feat(runtime): 启动时扫描并接管已有窗口

从 handle_map_request 中提取 populate_window_event 供复用,
新增 backend_scan_windows 扫描 X11 根窗口子树,
runtime_scan 将扫描到的窗口走完整 policy 流程纳入管理。
route_map_request 增加 override_redirect 过滤。
This commit is contained in:
2026-05-07 06:36:58 +08:00
parent c1a4795a85
commit 9275d14c5f
7 changed files with 141 additions and 23 deletions

View File

@@ -22,8 +22,10 @@
#include "base/macros.h"
#include "base/memory.h"
#include "base/window_list.h"
#include "core/event.h"
#include "core/plan.h"
#include "core/types.h"
#include "core/window.h"
#include "internal.h"
typedef struct atom_item_t {
@@ -625,3 +627,54 @@ bool backend_apply_effect(
xcb_flush(backend->conn);
return true;
}
backend_scan_result_t *backend_scan_windows(backend_t *backend) {
auto conn = backend->conn;
auto root = backend->screen->root;
auto cookie = xcb_query_tree_unchecked(conn, root);
auto reply = xcb_query_tree_reply(conn, cookie, nullptr);
if (!reply) return nullptr;
auto length = xcb_query_tree_children_length(reply);
if (!length) {
p_delete(&reply);
return nullptr;
}
auto list = xcb_query_tree_children(reply);
backend_scan_result_t *result = p_new(backend_scan_result_t, 1);
for (int i = 0; i < length; i++) {
auto slot = (window_map_request_event_t *)
array_push(result->windows, result->count, result->capacity);
if (!populate_window_event(backend, list[i], slot)) {
window_layer_props_cleanup(&slot->props);
window_metadata_cleanup(&slot->metadata);
result->count--;
}
}
p_delete(&reply);
if (result->count == 0) {
backend_scan_result_destroy(result);
result = nullptr;
return nullptr;
}
return result;
}
void backend_scan_result_destroy(backend_scan_result_t *result) {
if (!result) return;
for (size_t i = 0; i < result->count; i++) {
window_map_request_event_t *ev = &result->windows[i];
window_layer_props_cleanup(&ev->props);
window_metadata_cleanup(&ev->metadata);
}
p_delete(&result->windows);
p_delete(&result);
}

View File

@@ -91,18 +91,13 @@ static bool urgent_from_states(
return false;
}
static bool handle_map_request(
bool populate_window_event(
backend_t *backend,
event_t *event,
const xcb_map_request_event_t *xcb_event
xcb_window_t window,
window_map_request_event_t *ev
) {
xcb_window_t window = xcb_event->window;
event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST;
window_map_request_event_t *ev = &event->as.window_map_request;
ev->window = (window_id_t)window;
ev->transient_for = window_get_transient_for(backend, window);
ev->window = (window_id_t)window;
ev->transient_for = window_get_transient_for(backend, window);
xcb_get_window_attributes_reply_t *wa =
window_get_attributes(backend, window);
@@ -167,6 +162,19 @@ static bool handle_map_request(
return true;
}
static bool handle_map_request(
backend_t *backend,
event_t *event,
const xcb_map_request_event_t *xcb_event
) {
event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST;
return populate_window_event(
backend,
xcb_event->window,
&event->as.window_map_request
);
}
static bool handle_unmap_notify(
backend_t *backend,
event_t *event,

View File

@@ -7,6 +7,7 @@
#include <xcb/xproto.h>
#include "base/window_list.h"
#include "core/event.h"
#define ATOM_LIST(X) \
X(COMPOUND_TEXT) \
@@ -94,3 +95,9 @@ struct backend_t {
window_list_t map;
window_list_t kill;
};
bool populate_window_event(
struct backend_t *backend,
xcb_window_t window,
window_map_request_event_t *ev
);

View File

@@ -37,3 +37,17 @@ bool backend_apply_effect(
const effect_t *effects,
size_t effect_count
);
typedef struct backend_scan_result_t {
window_map_request_event_t *windows;
size_t count;
size_t capacity;
} backend_scan_result_t;
/**
* @brief 扫描已有窗口
*
* @details 仅扫描窗口并获取其基础信息
*/
backend_scan_result_t *backend_scan_windows(backend_t *backend);
void backend_scan_result_destroy(backend_scan_result_t *result);

View File

@@ -53,6 +53,7 @@ static void route_map_request(
const window_map_request_event_t *e,
command_buffer_t *out
) {
if (e->override_redirect) return;
if (state_window_get(state, e->window)) return;
window_layer_type_t layer_type = window_classify_layer(&e->props);

View File

@@ -257,20 +257,14 @@ static void runtime_arrange(runtime_t *runtime) {
}
}
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 policy_context_init(runtime_t *runtime) {
policy_context_t ctx = {
.bind_table = runtime->binding_table,
.state = &runtime->state,
.rules = &runtime->rules,
.border = &runtime->border,
.layouts = &runtime->layouts,
.runtime = runtime,
.bind_table = (runtime)->binding_table,
.state = &(runtime)->state,
.rules = &(runtime)->rules,
.border = &(runtime)->border,
.layouts = &(runtime)->layouts,
.runtime = (runtime),
.action_api = {
.spawn = spawn,
.quit = quit,
@@ -284,6 +278,46 @@ void runtime_run(runtime_t *runtime) {
.cycle_current_output = cycle_current_output,
},
};
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);
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;
}
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};

View File

@@ -46,4 +46,5 @@ 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);