diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 2518d5aa..dfadc200 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 d76cd551..88e5abc5 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 e416f6e7..d443c777 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,