feat: add more protocols + touch support:
* add touch support (experimental) * add support for wlr_cursor_shape_v1 * add support for wlr_relative_pointer_manager_v1
This commit is contained in:
184
touch.c
Normal file
184
touch.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <stdlib.h>
|
||||
#include "touch.h"
|
||||
#include "idle.h"
|
||||
#include "node.h"
|
||||
#include "seat.h"
|
||||
#include "cursor.h"
|
||||
struct touch_point
|
||||
{
|
||||
int32_t touch_id;
|
||||
uint32_t x_offset;
|
||||
uint32_t y_offset;
|
||||
struct wlr_surface *surface;
|
||||
struct wl_list link; /* seat.touch_points */
|
||||
};
|
||||
|
||||
static void seat_touch_down(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_seat *seat = wl_container_of(listener, seat, touch_down);
|
||||
struct wlr_touch_down_event *event = data;
|
||||
|
||||
diya_idle_manager_notify_activity(seat->wlr_seat);
|
||||
|
||||
/* Compute layout => surface offset and save for this touch point */
|
||||
struct touch_point *touch_point = calloc(1, sizeof(*touch_point));
|
||||
double x_offset = 0.0, y_offset = 0.0;
|
||||
|
||||
// get surface from touch point
|
||||
struct wlr_touch *touch = event->touch;
|
||||
/* Convert coordinates: first [0, 1] => layout, then layout => surface */
|
||||
double lx, ly;
|
||||
wlr_cursor_absolute_to_layout_coords(seat->cursor, &touch->base, event->x, event->y, &lx, &ly);
|
||||
double sx, sy;
|
||||
struct wlr_scene_node *node = wlr_scene_node_at(&seat->server->scene->tree.node, lx, ly, &sx, &sy);
|
||||
x_offset = lx - sx;
|
||||
y_offset = ly - sy;
|
||||
/* Find the surface and return it if it accepts touch events */
|
||||
struct wlr_surface *surface = diyac_wlr_surface_from_node(node);
|
||||
|
||||
if (surface && !wlr_surface_accepts_touch(seat->wlr_seat, surface))
|
||||
{
|
||||
surface = NULL;
|
||||
}
|
||||
|
||||
touch_point->surface = surface;
|
||||
touch_point->touch_id = event->touch_id;
|
||||
touch_point->x_offset = x_offset;
|
||||
touch_point->y_offset = y_offset;
|
||||
|
||||
wl_list_insert(&seat->touch_points, &touch_point->link);
|
||||
int touch_point_count = wl_list_length(&seat->touch_points);
|
||||
|
||||
/* hide the cursor when starting touch input */
|
||||
// cursor_set_visible(seat, /* visible */ false);
|
||||
|
||||
if (touch_point->surface)
|
||||
{
|
||||
diyac_seat_pointer_end_grab(seat, touch_point->surface);
|
||||
/* Clear focus to not interfere with touch input */
|
||||
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
|
||||
|
||||
if (touch_point_count == 1)
|
||||
{
|
||||
wlr_cursor_warp_absolute(seat->cursor, &event->touch->base, event->x, event->y);
|
||||
}
|
||||
wlr_seat_touch_notify_down(seat->wlr_seat, touch_point->surface, event->time_msec, event->touch_id, sx, sy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (touch_point_count == 1)
|
||||
{
|
||||
diyac_cursor_emulate_move_absolute(seat, &event->touch->base, event->x, event->y, event->time_msec);
|
||||
}
|
||||
diyac_cursor_emulate_button(seat, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED, event->time_msec);
|
||||
}
|
||||
}
|
||||
|
||||
static void seat_touch_up(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_seat *seat = wl_container_of(listener, seat, touch_up);
|
||||
struct wlr_touch_up_event *event = data;
|
||||
|
||||
diya_idle_manager_notify_activity(seat->wlr_seat);
|
||||
|
||||
/* Remove the touch point from the seat */
|
||||
struct touch_point *touch_point, *tmp;
|
||||
wl_list_for_each_safe(touch_point, tmp, &seat->touch_points, link)
|
||||
{
|
||||
if (touch_point->touch_id == event->touch_id)
|
||||
{
|
||||
if (touch_point->surface)
|
||||
{
|
||||
wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec,
|
||||
event->touch_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
diyac_cursor_emulate_button(seat, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED, event->time_msec);
|
||||
}
|
||||
wl_list_remove(&touch_point->link);
|
||||
free(touch_point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void seat_touch_motion(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_seat *seat = wl_container_of(listener, seat, touch_motion);
|
||||
struct wlr_touch_motion_event *event = data;
|
||||
|
||||
diya_idle_manager_notify_activity(seat->wlr_seat);
|
||||
|
||||
int touch_point_count = wl_list_length(&seat->touch_points);
|
||||
|
||||
/* Find existing touch point to determine initial offsets to subtract */
|
||||
struct touch_point *touch_point;
|
||||
wl_list_for_each(touch_point, &seat->touch_points, link)
|
||||
{
|
||||
if (touch_point->touch_id == event->touch_id)
|
||||
{
|
||||
if (touch_point->surface)
|
||||
{
|
||||
/* Convert coordinates: first [0, 1] => layout */
|
||||
double lx, ly;
|
||||
wlr_cursor_absolute_to_layout_coords(seat->cursor,
|
||||
&event->touch->base, event->x, event->y, &lx, &ly);
|
||||
|
||||
/* Apply offsets to get surface coords before reporting event */
|
||||
double sx = lx - touch_point->x_offset;
|
||||
double sy = ly - touch_point->y_offset;
|
||||
|
||||
if (touch_point_count == 1)
|
||||
{
|
||||
wlr_cursor_warp_absolute(seat->cursor, &event->touch->base, event->x, event->y);
|
||||
}
|
||||
wlr_seat_touch_notify_motion(seat->wlr_seat, event->time_msec,
|
||||
event->touch_id, sx, sy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (touch_point_count == 1)
|
||||
{
|
||||
diyac_cursor_emulate_move_absolute(seat, &event->touch->base, event->x, event->y, event->time_msec);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void seat_touch_frame(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_seat *seat = wl_container_of(listener, seat, touch_frame);
|
||||
|
||||
wlr_seat_touch_notify_frame(seat->wlr_seat);
|
||||
}
|
||||
|
||||
void diyac_touch_init(struct diyac_seat *seat)
|
||||
{
|
||||
seat->touch_down.notify = seat_touch_down;
|
||||
wl_signal_add(&seat->cursor->events.touch_down, &seat->touch_down);
|
||||
|
||||
seat->touch_up.notify = seat_touch_up;
|
||||
wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up);
|
||||
|
||||
seat->touch_motion.notify = seat_touch_motion;
|
||||
wl_signal_add(&seat->cursor->events.touch_motion, &seat->touch_motion);
|
||||
|
||||
seat->touch_frame.notify = seat_touch_frame;
|
||||
wl_signal_add(&seat->cursor->events.touch_frame, &seat->touch_frame);
|
||||
}
|
||||
void diyac_touch_drop(struct diyac_seat *seat)
|
||||
{
|
||||
wl_list_remove(&seat->touch_points);
|
||||
|
||||
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);
|
||||
}
|
Reference in New Issue
Block a user