oder
-special := [ exec <path> | exit | restart ]
+special := [ exec <path> | kill | exit | restart ]
an jeder Stelle kann mit escape abgebrochen werden
# 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
#ifndef _I3_H
#define _I3_H
-#define NUM_ATOMS 10
+#define NUM_ATOMS 12
extern char *application_path;
extern Display *xkbdpy;
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
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_DESKTOP,
_NET_WM_STRUT_PARTIAL,
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
UTF8_STRING
};
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).
# 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
}
/* 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")) {
/* 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)
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 */
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);
#include <assert.h>
#include <iconv.h>
+#include <xcb/xcb_icccm.h>
+
#include "i3.h"
#include "data.h"
#include "table.h"
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);
+}