1 #![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
2 
3 use std::os::raw;
4 #[cfg(feature = "x11")]
5 use std::{ptr, sync::Arc};
6 
7 #[cfg(feature = "wayland")]
8 use smithay_client_toolkit::window::{ButtonState as SCTKButtonState, Theme as SCTKTheme};
9 
10 use crate::{
11     event_loop::{EventLoop, EventLoopWindowTarget},
12     monitor::MonitorHandle,
13     window::{Window, WindowBuilder},
14 };
15 
16 #[cfg(feature = "x11")]
17 use crate::dpi::Size;
18 #[cfg(feature = "x11")]
19 use crate::platform_impl::x11::{ffi::XVisualInfo, XConnection};
20 use crate::platform_impl::{
21     EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
22     Window as LinuxWindow,
23 };
24 
25 // TODO: stupid hack so that glutin can do its work
26 #[doc(hidden)]
27 #[cfg(feature = "x11")]
28 pub use crate::platform_impl::x11;
29 #[cfg(feature = "x11")]
30 pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
31 
32 /// Additional methods on `EventLoopWindowTarget` that are specific to Unix.
33 pub trait EventLoopWindowTargetExtUnix {
34     /// True if the `EventLoopWindowTarget` uses Wayland.
35     #[cfg(feature = "wayland")]
is_wayland(&self) -> bool36     fn is_wayland(&self) -> bool;
37 
38     /// True if the `EventLoopWindowTarget` uses X11.
39     #[cfg(feature = "x11")]
is_x11(&self) -> bool40     fn is_x11(&self) -> bool;
41 
42     #[doc(hidden)]
43     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>44     fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
45 
46     /// Returns a pointer to the `wl_display` object of wayland that is used by this
47     /// `EventLoopWindowTarget`.
48     ///
49     /// Returns `None` if the `EventLoop` doesn't use wayland (if it uses xlib for example).
50     ///
51     /// The pointer will become invalid when the winit `EventLoop` is destroyed.
52     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>53     fn wayland_display(&self) -> Option<*mut raw::c_void>;
54 }
55 
56 impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
57     #[inline]
58     #[cfg(feature = "wayland")]
is_wayland(&self) -> bool59     fn is_wayland(&self) -> bool {
60         self.p.is_wayland()
61     }
62 
63     #[inline]
64     #[cfg(feature = "x11")]
is_x11(&self) -> bool65     fn is_x11(&self) -> bool {
66         !self.p.is_wayland()
67     }
68 
69     #[inline]
70     #[doc(hidden)]
71     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>72     fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
73         match self.p {
74             LinuxEventLoopWindowTarget::X(ref e) => Some(e.x_connection().clone()),
75             #[cfg(feature = "wayland")]
76             _ => None,
77         }
78     }
79 
80     #[inline]
81     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>82     fn wayland_display(&self) -> Option<*mut raw::c_void> {
83         match self.p {
84             LinuxEventLoopWindowTarget::Wayland(ref p) => {
85                 Some(p.display().get_display_ptr() as *mut _)
86             }
87             #[cfg(feature = "x11")]
88             _ => None,
89         }
90     }
91 }
92 
93 /// Additional methods on `EventLoop` that are specific to Unix.
94 pub trait EventLoopExtUnix {
95     /// Builds a new `EventLoop` that is forced to use X11.
96     ///
97     /// # Panics
98     ///
99     /// If called outside the main thread. To initialize an X11 event loop outside
100     /// the main thread, use [`new_x11_any_thread`](#tymethod.new_x11_any_thread).
101     #[cfg(feature = "x11")]
new_x11() -> Result<Self, XNotSupported> where Self: Sized102     fn new_x11() -> Result<Self, XNotSupported>
103     where
104         Self: Sized;
105 
106     /// Builds a new `EventLoop` that is forced to use Wayland.
107     ///
108     /// # Panics
109     ///
110     /// If called outside the main thread. To initialize a Wayland event loop outside
111     /// the main thread, use [`new_wayland_any_thread`](#tymethod.new_wayland_any_thread).
112     #[cfg(feature = "wayland")]
new_wayland() -> Self where Self: Sized113     fn new_wayland() -> Self
114     where
115         Self: Sized;
116 
117     /// Builds a new `EventLoop` on any thread.
118     ///
119     /// This method bypasses the cross-platform compatibility requirement
120     /// that `EventLoop` be created on the main thread.
new_any_thread() -> Self where Self: Sized121     fn new_any_thread() -> Self
122     where
123         Self: Sized;
124 
125     /// Builds a new X11 `EventLoop` on any thread.
126     ///
127     /// This method bypasses the cross-platform compatibility requirement
128     /// that `EventLoop` be created on the main thread.
129     #[cfg(feature = "x11")]
new_x11_any_thread() -> Result<Self, XNotSupported> where Self: Sized130     fn new_x11_any_thread() -> Result<Self, XNotSupported>
131     where
132         Self: Sized;
133 
134     /// Builds a new Wayland `EventLoop` on any thread.
135     ///
136     /// This method bypasses the cross-platform compatibility requirement
137     /// that `EventLoop` be created on the main thread.
138     #[cfg(feature = "wayland")]
new_wayland_any_thread() -> Self where Self: Sized139     fn new_wayland_any_thread() -> Self
140     where
141         Self: Sized;
142 }
143 
wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T>144 fn wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T> {
145     EventLoop {
146         event_loop,
147         _marker: std::marker::PhantomData,
148     }
149 }
150 
151 impl<T> EventLoopExtUnix for EventLoop<T> {
152     #[inline]
new_any_thread() -> Self153     fn new_any_thread() -> Self {
154         wrap_ev(LinuxEventLoop::new_any_thread())
155     }
156 
157     #[inline]
158     #[cfg(feature = "x11")]
new_x11_any_thread() -> Result<Self, XNotSupported>159     fn new_x11_any_thread() -> Result<Self, XNotSupported> {
160         LinuxEventLoop::new_x11_any_thread().map(wrap_ev)
161     }
162 
163     #[inline]
164     #[cfg(feature = "wayland")]
new_wayland_any_thread() -> Self165     fn new_wayland_any_thread() -> Self {
166         wrap_ev(
167             LinuxEventLoop::new_wayland_any_thread()
168                 // TODO: propagate
169                 .expect("failed to open Wayland connection"),
170         )
171     }
172 
173     #[inline]
174     #[cfg(feature = "x11")]
new_x11() -> Result<Self, XNotSupported>175     fn new_x11() -> Result<Self, XNotSupported> {
176         LinuxEventLoop::new_x11().map(wrap_ev)
177     }
178 
179     #[inline]
180     #[cfg(feature = "wayland")]
new_wayland() -> Self181     fn new_wayland() -> Self {
182         wrap_ev(
183             LinuxEventLoop::new_wayland()
184                 // TODO: propagate
185                 .expect("failed to open Wayland connection"),
186         )
187     }
188 }
189 
190 /// Additional methods on `Window` that are specific to Unix.
191 pub trait WindowExtUnix {
192     /// Returns the ID of the `Window` xlib object that is used by this window.
193     ///
194     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
195     #[cfg(feature = "x11")]
xlib_window(&self) -> Option<raw::c_ulong>196     fn xlib_window(&self) -> Option<raw::c_ulong>;
197 
198     /// Returns a pointer to the `Display` object of xlib that is used by this window.
199     ///
200     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
201     ///
202     /// The pointer will become invalid when the glutin `Window` is destroyed.
203     #[cfg(feature = "x11")]
xlib_display(&self) -> Option<*mut raw::c_void>204     fn xlib_display(&self) -> Option<*mut raw::c_void>;
205 
206     #[cfg(feature = "x11")]
xlib_screen_id(&self) -> Option<raw::c_int>207     fn xlib_screen_id(&self) -> Option<raw::c_int>;
208 
209     #[doc(hidden)]
210     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>211     fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
212 
213     /// Set window urgency hint (`XUrgencyHint`). Only relevant on X.
214     #[cfg(feature = "x11")]
set_urgent(&self, is_urgent: bool)215     fn set_urgent(&self, is_urgent: bool);
216 
217     /// This function returns the underlying `xcb_connection_t` of an xlib `Display`.
218     ///
219     /// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
220     ///
221     /// The pointer will become invalid when the glutin `Window` is destroyed.
222     #[cfg(feature = "x11")]
xcb_connection(&self) -> Option<*mut raw::c_void>223     fn xcb_connection(&self) -> Option<*mut raw::c_void>;
224 
225     /// Returns a pointer to the `wl_surface` object of wayland that is used by this window.
226     ///
227     /// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
228     ///
229     /// The pointer will become invalid when the glutin `Window` is destroyed.
230     #[cfg(feature = "wayland")]
wayland_surface(&self) -> Option<*mut raw::c_void>231     fn wayland_surface(&self) -> Option<*mut raw::c_void>;
232 
233     /// Returns a pointer to the `wl_display` object of wayland that is used by this window.
234     ///
235     /// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
236     ///
237     /// The pointer will become invalid when the glutin `Window` is destroyed.
238     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>239     fn wayland_display(&self) -> Option<*mut raw::c_void>;
240 
241     /// Sets the color theme of the client side window decorations on wayland
242     #[cfg(feature = "wayland")]
set_wayland_theme<T: Theme>(&self, theme: T)243     fn set_wayland_theme<T: Theme>(&self, theme: T);
244 
245     /// Check if the window is ready for drawing
246     ///
247     /// It is a remnant of a previous implementation detail for the
248     /// wayland backend, and is no longer relevant.
249     ///
250     /// Always return true.
251     #[deprecated]
is_ready(&self) -> bool252     fn is_ready(&self) -> bool;
253 }
254 
255 impl WindowExtUnix for Window {
256     #[inline]
257     #[cfg(feature = "x11")]
xlib_window(&self) -> Option<raw::c_ulong>258     fn xlib_window(&self) -> Option<raw::c_ulong> {
259         match self.window {
260             LinuxWindow::X(ref w) => Some(w.xlib_window()),
261             #[cfg(feature = "wayland")]
262             _ => None,
263         }
264     }
265 
266     #[inline]
267     #[cfg(feature = "x11")]
xlib_display(&self) -> Option<*mut raw::c_void>268     fn xlib_display(&self) -> Option<*mut raw::c_void> {
269         match self.window {
270             LinuxWindow::X(ref w) => Some(w.xlib_display()),
271             #[cfg(feature = "wayland")]
272             _ => None,
273         }
274     }
275 
276     #[inline]
277     #[cfg(feature = "x11")]
xlib_screen_id(&self) -> Option<raw::c_int>278     fn xlib_screen_id(&self) -> Option<raw::c_int> {
279         match self.window {
280             LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
281             #[cfg(feature = "wayland")]
282             _ => None,
283         }
284     }
285 
286     #[inline]
287     #[doc(hidden)]
288     #[cfg(feature = "x11")]
xlib_xconnection(&self) -> Option<Arc<XConnection>>289     fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
290         match self.window {
291             LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
292             #[cfg(feature = "wayland")]
293             _ => None,
294         }
295     }
296 
297     #[inline]
298     #[cfg(feature = "x11")]
set_urgent(&self, is_urgent: bool)299     fn set_urgent(&self, is_urgent: bool) {
300         match self.window {
301             LinuxWindow::X(ref w) => w.set_urgent(is_urgent),
302             #[cfg(feature = "wayland")]
303             _ => (),
304         }
305     }
306 
307     #[inline]
308     #[cfg(feature = "x11")]
xcb_connection(&self) -> Option<*mut raw::c_void>309     fn xcb_connection(&self) -> Option<*mut raw::c_void> {
310         match self.window {
311             LinuxWindow::X(ref w) => Some(w.xcb_connection()),
312             #[cfg(feature = "wayland")]
313             _ => None,
314         }
315     }
316 
317     #[inline]
318     #[cfg(feature = "wayland")]
wayland_surface(&self) -> Option<*mut raw::c_void>319     fn wayland_surface(&self) -> Option<*mut raw::c_void> {
320         match self.window {
321             LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
322             #[cfg(feature = "x11")]
323             _ => None,
324         }
325     }
326 
327     #[inline]
328     #[cfg(feature = "wayland")]
wayland_display(&self) -> Option<*mut raw::c_void>329     fn wayland_display(&self) -> Option<*mut raw::c_void> {
330         match self.window {
331             LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _),
332             #[cfg(feature = "x11")]
333             _ => None,
334         }
335     }
336 
337     #[inline]
338     #[cfg(feature = "wayland")]
set_wayland_theme<T: Theme>(&self, theme: T)339     fn set_wayland_theme<T: Theme>(&self, theme: T) {
340         match self.window {
341             LinuxWindow::Wayland(ref w) => w.set_theme(WaylandTheme(theme)),
342             #[cfg(feature = "x11")]
343             _ => {}
344         }
345     }
346 
347     #[inline]
is_ready(&self) -> bool348     fn is_ready(&self) -> bool {
349         true
350     }
351 }
352 
353 /// Additional methods on `WindowBuilder` that are specific to Unix.
354 pub trait WindowBuilderExtUnix {
355     #[cfg(feature = "x11")]
with_x11_visual<T>(self, visual_infos: *const T) -> Self356     fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
357     #[cfg(feature = "x11")]
with_x11_screen(self, screen_id: i32) -> Self358     fn with_x11_screen(self, screen_id: i32) -> Self;
359 
360     /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11.
361     #[cfg(feature = "x11")]
with_class(self, class: String, instance: String) -> Self362     fn with_class(self, class: String, instance: String) -> Self;
363     /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
364     #[cfg(feature = "x11")]
with_override_redirect(self, override_redirect: bool) -> Self365     fn with_override_redirect(self, override_redirect: bool) -> Self;
366     /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
367     #[cfg(feature = "x11")]
with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self368     fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
369     /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11.
370     #[cfg(feature = "x11")]
with_gtk_theme_variant(self, variant: String) -> Self371     fn with_gtk_theme_variant(self, variant: String) -> Self;
372     /// Build window with resize increment hint. Only implemented on X11.
373     #[cfg(feature = "x11")]
with_resize_increments<S: Into<Size>>(self, increments: S) -> Self374     fn with_resize_increments<S: Into<Size>>(self, increments: S) -> Self;
375     /// Build window with base size hint. Only implemented on X11.
376     #[cfg(feature = "x11")]
with_base_size<S: Into<Size>>(self, base_size: S) -> Self377     fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
378 
379     /// Build window with a given application ID. It should match the `.desktop` file distributed with
380     /// your program. Only relevant on Wayland.
381     ///
382     /// For details about application ID conventions, see the
383     /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
384     #[cfg(feature = "wayland")]
with_app_id(self, app_id: String) -> Self385     fn with_app_id(self, app_id: String) -> Self;
386 }
387 
388 impl WindowBuilderExtUnix for WindowBuilder {
389     #[inline]
390     #[cfg(feature = "x11")]
with_x11_visual<T>(mut self, visual_infos: *const T) -> Self391     fn with_x11_visual<T>(mut self, visual_infos: *const T) -> Self {
392         {
393             self.platform_specific.visual_infos =
394                 Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
395         }
396         self
397     }
398 
399     #[inline]
400     #[cfg(feature = "x11")]
with_x11_screen(mut self, screen_id: i32) -> Self401     fn with_x11_screen(mut self, screen_id: i32) -> Self {
402         self.platform_specific.screen_id = Some(screen_id);
403         self
404     }
405 
406     #[inline]
407     #[cfg(feature = "x11")]
with_class(mut self, instance: String, class: String) -> Self408     fn with_class(mut self, instance: String, class: String) -> Self {
409         self.platform_specific.class = Some((instance, class));
410         self
411     }
412 
413     #[inline]
414     #[cfg(feature = "x11")]
with_override_redirect(mut self, override_redirect: bool) -> Self415     fn with_override_redirect(mut self, override_redirect: bool) -> Self {
416         self.platform_specific.override_redirect = override_redirect;
417         self
418     }
419 
420     #[inline]
421     #[cfg(feature = "x11")]
with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self422     fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
423         self.platform_specific.x11_window_types = x11_window_types;
424         self
425     }
426 
427     #[inline]
428     #[cfg(feature = "x11")]
with_gtk_theme_variant(mut self, variant: String) -> Self429     fn with_gtk_theme_variant(mut self, variant: String) -> Self {
430         self.platform_specific.gtk_theme_variant = Some(variant);
431         self
432     }
433 
434     #[inline]
435     #[cfg(feature = "x11")]
with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self436     fn with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self {
437         self.platform_specific.resize_increments = Some(increments.into());
438         self
439     }
440 
441     #[inline]
442     #[cfg(feature = "x11")]
with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self443     fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
444         self.platform_specific.base_size = Some(base_size.into());
445         self
446     }
447 
448     #[inline]
449     #[cfg(feature = "wayland")]
with_app_id(mut self, app_id: String) -> Self450     fn with_app_id(mut self, app_id: String) -> Self {
451         self.platform_specific.app_id = Some(app_id);
452         self
453     }
454 }
455 
456 /// Additional methods on `MonitorHandle` that are specific to Linux.
457 pub trait MonitorHandleExtUnix {
458     /// Returns the inner identifier of the monitor.
native_id(&self) -> u32459     fn native_id(&self) -> u32;
460 }
461 
462 impl MonitorHandleExtUnix for MonitorHandle {
463     #[inline]
native_id(&self) -> u32464     fn native_id(&self) -> u32 {
465         self.inner.native_identifier()
466     }
467 }
468 
469 /// Wrapper for implementing SCTK's theme trait.
470 #[cfg(feature = "wayland")]
471 struct WaylandTheme<T: Theme>(T);
472 
473 pub trait Theme: Send + 'static {
474     /// Primary color of the scheme.
primary_color(&self, window_active: bool) -> [u8; 4]475     fn primary_color(&self, window_active: bool) -> [u8; 4];
476 
477     /// Secondary color of the scheme.
secondary_color(&self, window_active: bool) -> [u8; 4]478     fn secondary_color(&self, window_active: bool) -> [u8; 4];
479 
480     /// Color for the close button.
close_button_color(&self, status: ButtonState) -> [u8; 4]481     fn close_button_color(&self, status: ButtonState) -> [u8; 4];
482 
483     /// Icon color for the close button, defaults to the secondary color.
484     #[allow(unused_variables)]
close_button_icon_color(&self, status: ButtonState) -> [u8; 4]485     fn close_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
486         self.secondary_color(true)
487     }
488 
489     /// Background color for the maximize button.
maximize_button_color(&self, status: ButtonState) -> [u8; 4]490     fn maximize_button_color(&self, status: ButtonState) -> [u8; 4];
491 
492     /// Icon color for the maximize button, defaults to the secondary color.
493     #[allow(unused_variables)]
maximize_button_icon_color(&self, status: ButtonState) -> [u8; 4]494     fn maximize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
495         self.secondary_color(true)
496     }
497 
498     /// Background color for the minimize button.
minimize_button_color(&self, status: ButtonState) -> [u8; 4]499     fn minimize_button_color(&self, status: ButtonState) -> [u8; 4];
500 
501     /// Icon color for the minimize button, defaults to the secondary color.
502     #[allow(unused_variables)]
minimize_button_icon_color(&self, status: ButtonState) -> [u8; 4]503     fn minimize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
504         self.secondary_color(true)
505     }
506 }
507 
508 #[cfg(feature = "wayland")]
509 impl<T: Theme> SCTKTheme for WaylandTheme<T> {
get_primary_color(&self, active: bool) -> [u8; 4]510     fn get_primary_color(&self, active: bool) -> [u8; 4] {
511         self.0.primary_color(active)
512     }
513 
get_secondary_color(&self, active: bool) -> [u8; 4]514     fn get_secondary_color(&self, active: bool) -> [u8; 4] {
515         self.0.secondary_color(active)
516     }
517 
get_close_button_color(&self, status: SCTKButtonState) -> [u8; 4]518     fn get_close_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
519         self.0.close_button_color(ButtonState::from_sctk(status))
520     }
521 
get_close_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4]522     fn get_close_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
523         self.0
524             .close_button_icon_color(ButtonState::from_sctk(status))
525     }
526 
get_maximize_button_color(&self, status: SCTKButtonState) -> [u8; 4]527     fn get_maximize_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
528         self.0.maximize_button_color(ButtonState::from_sctk(status))
529     }
530 
get_maximize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4]531     fn get_maximize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
532         self.0
533             .maximize_button_icon_color(ButtonState::from_sctk(status))
534     }
535 
get_minimize_button_color(&self, status: SCTKButtonState) -> [u8; 4]536     fn get_minimize_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
537         self.0.minimize_button_color(ButtonState::from_sctk(status))
538     }
539 
get_minimize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4]540     fn get_minimize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
541         self.0
542             .minimize_button_icon_color(ButtonState::from_sctk(status))
543     }
544 }
545 
546 pub enum ButtonState {
547     /// Button is being hovered over by pointer.
548     Hovered,
549     /// Button is not being hovered over by pointer.
550     Idle,
551     /// Button is disabled.
552     Disabled,
553 }
554 
555 #[cfg(feature = "wayland")]
556 impl ButtonState {
from_sctk(button_state: SCTKButtonState) -> Self557     fn from_sctk(button_state: SCTKButtonState) -> Self {
558         match button_state {
559             SCTKButtonState::Hovered => Self::Hovered,
560             SCTKButtonState::Idle => Self::Idle,
561             SCTKButtonState::Disabled => Self::Disabled,
562         }
563     }
564 }
565