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 use std::ptr; 5 use std::sync::Arc; 6 7 use sctk::window::{ButtonState, Theme}; 8 9 use { 10 EventsLoop, 11 LogicalSize, 12 MonitorId, 13 Window, 14 WindowBuilder, 15 }; 16 use platform::{ 17 EventsLoop as LinuxEventsLoop, 18 Window as LinuxWindow, 19 }; 20 use platform::x11::XConnection; 21 use platform::x11::ffi::XVisualInfo; 22 23 // TODO: stupid hack so that glutin can do its work 24 #[doc(hidden)] 25 pub use platform::x11; 26 27 pub use platform::XNotSupported; 28 pub use platform::x11::util::WindowType as XWindowType; 29 30 /// Theme for wayland client side decorations 31 /// 32 /// Colors must be in ARGB8888 format 33 pub struct WaylandTheme { 34 /// Primary color when the window is focused 35 pub primary_active: [u8; 4], 36 /// Primary color when the window is unfocused 37 pub primary_inactive: [u8; 4], 38 /// Secondary color when the window is focused 39 pub secondary_active: [u8; 4], 40 /// Secondary color when the window is unfocused 41 pub secondary_inactive: [u8; 4], 42 /// Close button color when hovered over 43 pub close_button_hovered: [u8; 4], 44 /// Close button color 45 pub close_button: [u8; 4], 46 /// Close button color when hovered over 47 pub maximize_button_hovered: [u8; 4], 48 /// Maximize button color 49 pub maximize_button: [u8; 4], 50 /// Minimize button color when hovered over 51 pub minimize_button_hovered: [u8; 4], 52 /// Minimize button color 53 pub minimize_button: [u8; 4], 54 } 55 56 struct WaylandThemeObject(WaylandTheme); 57 58 impl Theme for WaylandThemeObject { get_primary_color(&self, active: bool) -> [u8; 4]59 fn get_primary_color(&self, active: bool) -> [u8; 4] { 60 if active { 61 self.0.primary_active 62 } else { 63 self.0.primary_inactive 64 } 65 } 66 67 // Used for division line get_secondary_color(&self, active: bool) -> [u8; 4]68 fn get_secondary_color(&self, active: bool) -> [u8; 4] { 69 if active { 70 self.0.secondary_active 71 } else { 72 self.0.secondary_inactive 73 } 74 } 75 get_close_button_color(&self, state: ButtonState) -> [u8; 4]76 fn get_close_button_color(&self, state: ButtonState) -> [u8; 4] { 77 match state { 78 ButtonState::Hovered => self.0.close_button_hovered, 79 _ => self.0.close_button, 80 } 81 } 82 get_maximize_button_color(&self, state: ButtonState) -> [u8; 4]83 fn get_maximize_button_color(&self, state: ButtonState) -> [u8; 4] { 84 match state { 85 ButtonState::Hovered => self.0.maximize_button_hovered, 86 _ => self.0.maximize_button, 87 } 88 } 89 get_minimize_button_color(&self, state: ButtonState) -> [u8; 4]90 fn get_minimize_button_color(&self, state: ButtonState) -> [u8; 4] { 91 match state { 92 ButtonState::Hovered => self.0.minimize_button_hovered, 93 _ => self.0.minimize_button, 94 } 95 } 96 } 97 98 /// Additional methods on `EventsLoop` that are specific to Linux. 99 pub trait EventsLoopExt { 100 /// Builds a new `EventsLoop` that is forced to use X11. new_x11() -> Result<Self, XNotSupported> where Self: Sized101 fn new_x11() -> Result<Self, XNotSupported> 102 where Self: Sized; 103 104 /// Builds a new `EventsLoop` that is forced to use Wayland. new_wayland() -> Self where Self: Sized105 fn new_wayland() -> Self 106 where Self: Sized; 107 108 /// True if the `EventsLoop` uses Wayland. is_wayland(&self) -> bool109 fn is_wayland(&self) -> bool; 110 111 /// True if the `EventsLoop` uses X11. is_x11(&self) -> bool112 fn is_x11(&self) -> bool; 113 114 #[doc(hidden)] get_xlib_xconnection(&self) -> Option<Arc<XConnection>>115 fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>; 116 117 /// Returns a pointer to the `wl_display` object of wayland that is used by this `EventsLoop`. 118 /// 119 /// Returns `None` if the `EventsLoop` doesn't use wayland (if it uses xlib for example). 120 /// 121 /// The pointer will become invalid when the glutin `EventsLoop` is destroyed. get_wayland_display(&self) -> Option<*mut raw::c_void>122 fn get_wayland_display(&self) -> Option<*mut raw::c_void>; 123 } 124 125 impl EventsLoopExt for EventsLoop { 126 #[inline] new_x11() -> Result<Self, XNotSupported>127 fn new_x11() -> Result<Self, XNotSupported> { 128 LinuxEventsLoop::new_x11().map(|ev| 129 EventsLoop { 130 events_loop: ev, 131 _marker: ::std::marker::PhantomData, 132 } 133 ) 134 } 135 136 #[inline] new_wayland() -> Self137 fn new_wayland() -> Self { 138 EventsLoop { 139 events_loop: match LinuxEventsLoop::new_wayland() { 140 Ok(e) => e, 141 Err(_) => panic!() // TODO: propagate 142 }, 143 _marker: ::std::marker::PhantomData, 144 } 145 } 146 147 #[inline] is_wayland(&self) -> bool148 fn is_wayland(&self) -> bool { 149 self.events_loop.is_wayland() 150 } 151 152 #[inline] is_x11(&self) -> bool153 fn is_x11(&self) -> bool { 154 !self.events_loop.is_wayland() 155 } 156 157 #[inline] 158 #[doc(hidden)] get_xlib_xconnection(&self) -> Option<Arc<XConnection>>159 fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> { 160 self.events_loop.x_connection().cloned() 161 } 162 163 #[inline] get_wayland_display(&self) -> Option<*mut raw::c_void>164 fn get_wayland_display(&self) -> Option<*mut raw::c_void> { 165 match self.events_loop { 166 LinuxEventsLoop::Wayland(ref e) => Some(e.get_display().c_ptr() as *mut _), 167 _ => None 168 } 169 } 170 } 171 172 /// Additional methods on `Window` that are specific to Unix. 173 pub trait WindowExt { 174 /// Returns the ID of the `Window` xlib object that is used by this window. 175 /// 176 /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). get_xlib_window(&self) -> Option<raw::c_ulong>177 fn get_xlib_window(&self) -> Option<raw::c_ulong>; 178 179 /// Returns a pointer to the `Display` object of xlib that is used by this window. 180 /// 181 /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). 182 /// 183 /// The pointer will become invalid when the glutin `Window` is destroyed. get_xlib_display(&self) -> Option<*mut raw::c_void>184 fn get_xlib_display(&self) -> Option<*mut raw::c_void>; 185 get_xlib_screen_id(&self) -> Option<raw::c_int>186 fn get_xlib_screen_id(&self) -> Option<raw::c_int>; 187 188 #[doc(hidden)] get_xlib_xconnection(&self) -> Option<Arc<XConnection>>189 fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>; 190 191 /// Set window urgency hint (`XUrgencyHint`). Only relevant on X. set_urgent(&self, is_urgent: bool)192 fn set_urgent(&self, is_urgent: bool); 193 194 /// This function returns the underlying `xcb_connection_t` of an xlib `Display`. 195 /// 196 /// Returns `None` if the window doesn't use xlib (if it uses wayland for example). 197 /// 198 /// The pointer will become invalid when the glutin `Window` is destroyed. get_xcb_connection(&self) -> Option<*mut raw::c_void>199 fn get_xcb_connection(&self) -> Option<*mut raw::c_void>; 200 201 /// Returns a pointer to the `wl_surface` object of wayland that is used by this window. 202 /// 203 /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). 204 /// 205 /// The pointer will become invalid when the glutin `Window` is destroyed. get_wayland_surface(&self) -> Option<*mut raw::c_void>206 fn get_wayland_surface(&self) -> Option<*mut raw::c_void>; 207 208 /// Returns a pointer to the `wl_display` object of wayland that is used by this window. 209 /// 210 /// Returns `None` if the window doesn't use wayland (if it uses xlib for example). 211 /// 212 /// The pointer will become invalid when the glutin `Window` is destroyed. get_wayland_display(&self) -> Option<*mut raw::c_void>213 fn get_wayland_display(&self) -> Option<*mut raw::c_void>; 214 215 /// Sets the color theme of the client side window decorations on wayland set_wayland_theme(&self, theme: WaylandTheme)216 fn set_wayland_theme(&self, theme: WaylandTheme); 217 218 /// Check if the window is ready for drawing 219 /// 220 /// It is a remnant of a previous implementation detail for the 221 /// wayland backend, and is no longer relevant. 222 /// 223 /// Always return true. 224 #[deprecated] is_ready(&self) -> bool225 fn is_ready(&self) -> bool; 226 } 227 228 impl WindowExt for Window { 229 #[inline] get_xlib_window(&self) -> Option<raw::c_ulong>230 fn get_xlib_window(&self) -> Option<raw::c_ulong> { 231 match self.window { 232 LinuxWindow::X(ref w) => Some(w.get_xlib_window()), 233 _ => None 234 } 235 } 236 237 #[inline] get_xlib_display(&self) -> Option<*mut raw::c_void>238 fn get_xlib_display(&self) -> Option<*mut raw::c_void> { 239 match self.window { 240 LinuxWindow::X(ref w) => Some(w.get_xlib_display()), 241 _ => None 242 } 243 } 244 245 #[inline] get_xlib_screen_id(&self) -> Option<raw::c_int>246 fn get_xlib_screen_id(&self) -> Option<raw::c_int> { 247 match self.window { 248 LinuxWindow::X(ref w) => Some(w.get_xlib_screen_id()), 249 _ => None 250 } 251 } 252 253 #[inline] 254 #[doc(hidden)] get_xlib_xconnection(&self) -> Option<Arc<XConnection>>255 fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> { 256 match self.window { 257 LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()), 258 _ => None 259 } 260 } 261 262 #[inline] get_xcb_connection(&self) -> Option<*mut raw::c_void>263 fn get_xcb_connection(&self) -> Option<*mut raw::c_void> { 264 match self.window { 265 LinuxWindow::X(ref w) => Some(w.get_xcb_connection()), 266 _ => None 267 } 268 } 269 270 #[inline] set_urgent(&self, is_urgent: bool)271 fn set_urgent(&self, is_urgent: bool) { 272 if let LinuxWindow::X(ref w) = self.window { 273 w.set_urgent(is_urgent); 274 } 275 } 276 277 #[inline] get_wayland_surface(&self) -> Option<*mut raw::c_void>278 fn get_wayland_surface(&self) -> Option<*mut raw::c_void> { 279 match self.window { 280 LinuxWindow::Wayland(ref w) => Some(w.get_surface().c_ptr() as *mut _), 281 _ => None 282 } 283 } 284 285 #[inline] get_wayland_display(&self) -> Option<*mut raw::c_void>286 fn get_wayland_display(&self) -> Option<*mut raw::c_void> { 287 match self.window { 288 LinuxWindow::Wayland(ref w) => Some(w.get_display().c_ptr() as *mut _), 289 _ => None 290 } 291 } 292 293 #[inline] set_wayland_theme(&self, theme: WaylandTheme)294 fn set_wayland_theme(&self, theme: WaylandTheme) { 295 match self.window { 296 LinuxWindow::Wayland(ref w) => w.set_theme(WaylandThemeObject(theme)), 297 _ => {} 298 } 299 } 300 301 #[inline] is_ready(&self) -> bool302 fn is_ready(&self) -> bool { 303 true 304 } 305 } 306 307 /// Additional methods on `WindowBuilder` that are specific to Unix. 308 pub trait WindowBuilderExt { with_x11_visual<T>(self, visual_infos: *const T) -> WindowBuilder309 fn with_x11_visual<T>(self, visual_infos: *const T) -> WindowBuilder; with_x11_screen(self, screen_id: i32) -> WindowBuilder310 fn with_x11_screen(self, screen_id: i32) -> WindowBuilder; 311 312 /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11. with_class(self, class: String, instance: String) -> WindowBuilder313 fn with_class(self, class: String, instance: String) -> WindowBuilder; 314 /// Build window with override-redirect flag; defaults to false. Only relevant on X11. with_override_redirect(self, override_redirect: bool) -> WindowBuilder315 fn with_override_redirect(self, override_redirect: bool) -> WindowBuilder; 316 /// Build window with `_NET_WM_WINDOW_TYPE` hint; defaults to `Normal`. Only relevant on X11. with_x11_window_type(self, x11_window_type: XWindowType) -> WindowBuilder317 fn with_x11_window_type(self, x11_window_type: XWindowType) -> WindowBuilder; 318 /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11. with_gtk_theme_variant(self, variant: String) -> WindowBuilder319 fn with_gtk_theme_variant(self, variant: String) -> WindowBuilder; 320 /// Build window with resize increment hint. Only implemented on X11. with_resize_increments(self, increments: LogicalSize) -> WindowBuilder321 fn with_resize_increments(self, increments: LogicalSize) -> WindowBuilder; 322 /// Build window with base size hint. Only implemented on X11. with_base_size(self, base_size: LogicalSize) -> WindowBuilder323 fn with_base_size(self, base_size: LogicalSize) -> WindowBuilder; 324 325 /// Build window with a given application ID. It should match the `.desktop` file distributed with 326 /// your program. Only relevant on Wayland. 327 /// 328 /// For details about application ID conventions, see the 329 /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) with_app_id(self, app_id: String) -> WindowBuilder330 fn with_app_id(self, app_id: String) -> WindowBuilder; 331 } 332 333 impl WindowBuilderExt for WindowBuilder { 334 #[inline] with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder335 fn with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder { 336 self.platform_specific.visual_infos = Some( 337 unsafe { ptr::read(visual_infos as *const XVisualInfo) } 338 ); 339 self 340 } 341 342 #[inline] with_x11_screen(mut self, screen_id: i32) -> WindowBuilder343 fn with_x11_screen(mut self, screen_id: i32) -> WindowBuilder { 344 self.platform_specific.screen_id = Some(screen_id); 345 self 346 } 347 348 #[inline] with_class(mut self, instance: String, class: String) -> WindowBuilder349 fn with_class(mut self, instance: String, class: String) -> WindowBuilder { 350 self.platform_specific.class = Some((instance, class)); 351 self 352 } 353 354 #[inline] with_override_redirect(mut self, override_redirect: bool) -> WindowBuilder355 fn with_override_redirect(mut self, override_redirect: bool) -> WindowBuilder { 356 self.platform_specific.override_redirect = override_redirect; 357 self 358 } 359 360 #[inline] with_x11_window_type(mut self, x11_window_type: XWindowType) -> WindowBuilder361 fn with_x11_window_type(mut self, x11_window_type: XWindowType) -> WindowBuilder { 362 self.platform_specific.x11_window_type = x11_window_type; 363 self 364 } 365 366 #[inline] with_resize_increments(mut self, increments: LogicalSize) -> WindowBuilder367 fn with_resize_increments(mut self, increments: LogicalSize) -> WindowBuilder { 368 self.platform_specific.resize_increments = Some(increments.into()); 369 self 370 } 371 372 #[inline] with_base_size(mut self, base_size: LogicalSize) -> WindowBuilder373 fn with_base_size(mut self, base_size: LogicalSize) -> WindowBuilder { 374 self.platform_specific.base_size = Some(base_size.into()); 375 self 376 } 377 378 #[inline] with_gtk_theme_variant(mut self, variant: String) -> WindowBuilder379 fn with_gtk_theme_variant(mut self, variant: String) -> WindowBuilder { 380 self.platform_specific.gtk_theme_variant = Some(variant); 381 self 382 } 383 384 #[inline] with_app_id(mut self, app_id: String) -> WindowBuilder385 fn with_app_id(mut self, app_id: String) -> WindowBuilder { 386 self.platform_specific.app_id = Some(app_id); 387 self 388 } 389 } 390 391 /// Additional methods on `MonitorId` that are specific to Linux. 392 pub trait MonitorIdExt { 393 /// Returns the inner identifier of the monitor. native_id(&self) -> u32394 fn native_id(&self) -> u32; 395 } 396 397 impl MonitorIdExt for MonitorId { 398 #[inline] native_id(&self) -> u32399 fn native_id(&self) -> u32 { 400 self.inner.get_native_identifier() 401 } 402 } 403