diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b28a177..34af8f51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Officially remove the Emscripten backend. - On Windows, fix handling of surrogate pairs when dispatching `ReceivedCharacter`. - On macOS 10.15, fix freeze upon exiting exclusive fullscreen mode. +- On X11, allow setting mulitple `XWindowType`s. - On iOS, fix null window on initial `HiDpiFactorChanged` event. - On Windows, fix fullscreen window shrinking upon getting restored to a normal window. - On macOS, fix events not being emitted during modal loops, such as when windows are being resized diff --git a/src/platform/unix.rs b/src/platform/unix.rs index eb9675e4..a72b1d33 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -267,17 +267,17 @@ impl WindowExtUnix for Window { } #[inline] - fn xcb_connection(&self) -> Option<*mut raw::c_void> { - match self.window { - LinuxWindow::X(ref w) => Some(w.xcb_connection()), - _ => None, + fn set_urgent(&self, is_urgent: bool) { + if let LinuxWindow::X(ref w) = self.window { + w.set_urgent(is_urgent); } } #[inline] - fn set_urgent(&self, is_urgent: bool) { - if let LinuxWindow::X(ref w) = self.window { - w.set_urgent(is_urgent); + fn xcb_connection(&self) -> Option<*mut raw::c_void> { + match self.window { + LinuxWindow::X(ref w) => Some(w.xcb_connection()), + _ => None, } } @@ -313,82 +313,82 @@ impl WindowExtUnix for Window { /// Additional methods on `WindowBuilder` that are specific to Unix. pub trait WindowBuilderExtUnix { - fn with_x11_visual(self, visual_infos: *const T) -> WindowBuilder; - fn with_x11_screen(self, screen_id: i32) -> WindowBuilder; + fn with_x11_visual(self, visual_infos: *const T) -> Self; + fn with_x11_screen(self, screen_id: i32) -> Self; /// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11. - fn with_class(self, class: String, instance: String) -> WindowBuilder; + fn with_class(self, class: String, instance: String) -> Self; /// Build window with override-redirect flag; defaults to false. Only relevant on X11. - fn with_override_redirect(self, override_redirect: bool) -> WindowBuilder; - /// Build window with `_NET_WM_WINDOW_TYPE` hint; defaults to `Normal`. Only relevant on X11. - fn with_x11_window_type(self, x11_window_type: XWindowType) -> WindowBuilder; + fn with_override_redirect(self, override_redirect: bool) -> Self; + /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11. + fn with_x11_window_type(self, x11_window_type: Vec) -> Self; /// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11. - fn with_gtk_theme_variant(self, variant: String) -> WindowBuilder; + fn with_gtk_theme_variant(self, variant: String) -> Self; /// Build window with resize increment hint. Only implemented on X11. - fn with_resize_increments(self, increments: LogicalSize) -> WindowBuilder; + fn with_resize_increments(self, increments: LogicalSize) -> Self; /// Build window with base size hint. Only implemented on X11. - fn with_base_size(self, base_size: LogicalSize) -> WindowBuilder; + fn with_base_size(self, base_size: LogicalSize) -> Self; /// Build window with a given application ID. It should match the `.desktop` file distributed with /// your program. Only relevant on Wayland. /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) - fn with_app_id(self, app_id: String) -> WindowBuilder; + fn with_app_id(self, app_id: String) -> Self; } impl WindowBuilderExtUnix for WindowBuilder { #[inline] - fn with_x11_visual(mut self, visual_infos: *const T) -> WindowBuilder { + fn with_x11_visual(mut self, visual_infos: *const T) -> Self { self.platform_specific.visual_infos = Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) }); self } #[inline] - fn with_x11_screen(mut self, screen_id: i32) -> WindowBuilder { + fn with_x11_screen(mut self, screen_id: i32) -> Self { self.platform_specific.screen_id = Some(screen_id); self } #[inline] - fn with_class(mut self, instance: String, class: String) -> WindowBuilder { + fn with_class(mut self, instance: String, class: String) -> Self { self.platform_specific.class = Some((instance, class)); self } #[inline] - fn with_override_redirect(mut self, override_redirect: bool) -> WindowBuilder { + fn with_override_redirect(mut self, override_redirect: bool) -> Self { self.platform_specific.override_redirect = override_redirect; self } #[inline] - fn with_x11_window_type(mut self, x11_window_type: XWindowType) -> WindowBuilder { - self.platform_specific.x11_window_type = x11_window_type; + fn with_x11_window_type(mut self, x11_window_types: Vec) -> Self { + self.platform_specific.x11_window_types = x11_window_types; self } #[inline] - fn with_resize_increments(mut self, increments: LogicalSize) -> WindowBuilder { - self.platform_specific.resize_increments = Some(increments.into()); - self - } - - #[inline] - fn with_base_size(mut self, base_size: LogicalSize) -> WindowBuilder { - self.platform_specific.base_size = Some(base_size.into()); - self - } - - #[inline] - fn with_gtk_theme_variant(mut self, variant: String) -> WindowBuilder { + fn with_gtk_theme_variant(mut self, variant: String) -> Self { self.platform_specific.gtk_theme_variant = Some(variant); self } #[inline] - fn with_app_id(mut self, app_id: String) -> WindowBuilder { + fn with_resize_increments(mut self, increments: LogicalSize) -> Self { + self.platform_specific.resize_increments = Some(increments.into()); + self + } + + #[inline] + fn with_base_size(mut self, base_size: LogicalSize) -> Self { + self.platform_specific.base_size = Some(base_size.into()); + self + } + + #[inline] + fn with_app_id(mut self, app_id: String) -> Self { self.platform_specific.app_id = Some(app_id); self } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index bc960190..60430a2c 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -7,7 +7,9 @@ use raw_window_handle::RawWindowHandle; use smithay_client_toolkit::reexports::client::ConnectError; pub use self::x11::XNotSupported; -use self::x11::{ffi::XVisualInfo, get_xtarget, XConnection, XError}; +use self::x11::{ + ffi::XVisualInfo, get_xtarget, util::WindowType as XWindowType, XConnection, XError, +}; use crate::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, error::{ExternalError, NotSupportedError, OsError as RootOsError}, @@ -30,7 +32,7 @@ pub mod x11; /// If this variable is set with any other value, winit will panic. const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; -#[derive(Clone, Default)] +#[derive(Clone)] pub struct PlatformSpecificWindowBuilderAttributes { pub visual_infos: Option, pub screen_id: Option, @@ -38,11 +40,27 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub base_size: Option<(u32, u32)>, pub class: Option<(String, String)>, pub override_redirect: bool, - pub x11_window_type: x11::util::WindowType, + pub x11_window_types: Vec, pub gtk_theme_variant: Option, pub app_id: Option, } +impl Default for PlatformSpecificWindowBuilderAttributes { + fn default() -> Self { + Self { + visual_infos: None, + screen_id: None, + resize_increments: None, + base_size: None, + class: None, + override_redirect: false, + x11_window_types: vec![XWindowType::Normal], + gtk_theme_variant: None, + app_id: None, + } + } +} + lazy_static! { pub static ref X11_BACKEND: Mutex, XNotSupported>> = { Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) }; diff --git a/src/platform_impl/linux/x11/util/hint.rs b/src/platform_impl/linux/x11/util/hint.rs index 28086460..94c7e33a 100644 --- a/src/platform_impl/linux/x11/util/hint.rs +++ b/src/platform_impl/linux/x11/util/hint.rs @@ -72,21 +72,21 @@ impl Default for WindowType { impl WindowType { pub(crate) fn as_atom(&self, xconn: &Arc) -> ffi::Atom { use self::WindowType::*; - let atom_name: &[u8] = match self { - &Desktop => b"_NET_WM_WINDOW_TYPE_DESKTOP\0", - &Dock => b"_NET_WM_WINDOW_TYPE_DOCK\0", - &Toolbar => b"_NET_WM_WINDOW_TYPE_TOOLBAR\0", - &Menu => b"_NET_WM_WINDOW_TYPE_MENU\0", - &Utility => b"_NET_WM_WINDOW_TYPE_UTILITY\0", - &Splash => b"_NET_WM_WINDOW_TYPE_SPLASH\0", - &Dialog => b"_NET_WM_WINDOW_TYPE_DIALOG\0", - &DropdownMenu => b"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0", - &PopupMenu => b"_NET_WM_WINDOW_TYPE_POPUP_MENU\0", - &Tooltip => b"_NET_WM_WINDOW_TYPE_TOOLTIP\0", - &Notification => b"_NET_WM_WINDOW_TYPE_NOTIFICATION\0", - &Combo => b"_NET_WM_WINDOW_TYPE_COMBO\0", - &Dnd => b"_NET_WM_WINDOW_TYPE_DND\0", - &Normal => b"_NET_WM_WINDOW_TYPE_NORMAL\0", + let atom_name: &[u8] = match *self { + Desktop => b"_NET_WM_WINDOW_TYPE_DESKTOP\0", + Dock => b"_NET_WM_WINDOW_TYPE_DOCK\0", + Toolbar => b"_NET_WM_WINDOW_TYPE_TOOLBAR\0", + Menu => b"_NET_WM_WINDOW_TYPE_MENU\0", + Utility => b"_NET_WM_WINDOW_TYPE_UTILITY\0", + Splash => b"_NET_WM_WINDOW_TYPE_SPLASH\0", + Dialog => b"_NET_WM_WINDOW_TYPE_DIALOG\0", + DropdownMenu => b"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0", + PopupMenu => b"_NET_WM_WINDOW_TYPE_POPUP_MENU\0", + Tooltip => b"_NET_WM_WINDOW_TYPE_TOOLTIP\0", + Notification => b"_NET_WM_WINDOW_TYPE_NOTIFICATION\0", + Combo => b"_NET_WM_WINDOW_TYPE_COMBO\0", + Dnd => b"_NET_WM_WINDOW_TYPE_DND\0", + Normal => b"_NET_WM_WINDOW_TYPE_NORMAL\0", }; unsafe { xconn.get_atom_unchecked(atom_name) } } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 078cc4d5..335e529f 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -298,9 +298,7 @@ impl UnownedWindow { window.set_pid().map(|flusher| flusher.queue()); - if pl_attribs.x11_window_type != Default::default() { - window.set_window_type(pl_attribs.x11_window_type).queue(); - } + window.set_window_types(pl_attribs.x11_window_types).queue(); if let Some(variant) = pl_attribs.gtk_theme_variant { window.set_gtk_theme_variant(variant).queue(); @@ -483,15 +481,19 @@ impl UnownedWindow { } } - fn set_window_type(&self, window_type: util::WindowType) -> util::Flusher<'_> { + fn set_window_types(&self, window_types: Vec) -> util::Flusher<'_> { let hint_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE\0") }; - let window_type_atom = window_type.as_atom(&self.xconn); + let atoms: Vec<_> = window_types + .iter() + .map(|t| t.as_atom(&self.xconn)) + .collect(); + self.xconn.change_property( self.xwindow, hint_atom, ffi::XA_ATOM, util::PropMode::Replace, - &[window_type_atom], + &atoms, ) } diff --git a/src/window.rs b/src/window.rs index 481e9728..1eaeec47 100644 --- a/src/window.rs +++ b/src/window.rs @@ -180,10 +180,11 @@ impl Default for WindowAttributes { } } } + impl WindowBuilder { /// Initializes a new `WindowBuilder` with default values. #[inline] - pub fn new() -> WindowBuilder { + pub fn new() -> Self { WindowBuilder { window: Default::default(), platform_specific: Default::default(), @@ -192,21 +193,21 @@ impl WindowBuilder { /// Requests the window to be of specific dimensions. #[inline] - pub fn with_inner_size(mut self, size: LogicalSize) -> WindowBuilder { + pub fn with_inner_size(mut self, size: LogicalSize) -> Self { self.window.inner_size = Some(size); self } /// Sets a minimum dimension size for the window #[inline] - pub fn with_min_inner_size(mut self, min_size: LogicalSize) -> WindowBuilder { + pub fn with_min_inner_size(mut self, min_size: LogicalSize) -> Self { self.window.min_inner_size = Some(min_size); self } /// Sets a maximum dimension size for the window #[inline] - pub fn with_max_inner_size(mut self, max_size: LogicalSize) -> WindowBuilder { + pub fn with_max_inner_size(mut self, max_size: LogicalSize) -> Self { self.window.max_inner_size = Some(max_size); self } @@ -222,14 +223,14 @@ impl WindowBuilder { /// /// Due to a bug in XFCE, this has no effect on Xfwm. #[inline] - pub fn with_resizable(mut self, resizable: bool) -> WindowBuilder { + pub fn with_resizable(mut self, resizable: bool) -> Self { self.window.resizable = resizable; self } /// Requests a specific title for the window. #[inline] - pub fn with_title>(mut self, title: T) -> WindowBuilder { + pub fn with_title>(mut self, title: T) -> Self { self.window.title = title.into(); self } @@ -241,42 +242,42 @@ impl WindowBuilder { /// /// - **Windows:** Screen saver is disabled in fullscreen mode. #[inline] - pub fn with_fullscreen(mut self, monitor: Option) -> WindowBuilder { + pub fn with_fullscreen(mut self, monitor: Option) -> Self { self.window.fullscreen = monitor; self } /// Requests maximized mode. #[inline] - pub fn with_maximized(mut self, maximized: bool) -> WindowBuilder { + pub fn with_maximized(mut self, maximized: bool) -> Self { self.window.maximized = maximized; self } /// Sets whether the window will be initially hidden or visible. #[inline] - pub fn with_visible(mut self, visible: bool) -> WindowBuilder { + pub fn with_visible(mut self, visible: bool) -> Self { self.window.visible = visible; self } /// Sets whether the background of the window should be transparent. #[inline] - pub fn with_transparent(mut self, transparent: bool) -> WindowBuilder { + pub fn with_transparent(mut self, transparent: bool) -> Self { self.window.transparent = transparent; self } /// Sets whether the window should have a border, a title bar, etc. #[inline] - pub fn with_decorations(mut self, decorations: bool) -> WindowBuilder { + pub fn with_decorations(mut self, decorations: bool) -> Self { self.window.decorations = decorations; self } /// Sets whether or not the window will always be on top of other windows. #[inline] - pub fn with_always_on_top(mut self, always_on_top: bool) -> WindowBuilder { + pub fn with_always_on_top(mut self, always_on_top: bool) -> Self { self.window.always_on_top = always_on_top; self } @@ -294,7 +295,7 @@ impl WindowBuilder { /// X11 has no universal guidelines for icon sizes, so you're at the whims of the WM. That /// said, it's usually in the same ballpark as on Windows. #[inline] - pub fn with_window_icon(mut self, window_icon: Option) -> WindowBuilder { + pub fn with_window_icon(mut self, window_icon: Option) -> Self { self.window.window_icon = window_icon; self }