From a749fc3c6c4c377c85cfbb4069c2c1592d9fa326 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Thu, 23 Apr 2026 04:49:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(core/policy):=20=E6=B7=BB=E5=8A=A0=20unman?= =?UTF-8?q?age/focus/kill=20=E5=91=BD=E4=BB=A4=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/command.h | 12 +++++- src/core/policy.c | 91 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/src/core/command.h b/src/core/command.h index 64ddf3a..82927a0 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -5,7 +5,10 @@ typedef enum command_type_t { ZDWM_COMMAND_MANAGE_WINDOW, - ZDWM_COMMAND_SWITCH_WORKSPACE + ZDWM_COMMAND_UNMANAGE_WINDOW, + ZDWM_COMMAND_FOCUS_WINDOW, + ZDWM_COMMAND_KILL_WINDOW, + ZDWM_COMMAND_SWITCH_WORKSPACE, } command_type_t; typedef struct manage_window_command_t { @@ -19,6 +22,10 @@ typedef struct switch_workspace_command_t { workspace_id_t workspace; } switch_workspace_command_t; +typedef struct only_window_command_t { + window_id_t window; +} only_window_command_t; + /** * @brief 非 owning 的命令值对象 * @details @@ -32,6 +39,9 @@ typedef struct command_t { command_type_t type; union { manage_window_command_t manage_window; + only_window_command_t unmanage; + only_window_command_t focus; + only_window_command_t kill; switch_workspace_command_t switch_workspace; } as; } command_t; diff --git a/src/core/policy.c b/src/core/policy.c index afee5cc..87a46e0 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -32,7 +32,7 @@ static void route_map_request( if (window) layer_type = MAX(window->layer, layer_type); } - command_t cmd = { + command_t manage_window_cmd = { .type = ZDWM_COMMAND_MANAGE_WINDOW, .as.manage_window = { .workspace = derive_window_workspace(state), @@ -59,7 +59,7 @@ static void route_map_request( rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID}; bool have_rule_match = rules_resolve(rules, &e->metadata, &action); if (have_rule_match) { - manage_window_command_t *data = &cmd.as.manage_window; + manage_window_command_t *data = &manage_window_cmd.as.manage_window; if (action.workspace != ZDWM_WORKSPACE_ID_INVALID) { data->workspace = action.workspace; } @@ -74,9 +74,9 @@ static void route_map_request( } } - command_buffer_push(out, &cmd); + command_buffer_push(out, &manage_window_cmd); if (have_rule_match && action.switch_to_workspace) { - workspace_id_t workspace_id = cmd.as.manage_window.workspace; + workspace_id_t workspace_id = manage_window_cmd.as.manage_window.workspace; const workspace_t *workspace = state_workspace_get(state, workspace_id); if (workspace) { @@ -93,6 +93,21 @@ static void route_map_request( } } +static void route_window_remove( + state_t *state, + const window_remove_event_t *e, + command_buffer_t *out +) { + const window_t *window = state_window_get(state, e->window); + if (!window) return; + + command_t unmanage_window_cmd = { + .type = ZDWM_COMMAND_UNMANAGE_WINDOW, + .as.unmanage.window = e->window, + }; + command_buffer_push(out, &unmanage_window_cmd); +} + void policy_route_event( const policy_context_t *ctx, const event_t *event, @@ -100,11 +115,12 @@ void policy_route_event( ) { auto state = ctx->state; switch (event->type) { - case ZDWM_EVENT_WINDOW_MAP_REQUEST: { - auto rules = ctx->rules; - route_map_request(state, rules, &event->as.window_map_request, out); + case ZDWM_EVENT_WINDOW_MAP_REQUEST: + route_map_request(state, ctx->rules, &event->as.window_map_request, out); + break; + case ZDWM_EVENT_WINDOW_REMOVE: + route_window_remove(state, &event->as.window_remove, out); break; - } default: } } @@ -174,6 +190,56 @@ static void add_switch_workspace_effects( plan_push_effect(plan, &focus_effect); } +static void unmanage_window(state_t *state, window_id_t window, plan_t *plan) { + const window_t *win = state_window_get(state, window); + if (!win) return; + + auto workspace_id = win->workspace_id; + auto workspace = state_workspace_get(state, workspace_id); + auto output = state_output_get(state, workspace->output_id); + + auto old_focused_window = workspace->focused_window_id; + state_window_remove(state, window); + if (output->current_workspace_id != workspace_id) return; + + if (old_focused_window != workspace->focused_window_id) { + effect_t focus_effect = { + .type = ZDWM_EFFECT_FOCUS_WINDOW, + .as.focus.window = workspace->focused_window_id + }; + plan_push_effect(plan, &focus_effect); + } +} + +static void focus_window(state_t *state, window_id_t window, plan_t *plan) { + auto win = state_window_get(state, window); + if (!win) return; + + auto workspace_id = win->workspace_id; + auto workspace = state_workspace_get(state, workspace_id); + auto old_focused_window = workspace->focused_window_id; + + state_workspace_set_focused_window(state, workspace_id, window); + if (old_focused_window == workspace->focused_window_id) return; + + effect_t focus_effect = { + .type = ZDWM_EFFECT_FOCUS_WINDOW, + .as.focus.window = workspace->focused_window_id, + }; + plan_push_effect(plan, &focus_effect); +} + +static void kill_window(state_t *state, window_id_t window, plan_t *plan) { + auto win = state_window_get(state, window); + if (!win) return; + + effect_t kill_effect = { + .type = ZDWM_EFFECT_KILL_WINDOW, + .as.kill.window = window, + }; + plan_push_effect(plan, &kill_effect); +} + static void switch_workspace( state_t *state, const switch_workspace_command_t *command, @@ -208,6 +274,15 @@ void policy_apply_command( case ZDWM_COMMAND_MANAGE_WINDOW: manage_window(ctx, &cmd->as.manage_window, plan); break; + case ZDWM_COMMAND_UNMANAGE_WINDOW: + unmanage_window(state, cmd->as.unmanage.window, plan); + break; + case ZDWM_COMMAND_FOCUS_WINDOW: + focus_window(state, cmd->as.focus.window, plan); + break; + case ZDWM_COMMAND_KILL_WINDOW: + kill_window(state, cmd->as.kill.window, plan); + break; case ZDWM_COMMAND_SWITCH_WORKSPACE: switch_workspace(state, &cmd->as.switch_workspace, plan); break;