From e22265937e48eb1a79b54bccf992d172910a3f58 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Mon, 4 Aug 2025 01:44:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=AB=E6=8F=8F=E7=AA=97=E5=8F=A3=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=99=A8=E5=90=AF=E5=8A=A8=E6=97=B6=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=9A=84=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 1 + src/include/xcb.h | 12 +++++- src/main.c | 11 ++++++ src/xcb/xcb-private.h | 1 + src/xcb/xcb.c | 86 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 674e660..2016942 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(XCB REQUIRED xcb xcb-cursor + xcb-ewmh xcb-icccm xcb-keysyms xcb-util diff --git a/src/include/xcb.h b/src/include/xcb.h index 24c557a..899ff79 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -2,6 +2,9 @@ #include #include +#include + +bool has_other_wm_running(void); typedef struct monitor_rect_t monitor_rect_t; struct monitor_rect_t { @@ -11,6 +14,11 @@ struct monitor_rect_t { uint32_t height; monitor_rect_t *next; }; - -bool has_other_wm_running(void); monitor_rect_t *detect_monitor_rect(void); + +typedef struct window_list_t { + uint32_t count; + xcb_window_t *list; +} window_list_t; +window_list_t *scan_window_list(void); +void free_window_list(window_list_t *window_list); diff --git a/src/main.c b/src/main.c index ec11bc4..aaae239 100644 --- a/src/main.c +++ b/src/main.c @@ -21,5 +21,16 @@ int main(int argc, char *argv[]) { } } + window_list_t *window_list = scan_window_list(); + if (window_list) { + for (uint32_t i = 0; i < window_list->count; i++) { + printf("window[%u]: 0x%x\n", i, window_list->list[i]); + } + } else { + printf("no window\n"); + } + + free_window_list(window_list); + return 0; } diff --git a/src/xcb/xcb-private.h b/src/xcb/xcb-private.h index 4abe490..e8e58f7 100644 --- a/src/xcb/xcb-private.h +++ b/src/xcb/xcb-private.h @@ -3,3 +3,4 @@ #include extern xcb_connection_t *conn; +extern xcb_screen_t *screen; diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index 04c3bb5..b6a26b5 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -1,13 +1,19 @@ #include "xcb.h" +#include +#include #include #include +#include +#include #include +#include #include "utils.h" #include "xcb-private.h" xcb_connection_t *conn = NULL; +xcb_screen_t *screen = NULL; bool has_other_wm_running(void) { conn = xcb_connect(NULL, NULL); @@ -17,7 +23,7 @@ bool has_other_wm_running(void) { const xcb_setup_t *setup = xcb_get_setup(conn); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); - xcb_screen_t *screen = iter.data; + screen = iter.data; uint32_t mask = XCB_CW_EVENT_MASK; xcb_params_cw_t params = { .event_mask = XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW | @@ -36,6 +42,14 @@ bool has_other_wm_running(void) { return false; } +/** + * 使用 xinerama 扩展探测每个屏幕的配置信息 + * + * @TODO: 后续考虑兼容无 xinerama 扩展或扩展未启用的情况 + * 当前仅需函数在自己环境下能正常工作即可,先不考虑其他环境 + * + * @note: 返回值使用完后记得释放其内存 + */ monitor_rect_t *detect_monitor_rect(void) { monitor_rect_t *list, *prev; xcb_xinerama_query_screens_cookie_t cookie = xcb_xinerama_query_screens(conn); @@ -68,3 +82,73 @@ monitor_rect_t *detect_monitor_rect(void) { return list; } + +static xcb_ewmh_connection_t *ewmh = NULL; +static void init_ewmh_extension(void) { + if (ewmh) return; + + ewmh = ecalloc(1, sizeof(xcb_ewmh_connection_t)); + xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(conn, ewmh); + if (!xcb_ewmh_init_atoms_replies(ewmh, cookie, NULL)) { + free(ewmh); + ewmh = NULL; + return; + } + + screen = ewmh->screens[ewmh->nb_screens - 1]; +} + +/** + * 扫描窗口列表 + * @returns 若无窗口,返回 NULL,否则返回窗口列表 + * @note: 返回的窗口列表数据使用完后使用 free_window_list 释放 + */ +window_list_t *scan_window_list(void) { + init_ewmh_extension(); + + xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, screen->root); + xcb_query_tree_reply_t *reply = xcb_query_tree_reply(conn, cookie, NULL); + xcb_window_t *list = xcb_query_tree_children(reply); + int len = xcb_query_tree_children_length(reply); + + uint32_t count = 0; + xcb_window_t temp_windoow_array[len]; + for (int i = 0; i < len; i++) { + xcb_window_t window = list[i]; + + xcb_get_window_attributes_cookie_t wa_cookie = + xcb_get_window_attributes(conn, window); + xcb_get_window_attributes_reply_t *reply = + xcb_get_window_attributes_reply(conn, wa_cookie, NULL); + uint8_t override_redirect = reply->override_redirect; + uint8_t map_state = reply->map_state; + free(reply); + if (override_redirect || map_state != XCB_MAP_STATE_VIEWABLE) continue; + + xcb_window_t transient_for = XCB_NONE; + xcb_get_property_cookie_t p_cookie = + xcb_icccm_get_wm_transient_for(conn, window); + xcb_icccm_get_wm_transient_for_reply(conn, p_cookie, &transient_for, NULL); + if (transient_for != XCB_NONE) continue; + + temp_windoow_array[count] = window; + count++; + } + + if (!count) return NULL; + + xcb_window_t *window_list = ecalloc(count, sizeof(xcb_window_t)); + for (uint32_t i = 0; i < count; i++) window_list[i] = temp_windoow_array[i]; + + window_list_t *r = ecalloc(1, sizeof(window_list_t)); + r->count = count; + r->list = window_list; + + return r; +} + +void free_window_list(window_list_t *window_list) { + if (window_list == NULL) return; + free(window_list->list); + free(window_list); +}