添加关闭窗口功能

This commit is contained in:
2026-02-24 03:12:48 +08:00
parent 6d65c53d43
commit d516d8f9e0
10 changed files with 84 additions and 13 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);
}
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_fullscreen(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
WM_DELETE_WINDOW
WM_PROTOCOLS
WM_TAKE_FOCUS
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,
xcb_get_geometry_reply_t *geometry_reply) {
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;
{
const xcb_params_cw_t params = {
.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);
set_window_event_mask(window, false);
xcb_map_window(wm.xcb_conn, window);
}
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,
_NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, 1, &window);
xwindow_set_state(window, XCB_ICCCM_WM_STATE_NORMAL);
monitor_arrange(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;
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 (!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);
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_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_workarea_geometry(client_t *client, area_t geometry);
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, XK_f, toggle_client_fullscreen, {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_Down, change_volume, {.i = -1}},

View File

@@ -4,6 +4,7 @@
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.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) {
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) {
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) {

View File

@@ -314,6 +314,16 @@ void wm_scan_clients(void) {
void wm_clean(void) {
clean_status();
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);
for (int i = 0; i < countof(sources); i++) {
@@ -321,7 +331,6 @@ void wm_clean(void) {
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_SUPPORTING_WM_CHECK);
xcb_aux_sync(wm.xcb_conn);

View File

@@ -228,6 +228,14 @@ bool xwindow_get_wm_desktop(xcb_window_t window, uint32_t *desktop) {
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_connection_t *conn = wm.xcb_conn;
xcb_window_t t_window = XCB_WINDOW_NONE;
@@ -250,6 +258,23 @@ int32_t xwindow_get_state(xcb_window_t window) {
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_cookie_t cookie = xcb_get_geometry(wm.xcb_conn, window);
return xcb_get_geometry_reply(wm.xcb_conn, cookie, nullptr);

View File

@@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xproto.h>
#include "action.h"
@@ -22,9 +23,11 @@ void xwindow_get_text_property(xcb_window_t window, xcb_atom_t property,
char **out);
void xwindow_set_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);
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_window_attributes_reply_t *xwindow_get_attributes_reply(
xcb_window_t window);