[gtk/wip/nacho/macos-pen-input] Support for macOS Pen / Eraser input #1551
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/nacho/macos-pen-input] Support for macOS Pen / Eraser input #1551
- Date: Mon, 18 May 2020 14:34:36 +0000 (UTC)
commit aad43922afaa3d02e04942091f9234b8756130ed
Author: Andreas Butti <andreas butti gmail com>
Date: Sun Jan 27 20:16:33 2019 +0100
Support for macOS Pen / Eraser input #1551
This fix is based on this patch: https://bugzilla.gnome.org/show_bug.cgi?id=695701
gdk/quartz/gdkdevice-core-quartz.c | 40 +++++++
gdk/quartz/gdkdevicemanager-core-quartz.c | 182 +++++++++++++++++++++++++++++-
gdk/quartz/gdkdevicemanager-core-quartz.h | 7 ++
gdk/quartz/gdkevents-quartz.c | 48 +++++++-
gdk/quartz/gdkinternal-quartz.h | 13 +++
5 files changed, 283 insertions(+), 7 deletions(-)
---
diff --git a/gdk/quartz/gdkdevice-core-quartz.c b/gdk/quartz/gdkdevice-core-quartz.c
index 788cbe4b04..fa46c93f45 100644
--- a/gdk/quartz/gdkdevice-core-quartz.c
+++ b/gdk/quartz/gdkdevice-core-quartz.c
@@ -31,6 +31,10 @@
struct _GdkQuartzDeviceCore
{
GdkDevice parent_instance;
+
+ gboolean active;
+ NSUInteger device_id;
+ unsigned long long unique_id;
};
struct _GdkQuartzDeviceCoreClass
@@ -364,3 +368,39 @@ gdk_quartz_device_core_select_window_events (GdkDevice *device,
{
/* The mask is set in the common code. */
}
+
+void
+_gdk_quartz_device_core_set_active (GdkDevice *device,
+ gboolean active,
+ NSUInteger device_id)
+{
+ GdkQuartzDeviceCore *self = GDK_QUARTZ_DEVICE_CORE (device);
+
+ self->active = active;
+ self->device_id = device_id;
+}
+
+gboolean
+_gdk_quartz_device_core_is_active (GdkDevice *device,
+ NSUInteger device_id)
+{
+ GdkQuartzDeviceCore *self = GDK_QUARTZ_DEVICE_CORE (device);
+
+ if (self->active && self->device_id == device_id)
+ return TRUE;
+
+ return FALSE;
+}
+
+void
+_gdk_quartz_device_core_set_unique (GdkDevice *device,
+ unsigned long long unique_id)
+{
+ GDK_QUARTZ_DEVICE_CORE (device)->unique_id = unique_id;
+}
+
+unsigned long long
+_gdk_quartz_device_core_get_unique (GdkDevice *device)
+{
+ return GDK_QUARTZ_DEVICE_CORE (device)->unique_id;
+}
diff --git a/gdk/quartz/gdkdevicemanager-core-quartz.c b/gdk/quartz/gdkdevicemanager-core-quartz.c
index d4756863c5..2ee5e99091 100644
--- a/gdk/quartz/gdkdevicemanager-core-quartz.c
+++ b/gdk/quartz/gdkdevicemanager-core-quartz.c
@@ -27,7 +27,30 @@
#include "gdkquartzdevice-core.h"
#include "gdkkeysyms.h"
#include "gdkprivate-quartz.h"
+#include "gdkinternal-quartz.h"
+typedef enum
+{
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_CURSOR = NSCursorPointingDevice,
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_ERASER = NSEraserPointingDevice,
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_PEN = NSPenPointingDevice,
+#else
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_CURSOR = NSPointingDeviceTypeCursor,
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_ERASER = NSPointingDeviceTypeEraser,
+ GDK_QUARTZ_POINTER_DEVICE_TYPE_PEN = NSPointingDeviceTypePen,
+#endif
+} GdkQuartzPointerDeviceType;
+
+#if MACOS_X_VERSION_MIN_SUPPORTED >= GDK_OSX_SIERRA
+#define TABLET_PROXIMITY NSEventTypeTabletProximity
+#define SUBTYPE_TABLET_PROXIMITY NSEventSubtypeTabletProximity
+#define SUBTYPE_TABLET_POINT NSEventSubtypeTabletPoint
+#else
+#define TABLET_PROXIMITY NSTabletProximity
+#define SUBTYPE_TABLET_PROXIMITY NSTabletProximityEventSubtype
+#define SUBTYPE_TABLET_POINT NSTabletPointEventSubtype
+#endif
#define HAS_FOCUS(toplevel) \
((toplevel)->has_focus || (toplevel)->has_pointer_focus)
@@ -87,6 +110,7 @@ create_core_keyboard (GdkDeviceManager *device_manager,
static void
gdk_quartz_device_manager_core_init (GdkQuartzDeviceManagerCore *device_manager)
{
+ device_manager->known_tablet_devices = NULL;
}
static void
@@ -99,6 +123,8 @@ gdk_quartz_device_manager_core_finalize (GObject *object)
g_object_unref (quartz_device_manager_core->core_pointer);
g_object_unref (quartz_device_manager_core->core_keyboard);
+ g_list_free_full (quartz_device_manager_core->known_tablet_devices, g_object_unref);
+
G_OBJECT_CLASS (gdk_quartz_device_manager_core_parent_class)->finalize (object);
}
@@ -127,16 +153,25 @@ static GList *
gdk_quartz_device_manager_core_list_devices (GdkDeviceManager *device_manager,
GdkDeviceType type)
{
- GdkQuartzDeviceManagerCore *quartz_device_manager_core;
+ GdkQuartzDeviceManagerCore *self;
GList *devices = NULL;
+ GList *l;
+
+ self = GDK_QUARTZ_DEVICE_MANAGER_CORE (device_manager);
if (type == GDK_DEVICE_TYPE_MASTER)
{
- quartz_device_manager_core = (GdkQuartzDeviceManagerCore *) device_manager;
- devices = g_list_prepend (devices, quartz_device_manager_core->core_keyboard);
- devices = g_list_prepend (devices, quartz_device_manager_core->core_pointer);
+ devices = g_list_prepend (devices, self->core_keyboard);
+ devices = g_list_prepend (devices, self->core_pointer);
}
+ for (l = self->known_tablet_devices; l; l = g_list_next (l))
+ {
+ devices = g_list_prepend (devices, GDK_DEVICE (l->data));
+ }
+
+ devices = g_list_reverse (devices);
+
return devices;
}
@@ -148,3 +183,142 @@ gdk_quartz_device_manager_core_get_client_pointer (GdkDeviceManager *device_mana
quartz_device_manager_core = (GdkQuartzDeviceManagerCore *) device_manager;
return quartz_device_manager_core->core_pointer;
}
+
+static GdkDevice *
+create_core_device (GdkDeviceManager *device_manager,
+ const gchar *device_name,
+ GdkInputSource source)
+{
+ GdkDisplay *display = gdk_device_manager_get_display (device_manager);
+ GdkDevice *device = g_object_new (GDK_TYPE_QUARTZ_DEVICE_CORE,
+ "name", device_name,
+ "type", GDK_DEVICE_TYPE_SLAVE,
+ "input-source", source,
+ "input-mode", GDK_MODE_SCREEN,
+ "has-cursor", TRUE,
+ "display", display,
+ "device-manager", device_manager,
+ /* "cocoa-unique-id", [nsevent uniqueID], */
+ NULL);
+
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_PRESSURE, 0.0, 1.0, 0.001);
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_XTILT, -1.0, 1.0, 0.001);
+ _gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_YTILT, -1.0, 1.0, 0.001);
+
+ return device;
+}
+
+GdkDevice *
+_gdk_quartz_device_manager_core_device_for_ns_event (GdkDeviceManager *device_manager,
+ NSEvent *nsevent)
+{
+ GdkQuartzDeviceManagerCore *self = GDK_QUARTZ_DEVICE_MANAGER_CORE (device_manager);
+ GdkDevice *device = NULL;
+
+ if ([nsevent type] == TABLET_PROXIMITY ||
+ [nsevent subtype] == SUBTYPE_TABLET_PROXIMITY)
+ {
+ GList *l = NULL;
+ GdkInputSource input_source = GDK_SOURCE_MOUSE;
+
+ if ([nsevent pointingDeviceType] == GDK_QUARTZ_POINTER_DEVICE_TYPE_PEN)
+ input_source = GDK_SOURCE_PEN;
+ else if ([nsevent pointingDeviceType] == GDK_QUARTZ_POINTER_DEVICE_TYPE_CURSOR)
+ input_source = GDK_SOURCE_CURSOR;
+ else if ([nsevent pointingDeviceType] == GDK_QUARTZ_POINTER_DEVICE_TYPE_ERASER)
+ input_source = GDK_SOURCE_ERASER;
+
+ for (l = self->known_tablet_devices; l; l = g_list_next (l))
+ {
+ GdkDevice *device_to_check = GDK_DEVICE (l->data);
+
+ if (input_source == gdk_device_get_source (device_to_check) &&
+ [nsevent uniqueID] == _gdk_quartz_device_core_get_unique (device_to_check))
+ {
+ device = device_to_check;
+ if ([nsevent isEnteringProximity])
+ {
+ if (!_gdk_quartz_device_core_is_active (device, [nsevent deviceID]))
+ self->num_active_devices++;
+
+ _gdk_quartz_device_core_set_active (device, TRUE, [nsevent deviceID]);
+ }
+ else
+ {
+ if (_gdk_quartz_device_core_is_active (device, [nsevent deviceID]))
+ self->num_active_devices--;
+
+ _gdk_quartz_device_core_set_active (device, FALSE, [nsevent deviceID]);
+ }
+ }
+ }
+
+ /* If we haven't seen this device before, add it */
+ if (!device)
+ {
+ switch (input_source)
+ {
+ case GDK_SOURCE_PEN:
+ device = create_core_device (device_manager,
+ "Quartz Pen",
+ GDK_SOURCE_PEN);
+ break;
+ case GDK_SOURCE_CURSOR:
+ device = create_core_device (device_manager,
+ "Quartz Cursor",
+ GDK_SOURCE_CURSOR);
+ break;
+ case GDK_SOURCE_ERASER:
+ device = create_core_device (device_manager,
+ "Quartz Eraser",
+ GDK_SOURCE_ERASER);
+ break;
+ default:
+ g_warning ("GDK Quarz unknown input source: %i", input_source);
+ break;
+ }
+
+ _gdk_device_set_associated_device (GDK_DEVICE (device), self->core_pointer);
+ _gdk_device_add_slave (self->core_pointer, GDK_DEVICE (device));
+
+ _gdk_quartz_device_core_set_unique (device, [nsevent uniqueID]);
+ _gdk_quartz_device_core_set_active (device, TRUE, [nsevent deviceID]);
+
+ self->known_tablet_devices = g_list_append (self->known_tablet_devices,
+ device);
+
+ if ([nsevent isEnteringProximity])
+ {
+ if (!_gdk_quartz_device_core_is_active (device, [nsevent deviceID]))
+ self->num_active_devices++;
+ _gdk_quartz_device_core_set_active (device, TRUE, [nsevent deviceID]);
+ }
+ }
+
+ if (self->num_active_devices)
+ [NSEvent setMouseCoalescingEnabled: FALSE];
+ else
+ [NSEvent setMouseCoalescingEnabled: TRUE];
+ }
+ else if ([nsevent subtype] == SUBTYPE_TABLET_POINT)
+ {
+ /* Find the device based on deviceID */
+ GList *l = NULL;
+
+ for (l = self->known_tablet_devices; l && !device; l = g_list_next (l))
+ {
+ GdkDevice *device_to_check = GDK_DEVICE (l->data);
+
+ if (_gdk_quartz_device_core_is_active (device_to_check, [nsevent deviceID]))
+ device = device_to_check;
+ }
+
+ if (!device)
+ g_warning ("GDK Quartz: received subtype tablet point event for unknown device");
+ }
+
+ if (!device)
+ device = self->core_pointer;
+
+ return device;
+}
diff --git a/gdk/quartz/gdkdevicemanager-core-quartz.h b/gdk/quartz/gdkdevicemanager-core-quartz.h
index db054ad685..a5020f4588 100644
--- a/gdk/quartz/gdkdevicemanager-core-quartz.h
+++ b/gdk/quartz/gdkdevicemanager-core-quartz.h
@@ -23,6 +23,8 @@
#include <gdkdevicemanagerprivate.h>
#include "gdkquartzdevicemanager-core.h"
+#import <Cocoa/Cocoa.h>
+
G_BEGIN_DECLS
struct _GdkQuartzDeviceManagerCore
@@ -30,6 +32,8 @@ struct _GdkQuartzDeviceManagerCore
GdkDeviceManager parent_object;
GdkDevice *core_pointer;
GdkDevice *core_keyboard;
+ GList *known_tablet_devices;
+ guint num_active_devices;
};
struct _GdkQuartzDeviceManagerCoreClass
@@ -37,6 +41,9 @@ struct _GdkQuartzDeviceManagerCoreClass
GdkDeviceManagerClass parent_class;
};
+GdkDevice *_gdk_quartz_device_manager_core_device_for_ns_event (GdkDeviceManager *device_manager,
+ NSEvent *ns_event);
+
G_END_DECLS
#endif /* __GDK_QUARTZ_DEVICE_MANAGER__ */
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index b0e6c0549e..702aa51ec1 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -42,12 +42,19 @@
#define GRIP_WIDTH 15
#define GRIP_HEIGHT 15
#define GDK_LION_RESIZE 5
+#define TABLET_AXES 5
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
#define NSEventTypeRotate 13
#define NSEventTypeMagnify 30
#endif
+#if MACOS_X_VERSION_MIN_SUPPORTED >= GDK_OSX_SIERRA
+#define SUBTYPE_TABLET_POINT NSEventSubtypeTabletPoint
+#else
+#define SUBTYPE_TABLET_POINT NSTabletPointEventSubType
+#endif
+
#define WINDOW_IS_TOPLEVEL(window) \
(GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
@@ -173,7 +180,7 @@ gdk_event_apply_filters (NSEvent *nsevent,
{
GList *tmp_list;
GdkFilterReturn result;
-
+
tmp_list = *filters;
while (tmp_list)
@@ -1019,6 +1026,8 @@ fill_button_event (GdkWindow *window,
gint y_root)
{
GdkEventType type;
+ GdkDevice *event_device = NULL;
+ gdouble *axes = NULL;
gint state;
GdkSeat *seat = gdk_display_get_default_seat (_gdk_display);
@@ -1045,6 +1054,20 @@ fill_button_event (GdkWindow *window,
g_assert_not_reached ();
}
+ event_device = _gdk_quartz_device_manager_core_device_for_ns_event (gdk_display_get_device_manager
(_gdk_display),
+ nsevent);
+
+ if ([nsevent subtype] == SUBTYPE_TABLET_POINT)
+ {
+ axes = g_new (gdouble, TABLET_AXES);
+
+ axes[0] = x;
+ axes[1] = y;
+ axes[2] = [nsevent pressure];
+ axes[3] = [nsevent tilt].x;
+ axes[4] = [nsevent tilt].y;
+ }
+
event->any.type = type;
event->button.window = window;
event->button.time = get_time_from_ns_event (nsevent);
@@ -1052,11 +1075,12 @@ fill_button_event (GdkWindow *window,
event->button.y = y;
event->button.x_root = x_root;
event->button.y_root = y_root;
- /* FIXME event->axes */
+ event->button.axes = axes;
event->button.state = state;
event->button.button = get_mouse_button_from_ns_event (nsevent);
event->button.device = gdk_seat_get_pointer (seat);
+ gdk_event_set_source_device(event, event_device);
gdk_event_set_seat (event, seat);
}
@@ -1070,6 +1094,22 @@ fill_motion_event (GdkWindow *window,
gint y_root)
{
GdkSeat *seat = gdk_display_get_default_seat (_gdk_display);
+ GdkDevice *event_device = NULL;
+ gdouble *axes = NULL;
+
+ event_device = _gdk_quartz_device_manager_core_device_for_ns_event (gdk_display_get_device_manager
(_gdk_display),
+ nsevent);
+
+ if ([nsevent subtype] == SUBTYPE_TABLET_POINT)
+ {
+ axes = g_new (gdouble, TABLET_AXES);
+
+ axes[0] = x;
+ axes[1] = y;
+ axes[2] = [nsevent pressure];
+ axes[3] = [nsevent tilt].x;
+ axes[4] = [nsevent tilt].y;
+ }
event->any.type = GDK_MOTION_NOTIFY;
event->motion.window = window;
@@ -1078,11 +1118,13 @@ fill_motion_event (GdkWindow *window,
event->motion.y = y;
event->motion.x_root = x_root;
event->motion.y_root = y_root;
- /* FIXME event->axes */
+ event->motion.axes = axes;
event->motion.state = get_keyboard_modifiers_from_ns_event (nsevent) |
_gdk_quartz_events_get_current_mouse_modifiers ();
event->motion.is_hint = FALSE;
event->motion.device = gdk_seat_get_pointer (seat);
+ gdk_event_set_source_device(event, event_device);
+
gdk_event_set_seat (event, seat);
}
diff --git a/gdk/quartz/gdkinternal-quartz.h b/gdk/quartz/gdkinternal-quartz.h
index 2f47e0a71f..214f585598 100644
--- a/gdk/quartz/gdkinternal-quartz.h
+++ b/gdk/quartz/gdkinternal-quartz.h
@@ -84,6 +84,19 @@ GdkModifierType _gdk_quartz_events_get_current_mouse_modifiers (void);
void _gdk_quartz_events_break_all_grabs (guint32 time);
+/* Devices */
+void _gdk_quartz_device_core_set_active (GdkDevice *device,
+ gboolean active,
+ NSUInteger device_id);
+
+gboolean _gdk_quartz_device_core_is_active (GdkDevice *device,
+ NSUInteger device_id);
+
+void _gdk_quartz_device_core_set_unique (GdkDevice *device,
+ unsigned long long unique_id);
+
+unsigned long long _gdk_quartz_device_core_get_unique (GdkDevice *device);
+
/* Event loop */
gboolean _gdk_quartz_event_loop_check_pending (void);
NSEvent * _gdk_quartz_event_loop_get_pending (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]