From b71b66921eb1e225f6bf6500cb453d92ee93cb62 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Mon, 22 Jun 2026 23:22:08 +0800 Subject: [PATCH] =?UTF-8?q?refactor(window):=20=E7=94=A8=E6=9B=B4=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=B0=BA=E5=AF=B8=E6=8F=90=E7=A4=BA(min/max?= =?UTF-8?q?=20size)=E6=9B=BF=E6=8D=A2=20fixed=5Fsize=20=E6=A0=87=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/x11/event.c | 63 +++++++++++++++++++--------- src/backend/x11/window.c | 16 +++----- src/backend/x11/window.h | 6 ++- src/core/command.h | 2 + src/core/event.h | 5 ++- src/core/policy.c | 88 ++++++++++++++++++++++++---------------- src/core/state.c | 22 +--------- src/core/state.h | 10 ----- src/core/types.h | 20 ++++++++- src/core/window.c | 25 +++++++++--- src/core/window.h | 7 +++- src/core/wm_desc.h | 4 +- 12 files changed, 161 insertions(+), 107 deletions(-) diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index c05719f..672f3ac 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -92,6 +92,28 @@ static bool urgent_from_states( return false; } +static void parse_size_hints( + const xcb_size_hints_t *hints, + zdwm_size_t *min, + zdwm_size_t *max +) { + assert(hints != nullptr); + assert(min != nullptr); + assert(max != nullptr); + + *min = (zdwm_size_t){.width = 0, .height = 0}; + *max = (zdwm_size_t){.width = INT32_MAX, .height = INT32_MAX}; + + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { + min->width = hints->min_width; + min->height = hints->min_height; + } + if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { + max->width = hints->max_width; + max->height = hints->max_height; + } +} + bool populate_window_event( backend_t *backend, xcb_window_t window, @@ -100,8 +122,7 @@ bool populate_window_event( ev->window = (window_id_t)window; ev->transient_for = window_get_transient_for(backend, window); - xcb_get_window_attributes_reply_t *wa = - window_get_attributes(backend, window); + auto wa = window_get_attributes(backend, window); if (!wa) return false; ev->override_redirect = (bool)wa->override_redirect; p_delete(&wa); @@ -112,7 +133,10 @@ bool populate_window_event( ev->minimized = minimized_from_hints(&wm_hints); } - if (!window_get_fixed_size(backend, window, &ev->fixed_size)) return false; + xcb_size_hints_t size_hints = {0}; + if (!window_get_size_hints(backend, window, &size_hints)) return false; + parse_size_hints(&size_hints, &ev->min_size, &ev->max_size); + if (!window_get_geometry(backend, window, &ev->rect)) return false; const atoms_t *atoms = &backend->atoms; @@ -360,34 +384,31 @@ static bool handle_property_notify( if (xcb_event->atom == XCB_ATOM_WM_HINTS) { xcb_icccm_wm_hints_t hints = {0}; - auto handled = window_get_wm_hints(backend, window_id, &hints); - if (!handled) return false; + if (!window_get_wm_hints(backend, window_id, &hints)) return false; - event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST; + event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; - auto data = &event->as.window_state_request; + auto data = &event->as.hints; data->window = window_id; if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) { - data->type = ZDWM_WINDOW_STATE_REQUEST_URGENT; - data->action = xcb_icccm_wm_hints_get_urgency(&hints) - ? ZDWM_WINDOW_STATE_ACTION_ADD - : ZDWM_WINDOW_STATE_ACTION_REMOVE; + data->changed_fields |= ZDWM_HINT_FIELD_URGENT; + data->urgent = xcb_icccm_wm_hints_get_urgency(&hints); return true; } return false; } if (xcb_event->atom == XCB_ATOM_WM_NORMAL_HINTS) { - bool fixed_size = false; - if (!window_get_fixed_size(backend, window_id, &fixed_size)) return false; + xcb_size_hints_t hints = {0}; + if (!window_get_size_hints(backend, window_id, &hints)) return false; - event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST; + event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; - auto data = &event->as.window_state_request; + auto data = &event->as.hints; data->window = window_id; - data->type = ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE; - data->action = fixed_size ? ZDWM_WINDOW_STATE_ACTION_ADD - : ZDWM_WINDOW_STATE_ACTION_REMOVE; + + data->changed_fields |= ZDWM_HINT_FIELD_SIZE; + parse_size_hints(&hints, &data->min_size, &data->max_size); return true; } @@ -467,7 +488,11 @@ static bool handle_client_message( } if (urgent_from_states(atoms, properties, count)) { - data->type = ZDWM_WINDOW_STATE_REQUEST_URGENT; + event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; + event->as.hints = (typeof(event->as.hints)){ + .urgent = true, + .changed_fields = ZDWM_HINT_FIELD_URGENT, + }; return true; } diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 7d51504..dd68195 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -160,22 +160,18 @@ bool window_get_types( return true; } -bool window_get_fixed_size(backend_t *backend, xcb_window_t window, bool *out) { - xcb_size_hints_t hints = {0}; +bool window_get_size_hints( + backend_t *backend, + xcb_window_t window, + xcb_size_hints_t *out +) { xcb_connection_t *conn = backend->conn; xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_normal_hints_unchecked(conn, window); - if (!xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &hints, nullptr)) { + if (!xcb_icccm_get_wm_normal_hints_reply(conn, cookie, out, nullptr)) { return false; } - if ((hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) && - (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) { - *out = hints.min_width == hints.max_width && - hints.min_height == hints.max_height; - } else { - *out = false; - } return true; } diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 23d6b6f..a9543c6 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -54,7 +54,11 @@ bool window_get_types( window_type_t **types, size_t *count ); -bool window_get_fixed_size(backend_t *backend, xcb_window_t window, bool *out); +bool window_get_size_hints( + backend_t *backend, + xcb_window_t window, + xcb_size_hints_t *out +); bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out); bool window_get_atom_array( backend_t *backend, diff --git a/src/core/command.h b/src/core/command.h index a99dbb1..f0e5493 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -22,6 +22,7 @@ typedef enum command_type_t { ZDWM_COMMAND_WINDOW_SET_MINIMIZED, ZDWM_COMMAND_WINDOW_SET_MAXIMIZED, ZDWM_COMMAND_WINDOW_SET_FULLSCREEN, + ZDWM_COMMAND_CHANGE_HINTS, ZDWM_COMMAND_SWITCH_WORKSPACE, ZDWM_COMMAND_SET_CURRENT_OUTPUT, ZDWM_COMMAND_SET_LAYOUT, @@ -110,6 +111,7 @@ typedef struct command_t { window_bool_state_t minimized; window_bool_state_t maximized; window_bool_state_t fullscreen; + hints_data_t hints; switch_workspace_command_t switch_workspace; set_current_output_command_t current_output; set_layout_command_t layout; diff --git a/src/core/event.h b/src/core/event.h index 07fa505..a252b80 100644 --- a/src/core/event.h +++ b/src/core/event.h @@ -47,12 +47,14 @@ typedef struct window_map_request_event_t { bool override_redirect; bool skip_taskbar; bool urgent; - bool fixed_size; bool fullscreen; bool maximized; bool minimized; rect_t rect; + zdwm_size_t min_size; + zdwm_size_t max_size; + window_layer_props_t props; window_metadata_t metadata; } window_map_request_event_t; @@ -101,6 +103,7 @@ typedef struct event_t { window_map_request_event_t window_map_request; window_remove_event_t window_remove; window_metadata_change_event_t window_metadata_change; + hints_data_t hints; window_activate_request_event_t window_activate_request; window_state_request_event_t window_state_request; configure_data_t configure_request; diff --git a/src/core/policy.c b/src/core/policy.c index ec3545c..2cf155b 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -606,8 +606,9 @@ static void route_map_request( .maximized = e->maximized, .minimized = e->minimized, .urgent = e->urgent, - .fixed_size = e->fixed_size, .skip_taskbar = e->skip_taskbar, + .min_size = e->min_size, + .max_size = e->max_size, }, }, }; @@ -690,28 +691,35 @@ static void route_window_metadata_changed( listeners_notify_window_updated(ctx->listeners, state, window_id); } +static void route_window_hints_changed( + state_t *state, + const hints_data_t *data, + command_buffer_t *out +) { + auto window = (window_t *)state_window_get(state, data->window); + if (!window) return; + + command_t change_hints_cmd = { + .type = ZDWM_COMMAND_CHANGE_HINTS, + .as.hints = *data, + }; + command_buffer_push(out, &change_hints_cmd); +} + static void route_window_activate_request( state_t *state, const window_activate_request_event_t *e, command_buffer_t *out ) { - auto window = state_window_get(state, e->window); + auto window = (window_t *)state_window_get(state, e->window); if (!window) return; switch (e->source) { case ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY: break; - case ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION: { - command_t change_window_state_cmd = { - .type = ZDWM_COMMAND_CHANGE_WINDOW_STATE, - .as.state_change = { - .type = ZDWM_WINDOW_STATE_REQUEST_URGENT, - .window = window->id, - .action = ZDWM_WINDOW_STATE_ACTION_ADD, - } - }; - command_buffer_push(out, &change_window_state_cmd); - } break; + case ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION: + window->urgent = true; + break; case ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER: add_switch_workspace_command(out, window->workspace_id); add_focus_window_command(out, window->id); @@ -776,6 +784,8 @@ void policy_route_event( ) { auto state = ctx->state; switch (event->type) { + case ZDWM_EVENT_NONE: + break; case ZDWM_EVENT_KEY_PRESS: route_key_press(ctx, &event->as.key_press, out); break; @@ -800,6 +810,9 @@ void policy_route_event( case ZDWM_EVENT_WINDOW_METADATA_CHANGED: route_window_metadata_changed(ctx, &event->as.window_metadata_change); break; + case ZDWM_EVENT_WINDOW_HINTS_CHANGED: + route_window_hints_changed(state, &event->as.hints, out); + break; case ZDWM_EVENT_WINDOW_ACTIVATE_REQUEST: { auto data = &event->as.window_activate_request; route_window_activate_request(state, data, out); @@ -811,7 +824,6 @@ void policy_route_event( auto data = &event->as.configure_request; route_configure_request(state, data, ctx->layouts, out); } break; - default: } } @@ -902,12 +914,17 @@ static void manage_window( auto window_id = window->id; auto workspace_id = command->workspace; state_window_set_workspace(state, window_id, workspace_id); - state_window_set_floating(state, window_id, command->floating); set_foucs_window(ctx, workspace_id, window_id, plan); plan_push_grab_button_effect(plan, window_id); push_window_list_effect(state, plan); listeners_notify_window_added(ctx->listeners, state, window_id); + if (window_should_fix_size(window)) { + state_window_set_floating(state, window_id, true); + } else { + state_window_set_floating(state, window_id, command->floating); + } + auto need_layout = window_need_layout(window); if (need_layout) { adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); @@ -1297,12 +1314,6 @@ static void change_window_state( case ZDWM_WINDOW_STATE_REQUEST_SKIP_TASKBAR: value = !window->skip_taskbar; break; - case ZDWM_WINDOW_STATE_REQUEST_URGENT: - value = !window->urgent; - break; - case ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE: - value = !window->fixed_size; - break; } } @@ -1320,12 +1331,6 @@ static void change_window_state( case ZDWM_WINDOW_STATE_REQUEST_SKIP_TASKBAR: state_window_set_skip_taskbar(state, window->id, value); break; - case ZDWM_WINDOW_STATE_REQUEST_URGENT: - state_window_set_urgent(state, window->id, value); - break; - case ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE: - state_window_set_fixed_size(state, window->id, value); - break; } listeners_notify_window_updated(ctx->listeners, state, command->window); @@ -1490,12 +1495,20 @@ static void command_window_set_maximized( maximize_window(ctx, data->window, data->state, plan); } -static void command_window_set_fullscreen( - const policy_context_t *ctx, - const window_bool_state_t *data, - plan_t *plan -) { - fullscreen_window(ctx, data->window, data->state, plan); +static void +command_change_hints(state_t *state, hints_data_t *data, plan_t *plan) { + auto window = (window_t *)state_window_get(state, data->window); + if (data->changed_fields & ZDWM_HINT_FIELD_URGENT) { + window->urgent = data->urgent; + } + if (data->changed_fields & ZDWM_HINT_FIELD_SIZE) { + window->max_size = data->max_size; + window->min_size = data->min_size; + + auto floating = window->floating; + if (window_should_fix_size(window)) window_set_floating(window, true); + if (floating != window->floating) plan->need_relayout = true; + } } static inline void change_current_output( @@ -1674,8 +1687,13 @@ void policy_apply_command( case ZDWM_COMMAND_WINDOW_SET_MAXIMIZED: command_window_set_maximized(ctx, &cmd->as.maximized, plan); break; - case ZDWM_COMMAND_WINDOW_SET_FULLSCREEN: - command_window_set_fullscreen(ctx, &cmd->as.fullscreen, plan); + case ZDWM_COMMAND_WINDOW_SET_FULLSCREEN: { + auto window = cmd->as.fullscreen.window; + auto state = cmd->as.fullscreen.state; + fullscreen_window(ctx, window, state, plan); + } break; + case ZDWM_COMMAND_CHANGE_HINTS: + command_change_hints(state, &cmd->as.hints, plan); break; case ZDWM_COMMAND_SWITCH_WORKSPACE: switch_workspace(ctx, cmd->as.switch_workspace.workspace, plan); diff --git a/src/core/state.c b/src/core/state.c index c3fa300..b3f98ba 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -328,9 +328,9 @@ const window_t *state_window_add(state_t *state, const window_info_t *info) { window_set_maximized(window, info->maximized); window_set_minimized(window, info->minimized); window_set_urgent(window, info->urgent); - window_set_fixed_size(window, info->fixed_size); window_set_frame_rect(window, info->frame_rect); window_set_float_rect(window, info->frame_rect); + window_set_size_hint(window, info->min_size, info->max_size); window_set_title(window, info->title); window_set_app_id(window, info->app_id); window_set_role(window, info->role); @@ -469,24 +469,6 @@ void state_window_set_sticky( if (window) window_set_sticky(window, sticky); } -void state_window_set_urgent( - state_t *state, - window_id_t window_id, - bool urgent -) { - window_t *window = (window_t *)state_window_get(state, window_id); - if (window) window_set_urgent(window, urgent); -} - -void state_window_set_fixed_size( - state_t *state, - window_id_t window_id, - bool fixed_size -) { - window_t *window = (window_t *)state_window_get(state, window_id); - if (window) window_set_fixed_size(window, fixed_size); -} - void state_window_set_border_width( state_t *state, window_id_t window_id, @@ -502,7 +484,7 @@ void state_window_set_skip_taskbar( bool skip_taskbar ) { window_t *window = (window_t *)state_window_get(state, window_id); - if (window) window_set_skip_taskbar(window, skip_taskbar); + if (window) window->skip_taskbar = skip_taskbar; } void state_window_set_float_rect( diff --git a/src/core/state.h b/src/core/state.h index 2353a77..7d94442 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -224,16 +224,6 @@ void state_window_set_sticky( window_id_t window_id, bool sticky ); -void state_window_set_urgent( - state_t *state, - window_id_t window_id, - bool urgent -); -void state_window_set_fixed_size( - state_t *state, - window_id_t window_id, - bool fixed_size -); void state_window_set_border_width( state_t *state, window_id_t window_id, diff --git a/src/core/types.h b/src/core/types.h index a7fffc4..261de4e 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -72,8 +72,6 @@ typedef enum window_state_request_type_t { ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED, ZDWM_WINDOW_STATE_REQUEST_MINIMIZED, ZDWM_WINDOW_STATE_REQUEST_SKIP_TASKBAR, - ZDWM_WINDOW_STATE_REQUEST_URGENT, - ZDWM_WINDOW_STATE_REQUEST_FIXED_SIZE, } window_state_request_type_t; typedef enum window_state_request_action_t { @@ -114,6 +112,24 @@ typedef struct only_window_data_t { window_id_t window; } only_window_data_t; +typedef enum hint_field_t { + ZDWM_HINT_FIELD_URGENT, + ZDWM_HINT_FIELD_SIZE, +} hint_field_t; + +typedef struct zdwm_size_t { + int32_t width; + int32_t height; +} zdwm_size_t; + +typedef struct hints_data_t { + window_id_t window; + uint32_t changed_fields; + bool urgent; + zdwm_size_t min_size; + zdwm_size_t max_size; +} hints_data_t; + typedef enum window_interaction_mode_t { ZDWM_WINDOW_INTERACTION_NONE, ZDWM_WINDOW_INTERACTION_MOVE, diff --git a/src/core/window.c b/src/core/window.c index 054e19d..8d74c16 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -49,7 +49,7 @@ void window_set_minimized(window_t *window, bool minimized) { } void window_set_floating(window_t *window, bool floating) { - if (!floating && (window->fixed_size || window->sticky)) return; + if (!floating && (window_should_fix_size(window) || window->sticky)) return; if (floating == window->floating) return; @@ -67,11 +67,6 @@ void window_set_urgent(window_t *window, bool urgent) { window->urgent = urgent; } -void window_set_fixed_size(window_t *window, bool fixed_size) { - window->fixed_size = fixed_size; - if (fixed_size) window_set_floating(window, true); -} - void window_set_skip_taskbar(window_t *window, bool skip_taskbar) { window->skip_taskbar = skip_taskbar; } @@ -84,6 +79,18 @@ void window_set_frame_rect(window_t *window, rect_t rect) { window->frame_rect = rect; } +void window_set_size_hint(window_t *window, zdwm_size_t min, zdwm_size_t max) { + window->min_size = min; + window->max_size = max; + if (!window_should_fix_size(window)) return; + + auto rect = window->frame_rect; + rect.width = min.width; + rect.height = min.height; + window_set_frame_rect(window, rect); + window_set_floating(window, true); +} + void window_set_title(window_t *window, const char *title) { p_delete(&window->title); window->title = p_strdup_nullable(title); @@ -158,3 +165,9 @@ bool window_should_has_border(const window_t *window) { if (window->fullscreen || window->maximized) return false; return window->floating; } + +bool window_should_fix_size(const window_t *window) { + auto max = window->max_size; + auto min = window->min_size; + return max.width == min.width && max.height == min.height; +} diff --git a/src/core/window.h b/src/core/window.h index 0b30e41..2bf70b2 100644 --- a/src/core/window.h +++ b/src/core/window.h @@ -76,9 +76,11 @@ typedef struct window_t { bool floating; bool sticky; bool urgent; - bool fixed_size; bool skip_taskbar; + zdwm_size_t min_size; + zdwm_size_t max_size; + /* 几何信息(均为包含边框后的外框矩形) */ rect_t float_rect; /* floating 模式下记忆的外框矩形 */ rect_t frame_rect; /* 当前外框矩形(由 layout 或 float_rect 解析) */ @@ -104,10 +106,10 @@ void window_set_minimized(window_t *window, bool minimized); void window_set_floating(window_t *window, bool floating); void window_set_sticky(window_t *window, bool sticky); void window_set_urgent(window_t *window, bool urgent); -void window_set_fixed_size(window_t *window, bool fixed_size); void window_set_skip_taskbar(window_t *window, bool skip_taskbar); void window_set_float_rect(window_t *window, rect_t rect); void window_set_frame_rect(window_t *window, rect_t rect); +void window_set_size_hint(window_t *window, zdwm_size_t min, zdwm_size_t max); void window_set_title(window_t *window, const char *title); void window_set_app_id(window_t *window, const char *app_id); void window_set_role(window_t *window, const char *role); @@ -127,3 +129,4 @@ bool window_need_layout(const window_t *window); bool window_need_move(const window_t *window, int32_t x, int32_t y); bool window_need_resize(const window_t *window, int32_t width, int32_t height); bool window_should_has_border(const window_t *window); +bool window_should_fix_size(const window_t *window); diff --git a/src/core/wm_desc.h b/src/core/wm_desc.h index 272430c..f941b8a 100644 --- a/src/core/wm_desc.h +++ b/src/core/wm_desc.h @@ -27,8 +27,10 @@ typedef struct window_info_t { bool maximized; bool minimized; bool urgent; - bool fixed_size; bool skip_taskbar; + + zdwm_size_t min_size; + zdwm_size_t max_size; } window_info_t; typedef struct workspace_desc_t {