From 88129293a01824d8d67e2d920eeb20691ea70470 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Wed, 29 Jul 2026 03:41:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E5=8F=91=20ConfigureNotify=20?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E5=87=A0=E4=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当 WM 拒绝窗口的 ConfigureRequest(因窗口需要重新布局)或映射 窗口时,按 ICCCM 规范主动向客户端发送 synthetic ConfigureNotify, 告知其当前真实几何,避免客户端状态不一致。 - core: 新增 NOTIFY_CONFIGURE 命令与 CONFIGURE_NOTIFY 效果, 由 policy 在 window_need_layout 分支生成,plan 层下发 - backend(x11): 新增 configure 批次,map/notify 时查询实际几何 并合成 ConfigureNotify 事件下发 --- src/backend/x11/backend.c | 51 ++++++++++++++++++++++++++++++++++++++ src/backend/x11/internal.h | 1 + src/core/command.h | 2 ++ src/core/plan.c | 10 ++++++++ src/core/plan.h | 1 + src/core/policy.c | 13 ++++++++++ src/interface/effect.h | 2 ++ 7 files changed, 80 insertions(+) diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index 4120203..5e04f20 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -558,6 +558,7 @@ static void backend_merge_effects( switch (e->type) { case ZDWM_EFFECT_MAP_WINDOW: window_list_push(&backend->map, e->as.map.window); + window_list_push(&backend->configure, e->as.map.window); break; case ZDWM_EFFECT_UNMAP_WINDOW: window_list_push(&backend->unmap, e->as.unmap.window); @@ -612,6 +613,9 @@ static void backend_merge_effects( case ZDWM_EFFECT_CONFIGURE_WINDOW: merge_window_configure_params(backend, &e->as.configure); break; + case ZDWM_EFFECT_CONFIGURE_NOTIFY: + window_list_push(&backend->configure, e->as.configure_notify.window); + break; case ZDWM_EFFECT_CHANGE_BORDER_COLOR: { xcb_change_window_attributes_value_list_t value = { .border_pixel = e->as.change_border_color.color->argb @@ -643,6 +647,46 @@ static void backend_merge_effects( } } +static void batch_send_configure_notify( + xcb_connection_t *conn, + xcb_window_t *windows, + size_t count +) { + if (count == 0) return; + + auto cookie_list = p_new(xcb_get_geometry_cookie_t, count); + + for (size_t i = 0; i < count; ++i) { + auto window = windows[i]; + cookie_list[i] = xcb_get_geometry(conn, window); + } + + uint32_t event_mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + for (size_t i = 0; i < count; ++i) { + auto window = windows[i]; + auto cookie = cookie_list[i]; + auto reply = xcb_get_geometry_reply(conn, cookie, nullptr); + if (!reply) continue; + + xcb_configure_notify_event_t ev = { + .response_type = XCB_CONFIGURE_NOTIFY, + .event = window, + .window = window, + .above_sibling = XCB_WINDOW_NONE, + .x = reply->x, + .y = reply->y, + .width = reply->width, + .height = reply->height, + .border_width = reply->border_width, + .override_redirect = false, + }; + xcb_send_event(conn, false, window, event_mask, (char *)&ev); + p_delete(&reply); + } + + p_delete(&cookie_list); +} + static void backend_batch_apply_effects(backend_t *backend) { xcb_connection_t *conn = backend->conn; if (backend->unmap.count) { @@ -672,6 +716,12 @@ static void backend_batch_apply_effects(backend_t *backend) { backend_apply_window_configure_list(backend); + { + auto windows = backend->configure.windows; + auto count = backend->configure.count; + batch_send_configure_notify(conn, windows, count); + } + if (backend->update_focus) { backend_focus_window(backend, backend->focus_window); } @@ -687,6 +737,7 @@ bool backend_apply_effect( window_list_reset(&backend->unmap); window_list_reset(&backend->map); window_list_reset(&backend->kill); + window_list_reset(&backend->configure); backend_merge_effects(backend, effects, effect_count); backend_batch_apply_effects(backend); diff --git a/src/backend/x11/internal.h b/src/backend/x11/internal.h index c0294fb..458fb49 100644 --- a/src/backend/x11/internal.h +++ b/src/backend/x11/internal.h @@ -115,6 +115,7 @@ typedef struct backend_t { window_list_t unmap; window_list_t map; window_list_t kill; + window_list_t configure; tray_host_t *tray; } backend_t; diff --git a/src/core/command.h b/src/core/command.h index bf946a8..2a3f36f 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -11,6 +11,7 @@ typedef enum command_type_t { ZDWM_COMMAND_RAISE_WINDOW, ZDWM_COMMAND_WITHDRAW_WINDOW, ZDWM_COMMAND_CONFIGURE_WINDOW, + ZDWM_COMMAND_NOTIFY_CONFIGURE, ZDWM_COMMAND_CHANGE_WINDOW_STATE, ZDWM_COMMAND_START_MOVE_WINDOW, ZDWM_COMMAND_STOP_MOVE_WINDOW, @@ -102,6 +103,7 @@ typedef struct command_t { only_window_data_t raise; only_window_data_t withdraw; configure_data_t configure; + only_window_data_t notify_configure; window_state_change_command_t state_change; start_interaction_command_t move; start_interaction_command_t resize; diff --git a/src/core/plan.c b/src/core/plan.c index 5496632..d3eb17b 100644 --- a/src/core/plan.c +++ b/src/core/plan.c @@ -121,6 +121,16 @@ void plan_push_resize_effect(plan_t *plan, window_id_t window_id) { plan_push_effect(plan, &effect); } +void plan_push_configure_notify_effect(plan_t *plan, window_id_t window_id) { + if (window_id_invalid(window_id)) return; + + effect_t effect = { + .type = ZDWM_EFFECT_CONFIGURE_NOTIFY, + .as.configure_notify.window = window_id, + }; + plan_push_effect(plan, &effect); +} + void plan_push_fullscreen_effect( plan_t *plan, window_id_t window_id, diff --git a/src/core/plan.h b/src/core/plan.h index 6912b23..3dab68f 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -26,6 +26,7 @@ void plan_push_kill_effect(plan_t *plan, window_id_t window_id); void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id); void plan_push_move_effect(plan_t *plan, window_id_t window_id); void plan_push_resize_effect(plan_t *plan, window_id_t window_id); +void plan_push_configure_notify_effect(plan_t *plan, window_id_t window_id); void plan_push_fullscreen_effect( plan_t *plan, window_id_t window_id, diff --git a/src/core/policy.c b/src/core/policy.c index 1cfef61..85856ac 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -771,6 +771,15 @@ static void route_window_state_request( command_buffer_push(out, &change_window_state_cmd); } +static void +add_notify_configure_command(command_buffer_t *out, window_id_t window) { + command_t notify_cmd = { + .type = ZDWM_COMMAND_NOTIFY_CONFIGURE, + .as.notify_configure = {.window = window}, + }; + command_buffer_push(out, ¬ify_cmd); +} + static void route_configure_request( state_t *state, const configure_data_t *data, @@ -788,6 +797,7 @@ static void route_configure_request( } if (!state_workspace_show(state, window->workspace_id)) return; + add_notify_configure_command(out, data->window); if (window_need_layout(window)) return; auto workspace = state_workspace_get(state, window->workspace_id); if (layout_get(layouts, workspace->layout_id)) return; @@ -1690,6 +1700,9 @@ void policy_apply_command( case ZDWM_COMMAND_CONFIGURE_WINDOW: configure_window(state, &cmd->as.configure, plan); break; + case ZDWM_COMMAND_NOTIFY_CONFIGURE: + plan_push_configure_notify_effect(plan, cmd->as.notify_configure.window); + break; case ZDWM_COMMAND_CHANGE_WINDOW_STATE: change_window_state(ctx, &cmd->as.state_change, plan); break; diff --git a/src/interface/effect.h b/src/interface/effect.h index 54a31c3..c4b3007 100644 --- a/src/interface/effect.h +++ b/src/interface/effect.h @@ -17,6 +17,7 @@ typedef enum effect_type_t { ZDWM_EFFECT_MAXIMIZE_WINDOW, ZDWM_EFFECT_FULLSCREEN_WINDOW, ZDWM_EFFECT_CONFIGURE_WINDOW, + ZDWM_EFFECT_CONFIGURE_NOTIFY, ZDWM_EFFECT_CHANGE_BORDER_COLOR, ZDWM_EFFECT_CHANGE_WINDOW_LIST, ZDWM_EFFECT_RESTACK_WINDOWS, @@ -86,6 +87,7 @@ typedef struct effect_t { effect_bool_window_t maximize; effect_bool_window_t fullscreen; configure_data_t configure; + only_window_data_t configure_notify; effect_change_border_color_t change_border_color; effect_window_list_t change_window_list; effect_window_list_t restack_windows;