[gtk+/wip/wayland-tablet: 1267/1271] Wayland: Add initial support for drawing tablets
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/wayland-tablet: 1267/1271] Wayland: Add initial support for drawing tablets
- Date: Wed, 21 Oct 2015 18:07:28 +0000 (UTC)
commit 13d970e541c518fac870973e69f7d6805454b36f
Author: Stephen Chandler Paul <thatslyude gmail com>
Date: Sun Jan 18 19:32:24 2015 -0500
Wayland: Add initial support for drawing tablets
Only the management of tablets and tools is added so far. No tablet events
are yet interpreted.
As it's been the tradition in GTK+, erasers are split into their own device,
whereas the rest of the tools are meant to be routed through the
GDK_SOURCE_PEN device. Both pen/eraser devices are slaves to a master
pointer device, separate to wl_pointer's. This is so each tablet can
maintain its own cursor/positioning accounting.
Signed-off-by: Stephen Chandler Paul <thatslyude gmail com>
gdk/wayland/gdkdevice-wayland.c | 357 +++++++++++++++++++++++++++++++++++++-
gdk/wayland/gdkdisplay-wayland.c | 7 +
gdk/wayland/gdkdisplay-wayland.h | 1 +
gdk/wayland/gdkprivate-wayland.h | 2 +
4 files changed, 360 insertions(+), 7 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 0c20238..8e7688d 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -38,6 +38,7 @@
typedef struct _GdkWaylandTouchData GdkWaylandTouchData;
typedef struct _GdkWaylandPointerData GdkWaylandPointerData;
+typedef struct _GdkWaylandDeviceTabletPair GdkWaylandDeviceTabletPair;
struct _GdkWaylandTouchData
{
@@ -74,6 +75,18 @@ struct _GdkWaylandPointerData {
GSList *pointer_surface_outputs;
};
+struct _GdkWaylandDeviceTabletPair
+{
+ struct wl_tablet *wl_tablet;
+ GdkDevice *master;
+ GdkDevice *stylus_device;
+ GdkDevice *eraser_device;
+ GdkDevice *current_device;
+
+ GdkWaylandDeviceData *wd;
+ GdkWaylandPointerData pointer_info;
+};
+
struct _GdkWaylandDeviceData
{
guint32 id;
@@ -83,6 +96,7 @@ struct _GdkWaylandDeviceData
struct wl_touch *wl_touch;
struct _wl_pointer_gesture_swipe *wl_pointer_gesture_swipe;
struct _wl_pointer_gesture_pinch *wl_pointer_gesture_pinch;
+ struct wl_tablet_manager *wl_tablet_manager;
GdkDisplay *display;
GdkDeviceManager *device_manager;
@@ -153,6 +167,7 @@ struct _GdkWaylandDeviceManager
{
GdkDeviceManager parent_object;
GList *devices;
+ GList *tablet_pairs;
};
struct _GdkWaylandDeviceManagerClass
@@ -206,6 +221,26 @@ gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer)
pointer->cursor_image_delay = 0;
}
+static GdkWaylandDeviceTabletPair *
+gdk_wayland_device_manager_find_tablet_pair (GdkDeviceManager *device_manager,
+ GdkDevice *device)
+{
+ GdkWaylandDeviceManager *wdm = GDK_WAYLAND_DEVICE_MANAGER (device_manager);
+ GList *l;
+
+ for (l = wdm->tablet_pairs; l; l = l->next)
+ {
+ GdkWaylandDeviceTabletPair *pair = l->data;
+
+ if (pair->master == device ||
+ pair->stylus_device == device ||
+ pair->eraser_device == device)
+ return pair;
+ }
+
+ return NULL;
+}
+
static gboolean
gdk_wayland_device_update_window_cursor (GdkDevice *device)
{
@@ -214,8 +249,11 @@ gdk_wayland_device_update_window_cursor (GdkDevice *device)
struct wl_buffer *buffer;
int x, y, w, h, scale;
guint next_image_index, next_image_delay;
+ GdkWaylandDeviceTabletPair *pair;
gboolean retval = G_SOURCE_REMOVE;
+ pair = gdk_wayland_device_manager_find_tablet_pair (wd->device_manager, device);
+
if (pointer->cursor)
{
buffer = _gdk_wayland_cursor_get_buffer (pointer->cursor,
@@ -228,13 +266,23 @@ gdk_wayland_device_update_window_cursor (GdkDevice *device)
return retval;
}
- if (!wd->wl_pointer)
+ if (pair)
+ {
+ wl_tablet_set_cursor (pair->wl_tablet,
+ pointer->enter_serial,
+ pointer->pointer_surface,
+ x, y);
+ }
+ else if (wd->wl_pointer)
+ {
+ wl_pointer_set_cursor (wd->wl_pointer,
+ pointer->enter_serial,
+ pointer->pointer_surface,
+ x, y);
+ }
+ else
return retval;
- wl_pointer_set_cursor (wd->wl_pointer,
- pointer->enter_serial,
- pointer->pointer_surface,
- x, y);
if (buffer)
{
wl_surface_attach (pointer->pointer_surface, buffer, 0, 0);
@@ -471,8 +519,19 @@ gdk_wayland_device_get_focus (GdkDevice *device)
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
return wayland_device->keyboard_focus;
+ else if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE)
+ return wayland_device->pointer_info.focus;
else
- return wayland_device->pointer_focus;
+ {
+ GdkWaylandDeviceTabletPair *pair;
+
+ pair = gdk_wayland_device_manager_find_tablet_pair (wayland_device->device_manager,
+ device);
+ if (pair)
+ return pair->pointer_info.focus;
+ }
+
+ return NULL;
}
static GdkGrabStatus
@@ -887,7 +946,6 @@ pointer_handle_enter (void *data,
if (!surface)
return;
-
if (!GDK_IS_WINDOW (wl_surface_get_user_data (surface)))
return;
@@ -1914,6 +1972,73 @@ gesture_pinch_end (void *data,
0, 0, 1, 0);
}
+static GdkDevice *
+tablet_select_device_for_tool (GdkWaylandDeviceTabletPair *device_pair,
+ GdkDeviceTool *tool)
+{
+ GdkDevice *device;
+
+ if (gdk_device_tool_get_tool_type (tool) == GDK_DEVICE_TOOL_TYPE_ERASER)
+ device = device_pair->eraser_device;
+ else
+ device = device_pair->stylus_device;
+
+ return device;
+}
+
+static void
+_gdk_wayland_device_manager_remove_tablet (GdkWaylandDeviceTabletPair *device_pair)
+{
+ GdkWaylandDeviceManager *device_manager =
+ GDK_WAYLAND_DEVICE_MANAGER (device_pair->wd->device_manager);
+
+ wl_tablet_release (device_pair->wl_tablet);
+
+ device_manager->devices =
+ g_list_remove (device_manager->devices, device_pair->master);
+ device_manager->devices =
+ g_list_remove (device_manager->devices, device_pair->stylus_device);
+ device_manager->devices =
+ g_list_remove (device_manager->devices, device_pair->eraser_device);
+
+ g_signal_emit_by_name (device_manager, "device-removed",
+ device_pair->stylus_device);
+ g_signal_emit_by_name (device_manager, "device-removed",
+ device_pair->eraser_device);
+ g_signal_emit_by_name (device_manager, "device-removed",
+ device_pair->master);
+
+ _gdk_device_set_associated_device (device_pair->master, NULL);
+ _gdk_device_set_associated_device (device_pair->stylus_device, NULL);
+ _gdk_device_set_associated_device (device_pair->eraser_device, NULL);
+
+ if (device_pair->pointer_info.focus)
+ g_object_unref (device_pair->pointer_info.focus);
+
+ wl_surface_destroy (device_pair->pointer_info.pointer_surface);
+ g_object_unref (device_pair->master);
+ g_object_unref (device_pair->stylus_device);
+ g_object_unref (device_pair->eraser_device);
+ g_free (device_pair);
+
+ device_manager->tablet_pairs =
+ g_list_remove (device_manager->tablet_pairs, device_pair);
+}
+
+static void
+tablet_handler_placeholder ()
+{
+}
+
+static void
+tablet_handle_removed (void *data,
+ struct wl_tablet *wl_tablet)
+{
+ GdkWaylandDeviceTabletPair *device_pair = data;
+
+ _gdk_wayland_device_manager_remove_tablet (device_pair);
+}
+
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
pointer_handle_leave,
@@ -1951,6 +2076,20 @@ static const struct _wl_pointer_gesture_pinch_listener gesture_pinch_listener =
gesture_pinch_end
};
+static const struct wl_tablet_listener tablet_listener = {
+ tablet_handler_placeholder, /* proximity_in */
+ tablet_handler_placeholder, /* proximity_out */
+ tablet_handler_placeholder, /* motion */
+ tablet_handler_placeholder, /* down */
+ tablet_handler_placeholder, /* up */
+ tablet_handler_placeholder, /* pressure */
+ tablet_handler_placeholder, /* distance */
+ tablet_handler_placeholder, /* tilt */
+ tablet_handler_placeholder, /* button */
+ tablet_handler_placeholder, /* frame */
+ tablet_handle_removed
+};
+
static void
seat_handle_capabilities (void *data,
struct wl_seat *seat,
@@ -2117,6 +2256,197 @@ static const struct wl_seat_listener seat_listener = {
};
static void
+tablet_tool_handle_removed (void *data,
+ struct wl_tablet_tool *wl_tool)
+{
+ GdkDeviceTool *tool = data;
+
+ gdk_device_tool_unref (tool);
+}
+
+static const struct wl_tablet_tool_listener tablet_tool_listener = {
+ tablet_tool_handle_removed
+};
+
+static void
+tablet_manager_handle_device_added (void *data,
+ struct wl_tablet_manager *wl_tablet_manager,
+ struct wl_tablet *id,
+ const char *name,
+ uint32_t vid,
+ uint32_t pid,
+ uint32_t type)
+{
+ GdkWaylandDeviceData *device =
+ wl_tablet_manager_get_user_data (wl_tablet_manager);
+ GdkWaylandDeviceManager *device_manager =
+ GDK_WAYLAND_DEVICE_MANAGER (device->device_manager);
+ GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (device->display);
+ GdkWaylandDeviceTabletPair *device_pair;
+ GdkDevice *master, *stylus_device, *eraser_device;
+ gchar *master_name, *eraser_name;
+
+ device_pair = g_new0 (GdkWaylandDeviceTabletPair, 1);
+ device_pair->wd = device;
+ device_pair->pointer_info.current_output_scale = 1;
+ device_pair->pointer_info.pointer_surface =
+ wl_compositor_create_surface (wayland_display->compositor);
+ device_pair->wl_tablet = id;
+
+ master_name = g_strdup_printf ("Master pointer for %s", name);
+ master = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
+ "name", master_name,
+ "type", GDK_DEVICE_TYPE_MASTER,
+ "input-source", GDK_SOURCE_MOUSE,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", TRUE,
+ "display", device->display,
+ "device-manager", device->device_manager,
+ NULL);
+ GDK_WAYLAND_DEVICE (master)->device = device;
+ GDK_WAYLAND_DEVICE (master)->pointer = &device_pair->pointer_info;
+
+ eraser_name = g_strconcat (name, " (Eraser)", NULL);
+
+ stylus_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
+ "name", name,
+ "type", GDK_DEVICE_TYPE_SLAVE,
+ "input-source", GDK_SOURCE_PEN,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", device->display,
+ "device-manager", device->device_manager,
+ NULL);
+ GDK_WAYLAND_DEVICE (stylus_device)->device = device;
+
+ eraser_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
+ "name", eraser_name,
+ "type", GDK_DEVICE_TYPE_SLAVE,
+ "input-source", GDK_SOURCE_ERASER,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", FALSE,
+ "display", device->display,
+ "device-manager", device->device_manager,
+ NULL);
+ GDK_WAYLAND_DEVICE (eraser_device)->device = device;
+
+ device_pair->master = master;
+ device_manager->devices =
+ g_list_prepend (device_manager->devices, device_pair->master);
+ g_signal_emit_by_name (device_manager, "device-added", master);
+
+ device_pair->stylus_device = stylus_device;
+ device_manager->devices =
+ g_list_prepend (device_manager->devices, device_pair->stylus_device);
+ g_signal_emit_by_name (device_manager, "device-added", stylus_device);
+
+ device_pair->eraser_device = eraser_device;
+ device_manager->devices =
+ g_list_prepend (device_manager->devices, device_pair->eraser_device);
+ g_signal_emit_by_name (device_manager, "device-added", eraser_device);
+
+ wl_tablet_add_listener (id, &tablet_listener, device_pair);
+
+ _gdk_device_set_associated_device (master, device->master_keyboard);
+ _gdk_device_set_associated_device (stylus_device, master);
+ _gdk_device_set_associated_device (eraser_device, master);
+
+ device_manager->tablet_pairs =
+ g_list_prepend (device_manager->tablet_pairs, device_pair);
+
+ g_free (eraser_name);
+ g_free (master_name);
+}
+
+static inline GdkDeviceToolType
+wl_tool_type_to_gdk_tool_type (enum wl_tablet_tool_type wl_tool_type)
+{
+ GdkDeviceToolType tool_type;
+
+ switch (wl_tool_type)
+ {
+ case WL_TABLET_TOOL_TYPE_PEN:
+ tool_type = GDK_DEVICE_TOOL_TYPE_PEN;
+ break;
+ case WL_TABLET_TOOL_TYPE_BRUSH:
+ tool_type = GDK_DEVICE_TOOL_TYPE_BRUSH;
+ break;
+ case WL_TABLET_TOOL_TYPE_AIRBRUSH:
+ tool_type = GDK_DEVICE_TOOL_TYPE_AIRBRUSH;
+ break;
+ case WL_TABLET_TOOL_TYPE_PENCIL:
+ tool_type = GDK_DEVICE_TOOL_TYPE_PENCIL;
+ break;
+ case WL_TABLET_TOOL_TYPE_ERASER:
+ tool_type = GDK_DEVICE_TOOL_TYPE_ERASER;
+ break;
+ default:
+ tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
+ break;
+ };
+
+ return tool_type;
+}
+
+GdkAxisFlags
+wl_tablet_tool_axis_flag_to_gdk_axes (uint32_t tool_axes)
+{
+ GdkAxisFlags axes = GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
+
+ if (tool_axes & WL_TABLET_TOOL_AXIS_FLAG_TILT)
+ axes |= GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT;
+ if (tool_axes & WL_TABLET_TOOL_AXIS_FLAG_DISTANCE)
+ axes |= GDK_AXIS_FLAG_DISTANCE;
+ if (tool_axes & WL_TABLET_TOOL_AXIS_FLAG_PRESSURE)
+ axes |= GDK_AXIS_FLAG_PRESSURE;
+
+ return axes;
+}
+
+static void
+tablet_manager_handle_tool_added (void *data,
+ struct wl_tablet_manager *wl_tablet_manager,
+ struct wl_tablet_tool *wl_tablet_tool,
+ struct wl_tablet *wl_tablet,
+ uint32_t tool_type,
+ uint32_t tool_serial,
+ uint32_t extra_axes)
+{
+ GdkWaylandDeviceTabletPair *device_pair =
+ wl_tablet_get_user_data (wl_tablet);
+ GdkDeviceTool *tool;
+
+ tool = gdk_device_tool_new (tool_serial,
+ wl_tool_type_to_gdk_tool_type (tool_type),
+ wl_tablet_tool_axis_flag_to_gdk_axes (extra_axes));
+
+ gdk_device_add_tool (tablet_select_device_for_tool (device_pair, tool),
+ tool);
+
+ wl_tablet_tool_add_listener (wl_tablet_tool, &tablet_tool_listener, tool);
+}
+
+static void
+tablet_manager_handle_seat (void *data,
+ struct wl_tablet_manager *wl_tablet_manager,
+ struct wl_seat *seat)
+{
+ GdkWaylandDeviceData *device = wl_seat_get_user_data (seat);
+
+ /* FIXME: This event should go away when the protocol gets merged into wayland,
+ * and this should just be done in _gdk_wayland_device_manager_add_tablet_manager().
+ */
+ device->wl_tablet_manager = wl_tablet_manager;
+ wl_tablet_manager_set_user_data (device->wl_tablet_manager, device);
+}
+
+static const struct wl_tablet_manager_listener tablet_manager_listener = {
+ tablet_manager_handle_device_added,
+ tablet_manager_handle_tool_added,
+ tablet_manager_handle_seat
+};
+
+static void
init_devices (GdkWaylandDeviceData *device)
{
GdkWaylandDeviceManager *device_manager = GDK_WAYLAND_DEVICE_MANAGER (device->device_manager);
@@ -2301,6 +2631,9 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager,
GdkWaylandDeviceManager *device_manager = GDK_WAYLAND_DEVICE_MANAGER (manager);
GList *l;
+ for (l = device_manager->tablet_pairs; l != NULL; l = l->next)
+ _gdk_wayland_device_manager_remove_tablet (l->data);
+
for (l = device_manager->devices; l != NULL; l = l->next)
{
GdkWaylandDevice *wayland_device = l->data;
@@ -2316,6 +2649,7 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager,
g_hash_table_destroy (device->touches);
gdk_window_destroy (device->foreign_dnd_window);
stop_key_repeat (device);
+ wl_tablet_manager_destroy (device->wl_tablet_manager);
g_free (device);
break;
@@ -2323,6 +2657,15 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager,
}
}
+void
+_gdk_wayland_device_manager_add_tablet_manager (struct wl_tablet_manager *wl_tablet_manager)
+{
+ wl_tablet_manager_add_listener (wl_tablet_manager, &tablet_manager_listener,
+ NULL);
+
+ /* FIXME: Handle the rest in tablet_manager_handle_seat () for now */
+}
+
static void
free_device (gpointer data)
{
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 64529fb..fb4ba79 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -284,6 +284,7 @@ gdk_registry_handle_global (void *data,
uint32_t version)
{
GdkWaylandDisplay *display_wayland = data;
+ struct wl_tablet_manager *tablet_manager;
struct wl_output *output;
gboolean handled = TRUE;
@@ -365,6 +366,12 @@ gdk_registry_handle_global (void *data,
wl_registry_bind (display_wayland->wl_registry,
id, &_wl_pointer_gestures_interface, version);
}
+ else if (strcmp (interface, "wl_tablet_manager") == 0)
+ {
+ tablet_manager = wl_registry_bind(display_wayland->wl_registry, id,
+ &wl_tablet_manager_interface, 1);
+ _gdk_wayland_device_manager_add_tablet_manager (tablet_manager);
+ }
else
handled = FALSE;
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index 4156bc6..27efca6 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -27,6 +27,7 @@
#include <wayland-client.h>
#include <wayland-cursor.h>
#include <wayland-egl.h>
+#include <gdk/wayland/wayland-tablet-client-protocol.h>
#include <gdk/wayland/gtk-shell-client-protocol.h>
#include <gdk/wayland/xdg-shell-client-protocol.h>
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index 5f8f37d..e557d50 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -174,6 +174,8 @@ void _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device
void _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *device_manager,
guint32 id);
+void _gdk_wayland_device_manager_add_tablet_manager (struct wl_tablet_manager *wl_tablet_manager);
+
typedef struct _GdkWaylandDeviceData GdkWaylandDeviceData;
GdkKeymap *_gdk_wayland_device_get_keymap (GdkDevice *device);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]