Allow using multiple XWindowTypes on X11 (#1140) (#1147)

* Allow using multiple `XWindowType`s on X11 (#1140)

* Update documentation to make combining window types clearer

* Update build flags because X11 runs on more than just Linux

* Revert "Update build flags because X11 runs on more than just Linux"

This reverts commit 882b9100462a5ee0cf89dcd42891ebd0f709964f.

* Revert "Update documentation to make combining window types clearer"

This reverts commit da00ad391a8ce42cea08b577b216316b013f9e36.

* Revert "Allow using multiple `XWindowType`s on X11 (#1140)"

This reverts commit a23033345697463400286c4d297f5c1552369fc2.

* Allow using multiple `XWindowType`s on X11 (slice variant) (#1140)

* Multiple `XWindowType`s, with non-static lifetime.

* Multiple `XWindowType`s (#1140) (`Vec` variant)

* Append change to changelog.

* Fix formatting.
This commit is contained in:
Michael Palmos 2019-09-24 00:10:33 +10:00 committed by Hal Gentz
parent 2ef39651eb
commit c0a7900341
6 changed files with 96 additions and 74 deletions

View file

@ -11,6 +11,7 @@
- Officially remove the Emscripten backend. - Officially remove the Emscripten backend.
- On Windows, fix handling of surrogate pairs when dispatching `ReceivedCharacter`. - On Windows, fix handling of surrogate pairs when dispatching `ReceivedCharacter`.
- On macOS 10.15, fix freeze upon exiting exclusive fullscreen mode. - 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 iOS, fix null window on initial `HiDpiFactorChanged` event.
- On Windows, fix fullscreen window shrinking upon getting restored to a normal window. - 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 - On macOS, fix events not being emitted during modal loops, such as when windows are being resized

View file

@ -267,17 +267,17 @@ impl WindowExtUnix for Window {
} }
#[inline] #[inline]
fn xcb_connection(&self) -> Option<*mut raw::c_void> { fn set_urgent(&self, is_urgent: bool) {
match self.window { if let LinuxWindow::X(ref w) = self.window {
LinuxWindow::X(ref w) => Some(w.xcb_connection()), w.set_urgent(is_urgent);
_ => None,
} }
} }
#[inline] #[inline]
fn set_urgent(&self, is_urgent: bool) { fn xcb_connection(&self) -> Option<*mut raw::c_void> {
if let LinuxWindow::X(ref w) = self.window { match self.window {
w.set_urgent(is_urgent); 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. /// Additional methods on `WindowBuilder` that are specific to Unix.
pub trait WindowBuilderExtUnix { pub trait WindowBuilderExtUnix {
fn with_x11_visual<T>(self, visual_infos: *const T) -> WindowBuilder; fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
fn with_x11_screen(self, screen_id: i32) -> WindowBuilder; 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. /// 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. /// Build window with override-redirect flag; defaults to false. Only relevant on X11.
fn with_override_redirect(self, override_redirect: bool) -> WindowBuilder; fn with_override_redirect(self, override_redirect: bool) -> Self;
/// Build window with `_NET_WM_WINDOW_TYPE` hint; defaults to `Normal`. Only relevant on X11. /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
fn with_x11_window_type(self, x11_window_type: XWindowType) -> WindowBuilder; fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
/// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11. /// 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. /// 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. /// 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 /// Build window with a given application ID. It should match the `.desktop` file distributed with
/// your program. Only relevant on Wayland. /// your program. Only relevant on Wayland.
/// ///
/// For details about application ID conventions, see the /// 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) /// [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 { impl WindowBuilderExtUnix for WindowBuilder {
#[inline] #[inline]
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder { fn with_x11_visual<T>(mut self, visual_infos: *const T) -> Self {
self.platform_specific.visual_infos = self.platform_specific.visual_infos =
Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) }); Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
self self
} }
#[inline] #[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.platform_specific.screen_id = Some(screen_id);
self self
} }
#[inline] #[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.platform_specific.class = Some((instance, class));
self self
} }
#[inline] #[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.platform_specific.override_redirect = override_redirect;
self self
} }
#[inline] #[inline]
fn with_x11_window_type(mut self, x11_window_type: XWindowType) -> WindowBuilder { fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
self.platform_specific.x11_window_type = x11_window_type; self.platform_specific.x11_window_types = x11_window_types;
self self
} }
#[inline] #[inline]
fn with_resize_increments(mut self, increments: LogicalSize) -> WindowBuilder { fn with_gtk_theme_variant(mut self, variant: String) -> Self {
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 {
self.platform_specific.gtk_theme_variant = Some(variant); self.platform_specific.gtk_theme_variant = Some(variant);
self self
} }
#[inline] #[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.platform_specific.app_id = Some(app_id);
self self
} }

