From 323a0f371120c4cb332c68119bc000eac858f08b Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Thu, 26 Feb 2026 11:28:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=AA=97=E5=8F=A3=E6=9C=80?= =?UTF-8?q?=E5=B0=8F=E5=8C=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/action.c | 8 ++++++ src/action.h | 2 ++ src/atoms-list.txt | 1 + src/client.c | 38 +++++++++++++++++++++---- src/default_config.h | 1 + src/event.c | 67 +++++++++++++++++++++++++++++++------------- 6 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/action.c b/src/action.c index 3e6ac12..58f5305 100644 --- a/src/action.c +++ b/src/action.c @@ -105,6 +105,14 @@ void toggle_client_maximize(const user_action_arg_t *arg) { client_set_maximize(wm.client_focused, !wm.client_focused->maximize); } +void toggle_client_minimize(const user_action_arg_t *arg) { + client_t *client = wm.client_focused; + if (arg->ptr) client = (client_t *)arg->ptr; + if (!client) return; + + client_set_minimize(client, !client->minimize); +} + void kill_client(const user_action_arg_t *arg) { if (wm.client_focused) { client_kill(wm.client_focused); diff --git a/src/action.h b/src/action.h index 0273998..e0ac62c 100644 --- a/src/action.h +++ b/src/action.h @@ -13,6 +13,7 @@ typedef union user_action_arg_t { typedef enum click_area_t { click_none, click_tag, + click_client_name, } click_area_t; typedef enum modifier_t { @@ -60,4 +61,5 @@ 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 toggle_client_minimize(const user_action_arg_t *arg); void kill_client(const user_action_arg_t *arg); diff --git a/src/atoms-list.txt b/src/atoms-list.txt index 1fc8d1b..2832a0b 100644 --- a/src/atoms-list.txt +++ b/src/atoms-list.txt @@ -1,5 +1,6 @@ _XKB_RULES_NAMES +WM_CHANGE_STATE WM_DELETE_WINDOW WM_PROTOCOLS WM_TAKE_FOCUS diff --git a/src/client.c b/src/client.c index 0f92ed0..9bf3804 100644 --- a/src/client.c +++ b/src/client.c @@ -140,7 +140,7 @@ static inline void client_update_names(client_t *c) { } static inline void client_init_geometry(client_t *c) { - if (c->maximize || c->fullscreen) return; + if (c->maximize || c->fullscreen || c->minimize) return; area_t workarea = c->monitor->workarea; if (c->geometry.x + client_width(c) > workarea.x + workarea.width) { @@ -194,10 +194,10 @@ void client_manage(xcb_window_t window, c->geometry = c->old_geometry; c->old_border_width = geometry_reply->border_width; - { - set_window_event_mask(window, false); - xcb_map_window(wm.xcb_conn, window); - } + c->minimize = xwindow_get_state(window) == XCB_ICCCM_WM_STATE_ICONIC; + + set_window_event_mask(window, false); + client_update_names(c); xwindow_get_text_property(c->window, WM_WINDOW_ROLE, &c->role); client_update_wm_hints(c); @@ -242,7 +242,13 @@ 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); + + if (c->minimize) { + xwindow_set_state(window, XCB_ICCCM_WM_STATE_ICONIC); + } else { + xwindow_set_state(window, XCB_ICCCM_WM_STATE_NORMAL); + xcb_map_window(wm.xcb_conn, window); + } monitor_arrange(c->monitor); monitor_draw_bar(c->monitor); @@ -469,6 +475,26 @@ void client_set_maximize(client_t *client, bool maximize) { client_focus(client); } +void client_set_minimize(client_t *client, bool minimize) { + if (client->minimize == minimize) return; + + client->minimize = minimize; + if (minimize) { + xwindow_set_state(client->window, XCB_ICCCM_WM_STATE_ICONIC); + + xcb_grab_server(wm.xcb_conn); + set_window_event_mask(client->window, true); + xcb_unmap_window(wm.xcb_conn, client->window); + set_window_event_mask(client->window, false); + xcb_ungrab_server(wm.xcb_conn); + } else { + xwindow_set_state(client->window, XCB_ICCCM_WM_STATE_NORMAL); + xcb_map_window(wm.xcb_conn, client->window); + } + monitor_arrange(client->monitor); + client_focus(client); +} + static void update_client_list(void) { xcb_connection_t *conn = wm.xcb_conn; xcb_window_t root = wm.screen->root; diff --git a/src/default_config.h b/src/default_config.h index 527ecb3..8bf1170 100644 --- a/src/default_config.h +++ b/src/default_config.h @@ -29,6 +29,7 @@ static const char *const active_border_color = "#005577"; static const button_t button_list[] = { {click_tag, modifier_none, button_left, select_tag_of_current_monitor, {0}}, + {click_client_name, modifier_none, button_left, toggle_client_minimize, {0}}, }; #define TAGKEYS(KEY, TAG) \ diff --git a/src/event.c b/src/event.c index 3a76787..2f5101f 100644 --- a/src/event.c +++ b/src/event.c @@ -24,26 +24,44 @@ static void button_press(xcb_button_press_event_t *ev) { click_area_t click_area = click_none; user_action_arg_t arg = {0}; + monitor_t *monitor = nullptr; for (monitor_t *m = wm.monitor_list; m; m = m->next) { if (ev->event == m->bar_window) { - if (wm.current_monitor != m) wm.current_monitor = m; - - if (ev->event_x >= m->tag_extent.start && - ev->event_x <= m->tag_extent.end) { - click_area = click_tag; - - for (tag_t *tag = m->tag_list; tag; tag = tag->next) { - if (ev->event_x >= tag->bar_extent.start && - ev->event_x <= tag->bar_extent.end) { - arg.ui = tag->mask; - break; - } - } - } + monitor = m; break; } } + if (!monitor) return; + + wm.current_monitor = monitor; + if (ev->event_x >= monitor->tag_extent.start && + ev->event_x <= monitor->tag_extent.end) { + click_area = click_tag; + + for (tag_t *tag = monitor->tag_list; tag; tag = tag->next) { + if (ev->event_x >= tag->bar_extent.start && + ev->event_x <= tag->bar_extent.end) { + arg.ui = tag->mask; + break; + } + } + } + + if (click_area == click_none) { + for (task_in_tag_t *task = monitor->selected_tag->task_list; task; + task = task->next) { + if (ev->event_x >= task->bar_extent.start && + ev->event_x <= task->bar_extent.end) { + click_area = click_client_name; + arg.ptr = task->client; + break; + } + } + } + + if (click_area == click_none) return; + for (int i = 0; i < countof(button_list); i++) { if (click_area == button_list[i].click_area && button_list[i].button == ev->detail && @@ -209,6 +227,15 @@ static void client_message(xcb_client_message_event_t *ev) { ev->data.data32[2] == _NET_WM_STATE_MAXIMIZED_VERT) { client_set_maximize(c, get_bool_property(c->maximize, action)); } + } else if (ev->type == WM_CHANGE_STATE) { + switch (ev->data.data32[0]) { + case XCB_ICCCM_WM_STATE_ICONIC: + client_set_minimize(c, true); + break; + case XCB_ICCCM_WM_STATE_NORMAL: + client_set_minimize(c, false); + break; + } } } @@ -238,12 +265,12 @@ static void destroy_notify(xcb_destroy_notify_event_t *ev) { static void unmap_notify(xcb_unmap_notify_event_t *ev) { client_t *client = client_get_by_window(ev->window); - if (client) { - if (XCB_EVENT_SENT(ev)) { - xwindow_set_state(ev->window, XCB_ICCCM_WM_STATE_WITHDRAWN); - } else { - client_unmanage(client, false); - } + if (!client || client->minimize) return; + + if (XCB_EVENT_SENT(ev)) { + xwindow_set_state(ev->window, XCB_ICCCM_WM_STATE_WITHDRAWN); + } else { + client_unmanage(client, false); } }