diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6066212..75f37f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.24) set(APP_NAME "zswm") set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +add_compile_definitions(LOG_FILE="$ENV{HOME}/zswm-log.txt") +# add_compile_definitions(RELEASE) + # generate compile_commands.json for clangd set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/src/include/event-adapter.h b/src/include/event-adapter.h index 137a37f..d76b33e 100644 --- a/src/include/event-adapter.h +++ b/src/include/event-adapter.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "types.h" @@ -21,6 +22,24 @@ typedef enum event_type_t { EVENT_TYPE_CLIENT_MESSAGE, } event_type_t; +typedef enum notify_mode_t { + notify_mode_normal = 0, + notify_mode_grab = 1, + notify_mode_ungrab = 2, + notify_mode_while_grabbed = 3 +} notify_mode_t; + +typedef enum notify_detail_t { + notify_detail_ancestor = 0, + notify_detail_virtual = 1, + notify_detail_inferior = 2, + notify_detail_nonlinear = 3, + notify_detail_nonlinear_virtual = 4, + notify_detail_pointer = 5, + notify_detail_pointer_root = 6, + notify_detail_none = 7, +} notify_detail_t; + typedef struct mapping_notify_event_t { event_type_t type; } mapping_notify_event_t; @@ -81,10 +100,14 @@ typedef struct motion_notify_event_t { typedef struct enter_notify_event_t { event_type_t type; + xcb_window_t window; + notify_mode_t mode; + notify_detail_t detail; } enter_notify_event_t; typedef struct focus_in_event_t { event_type_t type; + xcb_window_t window; } focus_in_event_t; typedef struct property_notify_event_t { diff --git a/src/include/utils.h b/src/include/utils.h index ca0e84e..b9bb90d 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "types.h" @@ -18,6 +19,14 @@ void *ecalloc(size_t number_of_member, size_t member_size); bool file_exist(const char *path); +#if defined(RELEASE) +#define logger(fmt, ...) +#elif defined(LOG_FILE) +void logger(const char *fmt, ...); +#else +#define logger(fmt, ...) printf(fmt, ##__VA_ARGS__) +#endif + /** * @brief 将 16 进制的颜色配置转换成 uint32 格式的 rgba数据 * diff --git a/src/include/xcb.h b/src/include/xcb.h index d2a9b16..7c76e5c 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -48,6 +48,7 @@ void map_window(xcb_window_t window); char *get_window_name(xcb_window_t window); void init_window_event_mask(xcb_window_t window); void change_window_border_color(xcb_window_t window, uint32_t argb); +void focus_window(xcb_window_t window); typedef struct bar_cairo_params_t { xcb_connection_t *conn; @@ -95,3 +96,12 @@ void grab_keybindings(const keybinding_t *keys, const size_t length); bool get_xresource_uint32(const char *name, uint32_t *value); void get_xresource_string(const char *name, char **value, const char *fallback); void clean_xresource(void); + +typedef enum atom_t { + atom_wm_protocols, + atom_wm_delete, + atom_wm_take_focus, +} atom_t; +bool send_event(xcb_window_t window, atom_t atom); + +bool get_pointer_position(int32_t *x, int32_t *y); diff --git a/src/main.c b/src/main.c index dc7313f..49e9906 100644 --- a/src/main.c +++ b/src/main.c @@ -40,6 +40,8 @@ static void configure_request(configure_request_event_t *event); static void map_request(map_request_event_t *event); static void unmap_notify(unmap_notify_event_t *event); static void motion_notify(motion_notify_event_t *event); +static void enter_notify(enter_notify_event_t *event); +static void focus_in(focus_in_event_t *event); static void manage_window(xcb_window_t window); static void unmanage_client(client_t *client); static void update_client_name(client_t *client); @@ -56,6 +58,7 @@ static void focus(client_t *client); static void unfocus(client_t *client, bool set_focus); static void apply_monitor_layout(monitor_t *monitor); static client_t *get_client_of_window(xcb_window_t window); +static monitor_t *get_monitor_of_window(xcb_window_t window); static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gpointer userdata); static void cleanup(void); @@ -96,22 +99,22 @@ void select_tag(const user_action_arg_t *arg) { /* 调试函数,开发完成后删除 */ static void print_monitor_list_info(monitor_t *monitor_list) { - printf("========================= monitor info =========================\n"); + logger("========================= monitor info =========================\n"); for (monitor_t *m = monitor_list; m; m = m->next) { - printf("========== mon[%u]:\n", m->index); - printf("x: %d, y: %d, width: %u, height: %u\n", m->monitor_x, m->monitor_y, + logger("========== mon[%u]:\n", m->index); + logger("x: %d, y: %d, width: %u, height: %u\n", m->monitor_x, m->monitor_y, m->monitor_width, m->monitor_height); - printf("mon[%u] tags: ", m->index); + logger("mon[%u] tags: ", m->index); for (int i = 0; m->tags[i]; i++) { - printf("%s%s", i > 0 ? ", " : "", m->tags[i]); + logger("%s%s", i > 0 ? ", " : "", m->tags[i]); } - printf("\n"); + logger("\n"); } - printf("======================= monitor info end =======================\n"); + logger("======================= monitor info end =======================\n"); } static void print_color(const char *prompt, const color_t *color) { const char *p = strlen(prompt) ? " " : ""; - printf("%s%srgba: #%08x, argb: #%08x\n", prompt, p, color->rgba, color->argb); + logger("%s%srgba: #%08x, argb: #%08x\n", prompt, p, color->rgba, color->argb); } static void print_color_set(color_set_t *set) { print_color("== bar bg:", &set->bar_bg); @@ -128,54 +131,54 @@ static void print_color_set(color_set_t *set) { } static void print_wallpaper_config(wallpaper_config_t *config) { if (!config) { - printf("no wallpaper\n"); + logger("no wallpaper\n"); return; } - printf("wallpaper count: %u\n", config->count); + logger("wallpaper count: %u\n", config->count); for (uint32_t i = 0; i < config->count; i++) { - printf("wallpaper[%02u]: %s\n", i, config->path_list[i]); + logger("wallpaper[%02u]: %s\n", i, config->path_list[i]); } } static void print_window_list(window_list_t *window_list) { if (!window_list) { - printf("no window\n"); + logger("no window\n"); return; } for (uint32_t i = 0; i < window_list->count; i++) { - printf("window[%u]: 0x%x\n", i, window_list->list[i]); + logger("window[%u]: 0x%x\n", i, window_list->list[i]); } } static char *bool2string(bool b) { return b ? "true" : "false"; } static void print_client(client_t *c) { if (!c) return; - printf("======= client info ========\n"); - printf("window: 0x%x, x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->window, c->x, + logger("======= client info ========\n"); + logger("window: 0x%x, x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->window, c->x, c->y, c->width, c->height, c->border_width); - printf("floating: %s, fullscreen: %s, maximize: %s\n", + logger("floating: %s, fullscreen: %s, maximize: %s\n", bool2string(c->floating), bool2string(c->fullscreen), bool2string(c->maximize)); - printf("tags: %b, monitor selected tags: %b\n", c->tags, + logger("tags: %b, monitor selected tags: %b\n", c->tags, c->monitor->selected_tags); - printf("name: %s\n", c->name); - printf("===== client info end ======\n"); + logger("name: %s\n", c->name); + logger("===== client info end ======\n"); } static void print_rule(const rule_t *r) { - printf("==================== rule ====================\n"); - printf("class: %s, instance: %s, title: %s\n", r->class, r->instance, + logger("==================== rule ====================\n"); + logger("class: %s, instance: %s, title: %s\n", r->class, r->instance, r->title); - printf("floating: %s, maximize: %s, fullscreen: %s, switch to tag: %s\n", + logger("floating: %s, maximize: %s, fullscreen: %s, switch to tag: %s\n", bool2string(r->action.floating), bool2string(r->action.maximize), bool2string(r->action.fullscreen), bool2string(r->action.switch_to_tag)); for (uint32_t i = 0; r->tag && r->tag[i].tags; i++) { const rule_tag_t *t = &r->tag[i]; - printf("monitor amount: %u, monitor index: %u, tags: %b\n", + logger("monitor amount: %u, monitor index: %u, tags: %b\n", t->monitor_amount, t->monitor_index, t->tags); } - printf("================== rule end ==================\n"); + logger("================== rule end ==================\n"); } /* 调试函数结束 */ @@ -279,7 +282,7 @@ void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config) { set_wallpaper(wallpaper); double end = get_time(); free(wallpaper); - printf("set wallpaper cost: %fs\n", end - start); + logger("set wallpaper cost: %fs\n", end - start); } free(screen_size); @@ -413,7 +416,7 @@ void init_monitor_bar(void) { m->cr = cr; } - printf("font height: %u, bar height: %u\n", font_height, bar_height); + logger("font height: %u, bar height: %u\n", font_height, bar_height); } void get_xresource_config(void) { @@ -424,7 +427,7 @@ void get_xresource_config(void) { get_xresource_uint32("zswm.tag_x_padding", &tag_x_pad); get_xresource_uint32("zswm.border_width", &border_px); - printf("dpi: %u, font family: %s, font size: %u\n", dpi, font_family, + logger("dpi: %u, font family: %s, font size: %u\n", dpi, font_family, font_size); clean_xresource(); } @@ -460,6 +463,8 @@ void xcb_event_handler(generic_event_t *event, void *user_data) { EVENT(EVENT_TYPE_MAP_REQUEST, map_request); EVENT(EVENT_TYPE_UNMAP_NOTIFY, unmap_notify); EVENT(EVENT_TYPE_MOTION_NOTIFY, motion_notify); + EVENT(EVENT_TYPE_ENTER_NOTIFY, enter_notify); + EVENT(EVENT_TYPE_FOCUS_IN, focus_in); #undef EVENT @@ -487,7 +492,7 @@ void configure_request(configure_request_event_t *event) { } else { configure_window(client->window, client->x, client->y, client->width, client->height, client->border_width); - printf("configure request: %s\n", client->name); + logger("configure request: %s\n", client->name); } flush_xcb_connection(); @@ -509,6 +514,10 @@ void unmap_notify(unmap_notify_event_t *event) { } void motion_notify(motion_notify_event_t *event) { + logger("motion: window: 0x%x, root: 0x%x\n", event->window, event->root); + logger("x: %d, y: %d, root_x: %d, root_y: %d\n", event->x, event->y, + event->root_x, event->root_y); + logger("root window: 0x%x\n", get_root_window()); if (event->window != get_root_window()) return; static monitor_t *mon = NULL; @@ -521,6 +530,31 @@ void motion_notify(motion_notify_event_t *event) { mon = m; } +void enter_notify(enter_notify_event_t *event) { + if ((event->mode != notify_mode_normal || + event->detail == notify_detail_inferior) && + event->window != get_root_window()) { + return; + } + client_t *c = get_client_of_window(event->window); + monitor_t *m = c ? c->monitor : get_monitor_of_window(event->window); + if (m != current_monitor) { + unfocus(current_monitor->selected_client, true); + current_monitor = m; + } else if (!c || c == current_monitor->selected_client) { + return; + } + focus(c); +} + +void focus_in(focus_in_event_t *event) { + if (current_monitor->selected_client && + event->window != current_monitor->selected_client->window) { + focus_window(event->window); + send_event(event->window, atom_wm_take_focus); + } +} + void manage_window(xcb_window_t window) { window_geometry_t *geometry = get_window_geometry(window); client_t *c = ecalloc(1, sizeof(client_t)); @@ -533,8 +567,8 @@ void manage_window(xcb_window_t window) { c->border_width = border_px; update_client_name(c); - printf("== manage window: %u\n", window); - printf("== x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->x, c->y, c->width, + logger("== manage window: %u\n", window); + logger("== x: %d, y: %d, w: %u, h: %u, bw: %u\n", c->x, c->y, c->width, c->height, c->border_width); xcb_window_t tw = get_transient_window_for(window); @@ -551,9 +585,12 @@ void manage_window(xcb_window_t window) { attach_stack_client(c); init_window_event_mask(window); change_window_border_color(window, color_set->border_color.argb); + if (c->monitor == current_monitor) { + unfocus(current_monitor->selected_client, false); + } arrange(c->monitor); map_window(window); - draw_all_monitor_bars(); + focus(NULL); } void unmanage_client(client_t *client) { @@ -626,7 +663,7 @@ void apply_rules(client_t *client) { } print_client(client); - printf("apply rules done\n"); + logger("apply rules done\n"); } uint32_t get_tags_mask_of_monitor(monitor_t *monitor) { @@ -681,16 +718,33 @@ void restack(monitor_t *monitor) { /* TODO: */ } void focus(client_t *client) { - /* TODO: */ + if (!client || !CLIENT_VISIBLE(client)) { + for (client = current_monitor->clients_stack; + client && !CLIENT_VISIBLE(client); client = client->stack_next); + } + if (current_monitor->selected_client && + current_monitor->selected_client != client) { + unfocus(current_monitor->selected_client, false); + } + if (client) { + if (client->monitor != current_monitor) current_monitor = client->monitor; + detach_stack_client(client); + attach_stack_client(client); + change_window_border_color(client->window, + color_set->active_border_color.argb); + focus_window(client->window); + } else { + focus_window(WINDOW_NONE); + } + current_monitor->selected_client = client; draw_all_monitor_bars(); } void unfocus(client_t *client, bool set_focus) { if (!client) return; + change_window_border_color(client->window, color_set->border_color.argb); - if (set_focus) { - /* TODO: */ - } + if (set_focus) focus_window(WINDOW_NONE); } void show_hide_client(client_t *client) { @@ -741,6 +795,22 @@ client_t *get_client_of_window(xcb_window_t window) { return NULL; } +monitor_t *get_monitor_of_window(xcb_window_t window) { + int32_t x, y; + if (window == get_root_window() && get_pointer_position(&x, &y)) { + return rect_to_monitor(monitors, x, y, 1, 1); + } + + for (monitor_t *m = monitors; m; m = m->next) { + if (window == m->bar_window) return m; + } + + client_t *c = get_client_of_window(window); + if (c) return c->monitor; + + return current_monitor; +} + gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gpointer userdata) { if (condition & (G_IO_HUP | G_IO_ERR)) { diff --git a/src/utils.c b/src/utils.c index 0e67a4a..0e1e58e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -44,6 +44,17 @@ bool file_exist(const char *path) { return access(path, R_OK) == 0; } +#if (!defined(RELEASE)) && defined(LOG_FILE) +void logger(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + FILE *log_file = fopen(LOG_FILE, "a+t"); + vfprintf(log_file, fmt, ap); + va_end(ap); + fclose(log_file); +} +#endif + bool hex_color_to_rgba(const char *hex, uint32_t *rgba) { if (hex[0] == '#') hex++; diff --git a/src/xcb/CMakeLists.txt b/src/xcb/CMakeLists.txt index 6ad5466..8db662e 100644 --- a/src/xcb/CMakeLists.txt +++ b/src/xcb/CMakeLists.txt @@ -1,7 +1,7 @@ set(LIB_XCB "zswm-xcb") set(LIB_XCB_NAME ${LIB_XCB} PARENT_SCOPE) -add_library(${LIB_XCB} STATIC xcb.c window.c res.c cursor.c event.c) +add_library(${LIB_XCB} STATIC xcb.c window.c res.c cursor.c event.c wm-extension.c) target_include_directories(${LIB_XCB} SYSTEM PRIVATE ${XCB_INCLUDE_DIRS} diff --git a/src/xcb/event.c b/src/xcb/event.c index 3683943..91d2f95 100644 --- a/src/xcb/event.c +++ b/src/xcb/event.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -19,7 +18,7 @@ static void convert_event(xcb_generic_event_t *xcb_event, generic_event_t *event) { uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(xcb_event); const char *label = xcb_event_get_label(event_type); - printf("=========================== %s ===========================\n", label); + logger("=========================== %s ===========================\n", label); switch (event_type) { case XCB_MAPPING_NOTIFY: event->type = EVENT_TYPE_MAPPING_NOTIFY; @@ -84,12 +83,19 @@ static void convert_event(xcb_generic_event_t *xcb_event, event->motiion_notify.y = ev->event_y; break; } - case XCB_ENTER_NOTIFY: - event->type = EVENT_TYPE_ENTER_NOTIFY; - break; - case XCB_FOCUS_IN: - event->type = EVENT_TYPE_FOCUS_IN; + case XCB_ENTER_NOTIFY: { + xcb_enter_notify_event_t *ev = (xcb_enter_notify_event_t *)xcb_event; + event->enter_notify.type = EVENT_TYPE_ENTER_NOTIFY; + event->enter_notify.window = ev->event; + event->enter_notify.mode = ev->mode; + event->enter_notify.detail = ev->detail; break; + } + case XCB_FOCUS_IN: { + xcb_focus_in_event_t *ev = (xcb_focus_in_event_t *)xcb_event; + event->focus_in.type = EVENT_TYPE_FOCUS_IN; + event->focus_in.window = ev->event; + } break; case XCB_PROPERTY_NOTIFY: event->type = EVENT_TYPE_PROPERTY_NOTIFY; break; @@ -97,6 +103,7 @@ static void convert_event(xcb_generic_event_t *xcb_event, event->type = EVENT_TYPE_CLIENT_MESSAGE; break; default: + event->type = -1; return; } } diff --git a/src/xcb/window.c b/src/xcb/window.c index 00b76d8..6d3a754 100644 --- a/src/xcb/window.c +++ b/src/xcb/window.c @@ -285,3 +285,19 @@ void change_window_border_color(xcb_window_t window, uint32_t argb) { xcb_params_cw_t params = {.border_pixel = argb}; xcb_aux_change_window_attributes(conn, window, XCB_CW_BORDER_PIXEL, ¶ms); } + +void focus_window(xcb_window_t window) { + xcb_window_t root = screen->root; + if (window == WINDOW_NONE) { + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, root, + XCB_CURRENT_TIME); + xcb_delete_property(conn, root, ewmh->_NET_ACTIVE_WINDOW); + } else { + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, window, + XCB_CURRENT_TIME); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, + ewmh->_NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, + &window); + send_event(window, atom_wm_take_focus); + } +} diff --git a/src/xcb/wm-extension.c b/src/xcb/wm-extension.c new file mode 100644 index 0000000..f6f711c --- /dev/null +++ b/src/xcb/wm-extension.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include + +#include "app.h" +#include "utils.h" +#include "window.h" +#include "xcb-private.h" +#include "xcb.h" + +xcb_ewmh_connection_t *ewmh = NULL; +static bool ewmh_init_failed = false; +static xcb_window_t wm_check_window = XCB_NONE; + +typedef struct atom_name_map_t { + const atom_t atom; + const char *name; + xcb_atom_t xcb_atom; +} atom_map_t; +static atom_map_t atom_map[] = { + {.atom = atom_wm_protocols, .name = "WM_PROTOCOLS"}, + {.atom = atom_wm_delete, .name = "WM_DELETE_WINDOW"}, + {.atom = atom_wm_take_focus, .name = "WM_TAKE_FOCUS"}, +}; + +void init_icccm_extension(void) { + xcb_intern_atom_cookie_t cookie; + for (int i = 0; i < LENGTH(atom_map); i++) { + const char *name = atom_map[i].name; + cookie = xcb_intern_atom(conn, false, strlen(name), name); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL); + atom_map[i].xcb_atom = reply->atom; + free(reply); + } +} + +void init_ewmh_extension(void) { + 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; + } + + 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; + 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, + 32, LENGTH(state), state); + xcb_change_property(conn, mode, screen->root, ewmh->_NET_SUPPORTED, atom, 32, + LENGTH(supported), supported); + xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST); +} + +void clean_ewmh_extension(void) { + if (wm_check_window != XCB_NONE) { + xcb_destroy_window(conn, wm_check_window); + wm_check_window = XCB_NONE; + } + + if (ewmh) { + if (!ewmh_init_failed) { + xcb_ewmh_connection_wipe(ewmh); + } + free(ewmh); + ewmh_init_failed = false; + ewmh = NULL; + } +} + +bool send_event(xcb_window_t window, atom_t atom) { + if (atom < 0 || atom >= LENGTH(atom_map)) return false; + + bool exist = false; + + xcb_atom_t xcb_atom = atom_map[atom].xcb_atom; + xcb_get_property_cookie_t cookie = + xcb_icccm_get_wm_protocols(conn, window, xcb_atom); + xcb_icccm_get_wm_protocols_reply_t reply; + if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &reply, NULL)) { + for (uint32_t i = 0; !exist && i < reply.atoms_len; i++) { + exist = reply.atoms[i] == xcb_atom; + } + xcb_icccm_get_wm_protocols_reply_wipe(&reply); + } + + if (exist) { + xcb_client_message_event_t ev = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .window = window, + .type = atom_map[atom_wm_protocols].xcb_atom, + .data = {.data32 = {xcb_atom, XCB_CURRENT_TIME, 0, 0, 0}}, + }; + xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); + } + + return exist; +} diff --git a/src/xcb/xcb-private.h b/src/xcb/xcb-private.h index b1dc116..d9db441 100644 --- a/src/xcb/xcb-private.h +++ b/src/xcb/xcb-private.h @@ -12,3 +12,7 @@ extern xcb_key_symbols_t *key_symbols; xcb_cursor_t get_xcb_cursor(cursor_t cursor); void clean_xcb_cursor(void); + +void init_icccm_extension(void); +void init_ewmh_extension(void); +void clean_ewmh_extension(void); diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index ddb21e7..e380a47 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -15,7 +15,6 @@ #include "app.h" #include "utils.h" -#include "window.h" #include "xcb-private.h" xcb_connection_t *conn = NULL; @@ -170,58 +169,13 @@ void set_wallpaper(uint32_t *wallpaper_data) { xcb_flush(conn); } -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 || 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; - } - - 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; - 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, - 32, LENGTH(state), state); - xcb_change_property(conn, mode, screen->root, ewmh->_NET_SUPPORTED, atom, 32, - LENGTH(supported), supported); - xcb_delete_property(conn, screen->root, ewmh->_NET_CLIENT_LIST); -} - /** * 扫描窗口列表 * @returns 若无窗口,返回 NULL,否则返回窗口列表 * @note: 返回的窗口列表数据使用完后使用 free_window_list 释放 */ window_list_t *scan_window_list(void) { + init_icccm_extension(); init_ewmh_extension(); xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, screen->root); @@ -278,21 +232,7 @@ void free_window_list(window_list_t *window_list) { void clean_xcb(void) { clean_xcb_cursor(); - - if (wm_check_window != XCB_NONE) { - xcb_destroy_window(conn, wm_check_window); - wm_check_window = XCB_NONE; - } - - if (ewmh) { - if (!ewmh_init_failed) { - xcb_ewmh_connection_wipe(ewmh); - } - free(ewmh); - ewmh_init_failed = false; - ewmh = NULL; - } - + clean_ewmh_extension(); xcb_disconnect(conn); conn = NULL; screen = NULL; @@ -322,3 +262,18 @@ void grab_keybindings(const keybinding_t *keys, const size_t length) { } } } + +bool get_pointer_position(int32_t *x, int32_t *y) { + xcb_query_pointer_cookie_t cookie = xcb_query_pointer(conn, screen->root); + xcb_query_pointer_reply_t *reply = + xcb_query_pointer_reply(conn, cookie, NULL); + + if (reply) { + *x = reply->root_x; + *y = reply->root_y; + free(reply); + return true; + } + + return false; +}