Implement kill-command to kill the current window, document it
This commit is contained in:
parent
cc0b060628
commit
cb9c7078be
2
CMDMODE
2
CMDMODE
|
@ -17,7 +17,7 @@ with := <w> { [ <times> ] <where> }+ <space> <cmd>
|
||||||
|
|
||||||
oder
|
oder
|
||||||
|
|
||||||
special := [ exec <path> | exit | restart ]
|
special := [ exec <path> | kill | exit | restart ]
|
||||||
|
|
||||||
an jeder Stelle kann mit escape abgebrochen werden
|
an jeder Stelle kann mit escape abgebrochen werden
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,9 @@ bind Mod1+Shift+19 m10
|
||||||
# Mod1+Enter starts a new terminal
|
# Mod1+Enter starts a new terminal
|
||||||
bind Mod1+36 exec /usr/bin/urxvt
|
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
|
# Mod1+v starts dmenu and launches the selected application
|
||||||
# for now, we don’t have an own launcher
|
# for now, we don’t have an own launcher
|
||||||
bind Mod1+55 exec /usr/bin/dmenu_run
|
bind Mod1+55 exec /usr/bin/dmenu_run
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#ifndef _I3_H
|
#ifndef _I3_H
|
||||||
#define _I3_H
|
#define _I3_H
|
||||||
|
|
||||||
#define NUM_ATOMS 10
|
#define NUM_ATOMS 12
|
||||||
|
|
||||||
extern char *application_path;
|
extern char *application_path;
|
||||||
extern Display *xkbdpy;
|
extern Display *xkbdpy;
|
||||||
|
|
|
@ -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 switch_layout_mode(xcb_connection_t *conn, Container *container, int mode);
|
||||||
void warp_pointer_into(xcb_connection_t *conn, Client *client);
|
void warp_pointer_into(xcb_connection_t *conn, Client *client);
|
||||||
void toggle_fullscreen(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
|
#endif
|
||||||
|
|
|
@ -46,6 +46,8 @@ enum { _NET_SUPPORTED = 0,
|
||||||
_NET_WM_WINDOW_TYPE_DOCK,
|
_NET_WM_WINDOW_TYPE_DOCK,
|
||||||
_NET_WM_DESKTOP,
|
_NET_WM_DESKTOP,
|
||||||
_NET_WM_STRUT_PARTIAL,
|
_NET_WM_STRUT_PARTIAL,
|
||||||
|
WM_PROTOCOLS,
|
||||||
|
WM_DELETE_WINDOW,
|
||||||
UTF8_STRING
|
UTF8_STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,9 @@ Enable stacking layout for the current container.
|
||||||
Mod1+d::
|
Mod1+d::
|
||||||
Enable default layout for the current container.
|
Enable default layout for the current container.
|
||||||
|
|
||||||
|
Mod1+Shift+q::
|
||||||
|
Kills the current client.
|
||||||
|
|
||||||
Mod1+Shift+r::
|
Mod1+Shift+r::
|
||||||
Restarts i3 in place (without losing any windows, but the layout).
|
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)
|
# Start dmenu (Mod1+v)
|
||||||
bind Mod1+55 exec /usr/bin/dmenu_run
|
bind Mod1+55 exec /usr/bin/dmenu_run
|
||||||
|
|
||||||
|
# Kill current client (Mod1+Shift+q)
|
||||||
|
bind Mod1+Shift+24 kill
|
||||||
|
|
||||||
# Beamer on/off
|
# Beamer on/off
|
||||||
bind Mod1+73 exec /home/michael/toggle_beamer.sh
|
bind Mod1+73 exec /home/michael/toggle_beamer.sh
|
||||||
|
|
||||||
|
|
|
@ -560,8 +560,10 @@ void parse_command(xcb_connection_t *conn, const char *command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is it an <exit>? */
|
/* Is it an <exit>? */
|
||||||
if (STARTS_WITH(command, "exit"))
|
if (STARTS_WITH(command, "exit")) {
|
||||||
exit(0);
|
LOG("User issued exit-command, exiting without error.\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/* Is it <restart>? Then restart in place. */
|
/* Is it <restart>? Then restart in place. */
|
||||||
if (STARTS_WITH(command, "restart")) {
|
if (STARTS_WITH(command, "restart")) {
|
||||||
|
@ -570,6 +572,17 @@ void parse_command(xcb_connection_t *conn, const char *command) {
|
||||||
/* not reached */
|
/* 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? */
|
/* Is it 'f' for fullscreen? */
|
||||||
if (command[0] == 'f') {
|
if (command[0] == 'f') {
|
||||||
if (CUR_CELL->currently_focused == NULL)
|
if (CUR_CELL->currently_focused == NULL)
|
||||||
|
|
|
@ -375,6 +375,8 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
REQUEST_ATOM(_NET_WM_DESKTOP);
|
REQUEST_ATOM(_NET_WM_DESKTOP);
|
||||||
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
|
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
|
||||||
REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
|
REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
|
||||||
|
REQUEST_ATOM(WM_PROTOCOLS);
|
||||||
|
REQUEST_ATOM(WM_DELETE_WINDOW);
|
||||||
REQUEST_ATOM(UTF8_STRING);
|
REQUEST_ATOM(UTF8_STRING);
|
||||||
|
|
||||||
/* TODO: this has to be more beautiful somewhen */
|
/* 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_DESKTOP);
|
||||||
GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
|
GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
|
||||||
GET_ATOM(_NET_WM_STRUT_PARTIAL);
|
GET_ATOM(_NET_WM_STRUT_PARTIAL);
|
||||||
|
GET_ATOM(WM_PROTOCOLS);
|
||||||
|
GET_ATOM(WM_DELETE_WINDOW);
|
||||||
GET_ATOM(UTF8_STRING);
|
GET_ATOM(UTF8_STRING);
|
||||||
|
|
||||||
xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
|
xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
|
||||||
|
|
53
src/util.c
53
src/util.c
|
@ -19,6 +19,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
|
||||||
|
#include <xcb/xcb_icccm.h>
|
||||||
|
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
|
@ -391,3 +393,54 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
|
||||||
|
|
||||||
xcb_flush(conn);
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue