Allow using multiple XWindowTypes on X11 (#1140)

This commit is contained in:
Michael Palmos
2019-09-06 20:49:33 +10:00
parent bfcd85ab15
commit a230333456
5 changed files with 94 additions and 65 deletions

View File

@@ -5,6 +5,7 @@
- On X11, performance is improved when rapidly calling `Window::set_cursor_icon`.
- On iOS, fix improper `msg_send` usage that was UB and/or would break if `!` is stabilized.
- On Windows, unset `maximized` when manually changing the window's position or size.
- On X11, allow combining `XWindowType`s.
# 0.20.0 Alpha 3 (2019-08-14)

View File

@@ -44,7 +44,7 @@ version = "0.1.3"
default_features = false
features = ["display_link"]
[target.'cfg(any(target_os = "ios", target_os = "windows"))'.dependencies]
[target.'cfg(any(target_os = "ios", target_os = "windows", target_os = "linux"))'.dependencies]
bitflags = "1"
[target.'cfg(target_os = "windows")'.dependencies.winapi]

View File

@@ -123,7 +123,7 @@ extern crate serde;
#[macro_use]
extern crate derivative;
#[macro_use]
#[cfg(any(target_os = "ios", target_os = "windows"))]
#[cfg(any(target_os = "ios", target_os = "windows", target_os = "linux"))]
extern crate bitflags;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]

View File

@@ -20,75 +20,103 @@ impl From<bool> for StateOperation {
}
}
/// X window type. Maps directly to
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowType {
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
/// root window clicks.
Desktop,
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
Dock,
/// Toolbar windows. "Torn off" from the main application.
Toolbar,
/// Pinnable menu windows. "Torn off" from the main application.
Menu,
/// A small persistent utility window, such as a palette or toolbox.
Utility,
/// The window is a splash screen displayed as an application is starting up.
Splash,
/// This is a dialog window.
Dialog,
/// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
/// This property is typically used on override-redirect windows.
DropdownMenu,
/// A popup menu that usually appears when the user right clicks on an object.
/// This property is typically used on override-redirect windows.
PopupMenu,
/// A tooltip window. Usually used to show additional information when hovering over an object with the cursor.
/// This property is typically used on override-redirect windows.
Tooltip,
/// The window is a notification.
/// This property is typically used on override-redirect windows.
Notification,
/// This should be used on the windows that are popped up by combo boxes.
/// This property is typically used on override-redirect windows.
Combo,
/// This indicates the the window is being dragged.
/// This property is typically used on override-redirect windows.
Dnd,
/// This is a normal, top-level window.
Normal,
bitflags! {
/// X window type. Maps directly to
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct WindowType: u32 {
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
/// root window clicks.
const DESKTOP = 1 << 0;
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
const DOCK = 1 << 1;
/// Toolbar windows. "Torn off" from the main application.
const TOOLBAR = 1 << 2;
/// Pinnable menu windows. "Torn off" from the main application.
const MENU = 1 << 3;
/// A small persistent utility window, such as a palette or toolbox.
const UTILITY = 1 << 4;
/// The window is a splash screen displayed as an application is starting up.
const SPLASH = 1 << 5;
/// This is a dialog window.
const DIALOG = 1 << 6;
/// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
/// This property is typically used on override-redirect windows.
const DROPDOWNMENU = 1 << 7;
/// A popup menu that usually appears when the user right clicks on an object.
/// This property is typically used on override-redirect windows.
const POPUPMENU = 1 << 8;
/// A tooltip window. Usually used to show additional information when hovering over an object with the cursor.
/// This property is typically used on override-redirect windows.
const TOOLTIP = 1 << 9;
/// The window is a notification.
/// This property is typically used on override-redirect windows.
const NOTIFICATION = 1 << 10;
/// This should be used on the windows that are popped up by combo boxes.
/// This property is typically used on override-redirect windows.
const COMBO = 1 << 11;
/// This indicates the the window is being dragged.
/// This property is typically used on override-redirect windows.
const DND = 1 << 12;
/// This is a normal, top-level window.
const NORMAL = 1 << 13;
}
}
impl Default for WindowType {
fn default() -> Self {
WindowType::Normal
WindowType::NORMAL
}
}
impl WindowType {
pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> 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",
};
unsafe { xconn.get_atom_unchecked(atom_name) }
pub(crate) fn get_atoms(&self, xconn: &Arc<XConnection>) -> Vec<ffi::Atom> {
let mut vec = vec![];
if self.contains(WindowType::DESKTOP) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_DESKTOP\0") });
}
if self.contains(WindowType::DOCK) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_DOCK\0") });
}
if self.contains(WindowType::TOOLBAR) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_TOOLBAR\0") });
}
if self.contains(WindowType::MENU) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_MENU\0") });
}
if self.contains(WindowType::UTILITY) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_UTILITY\0") });
}
if self.contains(WindowType::SPLASH) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_SPLASH\0") });
}
if self.contains(WindowType::DIALOG) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_DIALOG\0") });
}
if self.contains(WindowType::DROPDOWNMENU) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0") });
}
if self.contains(WindowType::POPUPMENU) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_POPUP_MENU\0") });
}
if self.contains(WindowType::TOOLTIP) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_TOOLTIP\0") });
}
if self.contains(WindowType::NOTIFICATION) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_NOTIFICATION\0") });
}
if self.contains(WindowType::COMBO) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_COMBO\0") });
}
if self.contains(WindowType::DND) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_DND\0") });
}
if self.contains(WindowType::NORMAL) {
vec.push(unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE_NORMAL\0") });
}
vec
}
}

View File

@@ -502,13 +502,13 @@ impl UnownedWindow {
fn set_window_type(&self, window_type: util::WindowType) -> 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 window_type_atoms = window_type.get_atoms(&self.xconn);
self.xconn.change_property(
self.xwindow,
hint_atom,
ffi::XA_ATOM,
util::PropMode::Replace,
&[window_type_atom],
&window_type_atoms,
)
}