Compare commits

...

3 Commits

10 changed files with 91 additions and 16 deletions

View File

@@ -104,3 +104,9 @@ void toggle_client_maximize(const user_action_arg_t *arg) {
client_set_maximize(wm.client_focused, !wm.client_focused->maximize); client_set_maximize(wm.client_focused, !wm.client_focused->maximize);
} }
void kill_client(const user_action_arg_t *arg) {
if (wm.client_focused) {
client_kill(wm.client_focused);
}
}

View File

@@ -60,3 +60,4 @@ void change_volume(const user_action_arg_t *arg);
void toggle_client_floating(const user_action_arg_t *arg); void toggle_client_floating(const user_action_arg_t *arg);
void toggle_client_fullscreen(const user_action_arg_t *arg); void toggle_client_fullscreen(const user_action_arg_t *arg);
void toggle_client_maximize(const user_action_arg_t *arg); void toggle_client_maximize(const user_action_arg_t *arg);
void kill_client(const user_action_arg_t *arg);

View File

@@ -1,5 +1,6 @@
_XKB_RULES_NAMES _XKB_RULES_NAMES
WM_DELETE_WINDOW
WM_PROTOCOLS WM_PROTOCOLS
WM_TAKE_FOCUS WM_TAKE_FOCUS
WM_NAME WM_NAME

View File

