wlr-seat: basic touch

This commit is contained in:
Tony Crisci 2017-11-12 11:43:50 -05:00
parent 0fe51b66e4
commit e5a31ae870
8 changed files with 217 additions and 43 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}