diff --git a/include/sway/commands.h b/include/sway/commands.h index 013a7b826..c95678d80 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -202,6 +202,7 @@ sway_cmd cmd_ws_auto_back_and_forth; sway_cmd cmd_xwayland; sway_cmd bar_cmd_bindcode; +sway_cmd bar_cmd_bindgesture; sway_cmd bar_cmd_binding_mode_indicator; sway_cmd bar_cmd_bindsym; sway_cmd bar_cmd_colors; @@ -228,6 +229,7 @@ sway_cmd bar_cmd_tray_bindsym; sway_cmd bar_cmd_tray_output; sway_cmd bar_cmd_tray_padding; sway_cmd bar_cmd_unbindcode; +sway_cmd bar_cmd_unbindgesture; sway_cmd bar_cmd_unbindsym; sway_cmd bar_cmd_wrap_scroll; sway_cmd bar_cmd_workspace_buttons; diff --git a/include/sway/config.h b/include/sway/config.h index 68c068462..4b7a29085 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -350,6 +350,7 @@ struct bar_config { list_t *outputs; char *position; list_t *bindings; + list_t *gestures; char *status_command; enum pango_markup_config pango_markup; char *font; @@ -403,6 +404,11 @@ struct bar_binding { char *command; }; +struct bar_gesture { + struct gesture gesture; + char *command; +}; + #if HAVE_TRAY struct tray_binding { uint32_t button; @@ -713,6 +719,8 @@ void free_bar_config(struct bar_config *bar); void free_bar_binding(struct bar_binding *binding); +void free_bar_gesture(struct bar_gesture *binding); + void free_workspace_config(struct workspace_config *wsc); /** diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 3ad0bdf3c..8505b0968 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -6,6 +6,7 @@ #include "pool-buffer.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" +#include "pointer-gestures-unstable-v1-client-protocol.h" struct swaybar_config; struct swaybar_output; @@ -31,6 +32,7 @@ struct swaybar { struct zwlr_layer_shell_v1 *layer_shell; struct zxdg_output_manager_v1 *xdg_output_manager; struct wl_shm *shm; + struct zwp_pointer_gestures_v1 *pointer_gestures; struct swaybar_config *config; struct status_line *status; diff --git a/include/swaybar/config.h b/include/swaybar/config.h index 361acd991..6aef6f9f8 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -4,6 +4,7 @@ #include #include #include "../include/config.h" +#include "gesture.h" #include "list.h" #include "util.h" #include @@ -25,6 +26,11 @@ struct swaybar_binding { bool release; }; +struct swaybar_gesture { + struct gesture gesture; + char *command; +}; + struct swaybar_config { char *status_command; bool pango_markup; @@ -41,6 +47,7 @@ struct swaybar_config { bool workspace_buttons; uint32_t workspace_min_width; list_t *bindings; + list_t *gestures; struct wl_list outputs; // config_output::link int height; int status_padding; @@ -91,5 +98,6 @@ struct swaybar_config *init_config(void); void free_config(struct swaybar_config *config); uint32_t parse_position(const char *position); void free_binding(struct swaybar_binding *binding); +void free_gesture(struct swaybar_gesture *gesture); #endif diff --git a/include/swaybar/input.h b/include/swaybar/input.h index e8735d883..bcb4de384 100644 --- a/include/swaybar/input.h +++ b/include/swaybar/input.h @@ -3,6 +3,7 @@ #include #include +#include "gesture.h" #include "list.h" #define SWAY_SCROLL_UP KEY_MAX + 1 @@ -66,6 +67,10 @@ struct swaybar_seat { struct wl_seat *wl_seat; struct swaybar_pointer pointer; struct swaybar_touch touch; + struct zwp_pointer_gesture_hold_v1 *hold; + struct zwp_pointer_gesture_pinch_v1 *pinch; + struct zwp_pointer_gesture_swipe_v1 *swipe; + struct gesture_tracker gestures; struct wl_list link; // swaybar_seat:link struct swaybar_scroll_axis axis[2]; }; diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h index d8cd0c761..2d2330695 100644 --- a/include/swaybar/ipc.h +++ b/include/swaybar/ipc.h @@ -8,5 +8,6 @@ bool handle_ipc_readable(struct swaybar *bar); bool ipc_get_workspaces(struct swaybar *bar); void ipc_send_workspace_command(struct swaybar *bar, const char *ws); void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); +void ipc_execute_gesture(struct swaybar *bar, struct swaybar_gesture *gest); #endif diff --git a/protocols/meson.build b/protocols/meson.build index df24a4e59..4ddf3b483 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -14,6 +14,7 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], @@ -25,6 +26,7 @@ protocols = [ client_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-input-inhibitor-unstable-v1.xml'], ] diff --git a/sway/commands/bar.c b/sway/commands/bar.c index 8571d282c..8a47dc34c 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c @@ -10,6 +10,7 @@ // Must be in alphabetical order for bsearch static const struct cmd_handler bar_handlers[] = { { "bindcode", bar_cmd_bindcode }, + { "bindgesture", bar_cmd_bindgesture }, { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, { "bindsym", bar_cmd_bindsym }, { "colors", bar_cmd_colors }, @@ -34,6 +35,7 @@ static const struct cmd_handler bar_handlers[] = { { "tray_output", bar_cmd_tray_output }, { "tray_padding", bar_cmd_tray_padding }, { "unbindcode", bar_cmd_unbindcode }, + { "unbindgesture", bar_cmd_unbindgesture }, { "unbindsym", bar_cmd_unbindsym }, { "workspace_buttons", bar_cmd_workspace_buttons }, { "workspace_min_width", bar_cmd_workspace_min_width }, diff --git a/sway/commands/bar/gesture.c b/sway/commands/bar/gesture.c new file mode 100644 index 000000000..9cf48e003 --- /dev/null +++ b/sway/commands/bar/gesture.c @@ -0,0 +1,109 @@ +#define _POSIX_C_SOURCE 200809L +#include "sway/config.h" + +#include +#include "log.h" +#include "stringop.h" +#include "sway/commands.h" + +/** + * Add gesture binding to config + */ +static struct cmd_results *bar_gesture_add( + struct bar_gesture *binding, const char *name) { + list_t *gestures = config->current_bar->gestures; + + // overwrite the binding if it already exists + bool overwritten = false; + for (int i = 0; i < gestures->length; ++i) { + struct bar_gesture *current = gestures->items[i]; + if (gesture_equal(¤t->gesture, &binding->gesture)) { + + overwritten = true; + gestures->items[i] = binding; + free_bar_gesture(current); + sway_log(SWAY_DEBUG, "[bar %s] Updated gesture for %s", + config->current_bar->id, name); + break; + } + } + + if (!overwritten) { + list_add(gestures, binding); + sway_log(SWAY_DEBUG, "[bar %s] Added binding for %s", + config->current_bar->id, name); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} + +/** + * Remove gesture binding from config + */ +static struct cmd_results *bar_gesture_remove( + struct bar_gesture *binding, const char *name) { + list_t *gestures = config->current_bar->gestures; + + for (int i = 0; i < gestures->length; ++i) { + struct bar_gesture *current = gestures->items[i]; + if (gesture_equal(¤t->gesture, &binding->gesture)) { + sway_log(SWAY_DEBUG, "[bar %s] Unbound binding for %s", + config->current_bar->id, name); + + free_bar_gesture(current); + free_bar_gesture(binding); + list_del(gestures, i); + + return cmd_results_new(CMD_SUCCESS, NULL); + } + } + + free_bar_gesture(binding); + return cmd_results_new(CMD_FAILURE, + "Could not find gesture for [bar %s] %s", + config->current_bar->id, name); +} + +/** + * Parse and execute bindgesture or unbindgesture command. + */ +static struct cmd_results *bar_cmd_gesture(int argc, char **argv, bool unbind) { + int minargs = 2; + char *bindtype = "bindgesture"; + if (unbind) { + minargs--; + bindtype = "unbindgesture"; + } + + struct cmd_results *error = NULL; + if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) { + return error; + } + + struct bar_gesture *binding = calloc(1, sizeof(struct bar_gesture)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "Unable to allocate binding"); + } + char *errmsg = NULL; + if ((errmsg = gesture_parse(argv[0], &binding->gesture))) { + free(binding); + struct cmd_results *final = cmd_results_new( + CMD_FAILURE, "Invalid %s command (%s)", bindtype, errmsg); + free(errmsg); + return final; + } + + if (unbind) { + return bar_gesture_remove(binding, argv[0]); + } + binding->command = join_args(argv + 1, argc - 1); + return bar_gesture_add(binding, argv[0]); +} + +struct cmd_results *bar_cmd_bindgesture(int argc, char **argv) { + return bar_cmd_gesture(argc, argv, false); +} + +struct cmd_results *bar_cmd_unbindgesture(int argc, char **argv) { + return bar_cmd_gesture(argc, argv, true); +} diff --git a/sway/config/bar.c b/sway/config/bar.c index d1b342e69..4c567a397 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -27,6 +27,14 @@ void free_bar_binding(struct bar_binding *binding) { free(binding); } +void free_bar_gesture(struct bar_gesture *gesture) { + if (!gesture) { + return; + } + free(gesture->command); + free(gesture); +} + void free_bar_config(struct bar_config *bar) { if (!bar) { return; @@ -45,6 +53,12 @@ void free_bar_config(struct bar_config *bar) { } } list_free(bar->bindings); + if (bar->gestures) { + for (int i = 0; i < bar->gestures->length; i++) { + free_bar_gesture(bar->gestures->items[i]); + } + } + list_free(bar->gestures); list_free_items_and_destroy(bar->outputs); if (bar->client != NULL) { wl_client_destroy(bar->client); @@ -115,6 +129,9 @@ struct bar_config *default_bar_config(void) { if (!(bar->bindings = create_list())) { goto cleanup; } + if (!(bar->gestures = create_list())) { + goto cleanup; + } // set default colors if (!(bar->colors.background = strndup("#000000ff", 9))) { goto cleanup; diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 61613f538..42f664a75 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1298,6 +1298,25 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { json_object_object_add(json, "bindings", bindings); } + if (bar->gestures->length > 0) { + json_object *gestures = json_object_new_array(); + for (int i = 0; i < bar->gestures->length; ++i) { + struct bar_gesture *binding = bar->gestures->items[i]; + struct gesture *gesture = &binding->gesture; + json_object *bind = json_object_new_object(); + json_object_object_add(bind, "type", + json_object_new_int(gesture->type)); + json_object_object_add(bind, "fingers", + json_object_new_int(gesture->fingers)); + json_object_object_add(bind, "directions", + json_object_new_int(gesture->directions)); + json_object_object_add(bind, "command", + json_object_new_string(binding->command)); + json_object_array_add(gestures, bind); + } + json_object_object_add(json, "gestures", gestures); + } + // Add outputs if defined if (bar->outputs && bar->outputs->length > 0) { json_object *outputs = json_object_new_array(); diff --git a/sway/meson.build b/sway/meson.build index ced7419cd..eb4a58ea3 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -128,6 +128,7 @@ sway_sources = files( 'commands/bar/colors.c', 'commands/bar/font.c', 'commands/bar/gaps.c', + 'commands/bar/gesture.c', 'commands/bar/height.c', 'commands/bar/hidden_state.c', 'commands/bar/icon_theme.c', diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 42e59d57d..6700ce1eb 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd @@ -27,6 +27,14 @@ runtime. an event code, which can be obtaining from *libinput debug-events*. To disable the default behavior for a button, use the command _nop_. +*bindgesture* [:][:directions] + Executes _command_ when the _gesture_ has been detected. _gesture_ can be + _hold_, _pinch_ or _swipe_. The optional _fingers_ allows you to limit the + binding to gestures with only a certain number of finger. The optional + _directions_ allows you to limit the binding to a gesture in a certain + direction, i.e. either _up_, _down_, _left_ or _right_ as well as + _inward_, _outward_, _clockwise_ and _counterclockwise_. + *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 @@ -128,6 +136,9 @@ runtime. *unbindcode* [--release] Removes the binding with the given . +*unbindgesture* [:][:directions] + Removes the gesture binding with the given , etc. + *unbindsym* [--release] button[1-9]| Removes the binding with the given