@@ -172,6 +172,17 @@ static void client_init_tag_by_wm_desktop(client_t *client) {
} }
} }
static void set_window_event_mask(xcb_window_t window, bool clean) {
xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
uint32_t init_event_mask =
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
uint32_t event_mask = clean ? XCB_EVENT_MASK_NO_EVENT : init_event_mask;
xcb_params_cw_t params = {.event_mask = event_mask};
xcb_aux_change_window_attributes(wm.xcb_conn, window, change_mask, &params);
}
void client_manage(xcb_window_t window, void client_manage(xcb_window_t window,
xcb_get_geometry_reply_t *geometry_reply) { xcb_get_geometry_reply_t *geometry_reply) {
client_t *c = p_new(client_t, 1); client_t *c = p_new(client_t, 1);
@@ -184,14 +195,7 @@ void client_manage(xcb_window_t window,
c->old_border_width = geometry_reply->border_width; c->old_border_width = geometry_reply->border_width;
{ {
const xcb_params_cw_t params = { set_window_event_mask(window, false);
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
};
xcb_aux_change_window_attributes(wm.xcb_conn, window, XCB_CW_EVENT_MASK,
&params);
xcb_map_window(wm.xcb_conn, window); xcb_map_window(wm.xcb_conn, window);
} }
client_update_names(c); client_update_names(c);
@@ -238,6 +242,7 @@ void client_manage(xcb_window_t window,
xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_APPEND, wm.screen->root, xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_APPEND, wm.screen->root,
_NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, 1, &window); _NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, 1, &window);
xwindow_set_state(window, XCB_ICCCM_WM_STATE_NORMAL);
monitor_arrange(c->monitor); monitor_arrange(c->monitor);
monitor_draw_bar(c->monitor); monitor_draw_bar(c->monitor);
@@ -477,7 +482,13 @@ static void update_client_list(void) {
} }
} }
void client_unmanage(client_t *client) { void client_kill(client_t *client) {
if (!xwindow_send_event(client->window, WM_DELETE_WINDOW)) {
xwindow_kill_window(client->window);
}
}
void client_unmanage(client_t *client, bool destroyed) {
monitor_t *m = client->monitor; monitor_t *m = client->monitor;
client_detach_list(client); client_detach_list(client);
@@ -487,6 +498,13 @@ void client_unmanage(client_t *client) {
if (tag->mask & client->tags) client_remove_from_tag(client, tag); if (tag->mask & client->tags) client_remove_from_tag(client, tag);
} }
if (!destroyed) {
set_window_event_mask(client->window, true);
client_change_border_width(client, client->old_border_width);
xwindow_set_state(client->window, XCB_ICCCM_WM_STATE_WITHDRAWN);
xcb_flush(wm.xcb_conn);
}
client_wipe(client); client_wipe(client);
update_client_list(); update_client_list();

View File

@@ -50,7 +50,7 @@ void client_set_transient_for_window(client_t *client,
void client_set_leader_window(client_t *client, xcb_window_t leader_window); void client_set_leader_window(client_t *client, xcb_window_t leader_window);
void client_kill(client_t *client); void client_kill(client_t *client);
void client_unmanage(client_t *client); void client_unmanage(client_t *client, bool destroyed);
void client_apply_geometry(client_t *client, area_t geometry); void client_apply_geometry(client_t *client, area_t geometry);
void client_apply_workarea_geometry(client_t *client, area_t geometry); void client_apply_workarea_geometry(client_t *client, area_t geometry);
void client_apply_rules(client_t *client, const rule_t rules[], void client_apply_rules(client_t *client, const rule_t rules[],

View File

@@ -99,6 +99,7 @@ static const keyboard_t key_list[] = {
{modifier_super | modifier_control, XK_space, toggle_client_floating, {0}}, {modifier_super | modifier_control, XK_space, toggle_client_floating, {0}},
{modifier_super, XK_f, toggle_client_fullscreen, {0}}, {modifier_super, XK_f, toggle_client_fullscreen, {0}},
{modifier_super, XK_m, toggle_client_maximize, {0}}, {modifier_super, XK_m, toggle_client_maximize, {0}},
{modifier_super | modifier_shift, XK_c, kill_client, {0}},
{modifier_super, XK_Up, change_volume, {.i = 1}}, {modifier_super, XK_Up, change_volume, {.i = 1}},
{modifier_super, XK_Down, change_volume, {.i = -1}}, {modifier_super, XK_Down, change_volume, {.i = -1}},
@@ -124,8 +125,9 @@ static const char *const autostart_list[] = {
static const rule_t rules[] = { static const rule_t rules[] = {
{.role = "dialog", .tag_index = -1, .floating = true}, {.role = "dialog", .tag_index = -1, .floating = true},
{.class = "firefox", .tag_index = 1, .maximize = true}, {.class = "firefox", .role = "About", .tag_index = 1, .floating = true},
{.class = "firefox", .role = "browser", .tag_index = 1, .maximize = true},
{.class = "Google-chrome", .tag_index = 1, .maximize = true}, {.class = "Google-chrome", .tag_index = 1, .maximize = true},
{.class = "mpv", .tag_index = 3, .switch_to_tag = true, .fullscreen = true}, {.class = "mpv", .tag_index = 11, .switch_to_tag = true, .fullscreen = true},
{.class = "Emacs", .tag_index = 10, .switch_to_tag = true, .maximize = true}, {.class = "Emacs", .tag_index = 10, .switch_to_tag = true, .maximize = true},
}; };

View File

@@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xcb_event.h> #include <xcb/xcb_event.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
@@ -201,12 +202,18 @@ static void property_notify(xcb_property_notify_event_t *ev) {
static void destroy_notify(xcb_destroy_notify_event_t *ev) { static void destroy_notify(xcb_destroy_notify_event_t *ev) {
client_t *client = client_get_by_window(ev->window); client_t *client = client_get_by_window(ev->window);
if (client) client_unmanage(client); if (client) client_unmanage(client, true);
} }
static void unmap_notify(xcb_unmap_notify_event_t *ev) { static void unmap_notify(xcb_unmap_notify_event_t *ev) {
client_t *client = client_get_by_window(ev->window); client_t *client = client_get_by_window(ev->window);
if (client) client_unmanage(client); if (client) {
if (XCB_EVENT_SENT(ev)) {
xwindow_set_state(ev->window, XCB_ICCCM_WM_STATE_WITHDRAWN);
} else {
client_unmanage(client, false);
}
}
} }
static void map_notify(xcb_map_notify_event_t *ev) { static void map_notify(xcb_map_notify_event_t *ev) {

View File

@@ -314,6 +314,16 @@ void wm_scan_clients(void) {
void wm_clean(void) { void wm_clean(void) {
clean_status(); clean_status();
text_clean_pango_layout(); text_clean_pango_layout();
{
client_t *c = wm.client_stack_list;
while (c) {
client_t *next_client = c->stack_next;
client_unmanage(c, false);
c = next_client;
}
}
monitor_clean(wm.monitor_list); monitor_clean(wm.monitor_list);
for (int i = 0; i < countof(sources); i++) { for (int i = 0; i < countof(sources); i++) {
@@ -321,7 +331,6 @@ void wm_clean(void) {
if (source_id) g_source_remove(source_id); if (source_id) g_source_remove(source_id);
} }
xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_CLIENT_LIST);
xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_ACTIVE_WINDOW); xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_ACTIVE_WINDOW);
xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_SUPPORTING_WM_CHECK); xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_SUPPORTING_WM_CHECK);
xcb_aux_sync(wm.xcb_conn); xcb_aux_sync(wm.xcb_conn);

View File

@@ -136,7 +136,7 @@ bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom) {
bool exist = false; bool exist = false;
xcb_get_property_cookie_t cookie = xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_protocols(wm.xcb_conn, window, atom); xcb_icccm_get_wm_protocols(wm.xcb_conn, window, WM_PROTOCOLS);
xcb_icccm_get_wm_protocols_reply_t reply; xcb_icccm_get_wm_protocols_reply_t reply;
if (xcb_icccm_get_wm_protocols_reply(wm.xcb_conn, cookie, &reply, nullptr)) { if (xcb_icccm_get_wm_protocols_reply(wm.xcb_conn, cookie, &reply, nullptr)) {
for (uint32_t i = 0; !exist && i < reply.atoms_len; i++) { for (uint32_t i = 0; !exist && i < reply.atoms_len; i++) {
@@ -154,6 +154,9 @@ bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom) {
ev.type = WM_PROTOCOLS; ev.type = WM_PROTOCOLS;
ev.data.data32[0] = atom; ev.data.data32[0] = atom;
ev.data.data32[1] = XCB_CURRENT_TIME; ev.data.data32[1] = XCB_CURRENT_TIME;
xcb_connection_t *conn = wm.xcb_conn;
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
} }
return exist; return exist;
@@ -225,6 +228,14 @@ bool xwindow_get_wm_desktop(xcb_window_t window, uint32_t *desktop) {
return success; return success;
} }
void xwindow_kill_window(xcb_window_t window) {
xcb_grab_server(wm.xcb_conn);
xcb_set_close_down_mode(wm.xcb_conn, XCB_CLOSE_DOWN_DESTROY_ALL);
xcb_kill_client(wm.xcb_conn, window);
xcb_flush(wm.xcb_conn);
xcb_ungrab_server(wm.xcb_conn);
}
xcb_window_t xwindow_get_transient_for(xcb_window_t window) { xcb_window_t xwindow_get_transient_for(xcb_window_t window) {
xcb_connection_t *conn = wm.xcb_conn; xcb_connection_t *conn = wm.xcb_conn;
xcb_window_t t_window = XCB_WINDOW_NONE; xcb_window_t t_window = XCB_WINDOW_NONE;
@@ -247,6 +258,23 @@ int32_t xwindow_get_state(xcb_window_t window) {
return hints.initial_state; return hints.initial_state;
} }
void xwindow_set_state(xcb_window_t window, xcb_icccm_wm_state_t state) {
xcb_icccm_wm_hints_t hints;
xcb_icccm_wm_hints_set_none(&hints);
switch (state) {
case XCB_ICCCM_WM_STATE_WITHDRAWN:
xcb_icccm_wm_hints_set_withdrawn(&hints);
break;
case XCB_ICCCM_WM_STATE_NORMAL:
xcb_icccm_wm_hints_set_normal(&hints);
break;
case XCB_ICCCM_WM_STATE_ICONIC:
xcb_icccm_wm_hints_set_iconic(&hints);
break;
}
xcb_icccm_set_wm_hints(wm.xcb_conn, window, &hints);
}
xcb_get_geometry_reply_t *xwindow_get_geometry_reply(xcb_window_t window) { xcb_get_geometry_reply_t *xwindow_get_geometry_reply(xcb_window_t window) {
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(wm.xcb_conn, window); xcb_get_geometry_cookie_t cookie = xcb_get_geometry(wm.xcb_conn, window);
return xcb_get_geometry_reply(wm.xcb_conn, cookie, nullptr); return xcb_get_geometry_reply(wm.xcb_conn, cookie, nullptr);

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "action.h" #include "action.h"
@@ -22,9 +23,11 @@ void xwindow_get_text_property(xcb_window_t window, xcb_atom_t property,
char **out); char **out);
void xwindow_set_wm_desktop(xcb_window_t window, uint32_t desktop); void xwindow_set_wm_desktop(xcb_window_t window, uint32_t desktop);
bool xwindow_get_wm_desktop(xcb_window_t window, uint32_t *desktop); bool xwindow_get_wm_desktop(xcb_window_t window, uint32_t *desktop);
void xwindow_kill_window(xcb_window_t window);
xcb_window_t xwindow_get_transient_for(xcb_window_t window); xcb_window_t xwindow_get_transient_for(xcb_window_t window);
int32_t xwindow_get_state(xcb_window_t window); int32_t xwindow_get_state(xcb_window_t window);
void xwindow_set_state(xcb_window_t window, xcb_icccm_wm_state_t state);
xcb_get_geometry_reply_t *xwindow_get_geometry_reply(xcb_window_t window); xcb_get_geometry_reply_t *xwindow_get_geometry_reply(xcb_window_t window);
xcb_get_window_attributes_reply_t *xwindow_get_attributes_reply( xcb_get_window_attributes_reply_t *xwindow_get_attributes_reply(
xcb_window_t window); xcb_window_t window);