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