diff options
-rw-r--r-- | src/clients/client.rs | 20 | ||||
-rw-r--r-- | src/clients/mod.rs | 11 | ||||
-rw-r--r-- | src/conn_info/mod.rs | 17 |
3 files changed, 36 insertions, 12 deletions
diff --git a/src/clients/client.rs b/src/clients/client.rs index a7b1a8d..3648f0c 100644 --- a/src/clients/client.rs +++ b/src/clients/client.rs @@ -3,7 +3,7 @@ use xcb::{ ChangeProperty, ChangeWindowAttributes, ConfigWindow, ConfigureNotifyEvent, ConfigureWindow, Cw, EventMask, MapWindow, SendEvent, SendEventDest, Window, }, - Xid, + VoidCookie, VoidCookieChecked, Xid, }; use crate::{config::BORDER_WIDTH, conn_info::Connection}; @@ -125,11 +125,15 @@ impl Client { /// Set the event mask for this window /// This function does not check for success, so `conn.flush()` should be called after. - pub fn set_event_mask(&self, conn: &Connection<'_>, event_mask: EventMask) { - conn.send_request(&ChangeWindowAttributes { + pub fn set_event_mask( + &self, + conn: &Connection<'_>, + event_mask: EventMask, + ) -> VoidCookieChecked { + conn.send_request_checked(&ChangeWindowAttributes { window: self.window(), value_list: &[Cw::EventMask(event_mask)], - }); + }) } /// Sync the non-geometry related properties with EWMH hints @@ -150,14 +154,14 @@ impl Client { } /// Set the given window as withdrawn / not withdrawn. - pub fn set_withdrawn(&self, conn: &Connection<'_>, withdrawn: bool) { - conn.send_request(&ChangeProperty { + pub fn set_withdrawn(&self, conn: &Connection<'_>, withdrawn: bool) -> VoidCookieChecked { + conn.send_request_checked(&ChangeProperty { mode: xcb::x::PropMode::Replace, window: self.window, property: conn.atoms.wm_state, r#type: conn.atoms.wm_state, - data: &[u8::from(!withdrawn), 0_u8], - }); + data: &[u32::from(!withdrawn), 0_u32], + }) } pub fn set_urgent(&mut self, urgent: bool) { diff --git a/src/clients/mod.rs b/src/clients/mod.rs index d07de74..70e3798 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -94,7 +94,9 @@ impl WM<'_> { pub(crate) fn handle_unmap_notify(&mut self, e: &UnmapNotifyEvent) -> Result<()> { if let Some(c) = self.clients.find_client_mut(e.window()) { if e.is_from_send_event() { - c.set_withdrawn(&self.conn, true); + let cookie = c.set_withdrawn(&self.conn, true); + // The above may fail if the window has already been destroyed - just discard the error here. + let _ = self.conn.check_request(cookie); } else { self.clients.unmanage(&self.conn, e.window(), false); } @@ -237,9 +239,12 @@ impl ClientState { let c = self.mons[mon].clients.remove(i); if !already_destroyed { - c.set_event_mask(conn, EventMask::empty()); + c.set_event_mask(conn, EventMask::NO_EVENT); // TODO: Ungrab button - c.set_withdrawn(conn, true); + let cookie = c.set_withdrawn(conn, true); + + // If any of the above requests fail, it's just a race condition and the window is already destroyed, so discard the error here. + let _ = conn.check_request(cookie); } self.rearrange(conn); } diff --git a/src/conn_info/mod.rs b/src/conn_info/mod.rs index 1981938..183f691 100644 --- a/src/conn_info/mod.rs +++ b/src/conn_info/mod.rs @@ -4,7 +4,7 @@ use xcb::{ self, ChangeProperty, ChangeWindowAttributes, CreateWindow, DeleteProperty, DestroyWindow, Window, WindowClass, }, - Connection as RawConnection, Cookie, + Connection as RawConnection, Cookie, VoidCookieChecked, }; mod atoms; @@ -190,6 +190,16 @@ impl<'a> Connection<'a> { cookie } + /// Delegate for [`RawConnection::send_request_checked`] + pub fn send_request_checked<R>(&self, req: &R) -> VoidCookieChecked + where + R: xcb::RequestWithoutReply + Debug, + { + let cookie = self.conn.send_request_checked(req); + debug_req!(req, cookie); + cookie + } + /// Delegate for [`RawConnection::send_and_check_request`] pub fn send_and_check_request<R>(&self, req: &R) -> Result<()> where @@ -199,6 +209,11 @@ impl<'a> Connection<'a> { self.conn.send_and_check_request(req).map_err(Into::into) } + /// Delegate for [`RawConnection::check_request`] + pub fn check_request(&self, c: VoidCookieChecked) -> Result<()> { + self.conn.check_request(c).map_err(Into::into) + } + /// Delegate for [`RawConnection::flush`] pub fn flush(&self) -> Result<()> { self.conn.flush().map_err(Into::into) |