refactor(runtime): 将 runtime 模块从 core 目录迁移至独立的 runtime 目录并封装内部细节
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user