From b5601a6eb3a8d0603bb837a847701d3d49f984c3 Mon Sep 17 00:00:00 2001 From: tcmal Date: Fri, 30 Aug 2024 15:48:34 +0100 Subject: Add bind for killing clients --- src/clients/mod.rs | 28 ++++++++++++++++++++++++---- src/config.rs | 5 +++-- src/conn_info/mod.rs | 8 +++++--- src/helpers.rs | 7 +++++++ 4 files changed, 39 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/clients/mod.rs b/src/clients/mod.rs index da341ba..4ebd634 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -11,12 +11,12 @@ use crate::{ }; use xcb::{ x::{ - self, ChangeProperty, ConfigWindow, ConfigWindowMask, ConfigureNotifyEvent, + self, ChangeProperty, CloseDown, ConfigWindow, ConfigWindowMask, ConfigureNotifyEvent, ConfigureRequestEvent, ConfigureWindow, DeleteProperty, DestroyNotifyEvent, EventMask, - GetWindowAttributes, InputFocus, MapRequestEvent, PropMode, SetInputFocus, - UnmapNotifyEvent, Window, + GetWindowAttributes, InputFocus, KillClient, MapRequestEvent, PropMode, SetCloseDownMode, + SetInputFocus, UnmapNotifyEvent, Window, }, - xinerama, BaseEvent, Extension, + xinerama, BaseEvent, Extension, Xid, }; pub use client::*; @@ -548,6 +548,26 @@ impl ClientState { pub fn client_mon(&self, pos: ClientIdx) -> &MonitorInfo { &self.mons[self.client_mon_idx(pos)] } + + pub fn kill_client(&self, conn: &Connection, pos: usize) { + let c = self.client(pos); + // Modern clients respond to the WM_DELETE event + if !conn.send_event(c.window(), conn.atoms.wm_delete) { + // Fallback to the old fashioned way + + // Using checked requests so we can ignore errors here without waiting for them to go to + // the event loop + let cookie1 = conn.send_request_checked(&SetCloseDownMode { + mode: CloseDown::DestroyAll, + }); + let cookie2 = conn.send_request_checked(&KillClient { + resource: c.window().resource_id(), + }); + + let _ = conn.check_request(cookie1); + let _ = conn.check_request(cookie2); + } + } } impl Default for ClientState { diff --git a/src/config.rs b/src/config.rs index f052c22..f806df4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,8 +9,8 @@ use crate::{ clients::TagFocus, conn_info::Colour, helpers::{ - focus_next, focus_prev, mouse_move, mouse_resize, set_tag, set_tag_focus, spawn, - toggle_floating, toggle_fullscreen, + focus_next, focus_prev, kill_client, mouse_move, mouse_resize, set_tag, set_tag_focus, + spawn, toggle_floating, toggle_fullscreen, }, keys::Keybinds, }; @@ -49,6 +49,7 @@ pub const KEYBINDS: Keybinds = Keybinds(&[ bind!(MAIN_MODIFIER , k -> &focus_prev), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , space -> &toggle_floating), bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , f -> &toggle_fullscreen), + bind!(MAIN_MODIFIER.union(ModMask::SHIFT) , q -> &kill_client), bind!(MAIN_MODIFIER , _1 -> &|wm| set_tag_focus(wm, TagFocus::Tag(1))), bind!(MAIN_MODIFIER , _2 -> &|wm| set_tag_focus(wm, TagFocus::Tag(2))), bind!(MAIN_MODIFIER , _3 -> &|wm| set_tag_focus(wm, TagFocus::Tag(3))), diff --git a/src/conn_info/mod.rs b/src/conn_info/mod.rs index f85cdc0..42f3955 100644 --- a/src/conn_info/mod.rs +++ b/src/conn_info/mod.rs @@ -180,7 +180,7 @@ impl<'a> Connection<'a> { } /// Send event to window `w`, if the event is supported. - pub fn send_event(&self, window: Window, event: Atom) { + pub fn send_event(&self, window: Window, event: Atom) -> bool { let Ok(protocols) = self.wait_for_reply(self.send_request(&GetProperty { delete: false, window, @@ -189,11 +189,11 @@ impl<'a> Connection<'a> { long_offset: 0, long_length: 100_000, })) else { - return; + return false; }; if protocols.r#type() != x::ATOM_ATOM || protocols.format() != 32 { - return; + return false; } let supported = protocols @@ -213,6 +213,8 @@ impl<'a> Connection<'a> { ), }); } + + supported } /// Delegate for [`RawConnection::send_request`] diff --git a/src/helpers.rs b/src/helpers.rs index 5a2844d..819719b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -70,6 +70,13 @@ pub fn toggle_fullscreen(wm: &mut WM<'_>) { } } +/// Send the kill signal to the currently focused client +pub fn kill_client(wm: &mut WM<'_>) { + if let Some(pos) = wm.clients.focused_pos() { + wm.clients.kill_client(&wm.conn, pos); + } +} + /// Set the focused tag for the currently selected monitor pub fn set_tag_focus(wm: &mut WM<'_>, tag_focus: TagFocus) { wm.clients -- cgit v1.2.3