swaybar: add bindgesture support

Co-authored-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
Florian Franzen 2022-04-23 10:34:42 +02:00
parent b896841824
commit 2e64eeda42
9 changed files with 268 additions and 0 deletions

View file

@ -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;

View file

@ -4,6 +4,7 @@
#include <stdint.h>
#include <wayland-client.h>
#include "../include/config.h"
#include "gesture.h"
#include "list.h"
#include "util.h"
@ -24,6 +25,11 @@ struct swaybar_binding {
bool release;
};
struct swaybar_gesture {
struct gesture gesture;
char *command;
};
struct swaybar_config {
char *status_command;
bool pango_markup;
@ -40,6 +46,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;
@ -90,5 +97,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

View file

@ -3,6 +3,7 @@
#include <wayland-client.h>
#include <stdbool.h>
#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];
};

View file

@ -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

View file

@ -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'],
]

View file

@ -29,6 +29,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"
void free_workspaces(struct wl_list *list) {
struct swaybar_workspace *ws, *tmp;
@ -362,6 +363,9 @@ static void handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
bar->xdg_output_manager = wl_registry_bind(registry, name,
&zxdg_output_manager_v1_interface, 2);
} else if (strcmp(interface, zwp_pointer_gestures_v1_interface.name) == 0) {
bar->pointer_gestures = wl_registry_bind(registry, name,
&zwp_pointer_gestures_v1_interface, 3);
}
}

View file

