diff --git a/src/config.h b/src/config.h index 9107c9f..abbc11e 100644 --- a/src/config.h +++ b/src/config.h @@ -80,11 +80,17 @@ const rule_t rules[] = { }, }; +#define MODIFIER_ANY XCB_MOD_MASK_ANY #define SUPER XCB_MOD_MASK_4 #define ALT XCB_MOD_MASK_1 #define CTRL XCB_MOD_MASK_CONTROL #define SHIFT XCB_MOD_MASK_SHIFT +#define BUTTON_ANY XCB_BUTTON_INDEX_ANY +#define BUTTON_LEFT XCB_BUTTON_INDEX_1 +#define BUTTON_RIGHT XCB_BUTTON_INDEX_2 +#define BUTTON_MIDDLE XCB_BUTTON_INDEX_3 + const char launcher[] = "rofi -show combi -modes window,drun,run,ssh,combi,windowcd"; const keybinding_t keys[] = { @@ -142,6 +148,11 @@ const keybinding_t keys[] = { {SUPER | SHIFT, XK_9, move_to_tag, {.ui = 1 << 8}}, }; +const button_t buttons[] = { + {click_tag, 0, BUTTON_LEFT, select_tag, {0}}, + {click_tag, SUPER, BUTTON_LEFT, move_to_tag, {0}}, +}; + const char *const bar_bg = "#222222"; const char *const tag_bg = "#222222"; const char *const active_tag_bg = "#005577"; diff --git a/src/include/types.h b/src/include/types.h index f94d5d0..dbf4223 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -183,3 +183,20 @@ typedef struct icons_t { icon_res_t cpu; icon_res_t clock; } icons_t; + +typedef enum click_area_t { + click_tag, + click_layout_symbol, + click_window_title, + click_status, + click_client_window, + click_root_win, +} click_area_t; + +typedef struct button_t { + click_area_t click_area; + uint16_t modifiers; + uint8_t button; + void (*func)(const user_action_arg_t *); + const user_action_arg_t arg; +} button_t; diff --git a/src/include/xcb.h b/src/include/xcb.h index 9b31e0b..4fea09e 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -159,3 +159,6 @@ void set_pointer_position(int32_t x, int32_t y); * @brief 非阻塞检查特定事件掩码(模拟 XCheckMaskEvent) */ bool xcb_check_mask_event(xcb_event_mask_t event_mask); + +void ungrab_any_button(xcb_window_t window); +void grab_button(xcb_window_t window, uint8_t button, uint16_t modifiers); diff --git a/src/main.c b/src/main.c index 9af4498..82aaf1a 100644 --- a/src/main.c +++ b/src/main.c @@ -59,6 +59,7 @@ static void focus_in(focus_in_event_t *event); static void property_notify(property_notify_event_t *event); static void client_message(client_message_event_t *event); static void manage_window(xcb_window_t window); +static void grab_buttons_for_client(client_t *client, bool focused); static void unmanage_client(client_t *client, bool destroyed); static void update_client_list(void); static void update_client_name(client_t *client); @@ -1030,8 +1031,10 @@ void manage_window(xcb_window_t window) { } set_client_tag_prop(c); + grab_buttons_for_client(c, false); set_window_event_mask(window, false); + change_window_border_color(window, color_set->border_color.argb); attach_client(c); @@ -1048,6 +1051,18 @@ void manage_window(xcb_window_t window) { focus(NULL); } +void grab_buttons_for_client(client_t *client, bool focused) { + ungrab_any_button(client->window); + + if (!focused) grab_button(client->window, BUTTON_ANY, MODIFIER_ANY); + + for (int i = 0; i < LENGTH(buttons); i++) { + if (buttons[i].click_area == click_client_window) { + grab_button(client->window, buttons[i].button, buttons[i].modifiers); + } + } +} + void unmanage_client(client_t *client, bool destroyed) { monitor_t *monitor = client->monitor; @@ -1231,6 +1246,7 @@ void focus(client_t *client) { if (client->monitor != current_monitor) current_monitor = client->monitor; detach_stack_client(client); attach_stack_client(client); + grab_buttons_for_client(client, true); change_window_border_color(client->window, color_set->active_border_color.argb); focus_window(client->window); @@ -1244,6 +1260,7 @@ void focus(client_t *client) { void unfocus(client_t *client, bool set_focus) { if (!client) return; + grab_buttons_for_client(client, false); change_window_border_color(client->window, color_set->border_color.argb); if (set_focus) focus_window(WINDOW_NONE); } diff --git a/src/xcb/window.c b/src/xcb/window.c index 7b23485..60845fe 100644 --- a/src/xcb/window.c +++ b/src/xcb/window.c @@ -361,3 +361,15 @@ void set_window_fullscreen_state(xcb_window_t window, bool fullscreen) { xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, atom, XCB_ATOM_WINDOW, 32, data_len, &atom); } + +void ungrab_any_button(xcb_window_t window) { + xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY); +} + +void grab_button(xcb_window_t window, uint8_t button, uint16_t modifiers) { + uint8_t owner_events = false; /* 事件仅发送给抓取者,不发送给其他窗口 */ + uint16_t event_mask = + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE; + xcb_grab_button(conn, owner_events, window, event_mask, XCB_GRAB_MODE_SYNC, + XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, button, modifiers); +}