aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
authorfrsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-23 21:38:29 -0400
committerfrsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-23 21:38:29 -0400
commit94dd8823a0081f7983dce368d5d093d1d3eeaefe (patch)
treef2147f1ef4871edb4d989d26cd9b1104797d27bc /sway
parent754372c3de1f5b357850cb58cc8ddc1aee596bd6 (diff)
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')
-rw-r--r--sway/commands/bind.c16
-rw-r--r--sway/input/cursor.c102
-rw-r--r--sway/input/keyboard.c40
3 files changed, 131 insertions, 27 deletions
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) {
struct cmd_results *cmd_bindcode(int argc, char **argv) {
return cmd_bindsym_or_bindcode(argc, argv, true);
}
+
+
+/**
+ * Execute the command associated to a binding
+ */
+void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
+ wlr_log(WLR_DEBUG, "running command for binding: %s",
+ binding->command);
+ config->handler_context.seat = seat;
+ struct cmd_results *results = execute_command(binding->command, NULL);
+ if (results->status != CMD_SUCCESS) {
+ wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
+ binding->command, results->error);
+ }
+ free_cmd_results(results);
+}
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,
seat_pointer_notify_button(seat, time_msec, button, state);
}
+/**
+ * Remove a button (and duplicates) to the sorted list of currently pressed buttons
+ */
+static void state_erase_button(struct sway_cursor *cursor, uint32_t button) {
+ size_t j = 0;
+ for (size_t i = 0; i < cursor->pressed_button_count; ++i) {
+ if (i > j) {
+ cursor->pressed_buttons[j] = cursor->pressed_buttons[i];
+ }
+ if (cursor->pressed_buttons[i] != button) {
+ ++j;
+ }
+ }
+ while (cursor->pressed_button_count > j) {
+ --cursor->pressed_button_count;
+ cursor->pressed_buttons[cursor->pressed_button_count] = 0;
+ }
+}
+
+/**
+ * Add a button to the sorted list of currently pressed buttons, if there
+ * is space.
+ */
+static void state_add_button(struct sway_cursor *cursor, uint32_t button) {
+ if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) {
+ return;
+ }
+ size_t i = 0;
+ while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) {
+ ++i;
+ }
+ size_t j = cursor->pressed_button_count;
+ while (j > i) {
+ cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1];
+ --j;
+ }
+ cursor->pressed_buttons[i] = button;
+ cursor->pressed_button_count++;
+}
+
+/**
+ * Return the mouse binding which matches modifier, click location, release,
+ * and pressed button state, otherwise return null.
+ */
+static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor,
+ list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar,
+ bool on_border, bool on_content) {
+ uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) |
+ (on_border ? BINDING_BORDER : 0) |
+ (on_content ? BINDING_CONTENTS : 0);
+
+ for (int i = 0; i < bindings->length; ++i) {
+ struct sway_binding *binding = bindings->items[i];
+ if (modifiers ^ binding->modifiers ||
+ cursor->pressed_button_count != (size_t)binding->keys->length ||
+ release != (binding->flags & BINDING_RELEASE) ||
+ !(click_region & binding->flags)) {
+ continue;
+ }
+
+ bool match = true;
+ for (size_t j = 0; j < cursor->pressed_button_count; j++) {
+ uint32_t key = *(uint32_t *)binding->keys->items[j];
+ if (key != cursor->pressed_buttons[j]) {
+ match = false;
+ break;
+ }
+ }
+ if (!match) {
+ continue;
+ }
+
+ return binding;
+ }
+ return NULL;
+}
+
void dispatch_cursor_button(struct sway_cursor *cursor,
uint32_t time_msec, uint32_t button, enum wlr_button_state state) {
if (cursor->seat->operation != OP_NONE &&
@@ -485,6 +562,31 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
double sx, sy;
struct sway_container *cont = container_at_coords(cursor->seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
+
+ // Handle mouse bindings
+ bool on_border = find_resize_edge(cont, cursor) != WLR_EDGE_NONE;
+ bool on_contents = !on_border && surface;
+ bool on_titlebar = !on_border && !surface;
+ struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat);
+ uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
+
+ struct sway_binding *binding = NULL;
+ if (state == WLR_BUTTON_PRESSED) {
+ state_add_button(cursor, button);
+ binding = get_active_mouse_binding(cursor,
+ config->current_mode->mouse_bindings, modifiers, false,
+ on_titlebar, on_border, on_contents);
+ } else {
+ binding = get_active_mouse_binding(cursor,
+ config->current_mode->mouse_bindings, modifiers, true,
+ on_titlebar, on_border, on_contents);
+ state_erase_button(cursor, button);
+ }
+ if (binding) {
+ seat_execute_command(cursor->seat, binding);
+ // TODO: do we want to pass on the event?
+ }
+
if (surface && wlr_surface_is_layer_surface(surface)) {
struct wlr_layer_surface *layer =
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 @@
#include <wlr/backend/multi.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_idle.h>
+#include "sway/commands.h"
#include "sway/desktop/transaction.h"
-#include "sway/input/seat.h"
-#include "sway/input/keyboard.h"
#include "sway/input/input-manager.h"
-#include "sway/commands.h"
+#include "sway/input/keyboard.h"
+#include "sway/input/seat.h"
#include "log.h"
/**
@@ -88,8 +88,8 @@ static void get_active_binding(const struct sway_shortcut_state *state,
uint32_t modifiers, bool release, bool locked) {
for (int i = 0; i < bindings->length; ++i) {
struct sway_binding *binding = bindings->items[i];
- bool binding_locked = binding->flags | BINDING_LOCKED;
- bool binding_release = binding->flags | BINDING_RELEASE;
+ bool binding_locked = binding->flags & BINDING_LOCKED;
+ bool binding_release = binding->flags & BINDING_RELEASE;
if (modifiers ^ binding->modifiers ||
state->npressed != (size_t)binding->keys->length ||
@@ -121,23 +121,6 @@ static void get_active_binding(const struct sway_shortcut_state *state,
}
/**
- * Execute the command associated to a binding
- */
-static void keyboard_execute_command(struct sway_keyboard *keyboard,
- struct sway_binding *binding) {
- wlr_log(WLR_DEBUG, "running command for binding: %s",
- binding->command);
- config->handler_context.seat = keyboard->seat_device->sway_seat;
- struct cmd_results *results = execute_command(binding->command, NULL);
- transaction_commit_dirty();
- if (results->status != CMD_SUCCESS) {
- wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
- binding->command, results->error);
- }
- free_cmd_results(results);
-}
-
-/**
* Execute a built-in, hardcoded compositor binding. These are triggered from a
* single keysym.
*
@@ -213,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
static void handle_keyboard_key(struct wl_listener *listener, void *data) {
struct sway_keyboard *keyboard =
wl_container_of(listener, keyboard, keyboard_key);
- struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
+ struct sway_seat* seat = keyboard->seat_device->sway_seat;
+ struct wlr_seat *wlr_seat = seat->wlr_seat;
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
- wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat);
+ wlr_idle_notify_activity(seat->input->server->idle, wlr_seat);
struct wlr_event_keyboard_key *event = data;
- bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL;
+ bool input_inhibited = seat->exclusive_client != NULL;
// Identify new keycode, raw keysym(s), and translated keysym(s)
xkb_keycode_t keycode = event->keycode + 8;
@@ -268,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
// Execute stored release binding once no longer active
if (keyboard->held_binding && binding_released != keyboard->held_binding &&
event->state == WLR_KEY_RELEASED) {
- keyboard_execute_command(keyboard, keyboard->held_binding);
+ seat_execute_command(seat, keyboard->held_binding);
handled = true;
}
if (binding_released != keyboard->held_binding) {
@@ -292,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
raw_modifiers, false, input_inhibited);
if (binding_pressed) {
- keyboard_execute_command(keyboard, binding_pressed);
+ seat_execute_command(seat, binding_pressed);
handled = true;
}
}
@@ -314,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
}
+
+ transaction_commit_dirty();
}
static void handle_keyboard_modifiers(struct wl_listener *listener,