View file

@ -7,7 +7,9 @@ use raw_window_handle::RawWindowHandle;
use smithay_client_toolkit::reexports::client::ConnectError; use smithay_client_toolkit::reexports::client::ConnectError;
pub use self::x11::XNotSupported; 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::{ use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}, dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
error::{ExternalError, NotSupportedError, OsError as RootOsError}, 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. /// If this variable is set with any other value, winit will panic.
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND"; const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND";
#[derive(Clone, Default)] #[derive(Clone)]
pub struct PlatformSpecificWindowBuilderAttributes { pub struct PlatformSpecificWindowBuilderAttributes {
pub visual_infos: Option<XVisualInfo>, pub visual_infos: Option<XVisualInfo>,
pub screen_id: Option<i32>, pub screen_id: Option<i32>,
@ -38,11 +40,27 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub base_size: Option<(u32, u32)>, pub base_size: Option<(u32, u32)>,
pub class: Option<(String, String)>, pub class: Option<(String, String)>,
pub override_redirect: bool, pub override_redirect: bool,
pub x11_window_type: x11::util::WindowType, pub x11_window_types: Vec<XWindowType>,
pub gtk_theme_variant: Option<String>, pub gtk_theme_variant: Option<String>,
pub app_id: Option<String>, pub app_id: Option<String>,
} }
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! { lazy_static! {
pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> = pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> =
{ Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) }; { Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) };

View file

