diff --git a/include/zdwm/action.h b/include/zdwm/action.h index 594d15a..99e709f 100644 --- a/include/zdwm/action.h +++ b/include/zdwm/action.h @@ -36,6 +36,7 @@ typedef struct zdwm_action_api_t { ); 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; typedef void zdwm_action_fn( diff --git a/src/config/defaults.c b/src/config/defaults.c index 4fef215..9b998af 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -67,6 +67,14 @@ static void toggle_floating( api->toggle_floating(runtime); } +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); +} + bool config_defaults_build( const zdwm_api_t *api, zdwm_config_builder_t *builder, @@ -143,6 +151,8 @@ bool config_defaults_build( 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}); #undef BIND diff --git a/src/core/action.c b/src/core/action.c index 8a5f75e..5d50872 100644 --- a/src/core/action.c +++ b/src/core/action.c @@ -177,3 +177,50 @@ 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); +} diff --git a/src/core/action.h b/src/core/action.h index 3842c2d..671b3de 100644 --- a/src/core/action.h +++ b/src/core/action.h @@ -21,3 +21,4 @@ void switch_workspace( ); 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); diff --git a/src/core/command.h b/src/core/command.h index 9dabdd8..1ccefd8 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -8,6 +8,7 @@ typedef enum command_type_t { ZDWM_COMMAND_UNMANAGE_WINDOW, ZDWM_COMMAND_FOCUS_WINDOW, ZDWM_COMMAND_KILL_WINDOW, + ZDWM_COMMAND_RAISE_WINDOW, ZDWM_COMMAND_WITHDRAW_WINDOW, ZDWM_COMMAND_CONFIGURE_WINDOW, ZDWM_COMMAND_CHANGE_WINDOW_STATE, @@ -56,6 +57,7 @@ typedef struct command_t { only_window_data_t unmanage; only_window_data_t focus; only_window_data_t kill; + only_window_data_t raise; only_window_data_t withdraw; configure_data_t configure; window_state_change_command_t state_change; diff --git a/src/core/policy.c b/src/core/policy.c index d5c5476..ecacb03 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -476,6 +476,26 @@ static void kill_window(state_t *state, window_id_t window, plan_t *plan) { plan_push_kill_effect(plan, window); } +static void raise_window(state_t *state, window_id_t window, plan_t *plan) { + if (!state_stack_raise(state, window)) return; + + window_list_t list = {0}; + for (size_t i = 0; i < countof(state->stacks); ++i) { + for (size_t j = 0; j < state->stacks[i].count; ++j) { + auto window_id = state->stacks[i].order[j]; + window_list_push(&list, window_id); + } + } + effect_t restack_windows_effect = { + .type = ZDWM_EFFECT_RESTACK_WINDOWS, + .as.restack_windows = { + .windows = list.windows, + .count = list.count, + }, + }; + plan_push_effect(plan, &restack_windows_effect); +} + static void withdraw_window(state_t *state, window_id_t window, plan_t *plan) { auto win = state_window_get(state, window); if (!win) return; @@ -846,6 +866,9 @@ void policy_apply_command( case ZDWM_COMMAND_KILL_WINDOW: kill_window(state, cmd->as.kill.window, plan); break; + case ZDWM_COMMAND_RAISE_WINDOW: + raise_window(state, cmd->as.raise.window, plan); + break; case ZDWM_COMMAND_WITHDRAW_WINDOW: withdraw_window(state, cmd->as.withdraw.window, plan); break; diff --git a/src/core/runtime.c b/src/core/runtime.c index b48cad7..d8f2355 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -276,6 +276,7 @@ policy_context_t policy_context_init(runtime_t *runtime) { .switch_workspace = switch_workspace, .cycle_layout = cycle_layout, .cycle_current_output = cycle_current_output, + .focus_window = focus_window, }, }; return ctx;