From 80f909ce22cebbca6994d13e524b138fd0478f6b Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Sun, 3 Aug 2025 01:25:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A3=80=E6=B5=8B=E6=98=BE=E7=A4=BA=E5=99=A8?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 22 ++++++++++++- src/include/utils.h | 8 +++++ src/include/xcb.h | 16 ++++++++++ src/main.c | 26 +++++++++++++++- src/utils.c | 32 +++++++++++++++++++ src/xcb/CMakeLists.txt | 9 ++++++ src/xcb/xcb-private.h | 5 +++ src/xcb/xcb.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/include/utils.h create mode 100644 src/include/xcb.h create mode 100644 src/utils.c create mode 100644 src/xcb/CMakeLists.txt create mode 100644 src/xcb/xcb-private.h create mode 100644 src/xcb/xcb.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 091ab8b..674e660 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.24) set(APP_NAME "zswm") +set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # generate compile_commands.json for clangd set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -14,7 +15,26 @@ project(${APP_NAME} LANGUAGES C ) -add_executable(${APP_NAME} main.c) +add_executable(${APP_NAME} main.c utils.c) # use C17 set_property(TARGET ${APP_NAME} PROPERTY C_STANDARD 17) + +target_include_directories(${APP_NAME} PRIVATE "${SOURCE_DIR}/include") + +find_package(PkgConfig REQUIRED) + +pkg_check_modules(XCB REQUIRED + xcb + xcb-cursor + xcb-icccm + xcb-keysyms + xcb-util + xcb-xfixes + xcb-xinerama + xcb-xrm +) +target_include_directories(${APP_NAME} SYSTEM PUBLIC ${XCB_INCLUDE_DIRS}) + +add_subdirectory(xcb) +target_link_libraries(${APP_NAME} ${LIB_XCB_NAME}) diff --git a/src/include/utils.h b/src/include/utils.h new file mode 100644 index 0000000..ed860bf --- /dev/null +++ b/src/include/utils.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#define LENGTH(X) (sizeof(X) / sizeof(X)[0]) + +void die(const char *format, ...); +void *ecalloc(size_t number_of_member, size_t member_size); diff --git a/src/include/xcb.h b/src/include/xcb.h new file mode 100644 index 0000000..24c557a --- /dev/null +++ b/src/include/xcb.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +typedef struct monitor_rect_t monitor_rect_t; +struct monitor_rect_t { + int32_t x; + int32_t y; + uint32_t width; + uint32_t height; + monitor_rect_t *next; +}; + +bool has_other_wm_running(void); +monitor_rect_t *detect_monitor_rect(void); diff --git a/src/main.c b/src/main.c index 44e82e2..ec11bc4 100644 --- a/src/main.c +++ b/src/main.c @@ -1 +1,25 @@ -int main(int argc, char *argv[]) { return 0; } +#include +#include +#include + +#include "utils.h" +#include "xcb.h" + +int main(int argc, char *argv[]) { + if (has_other_wm_running()) { + die("another window manager is already running"); + } + + { + monitor_rect_t *mr = detect_monitor_rect(); + uint32_t i = 0; + while (mr) { + printf("mon[%u]: x: %d, y: %d, w: %u, h: %u\n", i, mr->x, mr->y, + mr->width, mr->height); + mr = mr->next; + free(mr); + } + } + + return 0; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..7755a07 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,32 @@ +#include "utils.h" + +#include +#include +#include +#include + +void die(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} + +void *ecalloc(size_t number_of_member, size_t member_size) { + void *p; + + if (!(p = calloc(number_of_member, member_size))) { + die("calloc:"); + } + + return p; +} diff --git a/src/xcb/CMakeLists.txt b/src/xcb/CMakeLists.txt new file mode 100644 index 0000000..44f591b --- /dev/null +++ b/src/xcb/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LIB_XCB "zswm-xcb") +set(LIB_XCB_NAME ${LIB_XCB} PARENT_SCOPE) + +add_library(${LIB_XCB} STATIC xcb.c) + +target_include_directories(${LIB_XCB} SYSTEM PUBLIC ${XCB_INCLUDE_DIRS}) +target_include_directories(${LIB_XCB} PUBLIC "${CMAKE_SOURCE_DIR}/include") + +target_link_libraries(${LIB_XCB} ${XCB_LIBRARIES}) diff --git a/src/xcb/xcb-private.h b/src/xcb/xcb-private.h new file mode 100644 index 0000000..4abe490 --- /dev/null +++ b/src/xcb/xcb-private.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern xcb_connection_t *conn; diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c new file mode 100644 index 0000000..04c3bb5 --- /dev/null +++ b/src/xcb/xcb.c @@ -0,0 +1,70 @@ +#include "xcb.h" + +#include +#include +#include + +#include "utils.h" +#include "xcb-private.h" + +xcb_connection_t *conn = NULL; + +bool has_other_wm_running(void) { + conn = xcb_connect(NULL, NULL); + if (!conn || xcb_connection_has_error(conn)) { + die("connection:"); + } + + 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; + uint32_t mask = XCB_CW_EVENT_MASK; + xcb_params_cw_t params = { + .event_mask = XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, + }; + xcb_void_cookie_t cookie = + xcb_aux_change_window_attributes(conn, screen->root, mask, ¶ms); + xcb_generic_error_t *error = xcb_request_check(conn, cookie); + if (error) { + xcb_disconnect(conn); + return true; + } + + return false; +} + +monitor_rect_t *detect_monitor_rect(void) { + monitor_rect_t *list, *prev; + xcb_xinerama_query_screens_cookie_t cookie = xcb_xinerama_query_screens(conn); + xcb_xinerama_query_screens_reply_t *reply = + xcb_xinerama_query_screens_reply(conn, cookie, NULL); + xcb_xinerama_screen_info_t *screen_info = + xcb_xinerama_query_screens_screen_info(reply); + + if (screen_info == NULL) { + die("no monitor finded"); + } + + int count = xcb_xinerama_query_screens_screen_info_length(reply); + for (int i = 0; i < count; i++) { + monitor_rect_t *m = ecalloc(1, sizeof(monitor_rect_t)); + xcb_xinerama_screen_info_t info = screen_info[i]; + m->x = info.x_org; + m->y = info.y_org; + m->width = info.width; + m->height = info.height; + m->next = NULL; + + if (i == 0) { + list = m; + } else { + prev->next = m; + } + prev = m; + } + + return list; +}