From 3884d3fc50ec3dd1f81f445773d22de74f68c4dc Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Thu, 9 Apr 2026 02:23:06 +0800 Subject: [PATCH] =?UTF-8?q?backend:=20X11=20=E5=90=8E=E7=AB=AF=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=AA=97=E5=8F=A3=E5=87=A0=E4=BD=95=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=B9=B6=E4=BF=AE=E6=AD=A3=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E8=AF=AD=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 window_get_geometry/window_get_fixed_size/window_get_geometry_mode - window_get_atom_array 改为 bool 返回,区分 XCB 调用错误和空数据 - window_get_types/window_get_states 属性为空时返回 true 而非 false - handle_map_request 重排操作顺序:错误检查提前,失败路径无内存泄漏 - 补充 _NET_WM_STATE_MAXIMIZED_VERT/HORZ atom 注册 --- src/backend/x11/backend.c | 4 ++ src/backend/x11/event.c | 49 ++++++++++++---- src/backend/x11/internal.h | 2 + src/backend/x11/window.c | 112 ++++++++++++++++++++++++++++++------- src/backend/x11/window.h | 4 ++ src/core/event.h | 2 +- 6 files changed, 141 insertions(+), 32 deletions(-) diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index 626bb83..a51514b 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -47,6 +47,10 @@ static void atoms_init(backend_t *backend) { &atoms->_NET_WM_STATE_MODAL}, {"_NET_WM_STATE_SKIP_TASKBAR", sizeof("_NET_WM_STATE_SKIP_TASKBAR") - 1, &atoms->_NET_WM_STATE_SKIP_TASKBAR}, + {"_NET_WM_STATE_MAXIMIZED_VERT", sizeof("_NET_WM_STATE_MAXIMIZED_VERT") - 1, + &atoms->_NET_WM_STATE_MAXIMIZED_VERT}, + {"_NET_WM_STATE_MAXIMIZED_HORZ", sizeof("_NET_WM_STATE_MAXIMIZED_HORZ") - 1, + &atoms->_NET_WM_STATE_MAXIMIZED_HORZ}, {"_NET_WM_WINDOW_TYPE", sizeof("_NET_WM_WINDOW_TYPE") - 1, &atoms->_NET_WM_WINDOW_TYPE}, diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index 09e75d8..8d77c3b 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -8,33 +8,58 @@ #include "backend/x11/window.h" #include "base/memory.h" #include "core/backend.h" +#include "core/types.h" #include "core/window.h" #include "internal.h" /* IWYU pragma: keep */ +static void map_request_cleanup(event_t *event) { + window_metadata_t *metadata = &event->data.window_map_request.metadata; + window_props_t *props = &event->data.window_map_request.props; + p_delete(&metadata->role); + p_delete(&metadata->title); + p_delete(&metadata->class_name); + p_delete(&metadata->instance_name); + p_delete(&props->types); + p_delete(&props->states); +} + static bool handle_map_request(backend_t *backend, event_t *event, const xcb_map_request_event_t *xcb_event) { p_clear(event, 1); xcb_window_t window = xcb_event->window; event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST; - event->data.window_map_request.window = window; + event->data.window_map_request.window = (window_id_t)window; window_metadata_t *metadata = &event->data.window_map_request.metadata; + window_props_t *props = &event->data.window_map_request.props; + window_geometry_t *geometry = &event->data.window_map_request.geometry; + + { + xcb_get_window_attributes_reply_t *wa_reply = + window_get_attributes(backend, window); + if (!wa_reply) return false; + props->override_redirect = (bool)wa_reply->override_redirect; + p_delete(&wa_reply); + } + + if (!window_get_geometry(backend, window, &geometry->rect)) return false; + + props->transient_for = window_get_transient_for(backend, window); + props->skip_taskbar = window_get_skip_taskbar(backend, window); + props->urgent = window_get_urgency(backend, window); + geometry->mode = window_get_geometry_mode(backend, window); + geometry->fixed_size = window_get_fixed_size(backend, window); + metadata->role = window_get_role(backend, window); metadata->title = window_get_title(backend, window); window_get_class(backend, window, &metadata->class_name, &metadata->instance_name); - window_props_t *props = &event->data.window_map_request.props; - props->transient_for = window_get_transient_for(backend, window); - xcb_get_window_attributes_reply_t *wa_reply = - window_get_attributes(backend, window); - props->override_redirect = (bool)wa_reply->override_redirect; - p_delete(&wa_reply); - props->skip_taskbar = window_get_skip_taskbar(backend, window); - props->urgent = window_get_urgency(backend, window); - window_get_types(backend, window, &props->types, &props->type_count); - window_get_states(backend, window, &props->states, &props->state_count); - /* TODO: */ + if (!window_get_types(backend, window, &props->types, &props->type_count) || + !window_get_states(backend, window, &props->states, &props->state_count)) { + map_request_cleanup(event); + return false; + } return true; } diff --git a/src/backend/x11/internal.h b/src/backend/x11/internal.h index 30a7bdb..ea28101 100644 --- a/src/backend/x11/internal.h +++ b/src/backend/x11/internal.h @@ -17,6 +17,8 @@ typedef struct atoms_t { xcb_atom_t _NET_WM_STATE_STICKY; xcb_atom_t _NET_WM_STATE_MODAL; xcb_atom_t _NET_WM_STATE_SKIP_TASKBAR; + xcb_atom_t _NET_WM_STATE_MAXIMIZED_VERT; + xcb_atom_t _NET_WM_STATE_MAXIMIZED_HORZ; xcb_atom_t _NET_WM_WINDOW_TYPE; xcb_atom_t _NET_WM_WINDOW_TYPE_NORMAL; diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 487dc05..4ac75a7 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -113,25 +113,26 @@ bool window_get_urgency(backend_t *backend, xcb_window_t window) { return (bool)xcb_icccm_wm_hints_get_urgency(&hints); } -static xcb_atom_t *window_get_atom_array(backend_t *backend, - xcb_window_t window, - xcb_atom_t property, - uint32_t *out_len) { +static bool window_get_atom_array(backend_t *backend, xcb_window_t window, + xcb_atom_t property, xcb_atom_t **out_atoms, + uint32_t *out_len) { xcb_get_property_cookie_t cookie = xcb_get_property_unchecked( backend->conn, false, window, property, XCB_ATOM_ATOM, 0, UINT32_MAX); xcb_get_property_reply_t *reply = xcb_get_property_reply(backend->conn, cookie, nullptr); - if (!reply) return nullptr; + if (!reply) return false; - xcb_atom_t *result = nullptr; if (reply->type == XCB_ATOM_ATOM && reply->format == 32 && reply->value_len) { *out_len = reply->value_len; - result = + *out_atoms = p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len); + } else { + *out_len = 0; + *out_atoms = nullptr; } p_delete(&reply); - return result; + return true; } static window_type_t atom_to_window_type(const atoms_t *atoms, @@ -161,15 +162,17 @@ static window_type_t atom_to_window_type(const atoms_t *atoms, bool window_get_types(backend_t *backend, xcb_window_t window, window_type_t **types, size_t *count) { - if (!types || !count) return false; - uint32_t atom_count = 0; - xcb_atom_t *atoms = window_get_atom_array( - backend, window, backend->atoms._NET_WM_WINDOW_TYPE, &atom_count); + xcb_atom_t *atoms = nullptr; + if (!window_get_atom_array(backend, window, + backend->atoms._NET_WM_WINDOW_TYPE, &atoms, + &atom_count)) { + return false; + } if (!atoms) { *types = nullptr; *count = 0; - return false; + return true; } *count = atom_count; @@ -194,15 +197,16 @@ static window_state_t atom_to_window_state(const atoms_t *atoms, bool window_get_states(backend_t *backend, xcb_window_t window, window_state_t **states, size_t *count) { - if (!states || !count) return false; - uint32_t atom_count = 0; - xcb_atom_t *atoms = window_get_atom_array( - backend, window, backend->atoms._NET_WM_STATE, &atom_count); + xcb_atom_t *atoms = nullptr; + if (!window_get_atom_array(backend, window, backend->atoms._NET_WM_STATE, + &atoms, &atom_count)) { + return false; + } if (!atoms) { *states = nullptr; *count = 0; - return false; + return true; } /* 只保留已知 state,跳过未识别的 atom */ @@ -219,10 +223,80 @@ bool window_get_states(backend_t *backend, xcb_window_t window, p_delete(&buf); *states = nullptr; *count = 0; - return false; + return true; } *states = buf; *count = valid; return true; } + +bool window_get_fixed_size(backend_t *backend, xcb_window_t window) { + xcb_connection_t *conn = backend->conn; + xcb_size_hints_t hints; + xcb_get_property_cookie_t cookie = + xcb_icccm_get_wm_normal_hints_unchecked(conn, window); + if (!xcb_icccm_get_wm_normal_hints_reply(conn, cookie, &hints, nullptr)) { + return false; + } + + if ((hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) && + (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) { + return hints.min_width == hints.max_width && + hints.min_height == hints.max_height; + } + + return false; +} + +bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out) { + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(backend->conn, window); + xcb_get_geometry_reply_t *reply = + xcb_get_geometry_reply(backend->conn, cookie, nullptr); + if (!reply) return false; + + out->x = reply->x; + out->y = reply->y; + out->width = reply->width; + out->height = reply->height; + + p_delete(&reply); + return true; +} + +window_geometry_mode_t window_get_geometry_mode(backend_t *backend, + xcb_window_t window) { + xcb_connection_t *conn = backend->conn; + xcb_icccm_wm_hints_t hints; + xcb_get_property_cookie_t hints_cookie = + xcb_icccm_get_wm_hints_unchecked(conn, window); + if (xcb_icccm_get_wm_hints_reply(conn, hints_cookie, &hints, nullptr)) { + if (hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC) { + return ZDWM_GEOMETRY_MINIMIZED; + } + } + + uint32_t atom_count = 0; + xcb_atom_t *atoms = nullptr; + if (!window_get_atom_array(backend, window, backend->atoms._NET_WM_STATE, + &atoms, &atom_count)) { + return ZDWM_GEOMETRY_NORMAL; + } + + window_geometry_mode_t mode = ZDWM_GEOMETRY_NORMAL; + + for (uint32_t i = 0; i < atom_count; i++) { + if (atoms[i] == backend->atoms._NET_WM_STATE_FULLSCREEN) { + mode = ZDWM_GEOMETRY_FULLSCREEN; + break; + } + if (atoms[i] == backend->atoms._NET_WM_STATE_MAXIMIZED_VERT || + atoms[i] == backend->atoms._NET_WM_STATE_MAXIMIZED_HORZ) { + mode = ZDWM_GEOMETRY_MAXIMIZED; + break; + } + } + + p_delete(&atoms); + return mode; +} diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 3dc14f5..55a46c2 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -44,3 +44,7 @@ bool window_get_types(backend_t *backend, xcb_window_t window, window_type_t **types, size_t *count); bool window_get_states(backend_t *backend, xcb_window_t window, window_state_t **states, size_t *count); +bool window_get_fixed_size(backend_t *backend, xcb_window_t window); +bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out); +window_geometry_mode_t window_get_geometry_mode(backend_t *backend, + xcb_window_t window); diff --git a/src/core/event.h b/src/core/event.h index add909c..f232f8c 100644 --- a/src/core/event.h +++ b/src/core/event.h @@ -66,7 +66,7 @@ typedef struct window_map_request_event_t { window_id_t window; window_props_t props; window_metadata_t metadata; - window_geometry_mode_t geometry; + window_geometry_t geometry; } window_map_request_event_t; typedef enum window_remove_reason_t {