Signed-off-by: Stephen Chandler Paul <thatsly...@gmail.com>
---
 src/compositor.h      | 16 ++++++++++
 src/input.c           | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/libinput-device.c | 72 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/src/compositor.h b/src/compositor.h
index be28591..46619e3 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -398,6 +398,16 @@ struct weston_touch {
        uint32_t grab_time;
 };
 
+struct weston_tablet_tool {
+       enum wl_tablet_tool_type type;
+       uint32_t serial;
+
+       struct wl_signal destroy_signal;
+
+       struct wl_list resource_list;
+       struct wl_list link;
+};
+
 struct weston_tablet {
        struct weston_seat *seat;
        struct evdev_device *device;
@@ -409,6 +419,8 @@ struct weston_tablet {
        struct wl_listener focus_resource_listener;
        uint32_t focus_serial;
 
+       struct weston_tablet_tool *current_tool;
+
        int32_t hotspot_x, hotspot_y;
        wl_fixed_t x, y;
 
@@ -579,6 +591,7 @@ struct weston_seat {
        struct weston_keyboard *keyboard;
        struct weston_touch *touch;
        struct wl_list tablet_list;
+       struct wl_list tablet_tool_list;
        int pointer_device_count;
        int keyboard_device_count;
        int touch_device_count;
@@ -1101,6 +1114,9 @@ notify_touch_frame(struct weston_seat *seat);
 void
 notify_tablet_added(struct weston_tablet *tablet);
 void
+notify_tablet_proximity_in(struct weston_tablet *tablet, uint32_t time,
+                          struct weston_tablet_tool *tool);
+void
 notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time);
 void
 notify_tablet_motion(struct weston_tablet *tablet, uint32_t time,
diff --git a/src/input.c b/src/input.c
index 6048bb8..19e9971 100644
--- a/src/input.c
+++ b/src/input.c
@@ -441,6 +441,16 @@ static const struct weston_keyboard_grab_interface
 };
 
 static void
+default_grab_tablet_proximity_in(struct weston_tablet_grab *grab, uint32_t 
time,
+                                struct weston_tablet_tool *tool)
+{
+       /* default_grab_tablet_motion handles sending proximity_in events,
+        * since we can't figure out what surface to send the events to until
+        * we have the first motion event after proximity_in, so just don't do
+        * anything here */
+}
+
+static void
 default_grab_tablet_proximity_out(struct weston_tablet_grab *grab,
                                  uint32_t time)
 {
@@ -489,7 +499,7 @@ default_grab_tablet_cancel(struct weston_tablet_grab *grab)
 }
 
 static struct weston_tablet_grab_interface default_tablet_grab_interface = {
-       NULL,
+       default_grab_tablet_proximity_in,
        default_grab_tablet_proximity_out,
        default_grab_tablet_motion,
        NULL,
@@ -728,6 +738,11 @@ weston_tablet_destroy(struct weston_tablet *tablet)
        free(tablet);
 }
 
+static const struct wl_tablet_tool_interface tablet_tool_interface;
+
+static void
+unbind_tablet_tool_resource(struct wl_resource *resource);
+
 WL_EXPORT void
 weston_tablet_set_focus(struct weston_tablet *tablet, struct weston_view *view,
                        uint32_t time)
@@ -735,6 +750,7 @@ weston_tablet_set_focus(struct weston_tablet *tablet, 
struct weston_view *view,
        struct wl_list *focus_resource_list;
        struct wl_resource *resource;
        struct weston_seat *seat = tablet->seat;
+       struct weston_tablet_tool *tool = tablet->current_tool;
 
        focus_resource_list = &tablet->focus_resource_list;
 
@@ -757,11 +773,39 @@ weston_tablet_set_focus(struct weston_tablet *tablet, 
struct weston_view *view,
                tablet->focus_serial =
                        wl_display_next_serial(seat->compositor->wl_display);
 
-               wl_resource_for_each(resource, focus_resource_list)
+               if (!tool)
+                       return;
+
+               wl_resource_for_each(resource, focus_resource_list) {
+                       struct wl_resource *tool_resource;
+
+                       tool_resource = wl_resource_find_for_client(
+                           &tool->resource_list, surface_client);
+                       if (!tool_resource) {
+                               tool_resource = wl_resource_create(
+                                   surface_client, &wl_tablet_tool_interface,
+                                   1, 0);
+
+                               wl_resource_set_implementation(
+                                   tool_resource, &tablet_tool_interface, tool,
+                                   unbind_tablet_tool_resource);
+
+                               wl_list_insert(
+                                   &tool->resource_list,
+                                   wl_resource_get_link(tool_resource));
+
+                               wl_tablet_manager_send_tool_added(
+                                   wl_resource_find_for_client(
+                                       &seat->tablet_manager_resource_list,
+                                       surface_client),
+                                   tool_resource, tool->type, tool->serial);
+                       }
+
                        wl_tablet_send_proximity_in(resource,
                                                    tablet->focus_serial,
-                                                   time, NULL,
+                                                   time, tool_resource,
                                                    view->surface->resource);
+               }
        } else if (tablet->sprite)
                tablet_unmap_sprite(tablet);
 
@@ -1785,6 +1829,17 @@ notify_tablet_added(struct weston_tablet *tablet)
 }
 
 WL_EXPORT void
+notify_tablet_proximity_in(struct weston_tablet *tablet,
+                          uint32_t time, struct weston_tablet_tool *tool)
+{
+       struct weston_tablet_grab *grab = tablet->grab;
+
+       tablet->current_tool = tool;
+
+       grab->interface->proximity_in(grab, time, tool);
+}
+
+WL_EXPORT void
 notify_tablet_proximity_out(struct weston_tablet *tablet, uint32_t time)
 {
        struct weston_tablet_grab *grab = tablet->grab;
@@ -2087,6 +2142,30 @@ static const struct wl_seat_interface seat_interface = {
        seat_get_touch,
 };
 
+static void unbind_tablet_tool_resource(struct wl_resource *resource)
+{
+       struct weston_tablet_tool *tool = wl_resource_get_user_data(resource);
+
+       unbind_resource(resource);
+
+       if (wl_list_empty(&tool->resource_list)) {
+               wl_signal_emit(&tool->destroy_signal, tool);
+
+               wl_list_remove(&tool->link);
+               free(tool);
+       }
+}
+
+static void
+tablet_tool_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_tablet_tool_interface tablet_tool_interface = {
+       tablet_tool_release,
+};
+
 static void
 tablet_release(struct wl_client *client, struct wl_resource *resource)
 {
@@ -2658,6 +2737,7 @@ weston_seat_init(struct weston_seat *seat, struct 
weston_compositor *ec,
        wl_signal_init(&seat->updated_caps_signal);
        wl_list_init(&seat->tablet_list);
        wl_list_init(&seat->tablet_manager_resource_list);
+       wl_list_init(&seat->tablet_tool_list);
 
        seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 4,
                                        seat, bind_seat);
diff --git a/src/libinput-device.c b/src/libinput-device.c
index f5ed2a0..0501e9b 100644
--- a/src/libinput-device.c
+++ b/src/libinput-device.c
@@ -218,6 +218,74 @@ handle_touch_frame(struct libinput_device *libinput_device,
        notify_touch_frame(seat);
 }
 
+struct tool_destroy_listener {
+       struct wl_listener base;
+       struct libinput_tool *tool;
+};
+
+/* Because a libinput tool has the potential to stay in the memory after the
+ * last tablet disconnects, we need to make sure that we clear the user data on
+ * the tool after one of our tool objects is destroyed */
+static void
+reset_libinput_tool_data(struct wl_listener *listener, void *data)
+{
+       struct tool_destroy_listener *tool_destroy_listener =
+               container_of(listener, struct tool_destroy_listener, base);
+
+       libinput_tool_set_user_data(tool_destroy_listener->tool, NULL);
+       free(tool_destroy_listener);
+}
+
+static void
+handle_tablet_proximity_in(struct libinput_device *libinput_device,
+                          struct libinput_event_tablet *proximity_in_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       struct weston_tablet *tablet = device->tablet;
+       struct libinput_tool *libinput_tool;
+       struct weston_tablet_tool *tool;
+       uint32_t time;
+
+       time = libinput_event_tablet_get_time(proximity_in_event);
+       libinput_tool = libinput_event_tablet_get_tool(proximity_in_event);
+       tool = libinput_tool_get_user_data(libinput_tool);
+       if (!tool) {
+               struct tool_destroy_listener *listener;
+
+               listener = malloc(sizeof *listener);
+               if (!listener) {
+                       weston_log("failed to allocate memory for a new tablet "
+                                  "tool destroy listener, events with this "
+                                  "tool will be dropped\n");
+                       return;
+               }
+
+               tool = malloc(sizeof *tool);
+               if (!tool) {
+                       weston_log("failed to allocate memory for a new "
+                                  "tablet tool, events from this tool will be "
+                                  "dropped\n");
+                       free(listener);
+                       return;
+               }
+
+               tool->type = libinput_tool_get_type(libinput_tool);
+               tool->serial = libinput_tool_get_serial(libinput_tool);
+               wl_list_init(&tool->resource_list);
+               wl_list_insert(&tablet->seat->tablet_tool_list, &tool->link);
+
+               listener->base.notify = reset_libinput_tool_data;
+               listener->tool = libinput_tool;
+               wl_signal_init(&tool->destroy_signal);
+               wl_signal_add(&tool->destroy_signal, &listener->base);
+
+               libinput_tool_set_user_data(libinput_tool, tool);
+       }
+
+       notify_tablet_proximity_in(tablet, time, tool);
+}
+
 static void
 handle_tablet_axis(struct libinput_device *libinput_device,
                   struct libinput_event_tablet *axis_event)
@@ -312,6 +380,10 @@ evdev_device_process_event(struct libinput_event *event)
                handle_tablet_axis(libinput_device,
                                   libinput_event_get_tablet_event(event));
                break;
+       case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
+               handle_tablet_proximity_in(
+                   libinput_device, libinput_event_get_tablet_event(event));
+               break;
        case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
                handle_tablet_proximity_out(
                    libinput_device,
-- 
1.8.5.5

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to