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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user