Compare commits

..

2 Commits

Author SHA1 Message Date
a6d6798714 添加 xkbcommon 支持 2025-11-23 06:48:54 +08:00
edda316709 设置快捷键 2025-11-22 22:22:54 +08:00
10 changed files with 34 additions and 132 deletions

View File

@@ -48,7 +48,6 @@ pkg_check_modules(deps REQUIRED
xcb
xcb-aux
xcb-cursor
xcb-icccm
xcb-keysyms
xcb-randr
xcb-xfixes

View File

@@ -16,12 +16,3 @@ void spawn(const user_action_arg_t *arg) {
g_spawn_command_line_async((const char *)arg->ptr, nullptr);
}
void quit(const user_action_arg_t *arg) {
const bool restart = arg->b;
if (restart) {
wm_restart();
} else {
wm_quit();
}
}

View File

@@ -50,4 +50,3 @@ typedef struct keyboard_t {
void select_tag_of_current_monitor(const user_action_arg_t *arg);
void spawn(const user_action_arg_t *arg);
void quit(const user_action_arg_t *arg);

View File

@@ -1,6 +1 @@
_XKB_RULES_NAMES
WM_PROTOCOLS
WM_TAKE_FOCUS
_NET_ACTIVE_WINDOW

View File

@@ -28,7 +28,5 @@ static const button_t button_list[] = {
static const char launcher[] =
"rofi -show combi -modes window,drun,run,ssh,combi,windowcd";
static const keyboard_t key_list[] = {
{modifier_alt, XK_p, spawn, {.ptr = launcher}},
{modifier_alt, XK_q, quit, {.b = false}},
{modifier_alt, XK_r, quit, {.b = true}},
{modifier_super, XK_p, spawn, {.ptr = launcher}},
};

View File

@@ -2,12 +2,10 @@
#include <glib.h>
#include <stdint.h>
#include <stdio.h>
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include <xkbcommon/xkbcommon.h>
#include "action.h"
#include "default_config.h"
@@ -50,15 +48,7 @@ static void button_press(xcb_button_press_event_t *ev) {
}
static void key_press(xcb_key_press_event_t *ev) {
bool is_press = XCB_EVENT_RESPONSE_TYPE(ev) == XCB_KEY_PRESS;
xcb_keysym_t keysym = xcb_key_press_lookup_keysym(wm.key_symbols, ev, 0);
char key_name[16];
if (xkb_keysym_get_name(keysym, key_name, sizeof(key_name)) != -1) {
printf("key %s: %s\n", is_press ? "press" : "release", key_name);
}
if (!is_press) return;
for (int i = 0; i < countof(key_list); i++) {
keyboard_t key = key_list[i];
if (keysym == key.keysym && ev->state == key.modifiers && key.func) {
@@ -70,9 +60,6 @@ static void key_press(xcb_key_press_event_t *ev) {
static void handle_xcb_event(xcb_generic_event_t *event) {
uint8_t event_type = XCB_EVENT_RESPONSE_TYPE(event);
const char *label = xcb_event_get_label(event_type);
printf("event type: %u[%s], xkb_event: %u\n", event_type, label,
wm.event_base_xkb);
switch (event_type) {
#define EVENT(type, callback) \
@@ -82,7 +69,6 @@ static void handle_xcb_event(xcb_generic_event_t *event) {
EVENT(XCB_BUTTON_PRESS, button_press);
EVENT(XCB_KEY_PRESS, key_press);
EVENT(XCB_KEY_RELEASE, key_press);
#undef EVENT
}

View File

@@ -17,6 +17,7 @@
#include <xcb/xinerama.h>
#include <xcb/xproto.h>
#include "action.h"
#include "atoms.h"
#include "backtrace.h"
#include "buffer.h"
@@ -49,6 +50,11 @@ static char **cmd_argv;
/** A pipe that is used to asynchronously handle SIGCHLD */
static int sigchld_pipe[2];
static void wm_atexit(bool restart) {
wm.need_restart = restart;
wm_clean();
}
static gboolean restart_on_signal(gpointer data) {
wm_restart();
return TRUE;
@@ -267,7 +273,6 @@ void wm_clean(void) {
xkb_free();
xcb_ungrab_key(wm.xcb_conn, XCB_GRAB_ANY, wm.screen->root, modifier_any);
xcb_key_symbols_free(wm.key_symbols);
xcb_aux_sync(wm.xcb_conn);
xcb_disconnect(wm.xcb_conn);
}
@@ -296,9 +301,9 @@ static void wm_setup(void) {
xcb_aux_change_window_attributes(wm.xcb_conn, wm.screen->root, XCB_CW_CURSOR,
&params);
wm_setup_keybindings();
atoms_init(wm.xcb_conn);
xkb_init();
wm_setup_keybindings();
xcb_flush(wm.xcb_conn);
}
@@ -321,14 +326,12 @@ void wm_setup_keybindings(void) {
}
void wm_restart(void) {
wm.need_restart = true;
if (g_main_loop_is_running(wm.loop)) {
g_main_loop_quit(wm.loop);
}
wm_atexit(true);
execvp(cmd_argv[0], cmd_argv);
fatal("execv() failed: %s", strerror(errno));
}
void wm_quit(void) {
wm.need_restart = false;
if (g_main_loop_is_running(wm.loop)) {
g_main_loop_quit(wm.loop);
}
@@ -360,11 +363,12 @@ int main(int argc, char *argv[]) {
wm_check_xcb_extensions();
wm_detect_monitor();
setup_event_loop();
wm_setup();
debug_show_monitor_list();
setup_event_loop();
if (wm.loop == nullptr) {
wm.loop = g_main_loop_new(nullptr, FALSE);
g_main_loop_run(wm.loop);
@@ -372,12 +376,7 @@ int main(int argc, char *argv[]) {
g_main_loop_unref(wm.loop);
wm.loop = nullptr;
wm_clean();
if (wm.need_restart) {
execvp(cmd_argv[0], cmd_argv);
fatal("execv() failed: %s", strerror(errno));
}
wm_atexit(false);
return EXIT_SUCCESS;
}

View File

@@ -4,7 +4,6 @@
#include <glib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xcb/xcb.h>
#include <xcb/xcb_keysyms.h>
@@ -106,6 +105,11 @@ static void xkb_init_keymap(void) {
xkb_fill_state();
}
static void xkb_free_keymap(void) {
xkb_state_unref(wm.xkb_state);
xkb_context_unref(wm.xkb_ctx);
}
#define DEVICE_SPEC XCB_XKB_ID_USE_CORE_KBD
void xkb_init(void) {
@@ -114,15 +118,17 @@ void xkb_init(void) {
wm.have_xkb = xkb_x11_setup_xkb_extension(
wm.xcb_conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nullptr, nullptr, &wm.event_base_xkb,
nullptr);
printf("xkb base event: %u\n", wm.event_base_xkb);
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nullptr, nullptr, nullptr, nullptr);
if (!wm.have_xkb) {
warn("XKB not found or not supported");
xkb_init_keymap();
return;
}
const xcb_query_extension_reply_t *reply = nullptr;
reply = xcb_get_extension_data(wm.xcb_conn, &xcb_xkb_id);
if (reply && reply->present) wm.event_base_xkb = reply->first_event;
xcb_xkb_per_client_flags_cookie_t cookie = xcb_xkb_per_client_flags(
wm.xcb_conn, DEVICE_SPEC, XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, 0, 0, 0);
@@ -145,22 +151,18 @@ void xkb_free(void) {
if (wm.have_xkb) {
xcb_xkb_select_events(wm.xcb_conn, DEVICE_SPEC, 0, 0, 0, 0, 0, nullptr);
}
xkb_state_unref(wm.xkb_state);
xkb_context_unref(wm.xkb_ctx);
wm.xkb_state = nullptr;
wm.xkb_ctx = nullptr;
xkb_free_keymap();
}
static void xkb_reload_keymap(void) {
assert(wm.have_xkb);
xkb_state_unref(wm.xkb_state);
xkb_fill_state();
xcb_key_symbols_free(wm.key_symbols);
wm.key_symbols = xcb_key_symbols_alloc(wm.xcb_conn);
xwindow_grab_keys(wm.screen->root, key_list, countof(key_list));
xkb_state_unref(wm.xkb_state);
xkb_fill_state();
}
static gboolean xkb_refresh(gpointer ignore) {
@@ -182,8 +184,6 @@ static void xkb_schedule_refresh(void) {
void xkb_handle_event(xcb_generic_event_t *event) {
assert(wm.have_xkb);
printf("xkb event type: %u\n", event->pad0);
/* XKB 中没有对应所有事件的泛型类型xcb_generic_event_t 类型中的 pad0
* 字段对应 XKB 事件中的 xkbType 字段,故用该字段判断 XKB 事件类型 */
switch (event->pad0) {
@@ -204,12 +204,6 @@ void xkb_handle_event(xcb_generic_event_t *event) {
state_notify_event->latchedMods, state_notify_event->lockedMods,
state_notify_event->baseGroup, state_notify_event->latchedGroup,
state_notify_event->lockedGroup);
printf("changed: %u\n",
state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE);
if (state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE) {
xkb_schedule_refresh();
}
break;
}
}

View File

@@ -1,14 +1,11 @@
#include "xwindow.h"
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h>
#include "action.h"
#include "atoms-extern.h"
#include "utils.h"
#include "wm.h"
#include "xcursor.h"
@@ -119,55 +116,13 @@ void xwindow_grab_keys(xcb_window_t window, const keyboard_t *keys,
xcb_ungrab_key(conn, XCB_GRAB_ANY, window, modifier_any);
xcb_grab_mode_t mode = XCB_GRAB_MODE_ASYNC;
xcb_keycode_t *keycode = nullptr;
for (int i = 0; i < keys_length; i++) {
xcb_keycode_t *keycodes =
xcb_key_symbols_get_keycode(wm.key_symbols, keys[i].keysym);
if (keycodes) {
for (xcb_keycode_t *kc = keycodes; *kc != XCB_NO_SYMBOL; kc++) {
xcb_grab_key(conn, true, window, keys[i].modifiers, *kc, mode, mode);
}
p_delete(&keycodes);
keycode = xcb_key_symbols_get_keycode(wm.key_symbols, keys[i].keysym);
if (keycode) {
xcb_grab_key(conn, true, window, keys[i].modifiers, *keycode, mode, mode);
p_delete(&keycode);
}
}
}
bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom) {
bool exist = false;
xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_protocols(wm.xcb_conn, window, atom);
xcb_icccm_get_wm_protocols_reply_t reply;
if (xcb_icccm_get_wm_protocols_reply(wm.xcb_conn, cookie, &reply, nullptr)) {
for (uint32_t i = 0; !exist && i < reply.atoms_len; i++) {
exist = reply.atoms[i] == atom;
}
xcb_icccm_get_wm_protocols_reply_wipe(&reply);
}
if (exist) {
xcb_client_message_event_t ev;
p_clear(&ev, 1);
ev.response_type = XCB_CLIENT_MESSAGE;
ev.format = 32;
ev.window = window;
ev.type = WM_PROTOCOLS;
ev.data.data32[0] = atom;
ev.data.data32[1] = XCB_CURRENT_TIME;
}
return exist;
}
void xwindow_focus(xcb_window_t window) {
if (window == XCB_WINDOW_NONE || window == wm.screen->root) {
xcb_set_input_focus(wm.xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT,
wm.screen->root, XCB_CURRENT_TIME);
xcb_delete_property(wm.xcb_conn, wm.screen->root, _NET_ACTIVE_WINDOW);
} else {
xcb_set_input_focus(wm.xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, window,
XCB_CURRENT_TIME);
xcb_change_property(wm.xcb_conn, XCB_PROP_MODE_REPLACE, wm.screen->root,
_NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, &window);
xwindow_send_event(window, WM_TAKE_FOCUS);
}
}

View File

@@ -4,7 +4,6 @@
#include <xcb/xproto.h>
#include "action.h"
#include "app.h"
#include "xcursor.h"
typedef struct visual_t {
@@ -16,16 +15,3 @@ visual_t *xwindow_get_xcb_visual(bool prefer_alpha);
void xwindow_change_cursor(xcb_window_t window, cursor_t cursor);
void xwindow_grab_keys(xcb_window_t window, const keyboard_t *keys,
int keys_length);
bool xwindow_send_event(xcb_window_t window, xcb_atom_t atom);
void xwindow_focus(xcb_window_t window);
#define xwindow_set_name_static(window, name) \
xcb_icccm_set_wm_name(wm.xcb_conn, window, XCB_ATOM_STRING, 8, \
sizeof(name) - 1, name)
#define xwindow_set_class_instance(window) \
xwindow_set_class_instance_static(window, APP_NAME, APP_NAME)
#define xwindow_set_class_instance_static(window, class, instance) \
_xwindow_set_class_instance_static(window, instance "\0" class)
#define _xwindow_set_class_instance_static(window, instance_class) \
xcb_icccm_set_wm_class(wm.xcb_conn, window, sizeof(instance_class), \
instance_class)