feat(action): 重构 action 接口为函数指针表并实现 quit 和 raise_or_run

This commit is contained in:
2026-05-05 00:44:04 +08:00
parent d6512c531f
commit 70e2477649
9 changed files with 178 additions and 24 deletions

View File

@@ -2,6 +2,7 @@
#define ZDWM_ACTION_H #define ZDWM_ACTION_H
#include <stdint.h> #include <stdint.h>
#include <zdwm/types.h>
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
@@ -12,16 +13,36 @@ typedef union zdwm_action_arg_t {
int32_t i; int32_t i;
uint32_t ui; uint32_t ui;
const char *str; const char *str;
const void *ptr;
} zdwm_action_arg_t; } zdwm_action_arg_t;
typedef struct zdwm_action_ctx_t zdwm_action_ctx_t; typedef struct zdwm_runtime_t zdwm_runtime_t;
typedef void typedef struct zdwm_action_api_t {
zdwm_action_fn(const zdwm_action_ctx_t *ctx, const zdwm_action_arg_t *arg);
struct zdwm_action_ctx_t {
void (*spawn)(const char *command); void (*spawn)(const char *command);
}; void (*quit)(zdwm_runtime_t *runtime, bool restart);
void (*raise_or_run)(
zdwm_runtime_t *runtime,
const char *class_name,
const char *command
);
void (*toggle_fullscreen)(zdwm_runtime_t *runtime);
void (*toggle_maximize)(zdwm_runtime_t *runtime);
void (*toggle_floating)(zdwm_runtime_t *runtime);
void (*toggle_sticky)(zdwm_runtime_t *runtime);
void (*switch_workspace)(
zdwm_runtime_t *runtime,
zdwm_workspace_id_t workspace_id
);
void (*cycle_layout)(zdwm_runtime_t *runtime, int32_t delta);
void (*cycle_current_output)(zdwm_runtime_t *runtime, int32_t delta);
} zdwm_action_api_t;
typedef void zdwm_action_fn(
zdwm_runtime_t *runtime,
const zdwm_action_api_t *ctx,
const zdwm_action_arg_t *arg
);
#if defined(__cplusplus) #if defined(__cplusplus)
} }

View File

