From ac91ebbed3c826db208fd25627fe7b92985eb868 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Tue, 2 Sep 2025 16:27:45 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=85=89=E6=A0=87=E5=9C=A8?= =?UTF-8?q?=E6=AF=8F=E4=B8=AA=E5=B1=8F=E5=B9=95=E4=B8=AD=E6=9C=80=E5=90=8E?= =?UTF-8?q?=E5=81=9C=E7=95=99=E7=9A=84=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.h | 1 + src/include/event-adapter.h | 1 + src/include/types.h | 3 ++ src/include/xcb.h | 1 + src/main.c | 66 ++++++++++++++++++++++++++++++------- src/utils.c | 13 +++++--- src/xcb/event.c | 1 + src/xcb/xcb.c | 5 +++ 8 files changed, 75 insertions(+), 16 deletions(-) diff --git a/src/config.h b/src/config.h index 09ecca9..9107c9f 100644 --- a/src/config.h +++ b/src/config.h @@ -164,6 +164,7 @@ const char *const active_border_color = "#005577"; const char *const default_font_family = "sans-serif, monospace"; const uint32_t default_font_size = 10; const uint32_t dpi_fallback = 96; +const uint32_t refresh_rate = 60; const uint32_t bar_y_padding = 1; const uint32_t tag_x_padding = 10; diff --git a/src/include/event-adapter.h b/src/include/event-adapter.h index 9fec3d6..f13e043 100644 --- a/src/include/event-adapter.h +++ b/src/include/event-adapter.h @@ -100,6 +100,7 @@ typedef struct motion_notify_event_t { xcb_window_t window; int32_t x; int32_t y; + uint32_t time; /* 时间戳(单位:ms) */ } motion_notify_event_t; typedef struct enter_notify_event_t { diff --git a/src/include/types.h b/src/include/types.h index 7d5307d..f94d5d0 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -33,6 +33,9 @@ struct monitor_t { client_t *clients_stack; client_t *selected_client; + int32_t pointer_x; /* 记录光标 x 坐标位置 */ + int32_t pointer_y; /* 记录光标 y 坐标位置 */ + xcb_window_t bar_window; }; diff --git a/src/include/xcb.h b/src/include/xcb.h index 124a1be..9b31e0b 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -153,6 +153,7 @@ void set_window_tag(xcb_window_t window, client_tag_info_t *client_info); void remove_window_tag(xcb_window_t window); bool get_pointer_position(int32_t *x, int32_t *y); +void set_pointer_position(int32_t x, int32_t y); /** * @brief 非阻塞检查特定事件掩码(模拟 XCheckMaskEvent) diff --git a/src/main.c b/src/main.c index 675145e..9af4498 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,8 @@ static void init_monitors(void); static char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index); +static void record_mointor_pointer_position(int32_t x, int32_t y, + uint32_t timestamp); static void init_wallpaper(void); static gboolean update_wallpaper(gpointer user_data); static void set_wallpaper_by_index(uint32_t index, wallpaper_config_t *config, @@ -96,6 +98,7 @@ static event_adapter_t *adapter = NULL; static char *font_family = NULL; static uint32_t font_size = default_font_size; static uint32_t dpi = dpi_fallback; +static uint32_t fps = refresh_rate; static uint32_t bar_y_pad = bar_y_padding; static uint32_t tag_x_pad = tag_x_padding; static uint32_t layout_symbol_x_pad = layout_symbol_x_padding; @@ -174,7 +177,8 @@ void focus_monitor(const user_action_arg_t *arg) { unfocus(current_monitor->selected_client, false); current_monitor = monitor; focus(NULL); - /* TODO: 调整鼠标光标 */ + + set_pointer_position(monitor->pointer_x, monitor->pointer_y); } void raise_or_run(const user_action_arg_t *arg) { @@ -187,6 +191,8 @@ void raise_or_run(const user_action_arg_t *arg) { logger("==== raise client: %s, window: 0x%x\n", client->name, client->window); current_monitor = client->monitor; + set_pointer_position(current_monitor->pointer_x, + current_monitor->pointer_y); argument.ui = client->tags; select_tag(&argument); focus(client); @@ -231,19 +237,22 @@ void move_to_tag(const user_action_arg_t *arg) { arrange(current_monitor); } +static void print_monitor_info(monitor_t *monitor) { + logger("========== mon[%u]:\n", monitor->index); + logger("x: %d, y: %d, width: %u, height: %u, pointer x: %d, pointer y: %d\n", + monitor->monitor_x, monitor->monitor_y, monitor->monitor_width, + monitor->monitor_height, monitor->pointer_x, monitor->pointer_y); + logger("mon[%u] tags: ", monitor->index); + for (int i = 0; monitor->tags[i]; i++) { + logger("%s%s", i > 0 ? ", " : "", monitor->tags[i]); + } + logger("\n"); +} + /* 调试函数,开发完成后删除 */ static void print_monitor_list_info(monitor_t *monitor_list) { logger("========================= monitor info =========================\n"); - for (monitor_t *m = monitor_list; m; m = m->next) { - 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); - logger("mon[%u] tags: ", m->index); - for (int i = 0; m->tags[i]; i++) { - logger("%s%s", i > 0 ? ", " : "", m->tags[i]); - } - logger("\n"); - } + for (monitor_t *m = monitor_list; m; m = m->next) print_monitor_info(m); logger("======================= monitor info end =======================\n"); } static void print_color(const char *prompt, const color_t *color) { @@ -356,6 +365,25 @@ void init_monitors(void) { m->tags = get_monitor_tags(i, m->index); m->selected_tags = 0x1; } + + int32_t x, y; + if (get_pointer_position(&x, &y)) { + monitor_t *monitor = rect_to_monitor(monitors, x, y, 1, 1); + print_monitor_info(monitor); + + int32_t offset_x = x - monitor->monitor_x; + int32_t offset_y = y - monitor->monitor_y; + + logger("==== init monitor pointer position ====\n"); + logger("x: %d, y: %d, offset_x: %d, offset_y: %d\n", x, y, offset_x, + offset_y); + logger("== init monitor pointer position end ==\n"); + + for (monitor_t *m = monitors; m; m = m->next) { + m->pointer_x = m->monitor_x + offset_x; + m->pointer_y = m->monitor_y + offset_y; + } + } } char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) { @@ -385,6 +413,15 @@ char **get_monitor_tags(uint32_t monitor_count, uint32_t monitor_index) { return g_strv_builder_unref_to_strv(builder); } +void record_mointor_pointer_position(int32_t x, int32_t y, uint32_t timestamp) { + static uint32_t last_timestamp = 0; + if ((timestamp - last_timestamp) < (1000 / fps)) return; + + monitor_t *monitor = rect_to_monitor(monitors, x, y, 1, 1); + monitor->pointer_x = x; + monitor->pointer_x = y; +} + void init_wallpaper(void) { bar_cairo_params_t *p = prepare_wallpaper_surface_params(); rect_size_t *screen_size = get_screen_size(); @@ -693,6 +730,7 @@ void init_monitor_bar(void) { void get_xresource_config(void) { get_xresource_uint32("Xft.dpi", &dpi); + get_xresource_uint32("zswm.fps", &fps); get_xresource_string("zswm.font_family", &font_family, default_font_family); get_xresource_uint32("zswm.font_size", &font_size); get_xresource_uint32("zswm.bar_y_padding", &bar_y_pad); @@ -847,6 +885,8 @@ void expose(expose_event_t *event) { } void motion_notify(motion_notify_event_t *event) { + record_mointor_pointer_position(event->root_x, event->root_y, event->time); + if (event->window != get_root_window()) return; static monitor_t *mon = NULL; @@ -954,6 +994,8 @@ void client_message(client_message_event_t *event) { const user_action_arg_t arg = {.ui = target_tag}; current_monitor = client->monitor; + set_pointer_position(current_monitor->pointer_x, + current_monitor->pointer_y); select_tag(&arg); focus(client); restack(current_monitor); @@ -1098,6 +1140,8 @@ void apply_rules(client_t *client) { } if (switch_to_tag) { current_monitor = client->monitor; + set_pointer_position(current_monitor->pointer_x, + current_monitor->pointer_y); current_monitor->selected_tags = client->tags; } diff --git a/src/utils.c b/src/utils.c index 0e1e58e..72421cb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -2,11 +2,14 @@ #include #include +#include #include #include #include #include +#include "types.h" + double get_time() { struct timeval tv; gettimeofday(&tv, NULL); @@ -105,11 +108,11 @@ void extract_color_channel(const uint32_t rgba, double *red, double *green, *alpha = COLOR_SPLIT(rgba, 0); } -#define INTERSECT(x, y, w, h, m) \ - (MAX(0, MIN((x) + (w), (m)->window_x + (m)->window_width) - \ - MAX((x), (m)->window_x)) * \ - MAX(0, MIN((y) + (h), (m)->window_y + (m)->window_height) - \ - MAX((y), (m)->window_y))) +#define INTERSECT(x, y, w, h, m) \ + (MAX(0, MIN((x) + (w), (m)->monitor_x + (int)(m)->monitor_width) - \ + MAX((x), (m)->monitor_x)) * \ + MAX(0, MIN((y) + (h), (m)->monitor_y + (int)(m)->monitor_height) - \ + MAX((y), (m)->monitor_y))) monitor_t *rect_to_monitor(monitor_t *monitors, int32_t x, int32_t y, uint32_t width, uint32_t height) { monitor_t *r = monitors; diff --git a/src/xcb/event.c b/src/xcb/event.c index 4f78391..85f31f8 100644 --- a/src/xcb/event.c +++ b/src/xcb/event.c @@ -89,6 +89,7 @@ static void convert_event(xcb_generic_event_t *xcb_event, event->motiion_notify.window = ev->event; event->motiion_notify.x = ev->event_x; event->motiion_notify.y = ev->event_y; + event->motiion_notify.time = ev->time; break; } case XCB_ENTER_NOTIFY: { diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index 7ab70e6..83de426 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -337,6 +337,11 @@ bool get_pointer_position(int32_t *x, int32_t *y) { return false; } +void set_pointer_position(int32_t x, int32_t y) { + xcb_warp_pointer(conn, XCB_WINDOW_NONE, screen->root, 0, 0, 1, 1, x, y); + xcb_flush(conn); +} + bool xcb_check_mask_event(xcb_event_mask_t event_mask) { xcb_generic_event_t *event = xcb_poll_for_event(conn); if (!event) return false;