aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-23 21:38:29 -0400
committerLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-23 21:38:29 -0400
commit94dd8823a0081f7983dce368d5d093d1d3eeaefe (patch)
treef2147f1ef4871edb4d989d26cd9b1104797d27bc
parentParse mouse binding options (diff)
downloadsway-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.
-rw-r--r--include/sway/config.h2
-rw-r--r--include/sway/input/cursor.h6
-rw-r--r--sway/commands/bind.c16
-rw-r--r--sway/input/cursor.c102
-rw-r--r--sway/input/keyboard.c40
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
498struct sway_binding *sway_binding_dup(struct sway_binding *sb); 498struct sway_binding *sway_binding_dup(struct sway_binding *sb);
499 499
500void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
501
500void load_swaybars(); 502void load_swaybars();
501 503
502void invoke_swaybar(struct bar_config *bar); 504void 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
6struct sway_cursor { 8struct 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
34void sway_cursor_destroy(struct sway_cursor *cursor); 40void 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) {
267struct cmd_results *cmd_bindcode(int argc, char **argv) { 267struct 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 */
275void 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 */
475static 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 */
495static 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 */
516static 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
472void dispatch_cursor_button(struct sway_cursor *cursor, 549void 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 */
126static 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,
213static void handle_keyboard_key(struct wl_listener *listener, void *data) { 196static 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
319static void handle_keyboard_modifiers(struct wl_listener *listener, 305static void handle_keyboard_modifiers(struct wl_listener *listener,