@ -37,6 +37,7 @@ struct swaybar_config *init_config(void) {
config->workspace_buttons = true;
config->workspace_min_width = 0;
config->bindings = create_list();
config->gestures = create_list();
wl_list_init(&config->outputs);
config->status_padding = 1;
config->status_edge_padding = 3;
@ -93,6 +94,14 @@ void free_binding(struct swaybar_binding *binding) {
free(binding);
}
void free_gesture(struct swaybar_gesture *gesture) {
if (!gesture) {
return;
}
free(gesture->command);
free(gesture);
}
#if HAVE_TRAY
void free_tray_binding(struct tray_binding *binding) {
if (!binding) {
@ -114,6 +123,11 @@ void free_config(struct swaybar_config *config) {
free_binding(binding);
}
list_free(config->bindings);
for (int i = 0; i < config->gestures->length; i++) {
struct swaybar_gesture *gesture = config->gestures->items[i];
free_gesture(gesture);
}
list_free(config->gestures);
struct config_output *coutput, *tmp;
wl_list_for_each_safe(coutput, tmp, &config->outputs, link) {
wl_list_remove(&coutput->link);

View file

@ -9,6 +9,7 @@
#include "swaybar/config.h"
#include "swaybar/input.h"
#include "swaybar/ipc.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
void free_hotspots(struct wl_list *list) {
struct swaybar_hotspot *hotspot, *tmp;
@ -118,6 +119,11 @@ static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface) {
struct swaybar_seat *seat = data;
seat->pointer.current = NULL;
// Cancel any ongoing gesture if pointer leaves bar
if(!gesture_tracker_check(&seat->gestures, GESTURE_TYPE_NONE)) {
gesture_tracker_cancel(&seat->gestures);
}
}
static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
@ -461,6 +467,174 @@ static const struct wl_touch_listener touch_listener = {
.orientation = wl_touch_orientation,
};
static bool gesture_on_bar(struct swaybar_seat *seat,
struct wl_surface *surface) {
struct swaybar_output *output;
wl_list_for_each(output, &seat->bar->outputs, link) {
if (output->surface == surface) {
return true;
}
}
return false;
}
// Check if bar has any binding for gesture
static bool bar_gestures_check(struct swaybar *bar,
enum gesture_type type, uint8_t fingers) {
for (int i = 0; i < bar->config->gestures->length; i++) {
struct swaybar_gesture *binding = bar->config->gestures->items[i];
if (gesture_check(&binding->gesture, type, fingers)) {
return true;
}
}
return false;
}
// Check bar gesture binding for match
static struct swaybar_gesture *bar_gestures_match(struct swaybar *bar,
struct gesture *gesture) {
struct swaybar_gesture *current = NULL;
for (int i = 0; i < bar->config->gestures->length; i++) {
struct swaybar_gesture *binding = bar->config->gestures->items[i];
if (gesture_match(&binding->gesture, gesture, false)) {
if (current &&
gesture_compare(&current->gesture, &binding->gesture) < 0) {
continue;
}
current = binding;
}
}
return current;
}
static void gesture_begin(struct swaybar_seat* seat, struct wl_surface *surface,
enum gesture_type type, uint8_t fingers) {
// We only want to respond to holds on a bar surface
if (!gesture_on_bar(seat, surface)) {
return;
}
// Ensure there is a binding for this gesture
if (!bar_gestures_check(seat->bar, type, fingers)) {
sway_log(SWAY_DEBUG, "Ignore tracking gesture without binding: %s:%u:any",
gesture_type_string(type), fingers);
return;
}
gesture_tracker_begin(&seat->gestures, type, fingers);
}
static void gesture_end(struct swaybar_seat* seat, enum gesture_type type,
bool cancelled) {
if (!gesture_tracker_check(&seat->gestures, type)) {
return;
}
if (cancelled) {
gesture_tracker_cancel(&seat->gestures);
return;
}
struct gesture *gesture = gesture_tracker_end(&seat->gestures);
struct swaybar_gesture* binding = bar_gestures_match(seat->bar, gesture);
if (binding) {
ipc_execute_gesture(seat->bar, binding);
}
}
static void hold_begin(void *data, struct zwp_pointer_gesture_hold_v1 *wl_hold,
uint32_t serial, uint32_t time,struct wl_surface *surface,
uint32_t fingers) {
struct swaybar_seat *seat = data;
gesture_begin(seat, surface, GESTURE_TYPE_HOLD, fingers);
}
static void hold_end(void *data,
struct zwp_pointer_gesture_hold_v1 *wl_hold,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct swaybar_seat *seat = data;
gesture_end(seat, GESTURE_TYPE_HOLD, cancelled);
}
static const struct zwp_pointer_gesture_hold_v1_listener hold_listener = {
.begin = hold_begin,
.end = hold_end,
};
static void pinch_begin(void *data,
struct zwp_pointer_gesture_pinch_v1 *wl_pinch, uint32_t serial,
uint32_t time, struct wl_surface *surface, uint32_t fingers) {
struct swaybar_seat *seat = data;
gesture_begin(seat, surface, GESTURE_TYPE_PINCH, fingers);
}
static void pinch_update(void *data,
struct zwp_pointer_gesture_pinch_v1 *wl_pinch,
uint32_t time, wl_fixed_t dx, wl_fixed_t dy,
wl_fixed_t scale, wl_fixed_t rotation) {
struct swaybar_seat *seat = data;
if (gesture_tracker_check(&seat->gestures, GESTURE_TYPE_PINCH)) {
gesture_tracker_update(&seat->gestures,
wl_fixed_to_double(dx), wl_fixed_to_double(dy),
wl_fixed_to_double(scale),
wl_fixed_to_double(rotation));
}
}
static void pinch_end(void *data,
struct zwp_pointer_gesture_pinch_v1 *wl_pinch,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct swaybar_seat *seat = data;
gesture_end(seat, GESTURE_TYPE_PINCH, cancelled);
}
static const struct zwp_pointer_gesture_pinch_v1_listener pinch_listener = {
.begin = pinch_begin,
.update = pinch_update,
.end = pinch_end,
};
static void swipe_begin(void *data,
struct zwp_pointer_gesture_swipe_v1 *wl_swipe,
uint32_t serial, uint32_t time,
struct wl_surface *surface, uint32_t fingers) {
struct swaybar_seat *seat = data;
gesture_begin(seat, surface, GESTURE_TYPE_SWIPE, fingers);
}
static void swipe_update(void *data,
struct zwp_pointer_gesture_swipe_v1 *wl_swipe,
uint32_t time, wl_fixed_t dx, wl_fixed_t dy) {
struct swaybar_seat *seat = data;
if (gesture_tracker_check(&seat->gestures, GESTURE_TYPE_SWIPE)) {
gesture_tracker_update(&seat->gestures,
wl_fixed_to_double(dx), wl_fixed_to_double(dy),
NAN, NAN);
}
}
static void swipe_end(void *data,
struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct swaybar_seat *seat = data;
gesture_end(seat, GESTURE_TYPE_SWIPE, cancelled);
}
static const struct zwp_pointer_gesture_swipe_v1_listener swipe_listener = {
.begin = swipe_begin,
.update = swipe_update,
.end = swipe_end,
};
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps) {
struct swaybar_seat *seat = data;
@ -479,6 +653,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
assert(seat->pointer.cursor_surface);
}
wl_pointer_add_listener(seat->pointer.pointer, &pointer_listener, seat);
seat->hold = zwp_pointer_gestures_v1_get_hold_gesture(
seat->bar->pointer_gestures, seat->pointer.pointer);
zwp_pointer_gesture_hold_v1_add_listener(seat->hold,
&hold_listener, seat);
seat->pinch = zwp_pointer_gestures_v1_get_pinch_gesture(
seat->bar->pointer_gestures, seat->pointer.pointer);
zwp_pointer_gesture_pinch_v1_add_listener(seat->pinch,
&pinch_listener, seat);
seat->swipe = zwp_pointer_gestures_v1_get_swipe_gesture(
seat->bar->pointer_gestures, seat->pointer.pointer);
zwp_pointer_gesture_swipe_v1_add_listener(seat->swipe,
&swipe_listener, seat);
}
if (!have_touch && seat->touch.touch != NULL) {
wl_touch_release(seat->touch.touch);
@ -515,6 +704,15 @@ void swaybar_seat_free(struct swaybar_seat *seat) {
if (seat->touch.touch != NULL) {
wl_touch_release(seat->touch.touch);
}
if (seat->hold != NULL) {
zwp_pointer_gesture_hold_v1_destroy(seat->hold);
}
if (seat->pinch != NULL) {
zwp_pointer_gesture_pinch_v1_destroy(seat->pinch);
}
if (seat->swipe != NULL) {
zwp_pointer_gesture_swipe_v1_destroy(seat->swipe);
}
wl_seat_destroy(seat->wl_seat);
wl_list_remove(&seat->link);
free(seat);

View file

@ -140,6 +140,30 @@ static bool ipc_parse_config(
}
}
json_object *gestures = json_object_object_get(bar_config, "gestures");
while (config->gestures->length) {
struct swaybar_gesture *binding = config->gestures->items[0];
list_del(config->gestures, 0);
free_gesture(binding);
}
if (gestures) {
int length = json_object_array_length(gestures);
for (int i = 0; i < length; ++i) {
json_object *bindobj = json_object_array_get_idx(gestures, i);
struct swaybar_gesture *binding =
calloc(1, sizeof(struct swaybar_gesture));
binding->gesture.type = json_object_get_int(
json_object_object_get(bindobj, "type"));
binding->gesture.fingers = json_object_get_int(
json_object_object_get(bindobj, "fingers"));
binding->gesture.directions = json_object_get_int(
json_object_object_get(bindobj, "directions"));
binding->command = strdup(json_object_get_string(
json_object_object_get(bindobj, "command")));
list_add(config->gestures, binding);
}
}
json_object *colors = json_object_object_get(bar_config, "colors");
if (colors) {
ipc_parse_colors(config, colors);
@ -414,6 +438,16 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
IPC_COMMAND, bind->command, &len));
}
void ipc_execute_gesture(struct swaybar *bar, struct swaybar_gesture *bind) {
char *description = gesture_to_string(&bind->gesture);
sway_log(SWAY_DEBUG, "Executing binding for gesture %s: `%s`",
description, bind->command);
free(description);
uint32_t len = strlen(bind->command);
free(ipc_single_command(bar->ipc_socketfd,
IPC_COMMAND, bind->command, &len));
}
bool ipc_initialize(struct swaybar *bar) {
uint32_t len = strlen(bar->id);
char *res = ipc_single_command(bar->ipc_socketfd,