]> git.sur5r.net Git - i3/i3/commitdiff
Implement kill-command to kill the current window, document it
authorMichael Stapelberg <michael+x200@stapelberg.de>
Sat, 14 Mar 2009 21:09:36 +0000 (22:09 +0100)
committerMichael Stapelberg <michael+x200@stapelberg.de>
Sat, 14 Mar 2009 21:09:36 +0000 (22:09 +0100)
CMDMODE
i3.config
include/i3.h
include/util.h
include/xcb.h
man/i3.man
src/commands.c
src/mainx.c
src/util.c

diff --git a/CMDMODE b/CMDMODE
index 5e8ebbfa709735e22bcbaa6f867961bffb8c6074..6b8315e2fa027e30f5e62ee2464ff54af026f51f 100644 (file)
--- a/CMDMODE
+++ b/CMDMODE
@@ -17,7 +17,7 @@ with := <w> { [ <times> ] <where> }+ <space> <cmd>
 
 oder
 
-special := [ exec <path> | exit | restart ]
+special := [ exec <path> | kill | exit | restart ]
 
 an jeder Stelle kann mit escape abgebrochen werden
 
index a40f13ad15d396e739ab7ecaa9a2e952614ee64a..d2cf13a09e8eca695b8c37e94f1b480a24bdb553 100644 (file)
--- a/i3.config
+++ b/i3.config
@@ -72,6 +72,9 @@ bind Mod1+Shift+19 m10
 # Mod1+Enter starts a new terminal
 bind Mod1+36 exec /usr/bin/urxvt
 
+# Mod1+Shift+q kills the current client
+bind Mod1+Shift+24 kill
+
 # Mod1+v starts dmenu and launches the selected application
 # for now, we don’t have an own launcher
 bind Mod1+55 exec /usr/bin/dmenu_run
index 31da700a507b7a93b0384ff28d16d765871bde33..7a104b21894f64dbde74c3f6bb63bb31029a7c5e 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef _I3_H
 #define _I3_H
 
-#define NUM_ATOMS 10
+#define NUM_ATOMS 12
 
 extern char *application_path;
 extern Display *xkbdpy;
index 827ae6d18a694f13259b7b1f50114dca3210ba2d..a156f0a38944d358648725e3675a8b6941bc268d 100644 (file)
@@ -46,5 +46,6 @@ void leave_stack_mode(xcb_connection_t *conn, Container *container);
 void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode);
 void warp_pointer_into(xcb_connection_t *conn, Client *client);
 void toggle_fullscreen(xcb_connection_t *conn, Client *client);
+void kill_window(xcb_connection_t *conn, Client *window);
 
 #endif
index 338114e5d77f14353e256681dffe8fbed2bf5129..4302fbcb76a4b64f68b9d21bb3a9dfc6f2573f29 100644 (file)
@@ -46,6 +46,8 @@ enum { _NET_SUPPORTED = 0,
         _NET_WM_WINDOW_TYPE_DOCK,
         _NET_WM_DESKTOP,
         _NET_WM_STRUT_PARTIAL,
+        WM_PROTOCOLS,
+        WM_DELETE_WINDOW,
         UTF8_STRING
 };
 
index c5386c5c47540542fa26b89420153c0f6c3fe2f6..dc6ebc4259fff4f8e90d03db8ad5eb72bf4ecb35 100644 (file)
@@ -108,6 +108,9 @@ Enable stacking layout for the current container.
 Mod1+d::
 Enable default layout for the current container.
 
+Mod1+Shift+q::
+Kills the current client.
+
 Mod1+Shift+r::
 Restarts i3 in place (without losing any windows, but the layout).
 
@@ -136,6 +139,9 @@ bind Mod1+36 exec /usr/bin/urxvt
 # Start dmenu (Mod1+v)
 bind Mod1+55 exec /usr/bin/dmenu_run
 
+# Kill current client (Mod1+Shift+q)
+bind Mod1+Shift+24 kill
+
 # Beamer on/off
 bind Mod1+73 exec /home/michael/toggle_beamer.sh
 
index 3afd6c5e8ace7e89b234d7d46e5e9b93aac1851a..a1187c3c472767194effa6a3753cfea602e9fe2f 100644 (file)
@@ -560,8 +560,10 @@ void parse_command(xcb_connection_t *conn, const char *command) {
         }
 
         /* Is it an <exit>? */
