diff --git a/include/labwc.h b/include/labwc.h index 97be5dfc..d7ad1ea4 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -119,6 +119,11 @@ struct seat { struct wl_listener keyboard_key; struct wl_listener keyboard_modifiers; + struct wl_listener touch_down; + struct wl_listener touch_up; + struct wl_listener touch_motion; + struct wl_listener touch_frame; + struct wl_listener request_start_drag; struct wl_listener start_drag; struct wl_listener destroy_drag; @@ -498,6 +503,9 @@ void cursor_finish(struct seat *seat); void keyboard_init(struct seat *seat); void keyboard_finish(struct seat *seat); +void touch_init(struct seat *seat); +void touch_finish(struct seat *seat); + void seat_init(struct server *server); void seat_finish(struct server *server); void seat_reconfigure(struct server *server); diff --git a/src/meson.build b/src/meson.build index fd918939..aedda90f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,6 +16,7 @@ labwc_sources = files( 'resistance.c', 'seat.c', 'server.c', + 'touch.c', 'theme.c', 'view.c', 'view-impl.c', diff --git a/src/seat.c b/src/seat.c index f099886c..9a3b966a 100644 --- a/src/seat.c +++ b/src/seat.c @@ -166,6 +166,28 @@ new_keyboard(struct seat *seat, struct input *input) wlr_seat_set_keyboard(seat->seat, input->wlr_input_device); } +void +new_touch(struct seat *seat, struct input *input) +{ + struct wlr_input_device *dev = input->wlr_input_device; + if (wlr_input_device_is_libinput(dev)) { + configure_libinput(dev); + } + wlr_cursor_attach_input_device(seat->cursor, dev); + + /* In support of running with WLR_WL_OUTPUTS set to >=2 */ + if (dev->type == WLR_INPUT_DEVICE_TOUCH) { + wlr_log(WLR_INFO, "map touch to output %s\n", + dev->pointer->output_name); + struct wlr_output *output = NULL; + if (dev->pointer->output_name != NULL) { + output = output_by_name(seat->server, dev->pointer->output_name); + } + wlr_cursor_map_input_to_output(seat->cursor, dev, output); + wlr_cursor_map_input_to_region(seat->cursor, dev, NULL); + } +} + static void new_input_notify(struct wl_listener *listener, void *data) { @@ -182,6 +204,9 @@ new_input_notify(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_POINTER: new_pointer(seat, input); break; + case WLR_INPUT_DEVICE_TOUCH: + new_touch(seat, input); + break; default: wlr_log(WLR_INFO, "unsupported input device"); break; @@ -200,6 +225,9 @@ new_input_notify(struct wl_listener *listener, void *data) case WLR_INPUT_DEVICE_POINTER: caps |= WL_SEAT_CAPABILITY_POINTER; break; + case WLR_INPUT_DEVICE_TOUCH: + caps |= WL_SEAT_CAPABILITY_TOUCH; + break; default: break; } @@ -272,6 +300,7 @@ seat_init(struct server *server) keyboard_init(seat); cursor_init(seat); + touch_init(seat); } void @@ -281,6 +310,7 @@ seat_finish(struct server *server) wl_list_remove(&seat->new_input.link); keyboard_finish(seat); cursor_finish(seat); + touch_finish(seat); } void diff --git a/src/touch.c b/src/touch.c new file mode 100644 index 00000000..516f3fa4 --- /dev/null +++ b/src/touch.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include "labwc.h" + +static struct wlr_surface* +touch_get_coords(struct seat *seat, struct wlr_touch* touch, double x, double y, + double* nx, double* ny) +{ + /* Convert coordinates: first [0, 1] => layout, then layout => surface */ + double lx, ly; + wlr_cursor_absolute_to_layout_coords(seat->cursor, &touch->base, + x, y, &lx, &ly); + + struct wlr_scene_node *node = + wlr_scene_node_at(&seat->server->scene->node, lx, ly, nx, ny); + + /* Find the surface and return it if it accepts touch events. */ + struct wlr_surface* surface = NULL; + + if (node && node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node (node); + surface = scene_surface->surface; + } + + if (surface && !wlr_surface_accepts_touch(seat->seat, surface)) { + surface = NULL; + } + return surface; +} + +static void +touch_motion(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, touch_motion); + struct wlr_touch_motion_event *event = data; + wlr_idle_notify_activity(seat->wlr_idle, seat->seat); + + double nx, ny; + if (touch_get_coords(seat, event->touch, event->x, event->y, &nx, &ny)) { + wlr_seat_touch_notify_motion(seat->seat, event->time_msec, + event->touch_id, nx, ny); + } +} + +static void +touch_frame(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, touch_frame); + + wlr_seat_touch_notify_frame(seat->seat); +} + +static void +touch_down(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, touch_down); + struct wlr_touch_down_event *event = data; + + double nx, ny; + struct wlr_surface* surface = + touch_get_coords(seat, event->touch, event->x, event->y, &nx, &ny); + if (surface) { + wlr_seat_touch_notify_down(seat->seat, surface, event->time_msec, + event->touch_id, nx, ny); + } +} + +static void +touch_up(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, touch_up); + struct wlr_touch_up_event *event = data; + + wlr_seat_touch_notify_up(seat->seat, event->time_msec, event->touch_id); +} + +void +touch_init(struct seat *seat) +{ + seat->touch_down.notify = touch_down; + wl_signal_add(&seat->cursor->events.touch_down, &seat->touch_down); + seat->touch_up.notify = touch_up; + wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up); + seat->touch_motion.notify = touch_motion; + wl_signal_add(&seat->cursor->events.touch_motion, &seat->touch_motion); + seat->touch_frame.notify = touch_frame; + wl_signal_add(&seat->cursor->events.touch_frame, &seat->touch_frame); +} + +void +touch_finish(struct seat *seat) +{ + wl_list_remove(&seat->touch_down.link); + wl_list_remove(&seat->touch_up.link); + wl_list_remove(&seat->touch_motion.link); + wl_list_remove(&seat->touch_frame.link); +}