This only adds support for reporting motion events, proximity_in events (without the tool object information), proximity_out events and frame events.
Signed-off-by: Stephen Chandler Paul <[email protected]> --- src/compositor.h | 97 ++++++++++++++++ src/input.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libinput-device.c | 160 ++++++++++++++++++++++++++ src/libinput-device.h | 4 +- 4 files changed, 572 insertions(+), 1 deletion(-) diff --git a/src/compositor.h b/src/compositor.h index 102cfa7..f0f4e90 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -33,6 +33,7 @@ extern "C" { #define WL_HIDE_DEPRECATED #include <wayland-server.h> +#include <wayland-tablet-server-protocol.h> #include "version.h" #include "matrix.h" @@ -288,6 +289,45 @@ struct weston_touch_grab { struct weston_touch *touch; }; +struct weston_tablet_tool; +struct weston_tablet_grab; +struct weston_tablet_grab_interface { + void (*proximity_in)(struct weston_tablet_grab *grab, + uint32_t time, + struct weston_tablet_tool *tool); + void (*proximity_out)(struct weston_tablet_grab *grab, + uint32_t time); + void (*motion)(struct weston_tablet_grab *grab, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y); + void (*down)(struct weston_tablet_grab *grab, + uint32_t time); + void (*up)(struct weston_tablet_grab *grab, + uint32_t time); + void (*pressure)(struct weston_tablet_grab *grab, + uint32_t time, + wl_fixed_t pressure); + void (*distance)(struct weston_tablet_grab *grab, + uint32_t time, + wl_fixed_t distance); + void (*tilt)(struct weston_tablet_grab *grab, + uint32_t time, + wl_fixed_t tilt_x, + wl_fixed_t tilt_y); + void (*button)(struct weston_tablet_grab *grab, + uint32_t time, + uint32_t button, + enum wl_tablet_button_state state); + void (*frame)(struct weston_tablet_grab *grab); + void (*cancel)(struct weston_tablet_grab *grab); +}; + +struct weston_tablet_grab { + const struct weston_tablet_grab_interface *interface; + struct weston_tablet *tablet; +}; + struct weston_data_offer { struct wl_resource *resource; struct weston_data_source *source; @@ -358,6 +398,31 @@ struct weston_touch { uint32_t grab_time; }; +struct weston_tablet { + struct weston_seat *seat; + struct evdev_device *device; + + struct wl_list resource_list; + struct wl_list focus_resource_list; + struct weston_view *focus; + struct wl_listener focus_view_listener; + struct wl_listener focus_resource_listener; + uint32_t focus_serial; + + wl_fixed_t x, y; + + struct weston_tablet_grab *grab; + struct weston_tablet_grab default_grab; + + struct wl_list link; + + char *name; + enum wl_tablet_manager_tablet_type type; + uint32_t vid; + uint32_t pid; + struct weston_output *output; +}; + struct weston_pointer * weston_pointer_create(struct weston_seat *seat); void @@ -407,6 +472,19 @@ weston_touch_start_grab(struct weston_touch *device, void weston_touch_end_grab(struct weston_touch *touch); +struct weston_tablet * +weston_tablet_create(void); +void +weston_tablet_destroy(struct weston_tablet *tablet); +void +weston_tablet_set_focus(struct weston_tablet *tablet, struct weston_view *view, + uint32_t time); +void +weston_tablet_start_grab(struct weston_tablet *device, + struct weston_tablet_grab *grab); +void +weston_tablet_end_grab(struct weston_tablet *tablet); + void wl_data_device_set_keyboard_focus(struct weston_seat *seat); @@ -490,9 +568,11 @@ struct weston_seat { struct weston_pointer *pointer; struct weston_keyboard *keyboard; struct weston_touch *touch; + struct wl_list tablet_list; int pointer_device_count; int keyboard_device_count; int touch_device_count; + int tablet_device_count; struct weston_output *output; /* constraint */ @@ -511,6 +591,9 @@ struct weston_seat { struct wl_listener selection_data_source_listener; struct wl_signal selection_signal; + struct wl_global *tablet_manager; + struct wl_list tablet_manager_resource_list; + void (*led_update)(struct weston_seat *ws, enum weston_led leds); uint32_t slot_map; @@ -1006,6 +1089,16 @@ void notify_touch_frame(struct weston_seat *seat); void +notify_tablet_added(struct weston_tablet *tablet); +void +notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time); +void +notify_tablet_motion(struct weston_tablet *tablet, uint32_t time, + wl_fixed_t x, wl_fixed_t y); +void +notify_tablet_frame(struct weston_tablet *tablet); + +void weston_layer_entry_insert(struct weston_layer_entry *list, struct weston_layer_entry *entry); void @@ -1257,6 +1350,10 @@ void weston_seat_init_touch(struct weston_seat *seat); void weston_seat_release_touch(struct weston_seat *seat); +struct weston_tablet * +weston_seat_add_tablet(struct weston_seat *seat); +void +weston_seat_release_tablet(struct weston_tablet *tablet); void weston_seat_repick(struct weston_seat *seat); void diff --git a/src/input.c b/src/input.c index aaa2223..8a97632 100644 --- a/src/input.c +++ b/src/input.c @@ -122,6 +122,26 @@ touch_focus_resource_destroyed(struct wl_listener *listener, void *data) } static void +tablet_focus_view_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_tablet *tablet = + container_of(listener, struct weston_tablet, + focus_view_listener); + + weston_tablet_set_focus(tablet, NULL, 0); +} + +static void +tablet_focus_resource_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_tablet *tablet = + container_of(listener, struct weston_tablet, + focus_resource_listener); + + weston_tablet_set_focus(tablet, NULL, 0); +} + +static void move_resources(struct wl_list *destination, struct wl_list *source) { wl_list_insert_list(destination, source); @@ -421,6 +441,66 @@ static const struct weston_keyboard_grab_interface }; static void +default_grab_tablet_proximity_out(struct weston_tablet_grab *grab, + uint32_t time) +{ + weston_tablet_set_focus(grab->tablet, NULL, time); +} + +static void +default_grab_tablet_motion(struct weston_tablet_grab *grab, + uint32_t time, wl_fixed_t x, wl_fixed_t y) +{ + struct weston_tablet *tablet = grab->tablet; + struct weston_view *current_view; + wl_fixed_t sx, sy; + struct wl_resource *resource; + struct wl_list *resource_list = &tablet->focus_resource_list; + + current_view = weston_compositor_pick_view(tablet->seat->compositor, + x, y, &sx, &sy); + if (current_view != tablet->focus) + weston_tablet_set_focus(tablet, current_view, time); + + if (!wl_list_empty(resource_list)) { + wl_resource_for_each(resource, resource_list) + wl_tablet_send_motion(resource, time, sx, sy); + } +} + +static void +default_grab_tablet_frame(struct weston_tablet_grab *grab) +{ + struct wl_resource *resource; + struct wl_list *resource_list = &grab->tablet->focus_resource_list; + + if (!wl_list_empty(resource_list)) { + wl_resource_for_each(resource, resource_list) + wl_tablet_send_frame(resource); + } +} + +static void +default_grab_tablet_cancel(struct weston_tablet_grab *grab) +{ + +} + +static struct weston_tablet_grab_interface default_tablet_grab_interface = { + NULL, + default_grab_tablet_proximity_out, + default_grab_tablet_motion, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + default_grab_tablet_frame, + default_grab_tablet_cancel, +}; + +static void pointer_unmap_sprite(struct weston_pointer *pointer) { if (weston_surface_is_mapped(pointer->sprite->surface)) @@ -597,6 +677,90 @@ weston_touch_destroy(struct weston_touch *touch) free(touch); } +WL_EXPORT struct weston_tablet * +weston_tablet_create(void) +{ + struct weston_tablet *tablet; + + tablet = zalloc(sizeof *tablet); + if (tablet == NULL) + return NULL; + + wl_list_init(&tablet->resource_list); + wl_list_init(&tablet->focus_resource_list); + wl_list_init(&tablet->focus_view_listener.link); + tablet->focus_view_listener.notify = tablet_focus_view_destroyed; + wl_list_init(&tablet->focus_resource_listener.link); + tablet->focus_resource_listener.notify = tablet_focus_resource_destroyed; + tablet->default_grab.interface = &default_tablet_grab_interface; + tablet->default_grab.tablet = tablet; + tablet->grab = &tablet->default_grab; + + return tablet; +} + +WL_EXPORT void +weston_tablet_destroy(struct weston_tablet *tablet) +{ + free(tablet->name); + + wl_list_remove(&tablet->focus_view_listener.link); + wl_list_remove(&tablet->focus_resource_listener.link); + + free(tablet); +} + +WL_EXPORT void +weston_tablet_set_focus(struct weston_tablet *tablet, struct weston_view *view, + uint32_t time) +{ + struct wl_list *focus_resource_list; + struct wl_resource *resource; + struct weston_seat *seat = tablet->seat; + + focus_resource_list = &tablet->focus_resource_list; + + if (tablet->focus && !wl_list_empty(focus_resource_list)) { + wl_resource_for_each(resource, focus_resource_list) { + wl_tablet_send_proximity_out(resource, time); + wl_tablet_send_frame(resource); + } + + move_resources(&tablet->resource_list, focus_resource_list); + } + + if (find_resource_for_view(&tablet->resource_list, view)) { + struct wl_client *surface_client = + wl_resource_get_client(view->surface->resource); + + move_resources_for_client(focus_resource_list, + &tablet->resource_list, + surface_client); + tablet->focus_serial = + wl_display_next_serial(seat->compositor->wl_display); + + wl_resource_for_each(resource, focus_resource_list) + wl_tablet_send_proximity_in(resource, + tablet->focus_serial, + time, NULL, + view->surface->resource); + } + + wl_list_remove(&tablet->focus_view_listener.link); + wl_list_init(&tablet->focus_view_listener.link); + wl_list_remove(&tablet->focus_resource_listener.link); + wl_list_init(&tablet->focus_resource_listener.link); + if (view) + wl_signal_add(&view->destroy_signal, + &tablet->focus_view_listener); + if (view && view->surface->resource) + wl_resource_add_destroy_listener(view->surface->resource, + &tablet->focus_resource_listener); + + tablet->focus = view; + tablet->focus_view_listener.notify = tablet_focus_view_destroyed; +} + static void seat_send_updated_caps(struct weston_seat *seat) { @@ -1531,6 +1695,60 @@ notify_touch_frame(struct weston_seat *seat) grab->interface->frame(grab); } +static const struct wl_tablet_interface tablet_interface; + +WL_EXPORT void +notify_tablet_added(struct weston_tablet *tablet) +{ + struct wl_resource *resource; + struct weston_seat *seat = tablet->seat; + + wl_resource_for_each(resource, &seat->tablet_manager_resource_list) { + struct wl_resource *tablet_resource = + wl_resource_create(wl_resource_get_client(resource), + &wl_tablet_interface, + 1, 0); + + wl_list_insert(&tablet->resource_list, + wl_resource_get_link(tablet_resource)); + wl_resource_set_implementation(tablet_resource, + &tablet_interface, + tablet, + unbind_resource); + + wl_resource_set_user_data(tablet_resource, tablet); + wl_tablet_manager_send_device_added(resource, tablet_resource, + tablet->name, tablet->vid, + tablet->pid, 0, 0); + } +} + +WL_EXPORT void +notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time) +{ + struct weston_tablet_grab *grab = tablet->grab; + + grab->interface->proximity_out(grab, time); +} + +WL_EXPORT void +notify_tablet_motion(struct weston_tablet *tablet, uint32_t time, + wl_fixed_t x, wl_fixed_t y) +{ + struct weston_tablet_grab *grab = tablet->grab; + + weston_compositor_wake(tablet->seat->compositor); + grab->interface->motion(grab, time, x, y); +} + +WL_EXPORT void +notify_tablet_frame(struct weston_tablet *tablet) +{ + struct weston_tablet_grab *grab = tablet->grab; + + grab->interface->frame(grab); +} + static void pointer_cursor_surface_configure(struct weston_surface *es, int32_t dx, int32_t dy) @@ -1809,6 +2027,16 @@ static const struct wl_seat_interface seat_interface = { }; static void +tablet_release(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct wl_tablet_interface tablet_interface = { + tablet_release, +}; + +static void bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct weston_seat *seat = data; @@ -1833,6 +2061,44 @@ bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id) wl_seat_send_name(resource, seat->seat_name); } +static void +bind_tablet_manager(struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct weston_seat *seat = data; + struct wl_resource *seat_resource = + wl_resource_find_for_client(&seat->base_resource_list, client); + struct wl_resource *resource; + struct weston_tablet *tablet; + + resource = wl_resource_create(client, &wl_tablet_manager_interface, + MIN(version, 1), id); + wl_resource_set_implementation(resource, NULL, data, unbind_resource); + wl_list_insert(&seat->tablet_manager_resource_list, + wl_resource_get_link(resource)); + + /* Notify the client of the wl_seat object we're associated with */ + wl_tablet_manager_send_seat(resource, seat_resource); + + /* Notify the client of all tablets currently connected to the system */ + wl_list_for_each(tablet, &seat->tablet_list, link) { + struct wl_resource *tablet_resource = + wl_resource_create(client, &wl_tablet_interface, 1, 0); + + wl_resource_set_implementation(tablet_resource, + &tablet_interface, tablet, + unbind_resource); + wl_resource_set_user_data(tablet_resource, tablet); + + wl_list_insert(&tablet->resource_list, + wl_resource_get_link(tablet_resource)); + + wl_tablet_manager_send_device_added(resource, tablet_resource, + tablet->name, tablet->vid, + tablet->pid, 0, 0); + } +} + #ifdef ENABLE_XKBCOMMON int weston_compositor_xkb_init(struct weston_compositor *ec, @@ -2185,6 +2451,42 @@ weston_seat_init_touch(struct weston_seat *seat) seat_send_updated_caps(seat); } +WL_EXPORT struct weston_tablet * +weston_seat_add_tablet(struct weston_seat *seat) +{ + struct weston_tablet *tablet; + + seat->tablet_device_count++; + if (seat->tablet_device_count == 1) + seat_send_updated_caps(seat); + + tablet = weston_tablet_create(); + if (tablet == NULL) + return NULL; + + tablet->seat = seat; + + return tablet; +} + +WL_EXPORT void +weston_seat_release_tablet(struct weston_tablet *tablet) +{ + struct wl_resource *resource; + + weston_tablet_set_focus(tablet, NULL, 0); + wl_resource_for_each(resource, &tablet->resource_list) + wl_tablet_send_removed(resource); + + tablet->seat->tablet_device_count--; + wl_list_remove(&tablet->link); + + if (tablet->seat->tablet_device_count == 0) + seat_send_updated_caps(tablet->seat); + + weston_tablet_destroy(tablet); +} + WL_EXPORT void weston_seat_release_touch(struct weston_seat *seat) { @@ -2209,9 +2511,14 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec, wl_list_init(&seat->drag_resource_list); wl_signal_init(&seat->destroy_signal); wl_signal_init(&seat->updated_caps_signal); + wl_list_init(&seat->tablet_list); + wl_list_init(&seat->tablet_manager_resource_list); seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4, seat, bind_seat); + seat->tablet_manager = wl_global_create(ec->wl_display, + &wl_tablet_manager_interface, + 1, seat, bind_tablet_manager); seat->compositor = ec; seat->modifier_state = 0; @@ -2227,6 +2534,8 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec, WL_EXPORT void weston_seat_release(struct weston_seat *seat) { + struct weston_tablet *tablet; + wl_list_remove(&seat->link); if (seat->saved_kbd_focus) @@ -2238,10 +2547,13 @@ weston_seat_release(struct weston_seat *seat) weston_keyboard_destroy(seat->keyboard); if (seat->touch) weston_touch_destroy(seat->touch); + wl_list_for_each(tablet, &seat->tablet_list, link) + weston_tablet_destroy(tablet); free (seat->seat_name); wl_global_destroy(seat->global); + wl_global_destroy(seat->tablet_manager); wl_signal_emit(&seat->destroy_signal, seat); } diff --git a/src/libinput-device.c b/src/libinput-device.c index 2ba4ec3..f5ed2a0 100644 --- a/src/libinput-device.c +++ b/src/libinput-device.c @@ -38,6 +38,14 @@ #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10) +struct tablet_output_listener { + struct wl_listener base; + struct wl_list tablet_list; +}; + +static int +tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output); + void evdev_led_update(struct evdev_device *device, enum weston_led weston_leds) { @@ -210,6 +218,51 @@ handle_touch_frame(struct libinput_device *libinput_device, notify_touch_frame(seat); } +static void +handle_tablet_axis(struct libinput_device *libinput_device, + struct libinput_event_tablet *axis_event) +{ + struct evdev_device *device = + libinput_device_get_user_data(libinput_device); + struct weston_tablet *tablet = device->tablet; + + if (libinput_event_tablet_axis_has_changed(axis_event, + LIBINPUT_TABLET_AXIS_X) || + libinput_event_tablet_axis_has_changed(axis_event, + LIBINPUT_TABLET_AXIS_Y)) { + double x, y; + uint32_t width, height, + time; + + time = libinput_event_tablet_get_time(axis_event); + + width = tablet->output->current_mode->width; + height = tablet->output->current_mode->height; + x = libinput_event_tablet_get_x_transformed(axis_event, width); + y = libinput_event_tablet_get_y_transformed(axis_event, height); + + notify_tablet_motion(tablet, time, + wl_fixed_from_double(x), + wl_fixed_from_double(y)); + } + + notify_tablet_frame(tablet); +} + +static void +handle_tablet_proximity_out(struct libinput_device *libinput_device, + struct libinput_event_tablet *proximity_out_event) +{ + struct evdev_device *device = + libinput_device_get_user_data(libinput_device); + struct weston_tablet *tablet = device->tablet; + uint32_t time; + + time = libinput_event_tablet_get_time(proximity_out_event); + + notify_tablet_proximity_out(tablet, time); +} + int evdev_device_process_event(struct libinput_event *event) { @@ -255,6 +308,15 @@ evdev_device_process_event(struct libinput_event *event) handle_touch_frame(libinput_device, libinput_event_get_touch_event(event)); break; + case LIBINPUT_EVENT_TABLET_AXIS: + handle_tablet_axis(libinput_device, + libinput_event_get_tablet_event(event)); + break; + case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT: + handle_tablet_proximity_out( + libinput_device, + libinput_event_get_tablet_event(event)); + break; default: handled = 0; weston_log("unknown libinput event %d\n", @@ -297,6 +359,81 @@ evdev_device_set_output(struct evdev_device *device, &device->output_destroy_listener); } +static void +bind_unbound_tablets(struct wl_listener *listener_base, void *data) +{ + struct tablet_output_listener *listener = + wl_container_of(listener_base, listener, base); + struct weston_tablet *tablet, *tmp; + + wl_list_for_each_safe(tablet, tmp, &listener->tablet_list, link) { + if (tablet_bind_output(tablet, data)) { + wl_list_remove(&tablet->link); + wl_list_insert(&tablet->seat->tablet_list, + &tablet->link); + tablet->device->seat_caps |= EVDEV_SEAT_TABLET; + notify_tablet_added(tablet); + } + } + + if (wl_list_empty(&listener->tablet_list)) { + wl_list_remove(&listener_base->link); + free(listener); + } +} + +static int +tablet_bind_output(struct weston_tablet *tablet, struct weston_output *output) +{ + struct wl_list *output_list = &tablet->seat->compositor->output_list; + struct weston_compositor *compositor = tablet->seat->compositor; + + /* TODO: Properly bind tablets with built-in displays */ + switch (tablet->type) { + case WL_TABLET_MANAGER_TABLET_TYPE_EXTERNAL: + case WL_TABLET_MANAGER_TABLET_TYPE_INTERNAL: + case WL_TABLET_MANAGER_TABLET_TYPE_DISPLAY: + if (output) + tablet->output = output; + else { + if (wl_list_empty(output_list)) + break; + + /* Find the first available display */ + wl_list_for_each(output, output_list, link) + break; + tablet->output = output; + } + } + + if (!tablet->output) { + struct tablet_output_listener *listener; + struct wl_listener *listener_base; + + listener_base = + wl_signal_get(&compositor->output_created_signal, + bind_unbound_tablets); + if (listener_base == NULL) { + listener = zalloc(sizeof(*listener)); + + wl_list_init(&listener->tablet_list); + + listener_base = &listener->base; + listener_base->notify = bind_unbound_tablets; + + wl_signal_add(&compositor->output_created_signal, + listener_base); + } else + listener = wl_container_of(listener_base, listener, + base); + + wl_list_insert(&listener->tablet_list, &tablet->link); + return 0; + } + + return 1; +} + struct evdev_device * evdev_device_create(struct libinput_device *libinput_device, struct weston_seat *seat) @@ -326,6 +463,27 @@ evdev_device_create(struct libinput_device *libinput_device, weston_seat_init_touch(seat); device->seat_caps |= EVDEV_SEAT_TOUCH; } + if (libinput_device_has_capability(libinput_device, + LIBINPUT_DEVICE_CAP_TABLET)) { + struct weston_tablet *tablet = weston_seat_add_tablet(seat); + + tablet->name = strdup(libinput_device_get_name(libinput_device)); + tablet->vid = libinput_device_get_id_vendor(libinput_device); + tablet->pid = libinput_device_get_id_product(libinput_device); + + /* If we can successfully bind the tablet to an output, then + * it's ready to get added to the seat's tablet list, otherwise + * it will get added when an appropriate output is available */ + if (tablet_bind_output(tablet, NULL)) { + wl_list_insert(&seat->tablet_list, &tablet->link); + device->seat_caps |= EVDEV_SEAT_TABLET; + + notify_tablet_added(tablet); + } + + device->tablet = tablet; + tablet->device = device; + } libinput_device_set_user_data(libinput_device, device); libinput_device_ref(libinput_device); @@ -342,6 +500,8 @@ evdev_device_destroy(struct evdev_device *device) weston_seat_release_keyboard(device->seat); if (device->seat_caps & EVDEV_SEAT_TOUCH) weston_seat_release_touch(device->seat); + if (device->seat_caps & EVDEV_SEAT_TABLET) + weston_seat_release_tablet(device->tablet); if (device->output) wl_list_remove(&device->output_destroy_listener.link); diff --git a/src/libinput-device.h b/src/libinput-device.h index 0775743..02a2095 100644 --- a/src/libinput-device.h +++ b/src/libinput-device.h @@ -34,7 +34,8 @@ enum evdev_device_seat_capability { EVDEV_SEAT_POINTER = (1 << 0), EVDEV_SEAT_KEYBOARD = (1 << 1), - EVDEV_SEAT_TOUCH = (1 << 2) + EVDEV_SEAT_TOUCH = (1 << 2), + EVDEV_SEAT_TABLET = (1 << 3) }; struct evdev_device { @@ -44,6 +45,7 @@ struct evdev_device { struct wl_list link; struct weston_output *output; struct wl_listener output_destroy_listener; + struct weston_tablet *tablet; char *devnode; char *output_name; int fd; -- 1.8.5.5 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
