[PATCH weston 07/19] tablet: Add support for tablet tool objects

Stephen Chandler Paul thatslyude at gmail.com
Wed Aug 6 16:07:57 PDT 2014


Signed-off-by: Stephen Chandler Paul <thatslyude at 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



More information about the wayland-devel mailing list