commit 54dc2aae7587e02e5824a0db3621582ae978a966
parent 9202c0151600cf238b17df993f099e071bebf771
Author: Kebigon <git@kebigon.xyz>
Date: Tue, 21 Jul 2020 18:38:05 +0900
Add possibility to kill a client
Diffstat:
4 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/config.h b/config.h
@@ -27,6 +27,7 @@ static Key keys[] =
{ MODKEY, XK_Page_Down, workspace_next, { 0 } },
{ MODKEY | SHIFT, XK_Tab, focus_next, { .b = true } },
{ MODKEY, XK_Tab, focus_next, { .b = false } },
+ { MODKEY, XK_q, client_kill, { 0 } },
{ MODKEY | SHIFT, XK_q, quit, { 0 } },
WORKSPACEKEYS(XK_Home, 0)
WORKSPACEKEYS(XK_1, 0)
diff --git a/kbgwm.c b/kbgwm.c
@@ -22,6 +22,7 @@ static client* client_find(xcb_window_t);
static client* client_find_workspace(xcb_window_t, uint_fast8_t);
static client* client_remove();
static client* client_remove_workspace(uint_fast8_t);
+static void client_kill(const Arg*);
static void client_create(xcb_window_t);
static void client_sanitize_position(client*);
static void client_sanitize_dimensions(client*);
@@ -361,6 +362,21 @@ void client_sanitize_dimensions(client* client)
client->height = height;
}
+void client_kill(__attribute__((unused))const Arg* arg)
+{
+ // No client are focused
+ if (workspaces[current_workspace] == NULL)
+ return; // Nothing to be done
+
+ if (!xcb_send_atom(workspaces[current_workspace], wm_delete_window))
+ {
+ // The client does not support WM_DELETE, let's kill it
+ xcb_kill_client(c, workspaces[current_workspace]->id);
+ }
+
+ xcb_flush(c);
+}
+
/*
* Focus
*/
@@ -752,6 +768,9 @@ int main(void)
for (uint_fast8_t i = 0; i != NB_WORKSPACES; i++)
workspaces[i] = NULL;
+ wm_protocols = xcb_get_atom(WM_PROTOCOLS);
+ wm_delete_window = xcb_get_atom(WM_DELETE_WINDOW);
+
setup_keyboard();
setup_screen();
setup_events();
diff --git a/xcbutils.c b/xcbutils.c
@@ -1,7 +1,11 @@
#include "xcbutils.h"
-#include <stdio.h>
+#include <assert.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xcb/xcb_icccm.h>
+#include <xcb/xproto.h>
extern xcb_connection_t* c;
extern xcb_window_t root;
@@ -93,3 +97,60 @@ xcb_keysym_t xcb_get_keysym(xcb_keycode_t keycode)
xcb_key_symbols_free(keysyms);
return (keysym);
}
+
+#define ONLY_IF_EXISTS 0
+
+/* Get a defined atom from the X server. */
+xcb_atom_t xcb_get_atom(const char* atom_name)
+{
+ xcb_intern_atom_cookie_t cookie = xcb_intern_atom(c, ONLY_IF_EXISTS, strlen(atom_name), atom_name);
+
+ xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(c, cookie, NULL);
+
+ /* XXX Note that we return 0 as an atom if anything goes wrong.
+ * Might become interesting.*/
+
+ if (reply == NULL)
+ return 0;
+
+ xcb_atom_t atom = reply->atom;
+ free(reply);
+ return atom;
+}
+
+bool xcb_send_atom(client* client, xcb_atom_t atom)
+{
+ assert(client != NULL);
+
+ bool supported = false;
+ xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_protocols_unchecked(c, client->id, wm_protocols);
+
+ // Get the supported atoms for this client
+ xcb_icccm_get_wm_protocols_reply_t protocols;
+ if (xcb_icccm_get_wm_protocols_reply(c, cookie, &protocols, NULL) == 1)
+ {
+ for (uint_fast32_t i = 0; i < protocols.atoms_len; i++)
+ {
+ if (protocols.atoms[i] == atom)
+ {
+ supported = true;
+ break;
+ }
+ }
+ }
+
+ // The client does not support WM_DELETE, let's kill it
+ if (!supported)
+ return false;
+
+ xcb_client_message_event_t ev;
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.sequence = 0;
+ ev.window = client->id;
+ ev.type = wm_protocols;
+ ev.data.data32[0] = atom;
+ ev.data.data32[1] = XCB_CURRENT_TIME;
+ xcb_send_event(c, false, client->id, XCB_EVENT_MASK_NO_EVENT, (char*) &ev);
+ return true;
+}
diff --git a/xcbutils.h b/xcbutils.h
@@ -21,4 +21,17 @@ void xcb_register_button_events(Button button);
xcb_keycode_t* xcb_get_keycodes(xcb_keysym_t);
xcb_keysym_t xcb_get_keysym(xcb_keycode_t);
+/*
+ * Atoms
+ */
+
+#define WM_DELETE_WINDOW "WM_DELETE_WINDOW"
+#define WM_PROTOCOLS "WM_PROTOCOLS"
+
+xcb_atom_t wm_protocols;
+xcb_atom_t wm_delete_window;
+
+xcb_atom_t xcb_get_atom(const char*);
+bool xcb_send_atom(client*, xcb_atom_t);
+
#endif /* XCBUTILS_H_ */