gdk4/
display.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4
5use crate::{ffi, prelude::*, Display, Key, KeymapKey, ModifierType};
6
7#[derive(Debug, PartialEq, Eq, Ord, PartialOrd)]
8pub enum Backend {
9    Wayland,
10    X11,
11    Win32,
12    MacOS,
13    Broadway,
14}
15
16impl Backend {
17    // rustdoc-stripper-ignore-next
18    /// Equivalent to the C macro `GDK_IS_WAYLAND_DISPLAY`
19    #[doc(alias = "GDK_IS_WAYLAND_DISPLAY")]
20    pub fn is_wayland(&self) -> bool {
21        matches!(self, Self::Wayland)
22    }
23
24    // rustdoc-stripper-ignore-next
25    /// Equivalent to the C macro `GDK_IS_X11_DISPLAY`
26    #[doc(alias = "GDK_IS_X11_DISPLAY")]
27    pub fn is_x11(&self) -> bool {
28        matches!(self, Self::X11)
29    }
30
31    // rustdoc-stripper-ignore-next
32    /// Equivalent to the C macro `GDK_IS_WIN32_DISPLAY`
33    #[doc(alias = "GDK_IS_WIN32_DISPLAY")]
34    pub fn is_win32(&self) -> bool {
35        matches!(self, Self::Win32)
36    }
37
38    // rustdoc-stripper-ignore-next
39    /// Equivalent to the C macro `GDK_IS_MACOS_DISPLAY`
40    #[doc(alias = "GDK_IS_MACOS_DISPLAY")]
41    pub fn is_macos(&self) -> bool {
42        matches!(self, Self::MacOS)
43    }
44
45    // rustdoc-stripper-ignore-next
46    /// Equivalent to the C macro `GDK_IS_BROADWAY_DISPLAY`
47    #[doc(alias = "GDK_IS_BROADWAY_DISPLAY")]
48    pub fn is_broadway(&self) -> bool {
49        matches!(self, Self::Broadway)
50    }
51}
52
53// rustdoc-stripper-ignore-next
54/// Trait containing manually implemented methods of
55/// [`Display`](crate::Display).
56pub trait DisplayExtManual: IsA<Display> + 'static {
57    /// Translates the contents of a `GdkEventKey` into a keyval, effective group,
58    /// and level.
59    ///
60    /// Modifiers that affected the translation and are thus unavailable for
61    /// application use are returned in @consumed_modifiers.
62    ///
63    /// The @effective_group is the group that was actually used for the
64    /// translation; some keys such as Enter are not affected by the active
65    /// keyboard group. The @level is derived from @state.
66    ///
67    /// @consumed_modifiers gives modifiers that should be masked out
68    /// from @state when comparing this key press to a keyboard shortcut.
69    /// For instance, on a US keyboard, the `plus` symbol is shifted, so
70    /// when comparing a key press to a `<Control>plus` accelerator `<Shift>`
71    /// should be masked out.
72    ///
73    /// This function should rarely be needed, since `GdkEventKey` already
74    /// contains the translated keyval. It is exported for the benefit of
75    /// virtualized test environments.
76    /// ## `keycode`
77    /// a keycode
78    /// ## `state`
79    /// a modifier state
80    /// ## `group`
81    /// active keyboard group
82    ///
83    /// # Returns
84    ///
85    /// [`true`] if there was a keyval bound to keycode/state/group.
86    ///
87    /// ## `keyval`
88    /// return location for keyval
89    ///
90    /// ## `effective_group`
91    /// return location for effective group
92    ///
93    /// ## `level`
94    /// return location for level
95    ///
96    /// ## `consumed`
97    /// return location for modifiers that were used
98    ///   to determine the group or level
99    #[doc(alias = "gdk_display_translate_key")]
100    fn translate_key(
101        &self,
102        keycode: u32,
103        state: ModifierType,
104        group: i32,
105    ) -> Option<(Key, i32, i32, ModifierType)> {
106        unsafe {
107            let mut keyval = std::mem::MaybeUninit::uninit();
108            let mut effective_group = std::mem::MaybeUninit::uninit();
109            let mut level = std::mem::MaybeUninit::uninit();
110            let mut consumed = std::mem::MaybeUninit::uninit();
111            let ret = from_glib(ffi::gdk_display_translate_key(
112                self.as_ref().to_glib_none().0,
113                keycode,
114                state.into_glib(),
115                group,
116                keyval.as_mut_ptr(),
117                effective_group.as_mut_ptr(),
118                level.as_mut_ptr(),
119                consumed.as_mut_ptr(),
120            ));
121            if ret {
122                let keyval = keyval.assume_init();
123                let effective_group = effective_group.assume_init();
124                let level = level.assume_init();
125                let consumed = consumed.assume_init();
126                Some((
127                    from_glib(keyval),
128                    effective_group,
129                    level,
130                    from_glib(consumed),
131                ))
132            } else {
133                None
134            }
135        }
136    }
137
138    /// Retrieves a desktop-wide setting such as double-click time
139    /// for the @self.
140    /// ## `name`
141    /// the name of the setting
142    /// ## `value`
143    /// location to store the value of the setting
144    ///
145    /// # Returns
146    ///
147    /// [`true`] if the setting existed and a value was stored
148    ///   in @value, [`false`] otherwise
149    #[doc(alias = "gdk_display_get_setting")]
150    fn get_setting(&self, name: impl IntoGStr) -> Option<glib::Value> {
151        unsafe {
152            name.run_with_gstr(|name| {
153                let mut value = glib::Value::uninitialized();
154                let ret = ffi::gdk_display_get_setting(
155                    self.as_ref().to_glib_none().0,
156                    name.as_ptr(),
157                    value.to_glib_none_mut().0,
158                );
159                if from_glib(ret) {
160                    Some(value)
161                } else {
162                    None
163                }
164            })
165        }
166    }
167
168    /// Obtains a list of keycode/group/level combinations that will
169    /// generate @keyval.
170    ///
171    /// Groups and levels are two kinds of keyboard mode; in general, the level
172    /// determines whether the top or bottom symbol on a key is used, and the
173    /// group determines whether the left or right symbol is used.
174    ///
175    /// On US keyboards, the shift key changes the keyboard level, and there
176    /// are no groups. A group switch key might convert a keyboard between
177    /// Hebrew to English modes, for example.
178    ///
179    /// `GdkEventKey` contains a `group` field that indicates the active
180    /// keyboard group. The level is computed from the modifier mask.
181    ///
182    /// The returned array should be freed with g_free().
183    /// ## `keyval`
184    /// a keyval, such as `GDK_KEY_a`, `GDK_KEY_Up`, `GDK_KEY_Return`, etc.
185    ///
186    /// # Returns
187    ///
188    /// [`true`] if keys were found and returned
189    ///
190    /// ## `keys`
191    /// return location
192    ///   for an array of [`KeymapKey`][crate::KeymapKey]
193    #[doc(alias = "gdk_display_map_keyval")]
194    fn map_keyval(&self, keyval: Key) -> Option<Vec<KeymapKey>> {
195        unsafe {
196            let mut keys = std::ptr::null_mut();
197            let mut n_keys = std::mem::MaybeUninit::uninit();
198            let ret = from_glib(ffi::gdk_display_map_keyval(
199                self.as_ref().to_glib_none().0,
200                keyval.into_glib(),
201                &mut keys,
202                n_keys.as_mut_ptr(),
203            ));
204            if ret {
205                Some(FromGlibContainer::from_glib_full_num(
206                    keys,
207                    n_keys.assume_init() as usize,
208                ))
209            } else {
210                None
211            }
212        }
213    }
214
215    /// Returns the keyvals bound to @keycode.
216    ///
217    /// The Nth [`KeymapKey`][crate::KeymapKey] in @keys is bound to the Nth keyval in @keyvals.
218    ///
219    /// When a keycode is pressed by the user, the keyval from
220    /// this list of entries is selected by considering the effective
221    /// keyboard group and level.
222    ///
223    /// Free the returned arrays with g_free().
224    /// ## `keycode`
225    /// a keycode
226    ///
227    /// # Returns
228    ///
229    /// [`true`] if there were any entries
230    ///
231    /// ## `keys`
232    /// return
233    ///   location for array of [`KeymapKey`][crate::KeymapKey]
234    ///
235    /// ## `keyvals`
236    /// return
237    ///   location for array of keyvals
238    #[doc(alias = "gdk_display_map_keycode")]
239    fn map_keycode(&self, keycode: u32) -> Option<Vec<(KeymapKey, Key)>> {
240        unsafe {
241            let mut keys = std::ptr::null_mut();
242            let mut keyvals = std::ptr::null_mut();
243            let mut n_entries = std::mem::MaybeUninit::uninit();
244            let ret = from_glib(ffi::gdk_display_map_keycode(
245                self.as_ref().to_glib_none().0,
246                keycode,
247                &mut keys,
248                &mut keyvals,
249                n_entries.as_mut_ptr(),
250            ));
251            if ret {
252                let n_keys = n_entries.assume_init() as usize;
253                let keyvals: Vec<u32> = FromGlibContainer::from_glib_full_num(keyvals, n_keys);
254                let keyvals = keyvals.into_iter().map(|k| from_glib(k));
255                let keys: Vec<KeymapKey> = FromGlibContainer::from_glib_full_num(keys, n_keys);
256
257                Some(keys.into_iter().zip(keyvals).collect())
258            } else {
259                None
260            }
261        }
262    }
263
264    // rustdoc-stripper-ignore-next
265    /// Get the currently used display backend
266    fn backend(&self) -> Backend {
267        match self.as_ref().type_().name() {
268            "GdkWaylandDisplay" => Backend::Wayland,
269            "GdkX11Display" => Backend::X11,
270            "GdkMacosDisplay" => Backend::MacOS,
271            "GdkWin32Display" => Backend::Win32,
272            "GdkBroadwayDisplay" => Backend::Broadway,
273            e => panic!("Unsupported display backend {e}"),
274        }
275    }
276}
277
278impl<O: IsA<Display>> DisplayExtManual for O {}