@ -72,21 +72,21 @@ impl Default for WindowType {
impl WindowType { impl WindowType {
pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> ffi::Atom { pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> ffi::Atom {
use self::WindowType::*; use self::WindowType::*;
let atom_name: &[u8] = match self { let atom_name: &[u8] = match *self {
&Desktop => b"_NET_WM_WINDOW_TYPE_DESKTOP\0", Desktop => b"_NET_WM_WINDOW_TYPE_DESKTOP\0",
&Dock => b"_NET_WM_WINDOW_TYPE_DOCK\0", Dock => b"_NET_WM_WINDOW_TYPE_DOCK\0",
&Toolbar => b"_NET_WM_WINDOW_TYPE_TOOLBAR\0", Toolbar => b"_NET_WM_WINDOW_TYPE_TOOLBAR\0",
&Menu => b"_NET_WM_WINDOW_TYPE_MENU\0", Menu => b"_NET_WM_WINDOW_TYPE_MENU\0",
&Utility => b"_NET_WM_WINDOW_TYPE_UTILITY\0", Utility => b"_NET_WM_WINDOW_TYPE_UTILITY\0",
&Splash => b"_NET_WM_WINDOW_TYPE_SPLASH\0", Splash => b"_NET_WM_WINDOW_TYPE_SPLASH\0",
&Dialog => b"_NET_WM_WINDOW_TYPE_DIALOG\0", Dialog => b"_NET_WM_WINDOW_TYPE_DIALOG\0",
&DropdownMenu => b"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0", DropdownMenu => b"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0",
&PopupMenu => b"_NET_WM_WINDOW_TYPE_POPUP_MENU\0", PopupMenu => b"_NET_WM_WINDOW_TYPE_POPUP_MENU\0",
&Tooltip => b"_NET_WM_WINDOW_TYPE_TOOLTIP\0", Tooltip => b"_NET_WM_WINDOW_TYPE_TOOLTIP\0",
&Notification => b"_NET_WM_WINDOW_TYPE_NOTIFICATION\0", Notification => b"_NET_WM_WINDOW_TYPE_NOTIFICATION\0",
&Combo => b"_NET_WM_WINDOW_TYPE_COMBO\0", Combo => b"_NET_WM_WINDOW_TYPE_COMBO\0",
&Dnd => b"_NET_WM_WINDOW_TYPE_DND\0", Dnd => b"_NET_WM_WINDOW_TYPE_DND\0",
&Normal => b"_NET_WM_WINDOW_TYPE_NORMAL\0", Normal => b"_NET_WM_WINDOW_TYPE_NORMAL\0",
}; };
unsafe { xconn.get_atom_unchecked(atom_name) } unsafe { xconn.get_atom_unchecked(atom_name) }
} }

View file

@ -298,9 +298,7 @@ impl UnownedWindow {
window.set_pid().map(|flusher| flusher.queue()); window.set_pid().map(|flusher| flusher.queue());
if pl_attribs.x11_window_type != Default::default() { window.set_window_types(pl_attribs.x11_window_types).queue();
window.set_window_type(pl_attribs.x11_window_type).queue();
}
if let Some(variant) = pl_attribs.gtk_theme_variant { if let Some(variant) = pl_attribs.gtk_theme_variant {
window.set_gtk_theme_variant(variant).queue(); 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::WindowType>) -> util::Flusher<'_> {
let hint_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE\0") }; 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.xconn.change_property(
self.xwindow, self.xwindow,
hint_atom, hint_atom,
ffi::XA_ATOM, ffi::XA_ATOM,
util::PropMode::Replace, util::PropMode::Replace,
&[window_type_atom], &atoms,
) )
} }

View file

@ -180,10 +180,11 @@ impl Default for WindowAttributes {
} }
} }
} }
impl WindowBuilder { impl WindowBuilder {
/// Initializes a new `WindowBuilder` with default values. /// Initializes a new `WindowBuilder` with default values.
#[inline] #[inline]
pub fn new() -> WindowBuilder { pub fn new() -> Self {
WindowBuilder { WindowBuilder {
window: Default::default(), window: Default::default(),
platform_specific: Default::default(), platform_specific: Default::default(),
@ -192,21 +193,21 @@ impl WindowBuilder {
/// Requests the window to be of specific dimensions. /// Requests the window to be of specific dimensions.
#[inline] #[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.window.inner_size = Some(size);
self self
} }
/// Sets a minimum dimension size for the window /// Sets a minimum dimension size for the window
#[inline] #[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.window.min_inner_size = Some(min_size);
self self
} }
/// Sets a maximum dimension size for the window /// Sets a maximum dimension size for the window
#[inline] #[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.window.max_inner_size = Some(max_size);
self self
} }
@ -222,14 +223,14 @@ impl WindowBuilder {
/// ///
/// Due to a bug in XFCE, this has no effect on Xfwm. /// Due to a bug in XFCE, this has no effect on Xfwm.
#[inline] #[inline]
pub fn with_resizable(mut self, resizable: bool) -> WindowBuilder { pub fn with_resizable(mut self, resizable: bool) -> Self {
self.window.resizable = resizable; self.window.resizable = resizable;
self self
} }
/// Requests a specific title for the window. /// Requests a specific title for the window.
#[inline] #[inline]
pub fn with_title<T: Into<String>>(mut self, title: T) -> WindowBuilder { pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
self.window.title = title.into(); self.window.title = title.into();
self self
} }
@ -241,42 +242,42 @@ impl WindowBuilder {
/// ///
/// - **Windows:** Screen saver is disabled in fullscreen mode. /// - **Windows:** Screen saver is disabled in fullscreen mode.
#[inline] #[inline]
pub fn with_fullscreen(mut self, monitor: Option<Fullscreen>) -> WindowBuilder { pub fn with_fullscreen(mut self, monitor: Option<Fullscreen>) -> Self {
self.window.fullscreen = monitor; self.window.fullscreen = monitor;
self self
} }
/// Requests maximized mode. /// Requests maximized mode.
#[inline] #[inline]
pub fn with_maximized(mut self, maximized: bool) -> WindowBuilder { pub fn with_maximized(mut self, maximized: bool) -> Self {
self.window.maximized = maximized; self.window.maximized = maximized;
self self
} }
/// Sets whether the window will be initially hidden or visible. /// Sets whether the window will be initially hidden or visible.
#[inline] #[inline]
pub fn with_visible(mut self, visible: bool) -> WindowBuilder { pub fn with_visible(mut self, visible: bool) -> Self {
self.window.visible = visible; self.window.visible = visible;
self self
} }
/// Sets whether the background of the window should be transparent. /// Sets whether the background of the window should be transparent.
#[inline] #[inline]
pub fn with_transparent(mut self, transparent: bool) -> WindowBuilder { pub fn with_transparent(mut self, transparent: bool) -> Self {
self.window.transparent = transparent; self.window.transparent = transparent;
self self
} }
/// Sets whether the window should have a border, a title bar, etc. /// Sets whether the window should have a border, a title bar, etc.
#[inline] #[inline]
pub fn with_decorations(mut self, decorations: bool) -> WindowBuilder { pub fn with_decorations(mut self, decorations: bool) -> Self {
self.window.decorations = decorations; self.window.decorations = decorations;
self self
} }
/// Sets whether or not the window will always be on top of other windows. /// Sets whether or not the window will always be on top of other windows.
#[inline] #[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.window.always_on_top = always_on_top;
self 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 /// 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. /// said, it's usually in the same ballpark as on Windows.
#[inline] #[inline]
pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> WindowBuilder { pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
self.window.window_icon = window_icon; self.window.window_icon = window_icon;
self self
} }