@@ -3,13 +3,46 @@
#include <zdwm/action.h> #include <zdwm/action.h>
#include <zdwm/types.h> #include <zdwm/types.h>
#include "base/log.h"
#include "base/macros.h" #include "base/macros.h"
static constexpr char launcher[] = static constexpr char launcher[] =
"rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd"; "rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd";
static void spawn(const zdwm_action_ctx_t *ctx, const zdwm_action_arg_t *arg) { typedef struct raise_or_run_arg_t {
ctx->spawn(arg->str); const char *class_name;
const char *command;
} raise_or_run_arg_t;
static raise_or_run_arg_t terminal = {"XTerm", "xterm"};
static raise_or_run_arg_t editor = {"Emacs", "emacsclient -a '' -r -n"};
static raise_or_run_arg_t browser = {"firefox", "firefox-bin"};
static raise_or_run_arg_t chrome = {"Google-chrome", "google-chrome-stable"};
static void spawn(
zdwm_runtime_t *runtime,
const zdwm_action_api_t *api,
const zdwm_action_arg_t *arg
) {
api->spawn(arg->str);
}
static void quit(
zdwm_runtime_t *runtime,
const zdwm_action_api_t *api,
const zdwm_action_arg_t *arg
) {
logger("quit: restart: %s\n", arg->b ? "true" : "false");
api->quit(runtime, arg->b);
}
static void raise_or_run(
zdwm_runtime_t *runtime,
const zdwm_action_api_t *api,
const zdwm_action_arg_t *arg
) {
auto args = (raise_or_run_arg_t *)arg->ptr;
api->raise_or_run(runtime, args->class_name, args->command);
} }
bool config_defaults_build( bool config_defaults_build(
@@ -71,10 +104,20 @@ bool config_defaults_build(
auto default_mode = api->add_mode(builder, "default"); auto default_mode = api->add_mode(builder, "default");
#define BIND(mode, key, fn, arg) \ #define Alt "Mod1"
api->bind(builder, mode, key, fn, (zdwm_action_arg_t)arg) #define Super "Mod4"
#define BIND(MODE, KEY, FN, ARG) \
api->bind(builder, MODE, KEY, FN, (zdwm_action_arg_t)ARG)
BIND(default_mode, "Mod4+r", spawn, {.str = launcher}); BIND(default_mode, Super "+r", spawn, {.str = launcher});
BIND(default_mode, Super "+Shift+q", quit, {.b = false});
BIND(default_mode, Super "+Control+r", quit, {.b = true});
BIND(default_mode, Super "+Return", spawn, {.str = terminal.command});
BIND(default_mode, Alt "+Control+r", raise_or_run, {.ptr = &terminal});
BIND(default_mode, Super "+e", raise_or_run, {.ptr = &editor});
BIND(default_mode, Super "+q", raise_or_run, {.ptr = &browser});
BIND(default_mode, Super "+a", raise_or_run, {.ptr = &chrome});
#undef BIND #undef BIND

View File

@@ -1,11 +1,18 @@
#include "core/action.h" #include "core/action.h"
#include <paths.h> #include <paths.h>
#include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include "base/log.h" #include "base/log.h"
#include "base/macros.h"
#include "core/command.h"
#include "core/command_buffer.h"
#include "core/state.h"
#include "core/types.h"
#include "core/window.h"
void spawn(const char *command) { void spawn(const char *command) {
if (fork() == 0) { if (fork() == 0) {
@@ -21,3 +28,63 @@ void spawn(const char *command) {
wait(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(
zdwm_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);
}

View File

@@ -1,3 +1,11 @@
#pragma once #pragma once
#include "core/runtime.h"
void spawn(const char *command); void spawn(const char *command);
void quit(runtime_t *runtime, bool restart);
void raise_or_run(
zdwm_runtime_t *runtime,
const char *class_name,
const char *command
);

View File

@@ -18,11 +18,10 @@
#include "core/window.h" #include "core/window.h"
#include "core/wm_desc.h" #include "core/wm_desc.h"
static void route_key_press( static void
binding_table_t *binding_table, route_key_press(const policy_context_t *ctx, const key_press_event_t *e) {
const zdwm_action_ctx_t *action_ctx, auto binding_table = ctx->bind_table;
const key_press_event_t *e
) {
size_t count = 0; size_t count = 0;
auto bindings = binding_table_get_current_bindings(binding_table, &count); auto bindings = binding_table_get_current_bindings(binding_table, &count);
if (!bindings) return; if (!bindings) return;
@@ -30,7 +29,7 @@ static void route_key_press(
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto binding = &bindings[i]; auto binding = &bindings[i];
if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) { if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) {
binding->fn(action_ctx, &binding->arg); binding->fn(ctx->runtime, &ctx->action_api, &binding->arg);
} }
} }
} }
@@ -180,7 +179,7 @@ void policy_route_event(
auto state = ctx->state; auto state = ctx->state;
switch (event->type) { switch (event->type) {
case ZDWM_EVENT_KEY_PRESS: case ZDWM_EVENT_KEY_PRESS:
route_key_press(ctx->bind_table, &ctx->action_ctx, &event->as.key_press); route_key_press(ctx, &event->as.key_press);
break; break;
case ZDWM_EVENT_POINTER_ENTER: case ZDWM_EVENT_POINTER_ENTER:
route_pointer_enter(state, event->as.pointer_enter.window, out); route_pointer_enter(state, event->as.pointer_enter.window, out);

View File

@@ -17,7 +17,8 @@ typedef struct policy_context_t {
const rules_t *rules; const rules_t *rules;
const border_config_t *border; const border_config_t *border;
const layout_registry_t *layouts; const layout_registry_t *layouts;
const zdwm_action_ctx_t action_ctx; const zdwm_action_api_t action_api;
zdwm_runtime_t *runtime;
} policy_context_t; } policy_context_t;
/** /**

View File

@@ -5,9 +5,9 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/layout.h> #include <zdwm/layout.h>
#include "action.h"
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/action.h"
#include "core/backend.h" #include "core/backend.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/command_buffer.h" #include "core/command_buffer.h"
@@ -270,8 +270,11 @@ void runtime_run(runtime_t *runtime) {
.rules = &runtime->rules, .rules = &runtime->rules,
.border = &runtime->border, .border = &runtime->border,
.layouts = &runtime->layouts, .layouts = &runtime->layouts,
.action_ctx = { .runtime = runtime,
.spawn = spawn, .action_api = {
.spawn = spawn,
.quit = quit,
.raise_or_run = raise_or_run,
}, },
}; };

View File

@@ -26,7 +26,7 @@ typedef struct runtime_init_desc_t {
binding_table_t *binding_table; binding_table_t *binding_table;
} runtime_init_desc_t; } runtime_init_desc_t;
typedef struct runtime_t { typedef struct zdwm_runtime_t {
bool running; bool running;
bool will_restart; bool will_restart;

View File

@@ -1,3 +1,6 @@
#include <errno.h>
#include <unistd.h>
#include "base/log.h" #include "base/log.h"
#include "config/runtime_config.h" #include "config/runtime_config.h"
#include "core/backend.h" #include "core/backend.h"
@@ -32,7 +35,11 @@ static void bootstrap(runtime_t *runtime) {
} }
}; };
int main(void) { char **cmd_argv = nullptr;
int main(int argc, char *argv[]) {
cmd_argv = argv;
runtime_t runtime = {0}; runtime_t runtime = {0};
bootstrap(&runtime); bootstrap(&runtime);
@@ -40,5 +47,10 @@ int main(void) {
runtime_run(&runtime); runtime_run(&runtime);
runtime_shutdown(&runtime); runtime_shutdown(&runtime);
if (runtime.will_restart) {
execvp(cmd_argv[0], cmd_argv);
fatal("execv() failed: %s", strerror(errno));
}
return 0; return 0;
} }