diff --git a/src/core/command.h b/src/core/command.h index e3f3a8c..5b4db94 100644 --- a/src/core/command.h +++ b/src/core/command.h @@ -9,6 +9,7 @@ typedef enum command_type_t { ZDWM_COMMAND_FOCUS_WINDOW, ZDWM_COMMAND_KILL_WINDOW, ZDWM_COMMAND_WITHDRAW_WINDOW, + ZDWM_COMMAND_CONFIGURE_WINDOW, ZDWM_COMMAND_CHANGE_WINDOW_STATE, ZDWM_COMMAND_SWITCH_WORKSPACE, } command_type_t; @@ -51,6 +52,7 @@ typedef struct command_t { only_window_command_t focus; only_window_command_t kill; only_window_command_t withdraw; + configure_data_t configure; window_state_change_command_t state_change; switch_workspace_command_t switch_workspace; } as; diff --git a/src/core/policy.c b/src/core/policy.c index 8da03f2..2183523 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -1,6 +1,7 @@ #include "core/policy.h" #include +#include #include #include "base/macros.h" @@ -8,6 +9,7 @@ #include "core/command.h" #include "core/command_buffer.h" #include "core/event.h" +#include "core/layout.h" #include "core/plan.h" #include "core/rules.h" #include "core/state.h" @@ -137,6 +139,50 @@ static void route_window_remove( } } +static void route_configure_request( + state_t *state, + const configure_data_t *data, + const layout_registry_t *layouts, + command_buffer_t *out +) { + auto window = state_window_get(state, data->window); + if (!window) { + command_t configure_cmd = { + .type = ZDWM_COMMAND_CONFIGURE_WINDOW, + .as.configure = *data + }; + command_buffer_push(out, &configure_cmd); + return; + } + + if (data->changed_fields & ZDWM_CONFIGURE_FIELD_BORDER_WIDTH) { + command_t configure_border_width_cmd = { + .type = ZDWM_COMMAND_CONFIGURE_WINDOW, + .as.configure = { + .window = window->id, + .border_width = data->border_width, + .changed_fields = ZDWM_CONFIGURE_FIELD_BORDER_WIDTH, + } + }; + command_buffer_push(out, &configure_border_width_cmd); + return; + } + + if (!state_workspace_show(state, window->workspace_id)) return; + if (window_need_layout(window)) return; + auto workspace = state_workspace_get(state, window->workspace_id); + if (layout_get(layouts, workspace->layout_id)) return; + + command_t configure_rect_cmd = { + .type = ZDWM_COMMAND_CONFIGURE_WINDOW, + .as.configure = *data, + }; + configure_rect_cmd.as.configure.changed_fields &= + ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | + ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT; + command_buffer_push(out, &configure_rect_cmd); +} + void policy_route_event( const policy_context_t *ctx, const event_t *event, @@ -153,6 +199,10 @@ void policy_route_event( case ZDWM_EVENT_WINDOW_REMOVE: route_window_remove(state, &event->as.window_remove, out); break; + case ZDWM_EVENT_CONFIGURE_REQUEST: { + auto data = &event->as.configure_request; + route_configure_request(state, data, ctx->layouts, out); + } break; default: } } @@ -283,6 +333,56 @@ static void withdraw_window(state_t *state, window_id_t window, plan_t *plan) { plan_push_effect(plan, &withdraw_window_effect); } +static void +configure_window(state_t *state, const configure_data_t *data, plan_t *plan) { + auto window = state_window_get(state, data->window); + if (!window) { + effect_t configure_effect = { + .type = ZDWM_EFFECT_CONFIGURE_WINDOW, + .as.configure = *data, + }; + plan_push_effect(plan, &configure_effect); + return; + } + + auto rect = window->frame_rect; +#define PICK_FIELD(FIELD_MASK, RECT_FIELD, DATA_FIELD) \ + if (data->changed_fields & (FIELD_MASK)) rect.RECT_FIELD = data->DATA_FIELD + + PICK_FIELD(ZDWM_CONFIGURE_FIELD_X, x, x); + PICK_FIELD(ZDWM_CONFIGURE_FIELD_Y, y, y); + PICK_FIELD(ZDWM_CONFIGURE_FIELD_WIDTH, width, width); + PICK_FIELD(ZDWM_CONFIGURE_FIELD_HEIGHT, height, height); + +#undef PICK_FIELD + + auto need_move = window_need_move(window, rect.x, rect.y); + auto need_resize = window_need_resize(window, rect.width, rect.height); + if (!need_move && !need_resize) return; + + state_window_set_frame_rect(state, window->id, rect); + + effect_t configure_effect = { + .type = ZDWM_EFFECT_CONFIGURE_WINDOW, + .as.configure = { + .window = window->id, + .x = rect.x, + .y = rect.y, + .width = rect.width, + .height = rect.height, + } + }; + if (need_move) { + configure_effect.as.configure.changed_fields |= + ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y; + } + if (need_resize) { + configure_effect.as.configure.changed_fields |= + ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT; + } + plan_push_effect(plan, &configure_effect); +} + static void fullscreen_window( state_t *state, window_id_t window_id, @@ -489,6 +589,9 @@ void policy_apply_command( case ZDWM_COMMAND_WITHDRAW_WINDOW: withdraw_window(state, cmd->as.withdraw.window, plan); break; + case ZDWM_COMMAND_CONFIGURE_WINDOW: + configure_window(state, &cmd->as.configure, plan); + break; case ZDWM_COMMAND_CHANGE_WINDOW_STATE: change_window_state(state, &cmd->as.state_change, plan); break; diff --git a/src/core/policy.h b/src/core/policy.h index 6c9e82b..87c2374 100644 --- a/src/core/policy.h +++ b/src/core/policy.h @@ -5,6 +5,7 @@ #include "core/binding.h" #include "core/command_buffer.h" #include "core/event.h" +#include "core/layout.h" #include "core/plan.h" #include "core/rules.h" #include "core/state.h" @@ -13,6 +14,7 @@ typedef struct policy_context_t { binding_table_t *bind_table; state_t *state; const rules_t *rules; + const layout_registry_t *layouts; const zdwm_action_ctx_t action_ctx; } policy_context_t; diff --git a/src/core/runtime.c b/src/core/runtime.c index 3bf380b..2882271 100644 --- a/src/core/runtime.c +++ b/src/core/runtime.c @@ -265,6 +265,7 @@ void runtime_run(runtime_t *runtime) { .bind_table = runtime->binding_table, .state = &runtime->state, .rules = &runtime->rules, + .layouts = &runtime->layouts, .action_ctx = { .spawn = spawn, },