#include #include #include #include #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); }