refactor(policy): 删除 action 模块,将 action -> command 解析放在 policy 模块内部

- 删除 src/core/action.c|h,将 spawn 移至 src/base/process
- policy_resolve_action 实现完整的 action 分发逻辑
- binding_table_cycle_mode 改为纯计算,返回模式 ID 而非修改状态
- 从 state 移除 state_workspace_cycle_layout / state_cycle_current_output
- 新增 ZDWM_COMMAND_QUIT 命令,通过 plan 标志驱动 runtime 退出
- set_binding_mode 现在生成 BIND_KEY effect 以同步后端按键绑定
- 扩展 action 数据类型支持 window_send_to_workspace 和 window_cycle_output
This commit is contained in:
2026-05-27 01:12:04 +08:00
parent ff3b51fd1d
commit 09d5e4b4d0
14 changed files with 497 additions and 368 deletions

View File

@@ -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

View File

@@ -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;

23
src/base/process.c Normal file
View File

@@ -0,0 +1,23 @@
#include "base/process.h"
#include <paths.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#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);
}

3
src/base/process.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
void spawn(const char *command);

View File

@@ -1,265 +0,0 @@
#include "core/action.h"
#include <paths.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#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);
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include <stdint.h>
#include <zdwm/action.h>
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);

View File

@@ -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 *

View File

@@ -1,6 +1,7 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <zdwm/action.h>
#include <zdwm/types.h>
@@ -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 获取当前按键绑定列表

View File

@@ -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;

View File

@@ -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) {

View File

@@ -2,9 +2,12 @@
#include <stddef.h>
#include <stdint.h>
#include <zdwm/action.h>
#include <zdwm/types.h>
#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;
}
}

View File

@@ -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);
}
}

View File

@@ -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];

View File

@@ -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
*