Compare commits
2 Commits
e22265937e
...
645d6594b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
645d6594b8
|
|||
|
801124a8a2
|
@@ -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})
|
||||
|
||||
3
src/app.h.in
Normal file
3
src/app.h.in
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define APP_NAME "@APP_NAME@"
|
||||
@@ -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})
|
||||
|
||||
26
src/xcb/window.c
Normal file
26
src/xcb/window.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "window.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
6
src/xcb/window.h
Normal file
6
src/xcb/window.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
void set_window_class_instance(xcb_window_t window, const char *class,
|
||||
const char *instance);
|
||||
@@ -1,15 +1,21 @@
|
||||
#include "xcb.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/xcb_ewmh.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <xcb/xinerama.h>
|
||||
#include <xcb/xinput.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "utils.h"
|
||||
#include "window.h"
|
||||
#include "xcb-private.h"
|
||||
|
||||
xcb_connection_t *conn = NULL;
|
||||
@@ -24,6 +30,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);
|
||||
screen = iter.data;
|
||||
printf("screen number: %d\n", iter.rem);
|
||||
uint32_t mask = XCB_CW_EVENT_MASK;
|
||||
xcb_params_cw_t params = {
|
||||
.event_mask = XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW |
|
||||
@@ -42,15 +49,30 @@ bool has_other_wm_running(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 xinerama 扩展探测每个屏幕的配置信息
|
||||
*
|
||||
* @TODO: 后续考虑兼容无 xinerama 扩展或扩展未启用的情况
|
||||
* 当前仅需函数在自己环境下能正常工作即可,先不考虑其他环境
|
||||
*
|
||||
* @note: 返回值使用完后记得释放其内存
|
||||
*/
|
||||
monitor_rect_t *detect_monitor_rect(void) {
|
||||
/* xinerama 扩展是否激活 */
|
||||
static bool xinerama_active(void) {
|
||||
const char *name = "XINERAMA";
|
||||
xcb_query_extension_cookie_t xinerama_cookie =
|
||||
xcb_query_extension(conn, strlen(name), name);
|
||||
xcb_query_extension_reply_t *xinerama_reply =
|
||||
xcb_query_extension_reply(conn, xinerama_cookie, NULL);
|
||||
|
||||
/* 扩展不存在 */
|
||||
if (!xinerama_reply || !xinerama_reply->present) {
|
||||
free(xinerama_reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
xcb_xinerama_is_active_cookie_t active_cookie = xcb_xinerama_is_active(conn);
|
||||
xcb_xinerama_is_active_reply_t *active_reply =
|
||||
xcb_xinerama_is_active_reply(conn, active_cookie, NULL);
|
||||
bool active = active_reply && active_reply->state;
|
||||
free(xinerama_reply);
|
||||
free(active_reply);
|
||||
return active;
|
||||
}
|
||||
|
||||
static monitor_rect_t *detect_monitor_rect_by_xinerama(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 =
|
||||
@@ -83,19 +105,70 @@ monitor_rect_t *detect_monitor_rect(void) {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 探测屏幕信息
|
||||
* @note: 返回值使用完后记得释放其内存
|
||||
*/
|
||||
monitor_rect_t *detect_monitor_rect(void) {
|
||||
if (xinerama_active()) {
|
||||
return detect_monitor_rect_by_xinerama();
|
||||
}
|
||||
|
||||
if (!screen) return NULL;
|
||||
|
||||
monitor_rect_t *rect = ecalloc(1, sizeof(monitor_rect_t));
|
||||
rect->x = 0;
|
||||
rect->y = 0;
|
||||
rect->width = screen->width_in_pixels;
|
||||
rect->height = screen->height_in_pixels;
|
||||
return rect;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user