mirror of
https://github.com/swaywm/sway.git
synced 2026-04-23 06:46:27 -04:00
swaybar: Implement pointer gesture swipe support
After previous commits, swaybar bindsym statements would already accept
the new pseudo button names for swipe gestures. Also, sway itself would
not handle swipes when executed while the pointer was above a bar.
Add the necessary handling for three- and four-finger swipe pointer
gestures in swaybar. Cancel ongoing swipes when the pointer leaves the
bar as to not confuse successive swipes with focus changes inbetween
them. Add the pointer gestures protocol in client and server variants
to the meson build file to make the necessary definitions available.
Bind to the global interface on startup, instantiate a swipe gesture and
add a listener on seat setup as well as destroy it on seat shutdown.
Extend the sway-bar manual page as necessary.
Test-plan:
- add workspace switching to config like so:
bar bar-0 {
swaybar_command swaybar
bindsym release SWIPE_3_LEFT workspace prev_on_output
bindsym release SWIPE_4_RIGHT workspace next_on_output
bindsym --release SWIPE_3_LEFT exec yad --text foo
bindsym --release SWIPE_4_UP exec yad --text bar
}
- start sway and open two workspaces
- position pointer above a bar surface
- switch back and forth using horizontal three- and four-finger swipes,
observing that different finger counts are necessary per direction
- observe that the --release binding for left swipes is ignored because
there is an on-press binding already
- observe that the --release binding for upward swipes is honoured
because there is no on-press binding
- move pointer away from bar surface
- observe that switching by swipe no longer works
Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
parent
41488b0fdb
commit
d4482400f1
6 changed files with 160 additions and 0 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,15 @@
|
|||
#define SWAY_CONTINUOUS_SCROLL_TIMEOUT 1000
|
||||
#define SWAY_CONTINUOUS_SCROLL_THRESHOLD 10000
|
||||
|
||||
#define SWAY_SWIPE_DIR_UP 0
|
||||
#define SWAY_SWIPE_DIR_DOWN 1
|
||||
#define SWAY_SWIPE_DIR_LEFT 2
|
||||
#define SWAY_SWIPE_DIR_RIGHT 3
|
||||
#define SWAY_SWIPE_DIR_COUNT 4
|
||||
|
||||
#define SWAY_SWIPE_3 SWAY_SCROLL_RIGHT + 1
|
||||
#define SWAY_SWIPE_4 SWAY_SWIPE_3 + SWAY_SWIPE_DIR_COUNT
|
||||
|
||||
struct swaybar;
|
||||
struct swaybar_output;
|
||||
|
||||
|
|
@ -39,6 +48,13 @@ struct swaybar_touch {
|
|||
struct touch_slot slots[16];
|
||||
};
|
||||
|
||||
struct swaybar_swipe {
|
||||
struct zwp_pointer_gesture_swipe_v1 *swipe;
|
||||
bool swiping;
|
||||
uint8_t fingers;
|
||||
double travel_x, travel_y;
|
||||
};
|
||||
|
||||
enum hotspot_event_handling {
|
||||
HOTSPOT_IGNORE,
|
||||
HOTSPOT_PROCESS,
|
||||
|
|
@ -66,6 +82,7 @@ struct swaybar_seat {
|
|||
struct wl_seat *wl_seat;
|
||||
struct swaybar_pointer pointer;
|
||||
struct swaybar_touch touch;
|
||||
struct swaybar_swipe swipe;
|
||||
struct wl_list link; // swaybar_seat:link
|
||||
struct swaybar_scroll_axis axis[2];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['idle.xml'],
|
||||
|
|
@ -24,6 +25,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'],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ runtime.
|
|||
debug-events*. To disable the default behavior for a button, use the
|
||||
command _nop_.
|
||||
|
||||
Special events _SWIPE\_{3,4}\_{UP,DOWN,LEFT,RIGHT}_ respond to three- and
|
||||
four-finger swipe gestures respectively. Gestures have to happen while
|
||||
the pointer is above a bar to be considered. Gesture bindings for other
|
||||
contexts can be configured similarly in sway itself. The binding to
|
||||
execute is selected based on the number of fingers used and ultimate
|
||||
overall direction of the gesture. Because the latter cannot be
|
||||
determined before the gesture has actually finished, bindings are only
|
||||
ever executed on release. Therefore bindings with flag _--release_ are
|
||||
ignored if there is an on-press binding as well because they would be
|
||||
executed at the same time anyway.
|
||||
|
||||
*binding_mode_indicator* yes|no
|
||||
Enable or disable binding mode indicator. Default is _yes_.
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -367,6 +368,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, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
124
swaybar/input.c
124
swaybar/input.c
|
|
@ -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,12 @@ 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;
|
||||
|
||||
struct swaybar_swipe *swipe = &seat->swipe;
|
||||
if (swipe->swiping) {
|
||||
sway_log(SWAY_DEBUG, "Cancelling ongoing swipe due to pointer leaving bar");
|
||||
swipe->swiping = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
||||
|
|
@ -463,6 +470,115 @@ static const struct wl_touch_listener touch_listener = {
|
|||
.orientation = wl_touch_orientation,
|
||||
};
|
||||
|
||||
static uint32_t swipe_button_base(uint8_t fingers) {
|
||||
if (fingers == 3) {
|
||||
return SWAY_SWIPE_3;
|
||||
} else if (fingers == 4) {
|
||||
return SWAY_SWIPE_4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
struct swaybar_output *output;
|
||||
|
||||
wl_list_for_each(output, &seat->bar->outputs, link) {
|
||||
if (output->surface == surface) {
|
||||
surface = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we only want to respond to swipes on a bar surface
|
||||
if (surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not execute any button press bindings because due to the
|
||||
// nature of swipes we cannot know yet what kind of swipe it is going
|
||||
// to be.
|
||||
|
||||
struct swaybar_swipe *swipe = &seat->swipe;
|
||||
swipe->swiping = true;
|
||||
swipe->fingers = fingers;
|
||||
swipe->travel_x = 0;
|
||||
swipe->travel_y = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
struct swaybar_swipe *swipe = &seat->swipe;
|
||||
|
||||
if (!swipe->swiping) {
|
||||
sway_log(SWAY_DEBUG, "Ignoring swipe update without begin");
|
||||
return;
|
||||
}
|
||||
|
||||
swipe->travel_x += dx;
|
||||
swipe->travel_y += dy;
|
||||
}
|
||||
|
||||
static uint32_t swipe_to_button(struct swaybar_swipe *swipe) {
|
||||
uint8_t direction;
|
||||
if (fabs(swipe->travel_x) > fabs(swipe->travel_y)) {
|
||||
if (swipe->travel_x > 0) {
|
||||
direction = SWAY_SWIPE_DIR_RIGHT;
|
||||
} else {
|
||||
direction = SWAY_SWIPE_DIR_LEFT;
|
||||
}
|
||||
} else {
|
||||
if (swipe->travel_y > 0) {
|
||||
direction = SWAY_SWIPE_DIR_DOWN;
|
||||
} else {
|
||||
direction = SWAY_SWIPE_DIR_UP;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t button_base = swipe_button_base(swipe->fingers);
|
||||
return button_base + direction;
|
||||
}
|
||||
|
||||
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;
|
||||
struct swaybar_swipe *swipe = &seat->swipe;
|
||||
|
||||
if (!swipe->swiping) {
|
||||
sway_log(SWAY_DEBUG, "Ignoring swipe end without begin");
|
||||
return;
|
||||
}
|
||||
|
||||
swipe->swiping = false;
|
||||
|
||||
// can happen when changing finger count mid-swipe or swiping off the
|
||||
// tracking surface (touchpad)
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t button = swipe_to_button(swipe);
|
||||
|
||||
// try to execute button press binding because now we know what kind of
|
||||
// swipe this became. Ignore any on-release binding in case of success.
|
||||
if (check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_PRESSED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -481,6 +597,11 @@ 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->swipe.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,
|
||||
&swipe_listener, seat);
|
||||
}
|
||||
if (!have_touch && seat->touch.touch != NULL) {
|
||||
wl_touch_release(seat->touch.touch);
|
||||
|
|
@ -517,6 +638,9 @@ void swaybar_seat_free(struct swaybar_seat *seat) {
|
|||
if (seat->touch.touch != NULL) {
|
||||
wl_touch_release(seat->touch.touch);
|
||||
}
|
||||
if (seat->swipe.swipe != NULL) {
|
||||
zwp_pointer_gesture_swipe_v1_destroy(seat->swipe.swipe);
|
||||
}
|
||||
wl_seat_destroy(seat->wl_seat);
|
||||
wl_list_remove(&seat->link);
|
||||
free(seat);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue