From 3d6440ec26f2b39c54fd03aa3a3c822a8a2bbc72 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 10 Jan 2019 12:43:10 -0500 Subject: [PATCH] bar_cmd_bind: utilize mouse button helpers This modifies `bar_cmd_bindsym` to use `get_mouse_bindsym` for parsing mouse buttons. This also introduces `cmd_bar_bindcode`, which will use `get_mouse_bindcode` for parsing mouse buttons. Like sway bindings, the two commands are encapsulated in a single file with shared code. This also modifies swaybar to operate off of event codes rather than x11 button numbers, which allows for any mouse button to be used. This introduces two new IPC properties: - For `get_bar_config`, `event_code` has been added to the `bindings` section and will include to event code for the button. If the event code can be mapped to a x11 button, `input_code` will still be the x11 button number. Otherwise, `input_code` will be `0`. - Likewise for `click_events`, `event` has been added and will include the event code for the button clicked. If the event code can be mapped to a x11 button, `button` will still be the x11 button number. Otherwise, `button` will be `0`. --- include/sway/commands.h | 1 + include/swaybar/i3bar.h | 2 +- include/swaybar/input.h | 9 ++- sway/commands/bar.c | 1 + sway/commands/bar/bind.c | 106 ++++++++++++++++++++++++++++++++++++ sway/commands/bar/bindsym.c | 68 ----------------------- sway/ipc-json.c | 29 ++++++++++ sway/meson.build | 2 +- sway/sway-bar.5.scd | 16 ++++-- swaybar/i3bar.c | 31 ++++++++++- swaybar/input.c | 36 ++++-------- swaybar/ipc.c | 2 +- swaybar/render.c | 19 ++++--- 13 files changed, 208 insertions(+), 114 deletions(-) create mode 100644 sway/commands/bar/bind.c delete mode 100644 sway/commands/bar/bindsym.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 7d0ff8388..ffc18789d 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -183,6 +183,7 @@ sway_cmd cmd_workspace; sway_cmd cmd_ws_auto_back_and_forth; sway_cmd cmd_workspace_layout; +sway_cmd bar_cmd_bindcode; sway_cmd bar_cmd_binding_mode_indicator; sway_cmd bar_cmd_bindsym; sway_cmd bar_cmd_colors; diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h index ab4744a50..aa4415ff2 100644 --- a/include/swaybar/i3bar.h +++ b/include/swaybar/i3bar.h @@ -28,6 +28,6 @@ void i3bar_block_unref(struct i3bar_block *block); bool i3bar_handle_readable(struct status_line *status); enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, struct i3bar_block *block, int x, int y, int rx, int ry, int w, int h, - enum x11_button button); + uint32_t button); #endif diff --git a/include/swaybar/input.h b/include/swaybar/input.h index f480d009b..4b46b0de7 100644 --- a/include/swaybar/input.h +++ b/include/swaybar/input.h @@ -4,6 +4,11 @@ #include #include "list.h" +#define SWAY_SCROLL_UP KEY_MAX + 1 +#define SWAY_SCROLL_DOWN KEY_MAX + 2 +#define SWAY_SCROLL_LEFT KEY_MAX + 3 +#define SWAY_SCROLL_RIGHT KEY_MAX + 4 + struct swaybar; struct swaybar_output; @@ -39,8 +44,8 @@ struct swaybar_hotspot { struct wl_list link; // swaybar_output::hotspots int x, y, width, height; enum hotspot_event_handling (*callback)(struct swaybar_output *output, - struct swaybar_hotspot *hotspot, int x, int y, - enum x11_button button, void *data); + struct swaybar_hotspot *hotspot, int x, int y, uint32_t button, + void *data); void (*destroy)(void *data); void *data; }; diff --git a/sway/commands/bar.c b/sway/commands/bar.c index 507ee10a9..ee5a8ebf9 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c @@ -8,6 +8,7 @@ // Must be in alphabetical order for bsearch static struct cmd_handler bar_handlers[] = { + { "bindcode", bar_cmd_bindcode }, { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, { "bindsym", bar_cmd_bindsym }, { "colors", bar_cmd_colors }, diff --git a/sway/commands/bar/bind.c b/sway/commands/bar/bind.c new file mode 100644 index 000000000..a4c65ec42 --- /dev/null +++ b/sway/commands/bar/bind.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input/cursor.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code) { + const char *command = code ? "bar bindcode" : "bar bindsym"; + struct cmd_results *error = NULL; + if ((error = checkarg(argc, command, EXPECTED_AT_LEAST, 2))) { + return error; + } + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, command, "No bar defined."); + } + + struct bar_binding *binding = calloc(1, sizeof(struct bar_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, command, + "Unable to allocate bar binding"); + } + + binding->release = false; + if (strcmp("--release", argv[0]) == 0) { + binding->release = true; + argv++; + argc--; + } + + char *message = NULL; + if (code) { + binding->button = get_mouse_bindcode(argv[0], &message); + } else { + binding->button = get_mouse_bindsym(argv[0], &message); + } + if (message) { + free_bar_binding(binding); + error = cmd_results_new(CMD_INVALID, command, message); + free(message); + return error; + } else if (!binding->button) { + free_bar_binding(binding); + return cmd_results_new(CMD_INVALID, command, + "Unknown button %s", argv[0]); + } + + const char *name = libevdev_event_code_get_name(EV_KEY, binding->button); + if (!name) { + switch (binding->button) { + case SWAY_SCROLL_UP: + name = "SWAY_SCROLL_UP"; + break; + case SWAY_SCROLL_DOWN: + name = "SWAY_SCROLL_DOWN"; + break; + case SWAY_SCROLL_LEFT: + name = "SWAY_SCROLL_LEFT"; + break; + case SWAY_SCROLL_RIGHT: + name = "SWAY_SCROLL_RIGHT"; + break; + default: + // Unreachable + break; + } + } + + binding->command = join_args(argv + 1, argc - 1); + + list_t *bindings = config->current_bar->bindings; + bool overwritten = false; + for (int i = 0; i < bindings->length; i++) { + struct bar_binding *other = bindings->items[i]; + if (other->button == binding->button && + other->release == binding->release) { + overwritten = true; + bindings->items[i] = binding; + free_bar_binding(other); + wlr_log(WLR_DEBUG, "[bar %s] Updated binding for %u (%s)%s", + config->current_bar->id, binding->button, name, + binding->release ? " - release" : ""); + break; + } + } + if (!overwritten) { + list_add(bindings, binding); + wlr_log(WLR_DEBUG, "[bar %s] Added binding for %u (%s)%s", + config->current_bar->id, binding->button, name, + binding->release ? " - release" : ""); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_bindcode(int argc, char **argv) { + return bar_cmd_bind(argc, argv, true); +} + +struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { + return bar_cmd_bind(argc, argv, false); +} diff --git a/sway/commands/bar/bindsym.c b/sway/commands/bar/bindsym.c deleted file mode 100644 index e6d6220e1..000000000 --- a/sway/commands/bar/bindsym.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "list.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bar bindsym", EXPECTED_AT_LEAST, 2))) { - return error; - } - if (!config->current_bar) { - return cmd_results_new(CMD_FAILURE, "bar bindsym", "No bar defined."); - } - - struct bar_binding *binding = calloc(1, sizeof(struct bar_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "bar bindsym", - "Unable to allocate bar binding"); - } - - binding->release = false; - if (strcmp("--release", argv[0]) == 0) { - binding->release = true; - argv++; - argc--; - } - - binding->button = 0; - if (strncasecmp(argv[0], "button", strlen("button")) == 0 && - strlen(argv[0]) == strlen("button0")) { - binding->button = argv[0][strlen("button")] - '0'; - } - if (binding->button < 1 || binding->button > 9) { - free_bar_binding(binding); - return cmd_results_new(CMD_FAILURE, "bar bindsym", - "Only button<1-9> is supported"); - } - - binding->command = join_args(argv + 1, argc - 1); - - list_t *bindings = config->current_bar->bindings; - bool overwritten = false; - for (int i = 0; i < bindings->length; i++) { - struct bar_binding *other = bindings->items[i]; - if (other->button == binding->button && - other->release == binding->release) { - overwritten = true; - bindings->items[i] = binding; - free_bar_binding(other); - wlr_log(WLR_DEBUG, "[bar %s] Updated binding for button%u%s", - config->current_bar->id, binding->button, - binding->release ? " (release)" : ""); - break; - } - } - if (!overwritten) { - list_add(bindings, binding); - wlr_log(WLR_DEBUG, "[bar %s] Added binding for button%u%s", - config->current_bar->id, binding->button, - binding->release ? " (release)" : ""); - } - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 53e0e3353..616023435 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1,4 +1,5 @@ #include +#include #include #include #include "config.h" @@ -10,6 +11,7 @@ #include "sway/tree/workspace.h" #include "sway/output.h" #include "sway/input/input-manager.h" +#include "sway/input/cursor.h" #include "sway/input/seat.h" #include #include @@ -626,6 +628,31 @@ json_object *ipc_json_describe_seat(struct sway_seat *seat) { return object; } +static uint32_t event_to_x11_button(uint32_t event) { + switch (event) { + case BTN_LEFT: + return 1; + case BTN_MIDDLE: + return 2; + case BTN_RIGHT: + return 3; + case SWAY_SCROLL_UP: + return 4; + case SWAY_SCROLL_DOWN: + return 5; + case SWAY_SCROLL_LEFT: + return 6; + case SWAY_SCROLL_RIGHT: + return 7; + case BTN_SIDE: + return 8; + case BTN_EXTRA: + return 9; + default: + return 0; + } +} + json_object *ipc_json_describe_bar_config(struct bar_config *bar) { if (!sway_assert(bar, "Bar must not be NULL")) { return NULL; @@ -767,6 +794,8 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { struct bar_binding *binding = bar->bindings->items[i]; json_object *bind = json_object_new_object(); json_object_object_add(bind, "input_code", + json_object_new_int(event_to_x11_button(binding->button))); + json_object_object_add(bind, "event_code", json_object_new_int(binding->button)); json_object_object_add(bind, "command", json_object_new_string(binding->command)); diff --git a/sway/meson.build b/sway/meson.build index 98676ce0f..9518c62b9 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -100,8 +100,8 @@ sway_sources = files( 'commands/workspace_layout.c', 'commands/ws_auto_back_and_forth.c', + 'commands/bar/bind.c', 'commands/bar/binding_mode_indicator.c', - 'commands/bar/bindsym.c', 'commands/bar/colors.c', 'commands/bar/font.c', 'commands/bar/gaps.c', diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 2357591d3..ac1949b70 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd @@ -71,10 +71,18 @@ Sway allows configuring swaybar in the sway configuration file. *height* Sets the height of the bar. Default height will match the font size. -*bindsym* [--release] button - Executes _command_ when mouse button _n_ has been pressed (or if _released_ - is given, when mouse button _n_ has been released). To disable the default - behavior for a button, use the command _nop_. +*bindcode* [--release] + Executes _command_ when the mouse button has been pressed (or if _released_ + is given, when the button has been released). The buttons can be given as + an event code, which can be obtaining from `libinput debug-events`. To + disable the default behavior for a button, use the command _nop_. + +*bindsym* [--release] button[1-9]| + Executes _command_ when the mouse button has been pressed (or if _released_ + is given, when the button has been released). The buttons can be given as a + x11 button number or an event name, which can be obtained from `libinput + debug-events`. To disable the default behavior for a button, use the + command _nop_. *mode* dock|hide|invisible Specifies the visibility of the bar. In _dock_ mode, it is permanently diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 54607a3ae..116c8f6e4 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -259,9 +259,34 @@ bool i3bar_handle_readable(struct status_line *status) { } } +static uint32_t event_to_x11_button(uint32_t event) { + switch (event) { + case BTN_LEFT: + return 1; + case BTN_MIDDLE: + return 2; + case BTN_RIGHT: + return 3; + case SWAY_SCROLL_UP: + return 4; + case SWAY_SCROLL_DOWN: + return 5; + case SWAY_SCROLL_LEFT: + return 6; + case SWAY_SCROLL_RIGHT: + return 7; + case BTN_SIDE: + return 8; + case BTN_EXTRA: + return 9; + default: + return 0; + } +} + enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, struct i3bar_block *block, int x, int y, int rx, int ry, int w, int h, - enum x11_button button) { + uint32_t button) { wlr_log(WLR_DEBUG, "block %s clicked", block->name); if (!block->name || !status->click_events) { return HOTSPOT_PROCESS; @@ -275,7 +300,9 @@ enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, json_object_new_string(block->instance)); } - json_object_object_add(event_json, "button", json_object_new_int(button)); + json_object_object_add(event_json, "button", + json_object_new_int(event_to_x11_button(button))); + json_object_object_add(event_json, "event", json_object_new_int(button)); json_object_object_add(event_json, "x", json_object_new_int(x)); json_object_object_add(event_json, "y", json_object_new_int(y)); json_object_object_add(event_json, "relative_x", json_object_new_int(rx)); diff --git a/swaybar/input.c b/swaybar/input.c index 620da977a..bdd55e58a 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -22,32 +22,16 @@ void free_hotspots(struct wl_list *list) { } } -static enum x11_button wl_button_to_x11_button(uint32_t button) { - switch (button) { - case BTN_LEFT: - return LEFT; - case BTN_MIDDLE: - return MIDDLE; - case BTN_RIGHT: - return RIGHT; - case BTN_SIDE: - return BACK; - case BTN_EXTRA: - return FORWARD; - default: - return NONE; - } -} - -static enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value) { +static uint32_t wl_axis_to_button(uint32_t axis, wl_fixed_t value) { + bool negative = wl_fixed_to_double(value) < 0; switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: - return wl_fixed_to_double(value) < 0 ? SCROLL_UP : SCROLL_DOWN; + return negative ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - return wl_fixed_to_double(value) < 0 ? SCROLL_LEFT : SCROLL_RIGHT; + return negative ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT; default: wlr_log(WLR_DEBUG, "Unexpected axis value on mouse scroll"); - return NONE; + return 0; } } @@ -102,12 +86,12 @@ static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, bar->pointer.y = wl_fixed_to_int(surface_y); } -static bool check_bindings(struct swaybar *bar, uint32_t x11_button, +static bool check_bindings(struct swaybar *bar, uint32_t button, uint32_t state) { bool released = state == WL_POINTER_BUTTON_STATE_RELEASED; for (int i = 0; i < bar->config->bindings->length; i++) { struct swaybar_binding *binding = bar->config->bindings->items[i]; - if (binding->button == x11_button && binding->release == released) { + if (binding->button == button && binding->release == released) { ipc_execute_binding(bar, binding); return true; } @@ -124,7 +108,7 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, return; } - if (check_bindings(bar, wl_button_to_x11_button(button), state)) { + if (check_bindings(bar, button, state)) { return; } @@ -140,7 +124,7 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, && x < hotspot->x + hotspot->width && y < hotspot->y + hotspot->height) { if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, - pointer->x, pointer->y, wl_button_to_x11_button(button), hotspot->data)) { + pointer->x, pointer->y, button, hotspot->data)) { return; } } @@ -158,7 +142,7 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, // If there is a button press binding, execute it, skip default behavior, // and check button release bindings - enum x11_button button = wl_axis_to_x11_button(axis, value); + uint32_t button = wl_axis_to_button(axis, value); if (check_bindings(bar, button, WL_POINTER_BUTTON_STATE_PRESSED)) { check_bindings(bar, button, WL_POINTER_BUTTON_STATE_RELEASED); return; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 8e7a542ee..ba53d95d8 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -237,7 +237,7 @@ static bool ipc_parse_config( struct swaybar_binding *binding = calloc(1, sizeof(struct swaybar_binding)); binding->button = json_object_get_int( - json_object_object_get(bindobj, "input_code")); + json_object_object_get(bindobj, "event_code")); binding->command = strdup(json_object_get_string( json_object_object_get(bindobj, "command"))); binding->release = json_object_get_boolean( diff --git a/swaybar/render.c b/swaybar/render.c index 7cbcea07f..670e8e743 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -126,13 +127,13 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, } } -static enum hotspot_event_handling block_hotspot_callback(struct swaybar_output *output, - struct swaybar_hotspot *hotspot, - int x, int y, enum x11_button button, void *data) { +static enum hotspot_event_handling block_hotspot_callback( + struct swaybar_output *output, struct swaybar_hotspot *hotspot, + int x, int y, uint32_t button, void *data) { struct i3bar_block *block = data; struct status_line *status = output->bar->status; - return i3bar_block_send_click(status, block, x, y, x - hotspot->x, y - hotspot->y, - hotspot->width, hotspot->height, button); + return i3bar_block_send_click(status, block, x, y, x - hotspot->x, + y - hotspot->y, hotspot->width, hotspot->height, button); } static void i3bar_block_unref_callback(void *data) { @@ -360,10 +361,10 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo, return output->height; } -static enum hotspot_event_handling workspace_hotspot_callback(struct swaybar_output *output, - struct swaybar_hotspot *hotspot, - int x, int y, enum x11_button button, void *data) { - if (button != LEFT) { +static enum hotspot_event_handling workspace_hotspot_callback( + struct swaybar_output *output, struct swaybar_hotspot *hotspot, + int x, int y, uint32_t button, void *data) { + if (button != BTN_LEFT) { return HOTSPOT_PROCESS; } ipc_send_workspace_command(output->bar, (const char *)data);