Beginning of rust-xcb-wm
Initial structure and first basic working EWMH requests
This commit is contained in:
parent
a22ba5a60c
commit
36add615d9
8 changed files with 773 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
.idea
|
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "rust-xcb-wm"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = [ "Armin Friedl <dev@friedl.net>" ]
|
||||||
|
description = "Rust implementation of xcb-wm - icccm and ewmh extensions for xcb"
|
||||||
|
readme = "README.md"
|
||||||
|
keyworks = ["icccm", "ewmh", "xcb-wm", "xcb", "window", "xlib", "x11"]
|
||||||
|
license = "MIT"
|
||||||
|
edition = "2018"
|
||||||
|
repository = "https://git.friedl.net/incubator/rust-xcb-wm"
|
||||||
|
homepage = "https://git.friedl.net/incubator/rust-xcb-wm"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
xcb = "1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
icccm = []
|
||||||
|
ewmh = []
|
282
src/ewmh/atoms.rs
Normal file
282
src/ewmh/atoms.rs
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
const ATOM_NAMES: [&'static str; 82] = [
|
||||||
|
"_NET_SUPPORTED",
|
||||||
|
"_NET_CLIENT_LIST",
|
||||||
|
"_NET_CLIENT_LIST_STACKING",
|
||||||
|
"_NET_NUMBER_OF_DESKTOPS",
|
||||||
|
"_NET_DESKTOP_GEOMETRY",
|
||||||
|
"_NET_DESKTOP_VIEWPORT",
|
||||||
|
"_NET_CURRENT_DESKTOP",
|
||||||
|
"_NET_DESKTOP_NAMES",
|
||||||
|
"_NET_ACTIVE_WINDOW",
|
||||||
|
"_NET_WORKAREA",
|
||||||
|
"_NET_SUPPORTING_WM_CHECK",
|
||||||
|
"_NET_VIRTUAL_ROOTS",
|
||||||
|
"_NET_DESKTOP_LAYOUT",
|
||||||
|
"_NET_SHOWING_DESKTOP",
|
||||||
|
"_NET_CLOSE_WINDOW",
|
||||||
|
"_NET_MOVERESIZE_WINDOW",
|
||||||
|
"_NET_WM_MOVERESIZE",
|
||||||
|
"_NET_RESTACK_WINDOW",
|
||||||
|
"_NET_REQUEST_FRAME_EXTENTS",
|
||||||
|
"_NET_WM_NAME",
|
||||||
|
"_NET_WM_VISIBLE_NAME",
|
||||||
|
"_NET_WM_ICON_NAME",
|
||||||
|
"_NET_WM_VISIBLE_ICON_NAME",
|
||||||
|
"_NET_WM_DESKTOP",
|
||||||
|
"_NET_WM_WINDOW_TYPE",
|
||||||
|
"_NET_WM_STATE",
|
||||||
|
"_NET_WM_ALLOWED_ACTIONS",
|
||||||
|
"_NET_WM_STRUT",
|
||||||
|
"_NET_WM_STRUT_PARTIAL",
|
||||||
|
"_NET_WM_ICON_GEOMETRY",
|
||||||
|
"_NET_WM_ICON",
|
||||||
|
"_NET_WM_PID",
|
||||||
|
"_NET_WM_HANDLED_ICONS",
|
||||||
|
"_NET_WM_USER_TIME",
|
||||||
|
"_NET_WM_USER_TIME_WINDOW",
|
||||||
|
"_NET_FRAME_EXTENTS",
|
||||||
|
"_NET_WM_PING",
|
||||||
|
"_NET_WM_SYNC_REQUEST",
|
||||||
|
"_NET_WM_SYNC_REQUEST_COUNTER",
|
||||||
|
"_NET_WM_FULLSCREEN_MONITORS",
|
||||||
|
"_NET_WM_FULL_PLACEMENT",
|
||||||
|
"UTF8_STRING",
|
||||||
|
"WM_PROTOCOLS",
|
||||||
|
"MANAGER",
|
||||||
|
"_NET_WM_WINDOW_TYPE_DESKTOP",
|
||||||
|
"_NET_WM_WINDOW_TYPE_DOCK",
|
||||||
|
"_NET_WM_WINDOW_TYPE_TOOLBAR",
|
||||||
|
"_NET_WM_WINDOW_TYPE_MENU",
|
||||||
|
"_NET_WM_WINDOW_TYPE_UTILITY",
|
||||||
|
"_NET_WM_WINDOW_TYPE_SPLASH",
|
||||||
|
"_NET_WM_WINDOW_TYPE_DIALOG",
|
||||||
|
"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
|
||||||
|
"_NET_WM_WINDOW_TYPE_POPUP_MENU",
|
||||||
|
"_NET_WM_WINDOW_TYPE_TOOLTIP",
|
||||||
|
"_NET_WM_WINDOW_TYPE_NOTIFICATION",
|
||||||
|
"_NET_WM_WINDOW_TYPE_COMBO",
|
||||||
|
"_NET_WM_WINDOW_TYPE_DND",
|
||||||
|
"_NET_WM_WINDOW_TYPE_NORMAL",
|
||||||
|
"_NET_WM_STATE_MODAL",
|
||||||
|
"_NET_WM_STATE_STICKY",
|
||||||
|
"_NET_WM_STATE_MAXIMIZED_VERT",
|
||||||
|
"_NET_WM_STATE_MAXIMIZED_HORZ",
|
||||||
|
"_NET_WM_STATE_SHADED",
|
||||||
|
"_NET_WM_STATE_SKIP_TASKBAR",
|
||||||
|
"_NET_WM_STATE_SKIP_PAGER",
|
||||||
|
"_NET_WM_STATE_HIDDEN",
|
||||||
|
"_NET_WM_STATE_FULLSCREEN",
|
||||||
|
"_NET_WM_STATE_ABOVE",
|
||||||
|
"_NET_WM_STATE_BELOW",
|
||||||
|
"_NET_WM_STATE_DEMANDS_ATTENTION",
|
||||||
|
"_NET_WM_ACTION_MOVE",
|
||||||
|
"_NET_WM_ACTION_RESIZE",
|
||||||
|
"_NET_WM_ACTION_MINIMIZE",
|
||||||
|
"_NET_WM_ACTION_SHADE",
|
||||||
|
"_NET_WM_ACTION_STICK",
|
||||||
|
"_NET_WM_ACTION_MAXIMIZE_HORZ",
|
||||||
|
"_NET_WM_ACTION_MAXIMIZE_VERT",
|
||||||
|
"_NET_WM_ACTION_FULLSCREEN",
|
||||||
|
"_NET_WM_ACTION_CHANGE_DESKTOP",
|
||||||
|
"_NET_WM_ACTION_CLOSE",
|
||||||
|
"_NET_WM_ACTION_ABOVE",
|
||||||
|
"_NET_WM_ACTION_BELOW"
|
||||||
|
];
|
||||||
|
|
||||||
|
pub struct Atoms {
|
||||||
|
// TODO _NET_WM_CM_Sn atoms
|
||||||
|
pub _NET_SUPPORTED: xcb::x::Atom,
|
||||||
|
pub _NET_CLIENT_LIST: xcb::x::Atom,
|
||||||
|
pub _NET_CLIENT_LIST_STACKING: xcb::x::Atom,
|
||||||
|
pub _NET_NUMBER_OF_DESKTOPS: xcb::x::Atom,
|
||||||
|
pub _NET_DESKTOP_GEOMETRY: xcb::x::Atom,
|
||||||
|
pub _NET_DESKTOP_VIEWPORT: xcb::x::Atom,
|
||||||
|
pub _NET_CURRENT_DESKTOP: xcb::x::Atom,
|
||||||
|
pub _NET_DESKTOP_NAMES: xcb::x::Atom,
|
||||||
|
pub _NET_ACTIVE_WINDOW: xcb::x::Atom,
|
||||||
|
pub _NET_WORKAREA: xcb::x::Atom,
|
||||||
|
pub _NET_SUPPORTING_WM_CHECK: xcb::x::Atom,
|
||||||
|
pub _NET_VIRTUAL_ROOTS: xcb::x::Atom,
|
||||||
|
pub _NET_DESKTOP_LAYOUT: xcb::x::Atom,
|
||||||
|
pub _NET_SHOWING_DESKTOP: xcb::x::Atom,
|
||||||
|
pub _NET_CLOSE_WINDOW: xcb::x::Atom,
|
||||||
|
pub _NET_MOVERESIZE_WINDOW: xcb::x::Atom,
|
||||||
|
pub _NET_WM_MOVERESIZE: xcb::x::Atom,
|
||||||
|
pub _NET_RESTACK_WINDOW: xcb::x::Atom,
|
||||||
|
pub _NET_REQUEST_FRAME_EXTENTS: xcb::x::Atom,
|
||||||
|
pub _NET_WM_NAME: xcb::x::Atom,
|
||||||
|
pub _NET_WM_VISIBLE_NAME: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ICON_NAME: xcb::x::Atom,
|
||||||
|
pub _NET_WM_VISIBLE_ICON_NAME: xcb::x::Atom,
|
||||||
|
pub _NET_WM_DESKTOP: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ALLOWED_ACTIONS: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STRUT: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STRUT_PARTIAL: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ICON_GEOMETRY: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ICON: xcb::x::Atom,
|
||||||
|
pub _NET_WM_PID: xcb::x::Atom,
|
||||||
|
pub _NET_WM_HANDLED_ICONS: xcb::x::Atom,
|
||||||
|
pub _NET_WM_USER_TIME: xcb::x::Atom,
|
||||||
|
pub _NET_WM_USER_TIME_WINDOW: xcb::x::Atom,
|
||||||
|
pub _NET_FRAME_EXTENTS: xcb::x::Atom,
|
||||||
|
pub _NET_WM_PING: xcb::x::Atom,
|
||||||
|
pub _NET_WM_SYNC_REQUEST: xcb::x::Atom,
|
||||||
|
pub _NET_WM_SYNC_REQUEST_COUNTER: xcb::x::Atom,
|
||||||
|
pub _NET_WM_FULLSCREEN_MONITORS: xcb::x::Atom,
|
||||||
|
pub _NET_WM_FULL_PLACEMENT: xcb::x::Atom,
|
||||||
|
pub UTF8_STRING: xcb::x::Atom,
|
||||||
|
pub WM_PROTOCOLS: xcb::x::Atom,
|
||||||
|
pub MANAGER: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_DESKTOP: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_DOCK: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_TOOLBAR: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_MENU: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_UTILITY: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_SPLASH: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_DIALOG: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_DROPDOWN_MENU: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_POPUP_MENU: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_TOOLTIP: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_NOTIFICATION: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_COMBO: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_DND: xcb::x::Atom,
|
||||||
|
pub _NET_WM_WINDOW_TYPE_NORMAL: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_MODAL: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_STICKY: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_MAXIMIZED_VERT: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_MAXIMIZED_HORZ: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_SHADED: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_SKIP_TASKBAR: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_SKIP_PAGER: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_HIDDEN: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_FULLSCREEN: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_ABOVE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_BELOW: xcb::x::Atom,
|
||||||
|
pub _NET_WM_STATE_DEMANDS_ATTENTION: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_MOVE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_RESIZE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_MINIMIZE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_SHADE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_STICK: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_MAXIMIZE_HORZ: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_MAXIMIZE_VERT: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_FULLSCREEN: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_CHANGE_DESKTOP: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_CLOSE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_ABOVE: xcb::x::Atom,
|
||||||
|
pub _NET_WM_ACTION_BELOW: xcb::x::Atom
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Atoms {
|
||||||
|
pub (crate) fn intern(con: &xcb::Connection) -> Atoms {
|
||||||
|
let mut cookies: HashMap<&'static str, xcb::x::InternAtomCookie> = HashMap::new();
|
||||||
|
|
||||||
|
for atom in ATOM_NAMES {
|
||||||
|
let intern_atom = xcb::x::InternAtom {
|
||||||
|
only_if_exists: false,
|
||||||
|
name: atom.as_bytes(),
|
||||||
|
};
|
||||||
|
|
||||||
|
cookies.insert(atom, con.send_request(&intern_atom));
|
||||||
|
}
|
||||||
|
|
||||||
|
let interned_atoms: HashMap<&'static str, xcb::x::Atom> = cookies.into_iter()
|
||||||
|
.map(|(atom_name, cookie)| (atom_name, con.wait_for_reply(cookie).unwrap()))
|
||||||
|
.map(|(atom_name, reply)| (atom_name, reply.atom()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Atoms::from_interned_atoms(interned_atoms)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_interned_atoms(mut atoms: HashMap<&'static str, xcb::x::Atom>) -> Atoms {
|
||||||
|
Atoms {
|
||||||
|
_NET_SUPPORTED: atoms.remove("_NET_SUPPORTED").unwrap(),
|
||||||
|
_NET_CLIENT_LIST: atoms.remove("_NET_CLIENT_LIST").unwrap(),
|
||||||
|
_NET_CLIENT_LIST_STACKING: atoms.remove("_NET_CLIENT_LIST_STACKING").unwrap(),
|
||||||
|
_NET_NUMBER_OF_DESKTOPS: atoms.remove("_NET_NUMBER_OF_DESKTOPS").unwrap(),
|
||||||
|
_NET_DESKTOP_GEOMETRY: atoms.remove("_NET_DESKTOP_GEOMETRY").unwrap(),
|
||||||
|
_NET_DESKTOP_VIEWPORT: atoms.remove("_NET_DESKTOP_VIEWPORT").unwrap(),
|
||||||
|
_NET_CURRENT_DESKTOP: atoms.remove("_NET_CURRENT_DESKTOP").unwrap(),
|
||||||
|
_NET_DESKTOP_NAMES: atoms.remove("_NET_DESKTOP_NAMES").unwrap(),
|
||||||
|
_NET_ACTIVE_WINDOW: atoms.remove("_NET_ACTIVE_WINDOW").unwrap(),
|
||||||
|
_NET_WORKAREA: atoms.remove("_NET_WORKAREA").unwrap(),
|
||||||
|
_NET_SUPPORTING_WM_CHECK: atoms.remove("_NET_SUPPORTING_WM_CHECK").unwrap(),
|
||||||
|
_NET_VIRTUAL_ROOTS: atoms.remove("_NET_VIRTUAL_ROOTS").unwrap(),
|
||||||
|
_NET_DESKTOP_LAYOUT: atoms.remove("_NET_DESKTOP_LAYOUT").unwrap(),
|
||||||
|
_NET_SHOWING_DESKTOP: atoms.remove("_NET_SHOWING_DESKTOP").unwrap(),
|
||||||
|
_NET_CLOSE_WINDOW: atoms.remove("_NET_CLOSE_WINDOW").unwrap(),
|
||||||
|
_NET_MOVERESIZE_WINDOW: atoms.remove("_NET_MOVERESIZE_WINDOW").unwrap(),
|
||||||
|
_NET_WM_MOVERESIZE: atoms.remove("_NET_WM_MOVERESIZE").unwrap(),
|
||||||
|
_NET_RESTACK_WINDOW: atoms.remove("_NET_RESTACK_WINDOW").unwrap(),
|
||||||
|
_NET_REQUEST_FRAME_EXTENTS: atoms.remove("_NET_REQUEST_FRAME_EXTENTS").unwrap(),
|
||||||
|
_NET_WM_NAME: atoms.remove("_NET_WM_NAME").unwrap(),
|
||||||
|
_NET_WM_VISIBLE_NAME: atoms.remove("_NET_WM_VISIBLE_NAME").unwrap(),
|
||||||
|
_NET_WM_ICON_NAME: atoms.remove("_NET_WM_ICON_NAME").unwrap(),
|
||||||
|
_NET_WM_VISIBLE_ICON_NAME: atoms.remove("_NET_WM_VISIBLE_ICON_NAME").unwrap(),
|
||||||
|
_NET_WM_DESKTOP: atoms.remove("_NET_WM_DESKTOP").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE: atoms.remove("_NET_WM_WINDOW_TYPE").unwrap(),
|
||||||
|
_NET_WM_STATE: atoms.remove("_NET_WM_STATE").unwrap(),
|
||||||
|
_NET_WM_ALLOWED_ACTIONS: atoms.remove("_NET_WM_ALLOWED_ACTIONS").unwrap(),
|
||||||
|
_NET_WM_STRUT: atoms.remove("_NET_WM_STRUT").unwrap(),
|
||||||
|
_NET_WM_STRUT_PARTIAL: atoms.remove("_NET_WM_STRUT_PARTIAL").unwrap(),
|
||||||
|
_NET_WM_ICON_GEOMETRY: atoms.remove("_NET_WM_ICON_GEOMETRY").unwrap(),
|
||||||
|
_NET_WM_ICON: atoms.remove("_NET_WM_ICON").unwrap(),
|
||||||
|
_NET_WM_PID: atoms.remove("_NET_WM_PID").unwrap(),
|
||||||
|
_NET_WM_HANDLED_ICONS: atoms.remove("_NET_WM_HANDLED_ICONS").unwrap(),
|
||||||
|
_NET_WM_USER_TIME: atoms.remove("_NET_WM_USER_TIME").unwrap(),
|
||||||
|
_NET_WM_USER_TIME_WINDOW: atoms.remove("_NET_WM_USER_TIME_WINDOW").unwrap(),
|
||||||
|
_NET_FRAME_EXTENTS: atoms.remove("_NET_FRAME_EXTENTS").unwrap(),
|
||||||
|
_NET_WM_PING: atoms.remove("_NET_WM_PING").unwrap(),
|
||||||
|
_NET_WM_SYNC_REQUEST: atoms.remove("_NET_WM_SYNC_REQUEST").unwrap(),
|
||||||
|
_NET_WM_SYNC_REQUEST_COUNTER: atoms.remove("_NET_WM_SYNC_REQUEST_COUNTER").unwrap(),
|
||||||
|
_NET_WM_FULLSCREEN_MONITORS: atoms.remove("_NET_WM_FULLSCREEN_MONITORS").unwrap(),
|
||||||
|
_NET_WM_FULL_PLACEMENT: atoms.remove("_NET_WM_FULL_PLACEMENT").unwrap(),
|
||||||
|
UTF8_STRING: atoms.remove("UTF8_STRING").unwrap(),
|
||||||
|
WM_PROTOCOLS: atoms.remove("WM_PROTOCOLS").unwrap(),
|
||||||
|
MANAGER: atoms.remove("MANAGER").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_DESKTOP: atoms.remove("_NET_WM_WINDOW_TYPE_DESKTOP").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_DOCK: atoms.remove("_NET_WM_WINDOW_TYPE_DOCK").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_TOOLBAR: atoms.remove("_NET_WM_WINDOW_TYPE_TOOLBAR").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_MENU: atoms.remove("_NET_WM_WINDOW_TYPE_MENU").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_UTILITY: atoms.remove("_NET_WM_WINDOW_TYPE_UTILITY").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_SPLASH: atoms.remove("_NET_WM_WINDOW_TYPE_SPLASH").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_DIALOG: atoms.remove("_NET_WM_WINDOW_TYPE_DIALOG").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_DROPDOWN_MENU: atoms.remove("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_POPUP_MENU: atoms.remove("_NET_WM_WINDOW_TYPE_POPUP_MENU").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_TOOLTIP: atoms.remove("_NET_WM_WINDOW_TYPE_TOOLTIP").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_NOTIFICATION: atoms.remove("_NET_WM_WINDOW_TYPE_NOTIFICATION").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_COMBO: atoms.remove("_NET_WM_WINDOW_TYPE_COMBO").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_DND: atoms.remove("_NET_WM_WINDOW_TYPE_DND").unwrap(),
|
||||||
|
_NET_WM_WINDOW_TYPE_NORMAL: atoms.remove("_NET_WM_WINDOW_TYPE_NORMAL").unwrap(),
|
||||||
|
_NET_WM_STATE_MODAL: atoms.remove("_NET_WM_STATE_MODAL").unwrap(),
|
||||||
|
_NET_WM_STATE_STICKY: atoms.remove("_NET_WM_STATE_STICKY").unwrap(),
|
||||||
|
_NET_WM_STATE_MAXIMIZED_VERT: atoms.remove("_NET_WM_STATE_MAXIMIZED_VERT").unwrap(),
|
||||||
|
_NET_WM_STATE_MAXIMIZED_HORZ: atoms.remove("_NET_WM_STATE_MAXIMIZED_HORZ").unwrap(),
|
||||||
|
_NET_WM_STATE_SHADED: atoms.remove("_NET_WM_STATE_SHADED").unwrap(),
|
||||||
|
_NET_WM_STATE_SKIP_TASKBAR: atoms.remove("_NET_WM_STATE_SKIP_TASKBAR").unwrap(),
|
||||||
|
_NET_WM_STATE_SKIP_PAGER: atoms.remove("_NET_WM_STATE_SKIP_PAGER").unwrap(),
|
||||||
|
_NET_WM_STATE_HIDDEN: atoms.remove("_NET_WM_STATE_HIDDEN").unwrap(),
|
||||||
|
_NET_WM_STATE_FULLSCREEN: atoms.remove("_NET_WM_STATE_FULLSCREEN").unwrap(),
|
||||||
|
_NET_WM_STATE_ABOVE: atoms.remove("_NET_WM_STATE_ABOVE").unwrap(),
|
||||||
|
_NET_WM_STATE_BELOW: atoms.remove("_NET_WM_STATE_BELOW").unwrap(),
|
||||||
|
_NET_WM_STATE_DEMANDS_ATTENTION: atoms.remove("_NET_WM_STATE_DEMANDS_ATTENTION").unwrap(),
|
||||||
|
_NET_WM_ACTION_MOVE: atoms.remove("_NET_WM_ACTION_MOVE").unwrap(),
|
||||||
|
_NET_WM_ACTION_RESIZE: atoms.remove("_NET_WM_ACTION_RESIZE").unwrap(),
|
||||||
|
_NET_WM_ACTION_MINIMIZE: atoms.remove("_NET_WM_ACTION_MINIMIZE").unwrap(),
|
||||||
|
_NET_WM_ACTION_SHADE: atoms.remove("_NET_WM_ACTION_SHADE").unwrap(),
|
||||||
|
_NET_WM_ACTION_STICK: atoms.remove("_NET_WM_ACTION_STICK").unwrap(),
|
||||||
|
_NET_WM_ACTION_MAXIMIZE_HORZ: atoms.remove("_NET_WM_ACTION_MAXIMIZE_HORZ").unwrap(),
|
||||||
|
_NET_WM_ACTION_MAXIMIZE_VERT: atoms.remove("_NET_WM_ACTION_MAXIMIZE_VERT").unwrap(),
|
||||||
|
_NET_WM_ACTION_FULLSCREEN: atoms.remove("_NET_WM_ACTION_FULLSCREEN").unwrap(),
|
||||||
|
_NET_WM_ACTION_CHANGE_DESKTOP: atoms.remove("_NET_WM_ACTION_CHANGE_DESKTOP").unwrap(),
|
||||||
|
_NET_WM_ACTION_CLOSE: atoms.remove("_NET_WM_ACTION_CLOSE").unwrap(),
|
||||||
|
_NET_WM_ACTION_ABOVE: atoms.remove("_NET_WM_ACTION_ABOVE").unwrap(),
|
||||||
|
_NET_WM_ACTION_BELOW: atoms.remove("_NET_WM_ACTION_BELOW").unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
133
src/ewmh/ewmh.rs
Normal file
133
src/ewmh/ewmh.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
use xcb::x::{Atom, GetPropertyReply};
|
||||||
|
|
||||||
|
use crate::ewmh::proto_traits::{EwmhCookie, EwmhRequest};
|
||||||
|
|
||||||
|
use super::atoms::Atoms;
|
||||||
|
|
||||||
|
pub struct Connection<'a> {
|
||||||
|
pub(crate) con: &'a xcb::Connection,
|
||||||
|
pub atoms: Atoms,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Connection<'a> {
|
||||||
|
pub fn connect(xcb_con: &'a xcb::Connection) -> Connection<'a> {
|
||||||
|
Connection {
|
||||||
|
atoms: Atoms::intern(xcb_con),
|
||||||
|
con: xcb_con,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_client_message(
|
||||||
|
&self,
|
||||||
|
window: xcb::x::Window,
|
||||||
|
dest: xcb::x::Window,
|
||||||
|
atom: xcb::x::Atom,
|
||||||
|
data: xcb::x::ClientMessageData,
|
||||||
|
) -> xcb::VoidCookie {
|
||||||
|
let event = xcb::x::ClientMessageEvent::new(window, atom, data);
|
||||||
|
|
||||||
|
let request = xcb::x::SendEvent {
|
||||||
|
propagate: false,
|
||||||
|
destination: xcb::x::SendEventDest::Window(dest),
|
||||||
|
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||||
|
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||||
|
event: &event,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.con.send_request(&request)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_request<R: EwmhRequest>(&self, request: R) -> R::Cookie {
|
||||||
|
request.send_request(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_reply<C: EwmhCookie>(&self, cookie: C) -> C::Reply {
|
||||||
|
cookie.reply(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn supported_atoms_list() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetSupportedRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
|
||||||
|
for atom in reply.value {
|
||||||
|
let cookie = xcb_con.send_request(&xcb::x::GetAtomName { atom: atom });
|
||||||
|
|
||||||
|
println!("{}", xcb_con.wait_for_reply(cookie).unwrap().name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn client_list() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetClientListRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn number_of_desktops() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetNumberOfDesktopsRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desktop_geometry() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetDesktopGeometryRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desktop_viewport() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetDesktopViewportRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desktop_current() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetCurrentDesktopRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desktop_names() {
|
||||||
|
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||||
|
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||||
|
|
||||||
|
let request = crate::ewmh::proto::GetNetDesktopNamesRequest {};
|
||||||
|
let cookie = ewmh_con.send_request(request);
|
||||||
|
let reply = ewmh_con.wait_for_reply(cookie);
|
||||||
|
println!("{:?}", reply);
|
||||||
|
}
|
||||||
|
}
|
4
src/ewmh/mod.rs
Normal file
4
src/ewmh/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
mod ewmh;
|
||||||
|
mod atoms;
|
||||||
|
mod proto;
|
||||||
|
mod proto_traits;
|
228
src/ewmh/proto.rs
Normal file
228
src/ewmh/proto.rs
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
use crate::ewmh::ewmh::Connection;
|
||||||
|
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
|
||||||
|
use crate::{request, root_request};
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetSupportedRequest,
|
||||||
|
_NET_SUPPORTED,
|
||||||
|
ATOM_ATOM,
|
||||||
|
GetNetSupportedCookie,
|
||||||
|
GetNetSupportedCookieUnchecked,
|
||||||
|
GetNetSupportedReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetSupportedReply {
|
||||||
|
pub value: Vec<xcb::x::Atom>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetSupportedReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetSupportedReply {
|
||||||
|
value: reply.value().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetClientListRequest,
|
||||||
|
_NET_CLIENT_LIST,
|
||||||
|
ATOM_WINDOW,
|
||||||
|
GetNetClientListCookie,
|
||||||
|
GetNetClientListCookieUnchecked,
|
||||||
|
GetNetClientListReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetClientListReply {
|
||||||
|
pub value: Vec<xcb::x::Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetClientListReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetClientListReply {
|
||||||
|
value: reply.value().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetClientListStackingRequest,
|
||||||
|
_NET_CLIENT_LIST_STACKING,
|
||||||
|
ATOM_WINDOW,
|
||||||
|
GetNetClientListStackingCookie,
|
||||||
|
GetNetClientListStackingCookieUnchecked,
|
||||||
|
GetNetClientListStackingReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetClientListStackingReply {
|
||||||
|
pub value: Vec<xcb::x::Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetClientListStackingReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetClientListStackingReply {
|
||||||
|
value: reply.value().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetNumberOfDesktopsRequest,
|
||||||
|
_NET_NUMBER_OF_DESKTOPS,
|
||||||
|
ATOM_CARDINAL,
|
||||||
|
GetNetNumberOfDesktopsCookie,
|
||||||
|
GetNetNumberOfDesktopsCookieUnchecked,
|
||||||
|
GetNetNumberOfDesktopsReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetNumberOfDesktopsReply {
|
||||||
|
pub value: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetNumberOfDesktopsReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetNumberOfDesktopsReply {
|
||||||
|
value: reply.value::<u32>()[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetDesktopGeometryRequest,
|
||||||
|
_NET_DESKTOP_GEOMETRY,
|
||||||
|
ATOM_CARDINAL,
|
||||||
|
GetNetDesktopGeometryCookie,
|
||||||
|
GetNetDesktopGeometryCookieUnchecked,
|
||||||
|
GetNetDesktopGeometryReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetDesktopGeometryReply {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetDesktopGeometryReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetDesktopGeometryReply {
|
||||||
|
width: reply.value::<u32>()[0],
|
||||||
|
height: reply.value::<u32>()[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetDesktopViewportRequest,
|
||||||
|
_NET_DESKTOP_VIEWPORT,
|
||||||
|
ATOM_CARDINAL,
|
||||||
|
GetNetDesktopViewportCookie,
|
||||||
|
GetNetDesktopViewportCookieUnchecked,
|
||||||
|
GetNetDesktopViewportReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetDesktopViewportReply {
|
||||||
|
pub x: u32,
|
||||||
|
pub y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetDesktopViewportReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetDesktopViewportReply {
|
||||||
|
x: reply.value::<u32>()[0],
|
||||||
|
y: reply.value::<u32>()[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetCurrentDesktopRequest,
|
||||||
|
_NET_CURRENT_DESKTOP,
|
||||||
|
ATOM_CARDINAL,
|
||||||
|
GetNetCurrentDesktopCookie,
|
||||||
|
GetNetCurrentDesktopCookieUnchecked,
|
||||||
|
GetNetCurrentDesktopReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetCurrentDesktopReply {
|
||||||
|
pub desktop: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetCurrentDesktopReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetCurrentDesktopReply {
|
||||||
|
desktop: reply.value::<u32>()[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request! {
|
||||||
|
GetNetDesktopNamesRequest,
|
||||||
|
GetNetDesktopNamesCookie,
|
||||||
|
GetNetDesktopNamesCookieUnchecked,
|
||||||
|
GetNetDesktopNamesReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetDesktopNamesReply {
|
||||||
|
pub value: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhRequestData for GetNetDesktopNamesRequest {
|
||||||
|
fn get_request_data(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||||
|
property: con.atoms._NET_DESKTOP_NAMES,
|
||||||
|
r#type: con.atoms.UTF8_STRING,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetDesktopNamesReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
let mut vals = vec![];
|
||||||
|
let mut buf = vec![];
|
||||||
|
|
||||||
|
for b in reply.value::<u8>() {
|
||||||
|
if *b != 0x00 {
|
||||||
|
buf.push(*b)
|
||||||
|
} else if !buf.is_empty() {
|
||||||
|
vals.push(String::from_utf8(buf.clone()).unwrap());
|
||||||
|
buf.clear();
|
||||||
|
} else {
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetNetDesktopNamesReply { value: vals }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_request! {
|
||||||
|
GetNetActiveWindowRequest,
|
||||||
|
_NET_ACTIVE_WINDOW,
|
||||||
|
ATOM_WINDOW,
|
||||||
|
GetNetActiveWindowCookie,
|
||||||
|
GetNetActiveWindowCookieUnchecked,
|
||||||
|
GetNetActiveWindowReply
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetNetActiveWindowReply {
|
||||||
|
pub value: xcb::x::Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xcb::x::GetPropertyReply> for GetNetActiveWindowReply {
|
||||||
|
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||||
|
GetNetActiveWindowReply {
|
||||||
|
value: reply.value::<xcb::x::Window>()[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
src/ewmh/proto_traits.rs
Normal file
93
src/ewmh/proto_traits.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::ewmh::ewmh::Connection;
|
||||||
|
|
||||||
|
pub(crate) trait EwmhRequest: EwmhRequestData {
|
||||||
|
type Cookie;
|
||||||
|
type CookieUnchecked;
|
||||||
|
|
||||||
|
fn send_request(&self, con: &Connection) -> Self::Cookie;
|
||||||
|
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait EwmhRequestData {
|
||||||
|
fn get_request_data(&self, con: &Connection) -> xcb::x::GetProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait EwmhCookie {
|
||||||
|
type Reply: From<xcb::x::GetPropertyReply>;
|
||||||
|
fn reply(self, con: &Connection) -> Self::Reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait EwmhCookieUnchecked {
|
||||||
|
type Reply;
|
||||||
|
fn reply(self, con: &Connection) -> Option<Self::Reply>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! request {
|
||||||
|
($req: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||||
|
pub struct $req {}
|
||||||
|
pub struct $cookie {
|
||||||
|
cookie: xcb::x::GetPropertyCookie,
|
||||||
|
}
|
||||||
|
pub struct $cookie_unchecked {
|
||||||
|
cookie: xcb::x::GetPropertyCookieUnchecked,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhRequest for $req {
|
||||||
|
type Cookie = $cookie;
|
||||||
|
type CookieUnchecked = $cookie_unchecked;
|
||||||
|
|
||||||
|
fn send_request(&self, con: &Connection) -> Self::Cookie {
|
||||||
|
$cookie {
|
||||||
|
cookie: con.con.send_request(&self.get_request_data(con)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
|
||||||
|
$cookie_unchecked {
|
||||||
|
cookie: con.con.send_request_unchecked(&self.get_request_data(con)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhCookie for $cookie {
|
||||||
|
type Reply = $reply;
|
||||||
|
|
||||||
|
fn reply(self, con: &Connection) -> Self::Reply {
|
||||||
|
let reply = con.con.wait_for_reply(self.cookie).unwrap();
|
||||||
|
reply.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EwmhCookieUnchecked for $cookie_unchecked {
|
||||||
|
type Reply = $reply;
|
||||||
|
|
||||||
|
fn reply(self, con: &Connection) -> Option<Self::Reply> {
|
||||||
|
con.con
|
||||||
|
.wait_for_reply_unchecked(self.cookie)
|
||||||
|
.unwrap()
|
||||||
|
.map(|reply| reply.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! root_request {
|
||||||
|
($req: ident, $prop: ident, $type: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||||
|
request! {$req, $cookie, $cookie_unchecked, $reply}
|
||||||
|
|
||||||
|
impl EwmhRequestData for $req {
|
||||||
|
fn get_request_data(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||||
|
xcb::x::GetProperty {
|
||||||
|
delete: false,
|
||||||
|
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||||
|
property: con.atoms.$prop,
|
||||||
|
r#type: xcb::x::$type,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: u32::MAX,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
10
src/lib.rs
Normal file
10
src/lib.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
mod ewmh;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = 2 + 2;
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue