diff --git a/CMakeLists.txt b/CMakeLists.txt index 42ddb7b..8315e69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,13 +33,13 @@ add_executable(${APP_NAME} ${SOURCE_DIR}/base/color.c ${SOURCE_DIR}/base/log.c + ${SOURCE_DIR}/base/process.c ${SOURCE_DIR}/base/window_list.c ${SOURCE_DIR}/config/defaults.c ${SOURCE_DIR}/config/loader.c ${SOURCE_DIR}/config/runtime_config.c - ${SOURCE_DIR}/core/action.c ${SOURCE_DIR}/core/binding.c ${SOURCE_DIR}/core/command_buffer.c ${SOURCE_DIR}/core/event.c diff --git a/include/zdwm/action.h b/include/zdwm/action.h index 692a57f..916c384 100644 --- a/include/zdwm/action.h +++ b/include/zdwm/action.h @@ -52,6 +52,16 @@ typedef struct zdwm_action_data_index_only_t { uint32_t index; } zdwm_action_data_index_only_t; +typedef struct zdwm_action_data_window_send_to_workspace_t { + uint32_t index; + bool switch_workspace; +} zdwm_action_data_window_send_to_workspace_t; + +typedef struct zdwm_action_data_window_cycle_output_t { + int32_t delta; + bool keep_focus; +} zdwm_action_data_window_cycle_output_t; + typedef struct zdwm_action_t { zdwm_action_type_t type; union { @@ -63,8 +73,9 @@ typedef struct zdwm_action_t { zdwm_action_data_delta_only_t layout_cycle; zdwm_action_data_delta_only_t binding_mode_cycle; zdwm_action_data_delta_only_t window_focus_cycle; - zdwm_action_data_index_only_t window_send_to_workspace_same_output_by_index; - zdwm_action_data_delta_only_t window_cycle_output; + zdwm_action_data_window_send_to_workspace_t + window_send_to_workspace_same_output_by_index; + zdwm_action_data_window_cycle_output_t window_cycle_output; } as; } zdwm_action_t; diff --git a/src/base/process.c b/src/base/process.c new file mode 100644 index 0000000..43f9cdf --- /dev/null +++ b/src/base/process.c @@ -0,0 +1,23 @@ +#include "base/process.h" + +#include +#include +#include +#include + +#include "base/log.h" + +void spawn(const char *command) { + if (fork() == 0) { + setsid(); + + if (fork() == 0) { + execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, nullptr); + fatal("execl fail: %s", command); + } + + exit(0); + } + + wait(0); +} diff --git a/src/base/process.h b/src/base/process.h new file mode 100644 index 0000000..e1b1c21 --- /dev/null +++ b/src/base/process.h @@ -0,0 +1,3 @@ +#pragma once + +void spawn(const char *command); diff --git a/src/core/action.c b/src/core/action.c deleted file mode 100644 index 44658fc..0000000 --- a/src/core/action.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "core/action.h" - -#include -#include -#include -#include -#include -#include - -#include "base/log.h" -#include "base/macros.h" -#include "core/command.h" -#include "core/command_buffer.h" -#include "core/runtime.h" -#include "core/state.h" -#include "core/types.h" -#include "core/window.h" - -void spawn(const char *command) { - if (fork() == 0) { - setsid(); - - if (fork() == 0) { - execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, nullptr); - fatal("execl fail: %s", command); - } - - exit(0); - } - - wait(0); -} - -void quit(runtime_t *runtime, bool restart) { - runtime->will_restart = restart; - runtime->running = false; -} - -static const window_t * -get_next_window_by_class(state_t *state, const char *class_name) { - auto output = state_output_at(state, state->current_output_index); - auto workspace = state_workspace_get(state, output->current_workspace_id); - - size_t start_index = 0; - if (!window_id_invalid(workspace->focused_window_id)) { - for (size_t i = 0; i < state_window_count(state); ++i) { - if (state_window_at(state, i)->id == workspace->focused_window_id) { - start_index = i; - break; - } - } - } - - for (size_t i = start_index + 1; i < state_window_count(state); ++i) { - auto window = state_window_at(state, i); - if (strcmp(window->class_name, class_name) == 0) { - return window; - } - } - - for (size_t i = 0; i < MIN(start_index + 1, state_window_count(state)); ++i) { - auto window = state_window_at(state, i); - if (strcmp(window->class_name, class_name) == 0) { - return window; - } - } - return nullptr; -} - -void raise_or_run( - runtime_t *runtime, - const char *class_name, - const char *command -) { - auto window = get_next_window_by_class(&runtime->state, class_name); - if (!window) { - spawn(command); - return; - } - - command_t switch_workspace_cmd = { - .type = ZDWM_COMMAND_SWITCH_WORKSPACE, - .as.switch_workspace.workspace = window->workspace_id, - }; - command_buffer_push(&runtime->command_buffer, &switch_workspace_cmd); - - command_t focus_cmd = { - .type = ZDWM_COMMAND_FOCUS_WINDOW, - .as.focus.window = window->id, - }; - command_buffer_push(&runtime->command_buffer, &focus_cmd); -} - -static const window_t *get_current_focused_window(const state_t *state) { - auto output = state_output_at(state, state->current_output_index); - auto workspace = state_workspace_get(state, output->current_workspace_id); - return state_window_get(state, workspace->focused_window_id); -} - -void toggle_fullscreen(runtime_t *runtime) { - auto window = get_current_focused_window(&runtime->state); - if (!window) return; - - command_t window_set_fullscreen_cmd = { - .type = ZDWM_COMMAND_WINDOW_SET_FULLSCREEN, - .as.fullscreen = { - .window = window->id, - .state = !window->fullscreen, - } - }; - command_buffer_push(&runtime->command_buffer, &window_set_fullscreen_cmd); -} - -void toggle_maximize(runtime_t *runtime) { - auto window = get_current_focused_window(&runtime->state); - if (!window) return; - - command_t window_set_maximized_cmd = { - .type = ZDWM_COMMAND_WINDOW_SET_MAXIMIZED, - .as.maximized = { - .window = window->id, - .state = !window->maximized, - } - }; - command_buffer_push(&runtime->command_buffer, &window_set_maximized_cmd); -} - -void toggle_floating(runtime_t *runtime) { - auto window = get_current_focused_window(&runtime->state); - if (!window) return; - - command_t window_set_floating_cmd = { - .type = ZDWM_COMMAND_WINDOW_SET_FLOATING, - .as.floating = { - .window = window->id, - .state = !window->floating, - } - }; - command_buffer_push(&runtime->command_buffer, &window_set_floating_cmd); -} - -void toggle_sticky(runtime_t *runtime) { - auto window = get_current_focused_window(&runtime->state); - if (!window) return; - - command_t window_set_sticky_cmd = { - .type = ZDWM_COMMAND_WINDOW_SET_STICKY, - .as.sticky = { - .window = window->id, - .state = !window->sticky, - } - }; - command_buffer_push(&runtime->command_buffer, &window_set_sticky_cmd); -} - -void switch_workspace(runtime_t *runtime, workspace_id_t workspace_id) { - auto workspace = state_workspace_get(&runtime->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(&runtime->command_buffer, &switch_workspace_cmd); -} - -void switch_workspace_in_current_output( - runtime_t *runtime, - workspace_id_t workspace_id -) { - auto state = &runtime->state; - auto output = state_output_at(state, state->current_output_index); - auto workspace = state_workspace_get(state, workspace_id); - if (workspace->output_id != output->id) return; - - command_t switch_workspace_cmd = { - .type = ZDWM_COMMAND_SWITCH_WORKSPACE, - .as.switch_workspace.workspace = workspace_id - }; - command_buffer_push(&runtime->command_buffer, &switch_workspace_cmd); -} - -void switch_workspace_by_index_in_current_output( - runtime_t *runtime, - uint32_t index -) { - auto state = &runtime->state; - auto output = state_output_at(state, state->current_output_index); - uint32_t count = 0; - for (size_t i = 0; i < state_workspace_count(state); ++i) { - auto workspace = state_workspace_at(state, i); - if (workspace->output_id != output->id) continue; - - if (count == index) { - command_t switch_workspace_cmd = { - .type = ZDWM_COMMAND_SWITCH_WORKSPACE, - .as.switch_workspace.workspace = workspace->id, - }; - command_buffer_push(&runtime->command_buffer, &switch_workspace_cmd); - return; - } - count++; - } -} - -void cycle_layout(runtime_t *runtime, int32_t delta) { - auto state = &runtime->state; - auto output = state_output_at(state, state->current_output_index); - auto workspace = state_workspace_get(state, output->current_workspace_id); - if (!state_workspace_cycle_layout(state, workspace->id, delta)) return; - - runtime->plan.need_relayout = true; -} - -void cycle_current_output(runtime_t *runtime, int32_t delta) { - auto state = &runtime->state; - state_cycle_current_output(state, delta); -} - -void focus_window(runtime_t *runtime, int32_t delta) { - auto state = &runtime->state; - auto output = state_output_at(state, state->current_output_index); - auto workspace = state_workspace_get(state, output->current_workspace_id); - - size_t count = state_window_count(state); - if (!count) return; - - size_t indices[count]; - size_t num = 0; - for (size_t i = 0; i < count; ++i) { - auto window = state_window_at(state, i); - if (window->workspace_id == workspace->id) { - indices[num++] = i; - } - } - if (!num) return; - - size_t current = 0; - if (!window_id_invalid(workspace->focused_window_id)) { - for (size_t i = 0; i < num; ++i) { - auto window = state_window_at(state, indices[i]); - if (window->id == workspace->focused_window_id) { - current = i; - break; - } - } - } - - int64_t next = ((int64_t)current + (int64_t)delta) % (int64_t)num; - if (next < 0) next += (int64_t)num; - - auto target = state_window_at(state, indices[next]); - - command_t focus_cmd = { - .type = ZDWM_COMMAND_FOCUS_WINDOW, - .as.focus.window = target->id, - }; - command_buffer_push(&runtime->command_buffer, &focus_cmd); - - command_t raise_cmd = { - .type = ZDWM_COMMAND_RAISE_WINDOW, - .as.raise.window = target->id, - }; - command_buffer_push(&runtime->command_buffer, &raise_cmd); -} diff --git a/src/core/action.h b/src/core/action.h deleted file mode 100644 index ffda191..0000000 --- a/src/core/action.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -typedef struct runtime_t runtime_t; - -void spawn(const char *command); -void quit(runtime_t *runtime, bool restart); -void raise_or_run( - runtime_t *runtime, - const char *class_name, - const char *command -); - -void toggle_fullscreen(runtime_t *runtime); -void toggle_maximize(runtime_t *runtime); -void toggle_floating(runtime_t *runtime); -void toggle_sticky(runtime_t *runtime); -void switch_workspace(runtime_t *runtime, zdwm_workspace_id_t workspace_id); -void switch_workspace_in_current_output( - runtime_t *runtime, - zdwm_workspace_id_t workspace_id -); -void switch_workspace_by_index_in_current_output( - runtime_t *runtime, - uint32_t index -); -void cycle_layout(runtime_t *runtime, int32_t delta); -void cycle_current_output(runtime_t *runtime, int32_t delta); -void focus_window(runtime_t *runtime, int32_t delta); diff --git a/src/core/binding.c b/src/core/binding.c index 6e6a1be..fd96ad7 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -231,8 +231,11 @@ bool binding_table_set_current_mode( return true; } -bool binding_table_cycle_mode(binding_table_t *table, int delta) { - if (!table || !table->modes || table->count < 1) return false; +zdwm_binding_mode_id_t +binding_table_cycle_mode(const binding_table_t *table, int32_t delta) { + if (!table || !table->modes || table->count <= 1) { + return ZDWM_BINDING_MODE_ID_INVALID; + } bool matched = false; size_t index = (size_t)table->current_mode; @@ -248,17 +251,13 @@ bool binding_table_cycle_mode(binding_table_t *table, int delta) { } } - if (!matched) return false; - - /* 只有一个模式没必要切换 */ - if (table->count == 1) return true; + if (!matched) return ZDWM_BINDING_MODE_ID_INVALID; int64_t count = (int64_t)table->count; int64_t next_index = ((int64_t)index + (int64_t)delta) % count; if (next_index < 0) next_index += count; - table->current_mode = table->modes[next_index].id; - return true; + return table->modes[next_index].id; } const key_binding_t * diff --git a/src/core/binding.h b/src/core/binding.h index de92a21..ff4bb51 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -86,12 +87,15 @@ bool binding_table_set_current_mode( /** * @brief 切换按键绑定模式 * + * @details 纯计算不修改任何内容 + * * @param table 按键绑定表 * @param delta 切换变化量 * - * @return 无法切换返回 false 否则返回 true + * @return 切换后的模式 ID */ -bool binding_table_cycle_mode(binding_table_t *table, int delta); +zdwm_binding_mode_id_t +binding_table_cycle_mode(const binding_table_t *table, int32_t delta); /** * @brief 获取当前按键绑定列表 diff --git a/src/core/command.h b/src/core/command.h index 1c2a8f6..1069b29 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -22,6 +22,7 @@ typedef enum command_type_t { ZDWM_COMMAND_SET_CURRENT_OUTPUT, ZDWM_COMMAND_SET_LAYOUT, ZDWM_COMMAND_SET_BINDING_MODE, + ZDWM_COMMAND_QUIT, } command_type_t; typedef struct manage_window_command_t { @@ -63,6 +64,9 @@ typedef struct set_binding_mode_command_t { zdwm_binding_mode_id_t mode; } set_binding_mode_command_t; +typedef struct quit_command_t { + bool will_restart; +} quit_command_t; /** * @brief 非 owning 的命令值对象 @@ -94,5 +98,6 @@ typedef struct command_t { set_current_output_command_t current_output; set_layout_command_t layout; set_binding_mode_command_t binding_mode; + quit_command_t quit; } as; } command_t; diff --git a/src/core/plan.c b/src/core/plan.c index a27b635..0146d2a 100644 --- a/src/core/plan.c +++ b/src/core/plan.c @@ -36,8 +36,11 @@ void plan_reset(plan_t *plan) { void plan_cleanup(plan_t *plan) { free_memory_hold_by_effects(plan->effects, plan->count); p_delete(&plan->effects); - plan->count = 0; - plan->capacity = 0; + plan->count = 0; + plan->capacity = 0; + plan->need_relayout = false; + plan->quit = false; + plan->will_restart = false; } void plan_push_effect(plan_t *plan, const effect_t *effect) { diff --git a/src/core/policy.c b/src/core/policy.c index ec5e208..a10675d 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -2,9 +2,12 @@ #include #include +#include #include #include "base/macros.h" +#include "base/memory.h" +#include "base/process.h" #include "base/window_list.h" #include "core/binding.h" #include "core/command.h" @@ -18,11 +21,402 @@ #include "core/window.h" #include "core/wm_desc.h" -static void policy_resolve_action( +static void quit(bool restart, command_buffer_t *command_buffer) { + command_t quit_command = { + .type = ZDWM_COMMAND_QUIT, + .as.quit.will_restart = restart + }; + command_buffer_push(command_buffer, &quit_command); +} + +static const window_t * +get_next_window_by_class(const state_t *state, const char *class_name) { + auto output = state_output_at(state, state->current_output_index); + auto workspace = state_workspace_get(state, output->current_workspace_id); + + size_t start_index = 0; + if (!window_id_invalid(workspace->focused_window_id)) { + for (size_t i = 0; i < state_window_count(state); ++i) { + if (state_window_at(state, i)->id == workspace->focused_window_id) { + start_index = i; + break; + } + } + } + + for (size_t i = start_index + 1; i < state_window_count(state); ++i) { + auto window = state_window_at(state, i); + if (strcmp(window->class_name, class_name) == 0) { + return window; + } + } + + for (size_t i = 0; i < MIN(start_index + 1, state_window_count(state)); ++i) { + auto window = state_window_at(state, i); + if (strcmp(window->class_name, class_name) == 0) { + return window; + } + } + return nullptr; +} + +static void raise_or_run( const state_t *state, + const zdwm_action_data_raise_or_run_t *data, + command_buffer_t *command_buffer +) { + auto window = get_next_window_by_class(state, data->class_name); + if (!window) { + spawn(data->command); + return; + } + + command_t switch_workspace_cmd = { + .type = ZDWM_COMMAND_SWITCH_WORKSPACE, + .as.switch_workspace.workspace = window->workspace_id, + }; + command_buffer_push(command_buffer, &switch_workspace_cmd); + + command_t focus_cmd = { + .type = ZDWM_COMMAND_FOCUS_WINDOW, + .as.focus.window = window->id, + }; + command_buffer_push(command_buffer, &focus_cmd); +} + +static output_id_t get_cycled_output(const state_t *state, int32_t delta) { + if (state->output_count <= 1) return ZDWM_OUTPUT_ID_INVALID; + + int64_t count = (int64_t)state->output_count; + int64_t current = (int64_t)state->current_output_index; + int64_t next = (current + (int64_t)delta) % count; + if (next < 0) next += count; + + auto output = state_output_at(state, (size_t)next); + return output->id; +} + +static void cycle_current_output( + const state_t *state, + int32_t delta, + command_buffer_t *command_buffer +) { + auto output_id = get_cycled_output(state, delta); + if (output_id == ZDWM_OUTPUT_ID_INVALID) return; + + command_t cmd = { + .type = ZDWM_COMMAND_SET_CURRENT_OUTPUT, + .as.current_output.output = output_id, + }; + command_buffer_push(command_buffer, &cmd); +} + +static void switch_workspace_same_output_by_index( + const state_t *state, + uint32_t index, + command_buffer_t *command_buffer +) { + auto output = state_output_at(state, state->current_output_index); + uint32_t count = 0; + for (size_t i = 0; i < state_workspace_count(state); ++i) { + auto workspace = state_workspace_at(state, i); + if (workspace->output_id != output->id) continue; + + if (count == index) { + command_t switch_workspace_cmd = { + .type = ZDWM_COMMAND_SWITCH_WORKSPACE, + .as.switch_workspace.workspace = workspace->id, + }; + command_buffer_push(command_buffer, &switch_workspace_cmd); + return; + } + count++; + } +} + +static void cycle_layout( + const state_t *state, + int32_t delta, + command_buffer_t *command_buffer +) { + auto output = state_output_at(state, state->current_output_index); + auto workspace = state_workspace_get(state, output->current_workspace_id); + + int32_t index = 0; + bool matched = false; + auto layout_count = (int32_t)workspace->layout_count; + if (layout_count <= 1) return; + + for (int32_t i = 0; i < layout_count; ++i) { + if (workspace->layout_id == workspace->available_layouts[i]) { + index = i; + matched = true; + break; + } + } + + if (!matched) return; + + auto new_index = index + delta; + new_index %= layout_count; + if (new_index < 0) new_index += layout_count; + + if (new_index == index) return; + + auto next_layout_id = workspace->available_layouts[new_index]; + command_t set_layout_command = { + .type = ZDWM_COMMAND_SET_LAYOUT, + .as.layout = {.workspace = workspace->id, .layout = next_layout_id}, + }; + command_buffer_push(command_buffer, &set_layout_command); +} + +static void cycle_binding_mode( + const binding_table_t *table, + int32_t delta, + command_buffer_t *command_buffer +) { + auto next_mode_id = binding_table_cycle_mode(table, delta); + + if (next_mode_id == ZDWM_BINDING_MODE_ID_INVALID) return; + + command_t set_binding_mode_command = { + .type = ZDWM_COMMAND_SET_BINDING_MODE, + .as.binding_mode.mode = next_mode_id, + }; + command_buffer_push(command_buffer, &set_binding_mode_command); +} + +static const window_t *get_current_focused_window(const state_t *state) { + auto output = state_output_at(state, state->current_output_index); + auto workspace = state_workspace_get(state, output->current_workspace_id); + return state_window_get(state, workspace->focused_window_id); +} + +#define DEFUN_WINDOW_TOGGLE_FN(NAME, TYPE, DATA_FIELD, WINDOW_FIELD) \ + static void NAME(const state_t *state, command_buffer_t *command_buffer) { \ + auto window = get_current_focused_window(state); \ + if (!window) return; \ + \ + command_t command = { \ + .type = (TYPE), \ + .as.DATA_FIELD = {.window = window->id, .state = !window->WINDOW_FIELD}, \ + }; \ + command_buffer_push(command_buffer, &command); \ + } + +DEFUN_WINDOW_TOGGLE_FN( + toggle_window_fullscreen, + ZDWM_COMMAND_WINDOW_SET_FULLSCREEN, + fullscreen, + fullscreen +) +DEFUN_WINDOW_TOGGLE_FN( + toggle_window_maximize, + ZDWM_COMMAND_WINDOW_SET_MAXIMIZED, + maximized, + maximized +) +DEFUN_WINDOW_TOGGLE_FN( + toggle_window_floating, + ZDWM_COMMAND_WINDOW_SET_FLOATING, + floating, + floating +) +DEFUN_WINDOW_TOGGLE_FN( + toggle_window_sticky, + ZDWM_COMMAND_WINDOW_SET_STICKY, + sticky, + sticky +) + +#undef DEFUN_WINDOW_TOGGLE_FN + +static void cycle_focused_window( + const state_t *state, + int32_t delta, + command_buffer_t *command_buffer +) { + auto output = state_output_at(state, state->current_output_index); + auto workspace = state_workspace_get(state, output->current_workspace_id); + + size_t count = state_window_count(state); + if (!count) return; + + size_t indices[count]; + size_t num = 0; + for (size_t i = 0; i < count; ++i) { + auto window = state_window_at(state, i); + if (window->workspace_id == workspace->id) { + indices[num++] = i; + } + } + if (!num) return; + + size_t current = 0; + if (!window_id_invalid(workspace->focused_window_id)) { + for (size_t i = 0; i < num; ++i) { + auto window = state_window_at(state, indices[i]); + if (window->id == workspace->focused_window_id) { + current = i; + break; + } + } + } + + int64_t next = ((int64_t)current + (int64_t)delta) % (int64_t)num; + if (next < 0) next += (int64_t)num; + + auto target = state_window_at(state, indices[next]); + + command_t focus_cmd = { + .type = ZDWM_COMMAND_FOCUS_WINDOW, + .as.focus.window = target->id, + }; + command_buffer_push(command_buffer, &focus_cmd); + + command_t raise_cmd = { + .type = ZDWM_COMMAND_RAISE_WINDOW, + .as.raise.window = target->id, + }; + command_buffer_push(command_buffer, &raise_cmd); +} + +static void +kill_window_action(const state_t *state, command_buffer_t *command_buffer) { + auto window = get_current_focused_window(state); + if (!window) return; + + command_t kill_window_command = { + .type = ZDWM_COMMAND_KILL_WINDOW, + .as.kill.window = window->id, + }; + command_buffer_push(command_buffer, &kill_window_command); +} + +static void cycle_window_output( + const state_t *state, + const zdwm_action_data_window_cycle_output_t *data, + command_buffer_t *command_buffer +) { + auto window = get_current_focused_window(state); + if (!window) return; + + auto output_id = get_cycled_output(state, data->delta); + if (output_id == ZDWM_OUTPUT_ID_INVALID) return; + + if (data->keep_focus) { + command_t set_current_output_command = { + .type = ZDWM_COMMAND_SET_CURRENT_OUTPUT, + .as.current_output.output = output_id, + }; + command_buffer_push(command_buffer, &set_current_output_command); + } + + auto output = state_output_get(state, output_id); + auto workspace = state_workspace_get(state, output->current_workspace_id); + command_t send_window_to_workspace_command = { + .type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE, + .as.send_to_workspace = { + .window = window->id, + .workspace = workspace->id, + }, + }; + command_buffer_push(command_buffer, &send_window_to_workspace_command); +} + +static void send_window_to_workspace_same_output_by_index( + const state_t *state, + const zdwm_action_data_window_send_to_workspace_t *data, + command_buffer_t *command_buffer +) { + auto output = state_output_at(state, state->current_output_index); + auto current_workspace = + state_workspace_get(state, output->current_workspace_id); + + auto target_workspace = state_workspace_at(state, (size_t)data->index); + if (current_workspace->id == target_workspace->id) return; + + if (data->switch_workspace) { + command_t switch_workspace_command = { + .type = ZDWM_COMMAND_SWITCH_WORKSPACE, + .as.switch_workspace.workspace = target_workspace->id, + }; + command_buffer_push(command_buffer, &switch_workspace_command); + } + + command_t send_window_to_workspace_command = { + .type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE, + .as.send_to_workspace = { + .window = current_workspace->focused_window_id, + .workspace = target_workspace->id, + }, + }; + command_buffer_push(command_buffer, &send_window_to_workspace_command); +} + +static void policy_resolve_action( + const policy_context_t *ctx, const zdwm_action_t *action, command_buffer_t *out -) {} +) { + switch (action->type) { + case ZDWM_ACTION_SPAWN: + spawn(action->as.spawn.command); + break; + case ZDWM_ACTION_QUIT: + quit(action->as.quit.restart, out); + break; + case ZDWM_ACTION_RAISE_OR_RUN: + raise_or_run(ctx->state, &action->as.raise_or_run, out); + break; + case ZDWM_ACTION_OUTPUT_CYCLE: + cycle_current_output(ctx->state, action->as.output_cycle.delta, out); + break; + case ZDWM_ACTION_WORKSPACE_SWITCH_SAME_OUTPUT_BY_INDEX: { + auto index = action->as.workspace_switch_same_output_by_index.index; + switch_workspace_same_output_by_index(ctx->state, index, out); + } break; + case ZDWM_ACTION_LAYOUT_CYCLE: + cycle_layout(ctx->state, action->as.layout_cycle.delta, out); + break; + case ZDWM_ACTION_BINDING_MODE_CYCLE: { + auto delta = action->as.binding_mode_cycle.delta; + cycle_binding_mode(ctx->bind_table, delta, out); + } break; + case ZDWM_ACTION_WINDOW_TOGGLE_FULLSCREEN: + toggle_window_fullscreen(ctx->state, out); + break; + case ZDWM_ACTION_WINDOW_TOGGLE_MAXIMIZE: + toggle_window_maximize(ctx->state, out); + break; + case ZDWM_ACTION_WINDOW_TOGGLE_MINIMIZE: + /* TODO: 恢复需要单独的逻辑,需要考虑是否将最小化和恢复拆成两个 action */ + break; + case ZDWM_ACTION_WINDOW_TOGGLE_FLOATING: + toggle_window_floating(ctx->state, out); + break; + case ZDWM_ACTION_WINDOW_TOGGLE_STICKY: + toggle_window_sticky(ctx->state, out); + break; + case ZDWM_ACTION_WINDOW_FOCUS_CYCLE: + cycle_focused_window(ctx->state, action->as.window_focus_cycle.delta, out); + break; + case ZDWM_ACTION_WINDOW_KILL: + kill_window_action(ctx->state, out); + break; + case ZDWM_ACTION_WINDOW_SEND_TO_WORKSPACE_SAME_OUTPUT_BY_INDEX: + send_window_to_workspace_same_output_by_index( + ctx->state, + &action->as.window_send_to_workspace_same_output_by_index, + out + ); + break; + case ZDWM_ACTION_WINDOW_CYCLE_OUTPUT: + cycle_window_output(ctx->state, &action->as.window_cycle_output, out); + break; + } +} static void route_key_press( const policy_context_t *ctx, @@ -38,8 +432,7 @@ static void route_key_press( for (size_t i = 0; i < count; ++i) { auto binding = &bindings[i]; if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) { - policy_resolve_action(ctx->state, &binding->action, out); - /* binding->fn(ctx->runtime, &ctx->action_api, &binding->arg); */ + policy_resolve_action(ctx, &binding->action, out); } } } @@ -944,21 +1337,44 @@ static void set_layout( const set_layout_command_t *command, plan_t *plan ) { - auto state = ctx->state; + auto state = ctx->state; auto workspace_id = command->workspace; - auto layout_id = command->layout; + 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); + 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 + zdwm_binding_mode_id_t binding_mode, + plan_t *plan ) { if (!binding_table_set_current_mode(ctx->bind_table, binding_mode)) return; + + size_t count = 0; + auto bindings = binding_table_get_current_bindings(ctx->bind_table, &count); + if (bindings && count > 0) { + auto keys = p_new(key_bind_t, count); + for (size_t i = 0; i < count; ++i) { + keys[i].keysym = bindings[i].keysym; + keys[i].modifiers = bindings[i].modifiers; + } + + effect_t effect = { + .type = ZDWM_EFFECT_BIND_KEY, + .as.bind_key = {.count = count, .keys = keys}, + }; + plan_push_effect(plan, &effect); + } + listeners_notify_binding_mode(ctx->listeners, ctx->bind_table); } @@ -1023,7 +1439,11 @@ void policy_apply_command( set_layout(ctx, &cmd->as.layout, plan); break; case ZDWM_COMMAND_SET_BINDING_MODE: - set_binding_mode(ctx, cmd->as.binding_mode.mode); + set_binding_mode(ctx, cmd->as.binding_mode.mode, plan); + break; + case ZDWM_COMMAND_QUIT: + plan->quit = true; + plan->will_restart = cmd->as.quit.will_restart; break; } } diff --git a/src/core/runtime.c b/src/core/runtime.c index 9d5fd81..c5c5d17 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -7,7 +7,6 @@ #include "base/array.h" #include "base/memory.h" -#include "core/action.h" #include "core/backend.h" #include "core/binding.h" #include "core/command_buffer.h" @@ -363,6 +362,11 @@ void runtime_run(runtime_t *runtime) { if (plan->need_relayout) runtime_arrange(runtime); if (plan->count) backend_apply_effect(backend, plan->effects, plan->count); + if (plan->quit) { + runtime->running = false; + runtime->will_restart = plan->will_restart; + } + event_cleanup(&event); } } diff --git a/src/core/state.c b/src/core/state.c index 3659416..1ab3d49 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -145,39 +145,6 @@ static void state_workspace_adjust_focused_window( workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID; } -bool state_workspace_cycle_layout( - state_t *state, - workspace_id_t workspace_id, - int32_t delta -) { - workspace_t *workspace = - (workspace_t *)state_workspace_get(state, workspace_id); - if (!workspace) return false; - - int32_t index = 0; - bool matched = false; - auto layout_count = (int32_t)workspace->layout_count; - for (int32_t i = 0; i < layout_count; i++) { - if (workspace->layout_id == workspace->available_layouts[i]) { - index = i; - matched = true; - break; - } - } - - if (!matched) return false; - - auto new_index = index + delta; - new_index %= layout_count; - if (new_index < 0) new_index += layout_count; - - if (new_index == index) return false; - - auto next_layout_id = workspace->available_layouts[new_index]; - workspace->layout_id = next_layout_id; - return true; -} - bool state_workspace_set_layout_by_index( state_t *state, workspace_id_t workspace_id, @@ -309,14 +276,6 @@ bool state_output_valid(const state_t *state, output_id_t id) { #endif } -void state_cycle_current_output(state_t *state, int delta) { - int64_t count = (int64_t)state->output_count; - int64_t current = (int64_t)state->current_output_index; - int64_t next = (current + (int64_t)delta) % count; - if (next < 0) next += count; - 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]; diff --git a/src/core/state.h b/src/core/state.h index 4ed76dd..5108704 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -81,11 +81,6 @@ void state_cleanup(state_t *state); */ const workspace_t *state_workspace_get(const state_t *state, workspace_id_t id); const workspace_t *state_workspace_at(const state_t *state, size_t index); -bool state_workspace_cycle_layout( - state_t *state, - workspace_id_t workspace_id, - int32_t delta -); bool state_workspace_set_layout_by_index( state_t *state, workspace_id_t workspace_id, @@ -144,7 +139,6 @@ bool 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 *