检测显示器信息

This commit is contained in:
2025-08-03 01:25:14 +08:00
parent 82456e77c9
commit 80f909ce22
8 changed files with 186 additions and 2 deletions

View File

@@ -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})

8
src/include/utils.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <stddef.h>
#define LENGTH(X) (sizeof(X) / sizeof(X)[0])
void die(const char *format, ...);
void *ecalloc(size_t number_of_member, size_t member_size);

16
src/include/xcb.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
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);

View File

@@ -1 +1,25 @@
int main(int argc, char *argv[]) { return 0; }
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

32
src/utils.c Normal file
View File

@@ -0,0 +1,32 @@
#include "utils.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}

9
src/xcb/CMakeLists.txt Normal file
View File

@@ -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})

5
src/xcb/xcb-private.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <xcb/xcb.h>
extern xcb_connection_t *conn;

70
src/xcb/xcb.c Normal file
View File

@@ -0,0 +1,70 @@
#include "xcb.h"
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xinerama.h>
#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, &params);
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;
}