-        if (STARTS_WITH(command, "exit"))
-                exit(0);
+        if (STARTS_WITH(command, "exit")) {
+                LOG("User issued exit-command, exiting without error.\n");
+                exit(EXIT_SUCCESS);
+        }
 
         /* Is it <restart>? Then restart in place. */
         if (STARTS_WITH(command, "restart")) {
@@ -570,6 +572,17 @@ void parse_command(xcb_connection_t *conn, const char *command) {
                 /* not reached */
         }
 
+        if (STARTS_WITH(command, "kill")) {
+                if (CUR_CELL->currently_focused == NULL) {
+                        LOG("There is no window to kill\n");
+                        return;
+                }
+
+                LOG("Killing current window\n");
+                kill_window(conn, CUR_CELL->currently_focused);
+                return;
+        }
+
         /* Is it 'f' for fullscreen? */
         if (command[0] == 'f') {
                 if (CUR_CELL->currently_focused == NULL)
index 0b0e1bb1430429e6064e88a67fddc658b664b02f..cfb170a30909b47561f7b49a3a644fa03bf9a8be 100644 (file)
@@ -375,6 +375,8 @@ int main(int argc, char *argv[], char *env[]) {
         REQUEST_ATOM(_NET_WM_DESKTOP);
         REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
         REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
+        REQUEST_ATOM(WM_PROTOCOLS);
+        REQUEST_ATOM(WM_DELETE_WINDOW);
         REQUEST_ATOM(UTF8_STRING);
 
         /* TODO: this has to be more beautiful somewhen */
@@ -475,6 +477,8 @@ int main(int argc, char *argv[], char *env[]) {
         GET_ATOM(_NET_WM_DESKTOP);
         GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
         GET_ATOM(_NET_WM_STRUT_PARTIAL);
+        GET_ATOM(WM_PROTOCOLS);
+        GET_ATOM(WM_DELETE_WINDOW);
         GET_ATOM(UTF8_STRING);
 
         xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
index 1a2cc8c562e5a3a1795302795f190eadbc542bef..e8440b67d65a6dc50756b9c4a7069b55173168dc 100644 (file)
@@ -19,6 +19,8 @@
 #include <assert.h>
 #include <iconv.h>
 
+#include <xcb/xcb_icccm.h>
+
 #include "i3.h"
 #include "data.h"
 #include "table.h"
@@ -391,3 +393,54 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
 
         xcb_flush(conn);
 }
+
+/*
+ * Returns true if the client supports the given protocol atom (like WM_DELETE_WINDOW)
+ *
+ */
+static bool client_supports_protocol(xcb_connection_t *conn, Client *client, xcb_atom_t atom) {
+        xcb_get_property_cookie_t cookie;
+        xcb_get_wm_protocols_reply_t protocols;
+        bool result = false;
+
+        cookie = xcb_get_wm_protocols_unchecked(conn, client->child, atoms[WM_PROTOCOLS]);
+        if (xcb_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
+                return false;
+
+        /* Check if the client’s protocols have the requested atom set */
+        for (uint32_t i = 0; i < protocols.atoms_len; i++)
+                if (protocols.atoms[i] == atom)
+                        result = true;
+
+        xcb_get_wm_protocols_reply_wipe(&protocols);
+
+        return result;
+}
+
+/*
+ * Kills the given window using WM_DELETE_WINDOW or xcb_kill_window
+ *
+ */
+void kill_window(xcb_connection_t *conn, Client *window) {
+        /* If the client does not support WM_DELETE_WINDOW, we kill it the hard way */
+        if (!client_supports_protocol(conn, window, atoms[WM_DELETE_WINDOW])) {
+                LOG("Killing window the hard way\n");
+                xcb_kill_client(conn, window->child);
+                return;
+        }
+
+        xcb_client_message_event_t ev;
+
+        memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+        ev.response_type = XCB_CLIENT_MESSAGE;
+        ev.window = window->child;
+        ev.type = atoms[WM_PROTOCOLS];
+        ev.format = 32;
+        ev.data.data32[0] = atoms[WM_DELETE_WINDOW];
+        ev.data.data32[1] = XCB_CURRENT_TIME;
+
+        LOG("Sending WM_DELETE to the client\n");
+        xcb_send_event(conn, false, window->child, XCB_EVENT_MASK_NO_EVENT, (char*)&ev);
+        xcb_flush(conn);
+}