From 1c3e3cfef35d6fdfee65fb9ec185ca724b7cc6eb Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 17 Feb 2019 10:13:11 -0500 Subject: [PATCH 1/2] swaybar: process hotspots on touch tap --- include/swaybar/bar.h | 1 + include/swaybar/input.h | 13 ++++ swaybar/input.c | 139 +++++++++++++++++++++++++++++++++++----- 3 files changed, 138 insertions(+), 15 deletions(-) diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 2518d5aa83..dfadc200a4 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -34,6 +34,7 @@ struct swaybar { struct swaybar_config *config; struct swaybar_pointer pointer; + struct swaybar_touch touch; struct status_line *status; struct loop *eventloop; diff --git a/include/swaybar/input.h b/include/swaybar/input.h index d76cd551f5..88e5abc5ed 100644 --- a/include/swaybar/input.h +++ b/include/swaybar/input.h @@ -22,6 +22,19 @@ struct swaybar_pointer { uint32_t serial; }; +struct touch_slot { + int32_t id; + uint32_t time; + struct swaybar_output *output; + double start_x, start_y; + double x, y; +}; + +struct swaybar_touch { + struct wl_touch *touch; + struct touch_slot slots[16]; +}; + enum hotspot_event_handling { HOTSPOT_IGNORE, HOTSPOT_PROCESS, diff --git a/swaybar/input.c b/swaybar/input.c index e416f6e739..d443c77721 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -123,6 +123,23 @@ static bool check_bindings(struct swaybar *bar, uint32_t button, return false; } +static void process_hotspots(struct swaybar_output *output, + double x, double y, uint32_t button) { + x *= output->scale; + y *= output->scale; + struct swaybar_hotspot *hotspot; + wl_list_for_each(hotspot, &output->hotspots, link) { + if (x >= hotspot->x && y >= hotspot->y + && x < hotspot->x + hotspot->width + && y < hotspot->y + hotspot->height) { + if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, + x / output->scale, y / output->scale, button, hotspot->data)) { + return; + } + } + } +} + static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { struct swaybar *bar = data; @@ -139,20 +156,7 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (state != WL_POINTER_BUTTON_STATE_PRESSED) { return; } - struct swaybar_hotspot *hotspot; - wl_list_for_each(hotspot, &output->hotspots, link) { - double x = pointer->x * output->scale; - double y = pointer->y * output->scale; - if (x >= hotspot->x - && y >= hotspot->y - && x < hotspot->x + hotspot->width - && y < hotspot->y + hotspot->height) { - if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, - pointer->x, pointer->y, button, hotspot->data)) { - return; - } - } - } + process_hotspots(output, pointer->x, pointer->y, button); } static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, @@ -255,7 +259,7 @@ static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, // Who cares } -struct wl_pointer_listener pointer_listener = { +static struct wl_pointer_listener pointer_listener = { .enter = wl_pointer_enter, .leave = wl_pointer_leave, .motion = wl_pointer_motion, @@ -267,6 +271,107 @@ struct wl_pointer_listener pointer_listener = { .axis_discrete = wl_pointer_axis_discrete, }; +static struct touch_slot *get_touch_slot(struct swaybar_touch *touch, int32_t id) { + int next = -1; + for (size_t i = 0; i < sizeof(touch->slots) / sizeof(*touch->slots); ++i) { + if (touch->slots[i].id == id) { + return &touch->slots[i]; + } + if (next == -1 && !touch->slots[i].output) { + next = i; + } + } + if (next == -1) { + sway_log(SWAY_ERROR, "Ran out of touch slots"); + return NULL; + } + return &touch->slots[next]; +} + +static void wl_touch_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t _x, wl_fixed_t _y) { + struct swaybar *bar = data; + struct swaybar_output *_output, *output; + wl_list_for_each(_output, &bar->outputs, link) { + if (_output->surface == surface) { + output = _output; + break; + } + } + if (!output) { + sway_log(SWAY_DEBUG, "Got touch event for unknown surface"); + return; + } + struct touch_slot *slot = get_touch_slot(&bar->touch, id); + if (!slot) { + return; + } + slot->id = id; + slot->output = output; + slot->x = slot->start_x = wl_fixed_to_double(_x); + slot->y = slot->start_y = wl_fixed_to_double(_y); + slot->time = time; +} + +static void wl_touch_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) { + struct swaybar *bar = data; + struct touch_slot *slot = get_touch_slot(&bar->touch, id); + if (!slot) { + return; + } + if (time - slot->time < 500) { + // Tap, treat it like a pointer click + process_hotspots(slot->output, slot->x, slot->y, BTN_LEFT); + } + slot->output = NULL; +} + +static void wl_touch_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { + struct swaybar *bar = data; + struct touch_slot *slot = get_touch_slot(&bar->touch, id); + if (!slot) { + return; + } + slot->x = wl_fixed_to_double(x); + slot->y = wl_fixed_to_double(y); + // TODO: Slide gestures +} + +static void wl_touch_frame(void *data, struct wl_touch *wl_touch) { + // Who cares +} + +static void wl_touch_cancel(void *data, struct wl_touch *wl_touch) { + struct swaybar *bar = data; + struct swaybar_touch *touch = &bar->touch; + for (size_t i = 0; i < sizeof(touch->slots) / sizeof(*touch->slots); ++i) { + touch->slots[i].output = NULL; + } +} + +static void wl_touch_shape(void *data, struct wl_touch *wl_touch, int32_t id, + wl_fixed_t major, wl_fixed_t minor) { + // Who cares +} + +static void wl_touch_orientation(void *data, struct wl_touch *wl_touch, + int32_t id, wl_fixed_t orientation) { + // Who cares +} + +static struct wl_touch_listener touch_listener = { + .down = wl_touch_down, + .up = wl_touch_up, + .motion = wl_touch_motion, + .frame = wl_touch_frame, + .cancel = wl_touch_cancel, + .shape = wl_touch_shape, + .orientation = wl_touch_orientation, +}; + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct swaybar *bar = data; @@ -278,6 +383,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, bar->pointer.pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(bar->pointer.pointer, &pointer_listener, bar); } + if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { + bar->touch.touch = wl_seat_get_touch(wl_seat); + wl_touch_add_listener(bar->touch.touch, &touch_listener, bar); + } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, From 9ecf478eec8e538e1703586ea68acb22069973ff Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 17 Feb 2019 11:00:13 -0500 Subject: [PATCH 2/2] swaybar: cycle workspaces on touch drag --- swaybar/input.c | 93 +++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/swaybar/input.c b/swaybar/input.c index d443c77721..c83d8c33c6 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -159,6 +159,44 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, process_hotspots(output, pointer->x, pointer->y, button); } +static void workspace_next(struct swaybar *bar, struct swaybar_output *output, + bool left) { + struct swaybar_config *config = bar->config; + struct swaybar_workspace *first = + wl_container_of(output->workspaces.next, first, link); + struct swaybar_workspace *last = + wl_container_of(output->workspaces.prev, last, link); + + struct swaybar_workspace *active; + wl_list_for_each(active, &output->workspaces, link) { + if (active->visible) { + break; + } + } + if (!sway_assert(active->visible, "axis with null workspace")) { + return; + } + + struct swaybar_workspace *new; + if (left) { + if (active == first) { + new = config->wrap_scroll ? last : NULL; + } else { + new = wl_container_of(active->link.prev, new, link); + } + } else { + if (active == last) { + new = config->wrap_scroll ? first : NULL; + } else { + new = wl_container_of(active->link.next, new, link); + } + } + + if (new) { + ipc_send_workspace_command(bar, new->name); + } +} + static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { struct swaybar *bar = data; @@ -202,39 +240,7 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, return; } - struct swaybar_workspace *first = - wl_container_of(output->workspaces.next, first, link); - struct swaybar_workspace *last = - wl_container_of(output->workspaces.prev, last, link); - - struct swaybar_workspace *active; - wl_list_for_each(active, &output->workspaces, link) { - if (active->visible) { - break; - } - } - if (!sway_assert(active->visible, "axis with null workspace")) { - return; - } - - struct swaybar_workspace *new; - if (amt < 0.0) { - if (active == first) { - new = config->wrap_scroll ? last : NULL; - } else { - new = wl_container_of(active->link.prev, new, link); - } - } else { - if (active == last) { - new = config->wrap_scroll ? first : NULL; - } else { - new = wl_container_of(active->link.next, new, link); - } - } - - if (new) { - ipc_send_workspace_command(bar, new->name); - } + workspace_next(bar, output, amt < 0.0); // Check button release bindings check_bindings(bar, button, WL_POINTER_BUTTON_STATE_RELEASED); @@ -272,7 +278,7 @@ static struct wl_pointer_listener pointer_listener = { }; static struct touch_slot *get_touch_slot(struct swaybar_touch *touch, int32_t id) { - int next = -1; + ssize_t next = -1; for (size_t i = 0; i < sizeof(touch->slots) / sizeof(*touch->slots); ++i) { if (touch->slots[i].id == id) { return &touch->slots[i]; @@ -292,7 +298,7 @@ static void wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t _x, wl_fixed_t _y) { struct swaybar *bar = data; - struct swaybar_output *_output, *output; + struct swaybar_output *_output = NULL, *output = NULL; wl_list_for_each(_output, &bar->outputs, link) { if (_output->surface == surface) { output = _output; @@ -335,9 +341,18 @@ static void wl_touch_motion(void *data, struct wl_touch *wl_touch, if (!slot) { return; } + int prev_progress = (int)((slot->x - slot->start_x) + / slot->output->width * 100); slot->x = wl_fixed_to_double(x); slot->y = wl_fixed_to_double(y); - // TODO: Slide gestures + // "progress" is a measure from 0..100 representing the fraction of the + // output the touch gesture has travelled, positive when moving to the right + // and negative when moving to the left. + int progress = (int)((slot->x - slot->start_x) + / slot->output->width * 100); + if (abs(progress) / 20 != abs(prev_progress) / 20) { + workspace_next(bar, slot->output, progress - prev_progress < 0); + } } static void wl_touch_frame(void *data, struct wl_touch *wl_touch) { @@ -362,7 +377,7 @@ static void wl_touch_orientation(void *data, struct wl_touch *wl_touch, // Who cares } -static struct wl_touch_listener touch_listener = { +static const struct wl_touch_listener touch_listener = { .down = wl_touch_down, .up = wl_touch_up, .motion = wl_touch_motion, @@ -379,6 +394,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wl_pointer_release(bar->pointer.pointer); bar->pointer.pointer = NULL; } + if (bar->touch.touch != NULL) { + wl_touch_release(bar->touch.touch); + bar->touch.touch = NULL; + } if ((caps & WL_SEAT_CAPABILITY_POINTER)) { bar->pointer.pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(bar->pointer.pointer, &pointer_listener, bar);