Refactor and simplify traits, rename to xcb-wm
This commit is contained in:
parent
0980df1e2b
commit
fe183b4c4b
12 changed files with 960 additions and 778 deletions
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "rust-xcb-wm"
|
||||
name = "xcb-wm"
|
||||
version = "0.1.0"
|
||||
authors = [ "Armin Friedl <dev@friedl.net>" ]
|
||||
description = "Rust implementation of xcb-wm - icccm and ewmh extensions for xcb"
|
||||
|
@ -7,8 +7,8 @@ readme = "README.md"
|
|||
keywords = ["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"
|
||||
repository = "https://git.friedl.net/incubator/xcb-wm"
|
||||
homepage = "https://git.friedl.net/incubator/xcb-wm"
|
||||
|
||||
[dependencies]
|
||||
xcb = "1"
|
||||
|
|
|
@ -85,6 +85,12 @@ const ATOM_NAMES: [&str; 82] = [
|
|||
"_NET_WM_ACTION_BELOW",
|
||||
];
|
||||
|
||||
/// Interned [`xcb::x::Atom`]s for the `ewmh` protocol
|
||||
///
|
||||
/// The ids for these atoms are created when the [`crate::ewmh::Connection`] is established. Hence,
|
||||
/// are bound to the [`crate::ewmh::Connection`] and can only be retrieved from there.
|
||||
///
|
||||
/// See also: [`wm spec 1.5`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5)
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Atoms {
|
||||
// TODO _NET_WM_CM_Sn atoms
|
||||
|
|
468
src/ewmh/connection.rs
Normal file
468
src/ewmh/connection.rs
Normal file
|
@ -0,0 +1,468 @@
|
|||
use crate::ewmh::atoms::Atoms;
|
||||
use crate::ewmh::traits::{
|
||||
EwmhPropertyCookieChecked, EwmhPropertyCookieUnchecked, EwmhPropertyRequestUnchecked,
|
||||
EwmhRequest, EwmhVoidRequestChecked,
|
||||
};
|
||||
|
||||
/// The main `ewmh` entry point
|
||||
///
|
||||
/// `Connection` is a thin wrapper around [`xcb::Connection`]. It provides a
|
||||
/// subset of the [`xcb::Connection`] API covering the functionality needed for
|
||||
/// `ewmh`.
|
||||
///
|
||||
/// The provided subset works the same as the corresponding API in
|
||||
/// [`xcb::Connection`]. That is, methods with the same name do the same thing.
|
||||
/// The general usage pattern is the same for both crates.
|
||||
///
|
||||
/// This wrapper is needed because `ewmh` has to prepare the `Connection` for
|
||||
/// `ewmh` requests and store additional data on it. Concretely, this mostly
|
||||
/// means interning atoms.
|
||||
pub struct Connection<'a> {
|
||||
pub(crate) con: &'a xcb::Connection,
|
||||
|
||||
/// Interned [`Atoms`] for the `ewmh` protocol
|
||||
pub atoms: Atoms,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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_request<'b, R>(&self, request: &'b R) -> R::EwmhCookie
|
||||
where
|
||||
R: EwmhRequest<'b>,
|
||||
{
|
||||
request.send(self)
|
||||
}
|
||||
|
||||
fn send_request_checked<'b, R>(&self, request: &'b R) -> xcb::VoidCookieChecked
|
||||
where
|
||||
R: EwmhVoidRequestChecked<'b>,
|
||||
{
|
||||
request.send(self)
|
||||
}
|
||||
|
||||
fn send_request_unchecked<R>(&self, request: &R) -> R::EwmhCookie
|
||||
where
|
||||
R: EwmhPropertyRequestUnchecked,
|
||||
{
|
||||
request.send(self)
|
||||
}
|
||||
|
||||
fn wait_for_reply<C>(&self, cookie: C) -> C::Reply
|
||||
where
|
||||
C: EwmhPropertyCookieChecked,
|
||||
{
|
||||
let xcb_reply = self.con.wait_for_reply(cookie.inner());
|
||||
xcb_reply.unwrap().into()
|
||||
}
|
||||
|
||||
fn wait_for_reply_unchecked<C>(&self, cookie: C) -> C::Reply
|
||||
where
|
||||
C: EwmhPropertyCookieUnchecked,
|
||||
{
|
||||
let xcb_reply = self.con.wait_for_reply_unchecked(cookie.inner());
|
||||
xcb_reply.unwrap().unwrap().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn supported_atoms_list() {
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let request = crate::ewmh::GetSupported;
|
||||
let cookie = ewmh_con.send_request(&request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
|
||||
for atom in reply.atoms {
|
||||
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::GetClientList::new();
|
||||
// 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::GetNumberOfDesktops::new();
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_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::SetNumberOfDesktops::new(4);
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn number_of_desktops2() {
|
||||
// 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::GetNumberOfDesktops::new();
|
||||
// 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::GetNumberOfDesktops {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_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::SetDesktopGeometry::new(1024, 800);
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(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::GetDesktopViewport {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_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::SetDesktopViewport::new(200, 200);
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn desktop_viewport2() {
|
||||
// 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::GetDesktopViewport {};
|
||||
// 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::GetCurrentDesktop {};
|
||||
// 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::Connection::connect(&xcb_con);
|
||||
|
||||
let request = crate::ewmh::GetDesktopNames {};
|
||||
let cookie = ewmh_con.send_request(&request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_desktop_names() {
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let request = crate::ewmh::SetDesktopNames::new(vec!["X", "Y", "Z"]);
|
||||
let cookie = ewmh_con.send_request_checked(&request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
//
|
||||
// #[test]
|
||||
// fn set_active_window() {
|
||||
// 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::GetClientList {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
//
|
||||
// let request = crate::ewmh::proto::SetActiveWindow::new(
|
||||
// &ewmh_con,
|
||||
// reply.clients.last().unwrap().to_owned(),
|
||||
// 1,
|
||||
// xcb::x::CURRENT_TIME,
|
||||
// Option::None,
|
||||
// );
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// xcb_con.check_request(cookie).unwrap();
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn workarea() {
|
||||
// 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::GetWorkarea {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn supporting_wm_check() {
|
||||
// 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::GetSupportingWmCheck {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn virtual_roots() {
|
||||
// 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::GetVirtualRoots {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn desktop_layout() {
|
||||
// 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::GetDesktopLayout {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn showing_desktop() {
|
||||
// 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::GetShowingDesktop {};
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
#[test]
|
||||
fn set_showing_desktop() {
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let request = crate::ewmh::SetShowingDesktop::new(&ewmh_con, true);
|
||||
let cookie = ewmh_con.send_request_checked(&request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn close_window() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20979719) };
|
||||
//
|
||||
// let request =
|
||||
// crate::ewmh::proto::CloseWindow::new(&ewmh_con, window, 0, xcb::x::CURRENT_TIME);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn request_frame_extents() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20979719) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::RequestFrameExtents::new(&ewmh_con, window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn wm_name() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(77594744) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetWmName::new(window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn wm_visible_name() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20983603) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetWmVisibleName::new(window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn wm_desktop() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20983603) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetWmDesktop::new(window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_wm_type() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20995834) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::SetWmWindowType::new(
|
||||
// window,
|
||||
// vec![
|
||||
// ewmh_con.atoms._NET_WM_WINDOW_TYPE_UTILITY,
|
||||
// ewmh_con.atoms._NET_WM_WINDOW_TYPE_SPLASH,
|
||||
// ],
|
||||
// );
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn get_wm_type() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(20995834) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetWmWindowType::new(window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn set_wm_state() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(21002424) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::SetWmState::new(
|
||||
// window,
|
||||
// vec![
|
||||
// ewmh_con.atoms._NET_WM_STATE_STICKY,
|
||||
// ewmh_con.atoms._NET_WM_STATE_DEMANDS_ATTENTION,
|
||||
// ],
|
||||
// );
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = xcb_con.check_request(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn get_wm_state() {
|
||||
// use xcb::XidNew;
|
||||
//
|
||||
// let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
// let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
//
|
||||
// let window = unsafe { xcb::x::Window::new(21002424) };
|
||||
//
|
||||
// let request = crate::ewmh::proto::GetWmWindowType::new(window);
|
||||
//
|
||||
// let cookie = ewmh_con.send_request(request);
|
||||
// let reply = ewmh_con.wait_for_reply(cookie);
|
||||
// println!("{:?}", reply);
|
||||
// }
|
||||
}
|
431
src/ewmh/ewmh.rs
431
src/ewmh/ewmh.rs
|
@ -1,431 +0,0 @@
|
|||
use crate::ewmh::proto_traits::{EwmhCookie, EwmhRequest};
|
||||
|
||||
use super::atoms::Atoms;
|
||||
|
||||
pub struct Connection<'a> {
|
||||
pub(crate) con: &'a xcb::Connection,
|
||||
pub atoms: Atoms,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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<'a>>(&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::GetSupported::new();
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
|
||||
for atom in reply.atoms {
|
||||
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::GetClientList::new();
|
||||
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::GetNumberOfDesktops::new();
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_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::SetNumberOfDesktops::new(4);
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_of_desktops2() {
|
||||
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::GetNumberOfDesktops::new();
|
||||
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::GetNumberOfDesktops {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_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::SetDesktopGeometry::new(1024, 800);
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(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::GetDesktopViewport {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_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::SetDesktopViewport::new(200, 200);
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desktop_viewport2() {
|
||||
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::GetDesktopViewport {};
|
||||
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::GetCurrentDesktop {};
|
||||
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::GetDesktopNames {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_active_window() {
|
||||
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::GetClientList {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
|
||||
let request = crate::ewmh::proto::SetActiveWindow::new(
|
||||
&ewmh_con,
|
||||
reply.clients.last().unwrap().to_owned(),
|
||||
1,
|
||||
xcb::x::CURRENT_TIME,
|
||||
Option::None,
|
||||
);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
xcb_con.check_request(cookie).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workarea() {
|
||||
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::GetWorkarea {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supporting_wm_check() {
|
||||
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::GetSupportingWmCheck {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn virtual_roots() {
|
||||
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::GetVirtualRoots {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desktop_layout() {
|
||||
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::GetDesktopLayout {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn showing_desktop() {
|
||||
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::GetShowingDesktop {};
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_showing_desktop() {
|
||||
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::SetShowingDesktop::new(&ewmh_con, true);
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_window() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20979719) };
|
||||
|
||||
let request =
|
||||
crate::ewmh::proto::CloseWindow::new(&ewmh_con, window, 0, xcb::x::CURRENT_TIME);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_frame_extents() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20979719) };
|
||||
|
||||
let request = crate::ewmh::proto::RequestFrameExtents::new(&ewmh_con, window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wm_name() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(77594744) };
|
||||
|
||||
let request = crate::ewmh::proto::GetWmName::new(window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wm_visible_name() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20983603) };
|
||||
|
||||
let request = crate::ewmh::proto::GetWmVisibleName::new(window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wm_desktop() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20983603) };
|
||||
|
||||
let request = crate::ewmh::proto::GetWmDesktop::new(window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_wm_type() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20995834) };
|
||||
|
||||
let request = crate::ewmh::proto::SetWmWindowType::new(
|
||||
window,
|
||||
vec![
|
||||
ewmh_con.atoms._NET_WM_WINDOW_TYPE_UTILITY,
|
||||
ewmh_con.atoms._NET_WM_WINDOW_TYPE_SPLASH,
|
||||
],
|
||||
);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_wm_type() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(20995834) };
|
||||
|
||||
let request = crate::ewmh::proto::GetWmWindowType::new(window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_wm_state() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(21002424) };
|
||||
|
||||
let request = crate::ewmh::proto::SetWmState::new(
|
||||
window,
|
||||
vec![
|
||||
ewmh_con.atoms._NET_WM_STATE_STICKY,
|
||||
ewmh_con.atoms._NET_WM_STATE_DEMANDS_ATTENTION,
|
||||
],
|
||||
);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = xcb_con.check_request(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_wm_state() {
|
||||
use xcb::XidNew;
|
||||
|
||||
let xcb_con = xcb::Connection::connect(Option::None).unwrap().0;
|
||||
let ewmh_con = crate::ewmh::ewmh::Connection::connect(&xcb_con);
|
||||
|
||||
let window = unsafe { xcb::x::Window::new(21002424) };
|
||||
|
||||
let request = crate::ewmh::proto::GetWmWindowType::new(window);
|
||||
|
||||
let cookie = ewmh_con.send_request(request);
|
||||
let reply = ewmh_con.wait_for_reply(cookie);
|
||||
println!("{:?}", reply);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
#[macro_use]
|
||||
mod proto_traits;
|
||||
mod traits;
|
||||
|
||||
mod atoms;
|
||||
mod ewmh;
|
||||
mod connection;
|
||||
mod proto;
|
||||
|
||||
pub use atoms::Atoms;
|
||||
pub use connection::Connection;
|
||||
|
||||
pub use proto::net_desktop_names::*;
|
||||
pub use proto::net_showing_desktop::*;
|
||||
pub use proto::net_supported::*;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Application Window Properties
|
||||
//!
|
||||
//! see: https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048
|
||||
//! see: <https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45446104426048>
|
||||
|
||||
use xcb::{Xid, XidNew};
|
||||
|
||||
use crate::ewmh::ewmh::Connection;
|
||||
use crate::ewmh::connection::Connection;
|
||||
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
|
||||
|
||||
// _NET_WM_NAME, UTF8_STRING
|
||||
|
@ -204,14 +204,13 @@ pub struct GetWmWindowTypeReply {
|
|||
impl From<xcb::x::GetPropertyReply> for GetWmWindowTypeReply {
|
||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
GetWmWindowTypeReply {
|
||||
types: reply.value::<xcb::x::Atom>().into()
|
||||
types: reply.value::<xcb::x::Atom>().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
// _NET_WM_STATE, ATOM[]/32
|
||||
// {{{
|
||||
|
||||
|
@ -252,7 +251,7 @@ pub struct GetWmStateReply {
|
|||
impl From<xcb::x::GetPropertyReply> for GetWmStateReply {
|
||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
GetWmStateReply {
|
||||
types: reply.value::<xcb::x::Atom>().into()
|
||||
types: reply.value::<xcb::x::Atom>().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
mod application_props;
|
||||
#[allow(unused)]
|
||||
mod root_props;
|
||||
// mod application_props;
|
||||
// #[allow(unused)]
|
||||
// mod root_props;
|
||||
//
|
||||
// pub use application_props::*;
|
||||
// pub use root_props::*;
|
||||
|
||||
pub use application_props::*;
|
||||
pub use root_props::*;
|
||||
mod test_props;
|
||||
pub(crate) use test_props::*;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Root Window Properties (and Related Messages)
|
||||
//!
|
||||
//! see: https://specifications.freedesktop.org/wm-spec/1.5/ar01s03.html#idm45539547193552
|
||||
//! see: <https://specifications.freedesktop.org/wm-spec/1.5/ar01s03.html#idm45539547193552>
|
||||
|
||||
use xcb::{Xid, XidNew};
|
||||
|
||||
use crate::ewmh::ewmh::Connection;
|
||||
use crate::ewmh::connection::Connection;
|
||||
use crate::ewmh::proto_traits::{EwmhCookie, EwmhCookieUnchecked, EwmhRequest, EwmhRequestData};
|
||||
|
||||
// _NET_SUPPORTED, ATOM[]/32
|
||||
|
|
300
src/ewmh/proto/test_props.rs
Normal file
300
src/ewmh/proto/test_props.rs
Normal file
|
@ -0,0 +1,300 @@
|
|||
pub(crate) mod net_supported {
|
||||
use crate::ewmh::traits::*;
|
||||
use crate::ewmh::Connection;
|
||||
|
||||
pub struct GetSupported;
|
||||
|
||||
pub struct GetSupportedCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetSupportedCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetSupportedReply {
|
||||
pub atoms: Vec<xcb::x::Atom>,
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> for GetSupported {
|
||||
type XcbRequest = xcb::x::GetProperty;
|
||||
type EwmhCookie = GetSupportedCookie;
|
||||
|
||||
fn xcb_request(&self, con: &Connection) -> Self::XcbRequest {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms._NET_SUPPORTED,
|
||||
r#type: xcb::x::ATOM_ATOM,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_cookie(&'a self, xcb_cookie: xcb::x::GetPropertyCookie) -> Self::EwmhCookie {
|
||||
GetSupportedCookie(xcb_cookie)
|
||||
}
|
||||
}
|
||||
|
||||
impl EwmhPropertyRequestUnchecked for GetSupported {
|
||||
type EwmhCookie = GetSupportedCookieUnchecked;
|
||||
|
||||
fn convert_cookie(
|
||||
&self,
|
||||
xcb_cookie: xcb::x::GetPropertyCookieUnchecked,
|
||||
) -> Self::EwmhCookie {
|
||||
GetSupportedCookieUnchecked(xcb_cookie)
|
||||
}
|
||||
|
||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms._NET_SUPPORTED,
|
||||
r#type: xcb::x::ATOM_ATOM,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EwmhCookie for GetSupportedCookie {
|
||||
type XcbCookie = xcb::x::GetPropertyCookie;
|
||||
}
|
||||
|
||||
impl EwmhPropertyCookieChecked for GetSupportedCookie {
|
||||
type Reply = GetSupportedReply;
|
||||
|
||||
fn inner(self) -> xcb::x::GetPropertyCookie {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EwmhPropertyCookieUnchecked for GetSupportedCookieUnchecked {
|
||||
type Reply = GetSupportedReply;
|
||||
|
||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<xcb::x::GetPropertyReply> for GetSupportedReply {
|
||||
fn from(reply: xcb::x::GetPropertyReply) -> Self {
|
||||
GetSupportedReply {
|
||||
atoms: reply.value().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod net_desktop_names {
|
||||
use crate::ewmh::traits::*;
|
||||
use crate::ewmh::Connection;
|
||||
|
||||
pub struct GetDesktopNames;
|
||||
|
||||
pub struct GetDesktopNamesCookie(xcb::x::GetPropertyCookie);
|
||||
|
||||
pub struct GetDesktopNamesCookieUnchecked(xcb::x::GetPropertyCookieUnchecked);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetDesktopNamesReply {
|
||||
pub desktop_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> for GetDesktopNames {
|
||||
type XcbRequest = xcb::x::GetProperty;
|
||||
type EwmhCookie = GetDesktopNamesCookie;
|
||||
|
||||
fn xcb_request(&self, con: &Connection) -> Self::XcbRequest {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_cookie(&'a self, xcb_cookie: xcb::x::GetPropertyCookie) -> Self::EwmhCookie {
|
||||
GetDesktopNamesCookie(xcb_cookie)
|
||||
}
|
||||
}
|
||||
|
||||
impl EwmhPropertyRequestUnchecked for GetDesktopNames {
|
||||
type EwmhCookie = GetDesktopNamesCookieUnchecked;
|
||||
|
||||
fn convert_cookie(
|
||||
&self,
|
||||
xcb_cookie: xcb::x::GetPropertyCookieUnchecked,
|
||||
) -> Self::EwmhCookie {
|
||||
GetDesktopNamesCookieUnchecked(xcb_cookie)
|
||||
}
|
||||
|
||||
fn xcb_request(&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 EwmhCookie for GetDesktopNamesCookie {
|
||||
type XcbCookie = xcb::x::GetPropertyCookie;
|
||||
}
|
||||
|
||||
impl EwmhPropertyCookieChecked for GetDesktopNamesCookie {
|
||||
type Reply = GetDesktopNamesReply;
|
||||
|
||||
fn inner(self) -> xcb::x::GetPropertyCookie {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EwmhPropertyCookieUnchecked for GetDesktopNamesCookieUnchecked {
|
||||
type Reply = GetDesktopNamesReply;
|
||||
|
||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<xcb::x::GetPropertyReply> for GetDesktopNamesReply {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
GetDesktopNamesReply {
|
||||
desktop_names: vals,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetDesktopNames {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SetDesktopNames {
|
||||
pub fn new(names: Vec<&str>) -> SetDesktopNames {
|
||||
let mut data: Vec<u8> = vec![];
|
||||
|
||||
// flatten `new_names` into a continuous array of bytes
|
||||
for name in names {
|
||||
let mut bname = name.as_bytes().to_owned();
|
||||
bname.push(0b00);
|
||||
data.extend(bname)
|
||||
}
|
||||
|
||||
SetDesktopNames { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> for SetDesktopNames {
|
||||
type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
|
||||
type EwmhCookie = xcb::VoidCookie;
|
||||
|
||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms._NET_DESKTOP_NAMES,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
data: &self.data,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
|
||||
xcb_cookie
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhVoidRequestChecked<'a> for SetDesktopNames {
|
||||
type XcbRequest = xcb::x::ChangeProperty<'a, u8>;
|
||||
|
||||
fn xcb_request(&'a self, con: &Connection) -> xcb::x::ChangeProperty<'a, u8> {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms._NET_DESKTOP_NAMES,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
data: &self.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod net_showing_desktop {
|
||||
use crate::ewmh::traits::*;
|
||||
use crate::ewmh::Connection;
|
||||
|
||||
pub struct SetShowingDesktop {
|
||||
client_message: xcb::x::ClientMessageEvent,
|
||||
}
|
||||
|
||||
impl SetShowingDesktop {
|
||||
pub fn new(connection: &Connection, show_desktop: bool) -> SetShowingDesktop {
|
||||
let data = match show_desktop {
|
||||
false => 0 as u32,
|
||||
true => 1 as u32,
|
||||
};
|
||||
|
||||
let client_message = xcb::x::ClientMessageEvent::new(
|
||||
connection.con.get_setup().roots().next().unwrap().root(),
|
||||
connection.atoms._NET_SHOWING_DESKTOP,
|
||||
xcb::x::ClientMessageData::Data32([data, 0x00, 0x00, 0x00, 0x00]),
|
||||
);
|
||||
|
||||
SetShowingDesktop { client_message }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> for SetShowingDesktop {
|
||||
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
||||
type EwmhCookie = xcb::VoidCookie;
|
||||
|
||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
||||
xcb::x::SendEvent {
|
||||
propagate: false,
|
||||
destination: xcb::x::SendEventDest::Window(
|
||||
con.con.get_setup().roots().next().unwrap().root(),
|
||||
),
|
||||
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||
event: &self.client_message,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_cookie(&'a self, xcb_cookie: xcb::VoidCookie) -> Self::EwmhCookie {
|
||||
xcb_cookie
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhVoidRequestChecked<'a> for SetShowingDesktop {
|
||||
type XcbRequest = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>;
|
||||
|
||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest {
|
||||
xcb::x::SendEvent {
|
||||
propagate: false,
|
||||
destination: xcb::x::SendEventDest::Window(
|
||||
con.con.get_setup().roots().next().unwrap().root(),
|
||||
),
|
||||
event_mask: xcb::x::EventMask::SUBSTRUCTURE_NOTIFY
|
||||
| xcb::x::EventMask::SUBSTRUCTURE_REDIRECT,
|
||||
event: &self.client_message,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,329 +0,0 @@
|
|||
use crate::ewmh::ewmh::Connection;
|
||||
|
||||
pub(crate) trait EwmhRequest<'a>: EwmhRequestData<'a> {
|
||||
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<'a> {
|
||||
type Request: xcb::Request;
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request;
|
||||
}
|
||||
|
||||
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_rules! ewmh_get_window_request_private {
|
||||
($req: ident, $prop: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
pub struct $req {
|
||||
window: xcb::x::Window,
|
||||
}
|
||||
|
||||
pub struct $cookie {
|
||||
cookie: xcb::x::GetPropertyCookie,
|
||||
}
|
||||
pub struct $cookie_unchecked {
|
||||
cookie: xcb::x::GetPropertyCookieUnchecked,
|
||||
}
|
||||
|
||||
impl $req {
|
||||
pub fn new(window: xcb::x::Window) -> $req {
|
||||
$req { window }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> 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_rules! ewmh_get_window_request {
|
||||
($req: ident, $prop: ident, UTF8_STRING, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::GetProperty;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: self.window,
|
||||
property: con.atoms.$prop,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($req: ident, $prop: ident, CARDINAL, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::GetProperty;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: self.window,
|
||||
property: con.atoms.$prop,
|
||||
r#type: xcb::x::ATOM_CARDINAL,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($req: ident, $prop: ident, ATOM, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
ewmh_get_window_request_private! {$req, $prop, $cookie, $cookie_unchecked, $reply}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::GetProperty;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: self.window,
|
||||
property: con.atoms.$prop,
|
||||
r#type: xcb::x::ATOM_ATOM,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
macro_rules! ewmh_set_window_request {
|
||||
($req: ident, $prop: ident, $type: tt) => {
|
||||
impl<'a> EwmhRequest<'a> for $req {
|
||||
type Cookie = xcb::VoidCookieChecked;
|
||||
type CookieUnchecked = xcb::VoidCookie;
|
||||
|
||||
fn send_request(&self, con: &Connection) -> Self::Cookie {
|
||||
con.con.send_request_checked(&self.get_request_data(con))
|
||||
}
|
||||
|
||||
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
|
||||
con.con.send_request(&self.get_request_data(con))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::ChangeProperty<'a, xcb::x::Atom>;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: self.window,
|
||||
property: con.atoms.$prop,
|
||||
r#type: $type,
|
||||
data: &self.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! ewmh_get_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 $req {
|
||||
pub fn new() -> $req {
|
||||
$req {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequest<'a> 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_rules! ewmh_get_root_request {
|
||||
($req: ident, $prop: ident, UTF8_STRING, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
ewmh_get_request! {$req, $cookie, $cookie_unchecked, $reply}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::GetProperty;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::GetProperty {
|
||||
delete: false,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms.$prop,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
long_offset: 0,
|
||||
long_length: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($req: ident, $prop: ident, $type: ident, $cookie: ident, $cookie_unchecked: ident, $reply: ident) => {
|
||||
ewmh_get_request! {$req, $cookie, $cookie_unchecked, $reply}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::GetProperty;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! ewmh_set_root_request {
|
||||
($req: ident, $prop: ident, UTF8_STRING) => {
|
||||
impl<'a> EwmhRequest<'a> for $req {
|
||||
type Cookie = xcb::VoidCookieChecked;
|
||||
type CookieUnchecked = xcb::VoidCookie;
|
||||
|
||||
fn send_request(&self, con: &Connection) -> Self::Cookie {
|
||||
con.con.send_request_checked(&self.get_request_data(con))
|
||||
}
|
||||
|
||||
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
|
||||
con.con.send_request(&self.get_request_data(con))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::ChangeProperty<'a, u8>;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms.$prop,
|
||||
r#type: con.atoms.UTF8_STRING,
|
||||
data: self.data.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($req: ident, $prop: ident, $type: ident) => {
|
||||
impl<'a> EwmhRequest<'a> for $req {
|
||||
type Cookie = xcb::VoidCookieChecked;
|
||||
type CookieUnchecked = xcb::VoidCookie;
|
||||
|
||||
fn send_request(&self, con: &Connection) -> Self::Cookie {
|
||||
con.con.send_request_checked(&self.get_request_data(con))
|
||||
}
|
||||
|
||||
fn send_request_unchecked(&self, con: &Connection) -> Self::CookieUnchecked {
|
||||
con.con.send_request(&self.get_request_data(con))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EwmhRequestData<'a> for $req {
|
||||
type Request = xcb::x::ChangeProperty<'a, u32>;
|
||||
|
||||
fn get_request_data(&'a self, con: &Connection) -> Self::Request {
|
||||
xcb::x::ChangeProperty {
|
||||
mode: xcb::x::PropMode::Replace,
|
||||
window: con.con.get_setup().roots().next().unwrap().root(),
|
||||
property: con.atoms.$prop,
|
||||
r#type: xcb::x::$type,
|
||||
data: &self.data,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
156
src/ewmh/traits.rs
Normal file
156
src/ewmh/traits.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
use crate::ewmh::connection::Connection;
|
||||
|
||||
/// Default for a request sent by [`Connection::send_request`]
|
||||
///
|
||||
/// For `GetProperty` request (i.e. requests that expect a reply) this is usually
|
||||
/// a checked request.
|
||||
/// For `SetProperty` and `ClientMessage` requests (i.e. requests that expect void/no reply) this
|
||||
/// is usually an unchecked request.
|
||||
///
|
||||
/// This is a bit mind-bending and makes these traits hard to grasp. This was however done to align
|
||||
/// with how the parent [`xcb`] crate works.
|
||||
pub(crate) trait EwmhRequest<'a> {
|
||||
/// The underlying [`xcb::Request`] used to do the actual heavy lifting
|
||||
type XcbRequest: xcb::Request;
|
||||
|
||||
/// The ewmh wrapper for the [`xcb::Request::Cookie`]
|
||||
type EwmhCookie: EwmhCookie<XcbCookie = <Self::XcbRequest as xcb::Request>::Cookie>;
|
||||
|
||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest;
|
||||
|
||||
/// Convert the [`xcb::Request::Cookie`] to the ewmh cookie wrapper
|
||||
fn convert_cookie(
|
||||
&'a self,
|
||||
xcb_cookie: <Self::XcbRequest as xcb::Request>::Cookie,
|
||||
) -> Self::EwmhCookie;
|
||||
|
||||
/// Default implementation. Delegate the request to the [`xcb::Connection`] and wrap the
|
||||
/// response in the ewmh cookie wrapper.
|
||||
///
|
||||
/// There is usually no need to override the provided default implementation.
|
||||
fn send(&'a self, con: &Connection) -> Self::EwmhCookie {
|
||||
let xcb_request = self.xcb_request(con);
|
||||
let xcb_cookie = con.con.send_request(&xcb_request);
|
||||
self.convert_cookie(xcb_cookie)
|
||||
}
|
||||
}
|
||||
|
||||
/// Requests that can be sent by [`Connection::send_request_checked`]
|
||||
///
|
||||
/// To quote the parent [`xcb`]:
|
||||
/// > Checked requests do not expect a reply, but the returned cookie can be used to check for
|
||||
/// > errors using Connection::check_request.
|
||||
///
|
||||
/// For [`xcb-wm`] this means either `SetProperty` or `ClientMessage` requests.
|
||||
pub(crate) trait EwmhVoidRequestChecked<'a> {
|
||||
type XcbRequest: xcb::RequestWithoutReply;
|
||||
|
||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
||||
fn xcb_request(&'a self, con: &Connection) -> Self::XcbRequest;
|
||||
|
||||
/// Default implementation. Delegate the request to the [`xcb::Connection`].
|
||||
///
|
||||
/// Since we don't need to convert the reply we just re-use the [`xcb::VoidCookieChecked`]
|
||||
/// without wrapping it.
|
||||
///
|
||||
/// There is usually no need to override the provided default implementation.
|
||||
fn send(&'a self, con: &Connection) -> xcb::VoidCookieChecked {
|
||||
let xcb_request = self.xcb_request(con);
|
||||
con.con.send_request_checked(&xcb_request)
|
||||
}
|
||||
}
|
||||
|
||||
/// Requests that can be sent by [`Connection::send_request_unchecked`]
|
||||
///
|
||||
/// To quote the parent [`xcb`]:
|
||||
/// > Unchecked requests expect a reply that is to be retrieved by Connection::wait_for_reply_unchecked.
|
||||
/// > Unchecked means that the error is not checked when the reply is fetched. Instead, the error will
|
||||
/// > be sent to the event loop
|
||||
///
|
||||
/// For [`xcb-wm`] this means a `GetProperty` requests.
|
||||
pub(crate) trait EwmhPropertyRequestUnchecked {
|
||||
type EwmhCookie: EwmhPropertyCookieUnchecked;
|
||||
|
||||
/// Construct the [`xcb::Request`]. This is implementation specific.
|
||||
fn xcb_request(&self, con: &Connection) -> xcb::x::GetProperty;
|
||||
|
||||
/// Convert the [`xcb::Request::Cookie`] to the ewmh cookie wrapper
|
||||
fn convert_cookie(&self, xcb_cookie: xcb::x::GetPropertyCookieUnchecked) -> Self::EwmhCookie;
|
||||
|
||||
/// Default implementation. Delegate the request to the [`xcb::Connection`].
|
||||
///
|
||||
/// Returns a wrapped cookie that tracks the EwmhReply type which is needed
|
||||
/// to convert the reply after it is retrieved via [`Connection::wait_for_reply_unchecked`].
|
||||
///
|
||||
/// There is usually no need to override the provided default implementation.
|
||||
fn send(&self, con: &Connection) -> Self::EwmhCookie {
|
||||
let xcb_request = self.xcb_request(con);
|
||||
let xcb_cookie = con.con.send_request_unchecked(&xcb_request);
|
||||
self.convert_cookie(xcb_cookie)
|
||||
}
|
||||
}
|
||||
|
||||
/// Most generic ewmh wrapper for an [`xcb::Cookie`]
|
||||
///
|
||||
/// This is needed for [`EwmhRequest`] which basically cuts through
|
||||
/// all traits. I.e. it is an _unchecked_ request for void requests
|
||||
/// but a _checked_ request for requests with replies.
|
||||
///
|
||||
/// At the same time it may have a _response_ for reply requests or it
|
||||
/// may have no _response_ for void requests.
|
||||
pub(crate) trait EwmhCookie {
|
||||
/// The wrapped [`xcb::Cookie`]
|
||||
type XcbCookie: xcb::Cookie;
|
||||
}
|
||||
|
||||
/// Blanket impl for [`xcb::VoidCookie`] (basically unchecked void cookies)
|
||||
///
|
||||
/// This is implemented here because there are no special ewmh cookie wrapper
|
||||
/// for SetProperty and ClientMessage requests needed. [`xcb::VoidCookie`] satisfies
|
||||
/// all that is needed for [`ewmh`]. In order to use it with [`EwmhRequest`] we need
|
||||
/// this impl.
|
||||
impl EwmhCookie for xcb::VoidCookie {
|
||||
type XcbCookie = xcb::VoidCookie;
|
||||
}
|
||||
|
||||
/// ewmh wrapper for checked GetProperty requests
|
||||
///
|
||||
/// This is needed for 2 purposes:
|
||||
/// - Carry the reply type from the request to the retrieval of the response
|
||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply`]
|
||||
pub(crate) trait EwmhPropertyCookieChecked {
|
||||
type Reply: EwmhPropertyReply;
|
||||
|
||||
/// Retrieve the inner [`xcb::Cookie`]
|
||||
///
|
||||
/// This is needed for sending a [`xcb::Connection::wait_reply`] request which
|
||||
/// expects the xcb cookie
|
||||
fn inner(self) -> xcb::x::GetPropertyCookie;
|
||||
}
|
||||
|
||||
/// ewmh wrapper for unchecked GetProperty requests
|
||||
///
|
||||
/// This is needed for 2 purposes:
|
||||
/// - Carry the reply type from the request to the retrieval of the response
|
||||
/// - Restrict the methods that can be called with it, i.e. [`Connection::wait_for_reply_unchecked`]
|
||||
pub(crate) trait EwmhPropertyCookieUnchecked {
|
||||
type Reply: EwmhPropertyReply;
|
||||
|
||||
/// Retrieve the inner [`xcb::Cookie`]
|
||||
///
|
||||
/// This is needed for sending a [`xcb::Connection::wait_reply_unchecked`] request which
|
||||
/// expects the xcb cookie
|
||||
fn inner(self) -> xcb::x::GetPropertyCookieUnchecked;
|
||||
}
|
||||
|
||||
/// Marker trait with blanket implementation for everything that implements
|
||||
/// [`From<xcb::x::GetPropertyReply`].
|
||||
///
|
||||
/// The ewmh property reply trait is used to convert a generic reply to a [`xcb::x::GetProperty`]
|
||||
/// request to a specific ewmh reply struct.
|
||||
///
|
||||
/// The connection between a ewmh request and the reply struct is made via ewmh property cookies
|
||||
/// ([`EwmhPropertyCookieChecked`] and [`EwmhPropertyCookieUnchecked`]
|
||||
pub(crate) trait EwmhPropertyReply: From<xcb::x::GetPropertyReply> {}
|
||||
impl<T> EwmhPropertyReply for T where T: From<xcb::x::GetPropertyReply> {}
|
|
@ -1,4 +1,7 @@
|
|||
mod ewmh;
|
||||
#![warn(rustdoc::broken_intra_doc_links)]
|
||||
#![warn(rustdoc::private_intra_doc_links)]
|
||||
|
||||
pub mod ewmh;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
Loading…
Reference in a new issue