aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rootston/cursor.h1
-rw-r--r--include/rootston/seat.h7
-rw-r--r--include/wlr/types/wlr_cursor.h7
-rw-r--r--include/wlr/types/wlr_seat.h31
-rw-r--r--rootston/cursor.c73
-rw-r--r--rootston/seat.c2
-rw-r--r--types/wlr_cursor.c18
-rw-r--r--types/wlr_seat.c121
8 files changed, 217 insertions, 43 deletions
diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h
index f49b6439..b5af7de3 100644
--- a/include/rootston/cursor.h
+++ b/include/rootston/cursor.h
@@ -39,7 +39,6 @@ struct roots_cursor {
uint32_t resize_edges;
// Ring buffer of input events that could trigger move/resize/rotate
int input_events_idx;
- struct wl_list touch_points;
struct roots_input_event input_events[16];
struct wl_listener motion;
diff --git a/include/rootston/seat.h b/include/rootston/seat.h
index bef515a4..5fb2f196 100644
--- a/include/rootston/seat.h
+++ b/include/rootston/seat.h
@@ -43,13 +43,6 @@ struct roots_touch {
struct wl_list link;
};
-struct roots_touch_point {
- struct roots_touch *device;
- int32_t slot;
- double x, y;
- struct wl_list link;
-};
-
struct roots_tablet_tool {
struct roots_seat *seat;
struct wlr_input_device *device;
diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h
index 0db32eb2..c73a4c8d 100644
--- a/include/wlr/types/wlr_cursor.h
+++ b/include/wlr/types/wlr_cursor.h
@@ -126,4 +126,11 @@ void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box);
void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,
struct wlr_input_device *dev, struct wlr_box *box);
+/**
+ * Convert absolute coordinates to layout coordinates for the device.
+ */
+bool wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur,
+ struct wlr_input_device *device, double x_mm, double y_mm,
+ double width_mm, double height_mm, double *lx, double *ly);
+
#endif
diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h
index a5f00402..e8477b18 100644
--- a/include/wlr/types/wlr_seat.h
+++ b/include/wlr/types/wlr_seat.h
@@ -103,6 +103,23 @@ struct wlr_seat_keyboard_state {
struct wlr_seat_keyboard_grab *default_grab;
};
+struct wlr_touch_point {
+ int32_t touch_id;
+ struct wlr_surface *surface;
+ struct wlr_seat_client *client;
+ double sx, sy;
+
+ struct wl_listener surface_destroy;
+ struct wl_listener resource_destroy;
+
+ struct wl_list link;
+};
+
+struct wlr_seat_touch_state {
+ struct wlr_seat *seat;
+ struct wl_list touch_points; // wlr_touch_point::link
+};
+
struct wlr_seat {
struct wl_global *wl_global;
struct wl_display *display;
@@ -117,6 +134,7 @@ struct wlr_seat {
struct wlr_seat_pointer_state pointer_state;
struct wlr_seat_keyboard_state keyboard_state;
+ struct wlr_seat_touch_state touch_state;
struct wl_listener selection_data_source_destroy;
@@ -328,4 +346,17 @@ void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat);
// TODO: May be useful to be able to simulate keyboard input events
+struct wlr_touch_point *wlr_seat_touch_get_point(struct wlr_seat *seat,
+ int32_t touch_id);
+
+void wlr_seat_touch_notify_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy);
+
+void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id);
+
+void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id, double sx, double sy);
+
#endif
diff --git a/rootston/cursor.c b/rootston/cursor.c
index ecd5e9a0..417bdaf5 100644
--- a/rootston/cursor.c
+++ b/rootston/cursor.c
@@ -214,50 +214,57 @@ void roots_cursor_handle_axis(struct roots_cursor *cursor,
void roots_cursor_handle_touch_down(struct roots_cursor *cursor,
struct wlr_event_touch_down *event) {
- struct roots_touch_point *point =
- calloc(1, sizeof(struct roots_touch_point));
- if (!point) {
- wlr_log(L_ERROR, "could not allocate memory for touch point");
+ struct roots_desktop *desktop = cursor->seat->input->server->desktop;
+ struct wlr_surface *surface = NULL;
+ double lx, ly;
+ bool result =
+ wlr_cursor_absolute_to_layout_coords(cursor->cursor,
+ event->device, event->x_mm, event->y_mm, event->width_mm,
+ event->height_mm, &lx, &ly);
+ if (!result) {
return;
}
+ double sx, sy;
+ view_at(desktop, lx, ly, &surface, &sx, &sy);
- point->device = event->device->data;
- point->slot = event->slot;
- point->x = event->x_mm / event->width_mm;
- point->y = event->y_mm / event->height_mm;
- wlr_cursor_warp_absolute(cursor->cursor, event->device, point->x, point->y);
- roots_cursor_update_position(cursor, event->time_msec);
- wl_list_insert(&cursor->touch_points, &point->link);
- roots_cursor_press_button(cursor, event->device,
- event->time_msec, BTN_LEFT, 1);
+ if (surface) {
+ wlr_seat_touch_notify_down(cursor->seat->seat, surface,
+ event->time_msec, event->slot, sx, sy);
+ }
}
void roots_cursor_handle_touch_up(struct roots_cursor *cursor,
struct wlr_event_touch_up *event) {
- struct roots_touch_point *point;
- wl_list_for_each(point, &cursor->touch_points, link) {
- if (point->slot == event->slot) {
- wl_list_remove(&point->link);
- free(point);
- break;
- }
- }
- roots_cursor_press_button(cursor, event->device,
- event->time_msec, BTN_LEFT, 0);
+ // TODO
+ wlr_seat_touch_notify_up(cursor->seat->seat, event->time_msec, event->slot);
+ //roots_cursor_press_button(cursor, event->device, event->time_msec, BTN_LEFT, 0);
}
void roots_cursor_handle_touch_motion(struct roots_cursor *cursor,
struct wlr_event_touch_motion *event) {
- struct roots_touch_point *point;
- wl_list_for_each(point, &cursor->touch_points, link) {
- if (point->slot == event->slot) {
- point->x = event->x_mm / event->width_mm;
- point->y = event->y_mm / event->height_mm;
- wlr_cursor_warp_absolute(cursor->cursor, event->device,
- point->x, point->y);
- roots_cursor_update_position(cursor, event->time_msec);
- break;
- }
+ struct roots_desktop *desktop = cursor->seat->input->server->desktop;
+ struct wlr_touch_point *point =
+ wlr_seat_touch_get_point(cursor->seat->seat, event->slot);
+ if (!point) {
+ return;
+ }
+
+ struct wlr_surface *surface = NULL;
+ double lx, ly;
+ bool result =
+ wlr_cursor_absolute_to_layout_coords(cursor->cursor,
+ event->device, event->x_mm, event->y_mm, event->width_mm,
+ event->height_mm, &lx, &ly);
+ if (!result) {
+ return;
+ }
+
+ double sx, sy;
+ view_at(desktop, lx, ly, &surface, &sx, &sy);
+
+ if (surface == point->surface) {
+ wlr_seat_touch_notify_motion(cursor->seat->seat, event->time_msec,
+ event->slot, sx, sy);
}
}
diff --git a/rootston/seat.c b/rootston/seat.c
index 6d8dc749..a99e2310 100644
--- a/rootston/seat.c
+++ b/rootston/seat.c
@@ -188,8 +188,6 @@ static void roots_seat_init_cursor(struct roots_seat *seat) {
// TODO: be able to configure per-seat cursor themes
seat->cursor->xcursor_manager = desktop->xcursor_manager;
- wl_list_init(&seat->cursor->touch_points);
-
roots_seat_configure_cursor(seat);
roots_seat_configure_xcursor(seat);
diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c
index e8965b68..ec66f7c7 100644
--- a/types/wlr_cursor.c
+++ b/types/wlr_cursor.c
@@ -637,3 +637,21 @@ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,
c_device->mapped_box = box;
}
+
+bool wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur,
+ struct wlr_input_device *device, double x_mm, double y_mm,
+ double width_mm, double height_mm, double *lx, double *ly) {
+ if (width_mm <= 0 || height_mm <= 0) {
+ return false;
+ }
+
+ struct wlr_box *mapping = get_mapping(cur, device);
+ if (!mapping) {
+ mapping = wlr_output_layout_get_box(cur->state->layout, NULL);
+ }
+
+ *lx = x_mm > 0 ? mapping->width * (x_mm / width_mm) + mapping->x : cur->x;
+ *ly = y_mm > 0 ? mapping->height * (y_mm / height_mm) + mapping->y : cur->y;
+
+ return true;
+}
diff --git a/types/wlr_seat.c b/types/wlr_seat.c
index dad88354..d52a4bdc 100644
--- a/types/wlr_seat.c
+++ b/types/wlr_seat.c
@@ -338,6 +338,10 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
wl_list_init(
&wlr_seat->keyboard_state.surface_destroy.link);
+ // touch state
+ wlr_seat->touch_state.seat = wlr_seat;
+ wl_list_init(&wlr_seat->touch_state.touch_points);
+
struct wl_global *wl_global = wl_global_create(display,
&wl_seat_interface, 6, wlr_seat, wl_seat_bind);
if (!wl_global) {
@@ -819,3 +823,120 @@ void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
grab->interface->key(grab, time, key, state);
}
+
+static void touch_point_destroy(struct wlr_touch_point *point) {
+ wl_list_remove(&point->surface_destroy.link);
+ wl_list_remove(&point->resource_destroy.link);
+ wl_list_remove(&point->link);
+ free(point);
+}
+
+static void handle_touch_point_resource_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, resource_destroy);
+ touch_point_destroy(point);
+}
+
+static void handle_touch_point_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, surface_destroy);
+ touch_point_destroy(point);
+}
+
+static struct wlr_touch_point *touch_point_create(
+ struct wlr_seat *seat, int32_t touch_id,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ struct wlr_seat_client *client = wlr_seat_client_for_wl_client(seat, wl_client);
+
+ if (!client || !client->touch) {
+ // touch points are not valid without a connected client with touch
+ return NULL;
+ }
+
+ struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point));
+ if (!point) {
+ return NULL;
+ }
+
+ point->touch_id = touch_id;
+ point->surface = surface;
+ point->client = client;
+
+ point->sx = sx;
+ point->sy = sy;
+
+ wl_signal_add(&surface->events.destroy, &point->surface_destroy);
+ point->surface_destroy.notify = handle_touch_point_surface_destroy;
+ wl_resource_add_destroy_listener(surface->resource,
+ &point->resource_destroy);
+ point->resource_destroy.notify = handle_touch_point_resource_destroy;
+
+ wl_list_insert(&seat->touch_state.touch_points, &point->link);
+
+ return point;
+}
+
+struct wlr_touch_point *wlr_seat_touch_get_point(
+ struct wlr_seat *seat, int32_t touch_id) {
+ struct wlr_touch_point *point = NULL;
+ wl_list_for_each(point, &seat->touch_state.touch_points, link) {
+ if (point->touch_id == touch_id) {
+ return point;
+ }
+ }
+
+ return NULL;
+}
+
+void wlr_seat_touch_notify_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ if (wlr_seat_touch_get_point(seat, touch_id)) {
+ wlr_log(L_ERROR, "got touch down for a touch point that's already down");
+ return;
+ }
+
+ struct wlr_touch_point *point =
+ touch_point_create(seat, touch_id, surface, sx, sy);
+ if (!point) {
+ wlr_log(L_ERROR, "could not create touch point");
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ wl_touch_send_down(point->client->touch, serial, time, surface->resource,
+ touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ wl_touch_send_frame(point->client->touch);
+}
+
+void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch notify up for unknown touch point");
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ wl_touch_send_up(point->client->touch, serial, time, touch_id);
+ wl_touch_send_frame(point->client->touch);
+ touch_point_destroy(point);
+}
+
+void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id,
+ double sx, double sy) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch motion notify for unknown touch point");
+ return;
+ }
+
+ point->sx = sx;
+ point->sy = sy;
+
+ wl_touch_send_motion(point->client->touch, time, touch_id,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ wl_touch_send_frame(point->client->touch);
+}