Compare commits
6 Commits
edde023f5a
...
09d5e4b4d0
| Author | SHA1 | Date | |
|---|---|---|---|
|
09d5e4b4d0
|
|||
|
ff3b51fd1d
|
|||
|
989a1ce6e8
|
|||
|
13fc41f141
|
|||
|
ca9e543cc0
|
|||
|
33b0f2f54f
|
@@ -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
|
||||
|
||||
@@ -8,50 +8,76 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef union zdwm_action_arg_t {
|
||||
bool b;
|
||||
int32_t i;
|
||||
uint32_t ui;
|
||||
const char *str;
|
||||
const void *ptr;
|
||||
} zdwm_action_arg_t;
|
||||
typedef enum zdwm_action_type_t {
|
||||
ZDWM_ACTION_SPAWN,
|
||||
ZDWM_ACTION_QUIT,
|
||||
ZDWM_ACTION_RAISE_OR_RUN,
|
||||
|
||||
typedef struct zdwm_runtime_t zdwm_runtime_t;
|
||||
ZDWM_ACTION_OUTPUT_CYCLE,
|
||||
ZDWM_ACTION_WORKSPACE_SWITCH_SAME_OUTPUT_BY_INDEX,
|
||||
ZDWM_ACTION_LAYOUT_CYCLE,
|
||||
ZDWM_ACTION_BINDING_MODE_CYCLE,
|
||||
|
||||
typedef struct zdwm_action_api_t {
|
||||
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 (*switch_workspace_in_current_output)(
|
||||
zdwm_runtime_t *runtime,
|
||||
zdwm_workspace_id_t workspace_id
|
||||
);
|
||||
void (*switch_workspace_by_index_in_current_output)(
|
||||
zdwm_runtime_t *runtime,
|
||||
uint32_t index
|
||||
);
|
||||
void (*cycle_layout)(zdwm_runtime_t *runtime, int32_t delta);
|
||||
void (*cycle_current_output)(zdwm_runtime_t *runtime, int32_t delta);
|
||||
void (*focus_window)(zdwm_runtime_t *runtime, int32_t delta);
|
||||
} zdwm_action_api_t;
|
||||
ZDWM_ACTION_WINDOW_TOGGLE_FULLSCREEN,
|
||||
ZDWM_ACTION_WINDOW_TOGGLE_MAXIMIZE,
|
||||
ZDWM_ACTION_WINDOW_TOGGLE_MINIMIZE,
|
||||
ZDWM_ACTION_WINDOW_TOGGLE_FLOATING,
|
||||
ZDWM_ACTION_WINDOW_TOGGLE_STICKY,
|
||||
|
||||
typedef void zdwm_action_fn(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *ctx,
|
||||
const zdwm_action_arg_t *arg
|
||||
);
|
||||
ZDWM_ACTION_WINDOW_FOCUS_CYCLE,
|
||||
ZDWM_ACTION_WINDOW_KILL,
|
||||
|
||||
ZDWM_ACTION_WINDOW_SEND_TO_WORKSPACE_SAME_OUTPUT_BY_INDEX,
|
||||
ZDWM_ACTION_WINDOW_CYCLE_OUTPUT,
|
||||
} zdwm_action_type_t;
|
||||
|
||||
typedef struct zdwm_action_data_spawn_t {
|
||||
const char *command;
|
||||
} zdwm_action_data_spawn_t;
|
||||
|
||||
typedef struct zdwm_action_data_quit_t {
|
||||
bool restart;
|
||||
} zdwm_action_data_quit_t;
|
||||
|
||||
typedef struct zdwm_action_data_raise_or_run_t {
|
||||
const char *class_name;
|
||||
const char *command;
|
||||
} zdwm_action_data_raise_or_run_t;
|
||||
|
||||
typedef struct zdwm_action_data_delta_only_t {
|
||||
int32_t delta;
|
||||
} zdwm_action_data_delta_only_t;
|
||||
|
||||
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 {
|
||||
zdwm_action_data_spawn_t spawn;
|
||||
zdwm_action_data_quit_t quit;
|
||||
zdwm_action_data_raise_or_run_t raise_or_run;
|
||||
zdwm_action_data_delta_only_t output_cycle;
|
||||
zdwm_action_data_index_only_t workspace_switch_same_output_by_index;
|
||||
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_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;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -112,8 +112,7 @@ typedef struct zdwm_api_t {
|
||||
zdwm_config_builder_t *builder,
|
||||
zdwm_binding_mode_id_t bind_mode,
|
||||
const char *key_sequence,
|
||||
zdwm_action_fn action_fn,
|
||||
zdwm_action_arg_t action_arg
|
||||
zdwm_action_t action
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,13 +30,14 @@ typedef void zdwm_workspace_active_updated(
|
||||
typedef struct zdwm_layout_notify_t {
|
||||
zdwm_workspace_id_t workspace;
|
||||
zdwm_layout_id_t id;
|
||||
const char *name; /* 不持有内存 */
|
||||
const char *symbol; /* 不持有内存 */
|
||||
const char *description; /* 不持有内存 */
|
||||
} zdwm_layout_notify_t;
|
||||
typedef void zdwm_layout_notify(zdwm_layout_notify_t layout, void *user_data);
|
||||
|
||||
typedef struct zdwm_binding_mode_notify_t {
|
||||
bool is_default_mode;
|
||||
bool is_current_mode;
|
||||
zdwm_binding_mode_id_t id;
|
||||
const char *name; /* 不持有内存 */
|
||||
} zdwm_binding_mode_notify_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);
|
||||
@@ -13,80 +13,12 @@
|
||||
static constexpr char launcher[] =
|
||||
"rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd";
|
||||
|
||||
typedef struct raise_or_run_arg_t {
|
||||
const char *class_name;
|
||||
const char *command;
|
||||
} raise_or_run_arg_t;
|
||||
typedef struct zdwm_action_data_raise_or_run_t raise_or_run_data_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
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
||||
static void toggle_fullscreen(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *api,
|
||||
const zdwm_action_arg_t *arg
|
||||
) {
|
||||
api->toggle_fullscreen(runtime);
|
||||
}
|
||||
|
||||
static void toggle_maximize(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *api,
|
||||
const zdwm_action_arg_t *arg
|
||||
) {
|
||||
api->toggle_maximize(runtime);
|
||||
}
|
||||
|
||||
static void toggle_floating(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *api,
|
||||
const zdwm_action_arg_t *arg
|
||||
) {
|
||||
api->toggle_floating(runtime);
|
||||
}
|
||||
|
||||
static void switch_workspace(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *api,
|
||||
const zdwm_action_arg_t *arg
|
||||
) {
|
||||
api->switch_workspace_by_index_in_current_output(runtime, arg->ui);
|
||||
}
|
||||
|
||||
static void focus_window(
|
||||
zdwm_runtime_t *runtime,
|
||||
const zdwm_action_api_t *api,
|
||||
const zdwm_action_arg_t *arg
|
||||
) {
|
||||
api->focus_window(runtime, arg->i);
|
||||
}
|
||||
static raise_or_run_data_t terminal = {"XTerm", "xterm"};
|
||||
static raise_or_run_data_t editor = {"Emacs", "emacsclient -a '' -r -n"};
|
||||
static raise_or_run_data_t browser = {"firefox", "firefox-bin"};
|
||||
static raise_or_run_data_t chrome = {"Google-chrome", "google-chrome-stable"};
|
||||
|
||||
bool config_defaults_build(
|
||||
const zdwm_api_t *api,
|
||||
@@ -156,32 +88,63 @@ bool config_defaults_build(
|
||||
|
||||
auto default_mode = api->add_mode(builder, "default");
|
||||
|
||||
#define Alt "Mod1"
|
||||
#define Super "Mod4"
|
||||
#define BIND(MODE, KEY, FN, ARG) \
|
||||
api->bind(builder, MODE, KEY, FN, (zdwm_action_arg_t)ARG)
|
||||
#define Alt_Key "Mod1"
|
||||
#define Super_key "Mod4"
|
||||
#define Alt(K) Alt_Key "+" K
|
||||
#define Super(K) Super_key "+" K
|
||||
|
||||
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});
|
||||
#define BIND(MODE, KEY, ...) \
|
||||
api->bind(builder, MODE, KEY, (zdwm_action_t)__VA_ARGS__)
|
||||
#define SPAWN(MODE, KEY, COMMAND) \
|
||||
BIND(MODE, KEY, {.type = ZDWM_ACTION_SPAWN, .as.spawn.command = (COMMAND)})
|
||||
#define QUIT(MODE, KEY, RESTART) \
|
||||
BIND(MODE, KEY, {.type = ZDWM_ACTION_QUIT, .as.quit.restart = (RESTART)})
|
||||
#define RAISE_OR_RUN(MODE, KEY, ...) \
|
||||
BIND( \
|
||||
MODE, \
|
||||
KEY, \
|
||||
{ \
|
||||
.type = ZDWM_ACTION_RAISE_OR_RUN, \
|
||||
.as.raise_or_run = (zdwm_action_data_raise_or_run_t)__VA_ARGS__, \
|
||||
} \
|
||||
)
|
||||
#define BIND_DEFAULT(KEY, ...) BIND(default_mode, KEY, __VA_ARGS__)
|
||||
|
||||
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});
|
||||
BIND(default_mode, Super "+f", toggle_fullscreen, {0});
|
||||
BIND(default_mode, Super "+m", toggle_maximize, {0});
|
||||
BIND(default_mode, Super "+Control+space", toggle_floating, {0});
|
||||
BIND(default_mode, Alt "+j", focus_window, {.i = 1});
|
||||
BIND(default_mode, Alt "+k", focus_window, {.i = -1});
|
||||
SPAWN(default_mode, Super("r"), launcher);
|
||||
QUIT(default_mode, Super("Shift+q"), false);
|
||||
QUIT(default_mode, Super("Control+r"), true);
|
||||
|
||||
SPAWN(default_mode, Super("Return"), terminal.command);
|
||||
RAISE_OR_RUN(default_mode, Alt("Control+r"), terminal);
|
||||
RAISE_OR_RUN(default_mode, Super("e"), editor);
|
||||
RAISE_OR_RUN(default_mode, Super("q"), browser);
|
||||
RAISE_OR_RUN(default_mode, Super("a"), chrome);
|
||||
BIND_DEFAULT(Super("f"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_FLOATING});
|
||||
BIND_DEFAULT(Super("m"), {.type = ZDWM_ACTION_WINDOW_TOGGLE_MAXIMIZE});
|
||||
BIND_DEFAULT(
|
||||
Super("Control+space"),
|
||||
{.type = ZDWM_ACTION_WINDOW_TOGGLE_FLOATING}
|
||||
);
|
||||
BIND_DEFAULT(
|
||||
Alt("j"),
|
||||
{.type = ZDWM_ACTION_WINDOW_FOCUS_CYCLE, .as.window_focus_cycle.delta = 1}
|
||||
);
|
||||
BIND_DEFAULT(
|
||||
Alt("k"),
|
||||
{.type = ZDWM_ACTION_WINDOW_FOCUS_CYCLE, .as.window_focus_cycle.delta = -1}
|
||||
);
|
||||
|
||||
char buffer[64] = {0};
|
||||
for (uint32_t i = 0; i < 9; ++i) {
|
||||
snprintf(buffer, sizeof(buffer), "%s+%d", Super, i + 1);
|
||||
BIND(default_mode, buffer, switch_workspace, {.ui = i});
|
||||
snprintf(buffer, sizeof(buffer), "%s+%d", Super_key, i + 1);
|
||||
zdwm_action_t action = {
|
||||
.type = ZDWM_ACTION_WINDOW_SEND_TO_WORKSPACE_SAME_OUTPUT_BY_INDEX,
|
||||
.as.workspace_switch_same_output_by_index.index = i,
|
||||
};
|
||||
BIND_DEFAULT(buffer, action);
|
||||
}
|
||||
|
||||
#undef BIND_DEFAULT
|
||||
#undef BIND
|
||||
|
||||
api->set_default_mode(builder, default_mode);
|
||||
|
||||
@@ -41,6 +41,7 @@ void runtime_config_cleanup(runtime_init_desc_t *desc) {
|
||||
}
|
||||
binding_table_destroy(desc->binding_table);
|
||||
desc->binding_table = nullptr;
|
||||
listeners_cleanup(&desc->listeners);
|
||||
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
|
||||
if (desc->config_module_handle) dlclose(desc->config_module_handle);
|
||||
desc->config_module_handle = nullptr;
|
||||
@@ -59,6 +60,7 @@ static void config_builder_cleanup(zdwm_config_builder_t *builder) {
|
||||
|
||||
binding_table_destroy(builder->binding_table);
|
||||
builder->binding_table = nullptr;
|
||||
listeners_cleanup(&builder->listeners);
|
||||
}
|
||||
|
||||
static layout_id_t runtime_config_register_layout(
|
||||
@@ -167,10 +169,9 @@ static bool runtime_config_bind(
|
||||
zdwm_config_builder_t *builder,
|
||||
zdwm_binding_mode_id_t mode,
|
||||
const char *key,
|
||||
zdwm_action_fn fn,
|
||||
zdwm_action_arg_t arg
|
||||
zdwm_action_t action
|
||||
) {
|
||||
return binding_table_add_bind(builder->binding_table, mode, key, fn, arg);
|
||||
return binding_table_add_bind(builder->binding_table, mode, key, action);
|
||||
}
|
||||
|
||||
static bool runtime_config_set_default_mode(
|
||||
|
||||
@@ -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,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zdwm/action.h>
|
||||
|
||||
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 switch_workspace_in_current_output(
|
||||
zdwm_runtime_t *runtime,
|
||||
zdwm_workspace_id_t workspace_id
|
||||
);
|
||||
void switch_workspace_by_index_in_current_output(
|
||||
zdwm_runtime_t *runtime,
|
||||
uint32_t index
|
||||
);
|
||||
void cycle_layout(zdwm_runtime_t *runtime, int32_t delta);
|
||||
void cycle_current_output(zdwm_runtime_t *runtime, int32_t delta);
|
||||
void focus_window(zdwm_runtime_t *runtime, int32_t delta);
|
||||
@@ -43,8 +43,7 @@ binding_table_add_mode(binding_table_t *table, const char *mode_name) {
|
||||
}
|
||||
|
||||
zdwm_binding_mode_id_t id = (zdwm_binding_mode_id_t)table->count;
|
||||
binding_mode_t *new_mode =
|
||||
array_push(table->modes, table->count, table->capacity);
|
||||
auto new_mode = array_push(table->modes, table->count, table->capacity);
|
||||
new_mode->name = mode_name;
|
||||
new_mode->id = id;
|
||||
|
||||
@@ -166,8 +165,7 @@ bool binding_table_add_bind(
|
||||
binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id,
|
||||
const char *key_sequence,
|
||||
zdwm_action_fn fn,
|
||||
zdwm_action_arg_t arg
|
||||
zdwm_action_t action
|
||||
) {
|
||||
binding_mode_t *mode = binding_table_get_mode(table, mode_id);
|
||||
if (!mode) return false;
|
||||
@@ -176,12 +174,11 @@ bool binding_table_add_bind(
|
||||
xkb_keysym_t keysym = XKB_KEY_NoSymbol;
|
||||
if (!parse_key_sequence(key_sequence, &modifiers, &keysym)) return false;
|
||||
|
||||
key_binding_t *item = array_push(mode->items, mode->count, mode->capacity);
|
||||
auto item = array_push(mode->items, mode->count, mode->capacity);
|
||||
item->key_str = key_sequence;
|
||||
item->modifiers = modifiers;
|
||||
item->keysym = keysym;
|
||||
item->fn = fn;
|
||||
item->arg = arg;
|
||||
item->action = action;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -228,14 +225,17 @@ bool binding_table_set_current_mode(
|
||||
binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id
|
||||
) {
|
||||
if (mode_id >= table->count) return false;
|
||||
if (mode_id >= table->count || mode_id == table->current_mode) return false;
|
||||
|
||||
table->current_mode = mode_id;
|
||||
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;
|
||||
@@ -251,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 *
|
||||
@@ -272,3 +268,48 @@ binding_table_get_current_bindings(binding_table_t *table, size_t *count) {
|
||||
*count = mode->count;
|
||||
return mode->items;
|
||||
}
|
||||
|
||||
size_t binding_table_mode_count(const binding_table_t *table) {
|
||||
if (!table) return 0;
|
||||
return table->count;
|
||||
}
|
||||
|
||||
zdwm_binding_mode_id_t binding_table_get_default_mode(
|
||||
const binding_table_t *table
|
||||
) {
|
||||
if (!table) return ZDWM_BINDING_MODE_ID_INVALID;
|
||||
return table->default_mode;
|
||||
}
|
||||
|
||||
zdwm_binding_mode_id_t binding_table_get_current_mode(
|
||||
const binding_table_t *table
|
||||
) {
|
||||
if (!table) return ZDWM_BINDING_MODE_ID_INVALID;
|
||||
return table->current_mode;
|
||||
}
|
||||
|
||||
static const binding_mode_t *binding_table_get_mode_const(
|
||||
const binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id
|
||||
) {
|
||||
if (!table || mode_id >= table->count) return nullptr;
|
||||
|
||||
const binding_mode_t *mode = &table->modes[mode_id];
|
||||
if (mode->id == mode_id) return mode;
|
||||
|
||||
for (size_t i = 0; i < table->count; ++i) {
|
||||
mode = &table->modes[i];
|
||||
if (mode->id == mode_id) return mode;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *binding_table_get_mode_name(
|
||||
const binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id
|
||||
) {
|
||||
auto mode = binding_table_get_mode_const(table, mode_id);
|
||||
if (!mode) return nullptr;
|
||||
return mode->name;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <zdwm/action.h>
|
||||
#include <zdwm/types.h>
|
||||
|
||||
@@ -12,8 +13,7 @@ typedef struct key_binding_t {
|
||||
const char *key_str;
|
||||
modifier_mask_t modifiers;
|
||||
keysym_t keysym;
|
||||
zdwm_action_fn *fn;
|
||||
zdwm_action_arg_t arg;
|
||||
zdwm_action_t action;
|
||||
} key_binding_t;
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,7 @@ binding_table_add_mode(binding_table_t *table, const char *mode_name);
|
||||
* @param table 按键绑定表
|
||||
* @param mode_id 模式 ID
|
||||
* @param key_sequence 按键序列的字符串表达
|
||||
* @param fn 用户行为函数
|
||||
* @param arg 用户行为函数所需的参数
|
||||
* @param action 用户行为描述
|
||||
*
|
||||
* @return 添加成功返回 true 否则返回 false
|
||||
*/
|
||||
@@ -46,8 +45,7 @@ bool binding_table_add_bind(
|
||||
binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id,
|
||||
const char *key_sequence,
|
||||
zdwm_action_fn fn,
|
||||
zdwm_action_arg_t arg
|
||||
zdwm_action_t action
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -89,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 获取当前按键绑定列表
|
||||
@@ -110,3 +111,15 @@ bool binding_table_cycle_mode(binding_table_t *table, int delta);
|
||||
*/
|
||||
const key_binding_t *
|
||||
binding_table_get_current_bindings(binding_table_t *table, size_t *count);
|
||||
|
||||
size_t binding_table_mode_count(const binding_table_t *table);
|
||||
zdwm_binding_mode_id_t binding_table_get_default_mode(
|
||||
const binding_table_t *table
|
||||
);
|
||||
zdwm_binding_mode_id_t binding_table_get_current_mode(
|
||||
const binding_table_t *table
|
||||
);
|
||||
const char *binding_table_get_mode_name(
|
||||
const binding_table_t *table,
|
||||
zdwm_binding_mode_id_t mode_id
|
||||
);
|
||||
|
||||
@@ -12,12 +12,17 @@ typedef enum command_type_t {
|
||||
ZDWM_COMMAND_WITHDRAW_WINDOW,
|
||||
ZDWM_COMMAND_CONFIGURE_WINDOW,
|
||||
ZDWM_COMMAND_CHANGE_WINDOW_STATE,
|
||||
ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE,
|
||||
ZDWM_COMMAND_WINDOW_SET_FLOATING,
|
||||
ZDWM_COMMAND_WINDOW_SET_STICKY,
|
||||
ZDWM_COMMAND_WINDOW_SET_MINIMIZED,
|
||||
ZDWM_COMMAND_WINDOW_SET_MAXIMIZED,
|
||||
ZDWM_COMMAND_WINDOW_SET_FULLSCREEN,
|
||||
ZDWM_COMMAND_SWITCH_WORKSPACE,
|
||||
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 {
|
||||
@@ -36,11 +41,33 @@ typedef struct window_state_change_command_t {
|
||||
window_state_request_action_t action;
|
||||
} window_state_change_command_t;
|
||||
|
||||
typedef struct window_send_to_workspace_command_t {
|
||||
window_id_t window;
|
||||
workspace_id_t workspace;
|
||||
} window_send_to_workspace_command_t;
|
||||
|
||||
typedef struct window_bool_state_t {
|
||||
window_id_t window;
|
||||
bool state;
|
||||
} window_bool_state_t;
|
||||
|
||||
typedef struct set_current_output_command_t {
|
||||
output_id_t output;
|
||||
} set_current_output_command_t;
|
||||
|
||||
typedef struct set_layout_command_t {
|
||||
workspace_id_t workspace;
|
||||
layout_id_t layout;
|
||||
} set_layout_command_t;
|
||||
|
||||
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 的命令值对象
|
||||
* @details
|
||||
@@ -61,11 +88,16 @@ typedef struct command_t {
|
||||
only_window_data_t withdraw;
|
||||
configure_data_t configure;
|
||||
window_state_change_command_t state_change;
|
||||
window_send_to_workspace_command_t send_to_workspace;
|
||||
window_bool_state_t floating;
|
||||
window_bool_state_t sticky;
|
||||
window_bool_state_t minimized;
|
||||
window_bool_state_t maximized;
|
||||
window_bool_state_t fullscreen;
|
||||
switch_workspace_command_t switch_workspace;
|
||||
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;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "core/listeners.h"
|
||||
|
||||
#include "base/array.h"
|
||||
#include "base/memory.h"
|
||||
#include "core/binding.h"
|
||||
#include "core/layout.h"
|
||||
#include "core/state.h"
|
||||
|
||||
#define ADD_LISTENER(FIELD) \
|
||||
auto list = &listeners->FIELD; \
|
||||
@@ -81,3 +85,209 @@ void listeners_add_window_removed_listener(
|
||||
}
|
||||
|
||||
#undef ADD_LISTENER
|
||||
|
||||
#define CLEANUP_LIST(FIELD) \
|
||||
p_delete(&listeners->FIELD.items); \
|
||||
listeners->FIELD.count = 0; \
|
||||
listeners->FIELD.capacity = 0
|
||||
|
||||
void listeners_cleanup(listeners_t *listeners) {
|
||||
if (!listeners) return;
|
||||
|
||||
CLEANUP_LIST(output_listeners);
|
||||
CLEANUP_LIST(initial_workspace_listeners);
|
||||
CLEANUP_LIST(active_workspace_listeners);
|
||||
CLEANUP_LIST(layout_listeners);
|
||||
CLEANUP_LIST(binding_mode_listeners);
|
||||
CLEANUP_LIST(initial_window_listeners);
|
||||
CLEANUP_LIST(window_added_listeners);
|
||||
CLEANUP_LIST(window_updated_listeners);
|
||||
CLEANUP_LIST(window_removed_listeners);
|
||||
}
|
||||
|
||||
#undef CLEANUP_LIST
|
||||
|
||||
#define FOR_EACH_LISTENER(FIELD, BODY) \
|
||||
do { \
|
||||
if (!(listeners)) return; \
|
||||
auto list = &(listeners)->FIELD; \
|
||||
for (size_t i = 0; i < list->count; ++i) { \
|
||||
auto item = &list->items[i]; \
|
||||
BODY; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
void listeners_notify_current_output(
|
||||
const listeners_t *listeners,
|
||||
output_id_t output_id
|
||||
) {
|
||||
FOR_EACH_LISTENER(output_listeners, item->fn(output_id, item->user_data));
|
||||
}
|
||||
|
||||
void listeners_notify_initial_workspaces(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state
|
||||
) {
|
||||
if (!listeners || !state) return;
|
||||
|
||||
size_t count = state_workspace_count(state);
|
||||
auto items = count ? p_new(zdwm_workspace_t, count) : nullptr;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto workspace = state_workspace_at(state, i);
|
||||
|
||||
items[i] = (zdwm_workspace_t){
|
||||
.output_id = workspace->output_id,
|
||||
.id = workspace->id,
|
||||
.name = workspace->name,
|
||||
};
|
||||
}
|
||||
|
||||
FOR_EACH_LISTENER(
|
||||
initial_workspace_listeners,
|
||||
item->fn(items, count, item->user_data)
|
||||
);
|
||||
|
||||
p_delete(&items);
|
||||
}
|
||||
|
||||
void listeners_notify_workspace_active(
|
||||
const listeners_t *listeners,
|
||||
output_id_t output_id,
|
||||
workspace_id_t workspace_id
|
||||
) {
|
||||
FOR_EACH_LISTENER(
|
||||
active_workspace_listeners,
|
||||
item->fn(output_id, workspace_id, item->user_data)
|
||||
);
|
||||
}
|
||||
|
||||
void listeners_notify_layout(
|
||||
const listeners_t *listeners,
|
||||
const layout_registry_t *layouts,
|
||||
workspace_id_t workspace_id,
|
||||
layout_id_t layout_id
|
||||
) {
|
||||
if (!listeners || !layouts) return;
|
||||
|
||||
auto slot = layout_slot_get(layouts, layout_id);
|
||||
if (!slot) return;
|
||||
|
||||
zdwm_layout_notify_t notify = {
|
||||
.workspace = workspace_id,
|
||||
.id = layout_id,
|
||||
.name = slot->name,
|
||||
.symbol = slot->symbol,
|
||||
.description = slot->description,
|
||||
};
|
||||
|
||||
FOR_EACH_LISTENER(layout_listeners, item->fn(notify, item->user_data));
|
||||
}
|
||||
|
||||
void listeners_notify_binding_mode(
|
||||
const listeners_t *listeners,
|
||||
const binding_table_t *binding_table
|
||||
) {
|
||||
if (!listeners || !binding_table) return;
|
||||
|
||||
auto default_mode = binding_table_get_default_mode(binding_table);
|
||||
auto current_mode = binding_table_get_current_mode(binding_table);
|
||||
auto name = binding_table_get_mode_name(binding_table, current_mode);
|
||||
|
||||
zdwm_binding_mode_notify_t notify = {
|
||||
.is_default_mode = default_mode == current_mode,
|
||||
.id = current_mode,
|
||||
.name = name,
|
||||
};
|
||||
|
||||
FOR_EACH_LISTENER(binding_mode_listeners, item->fn(notify, item->user_data));
|
||||
}
|
||||
|
||||
static bool listeners_window_snapshot(
|
||||
const state_t *state,
|
||||
window_id_t window_id,
|
||||
zdwm_window_t *out
|
||||
) {
|
||||
if (!state || !out || window_id_invalid(window_id)) return false;
|
||||
|
||||
auto window = state_window_get(state, window_id);
|
||||
if (!window) return false;
|
||||
|
||||
auto workspace = state_workspace_get(state, window->workspace_id);
|
||||
if (!workspace) return false;
|
||||
|
||||
*out = (zdwm_window_t){
|
||||
.workspace = window->workspace_id,
|
||||
.id = window->id,
|
||||
.title = window->title,
|
||||
.focused = workspace->focused_window_id == window->id,
|
||||
.urgent = window->urgent,
|
||||
.skip_taskbar = window->skip_taskbar,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
void listeners_notify_initial_windows(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state
|
||||
) {
|
||||
if (!listeners || !state) return;
|
||||
|
||||
size_t count = state_window_count(state);
|
||||
zdwm_window_t *items = count ? p_new(zdwm_window_t, count) : nullptr;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto window = state_window_at(state, i);
|
||||
if (!listeners_window_snapshot(state, window->id, &items[i])) {
|
||||
p_clear(&items[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_LISTENER(
|
||||
initial_window_listeners,
|
||||
item->fn(items, count, item->user_data)
|
||||
);
|
||||
|
||||
p_delete(&items);
|
||||
}
|
||||
|
||||
void listeners_notify_window_added(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state,
|
||||
window_id_t window_id
|
||||
) {
|
||||
if (!listeners || !state) return;
|
||||
|
||||
zdwm_window_t window = {0};
|
||||
if (!listeners_window_snapshot(state, window_id, &window)) return;
|
||||
|
||||
FOR_EACH_LISTENER(window_added_listeners, item->fn(&window, item->user_data));
|
||||
}
|
||||
|
||||
void listeners_notify_window_updated(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state,
|
||||
window_id_t window_id
|
||||
) {
|
||||
if (!listeners || !state) return;
|
||||
|
||||
zdwm_window_t window = {0};
|
||||
if (!listeners_window_snapshot(state, window_id, &window)) return;
|
||||
|
||||
FOR_EACH_LISTENER(
|
||||
window_updated_listeners,
|
||||
item->fn(&window, item->user_data)
|
||||
);
|
||||
}
|
||||
|
||||
void listeners_notify_window_removed(
|
||||
const listeners_t *listeners,
|
||||
window_id_t window_id
|
||||
) {
|
||||
if (!listeners || window_id_invalid(window_id)) return;
|
||||
|
||||
FOR_EACH_LISTENER(
|
||||
window_removed_listeners,
|
||||
item->fn(window_id, item->user_data)
|
||||
);
|
||||
}
|
||||
|
||||
#undef FOR_EACH_LISTENER
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#include <stddef.h>
|
||||
#include <zdwm/listeners.h>
|
||||
|
||||
#include "core/types.h"
|
||||
|
||||
typedef struct binding_table_t binding_table_t;
|
||||
typedef struct layout_registry_t layout_registry_t;
|
||||
typedef struct state_t state_t;
|
||||
|
||||
#define ITEM(NAME, FN_TYPE) \
|
||||
typedef struct NAME##_listener_item_t { \
|
||||
FN_TYPE *fn; \
|
||||
@@ -87,3 +93,90 @@ void listeners_add_window_removed_listener(
|
||||
zdwm_window_removed fn,
|
||||
void *user_data
|
||||
);
|
||||
|
||||
void listeners_cleanup(listeners_t *listeners);
|
||||
|
||||
/**
|
||||
* @brief 通知当前 output 信息
|
||||
*
|
||||
* @param listeners 通知函数集合
|
||||
* @param output_id 当前 output id
|
||||
*/
|
||||
void listeners_notify_current_output(
|
||||
const listeners_t *listeners,
|
||||
output_id_t output_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知初始化 workspace 列表
|
||||
*/
|
||||
void listeners_notify_initial_workspaces(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知当前激活的 workspace 信息
|
||||
*/
|
||||
void listeners_notify_workspace_active(
|
||||
const listeners_t *listeners,
|
||||
output_id_t output_id,
|
||||
workspace_id_t workspace_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知当前布局信息
|
||||
*
|
||||
* @param listeners 通知函数集合
|
||||
* @param layouts 布局注册系统
|
||||
* @param workspace_id 当前 workspace id
|
||||
* @param layout_id 当前 workspace 的当前布局 id
|
||||
*/
|
||||
void listeners_notify_layout(
|
||||
const listeners_t *listeners,
|
||||
const layout_registry_t *layouts,
|
||||
workspace_id_t workspace_id,
|
||||
layout_id_t layout_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知当前绑定模式信息
|
||||
*/
|
||||
void listeners_notify_binding_mode(
|
||||
const listeners_t *listeners,
|
||||
const binding_table_t *binding_table
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知初始窗口列表
|
||||
*/
|
||||
void listeners_notify_initial_windows(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知新增窗口
|
||||
*/
|
||||
void listeners_notify_window_added(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state,
|
||||
window_id_t window_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知窗口信息更新
|
||||
*/
|
||||
void listeners_notify_window_updated(
|
||||
const listeners_t *listeners,
|
||||
const state_t *state,
|
||||
window_id_t window_id
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief 通知移除窗口
|
||||
*/
|
||||
void listeners_notify_window_removed(
|
||||
const listeners_t *listeners,
|
||||
window_id_t window_id
|
||||
);
|
||||
|
||||
@@ -38,6 +38,9 @@ void plan_cleanup(plan_t *plan) {
|
||||
p_delete(&plan->effects);
|
||||
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) {
|
||||
|
||||
@@ -77,6 +77,8 @@ typedef struct plan_t {
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
bool need_relayout;
|
||||
bool quit;
|
||||
bool will_restart;
|
||||
} plan_t;
|
||||
|
||||
void plan_reset(plan_t *plan);
|
||||
|
||||
@@ -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,8 +21,408 @@
|
||||
#include "core/window.h"
|
||||
#include "core/wm_desc.h"
|
||||
|
||||
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
|
||||
route_key_press(const policy_context_t *ctx, const key_press_event_t *e) {
|
||||
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,
|
||||
const key_press_event_t *e,
|
||||
command_buffer_t *out
|
||||
) {
|
||||
auto binding_table = ctx->bind_table;
|
||||
|
||||
size_t count = 0;
|
||||
@@ -29,7 +432,7 @@ route_key_press(const policy_context_t *ctx, const key_press_event_t *e) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto binding = &bindings[i];
|
||||
if (binding->modifiers == e->modifiers && binding->keysym == e->keysym) {
|
||||
binding->fn(ctx->runtime, &ctx->action_api, &binding->arg);
|
||||
policy_resolve_action(ctx, &binding->action, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +667,7 @@ void policy_route_event(
|
||||
auto state = ctx->state;
|
||||
switch (event->type) {
|
||||
case ZDWM_EVENT_KEY_PRESS:
|
||||
route_key_press(ctx, &event->as.key_press);
|
||||
route_key_press(ctx, &event->as.key_press, out);
|
||||
break;
|
||||
case ZDWM_EVENT_POINTER_ENTER:
|
||||
route_pointer_enter(state, event->as.pointer_enter.window, out);
|
||||
@@ -778,6 +1181,82 @@ static void change_window_state(
|
||||
}
|
||||
}
|
||||
|
||||
static void send_window_to_workspace(
|
||||
const policy_context_t *ctx,
|
||||
const window_send_to_workspace_command_t *command,
|
||||
plan_t *plan
|
||||
) {
|
||||
auto state = ctx->state;
|
||||
auto window = state_window_get(state, command->window);
|
||||
if (!window) return;
|
||||
if (!state_workspace_valid(state, command->workspace)) return;
|
||||
if (window->workspace_id == command->workspace) return;
|
||||
|
||||
workspace_id_t src_workspace_id = window->workspace_id;
|
||||
bool src_visible = state_workspace_show(state, src_workspace_id);
|
||||
bool dst_visible = state_workspace_show(state, command->workspace);
|
||||
|
||||
const workspace_t *src_ws = state_workspace_get(state, src_workspace_id);
|
||||
window_id_t src_old_focused =
|
||||
src_ws ? src_ws->focused_window_id : ZDWM_WINDOW_ID_INVALID;
|
||||
|
||||
state_window_set_workspace(state, command->window, command->workspace);
|
||||
|
||||
if (!window->sticky) {
|
||||
if (src_visible) plan_push_unmap_effect(plan, command->window);
|
||||
if (dst_visible) plan_push_map_effect(plan, command->window);
|
||||
}
|
||||
|
||||
if (src_visible) {
|
||||
if (src_ws && src_ws->focused_window_id != src_old_focused) {
|
||||
if (!window_id_invalid(src_old_focused) &&
|
||||
state_window_get(state, src_old_focused)) {
|
||||
plan_push_change_border_color_effect(
|
||||
plan,
|
||||
src_old_focused,
|
||||
&ctx->border->normal_color
|
||||
);
|
||||
}
|
||||
if (!window_id_invalid(src_ws->focused_window_id) &&
|
||||
state_window_get(state, src_ws->focused_window_id)) {
|
||||
plan_push_focus_effect(plan, src_ws->focused_window_id);
|
||||
plan_push_change_border_color_effect(
|
||||
plan,
|
||||
src_ws->focused_window_id,
|
||||
&ctx->border->focused_color
|
||||
);
|
||||
}
|
||||
}
|
||||
adjust_layout_windows_border_width(
|
||||
state,
|
||||
ctx->border->width,
|
||||
src_workspace_id
|
||||
);
|
||||
}
|
||||
|
||||
if (dst_visible) {
|
||||
set_foucs_window(ctx, command->workspace, command->window, plan);
|
||||
adjust_layout_windows_border_width(
|
||||
state,
|
||||
ctx->border->width,
|
||||
command->workspace
|
||||
);
|
||||
}
|
||||
|
||||
plan->need_relayout = true;
|
||||
|
||||
auto listeners = ctx->listeners;
|
||||
listeners_notify_window_updated(listeners, state, command->window);
|
||||
if (src_ws && src_ws->focused_window_id != src_old_focused &&
|
||||
!window_id_invalid(src_ws->focused_window_id)) {
|
||||
listeners_notify_window_updated(
|
||||
listeners,
|
||||
state,
|
||||
src_ws->focused_window_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void command_window_set_floating(
|
||||
const policy_context_t *ctx,
|
||||
const window_bool_state_t *data,
|
||||
@@ -845,6 +1324,60 @@ switch_workspace(state_t *state, workspace_id_t workspace_id, plan_t *plan) {
|
||||
state_set_current_output(state, output_id);
|
||||
}
|
||||
|
||||
static void set_current_output(
|
||||
const policy_context_t *ctx,
|
||||
const set_current_output_command_t *command
|
||||
) {
|
||||
if (!state_set_current_output(ctx->state, command->output)) return;
|
||||
listeners_notify_current_output(ctx->listeners, command->output);
|
||||
}
|
||||
|
||||
static void set_layout(
|
||||
const policy_context_t *ctx,
|
||||
const set_layout_command_t *command,
|
||||
plan_t *plan
|
||||
) {
|
||||
auto state = ctx->state;
|
||||
auto workspace_id = command->workspace;
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
static void set_binding_mode(
|
||||
const policy_context_t *ctx,
|
||||
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);
|
||||
}
|
||||
|
||||
void policy_apply_command(
|
||||
const policy_context_t *ctx,
|
||||
const command_buffer_t *command_buffer,
|
||||
@@ -878,6 +1411,9 @@ void policy_apply_command(
|
||||
case ZDWM_COMMAND_CHANGE_WINDOW_STATE:
|
||||
change_window_state(ctx, &cmd->as.state_change, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE:
|
||||
send_window_to_workspace(ctx, &cmd->as.send_to_workspace, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_WINDOW_SET_FLOATING:
|
||||
command_window_set_floating(ctx, &cmd->as.floating, plan);
|
||||
break;
|
||||
@@ -896,6 +1432,19 @@ void policy_apply_command(
|
||||
case ZDWM_COMMAND_SWITCH_WORKSPACE:
|
||||
switch_workspace(state, cmd->as.switch_workspace.workspace, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_SET_CURRENT_OUTPUT:
|
||||
set_current_output(ctx, &cmd->as.current_output);
|
||||
break;
|
||||
case ZDWM_COMMAND_SET_LAYOUT:
|
||||
set_layout(ctx, &cmd->as.layout, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_SET_BINDING_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/command_buffer.h"
|
||||
#include "core/event.h"
|
||||
#include "core/layout.h"
|
||||
#include "core/listeners.h"
|
||||
#include "core/plan.h"
|
||||
#include "core/rules.h"
|
||||
#include "core/state.h"
|
||||
@@ -15,10 +16,9 @@ typedef struct policy_context_t {
|
||||
binding_table_t *bind_table;
|
||||
state_t *state;
|
||||
const rules_t *rules;
|
||||
const listeners_t *listeners;
|
||||
const border_config_t *border;
|
||||
const layout_registry_t *layouts;
|
||||
const zdwm_action_api_t action_api;
|
||||
zdwm_runtime_t *runtime;
|
||||
} policy_context_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
#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"
|
||||
#include "core/event.h"
|
||||
#include "core/layout.h"
|
||||
#include "core/listeners.h"
|
||||
#include "core/plan.h"
|
||||
#include "core/policy.h"
|
||||
#include "core/rules.h"
|
||||
@@ -88,6 +88,7 @@ void runtime_init_desc_cleanup(runtime_init_desc_t *desc) {
|
||||
|
||||
binding_table_destroy(desc->binding_table);
|
||||
desc->binding_table = nullptr;
|
||||
listeners_cleanup(&desc->listeners);
|
||||
|
||||
if (desc->backend) {
|
||||
backend_destroy(desc->backend);
|
||||
@@ -116,12 +117,48 @@ void runtime_shutdown(runtime_t *runtime) {
|
||||
layout_result_cleanup(&runtime->layout_result);
|
||||
binding_table_destroy(runtime->binding_table);
|
||||
runtime->binding_table = nullptr;
|
||||
listeners_cleanup(&runtime->listeners);
|
||||
backend_destroy(runtime->backend);
|
||||
runtime->backend = nullptr;
|
||||
if (runtime->config_module_handle) dlclose(runtime->config_module_handle);
|
||||
runtime->config_module_handle = nullptr;
|
||||
}
|
||||
|
||||
static void runtime_notify_initial_state(runtime_t *runtime) {
|
||||
auto listeners = &runtime->listeners;
|
||||
auto state = &runtime->state;
|
||||
|
||||
auto output = state_output_at(state, state->current_output_index);
|
||||
if (output) listeners_notify_current_output(listeners, output->id);
|
||||
|
||||
listeners_notify_initial_workspaces(listeners, state);
|
||||
|
||||
for (size_t i = 0; i < state_output_count(state); ++i) {
|
||||
auto item = state_output_at(state, i);
|
||||
if (!item) continue;
|
||||
|
||||
listeners_notify_workspace_active(
|
||||
listeners,
|
||||
item->id,
|
||||
item->current_workspace_id
|
||||
);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < state_workspace_count(state); ++i) {
|
||||
auto workspace = state_workspace_at(state, i);
|
||||
if (!workspace) continue;
|
||||
|
||||
listeners_notify_layout(
|
||||
listeners,
|
||||
&runtime->layouts,
|
||||
workspace->id,
|
||||
workspace->layout_id
|
||||
);
|
||||
}
|
||||
|
||||
listeners_notify_binding_mode(listeners, runtime->binding_table);
|
||||
}
|
||||
|
||||
void runtime_setup(runtime_t *runtime) {
|
||||
size_t bind_count = 0;
|
||||
auto bindings =
|
||||
@@ -146,6 +183,7 @@ void runtime_setup(runtime_t *runtime) {
|
||||
|
||||
backend_apply_effect(backend, plan->effects, plan->count);
|
||||
plan_reset(plan);
|
||||
runtime_notify_initial_state(runtime);
|
||||
}
|
||||
|
||||
static const layout_result_t *runtime_layout_calc(runtime_t *runtime) {
|
||||
@@ -264,27 +302,9 @@ static policy_context_t policy_context_init(runtime_t *runtime) {
|
||||
.bind_table = (runtime)->binding_table,
|
||||
.state = &(runtime)->state,
|
||||
.rules = &(runtime)->rules,
|
||||
.listeners = &runtime->listeners,
|
||||
.border = &(runtime)->border,
|
||||
.layouts = &(runtime)->layouts,
|
||||
.runtime = (runtime),
|
||||
.action_api = {
|
||||
.spawn = spawn,
|
||||
.quit = quit,
|
||||
.raise_or_run = raise_or_run,
|
||||
.toggle_fullscreen = toggle_fullscreen,
|
||||
.toggle_maximize = toggle_maximize,
|
||||
.toggle_floating = toggle_floating,
|
||||
.toggle_sticky = toggle_sticky,
|
||||
|
||||
.switch_workspace = switch_workspace,
|
||||
.switch_workspace_in_current_output = switch_workspace_in_current_output,
|
||||
.switch_workspace_by_index_in_current_output =
|
||||
switch_workspace_by_index_in_current_output,
|
||||
|
||||
.cycle_layout = cycle_layout,
|
||||
.cycle_current_output = cycle_current_output,
|
||||
.focus_window = focus_window,
|
||||
},
|
||||
};
|
||||
return ctx;
|
||||
}
|
||||
@@ -294,6 +314,7 @@ void runtime_scan(runtime_t *runtime) {
|
||||
if (!result) return;
|
||||
|
||||
policy_context_t ctx = policy_context_init(runtime);
|
||||
ctx.listeners = nullptr;
|
||||
|
||||
auto backend = runtime->backend;
|
||||
auto command_buffer = &runtime->command_buffer;
|
||||
@@ -316,6 +337,8 @@ void runtime_scan(runtime_t *runtime) {
|
||||
|
||||
backend_scan_result_destroy(result);
|
||||
result = nullptr;
|
||||
|
||||
listeners_notify_initial_windows(&runtime->listeners, &runtime->state);
|
||||
}
|
||||
|
||||
void runtime_run(runtime_t *runtime) {
|
||||
@@ -339,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ typedef struct runtime_init_desc_t {
|
||||
listeners_t listeners;
|
||||
} runtime_init_desc_t;
|
||||
|
||||
typedef struct zdwm_runtime_t {
|
||||
typedef struct runtime_t {
|
||||
bool running;
|
||||
bool will_restart;
|
||||
|
||||
|
||||
@@ -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