[gtk+/wip/wayland-tablet: 19/23] 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: 19/23] Wayland: Add initial support for drawing tablets
- Date: Mon, 22 Jun 2015 17:16:29 +0000 (UTC)
commit 0cd5581f1bcfc82f5970d29083d8b30eea47b6aa
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 | 349 +++++++++++++++++++++++++++++++++++++-
gdk/wayland/gdkdisplay-wayland.c | 7 +
gdk/wayland/gdkdisplay-wayland.h | 1 +
gdk/wayland/gdkprivate-wayland.h | 2 +
4 files changed, 352 insertions(+), 7 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 8234b45..b4a7b5a 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -37,6 +37,7 @@
typedef struct _GdkWaylandTouchData GdkWaylandTouchData;
typedef struct _GdkWaylandPointerData GdkWaylandPointerData;
+typedef struct _GdkWaylandDeviceTabletPair GdkWaylandDeviceTabletPair;
struct _GdkWaylandTouchData
{
@@ -72,6 +73,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;
@@ -79,6 +92,7 @@ struct _GdkWaylandDeviceData
struct wl_pointer *wl_pointer;
struct wl_keyboard *wl_keyboard;
struct wl_touch *wl_touch;
+ struct wl_tablet_manager *wl_tablet_manager;
GdkDisplay *display;
GdkDeviceManager *device_manager;
@@ -144,6 +158,7 @@ struct _GdkWaylandDeviceManager
{
GdkDeviceManager parent_object;
GList *devices;
+ GList *tablet_pairs;
};
struct _GdkWaylandDeviceManagerClass
@@ -196,6 +211,26 @@ gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer)
pointer->cursor_image_index = 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)
{
@@ -204,6 +239,9 @@ 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;
+
+ pair = gdk_wayland_device_manager_find_tablet_pair (wd->device_manager, device);
if (pointer->cursor)
{
@@ -217,13 +255,26 @@ gdk_wayland_device_update_window_cursor (GdkDevice *device)
return TRUE;
}
- if (!wd->wl_pointer)
- return FALSE;
+ 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
+ {
+ pointer->cursor_timeout_id = 0;
+ return TRUE;
+ }
- 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);
@@ -778,7 +829,6 @@ pointer_handle_enter (void *data,
if (!surface)
return;
-
if (!GDK_IS_WINDOW (wl_surface_get_user_data (surface)))
return;
@@ -1585,6 +1635,73 @@ touch_handle_cancel (void *data,
GDK_NOTE (EVENTS, g_message ("touch cancel"));
}
+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,
@@ -1610,6 +1727,20 @@ static const struct wl_touch_listener touch_listener = {
touch_handle_cancel
};
+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,
@@ -1757,6 +1888,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);
@@ -1939,6 +2261,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;
@@ -1953,6 +2278,7 @@ _gdk_wayland_device_manager_remove_seat (GdkDeviceManager *manager,
g_clear_object (&device->keyboard_settings);
g_hash_table_destroy (device->touches);
gdk_window_destroy (device->foreign_dnd_window);
+ wl_tablet_manager_destroy (device->wl_tablet_manager);
g_free (device);
break;
@@ -1960,6 +2286,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 a0a5d0c..72e57ae 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -283,6 +283,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;
@@ -357,6 +358,12 @@ gdk_registry_handle_global (void *data,
display_wayland->subcompositor =
wl_registry_bind (display_wayland->wl_registry, id, &wl_subcompositor_interface, 1);
}
+ 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 d6e6b06..28e7e09 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 beb489a..a83ae24 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]