From 2a7ab324be3550e052c8ab3b6983c21e41868507 Mon Sep 17 00:00:00 2001 From: Zedhugh Chen Date: Tue, 19 Aug 2025 21:37:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BF=AB=E6=8D=B7=E9=94=AE?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/action.h | 6 ++++++ src/config.h | 19 ++++++++++++++-- src/include/event-adapter.h | 2 +- src/include/types.h | 17 ++++++++++++++- src/include/xcb.h | 4 ++++ src/main.c | 43 +++++++++++++++++++++++++++++++++++++ src/xcb/event.c | 2 +- src/xcb/xcb.c | 25 +++++++++++++++++++++ 8 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/action.h diff --git a/src/action.h b/src/action.h new file mode 100644 index 0000000..47fe581 --- /dev/null +++ b/src/action.h @@ -0,0 +1,6 @@ +#pragma once + +#include "types.h" + +void spawn(const user_action_arg_t *arg); +void quit(const user_action_arg_t *arg); diff --git a/src/config.h b/src/config.h index a6312c6..9585e24 100644 --- a/src/config.h +++ b/src/config.h @@ -1,11 +1,13 @@ #pragma once +#include #include -#include +#include +#include "action.h" #include "types.h" -/* 壁纸列表,支持通配符和 shell 环境变量拼接,最后以 NULL 结尾 */ +/* 壁纸列表,支持通配符和 shell 环境变量拼接 */ const char *wallpapers[] = {}; /* 壁纸切换间隔(单位:秒),0 表示不切换 */ const uint32_t wallpaper_interval = 0; @@ -59,6 +61,19 @@ const rule_t rules[] = { {.class = "Emacs", .monitor_amount = 2, .monitor_index = 0, .tags = 1 << 1}, }; +#define SUPER XCB_MOD_MASK_4 +#define ALT XCB_MOD_MASK_1 +#define CTRL XCB_MOD_MASK_CONTROL +#define SHIFT XCB_MOD_MASK_SHIFT + +const char launcher[] = + "rofi -show combi -modes window,drun,run,ssh,combi,windowcd"; +const keybinding_t keys[] = { + {SUPER, XK_p, spawn, {.ptr = launcher}}, + {SUPER, XK_q, quit, {.b = false}}, + {SUPER, XK_r, quit, {.b = true}}, +}; + const char *const bar_bg = "#222222"; const char *const tag_bg = "#222222"; const char *const active_tag_bg = "#005577"; diff --git a/src/include/event-adapter.h b/src/include/event-adapter.h index 497f98c..17ef13b 100644 --- a/src/include/event-adapter.h +++ b/src/include/event-adapter.h @@ -25,7 +25,7 @@ typedef struct mapping_notify_event_t { typedef struct key_press_event_t { event_type_t type; - uint32_t key_symbols; + uint32_t key_symbol; uint32_t modifiers; } key_press_event_t; diff --git a/src/include/types.h b/src/include/types.h index 6b57618..6a8d6a5 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -24,7 +24,7 @@ struct monitor_t { /* 为了避免引入 cairo 相关头文件,这里用 void * * 指针代替实际的指针类型,使用时强转为相应指针类型使用即可 */ - void *cr; /* cairo_t */ + void *cr; /* cairo_t */ const layout_t *layout; monitor_t *next; @@ -73,6 +73,21 @@ typedef struct rule_t { bool floating; } rule_t; +typedef union user_action_arg_t { + bool b; + int32_t i; + uint32_t ui; + float f; + const void *ptr; +} user_action_arg_t; + +typedef struct keybinding_t { + uint32_t modifiers; + uint32_t key_symbol; + void (*func)(const user_action_arg_t *); + const user_action_arg_t arg; +} keybinding_t; + typedef struct color_t { uint32_t rgba; uint32_t argb; diff --git a/src/include/xcb.h b/src/include/xcb.h index ae8ff80..6072a10 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include "types.h" bool has_other_wm_running(void); int get_xcb_connection_fd(void); @@ -56,6 +58,8 @@ window_list_t *scan_window_list(void); void free_window_list(window_list_t *window_list); void clean_xcb(void); +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); diff --git a/src/main.c b/src/main.c index 7be9439..24b1e1c 100644 --- a/src/main.c +++ b/src/main.c @@ -8,8 +8,10 @@ #include #include #include +#include #include +#include "action.h" #include "config.h" #include "event-adapter.h" #include "renderer.h" @@ -30,6 +32,8 @@ static void init_monitor_bar(void); static void get_xresource_config(void); static void update_bars(void); static void init_xcb_event_loop(void); +static void xcb_event_handler(generic_event_t *event, void *user_data); +static void key_press(key_press_event_t *event); static gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gpointer userdata); static void cleanup(void); @@ -47,6 +51,16 @@ static uint32_t bar_y_pad = bar_y_padding; static uint32_t tag_x_pad = tag_x_padding; static uint32_t bar_height = 0; +static bool need_restart = false; + +void spawn(const user_action_arg_t *arg) { + g_spawn_command_line_async(arg->ptr, NULL); +} +void quit(const user_action_arg_t *arg) { + need_restart = arg->b; + g_main_loop_quit(loop); +} + /* 调试函数,开发完成后删除 */ static void print_monitor_list_info(monitor_t *monitor_list) { printf("========================= monitor info =========================\n"); @@ -359,6 +373,7 @@ void update_bars(void) { void init_xcb_event_loop(void) { adapter = create_event_adapter(); + event_adapter_set_handler(adapter, xcb_event_handler, NULL); GIOChannel *channel = g_io_channel_unix_new(get_xcb_connection_fd()); g_io_channel_set_encoding(channel, NULL, NULL); GIOCondition cond = G_IO_IN | G_IO_HUP | G_IO_ERR; @@ -366,6 +381,27 @@ void init_xcb_event_loop(void) { g_io_channel_unref(channel); } +void xcb_event_handler(generic_event_t *event, void *user_data) { + switch (event->type) { + case EVENT_TYPE_KEY_PRESS: + key_press((key_press_event_t *)event); + break; + default: + break; + } +} + +void key_press(key_press_event_t *event) { + const keybinding_t *key = NULL; + for (int i = 0; i < LENGTH(keys); i++) { + key = &keys[i]; + if (key->key_symbol == event->key_symbol && + key->modifiers == event->modifiers && key->func) { + key->func(&key->arg); + } + } +} + gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, gpointer userdata) { if (condition & (G_IO_HUP | G_IO_ERR)) { @@ -434,6 +470,8 @@ int main(int argc, char *argv[]) { free_window_list(window_list); + grab_keybindings(keys, LENGTH(keys)); + init_xcb_event_loop(); loop = g_main_loop_new(NULL, FALSE); @@ -441,5 +479,10 @@ int main(int argc, char *argv[]) { cleanup(); + if (need_restart) { + need_restart = false; + execvp(argv[0], argv); + } + return 0; } diff --git a/src/xcb/event.c b/src/xcb/event.c index 35309b4..0ca8819 100644 --- a/src/xcb/event.c +++ b/src/xcb/event.c @@ -29,7 +29,7 @@ static void convert_event(xcb_generic_event_t *xcb_event, int col = ev->state & XCB_MOD_MASK_2 ? 1 : 0; xcb_keysym_t keysym = xcb_key_press_lookup_keysym(key_symbols, ev, col); event->key_press.type = EVENT_TYPE_KEY_PRESS; - event->key_press.key_symbols = keysym; + event->key_press.key_symbol = keysym; event->key_press.modifiers = ev->state; break; } diff --git a/src/xcb/xcb.c b/src/xcb/xcb.c index 0045fbc..62a8a4e 100644 --- a/src/xcb/xcb.c +++ b/src/xcb/xcb.c @@ -297,3 +297,28 @@ void clean_xcb(void) { conn = NULL; screen = NULL; } + +void grab_keybindings(const keybinding_t *keys, const size_t length) { + xcb_window_t root = screen->root; + xcb_keycode_t key = XCB_GRAB_ANY; + xcb_ungrab_key(conn, key, root, XCB_MOD_MASK_ANY); + key_symbols = xcb_key_symbols_alloc(conn); + + xcb_grab_mode_t mode = XCB_GRAB_MODE_ASYNC; + xcb_keycode_t *keycode = NULL; + xcb_mod_mask_t modifiers; + xcb_void_cookie_t cookie; + xcb_generic_error_t *error = NULL; + + for (int i = 0; i < length; i++) { + xcb_keysym_t keysym = keys[i].key_symbol; + keycode = xcb_key_symbols_get_keycode(key_symbols, keysym); + modifiers = keys[i].modifiers; + cookie = xcb_grab_key(conn, key, root, modifiers, *keycode, mode, mode); + error = xcb_request_check(conn, cookie); + if (error) { + clean_xcb(); + die("%scannot grap key", APP_NAME); + } + } +}