diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index 8d77c3b..ddc2dd2 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "backend/x11/window.h" @@ -12,55 +13,113 @@ #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 window_state_t *derive_window_states(const atoms_t *atoms, + const xcb_atom_t *raw, + uint32_t count, size_t *out_count) { + if (!raw || count == 0) { + *out_count = 0; + return nullptr; + } + window_state_t *buf = p_new(window_state_t, count); + size_t valid = 0; + for (uint32_t i = 0; i < count; i++) { + window_state_t s = atom_to_window_state(atoms, raw[i]); + if (s != (window_state_t)-1) buf[valid++] = s; + } + if (valid == 0) { + p_delete(&buf); + *out_count = 0; + return nullptr; + } + *out_count = valid; + return buf; +} + +static bool derive_skip_taskbar(const atoms_t *atoms, const xcb_atom_t *raw, + uint32_t count) { + for (uint32_t i = 0; i < count; i++) + if (raw[i] == atoms->_NET_WM_STATE_SKIP_TASKBAR) return true; + return false; +} + +static window_geometry_mode_t geometry_mode_from_hints( + const xcb_icccm_wm_hints_t *hints) { + if (hints->initial_state == XCB_ICCCM_WM_STATE_ICONIC) + return ZDWM_GEOMETRY_MINIMIZED; + return ZDWM_GEOMETRY_NORMAL; +} + +static window_geometry_mode_t geometry_mode_from_states( + const atoms_t *atoms, const xcb_atom_t *state_atoms, uint32_t state_count) { + for (uint32_t i = 0; i < state_count; i++) { + if (state_atoms[i] == atoms->_NET_WM_STATE_FULLSCREEN) + return ZDWM_GEOMETRY_FULLSCREEN; + if (state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_VERT || + state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_HORZ) + return ZDWM_GEOMETRY_MAXIMIZED; + } + return ZDWM_GEOMETRY_NORMAL; } 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; + + p_clear(event, 1); event->type = ZDWM_EVENT_WINDOW_MAP_REQUEST; - 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; + window_map_request_event_t *ev = &event->data.window_map_request; + ev->window = (window_id_t)window; + ev->transient_for = window_get_transient_for(backend, window); + ev->geometry_mode = ZDWM_GEOMETRY_NORMAL; - { - 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); + xcb_get_window_attributes_reply_t *wa = + window_get_attributes(backend, window); + if (!wa) return false; + ev->override_redirect = (bool)wa->override_redirect; + p_delete(&wa); + + xcb_icccm_wm_hints_t wm_hints = {0}; + if (window_get_wm_hints(backend, window, &wm_hints)) { + ev->urgent = (bool)xcb_icccm_wm_hints_get_urgency(&wm_hints); + ev->geometry_mode = geometry_mode_from_hints(&wm_hints); } - if (!window_get_geometry(backend, window, &geometry->rect)) return false; + if (!window_get_fixed_size(backend, window, &ev->fixed_size)) return false; + if (!window_get_geometry(backend, window, &ev->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); - - 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); + const atoms_t *atoms = &backend->atoms; + xcb_atom_t *state_atoms = nullptr; + uint32_t state_count = 0; + if (!window_get_atom_array(backend, window, atoms->_NET_WM_STATE, + &state_atoms, &state_count)) { return false; } + if (ev->geometry_mode == ZDWM_GEOMETRY_NORMAL && state_atoms) { + ev->geometry_mode = + geometry_mode_from_states(atoms, state_atoms, state_count); + } + + if (state_atoms) { + ev->skip_taskbar = derive_skip_taskbar(atoms, state_atoms, state_count); + ev->props.states = derive_window_states(atoms, state_atoms, state_count, + &ev->props.state_count); + } + + p_delete(&state_atoms); + + window_layer_props_t *props = &ev->props; + if (!window_get_types(backend, window, &props->types, &props->type_count)) { + p_delete(&props->states); + return false; + } + + ev->metadata.role = window_get_role(backend, window); + ev->metadata.title = window_get_title(backend, window); + window_get_class(backend, window, &ev->metadata.class_name, + &ev->metadata.instance_name); + return true; } diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 4ac75a7..5494e1a 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -81,60 +81,6 @@ xcb_get_window_attributes_reply_t *window_get_attributes(backend_t *backend, return xcb_get_window_attributes_reply(backend->conn, cookie, nullptr); } -bool window_get_skip_taskbar(backend_t *backend, xcb_window_t window) { - xcb_get_property_cookie_t cookie = xcb_get_property_unchecked( - backend->conn, false, window, backend->atoms._NET_WM_STATE, XCB_ATOM_ATOM, - 0, UINT32_MAX); - xcb_get_property_reply_t *reply = - xcb_get_property_reply(backend->conn, cookie, nullptr); - if (!reply) return false; - - bool found = false; - if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { - xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); - uint32_t len = reply->value_len; - for (uint32_t i = 0; i < len; i++) { - if (atoms[i] == backend->atoms._NET_WM_STATE_SKIP_TASKBAR) { - found = true; - break; - } - } - } - - p_delete(&reply); - return found; -} - -bool window_get_urgency(backend_t *backend, xcb_window_t window) { - xcb_get_property_cookie_t cookie = - xcb_icccm_get_wm_hints_unchecked(backend->conn, window); - xcb_icccm_wm_hints_t hints; - xcb_icccm_get_wm_hints_reply(backend->conn, cookie, &hints, nullptr); - return (bool)xcb_icccm_wm_hints_get_urgency(&hints); -} - -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 false; - - if (reply->type == XCB_ATOM_ATOM && reply->format == 32 && reply->value_len) { - *out_len = reply->value_len; - *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 true; -} - static window_type_t atom_to_window_type(const atoms_t *atoms, xcb_atom_t atom) { if (atom == atoms->_NET_WM_WINDOW_TYPE_DESKTOP) @@ -185,55 +131,9 @@ bool window_get_types(backend_t *backend, xcb_window_t window, return true; } -static window_state_t atom_to_window_state(const atoms_t *atoms, - xcb_atom_t atom) { - if (atom == atoms->_NET_WM_STATE_FULLSCREEN) - return ZDWM_WINDOW_STATE_FULLSCREEN; - if (atom == atoms->_NET_WM_STATE_ABOVE) return ZDWM_WINDOW_STATE_ABOVE; - if (atom == atoms->_NET_WM_STATE_STICKY) return ZDWM_WINDOW_STATE_STICKY; - if (atom == atoms->_NET_WM_STATE_MODAL) return ZDWM_WINDOW_STATE_MODAL; - return (window_state_t)-1; -} - -bool window_get_states(backend_t *backend, xcb_window_t window, - window_state_t **states, size_t *count) { - 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 false; - } - if (!atoms) { - *states = nullptr; - *count = 0; - return true; - } - - /* 只保留已知 state,跳过未识别的 atom */ - window_state_t *buf = p_new(window_state_t, atom_count); - size_t valid = 0; - for (uint32_t i = 0; i < atom_count; i++) { - window_state_t s = atom_to_window_state(&backend->atoms, atoms[i]); - if (s != (window_state_t)-1) buf[valid++] = s; - } - - p_delete(&atoms); - - if (valid == 0) { - p_delete(&buf); - *states = nullptr; - *count = 0; - return true; - } - - *states = buf; - *count = valid; - return true; -} - -bool window_get_fixed_size(backend_t *backend, xcb_window_t window) { +bool window_get_fixed_size(backend_t *backend, xcb_window_t window, bool *out) { + xcb_size_hints_t hints = {0}; 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)) { @@ -242,11 +142,12 @@ bool window_get_fixed_size(backend_t *backend, xcb_window_t window) { 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 && + *out = hints.min_width == hints.max_width && hints.min_height == hints.max_height; + } else { + *out = false; } - - return false; + return true; } bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out) { @@ -264,39 +165,44 @@ bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out) { 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; - } +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 false; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32 && reply->value_len) { + *out_len = reply->value_len; + *out_atoms = + p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len); + } else { + *out_len = 0; + *out_atoms = nullptr; } - 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; + p_delete(&reply); + return true; +} - 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; - } +bool window_get_wm_hints(backend_t *backend, xcb_window_t window, + xcb_icccm_wm_hints_t *out) { + xcb_get_property_cookie_t cookie = + xcb_icccm_get_wm_hints_unchecked(backend->conn, window); + if (!xcb_icccm_get_wm_hints_reply(backend->conn, cookie, out, nullptr)) { + p_clear(out, 1); + return false; } + return true; +} - p_delete(&atoms); - return mode; +window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom) { + if (atom == atoms->_NET_WM_STATE_FULLSCREEN) + return ZDWM_WINDOW_STATE_FULLSCREEN; + if (atom == atoms->_NET_WM_STATE_ABOVE) return ZDWM_WINDOW_STATE_ABOVE; + if (atom == atoms->_NET_WM_STATE_STICKY) return ZDWM_WINDOW_STATE_STICKY; + if (atom == atoms->_NET_WM_STATE_MODAL) return ZDWM_WINDOW_STATE_MODAL; + return (window_state_t)-1; } diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index 55a46c2..1c9e8ec 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -1,11 +1,15 @@ #pragma once +#include #include +#include #include #include "core/backend.h" #include "core/window.h" +typedef struct atoms_t atoms_t; + /** * @brief 获取窗口的 role 属性 * @param backend 后端实例指针 @@ -33,18 +37,16 @@ char *window_get_title(backend_t *backend, xcb_window_t window); */ void window_get_class(backend_t *backend, xcb_window_t window, char **class_out, char **instance_out); - xcb_window_t window_get_transient_for(backend_t *backend, xcb_window_t window); - xcb_get_window_attributes_reply_t *window_get_attributes(backend_t *backend, xcb_window_t window); -bool window_get_skip_taskbar(backend_t *backend, xcb_window_t window); -bool window_get_urgency(backend_t *backend, xcb_window_t window); 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_fixed_size(backend_t *backend, xcb_window_t window, bool *out); 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); +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); +bool window_get_wm_hints(backend_t *backend, xcb_window_t window, + xcb_icccm_wm_hints_t *out); +window_state_t atom_to_window_state(const atoms_t *atoms, xcb_atom_t atom); diff --git a/src/core/event.h b/src/core/event.h index f232f8c..ae486f5 100644 --- a/src/core/event.h +++ b/src/core/event.h @@ -64,9 +64,16 @@ typedef struct pointer_enter_event_t { typedef struct window_map_request_event_t { window_id_t window; - window_props_t props; + window_id_t transient_for; + bool override_redirect; + bool skip_taskbar; + bool urgent; + bool fixed_size; + window_geometry_mode_t geometry_mode; + rect_t rect; + + window_layer_props_t props; window_metadata_t metadata; - window_geometry_t geometry; } window_map_request_event_t; typedef enum window_remove_reason_t { diff --git a/src/core/layer.c b/src/core/layer.c index f953bc4..230735a 100644 --- a/src/core/layer.c +++ b/src/core/layer.c @@ -88,7 +88,7 @@ bool layer_stack_lower(layer_stack_t *layer, window_id_t window) { return true; } -layer_type_t layer_classify(const window_props_t *props) { +layer_type_t layer_classify(const window_layer_props_t *props) { for (size_t i = 0; i < props->type_count; ++i) { window_type_t type = props->types[i]; if (type == ZDWM_WINDOW_TYPE_NOTIFICATION) return ZDWM_WINDOW_LAYER_OVERLAY; diff --git a/src/core/layer.h b/src/core/layer.h index 9a6fffe..220ec2b 100644 --- a/src/core/layer.h +++ b/src/core/layer.h @@ -57,4 +57,4 @@ bool layer_stack_raise(layer_stack_t *layer, window_id_t window); */ bool layer_stack_lower(layer_stack_t *layer, window_id_t window); -layer_type_t layer_classify(const window_props_t *props); +layer_type_t layer_classify(const window_layer_props_t *props); diff --git a/src/core/window.h b/src/core/window.h index 60e94b1..589524e 100644 --- a/src/core/window.h +++ b/src/core/window.h @@ -30,19 +30,13 @@ typedef enum window_state_t { ZDWM_WINDOW_STATE_STICKY, } window_state_t; -typedef struct window_props_t { - window_id_t transient_for; - - bool override_redirect; - bool skip_taskbar; - bool urgent; - +typedef struct window_layer_props_t { window_type_t *types; size_t type_count; window_state_t *states; size_t state_count; -} window_props_t; +} window_layer_props_t; typedef struct window_metadata_t { char *title; @@ -51,9 +45,3 @@ typedef struct window_metadata_t { char *class_name; char *instance_name; } window_metadata_t; - -typedef struct window_geometry_t { - window_geometry_mode_t mode; - rect_t rect; - bool fixed_size; -} window_geometry_t;