diff --git a/CMakeLists.txt b/CMakeLists.txt index 881522e..ceea343 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ project(${APP_NAME} add_executable(${APP_NAME} ${SOURCE_DIR}/backend/output_utils.c ${SOURCE_DIR}/backend/x11/backend.c + ${SOURCE_DIR}/backend/x11/common.c ${SOURCE_DIR}/backend/x11/cursor.c ${SOURCE_DIR}/backend/x11/event.c ${SOURCE_DIR}/backend/x11/window.c diff --git a/src/backend/x11/backend.c b/src/backend/x11/backend.c index b7b590e..cb5a3b9 100644 --- a/src/backend/x11/backend.c +++ b/src/backend/x11/backend.c @@ -522,6 +522,22 @@ backend_bind_key(backend_t *backend, const effect_bind_key_t *bind_key) { window_grab_keys(backend, root, bind_key->keys, bind_key->count); } +static void backend_grab_button( + backend_t *backend, + const effect_grab_button_t *grab_button +) { + auto conn = backend->conn; + auto window = grab_button->window; + xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY); + + auto buttons = grab_button->buttons; + for (size_t i = 0; i < grab_button->count; ++i) { + auto button = buttons[i].button; + auto modifiers = buttons[i].modifiers; + window_grab_button(backend, window, button, modifiers); + } +} + static void backend_merge_effects( backend_t *backend, const effect_t *effects, @@ -601,6 +617,8 @@ static void backend_merge_effects( case ZDWM_EFFECT_BIND_KEY: backend_bind_key(backend, &e->as.bind_key); break; + case ZDWM_EFFECT_GRAB_BUTTON: + backend_grab_button(backend, &e->as.grab_button); } } } diff --git a/src/backend/x11/common.c b/src/backend/x11/common.c new file mode 100644 index 0000000..293336b --- /dev/null +++ b/src/backend/x11/common.c @@ -0,0 +1,71 @@ +#include "common.h" + +#include +#include +#include + +#include "base/macros.h" +#include "core/types.h" + +typedef struct modifier_map_t { + modifier_bit_t modifier; + xcb_mod_mask_t mask; +} modifier_map_t; + +static constexpr modifier_map_t modifier_map[] = { + {ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT}, + {ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL}, + {ZDWM_MOD_1, XCB_MOD_MASK_1}, + {ZDWM_MOD_2, XCB_MOD_MASK_2}, + {ZDWM_MOD_3, XCB_MOD_MASK_3}, + {ZDWM_MOD_4, XCB_MOD_MASK_4}, + {ZDWM_MOD_5, XCB_MOD_MASK_5}, +}; + +modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask) { + modifier_mask_t mods = ZDWM_MOD_NONE; + for (size_t i = 0; i < countof(modifier_map); ++i) { + auto item = &modifier_map[i]; + if (mask & item->mask) mods |= item->modifier; + } + return mods; +} + +uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask) { + uint16_t mods = 0U; + for (size_t i = 0; i < countof(modifier_map); ++i) { + auto item = &modifier_map[i]; + if (mask & item->modifier) mods |= item->mask; + } + return mods; +} + +typedef struct button_map_t { + button_t zdwm_button; + xcb_button_index_t xcb_button; +} button_map_t; + +static constexpr button_map_t button_map[] = { + {ZDWM_BUTTON_LEFT, XCB_BUTTON_INDEX_1}, + {ZDWM_BUTTON_RIGHT, XCB_BUTTON_INDEX_3}, + {ZDWM_BUTTON_MIDDLE, XCB_BUTTON_INDEX_2}, + /* TODO: 后续可以考虑加上鼠标滚轮事件 */ +}; + +button_t button_xcb_to_zdwm(xcb_button_t button) { + for (size_t i = 0; i < countof(button_map); ++i) { + auto item = &button_map[i]; + if (button == item->xcb_button) return item->zdwm_button; + } + + return ZDWM_BUTTON_NONE; +} + +xcb_button_t button_zdwm_to_xcb(button_t button) { + for (size_t i = 0; i < countof(button_map); ++i) { + auto item = &button_map[i]; + if (button == item->zdwm_button) return item->xcb_button; + } + + return XCB_BUTTON_INDEX_ANY; +} diff --git a/src/backend/x11/common.h b/src/backend/x11/common.h new file mode 100644 index 0000000..91c9e8a --- /dev/null +++ b/src/backend/x11/common.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include "core/types.h" + +modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask); +uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask); + +button_t button_xcb_to_zdwm(xcb_button_t button); +xcb_button_t button_zdwm_to_xcb(button_t button); diff --git a/src/backend/x11/event.c b/src/backend/x11/event.c index cafce66..f6f8ddc 100644 --- a/src/backend/x11/event.c +++ b/src/backend/x11/event.c @@ -9,8 +9,8 @@ #include #include +#include "backend/x11/common.h" #include "backend/x11/window.h" -#include "base/macros.h" #include "base/memory.h" #include "core/backend.h" #include "core/types.h" @@ -233,29 +233,6 @@ static bool handle_configure_request( return true; } -static modifier_mask_t get_modifiers(uint16_t mask) { - typedef struct modifier_map_t { - modifier_bit_t modifier; - xcb_mod_mask_t mask; - } modifier_map_t; - static constexpr modifier_map_t modifier_map[] = { - {ZDWM_MOD_SHIFT, XCB_MOD_MASK_SHIFT}, - {ZDWM_MOD_CONTROL, XCB_MOD_MASK_CONTROL}, - {ZDWM_MOD_1, XCB_MOD_MASK_1}, - {ZDWM_MOD_2, XCB_MOD_MASK_2}, - {ZDWM_MOD_3, XCB_MOD_MASK_3}, - {ZDWM_MOD_4, XCB_MOD_MASK_4}, - {ZDWM_MOD_5, XCB_MOD_MASK_5}, - }; - - auto mods = ZDWM_MOD_NONE; - for (size_t i = 0; i < countof(modifier_map); ++i) { - auto item = &modifier_map[i]; - if (mask & item->mask) mods |= item->modifier; - } - return mods; -} - static bool handle_key_press( backend_t *backend, event_t *event, @@ -269,39 +246,18 @@ static bool handle_key_press( event->type = ZDWM_EVENT_KEY_PRESS; event->as.key_press.keycode = keycode; event->as.key_press.keysym = keysym; - event->as.key_press.modifiers = get_modifiers(xcb_event->state); + event->as.key_press.modifiers = modifiers_xcb_to_zdwm(xcb_event->state); return true; } -static bool get_button(xcb_button_t button_detail, uint32_t *button) { - assert(button != nullptr); - switch (button_detail) { - case XCB_BUTTON_INDEX_1: - *button = ZDWM_BUTTON_LEFT; - return true; - case XCB_BUTTON_INDEX_2: - *button = ZDWM_BUTTON_RIGHT; - return true; - case XCB_BUTTON_INDEX_3: - *button = ZDWM_BUTTON_MIDDLE; - return true; - case XCB_BUTTON_INDEX_4: - case XCB_BUTTON_INDEX_5: - /* TODO: 后续可以考虑加上鼠标滚轮事件 */ - default: - return false; - } -} - static bool fill_button_event( const xcb_button_press_event_t *xcb_event, pointer_button_event_t *data ) { - uint32_t button = 0; - if (!get_button(xcb_event->detail, &button)) return false; + auto button = button_xcb_to_zdwm(xcb_event->detail); - data->modifiers = get_modifiers(xcb_event->state); + data->modifiers = modifiers_xcb_to_zdwm(xcb_event->state); data->button = button; data->window = xcb_event->event; data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y}; diff --git a/src/backend/x11/window.c b/src/backend/x11/window.c index 660c9f6..7d51504 100644 --- a/src/backend/x11/window.c +++ b/src/backend/x11/window.c @@ -8,6 +8,7 @@ #include #include +#include "backend/x11/common.h" #include "backend/x11/cursor.h" #include "base/macros.h" #include "base/memory.h" @@ -463,3 +464,26 @@ void window_change_cursor( xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)}; xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, ¶ms); } + +void window_grab_button( + backend_t *backend, + xcb_window_t window, + button_t button, + modifier_mask_t modifiers +) { + auto xcb_button = button_zdwm_to_xcb(button); + if (xcb_button == XCB_BUTTON_INDEX_ANY) return; + + xcb_grab_button( + backend->conn, + false, /* 事件仅发送给抓取者,不发送给其他窗口 */ + window, + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_SYNC, + XCB_WINDOW_NONE, + XCB_CURSOR_NONE, + xcb_button, + modifiers_zdwm_to_xcb(modifiers) + ); +} diff --git a/src/backend/x11/window.h b/src/backend/x11/window.h index ae8e47e..23d6b6f 100644 --- a/src/backend/x11/window.h +++ b/src/backend/x11/window.h @@ -124,3 +124,10 @@ void window_change_cursor( xcb_window_t window, cursor_t cursor ); + +void window_grab_button( + backend_t *backend, + xcb_window_t window, + button_t button, + modifier_mask_t modifiers +); diff --git a/src/core/event.h b/src/core/event.h index 1ef45fb..07fa505 100644 --- a/src/core/event.h +++ b/src/core/event.h @@ -27,12 +27,6 @@ typedef struct key_press_event_t { uint32_t keycode; } key_press_event_t; -typedef enum button_t { - ZDWM_BUTTON_LEFT, - ZDWM_BUTTON_RIGHT, - ZDWM_BUTTON_MIDDLE, -} button_t; - typedef struct pointer_button_event_t { modifier_mask_t modifiers; button_t button; diff --git a/src/core/plan.c b/src/core/plan.c index 0146d2a..0d4bb53 100644 --- a/src/core/plan.c +++ b/src/core/plan.c @@ -20,6 +20,8 @@ static void free_memory_hold_by_effects(effect_t *effects, size_t count) { case ZDWM_EFFECT_BIND_KEY: p_delete(&effect->as.bind_key.keys); break; + case ZDWM_EFFECT_GRAB_BUTTON: + p_delete(&effect->as.grab_button.buttons); default: } } diff --git a/src/core/plan.h b/src/core/plan.h index b01d386..5e3ef31 100644 --- a/src/core/plan.h +++ b/src/core/plan.h @@ -20,6 +20,7 @@ typedef enum effect_type_t { ZDWM_EFFECT_CHANGE_WINDOW_LIST, ZDWM_EFFECT_RESTACK_WINDOWS, ZDWM_EFFECT_BIND_KEY, + ZDWM_EFFECT_GRAB_BUTTON, } effect_type_t; typedef struct effect_move_window_t { @@ -48,6 +49,12 @@ typedef struct effect_bind_key_t { size_t count; } effect_bind_key_t; +typedef struct effect_grab_button_t { + window_id_t window; + const grab_button_t *buttons; + size_t count; +} effect_grab_button_t; + typedef struct effect_bool_window_t { window_id_t window; bool value; @@ -69,6 +76,7 @@ typedef struct effect_t { effect_window_list_t change_window_list; effect_window_list_t restack_windows; effect_bind_key_t bind_key; + effect_grab_button_t grab_button; } as; } effect_t; diff --git a/src/core/policy.c b/src/core/policy.c index bf3211e..43a78b3 100644 --- a/src/core/policy.c +++ b/src/core/policy.c @@ -762,6 +762,24 @@ static void push_window_list_effect(const state_t *state, plan_t *plan) { plan_push_effect(plan, &effect); } +static void plan_push_grab_button_effect(plan_t *plan, window_id_t window) { + /* TODO: 后续会改成配置 */ + static const grab_button_t buttons[] = { + [0] = {.modifiers = ZDWM_MOD_4, .button = ZDWM_BUTTON_LEFT}, + [1] = {.modifiers = ZDWM_MOD_4, .button = ZDWM_BUTTON_RIGHT}, + }; + + constexpr const size_t count = countof(buttons); + auto btns = p_new(grab_button_t, count); + memcpy(btns, buttons, sizeof(buttons)); + + effect_t grab_button_effect = { + .type = ZDWM_EFFECT_GRAB_BUTTON, + .as.grab_button = {.window = window, .buttons = btns, .count = count}, + }; + plan_push_effect(plan, &grab_button_effect); +} + static void manage_window( const policy_context_t *ctx, const manage_window_command_t *command, @@ -774,6 +792,7 @@ static void manage_window( state_window_set_workspace(state, window_id, workspace_id); state_window_set_floating(state, window_id, command->floating); set_foucs_window(ctx, workspace_id, window_id, plan); + plan_push_grab_button_effect(plan, window_id); push_window_list_effect(state, plan); listeners_notify_window_added(ctx->listeners, state, window_id); diff --git a/src/core/types.h b/src/core/types.h index 331de7b..47f9cba 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -55,6 +55,18 @@ typedef struct key_bind_t { keysym_t keysym; } key_bind_t; +typedef enum button_t { + ZDWM_BUTTON_NONE, + ZDWM_BUTTON_LEFT, + ZDWM_BUTTON_RIGHT, + ZDWM_BUTTON_MIDDLE, +} button_t; + +typedef struct grab_button_t { + modifier_mask_t modifiers; + button_t button; +} grab_button_t; + typedef enum window_state_request_type_t { ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN, ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED,