refactor(runtime): 将 runtime 模块从 core 目录迁移至独立的 runtime 目录并封装内部细节

This commit is contained in:
2026-06-06 02:08:35 +08:00
parent f82d0b7a87
commit be37b17c2e
7 changed files with 98 additions and 102 deletions

View File

@@ -1,372 +0,0 @@
#include "core/runtime.h"
#include <dlfcn.h>
#include <stddef.h>
#include <stdint.h>
#include <zdwm/layout.h>
#include "base/array.h"
#include "base/memory.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"
#include "core/state.h"
#include "core/types.h"
#include "core/window.h"
#include "core/wm_desc.h"
static bool runtime_workspace_desc_has_valid_layouts(
const layout_registry_t *layouts,
const workspace_desc_t *workspace
) {
if (!layouts || !workspace) return false;
for (size_t i = 0; i < workspace->layout_count; i++) {
if (!layout_slot_get(layouts, workspace->layout_ids[i])) return false;
}
return true;
}
static bool runtime_init_desc_valid(const runtime_init_desc_t *desc) {
if (!desc || !desc->backend || !desc->outputs || desc->output_count == 0) {
return false;
}
if (!desc->layouts.slots || desc->layouts.slot_count == 0) return false;
if (!desc->workspaces || desc->workspace_count == 0) return false;
for (size_t i = 0; i < desc->workspace_count; i++) {
const workspace_desc_t *workspace = &desc->workspaces[i];
if (!workspace_desc_valid(workspace, desc->output_count)) return false;
if (!runtime_workspace_desc_has_valid_layouts(&desc->layouts, workspace)) {
return false;
}
}
return true;
}
bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
if (!runtime || !runtime_init_desc_valid(desc)) return false;
p_clear(runtime, 1);
runtime->backend = desc->backend;
layout_registry_move(&desc->layouts, &runtime->layouts);
rules_move(&desc->rules, &runtime->rules);
runtime->border = desc->border;
runtime->config_module_handle = desc->config_module_handle;
runtime->binding_table = desc->binding_table;
runtime->listeners = desc->listeners;
desc->backend = nullptr;
desc->config_module_handle = nullptr;
desc->binding_table = nullptr;
p_clear(&desc->listeners, 1);
state_init(
&runtime->state,
desc->outputs,
desc->output_count,
desc->workspaces,
desc->workspace_count
);
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr;
desc->output_count = 0;
return true;
}
void runtime_init_desc_cleanup(runtime_init_desc_t *desc) {
if (!desc) return;
binding_table_destroy(desc->binding_table);
desc->binding_table = nullptr;
listeners_cleanup(&desc->listeners);
if (desc->backend) {
backend_destroy(desc->backend);
desc->backend = nullptr;
}
if (desc->layouts.slots || desc->layouts.slot_count ||
desc->layouts.slot_capacity) {
layout_registry_cleanup(&desc->layouts);
}
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr;
desc->output_count = 0;
if (desc->config_module_handle) dlclose(desc->config_module_handle);
desc->config_module_handle = nullptr;
}
void runtime_shutdown(runtime_t *runtime) {
runtime->running = false;
plan_cleanup(&runtime->plan);
command_buffer_cleanup(&runtime->command_buffer);
layout_registry_cleanup(&runtime->layouts);
rules_cleanup(&runtime->rules);
state_cleanup(&runtime->state);
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 =
binding_table_get_current_bindings(runtime->binding_table, &bind_count);
if (!bindings) return;
auto backend = runtime->backend;
auto plan = &runtime->plan;
plan_reset(plan);
auto keys = p_new(key_bind_t, bind_count);
for (size_t i = 0; i < bind_count; ++i) {
keys[i].keysym = bindings[i].keysym;
keys[i].modifiers = bindings[i].modifiers;
}
effect_t effect_bind_key = {
.type = ZDWM_EFFECT_BIND_KEY,
.as.bind_key = {.count = bind_count, .keys = keys},
};
plan_push_effect(plan, &effect_bind_key);
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) {
auto result = &runtime->layout_result;
zdwm_layout_result_reset(result);
auto state = &runtime->state;
for (size_t i = 0; i < state->output_count; ++i) {
auto output = state_output_at(state, i);
if (!output) continue;
auto workspace = state_workspace_get(state, output->current_workspace_id);
if (!workspace) continue;
auto layout_slot = layout_slot_get(&runtime->layouts, workspace->layout_id);
if (!layout_slot || !layout_slot->fn) continue;
size_t window_count = 0;
size_t window_list_capacity = 0;
window_id_t *window_ids = nullptr;
for (size_t j = 0; j < state_window_count(state); j++) {
auto window = state_window_at(state, j);
if (!window || window->workspace_id != workspace->id) continue;
if (window_need_layout(window)) {
window_id_t *window_id_slot =
array_push(window_ids, window_count, window_list_capacity);
*window_id_slot = window->id;
} else if (window->fullscreen) {
layout_item_t item = {
.window_id = window->id,
.rect = output->geometry,
};
layout_result_push(result, item);
} else if (window->maximized) {
layout_item_t item = {
.window_id = window->id,
.rect = output->workarea,
};
layout_result_push(result, item);
}
}
if (window_count) {
zdwm_layout_ctx_t ctx = {
.workspace_id = workspace->id,
.focused_window_id = workspace->focused_window_id,
.output_geometry = output->geometry,
.workarea = output->workarea,
.window_ids = window_ids,
.window_count = window_count,
};
layout_slot->fn(&ctx, result);
}
if (window_ids) p_delete(&window_ids);
}
return result->item_count ? result : nullptr;
}
static void runtime_apply_window_rect(
state_t *state,
window_id_t window_id,
rect_t rect,
plan_t *plan
) {
auto window = state_window_get(state, window_id);
if (!window) return;
auto need_move = window_need_move(window, rect.x, rect.y);
auto need_resize = window_need_resize(window, rect.width, rect.height);
uint32_t changed_fields = 0u;
if (need_move) {
changed_fields |= ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y;
}
if (need_resize) {
changed_fields |= ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT;
changed_fields |= ZDWM_CONFIGURE_FIELD_BORDER_WIDTH;
}
effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = {
.window = window_id,
.x = rect.x,
.y = rect.y,
.width = rect.width - 2 * (int32_t)window->border_width,
.height = rect.height - 2 * (int32_t)window->border_width,
.border_width = window->border_width,
.changed_fields = changed_fields,
}
};
plan_push_effect(plan, &configure_effect);
if (need_move || need_resize) {
state_window_set_frame_rect(state, window_id, rect);
}
}
static void runtime_arrange(runtime_t *runtime) {
auto result = runtime_layout_calc(runtime);
if (!result) return;
auto state = &runtime->state;
auto plan = &runtime->plan;
for (size_t i = 0; i < result->item_count; ++i) {
auto item = &result->items[i];
runtime_apply_window_rect(state, item->window_id, item->rect, plan);
}
}
static policy_context_t policy_context_init(runtime_t *runtime) {
policy_context_t ctx = {
.bind_table = (runtime)->binding_table,
.state = &(runtime)->state,
.rules = &(runtime)->rules,
.listeners = &runtime->listeners,
.border = &(runtime)->border,
.layouts = &(runtime)->layouts,
};
return ctx;
}
void runtime_scan(runtime_t *runtime) {
auto result = backend_scan_windows(runtime->backend);
if (!result) return;
policy_context_t ctx = policy_context_init(runtime);
ctx.listeners = nullptr;
auto backend = runtime->backend;
auto command_buffer = &runtime->command_buffer;
auto plan = &runtime->plan;
command_buffer_reset(command_buffer);
plan_reset(plan);
for (size_t i = 0; i < result->count; i++) {
event_t event = {
.type = ZDWM_EVENT_WINDOW_MAP_REQUEST,
.as.window_map_request = result->windows[i],
};
policy_route_event(&ctx, &event, command_buffer);
}
policy_apply_command(&ctx, command_buffer, plan);
if (plan->need_relayout) runtime_arrange(runtime);
if (plan->count) backend_apply_effect(backend, plan->effects, plan->count);
backend_scan_result_destroy(result);
result = nullptr;
listeners_notify_initial_windows(&runtime->listeners, &runtime->state);
}
void runtime_run(runtime_t *runtime) {
runtime->running = true;
backend_t *backend = runtime->backend;
command_buffer_t *command_buffer = &runtime->command_buffer;
plan_t *plan = &runtime->plan;
policy_context_t ctx = policy_context_init(runtime);
while (runtime->running) {
event_t event = {0};
if (!backend_next_event(backend, &event)) break;
command_buffer_reset(command_buffer);
plan_reset(plan);
policy_route_event(&ctx, &event, command_buffer);
policy_apply_command(&ctx, command_buffer, plan);
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);
}
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "core/backend.h"
#include "core/binding.h"
#include "core/command_buffer.h"
#include "core/layout.h"
#include "core/listeners.h"
#include "core/plan.h"
#include "core/rules.h"
#include "core/state.h"
#include "core/types.h"
typedef struct runtime_init_desc_t {
backend_t *backend;
output_info_t *outputs;
size_t output_count;
layout_registry_t layouts;
rules_t rules;
border_config_t border;
workspace_desc_t *workspaces;
size_t workspace_count;
void *config_module_handle;
binding_table_t *binding_table;
listeners_t listeners;
} runtime_init_desc_t;
typedef struct runtime_t {
bool running;
bool will_restart;
plan_t plan;
command_buffer_t command_buffer;
state_t state;
layout_result_t layout_result;
layout_registry_t layouts;
rules_t rules;
border_config_t border;
backend_t *backend;
void *config_module_handle;
binding_table_t *binding_table;
listeners_t listeners;
} runtime_t;
bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc);
void runtime_init_desc_cleanup(runtime_init_desc_t *desc);
void runtime_shutdown(runtime_t *runtime);
void runtime_setup(runtime_t *runtime);
void runtime_scan(runtime_t *runtime);
void runtime_run(runtime_t *runtime);