From ff3b51fd1d7a1df448044246b4636e81eb5ee6b6 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Tue, 26 May 2026 13:15:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(policy):=20=E6=89=A9=E5=B1=95=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=B9=B6=E5=AE=9E=E7=8E=B0=E7=AA=97=E5=8F=A3=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E3=80=81=20output/layout/binding=5Fmode=20=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - command.h 新增 SEND_TO_WORKSPACE、SET_CURRENT_OUTPUT、SET_LAYOUT、SET_BINDING_MODE 四个命令类型及载荷 - policy.c 实现对应的 apply 逻辑,包含焦点转移、映射/取消映射副作用和 listener 通知 - plan.h 增加 quit/will_restart 标志,为后续优雅退出做准备 - binding.c 对重复设置同一 mode 增加短路返回 --- src/core/binding.c | 2 +- src/core/command.h | 27 ++++++++++ src/core/plan.h | 2 + src/core/policy.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) diff --git a/src/core/binding.c b/src/core/binding.c index 105e2ae..6e6a1be 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -225,7 +225,7 @@ bool binding_table_set_current_mode( binding_table_t *table, zdwm_binding_mode_id_t mode_id ) { - if (mode_id >= table->count) return false; + if (mode_id >= table->count || mode_id == table->current_mode) return false; table->current_mode = mode_id; return true; diff --git a/src/core/command.h b/src/core/command.h index 1ccefd8..1c2a8f6 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -12,12 +12,16 @@ typedef enum command_type_t { ZDWM_COMMAND_WITHDRAW_WINDOW, ZDWM_COMMAND_CONFIGURE_WINDOW, ZDWM_COMMAND_CHANGE_WINDOW_STATE, + ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE, ZDWM_COMMAND_WINDOW_SET_FLOATING, ZDWM_COMMAND_WINDOW_SET_STICKY, ZDWM_COMMAND_WINDOW_SET_MINIMIZED, ZDWM_COMMAND_WINDOW_SET_MAXIMIZED, ZDWM_COMMAND_WINDOW_SET_FULLSCREEN, ZDWM_COMMAND_SWITCH_WORKSPACE, + ZDWM_COMMAND_SET_CURRENT_OUTPUT, + ZDWM_COMMAND_SET_LAYOUT, + ZDWM_COMMAND_SET_BINDING_MODE, } command_type_t; typedef struct manage_window_command_t { @@ -36,11 +40,30 @@ typedef struct window_state_change_command_t { window_state_request_action_t action; } window_state_change_command_t; +typedef struct window_send_to_workspace_command_t { + window_id_t window; + workspace_id_t workspace; +} window_send_to_workspace_command_t; + typedef struct window_bool_state_t { window_id_t window; bool state; } window_bool_state_t; +typedef struct set_current_output_command_t { + output_id_t output; +} set_current_output_command_t; + +typedef struct set_layout_command_t { + workspace_id_t workspace; + layout_id_t layout; +} set_layout_command_t; + +typedef struct set_binding_mode_command_t { + zdwm_binding_mode_id_t mode; +} set_binding_mode_command_t; + + /** * @brief 非 owning 的命令值对象 * @details @@ -61,11 +84,15 @@ typedef struct command_t { only_window_data_t withdraw; configure_data_t configure; window_state_change_command_t state_change; + window_send_to_workspace_command_t send_to_workspace; window_bool_state_t floating; window_bool_state_t sticky; window_bool_state_t minimized; window_bool_state_t maximized; window_bool_state_t fullscreen; switch_workspace_command_t switch_workspace; + set_current_output_command_t current_output; + set_layout_command_t layout; + set_binding_mode_command_t binding_mode; } as; } command_t; diff --git a/src/core/plan.h b/src/core/plan.h index 45eb1bb..b01d386 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -77,6 +77,8 @@ typedef struct plan_t { size_t count; size_t capacity; bool need_relayout; + bool quit; + bool will_restart; } plan_t; void plan_reset(plan_t *plan); diff --git a/src/core/policy.c b/src/core/policy.c index b05476a..ec5e208 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -788,6 +788,82 @@ static void change_window_state( } } +static void send_window_to_workspace( + const policy_context_t *ctx, + const window_send_to_workspace_command_t *command, + plan_t *plan +) { + auto state = ctx->state; + auto window = state_window_get(state, command->window); + if (!window) return; + if (!state_workspace_valid(state, command->workspace)) return; + if (window->workspace_id == command->workspace) return; + + workspace_id_t src_workspace_id = window->workspace_id; + bool src_visible = state_workspace_show(state, src_workspace_id); + bool dst_visible = state_workspace_show(state, command->workspace); + + const workspace_t *src_ws = state_workspace_get(state, src_workspace_id); + window_id_t src_old_focused = + src_ws ? src_ws->focused_window_id : ZDWM_WINDOW_ID_INVALID; + + state_window_set_workspace(state, command->window, command->workspace); + + if (!window->sticky) { + if (src_visible) plan_push_unmap_effect(plan, command->window); + if (dst_visible) plan_push_map_effect(plan, command->window); + } + + if (src_visible) { + if (src_ws && src_ws->focused_window_id != src_old_focused) { + if (!window_id_invalid(src_old_focused) && + state_window_get(state, src_old_focused)) { + plan_push_change_border_color_effect( + plan, + src_old_focused, + &ctx->border->normal_color + ); + } + if (!window_id_invalid(src_ws->focused_window_id) && + state_window_get(state, src_ws->focused_window_id)) { + plan_push_focus_effect(plan, src_ws->focused_window_id); + plan_push_change_border_color_effect( + plan, + src_ws->focused_window_id, + &ctx->border->focused_color + ); + } + } + adjust_layout_windows_border_width( + state, + ctx->border->width, + src_workspace_id + ); + } + + if (dst_visible) { + set_foucs_window(ctx, command->workspace, command->window, plan); + adjust_layout_windows_border_width( + state, + ctx->border->width, + command->workspace + ); + } + + plan->need_relayout = true; + + auto listeners = ctx->listeners; + listeners_notify_window_updated(listeners, state, command->window); + if (src_ws && src_ws->focused_window_id != src_old_focused && + !window_id_invalid(src_ws->focused_window_id)) { + listeners_notify_window_updated( + listeners, + state, + src_ws->focused_window_id + ); + } +} + static void command_window_set_floating( const policy_context_t *ctx, const window_bool_state_t *data, @@ -855,6 +931,37 @@ switch_workspace(state_t *state, workspace_id_t workspace_id, plan_t *plan) { state_set_current_output(state, output_id); } +static void set_current_output( + const policy_context_t *ctx, + const set_current_output_command_t *command +) { + if (!state_set_current_output(ctx->state, command->output)) return; + listeners_notify_current_output(ctx->listeners, command->output); +} + +static void set_layout( + const policy_context_t *ctx, + const set_layout_command_t *command, + plan_t *plan +) { + auto state = ctx->state; + auto workspace_id = command->workspace; + auto layout_id = command->layout; + + if (!state_workspace_set_layout_by_id(state, workspace_id, layout_id)) return; + + plan->need_relayout = true; + listeners_notify_layout(ctx->listeners, ctx->layouts, workspace_id, layout_id); +} + +static void set_binding_mode( + const policy_context_t *ctx, + zdwm_binding_mode_id_t binding_mode +) { + if (!binding_table_set_current_mode(ctx->bind_table, binding_mode)) return; + listeners_notify_binding_mode(ctx->listeners, ctx->bind_table); +} + void policy_apply_command( const policy_context_t *ctx, const command_buffer_t *command_buffer, @@ -888,6 +995,9 @@ void policy_apply_command( case ZDWM_COMMAND_CHANGE_WINDOW_STATE: change_window_state(ctx, &cmd->as.state_change, plan); break; + case ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE: + send_window_to_workspace(ctx, &cmd->as.send_to_workspace, plan); + break; case ZDWM_COMMAND_WINDOW_SET_FLOATING: command_window_set_floating(ctx, &cmd->as.floating, plan); break; @@ -906,6 +1016,15 @@ void policy_apply_command( case ZDWM_COMMAND_SWITCH_WORKSPACE: switch_workspace(state, cmd->as.switch_workspace.workspace, plan); break; + case ZDWM_COMMAND_SET_CURRENT_OUTPUT: + set_current_output(ctx, &cmd->as.current_output); + break; + case ZDWM_COMMAND_SET_LAYOUT: + set_layout(ctx, &cmd->as.layout, plan); + break; + case ZDWM_COMMAND_SET_BINDING_MODE: + set_binding_mode(ctx, cmd->as.binding_mode.mode); + break; } } }