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:
@@ -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
|
||||
|
||||
@@ -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
23
src/base/process.c
Normal 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
3
src/base/process.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void spawn(const char *command);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 *
|
||||
|
||||
@@ -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 获取当前按键绑定列表
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user