From a7225836e4ac02b180020ad754d134b26eb1f53a Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Sun, 19 Apr 2026 23:38:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(core/policy):=20=E5=AE=9E=E7=8E=B0=20polic?= =?UTF-8?q?y=5Fapply=5Fcommand=20=E5=91=BD=E4=BB=A4=E5=88=86=E5=8F=91?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/command.h | 1 - src/core/plan.h | 3 +- src/core/policy.c | 82 +++++++++++++++++++++++++++++++++++++++++----- src/core/policy.h | 2 +- src/core/state.c | 46 ++++++++++++++++++++++++-- src/core/state.h | 33 ++++++++++++++++++- 6 files changed, 151 insertions(+), 16 deletions(-) diff --git a/src/core/command.h b/src/core/command.h index a9c25b2..64ddf3a 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -11,7 +11,6 @@ typedef enum command_type_t { typedef struct manage_window_command_t { workspace_id_t workspace; bool floating; - bool switch_to_workspace; window_info_t info; } manage_window_command_t; diff --git a/src/core/plan.h b/src/core/plan.h index 929b02d..291377f 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -9,7 +9,8 @@ typedef uint32_t dirty_mask_t; typedef enum dirty_flags_t : dirty_mask_t { ZDWM_DIRTY_NONE = 0, - ZDWM_DIRTY_LAYOUT = 1u << 0, + ZDWM_DIRTY_LAYOUT = 1u << 0, /* 需要重新计算布局 */ + ZDWM_DIRTY_OUTPUT = 1u << 1, /* 当前 output 有变更 */ } dirty_flags_t; typedef enum effect_type_t { diff --git a/src/core/policy.c b/src/core/policy.c index d07af66..39a0e66 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -1,5 +1,6 @@ #include "core/policy.h" +#include #include #include "base/macros.h" @@ -7,6 +8,7 @@ #include "core/command_buffer.h" #include "core/event.h" #include "core/layer.h" +#include "core/plan.h" #include "core/rules.h" #include "core/state.h" #include "core/types.h" @@ -98,24 +100,86 @@ bool policy_route_event( const event_t *event, command_buffer_t *out ) { + auto state = ctx->state; switch (event->type) { - case ZDWM_EVENT_WINDOW_MAP_REQUEST: - return route_map_request( - ctx->state, - ctx->rules, - &event->as.window_map_request, - out - ); + case ZDWM_EVENT_WINDOW_MAP_REQUEST: { + auto rules = ctx->rules; + return route_map_request(state, rules, &event->as.window_map_request, out); + } default: return false; } } +static bool manage_window( + const policy_context_t *ctx, + const manage_window_command_t *command, + plan_t *plan +) { + auto state = ctx->state; + auto window = state_window_add(state, &command->info); + auto window_id = window->id; + state_window_set_workspace(state, window_id, command->workspace); + state_window_set_floating(state, window_id, command->floating); + + if (!state_workspace_show(state, command->workspace)) return false; + + effect_t map_effect = { + .type = ZDWM_EFFECT_MAP_WINDOW, + .as.map.window = window_id, + }; + plan_push_effect(plan, &map_effect); + + if (window_need_layout(window)) { + plan->dirty_flags |= ZDWM_DIRTY_LAYOUT; + } + + return true; +} + +static bool switch_workspace( + const state_t *state, + const switch_workspace_command_t *command, + plan_t *plan +) { + auto output_id = command->output; + auto workspace_id = command->workspace; + + if (state_output_set_current_workspace(state, output_id, workspace_id)) { + plan->dirty_flags |= ZDWM_DIRTY_LAYOUT; + } + + if (state_set_current_output(state, output_id)) { + plan->dirty_flags |= ZDWM_DIRTY_OUTPUT; + } + + /* TODO: 后续考虑加上 ewmh 相关副作用 */ + + return false; +} + bool policy_apply_command( const policy_context_t *ctx, const command_buffer_t *command_buffer, plan_t *plan ) { - /* TODO: */ - return true; + bool has_effect = false; + auto state = ctx->state; + for (size_t i = 0; i < command_buffer->count; ++i) { + auto cmd = &command_buffer->items[i]; + switch (cmd->type) { + case ZDWM_COMMAND_MANAGE_WINDOW: + if (manage_window(ctx, &cmd->as.manage_window, plan)) { + has_effect = true; + } + break; + case ZDWM_COMMAND_SWITCH_WORKSPACE: + if (switch_workspace(state, &cmd->as.switch_workspace, plan)) { + has_effect = true; + } + break; + default: + } + } + return has_effect; } diff --git a/src/core/policy.h b/src/core/policy.h index 2bf4507..a4fae65 100644 --- a/src/core/policy.h +++ b/src/core/policy.h @@ -7,7 +7,7 @@ #include "core/state.h" typedef struct policy_context_t { - const state_t *state; + state_t *state; const rules_t *rules; } policy_context_t; diff --git a/src/core/state.c b/src/core/state.c index 7806a07..e10d9a9 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -237,6 +237,12 @@ bool state_workspace_valid(const state_t *state, workspace_id_t id) { #endif } +bool state_workspace_show(const state_t *state, workspace_id_t workspace_id) { + auto workspace = state_workspace_get(state, workspace_id); + auto output = state_output_get(state, workspace->output_id); + return output->current_workspace_id == workspace_id; +} + const output_t *state_output_get(const state_t *state, output_id_t id) { if (id < state->output_count) return &state->outputs[id]; return nullptr; @@ -256,17 +262,20 @@ void state_output_set_workarea( if (output) output->workarea = workarea; } -void state_output_set_current_workspace( +bool state_output_set_current_workspace( state_t *state, output_id_t output_id, workspace_id_t workspace_id ) { output_t *output = (output_t *)state_output_get(state, output_id); - if (!output) return; + if (!output) return false; const workspace_t *workspace = state_workspace_get(state, workspace_id); - if (!workspace || workspace->output_id != output_id) return; + if (!workspace || workspace->output_id != output_id) return false; + + if (output->current_workspace_id == workspace_id) return false; output->current_workspace_id = workspace_id; + return true; } size_t state_output_count(const state_t *state) { return state->output_count; } @@ -294,6 +303,21 @@ void state_cycle_current_output(state_t *state, int delta) { state->current_output_index = (size_t)next; } +bool state_set_current_output(state_t *state, output_id_t output_id) { + for (size_t i = 0; i < state->output_count; ++i) { + auto output = &state->outputs[i]; + if (output->id != output_id) continue; + + if (i == state->current_output_index) return false; + + state->current_output_index = i; + return true; + } + + warn("state_set_current_output: invalid output_id %u", output_id); + return false; +} + static inline void window_set_geometry_mode( window_t *window, window_geometry_mode_t geometry_mode @@ -634,3 +658,19 @@ bool state_stack_lower(state_t *state, window_id_t window_id) { return layer_stack_lower(layer, window_id); } + +bool window_need_layout(const window_t *window) { + if (window->sticky || window->floating) { + return false; + } + + switch (window->geometry_mode) { + case ZDWM_GEOMETRY_FULLSCREEN: + case ZDWM_GEOMETRY_MAXIMIZED: + case ZDWM_GEOMETRY_MINIMIZED: + return false; + default: + } + + return true; +} diff --git a/src/core/state.h b/src/core/state.h index 355fe92..82de838 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -126,6 +126,14 @@ void state_workspace_set_focused_window( size_t state_workspace_count(const state_t *state); bool state_workspace_valid(const state_t *state, workspace_id_t id); +/** + * @brief 当前 workspace 是否显示 + * + * @return 若 workspace_id 代表的 workspace 是其所属的 output 当前显示的 + * workspace 则返回 true ,否则返回 false + */ +bool state_workspace_show(const state_t *state, workspace_id_t workspace_id); + /* * state 持有的 output 集合接口 * @@ -139,7 +147,16 @@ void state_output_set_workarea( output_id_t output_id, rect_t workarea ); -void state_output_set_current_workspace( +/** + * @brief 设置 output 的当前 workspace + * + * @param state 状态实例指针 + * @param output_id 需要切换的当前 workspace 的 output 的 id + * @param workspace_id 目标 workspace 的 id + * + * @return 若 workspace 需要切换返回 true ,否则返回 false + */ +bool state_output_set_current_workspace( state_t *state, output_id_t output_id, workspace_id_t workspace_id @@ -147,6 +164,15 @@ void state_output_set_current_workspace( size_t state_output_count(const state_t *state); bool state_output_valid(const state_t *state, output_id_t id); void state_cycle_current_output(state_t *state, int delta); +/** + * @brief 设置当前 output + * + * @param state 状态实例指针 + * @param output_id 目标 output 的 id + * + * @return 有变更返回 true ,无变更返回 false + */ +bool state_set_current_output(state_t *state, output_id_t output_id); /* * state 持有的 window 集合接口 @@ -262,3 +288,8 @@ bool state_window_set_instance( bool state_stack_raise(state_t *state, window_id_t window_id); bool state_stack_lower(state_t *state, window_id_t window_id); + +/** + * @brief 窗口是否需要参与布局计算 + */ +bool window_need_layout(const window_t *window);