diff --git a/include/zdwm/action.h b/include/zdwm/action.h index 75a28fa..594d15a 100644 --- a/include/zdwm/action.h +++ b/include/zdwm/action.h @@ -2,6 +2,7 @@ #define ZDWM_ACTION_H #include +#include #if defined(__cplusplus) extern "C" { @@ -12,16 +13,36 @@ typedef union zdwm_action_arg_t { int32_t i; uint32_t ui; const char *str; + const void *ptr; } zdwm_action_arg_t; -typedef struct zdwm_action_ctx_t zdwm_action_ctx_t; +typedef struct zdwm_runtime_t zdwm_runtime_t; -typedef void -zdwm_action_fn(const zdwm_action_ctx_t *ctx, const zdwm_action_arg_t *arg); - -struct zdwm_action_ctx_t { +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 (*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) } diff --git a/src/config/defaults.c b/src/config/defaults.c index 76f79ed..a4ed91e 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -3,13 +3,46 @@ #include #include +#include "base/log.h" #include "base/macros.h" static constexpr char launcher[] = "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) { - ctx->spawn(arg->str); +typedef struct raise_or_run_arg_t { + 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( @@ -71,10 +104,20 @@ bool config_defaults_build( auto default_mode = api->add_mode(builder, "default"); -#define BIND(mode, key, fn, arg) \ - api->bind(builder, mode, key, fn, (zdwm_action_arg_t)arg) +#define Alt "Mod1" +#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 diff --git a/src/core/action.c b/src/core/action.c index f4308ff..3f177ac 100644 --- a/src/core/action.c +++ b/src/core/action.c @@ -1,11 +1,18 @@ #include "core/action.h" #include +#include #include #include #include #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) { if (fork() == 0) { @@ -21,3 +28,63 @@ void spawn(const char *command) { 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); +} diff --git a/src/core/action.h b/src/core/action.h index e1b1c21..fa6b4de 100644 --- a/src/core/action.h +++ b/src/core/action.h @@ -1,3 +1,11 @@ #pragma once +#include "core/runtime.h" + 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 +); diff --git a/src/core/policy.c b/src/core/policy.c index b23b161..5915342 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -18,11 +18,10 @@ #include "core/window.h" #include "core/wm_desc.h" -static void route_key_press( - binding_table_t *binding_table, - const zdwm_action_ctx_t *action_ctx, - const key_press_event_t *e -) { +static void +route_key_press(const policy_context_t *ctx, const key_press_event_t *e) { + auto binding_table = ctx->bind_table; + size_t count = 0; auto bindings = binding_table_get_current_bindings(binding_table, &count); if (!bindings) return; @@ -30,7 +29,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) { - 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; switch (event->type) { 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; case ZDWM_EVENT_POINTER_ENTER: route_pointer_enter(state, event->as.pointer_enter.window, out); diff --git a/src/core/policy.h b/src/core/policy.h index 9692db9..bd32948 100644 --- a/src/core/policy.h +++ b/src/core/policy.h @@ -17,7 +17,8 @@ typedef struct policy_context_t { const rules_t *rules; const border_config_t *border; 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; /** diff --git a/src/core/runtime.c b/src/core/runtime.c index 8163d31..4bcd8df 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -5,9 +5,9 @@ #include #include -#include "action.h" #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" @@ -270,8 +270,11 @@ void runtime_run(runtime_t *runtime) { .rules = &runtime->rules, .border = &runtime->border, .layouts = &runtime->layouts, - .action_ctx = { - .spawn = spawn, + .runtime = runtime, + .action_api = { + .spawn = spawn, + .quit = quit, + .raise_or_run = raise_or_run, }, }; diff --git a/src/core/runtime.h b/src/core/runtime.h index fc25dde..0a2f34d 100644 --- a/src/core/runtime.h +++ b/src/core/runtime.h @@ -26,7 +26,7 @@ typedef struct runtime_init_desc_t { binding_table_t *binding_table; } runtime_init_desc_t; -typedef struct runtime_t { +typedef struct zdwm_runtime_t { bool running; bool will_restart; diff --git a/tests/core/main.c b/tests/core/main.c index dfc5074..d652f52 100644 --- a/tests/core/main.c +++ b/tests/core/main.c @@ -1,3 +1,6 @@ +#include +#include + #include "base/log.h" #include "config/runtime_config.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}; bootstrap(&runtime); @@ -40,5 +47,10 @@ int main(void) { runtime_run(&runtime); runtime_shutdown(&runtime); + if (runtime.will_restart) { + execvp(cmd_argv[0], cmd_argv); + fatal("execv() failed: %s", strerror(errno)); + } + return 0; }