diff options
author | frsfnrrg <frsfnrrg@users.noreply.github.com> | 2018-07-23 21:38:29 -0400 |
---|---|---|
committer | frsfnrrg <frsfnrrg@users.noreply.github.com> | 2018-07-23 21:38:29 -0400 |
commit | 94dd8823a0081f7983dce368d5d093d1d3eeaefe (patch) | |
tree | f2147f1ef4871edb4d989d26cd9b1104797d27bc /sway/input/cursor.c | |
parent | Parse mouse binding options (diff) | |
download | sway-94dd8823a0081f7983dce368d5d093d1d3eeaefe.tar.gz sway-94dd8823a0081f7983dce368d5d093d1d3eeaefe.tar.zst sway-94dd8823a0081f7983dce368d5d093d1d3eeaefe.zip |
Invoke mouse bindings
The mouse binding logic is inspired/copied from the
keyboard binding logic; we store a sorted list of the
currently pressed buttons, and trigger a binding when
the currently pressed (or just recently pressed, in
the case of a release binding) buttons, as well as
modifiers/container region, match those of a given
binding.
As the code to execute a binding is not very keyboard
specific, keyboard_execute_command is renamed to
seat_execute_command and moved to where the other
binding handling functions are. The call to
transaction_commit_dirty has been lifted out.
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 102 |
1 files changed, 102 insertions, 0 deletions
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); |