#include "core/policy.h" #include #include #include #include "base/macros.h" #include "base/window_list.h" #include "core/binding.h" #include "core/command.h" #include "core/command_buffer.h" #include "core/event.h" #include "core/layout.h" #include "core/plan.h" #include "core/rules.h" #include "core/state.h" #include "core/types.h" #include "core/window.h" #include "core/wm_desc.h" static void route_key_press(const policy_context_t *ctx, const key_press_event_t *e) { auto binding_table = ctx->bind_table; size_t count = 0; auto bindings = binding_table_get_current_bindings(binding_table, &count); if (!bindings) return; for (size_t i = 0; i < count; ++i) { auto binding = &bindings[i]; if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) { binding->fn(ctx->runtime, &ctx->action_api, &binding->arg); } } } static void route_pointer_enter(state_t *state, window_id_t window, command_buffer_t *out) { command_t focus_command = { .type = ZDWM_COMMAND_FOCUS_WINDOW, .as.focus.window = window, }; command_buffer_push(out, &focus_command); } static workspace_id_t derive_window_workspace(const state_t *state) { return state->outputs[state->current_output_index].current_workspace_id; } static void route_map_request( const state_t *state, const rules_t *rules, const window_map_request_event_t *e, command_buffer_t *out ) { if (e->override_redirect) return; if (state_window_get(state, e->window)) return; window_layer_type_t layer_type = window_classify_layer(&e->props); if (e->transient_for != ZDWM_WINDOW_ID_INVALID) { const window_t *window = state_window_get(state, e->transient_for); if (window) layer_type = MAX(window->layer, layer_type); } command_t manage_window_cmd = { .type = ZDWM_COMMAND_MANAGE_WINDOW, .as.manage_window = { .workspace = derive_window_workspace(state), .info = { .id = e->window, .transient_for = e->transient_for, .frame_rect = e->rect, .title = e->metadata.title, .app_id = e->metadata.app_id, .role = e->metadata.role, .class_name = e->metadata.class_name, .instance_name = e->metadata.instance_name, .layer_type = layer_type, .fullscreen = e->fullscreen, .maximized = e->maximized, .minimized = e->minimized, .urgent = e->urgent, .fixed_size = e->fixed_size, .skip_taskbar = e->skip_taskbar, }, }, }; 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 = &manage_window_cmd.as.manage_window; if (!workspace_id_invalid(action.workspace)) { data->workspace = action.workspace; } if (action.floating) data->floating = true; if (action.fullscreen) data->info.fullscreen = true; if (action.maximize) data->info.maximized = true; } command_buffer_push(out, &manage_window_cmd); if (!have_rule_match || !action.switch_to_workspace) return; workspace_id_t workspace_id = manage_window_cmd.as.manage_window.workspace; const workspace_t *workspace = state_workspace_get(state, workspace_id); if (!workspace) return; command_t switch_workspace_cmd = { .type = ZDWM_COMMAND_SWITCH_WORKSPACE, .as.switch_workspace.workspace = workspace_id, }; command_buffer_push(out, &switch_workspace_cmd); } 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; switch (e->reason) { case ZDWM_WINDOW_REMOVE_WITHDRAWN: command_t withdrawn_window_cmd = { .type = ZDWM_COMMAND_WITHDRAW_WINDOW, .as.withdraw.window = e->window, }; command_buffer_push(out, &withdrawn_window_cmd); break; case ZDWM_WINDOW_REMOVE_DESTROY: command_t unmanage_window_cmd = { .type = ZDWM_COMMAND_UNMANAGE_WINDOW, .as.unmanage.window = e->window, }; command_buffer_push(out, &unmanage_window_cmd); break; } } static void route_window_metadata_changed( state_t *state, const window_metadata_change_event_t *e ) { auto window = state_window_get(state, e->window); if (!window) return; auto window_id = e->window; auto metadata = &e->metadata; if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_TITLE) { state_window_set_title(state, window_id, metadata->title); } if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_APP_ID) { state_window_set_app_id(state, window_id, metadata->app_id); } if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_ROLE) { state_window_set_role(state, window_id, metadata->role); } if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_CLASS) { state_window_set_class(state, window_id, metadata->class_name); } if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_INSTANCE) { state_window_set_instance(state, window_id, metadata->instance_name); } } 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); 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_PAGER: { command_t switch_workspace_cmd = { .type = ZDWM_COMMAND_SWITCH_WORKSPACE, .as.switch_workspace.workspace = window->workspace_id, }; command_buffer_push(out, &switch_workspace_cmd); command_t focus_cmd = { .type = ZDWM_COMMAND_FOCUS_WINDOW, .as.focus.window = window->id, }; command_buffer_push(out, &focus_cmd); } break; } } static void route_window_state_request( state_t *state, const window_state_request_event_t *e, command_buffer_t *out ) { auto window = state_window_get(state, e->window); if (!window) return; command_t change_window_state_cmd = { .type = ZDWM_COMMAND_CHANGE_WINDOW_STATE, .as.state_change = { .type = e->type, .window = e->window, .action = e->action, } }; command_buffer_push(out, &change_window_state_cmd); } static void route_configure_request( state_t *state, const configure_data_t *data, const layout_registry_t *layouts, command_buffer_t *out ) { auto window = state_window_get(state, data->window); if (!window) { command_t configure_cmd = { .type = ZDWM_COMMAND_CONFIGURE_WINDOW, .as.configure = *data }; command_buffer_push(out, &configure_cmd); return; } if (!state_workspace_show(state, window->workspace_id)) return; if (window_need_layout(window)) return; auto workspace = state_workspace_get(state, window->workspace_id); if (layout_get(layouts, workspace->layout_id)) return; command_t configure_rect_cmd = { .type = ZDWM_COMMAND_CONFIGURE_WINDOW, .as.configure = *data, }; configure_rect_cmd.as.configure.changed_fields &= ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT; command_buffer_push(out, &configure_rect_cmd); } void policy_route_event( const policy_context_t *ctx, const event_t *event, command_buffer_t *out ) { auto state = ctx->state; switch (event->type) { case ZDWM_EVENT_KEY_PRESS: route_key_press(ctx, &event->as.key_press); break; case ZDWM_EVENT_POINTER_ENTER: route_pointer_enter(state, event->as.pointer_enter.window, out); break; 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; case ZDWM_EVENT_WINDOW_METADATA_CHANGED: route_window_metadata_changed(state, &event->as.window_metadata_change); break; case ZDWM_EVENT_WINDOW_ACTIVATE_REQUEST: { auto data = &event->as.window_activate_request; route_window_activate_request(state, data, out); } break; case ZDWM_EVENT_WINDOW_STATE_REQUEST: route_window_state_request(state, &event->as.window_state_request, out); break; case ZDWM_EVENT_CONFIGURE_REQUEST: { auto data = &event->as.configure_request; route_configure_request(state, data, ctx->layouts, out); } break; default: } } static void adjust_layout_windows_border_width( state_t *state, uint32_t border_width, workspace_id_t workspace_id ) { static window_list_t list = {0}; state_get_windows_need_layout_in_workspace(state, workspace_id, &list); if (list.count <= 1) border_width = 0; for (size_t i = 0; i < list.count; ++i) { auto window_id = list.windows[i]; state_window_set_border_width(state, window_id, border_width); } window_list_reset(&list); } static void set_foucs_window( const policy_context_t *ctx, workspace_id_t workspace_id, window_id_t window_id, plan_t *plan ) { auto state = ctx->state; auto border = ctx->border; auto workspace = state_workspace_get(state, workspace_id); if (!workspace) return; auto old_focused_window_id = workspace->focused_window_id; if (window_id == old_focused_window_id) return; state_workspace_set_focused_window(state, workspace_id, window_id); plan_push_focus_effect(plan, window_id); if (state_window_get(state, window_id)) { auto color = &border->focused_color; plan_push_change_border_color_effect(plan, window_id, color); } if (state_window_get(state, old_focused_window_id)) { auto color = &border->normal_color; plan_push_change_border_color_effect(plan, old_focused_window_id, color); } } static void push_window_list_effect(const state_t *state, plan_t *plan) { window_list_t list = {0}; for (size_t i = 0; i < state_window_count(state); ++i) { auto window = state_window_at(state, i); window_list_push(&list, window->id); } effect_t effect = { .type = ZDWM_EFFECT_CHANGE_WINDOW_LIST, .as.change_window_list = { .windows = list.windows, .count = list.count, }, }; plan_push_effect(plan, &effect); } static void 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; 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); push_window_list_effect(state, plan); auto need_layout = window_need_layout(window); if (need_layout) { adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); } else { state_window_set_border_width(state, window_id, ctx->border->width); } if (!state_workspace_show(state, command->workspace)) return; plan_push_map_effect(plan, window_id); plan_push_focus_effect(plan, window_id); if (window_need_layout(window)) { plan->need_relayout = true; return; } effect_t configure_effect = { .type = ZDWM_EFFECT_CONFIGURE_WINDOW, .as.configure = { .window = window_id, .x = window->frame_rect.x, .y = window->frame_rect.y, .width = window->frame_rect.width - 2 * (int32_t)window->border_width, .height = window->frame_rect.height - 2 * (int32_t)window->border_width, .border_width = window->border_width, .changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT | ZDWM_CONFIGURE_FIELD_BORDER_WIDTH, } }; plan_push_effect(plan, &configure_effect); } static void add_switch_workspace_effects( const state_t *state, workspace_id_t old_workspace, workspace_id_t new_workspace, plan_t *plan ) { for (size_t i = 0; i < state->window_count; ++i) { window_t *window = &state->windows[i]; if (window->sticky) continue; if (window->workspace_id == old_workspace) { plan_push_unmap_effect(plan, window->id); } else if (window->workspace_id == new_workspace) { plan_push_map_effect(plan, window->id); } } const workspace_t *workspace = state_workspace_get(state, new_workspace); if (!workspace) return; plan_push_focus_effect(plan, workspace->focused_window_id); } static void unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) { auto state = ctx->state; 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 need_layout = window_need_layout(win); auto old_focused_window = workspace->focused_window_id; state_window_remove(state, window); push_window_list_effect(state, plan); if (need_layout) { adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); plan->need_relayout = true; } if (output->current_workspace_id != workspace_id) return; if (old_focused_window != workspace->focused_window_id) { plan_push_focus_effect(plan, workspace->focused_window_id); } } static void focus_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) { auto state = ctx->state; 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; set_foucs_window(ctx, workspace_id, window, plan); if (old_focused_window == workspace->focused_window_id) return; plan_push_focus_effect(plan, workspace->focused_window_id); } static void kill_window(state_t *state, window_id_t window, plan_t *plan) { auto win = state_window_get(state, window); if (!win) return; plan_push_kill_effect(plan, window); } static void raise_window(state_t *state, window_id_t window, plan_t *plan) { if (!state_stack_raise(state, window)) return; window_list_t list = {0}; for (size_t i = 0; i < countof(state->stacks); ++i) { for (size_t j = 0; j < state->stacks[i].count; ++j) { auto window_id = state->stacks[i].order[j]; window_list_push(&list, window_id); } } effect_t restack_windows_effect = { .type = ZDWM_EFFECT_RESTACK_WINDOWS, .as.restack_windows = { .windows = list.windows, .count = list.count, }, }; plan_push_effect(plan, &restack_windows_effect); } static void withdraw_window(state_t *state, window_id_t window, plan_t *plan) { auto win = state_window_get(state, window); if (!win) return; plan_push_withdraw_effect(plan, window); } static void configure_window(state_t *state, const configure_data_t *data, plan_t *plan) { auto window = state_window_get(state, data->window); if (!window) { effect_t configure_effect = { .type = ZDWM_EFFECT_CONFIGURE_WINDOW, .as.configure = *data, }; plan_push_effect(plan, &configure_effect); return; } auto rect = window->frame_rect; #define PICK_FIELD(FIELD_MASK, RECT_FIELD, DATA_FIELD) \ if (data->changed_fields & (FIELD_MASK)) rect.RECT_FIELD = data->DATA_FIELD PICK_FIELD(ZDWM_CONFIGURE_FIELD_X, x, x); PICK_FIELD(ZDWM_CONFIGURE_FIELD_Y, y, y); PICK_FIELD(ZDWM_CONFIGURE_FIELD_WIDTH, width, width); PICK_FIELD(ZDWM_CONFIGURE_FIELD_HEIGHT, height, height); #undef PICK_FIELD auto need_move = window_need_move(window, rect.x, rect.y); auto need_resize = window_need_resize(window, rect.width, rect.height); if (!need_move && !need_resize) return; state_window_set_frame_rect(state, window->id, rect); effect_t configure_effect = { .type = ZDWM_EFFECT_CONFIGURE_WINDOW, .as.configure = { .window = window->id, .x = rect.x, .y = rect.y, .width = rect.width, .height = rect.height, } }; if (need_move) { configure_effect.as.configure.changed_fields |= ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y; } if (need_resize) { configure_effect.as.configure.changed_fields |= ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT; } plan_push_effect(plan, &configure_effect); } static void fullscreen_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ); static void maximize_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ); static void add_window_floating_effect( const policy_context_t *ctx, const window_t *window, plan_t *plan ) { effect_t configure_effect = { .type = ZDWM_EFFECT_CONFIGURE_WINDOW, .as.configure = { .window = window->id, .border_width = ctx->border->width, .x = window->frame_rect.x, .y = window->frame_rect.y, .width = window->frame_rect.width - 2 * (int32_t)ctx->border->width, .height = window->frame_rect.height - 2 * (int32_t)ctx->border->width, .changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT | ZDWM_CONFIGURE_FIELD_BORDER_WIDTH } }; plan_push_effect(plan, &configure_effect); } static void floating_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ) { auto window = state_window_get(ctx->state, window_id); if (!window) return; bool old_floating = window->floating; state_window_set_floating(ctx->state, window_id, value); if (old_floating == window->floating) return; if (window->floating) add_window_floating_effect(ctx, window, plan); plan->need_relayout = true; } static void fullscreen_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ) { auto state = ctx->state; auto window = state_window_get(state, window_id); if (!window) return; if (window->fullscreen == value) return; plan_push_fullscreen_effect(plan, window_id, value); state_window_set_fullscreen(state, window_id, value); if (value) { state_window_set_border_width(state, window_id, 0); if (window->floating) { state_window_set_float_rect(state, window_id, window->frame_rect); add_window_floating_effect(ctx, window, plan); } } else { state_window_set_border_width(state, window_id, ctx->border->width); if (window->floating) { state_window_set_frame_rect(state, window_id, window->float_rect); add_window_floating_effect(ctx, window, plan); } } auto workspace_id = window->workspace_id; adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); plan->need_relayout = true; } static void maximize_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ) { auto state = ctx->state; auto window = state_window_get(state, window_id); if (!window) return; if (window->maximized == value) return; plan_push_maximize_effect(plan, window_id, value); state_window_set_maximized(state, window_id, value); if (value) { state_window_set_border_width(state, window_id, 0); if (window->floating) { state_window_set_float_rect(state, window_id, window->frame_rect); add_window_floating_effect(ctx, window, plan); } } else { state_window_set_border_width(state, window_id, ctx->border->width); if (window->floating) { state_window_set_frame_rect(state, window_id, window->float_rect); add_window_floating_effect(ctx, window, plan); } } auto workspace_id = window->workspace_id; adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); plan->need_relayout = true; } static void minimize_window( const policy_context_t *ctx, window_id_t window_id, bool value, plan_t *plan ) { auto state = ctx->state; auto window = state_window_get(state, window_id); if (!window) return; if (window->minimized == value) return; plan_push_minimize_effect(plan, window_id, value); state_window_set_minimized(state, window_id, value); if (value) { plan_push_unmap_effect(plan, window_id); auto workspace = state_workspace_get(state, window->workspace_id); auto old_focused_window_id = workspace->focused_window_id; auto new_focused_window_id = workspace->focused_window_id; if (old_focused_window_id != new_focused_window_id) { auto color = &ctx->border->normal_color; plan_push_change_border_color_effect(plan, old_focused_window_id, color); color = &ctx->border->focused_color; plan_push_change_border_color_effect(plan, new_focused_window_id, color); } } else { plan_push_map_effect(plan, window_id); set_foucs_window(ctx, window->workspace_id, window_id, plan); } auto workspace_id = window->workspace_id; adjust_layout_windows_border_width(state, ctx->border->width, workspace_id); plan->need_relayout = true; } static void change_window_state( const policy_context_t *ctx, const window_state_change_command_t *command, plan_t *plan ) { auto state = ctx->state; auto window = state_window_get(state, command->window); if (!window) return; bool value = false; switch (command->action) { case ZDWM_WINDOW_STATE_ACTION_ADD: value = true; break; case ZDWM_WINDOW_STATE_ACTION_REMOVE: value = false; break; case ZDWM_WINDOW_STATE_ACTION_TOGGLE: switch (command->type) { case ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN: value = !window->fullscreen; break; case ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED: value = !window->maximized; break; case ZDWM_WINDOW_STATE_REQUEST_MINIMIZED: value = !window->minimized; break; 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; } } switch (command->type) { case ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN: fullscreen_window(ctx, window->id, value, plan); break; case ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED: maximize_window(ctx, window->id, value, plan); break; case ZDWM_WINDOW_STATE_REQUEST_MINIMIZED: minimize_window(ctx, window->id, value, plan); break; /* TODO: 下面三个可能需要添加处理,尤其是 fixed_size 和 floating 相关 */ 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; } } static void command_window_set_floating( const policy_context_t *ctx, const window_bool_state_t *data, plan_t *plan ) { floating_window(ctx, data->window, data->state, plan); } static void command_window_set_sticky( const policy_context_t *ctx, const window_bool_state_t *data, plan_t *plan ) { auto window = state_window_get(ctx->state, data->window); if (!window || window->sticky == data->state) return; if (!window->floating) { } state_window_set_sticky(ctx->state, data->window, data->state); if (data->state) return; } static void command_window_set_minimized( const policy_context_t *ctx, const window_bool_state_t *data, plan_t *plan ) { minimize_window(ctx, data->window, data->state, plan); } static void command_window_set_maximized( const policy_context_t *ctx, const window_bool_state_t *data, plan_t *plan ) { 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 switch_workspace(state_t *state, workspace_id_t workspace_id, plan_t *plan) { auto workspace = state_workspace_get(state, workspace_id); if (!workspace) return; auto output_id = workspace->output_id; workspace_id_t old_workspace = ZDWM_WORKSPACE_ID_INVALID; if (state_output_set_current_workspace( state, output_id, workspace_id, &old_workspace )) { plan->need_relayout = true; add_switch_workspace_effects(state, old_workspace, workspace_id, plan); } state_set_current_output(state, output_id); } void policy_apply_command( const policy_context_t *ctx, const command_buffer_t *command_buffer, plan_t *plan ) { 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: manage_window(ctx, &cmd->as.manage_window, plan); break; case ZDWM_COMMAND_UNMANAGE_WINDOW: unmanage_window(ctx, cmd->as.unmanage.window, plan); break; case ZDWM_COMMAND_FOCUS_WINDOW: focus_window(ctx, cmd->as.focus.window, plan); break; case ZDWM_COMMAND_KILL_WINDOW: kill_window(state, cmd->as.kill.window, plan); break; case ZDWM_COMMAND_RAISE_WINDOW: raise_window(state, cmd->as.raise.window, plan); break; case ZDWM_COMMAND_WITHDRAW_WINDOW: withdraw_window(state, cmd->as.withdraw.window, plan); break; case ZDWM_COMMAND_CONFIGURE_WINDOW: configure_window(state, &cmd->as.configure, plan); break; case ZDWM_COMMAND_CHANGE_WINDOW_STATE: change_window_state(ctx, &cmd->as.state_change, plan); break; case ZDWM_COMMAND_WINDOW_SET_FLOATING: command_window_set_floating(ctx, &cmd->as.floating, plan); break; case ZDWM_COMMAND_WINDOW_SET_STICKY: command_window_set_sticky(ctx, &cmd->as.sticky, plan); break; case ZDWM_COMMAND_WINDOW_SET_MINIMIZED: command_window_set_minimized(ctx, &cmd->as.minimized, plan); break; 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); break; case ZDWM_COMMAND_SWITCH_WORKSPACE: switch_workspace(state, cmd->as.switch_workspace.workspace, plan); break; } } }