diff options
-rw-r--r-- | include/sway/config.h | 2 | ||||
-rw-r--r-- | include/sway/input/cursor.h | 6 | ||||
-rw-r--r-- | sway/commands/bind.c | 16 | ||||
-rw-r--r-- | sway/input/cursor.c | 102 | ||||
-rw-r--r-- | sway/input/keyboard.c | 40 |
5 files changed, 139 insertions, 27 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 92536d10..bcd503a4 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -497,6 +497,8 @@ void free_sway_binding(struct sway_binding *sb); | |||
497 | 497 | ||
498 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); | 498 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); |
499 | 499 | ||
500 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | ||
501 | |||
500 | void load_swaybars(); | 502 | void load_swaybars(); |
501 | 503 | ||
502 | void invoke_swaybar(struct bar_config *bar); | 504 | void invoke_swaybar(struct bar_config *bar); |
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index b0a3a7c5..7ec45120 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h | |||
@@ -3,6 +3,8 @@ | |||
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | 5 | ||
6 | #define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 | ||
7 | |||
6 | struct sway_cursor { | 8 | struct sway_cursor { |
7 | struct sway_seat *seat; | 9 | struct sway_seat *seat; |
8 | struct wlr_cursor *cursor; | 10 | struct wlr_cursor *cursor; |
@@ -29,6 +31,10 @@ struct sway_cursor { | |||
29 | uint32_t tool_buttons; | 31 | uint32_t tool_buttons; |
30 | 32 | ||
31 | struct wl_listener request_set_cursor; | 33 | struct wl_listener request_set_cursor; |
34 | |||
35 | // Mouse binding state | ||
36 | uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; | ||
37 | size_t pressed_button_count; | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | void sway_cursor_destroy(struct sway_cursor *cursor); | 40 | void sway_cursor_destroy(struct sway_cursor *cursor); |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 6910237f..133fd089 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -267,3 +267,19 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { | |||
267 | struct cmd_results *cmd_bindcode(int argc, char **argv) { | 267 | struct cmd_results *cmd_bindcode(int argc, char **argv) { |
268 | return cmd_bindsym_or_bindcode(argc, argv, true); | 268 | return cmd_bindsym_or_bindcode(argc, argv, true); |
269 | } | 269 | } |
270 | |||
271 | |||
272 | /** | ||
273 | * Execute the command associated to a binding | ||
274 | */ | ||
275 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { | ||
276 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
277 | binding->command); | ||
278 | config->handler_context.seat = seat; | ||
279 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
280 | if (results->status != CMD_SUCCESS) { | ||
281 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
282 | binding->command, results->error); | ||
283 | } | ||
284 | free_cmd_results(results); | ||
285 | } | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 65d04cac..f1481936 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -469,6 +469,83 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
469 | seat_pointer_notify_button(seat, time_msec, button, state); | 469 | seat_pointer_notify_button(seat, time_msec, button, state); |
470 | } | 470 | } |
471 | 471 | ||
472 | /** | ||
473 | * Remove a button (and duplicates) to the sorted list of currently pressed buttons | ||
474 | */ | ||
475 | static void state_erase_button(struct sway_cursor *cursor, uint32_t button) { | ||
476 | size_t j = 0; | ||
477 | for (size_t i = 0; i < cursor->pressed_button_count; ++i) { | ||
478 | if (i > j) { | ||
479 | cursor->pressed_buttons[j] = cursor->pressed_buttons[i]; | ||
480 | } | ||
481 | if (cursor->pressed_buttons[i] != button) { | ||
482 | ++j; | ||
483 | } | ||
484 | } | ||
485 | while (cursor->pressed_button_count > j) { | ||
486 | --cursor->pressed_button_count; | ||
487 | cursor->pressed_buttons[cursor->pressed_button_count] = 0; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | /** | ||
492 | * Add a button to the sorted list of currently pressed buttons, if there | ||
493 | * is space. | ||
494 | */ | ||
495 | static void state_add_button(struct sway_cursor *cursor, uint32_t button) { | ||
496 | if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { | ||
497 | return; | ||
498 | } | ||
499 | size_t i = 0; | ||
500 | while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) { | ||
501 | ++i; | ||
502 | } | ||
503 | size_t j = cursor->pressed_button_count; | ||
504 | while (j > i) { | ||
505 | cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1]; | ||
506 | --j; | ||
507 | } | ||
508 | cursor->pressed_buttons[i] = button; | ||
509 | cursor->pressed_button_count++; | ||
510 | } | ||
511 | |||
512 | /** | ||
513 | * Return the mouse binding which matches modifier, click location, release, | ||
514 | * and pressed button state, otherwise return null. | ||
515 | */ | ||
516 | static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor, | ||
517 | list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, | ||
518 | bool on_border, bool on_content) { | ||
519 | uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | | ||
520 | (on_border ? BINDING_BORDER : 0) | | ||
521 | (on_content ? BINDING_CONTENTS : 0); | ||
522 | |||
523 | for (int i = 0; i < bindings->length; ++i) { | ||
524 | struct sway_binding *binding = bindings->items[i]; | ||
525 | if (modifiers ^ binding->modifiers || | ||
526 | cursor->pressed_button_count != (size_t)binding->keys->length || | ||
527 | release != (binding->flags & BINDING_RELEASE) || | ||
528 | !(click_region & binding->flags)) { | ||
529 | continue; | ||
530 | } | ||
531 | |||
532 | bool match = true; | ||
533 | for (size_t j = 0; j < cursor->pressed_button_count; j++) { | ||
534 | uint32_t key = *(uint32_t *)binding->keys->items[j]; | ||
535 | if (key != cursor->pressed_buttons[j]) { | ||
536 | match = false; | ||
537 | break; | ||
538 | } | ||
539 | } | ||
540 | if (!match) { | ||
541 | continue; | ||
542 | } | ||
543 | |||
544 | return binding; | ||
545 | } | ||
546 | return NULL; | ||
547 | } | ||
548 | |||
472 | void dispatch_cursor_button(struct sway_cursor *cursor, | 549 | void dispatch_cursor_button(struct sway_cursor *cursor, |
473 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { | 550 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { |
474 | if (cursor->seat->operation != OP_NONE && | 551 | if (cursor->seat->operation != OP_NONE && |
@@ -485,6 +562,31 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
485 | double sx, sy; | 562 | double sx, sy; |
486 | struct sway_container *cont = container_at_coords(cursor->seat, | 563 | struct sway_container *cont = container_at_coords(cursor->seat, |
487 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 564 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
565 | |||
566 | // Handle mouse bindings | ||
567 | bool on_border = find_resize_edge(cont, cursor) != WLR_EDGE_NONE; | ||
568 | bool on_contents = !on_border && surface; | ||
569 | bool on_titlebar = !on_border && !surface; | ||
570 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); | ||
571 | uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; | ||
572 | |||
573 | struct sway_binding *binding = NULL; | ||
574 | if (state == WLR_BUTTON_PRESSED) { | ||
575 | state_add_button(cursor, button); | ||
576 | binding = get_active_mouse_binding(cursor, | ||
577 | config->current_mode->mouse_bindings, modifiers, false, | ||
578 | on_titlebar, on_border, on_contents); | ||
579 | } else { | ||
580 | binding = get_active_mouse_binding(cursor, | ||
581 | config->current_mode->mouse_bindings, modifiers, true, | ||
582 | on_titlebar, on_border, on_contents); | ||
583 | state_erase_button(cursor, button); | ||
584 | } | ||
585 | if (binding) { | ||
586 | seat_execute_command(cursor->seat, binding); | ||
587 | // TODO: do we want to pass on the event? | ||
588 | } | ||
589 | |||
488 | if (surface && wlr_surface_is_layer_surface(surface)) { | 590 | if (surface && wlr_surface_is_layer_surface(surface)) { |
489 | struct wlr_layer_surface *layer = | 591 | struct wlr_layer_surface *layer = |
490 | wlr_layer_surface_from_wlr_surface(surface); | 592 | wlr_layer_surface_from_wlr_surface(surface); |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index e6c5c335..49241db8 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -3,11 +3,11 @@ | |||
3 | #include <wlr/backend/multi.h> | 3 | #include <wlr/backend/multi.h> |
4 | #include <wlr/backend/session.h> | 4 | #include <wlr/backend/session.h> |
5 | #include <wlr/types/wlr_idle.h> | 5 | #include <wlr/types/wlr_idle.h> |
6 | #include "sway/commands.h" | ||
6 | #include "sway/desktop/transaction.h" | 7 | #include "sway/desktop/transaction.h" |
7 | #include "sway/input/seat.h" | ||
8 | #include "sway/input/keyboard.h" | ||
9 | #include "sway/input/input-manager.h" | 8 | #include "sway/input/input-manager.h" |
10 | #include "sway/commands.h" | 9 | #include "sway/input/keyboard.h" |
10 | #include "sway/input/seat.h" | ||
11 | #include "log.h" | 11 | #include "log.h" |
12 | 12 | ||
13 | /** | 13 | /** |
@@ -88,8 +88,8 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
88 | uint32_t modifiers, bool release, bool locked) { | 88 | uint32_t modifiers, bool release, bool locked) { |
89 | for (int i = 0; i < bindings->length; ++i) { | 89 | for (int i = 0; i < bindings->length; ++i) { |
90 | struct sway_binding *binding = bindings->items[i]; | 90 | struct sway_binding *binding = bindings->items[i]; |
91 | bool binding_locked = binding->flags | BINDING_LOCKED; | 91 | bool binding_locked = binding->flags & BINDING_LOCKED; |
92 | bool binding_release = binding->flags | BINDING_RELEASE; | 92 | bool binding_release = binding->flags & BINDING_RELEASE; |
93 | 93 | ||
94 | if (modifiers ^ binding->modifiers || | 94 | if (modifiers ^ binding->modifiers || |
95 | state->npressed != (size_t)binding->keys->length || | 95 | state->npressed != (size_t)binding->keys->length || |
@@ -121,23 +121,6 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
121 | } | 121 | } |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * Execute the command associated to a binding | ||
125 | */ | ||
126 | static void keyboard_execute_command(struct sway_keyboard *keyboard, | ||
127 | struct sway_binding *binding) { | ||
128 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
129 | binding->command); | ||
130 | config->handler_context.seat = keyboard->seat_device->sway_seat; | ||
131 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
132 | transaction_commit_dirty(); | ||
133 | if (results->status != CMD_SUCCESS) { | ||
134 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
135 | binding->command, results->error); | ||
136 | } | ||
137 | free_cmd_results(results); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * Execute a built-in, hardcoded compositor binding. These are triggered from a | 124 | * Execute a built-in, hardcoded compositor binding. These are triggered from a |
142 | * single keysym. | 125 | * single keysym. |
143 | * | 126 | * |
@@ -213,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, | |||
213 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { | 196 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { |
214 | struct sway_keyboard *keyboard = | 197 | struct sway_keyboard *keyboard = |
215 | wl_container_of(listener, keyboard, keyboard_key); | 198 | wl_container_of(listener, keyboard, keyboard_key); |
216 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | 199 | struct sway_seat* seat = keyboard->seat_device->sway_seat; |
200 | struct wlr_seat *wlr_seat = seat->wlr_seat; | ||
217 | struct wlr_input_device *wlr_device = | 201 | struct wlr_input_device *wlr_device = |
218 | keyboard->seat_device->input_device->wlr_device; | 202 | keyboard->seat_device->input_device->wlr_device; |
219 | wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat); | 203 | wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); |
220 | struct wlr_event_keyboard_key *event = data; | 204 | struct wlr_event_keyboard_key *event = data; |
221 | bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; | 205 | bool input_inhibited = seat->exclusive_client != NULL; |
222 | 206 | ||
223 | // Identify new keycode, raw keysym(s), and translated keysym(s) | 207 | // Identify new keycode, raw keysym(s), and translated keysym(s) |
224 | xkb_keycode_t keycode = event->keycode + 8; | 208 | xkb_keycode_t keycode = event->keycode + 8; |
@@ -268,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
268 | // Execute stored release binding once no longer active | 252 | // Execute stored release binding once no longer active |
269 | if (keyboard->held_binding && binding_released != keyboard->held_binding && | 253 | if (keyboard->held_binding && binding_released != keyboard->held_binding && |
270 | event->state == WLR_KEY_RELEASED) { | 254 | event->state == WLR_KEY_RELEASED) { |
271 | keyboard_execute_command(keyboard, keyboard->held_binding); | 255 | seat_execute_command(seat, keyboard->held_binding); |
272 | handled = true; | 256 | handled = true; |
273 | } | 257 | } |
274 | if (binding_released != keyboard->held_binding) { | 258 | if (binding_released != keyboard->held_binding) { |
@@ -292,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
292 | raw_modifiers, false, input_inhibited); | 276 | raw_modifiers, false, input_inhibited); |
293 | 277 | ||
294 | if (binding_pressed) { | 278 | if (binding_pressed) { |
295 | keyboard_execute_command(keyboard, binding_pressed); | 279 | seat_execute_command(seat, binding_pressed); |
296 | handled = true; | 280 | handled = true; |
297 | } | 281 | } |
298 | } | 282 | } |
@@ -314,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
314 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 298 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
315 | event->keycode, event->state); | 299 | event->keycode, event->state); |
316 | } | 300 | } |
301 | |||
302 | transaction_commit_dirty(); | ||
317 | } | 303 | } |
318 | 304 | ||
319 | static void handle_keyboard_modifiers(struct wl_listener *listener, | 305 | static void handle_keyboard_modifiers(struct wl_listener *listener, |