From 645d6594b835a45bea049d8fa23e6c983d831a4a Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Mon, 4 Aug 2025 14:28:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20ewmh=20=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 7 +++++++ src/app.h.in | 3 +++ src/xcb/CMakeLists.txt | 7 +++++-- src/xcb/window.c | 26 ++++++++++++++++++++++++++ src/xcb/window.h | 6 ++++++ src/xcb/xcb.c | 39 +++++++++++++++++++++++++++++++++++++-- 6 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/app.h.in create mode 100644 src/xcb/window.c create mode 100644 src/xcb/window.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2016942..d961439 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,3 +39,10 @@ target_include_directories(${APP_NAME} SYSTEM PUBLIC ${XCB_INCLUDE_DIRS}) add_subdirectory(xcb) target_link_libraries(${APP_NAME} ${LIB_XCB_NAME}) + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/app.h.in" + "${CMAKE_BINARY_DIR}/app.h" + @ONLY +) +target_include_directories(${APP_NAME} PRIVATE ${CMAKE_BINARY_DIR}) diff --git a/src/app.h.in b/src/app.h.in new file mode 100644 index 0000000..30f51d9 --- /dev/null +++ b/src/app.h.in @@ -0,0 +1,3 @@ +#pragma once + +#define APP_NAME "@APP_NAME@" diff --git a/src/xcb/CMakeLists.txt b/src/xcb/CMakeLists.txt index 44f591b..da83114 100644 --- a/src/xcb/CMakeLists.txt +++ b/src/xcb/CMakeLists.txt @@ -1,9 +1,12 @@ set(LIB_XCB "zswm-xcb") set(LIB_XCB_NAME ${LIB_XCB} PARENT_SCOPE) -add_library(${LIB_XCB} STATIC xcb.c) +add_library(${LIB_XCB} STATIC xcb.c window.c) target_include_directories(${LIB_XCB} SYSTEM PUBLIC ${XCB_INCLUDE_DIRS}) -target_include_directories(${LIB_XCB} PUBLIC "${CMAKE_SOURCE_DIR}/include") +target_include_directories(${LIB_XCB} PUBLIC + "${CMAKE_SOURCE_DIR}/include" + "${CMAKE_BINARY_DIR}" +) target_link_libraries(${LIB_XCB} ${XCB_LIBRARIES}) diff --git a/src/xcb/window.c b/src/xcb/window.c new file mode 100644 index 0000000..c3167df --- /dev/null +++ b/src/xcb/window.c @@ -0,0 +1,26 @@ +#include "window.h" + +#include +#include +#include + +#include "xcb-private.h" + +void set_window_class_instance(xcb_window_t window, const char *class, + const char *instance) { + size_t class_length = strlen(class) + 1; + size_t instance_length = strlen(instance) + 1; + size_t length = class_length + instance_length; + + char *str = malloc(length * sizeof(char)); + for (size_t i = 0; i < length; i++) { + if (i < class_length) { + str[i] = class[i]; + } else { + str[i] = instance[i - class_length]; + } + } + + xcb_icccm_set_wm_class(conn, window, length, str); + free(str); +} diff --git a/src/xcb/window.h b/src/xcb/window.h new file mode 100644 index 0000000..7bc0311 --- /dev/null +++ b/src/xcb/window.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void set_window_class_instance(xcb_window_t window, const char *class, + const char *instance); diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index 3504a7d..5cb01ee 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -10,9 +10,12 @@ #include #include #include +#include #include +#include "app.h" #include "utils.h" +#include "window.h" #include "xcb-private.h" xcb_connection_t *conn = NULL; @@ -122,18 +125,50 @@ monitor_rect_t *detect_monitor_rect(void) { } static xcb_ewmh_connection_t *ewmh = NULL; +static bool ewmh_init_failed = false; +static xcb_window_t wm_check_window = XCB_NONE; static void init_ewmh_extension(void) { - if (ewmh) return; + if (ewmh || ewmh_init_failed) 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; + ewmh_init_failed = true; return; } - screen = ewmh->screens[ewmh->nb_screens - 1]; + wm_check_window = xcb_generate_id(conn); + xcb_create_window(conn, XCB_COPY_FROM_PARENT, wm_check_window, screen->root, + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, + screen->root_visual, XCB_NONE, NULL); + const char *class = APP_NAME "_wm_check"; + set_window_class_instance(wm_check_window, class, class); + xcb_ewmh_set_wm_name(ewmh, wm_check_window, strlen(APP_NAME), APP_NAME); + xcb_ewmh_set_supporting_wm_check(ewmh, screen->root, wm_check_window); + xcb_ewmh_set_supporting_wm_check(ewmh, wm_check_window, wm_check_window); + + uint8_t mode = XCB_PROP_MODE_REPLACE; + uint8_t format = XCB_INPUT_PROPERTY_FORMAT_32_BITS; + xcb_atom_t atom = XCB_ATOM_ATOM; + const xcb_atom_t state[] = {ewmh->_NET_WM_STATE_STICKY}; + const xcb_atom_t supported[] = { + ewmh->_NET_ACTIVE_WINDOW, + ewmh->_NET_SUPPORTED, + ewmh->_NET_WM_NAME, + ewmh->_NET_WM_STATE, + ewmh->_NET_SUPPORTING_WM_CHECK, + ewmh->_NET_WM_STATE_FULLSCREEN, + ewmh->_NET_WM_WINDOW_TYPE, + ewmh->_NET_WM_WINDOW_TYPE_DIALOG, + ewmh->_NET_CLIENT_LIST, + }; + xcb_change_property(conn, mode, wm_check_window, ewmh->_NET_WM_STATE, atom, + format, LENGTH(state), state); + xcb_change_property(conn, mode, screen->root, ewmh->_NET_SUPPORTED, atom, + format, LENGTH(supported), supported); + xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST); } /**