From eb7785a74abf27f1d8c98eba1cfe6b0cc16002a0 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 14 May 2022 21:07:11 +0200 Subject: [PATCH] CloseWindow and RequestFrameExtents properties --- src/ewmh/atoms.rs | 22 +++--- src/ewmh/ewmh.rs | 33 +++++++++ src/ewmh/mod.rs | 6 +- src/ewmh/proto/root_props.rs | 130 +++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 10 deletions(-) diff --git a/src/ewmh/atoms.rs b/src/ewmh/atoms.rs index 9d28179..d9230d4 100644 --- a/src/ewmh/atoms.rs +++ b/src/ewmh/atoms.rs @@ -82,7 +82,7 @@ const ATOM_NAMES: [&str; 82] = [ "_NET_WM_ACTION_CHANGE_DESKTOP", "_NET_WM_ACTION_CLOSE", "_NET_WM_ACTION_ABOVE", - "_NET_WM_ACTION_BELOW" + "_NET_WM_ACTION_BELOW", ]; #[allow(non_snake_case)] @@ -169,12 +169,11 @@ pub struct Atoms { 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 + pub _NET_WM_ACTION_BELOW: xcb::x::Atom, } - impl Atoms { - pub (crate) fn intern(con: &xcb::Connection) -> 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 { @@ -186,7 +185,8 @@ impl Atoms { cookies.insert(atom, con.send_request(&intern_atom)); } - let interned_atoms: HashMap<&'static str, xcb::x::Atom> = cookies.into_iter() + 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(); @@ -247,10 +247,14 @@ impl Atoms { _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_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_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(), @@ -265,7 +269,9 @@ impl Atoms { _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_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(), diff --git a/src/ewmh/ewmh.rs b/src/ewmh/ewmh.rs index 995eedf..6939dcc 100644 --- a/src/ewmh/ewmh.rs +++ b/src/ewmh/ewmh.rs @@ -271,4 +271,37 @@ mod tests { 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); + } } diff --git a/src/ewmh/mod.rs b/src/ewmh/mod.rs index edc6910..e975212 100644 --- a/src/ewmh/mod.rs +++ b/src/ewmh/mod.rs @@ -1,4 +1,6 @@ -mod ewmh; -mod atoms; +#[macro_use] mod proto_traits; + +mod atoms; +mod ewmh; mod proto; diff --git a/src/ewmh/proto/root_props.rs b/src/ewmh/proto/root_props.rs index 5c09942..8e2052f 100644 --- a/src/ewmh/proto/root_props.rs +++ b/src/ewmh/proto/root_props.rs @@ -604,3 +604,133 @@ impl<'a> EwmhRequestData<'a> for SetShowingDesktop { } // }}} + +// _NET_CLOSE_WINDOW +// {{{ +pub struct CloseWindow { + client_message: xcb::x::ClientMessageEvent, +} + +impl CloseWindow { + pub fn new( + connection: &Connection, + window: xcb::x::Window, + source_indication: u32, + timestamp: u32, + ) -> CloseWindow { + let data = [timestamp, source_indication, 0x00, 0x00, 0x00]; + + let client_message = xcb::x::ClientMessageEvent::new( + window, + connection.atoms._NET_CLOSE_WINDOW, + xcb::x::ClientMessageData::Data32(data), + ); + + CloseWindow { client_message } + } +} + +impl<'a> EwmhRequest<'a> for CloseWindow { + 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 CloseWindow { + type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>; + + fn get_request_data( + &'a self, + con: &Connection, + ) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> { + 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, + } + } +} +// }}} + +// _NET_MOVERESIZE_WINDOW +// {{{ + +// TODO + +// }}} + +// _NET_WM_MOVERESIZE +// {{{ + +// TODO + +// }}} + +// _NET_RESTACK_WINDOW +// {{{ + +// TODO + +// }}} + +// _NET_REQUEST_FRAME_EXTENTS +// {{{ +pub struct RequestFrameExtents { + client_message: xcb::x::ClientMessageEvent, +} + +impl RequestFrameExtents { + pub fn new(connection: &Connection, window: xcb::x::Window) -> RequestFrameExtents { + let client_message = xcb::x::ClientMessageEvent::new( + window, + connection.atoms._NET_REQUEST_FRAME_EXTENTS, + xcb::x::ClientMessageData::Data32([0x0, 0x0, 0x0, 0x0, 0x0]), + ); + + RequestFrameExtents { client_message } + } +} + +impl<'a> EwmhRequest<'a> for RequestFrameExtents { + 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 RequestFrameExtents { + type Request = xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent>; + + fn get_request_data( + &'a self, + con: &Connection, + ) -> xcb::x::SendEvent<'a, xcb::x::ClientMessageEvent> { + 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, + } + } +} +// }}}