From f5efb15cbae1ae1c6aca07066a4a5720dc84706a Mon Sep 17 00:00:00 2001 From: Ignacio Casal Quinteiro Date: Thu, 7 Jan 2021 13:40:12 +0100 Subject: Support stylus devices on macos --- gdk/macos/gdkmacosdisplay-translate.c | 48 ++- gdk/macos/gdkmacosseat-private.h | 11 + gdk/macos/gdkmacosseat.c | 606 ++++++++++++++++++++++++++++++++-- gdk/macos/gdkmacosseat.h | 40 +++ gdk/macos/meson.build | 1 + 5 files changed, 679 insertions(+), 27 deletions(-) create mode 100644 gdk/macos/gdkmacosseat.h diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c index e6551581a2..2a825879a5 100644 --- a/gdk/macos/gdkmacosdisplay-translate.c +++ b/gdk/macos/gdkmacosdisplay-translate.c @@ -28,6 +28,7 @@ #include "gdkmacosdisplay-private.h" #include "gdkmacoskeymap-private.h" #include "gdkmacossurface-private.h" +#include "gdkmacosseat-private.h" #define GDK_MOD2_MASK (1 << 4) #define GRIP_WIDTH 15 @@ -205,6 +206,9 @@ fill_button_event (GdkMacosDisplay *display, GdkSeat *seat; GdkEventType type; GdkModifierType state; + GdkDevice *pointer = NULL; + GdkDeviceTool *tool = NULL; + double *axes = NULL; g_assert (GDK_IS_MACOS_DISPLAY (display)); g_assert (GDK_IS_MACOS_SURFACE (surface)); @@ -241,16 +245,22 @@ fill_button_event (GdkMacosDisplay *display, y < 0 || y > GDK_SURFACE (surface)->height)) return NULL; + if (([nsevent subtype] == NSEventSubtypeTabletPoint) && + _gdk_macos_seat_get_tablet (GDK_MACOS_SEAT (seat), &pointer, &tool)) + axes = _gdk_macos_seat_get_tablet_axes_from_nsevent (GDK_MACOS_SEAT (seat), nsevent); + else + pointer = gdk_seat_get_pointer (seat); + return gdk_button_event_new (type, GDK_SURFACE (surface), - gdk_seat_get_pointer (seat), - NULL, + pointer, + tool, get_time_from_ns_event (nsevent), state, get_mouse_button_from_ns_event (nsevent), x, y, - NULL); + axes); } static GdkEvent * @@ -557,6 +567,9 @@ fill_motion_event (GdkMacosDisplay *display, { GdkSeat *seat; GdkModifierType state; + GdkDevice *pointer = NULL; + GdkDeviceTool *tool = NULL; + double *axes = NULL; g_assert (GDK_IS_MACOS_SURFACE (surface)); g_assert (nsevent != NULL); @@ -566,14 +579,20 @@ fill_motion_event (GdkMacosDisplay *display, state = get_keyboard_modifiers_from_ns_event (nsevent) | _gdk_macos_display_get_current_mouse_modifiers (display); + if (([nsevent subtype] == NSEventSubtypeTabletPoint) && + _gdk_macos_seat_get_tablet (GDK_MACOS_SEAT (seat), &pointer, &tool)) + axes = _gdk_macos_seat_get_tablet_axes_from_nsevent (GDK_MACOS_SEAT (seat), nsevent); + else + pointer = gdk_seat_get_pointer (seat); + return gdk_motion_event_new (GDK_SURFACE (surface), - gdk_seat_get_pointer (seat), - NULL, + pointer, + tool, get_time_from_ns_event (nsevent), state, x, y, - NULL); + axes); } static GdkEvent * @@ -1051,6 +1070,23 @@ _gdk_macos_display_translate (GdkMacosDisplay *self, return NULL; } + /* We need to register the proximity event from any point on the screen + * to properly register the devices + * FIXME: is there a better way to detect if a tablet has been plugged? + */ + if (event_type == NSEventTypeTabletProximity) + { + GdkSeat *seat = gdk_display_get_default_seat (GDK_DISPLAY (self)); + + _gdk_macos_seat_handle_tablet_tool_event (GDK_MACOS_SEAT (seat), nsevent); + + /* FIXME: we might want to cache this proximity event and propagate it + * but proximity events in gdk work at a window level while on macos + * works at a screen level. For now we just skip them. + */ + return NULL; + } + if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y))) return NULL; diff --git a/gdk/macos/gdkmacosseat-private.h b/gdk/macos/gdkmacosseat-private.h index 57e5605018..889051e74a 100644 --- a/gdk/macos/gdkmacosseat-private.h +++ b/gdk/macos/gdkmacosseat-private.h @@ -23,6 +23,7 @@ #include #include "gdkmacosdisplay.h" +#include "gdkmacosseat.h" #include "gdkseatprivate.h" @@ -30,6 +31,16 @@ G_BEGIN_DECLS GdkSeat *_gdk_macos_seat_new (GdkMacosDisplay *display); +void _gdk_macos_seat_handle_tablet_tool_event (GdkMacosSeat *seat, + NSEvent *nsevent); + +gboolean _gdk_macos_seat_get_tablet (GdkMacosSeat *seat, + GdkDevice **device, + GdkDeviceTool **tool); + +double *_gdk_macos_seat_get_tablet_axes_from_nsevent (GdkMacosSeat *seat, + NSEvent *nsevent); + G_END_DECLS #endif /* __GDK_MACOS_SEAT_PRIVATE_H__ */ diff --git a/gdk/macos/gdkmacosseat.c b/gdk/macos/gdkmacosseat.c index e239c6cb3c..a7b7c59915 100644 --- a/gdk/macos/gdkmacosseat.c +++ b/gdk/macos/gdkmacosseat.c @@ -1,5 +1,6 @@ /* * Copyright © 2020 Red Hat, Inc. + * Copyright © 2021 Amazon.com, Inc. and its affiliates. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,42 +23,605 @@ #include #include "gdkdeviceprivate.h" -#include "gdkseatdefaultprivate.h" +#include "gdkdevicetoolprivate.h" #include "gdkmacosdevice.h" #include "gdkmacosseat-private.h" +typedef struct +{ + NSUInteger device_id; + char *name; + + GdkDevice *logical_device; + GdkDevice *stylus_device; + GdkSeat *seat; + + GdkDeviceTool *current_tool; + + int axis_indices[GDK_AXIS_LAST]; + double axes[GDK_AXIS_LAST]; +} GdkMacosTabletData; + +struct _GdkMacosSeat +{ + GdkSeat parent_instance; + + GdkMacosDisplay *display; + + GdkDevice *logical_pointer; + GdkDevice *logical_keyboard; + + GdkMacosTabletData *current_tablet; + GPtrArray *tablets; + GPtrArray *tools; +}; + +struct _GdkMacosSeatClass +{ + GdkSeatClass parent_class; +}; + +G_DEFINE_TYPE (GdkMacosSeat, gdk_macos_seat, GDK_TYPE_SEAT) + +#define KEYBOARD_EVENTS (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | \ + GDK_FOCUS_CHANGE_MASK) +#define TOUCH_EVENTS (GDK_TOUCH_MASK) +#define POINTER_EVENTS (GDK_POINTER_MOTION_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | \ + GDK_ENTER_NOTIFY_MASK | \ + GDK_LEAVE_NOTIFY_MASK | \ + GDK_PROXIMITY_IN_MASK | \ + GDK_PROXIMITY_OUT_MASK) + +static void +gdk_macos_tablet_data_free (gpointer user_data) +{ + GdkMacosTabletData *tablet = user_data; + + gdk_seat_device_removed (GDK_SEAT (tablet->seat), tablet->stylus_device); + gdk_seat_device_removed (GDK_SEAT (tablet->seat), tablet->logical_device); + + _gdk_device_set_associated_device (tablet->logical_device, NULL); + _gdk_device_set_associated_device (tablet->stylus_device, NULL); + + g_object_unref (tablet->logical_device); + g_object_unref (tablet->stylus_device); + + g_free (tablet->name); + g_free (tablet); +} + +static void +gdk_macos_seat_dispose (GObject *object) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (object); + + if (self->logical_pointer) + { + gdk_seat_device_removed (GDK_SEAT (self), self->logical_pointer); + g_clear_object (&self->logical_pointer); + } + + if (self->logical_keyboard) + { + gdk_seat_device_removed (GDK_SEAT (self), self->logical_keyboard); + g_clear_object (&self->logical_pointer); + } + + g_clear_pointer (&self->tablets, g_ptr_array_unref); + g_clear_pointer (&self->tools, g_ptr_array_unref); + + G_OBJECT_CLASS (gdk_macos_seat_parent_class)->dispose (object); +} + +static GdkSeatCapabilities +gdk_macos_seat_get_capabilities (GdkSeat *seat) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + GdkSeatCapabilities caps = 0; + + if (self->logical_pointer) + caps |= GDK_SEAT_CAPABILITY_POINTER; + if (self->logical_keyboard) + caps |= GDK_SEAT_CAPABILITY_KEYBOARD; + + return caps; +} + +static GdkGrabStatus +gdk_macos_seat_grab (GdkSeat *seat, + GdkSurface *surface, + GdkSeatCapabilities capabilities, + gboolean owner_events, + GdkCursor *cursor, + GdkEvent *event, + GdkSeatGrabPrepareFunc prepare_func, + gpointer prepare_func_data) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; + GdkGrabStatus status = GDK_GRAB_SUCCESS; + gboolean was_visible; + + was_visible = gdk_surface_get_mapped (surface); + + if (prepare_func) + (prepare_func) (seat, surface, prepare_func_data); + + if (!gdk_surface_get_mapped (surface)) + { + g_critical ("Surface %p has not been mapped in GdkSeatGrabPrepareFunc", + surface); + return GDK_GRAB_NOT_VIEWABLE; + } + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + + if (capabilities & GDK_SEAT_CAPABILITY_ALL_POINTING) + { + /* ALL_POINTING spans 3 capabilities; get the mask for the ones we have */ + GdkEventMask pointer_evmask = 0; + + /* We let tablet styli take over the pointer cursor */ + if (capabilities & (GDK_SEAT_CAPABILITY_POINTER | + GDK_SEAT_CAPABILITY_TABLET_STYLUS)) + { + pointer_evmask |= POINTER_EVENTS; + } + + if (capabilities & GDK_SEAT_CAPABILITY_TOUCH) + pointer_evmask |= TOUCH_EVENTS; + + status = gdk_device_grab (self->logical_pointer, surface, + owner_events, + pointer_evmask, cursor, + evtime); + } + + if (status == GDK_GRAB_SUCCESS && + capabilities & GDK_SEAT_CAPABILITY_KEYBOARD) + { + status = gdk_device_grab (self->logical_keyboard, surface, + owner_events, + KEYBOARD_EVENTS, cursor, + evtime); + + if (status != GDK_GRAB_SUCCESS) + { + if (capabilities & ~GDK_SEAT_CAPABILITY_KEYBOARD) + gdk_device_ungrab (self->logical_pointer, evtime); + } + } + + if (status != GDK_GRAB_SUCCESS && !was_visible) + gdk_surface_hide (surface); + + G_GNUC_END_IGNORE_DEPRECATIONS; + + return status; +} + +static void +gdk_macos_seat_ungrab (GdkSeat *seat) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_device_ungrab (self->logical_pointer, GDK_CURRENT_TIME); + gdk_device_ungrab (self->logical_keyboard, GDK_CURRENT_TIME); + G_GNUC_END_IGNORE_DEPRECATIONS; +} + +static GdkDevice * +gdk_macos_seat_get_logical_device (GdkSeat *seat, + GdkSeatCapabilities capability) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + + /* There must be only one flag set */ + switch ((guint) capability) + { + case GDK_SEAT_CAPABILITY_POINTER: + case GDK_SEAT_CAPABILITY_TOUCH: + return self->logical_pointer; + case GDK_SEAT_CAPABILITY_KEYBOARD: + return self->logical_keyboard; + default: + g_warning ("Unhandled capability %x", capability); + break; + } + + return NULL; +} + +static GList * +gdk_macos_seat_get_devices (GdkSeat *seat, + GdkSeatCapabilities capabilities) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + GList *physical_devices = NULL; + + if (self->logical_pointer && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) + physical_devices = g_list_prepend (physical_devices, self->logical_pointer); + + if (self->logical_keyboard && (capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)) + physical_devices = g_list_prepend (physical_devices, self->logical_keyboard); + + if (capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS) + { + for (guint i = 0; i < self->tablets->len; i++) + { + GdkMacosTabletData *tablet = g_ptr_array_index (self->tablets, i); + + physical_devices = g_list_prepend (physical_devices, tablet->stylus_device); + } + } + + return physical_devices; +} + +static GList * +gdk_macos_seat_get_tools (GdkSeat *seat) +{ + GdkMacosSeat *self = GDK_MACOS_SEAT (seat); + GdkDeviceTool *tool; + GList *tools = NULL; + + for (guint i = 0; i < self->tools->len; i++) + { + tool = g_ptr_array_index (self->tools, i); + tools = g_list_prepend (tools, tool); + } + + return tools; +} + +static void +gdk_macos_seat_class_init (GdkMacosSeatClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass); + + object_class->dispose = gdk_macos_seat_dispose; + + seat_class->get_capabilities = gdk_macos_seat_get_capabilities; + seat_class->grab = gdk_macos_seat_grab; + seat_class->ungrab = gdk_macos_seat_ungrab; + seat_class->get_logical_device = gdk_macos_seat_get_logical_device; + seat_class->get_devices = gdk_macos_seat_get_devices; + seat_class->get_tools = gdk_macos_seat_get_tools; +} + +static void +gdk_macos_seat_init (GdkMacosSeat *self) +{ + self->tablets = g_ptr_array_new_with_free_func (gdk_macos_tablet_data_free); + self->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +static void +init_devices (GdkMacosSeat *self) +{ + /* pointer */ + self->logical_pointer = g_object_new (GDK_TYPE_MACOS_DEVICE, + "name", "Core Pointer", + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", self->display, + "seat", self, + NULL); + + /* keyboard */ + self->logical_keyboard = g_object_new (GDK_TYPE_MACOS_DEVICE, + "name", "Core Keyboard", + "source", GDK_SOURCE_KEYBOARD, + "has-cursor", FALSE, + "display", self->display, + "seat", self, + NULL); + + /* link both */ + _gdk_device_set_associated_device (self->logical_pointer, self->logical_keyboard); + _gdk_device_set_associated_device (self->logical_keyboard, self->logical_pointer); + + gdk_seat_device_added (GDK_SEAT (self), self->logical_pointer); + gdk_seat_device_added (GDK_SEAT (self), self->logical_keyboard); +} + GdkSeat * _gdk_macos_seat_new (GdkMacosDisplay *display) { - GdkDevice *core_keyboard; - GdkDevice *core_pointer; - GdkSeat *seat; + GdkMacosSeat *self; g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL); - core_pointer = g_object_new (GDK_TYPE_MACOS_DEVICE, - "name", "Core Pointer", - "source", GDK_SOURCE_MOUSE, - "has-cursor", TRUE, - "display", display, - NULL); - core_keyboard = g_object_new (GDK_TYPE_MACOS_DEVICE, - "name", "Core Keyboard", - "source", GDK_SOURCE_KEYBOARD, + self = g_object_new (GDK_TYPE_MACOS_SEAT, + "display", display, + NULL); + + self->display = display; + + init_devices (self); + + return g_steal_pointer (&self); +} + +static GdkDeviceToolType +get_device_tool_type_from_nsevent (NSEvent *nsevent) +{ + GdkDeviceToolType tool_type; + + switch ([nsevent pointingDeviceType]) + { + case NSPointingDeviceTypePen: + tool_type = GDK_DEVICE_TOOL_TYPE_PEN; + break; + case NSPointingDeviceTypeEraser: + tool_type = GDK_DEVICE_TOOL_TYPE_ERASER; + break; + case NSPointingDeviceTypeCursor: + tool_type = GDK_DEVICE_TOOL_TYPE_MOUSE; + break; + case NSPointingDeviceTypeUnknown: + default: + tool_type = GDK_DEVICE_TOOL_TYPE_UNKNOWN; + } + + return tool_type; +} + +static GdkAxisFlags +get_device_tool_axes_from_nsevent (NSEvent *nsevent) +{ + /* TODO: do we need to be smarter about the capabilities? */ + return GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT | GDK_AXIS_FLAG_PRESSURE | + GDK_AXIS_FLAG_ROTATION; +} + +static GdkMacosTabletData * +create_tablet_data_from_nsevent (GdkMacosSeat *self, + NSEvent *nsevent) +{ + GdkMacosTabletData *tablet; + GdkDisplay *display = gdk_seat_get_display (GDK_SEAT (self)); + GdkDevice *logical_device, *stylus_device; + char *logical_name; + char *vid, *pid; + + tablet = g_new0 (GdkMacosTabletData, 1); + tablet->seat = GDK_SEAT (self); + tablet->device_id = [nsevent deviceID]; + /* FIXME: find a better name */ + tablet->name = g_strdup_printf ("Tablet %lu", [nsevent deviceID]); + + vid = g_strdup_printf ("%.4lx", [nsevent vendorID]); + pid = g_strdup_printf ("%.4lx", [nsevent tabletID]); + + logical_name = g_strdup_printf ("Logical pointer for %s", tablet->name); + logical_device = g_object_new (GDK_TYPE_MACOS_DEVICE, + "name", logical_name, + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", display, + "seat", self, + NULL); + + stylus_device = g_object_new (GDK_TYPE_MACOS_DEVICE, + "name", tablet->name, + "source", GDK_SOURCE_PEN, "has-cursor", FALSE, "display", display, + "seat", self, + "vendor-id", vid, + "product-id", pid, NULL); - _gdk_device_set_associated_device (GDK_DEVICE (core_pointer), - GDK_DEVICE (core_keyboard)); - _gdk_device_set_associated_device (GDK_DEVICE (core_keyboard), - GDK_DEVICE (core_pointer)); + tablet->logical_device = logical_device; + tablet->stylus_device = stylus_device; + + _gdk_device_set_associated_device (logical_device, self->logical_keyboard); + _gdk_device_set_associated_device (stylus_device, logical_device); + + gdk_seat_device_added (GDK_SEAT (self), logical_device); + gdk_seat_device_added (GDK_SEAT (self), stylus_device); + + g_free (logical_name); + g_free (vid); + g_free (pid); + + return tablet; +} + +static GdkMacosTabletData * +get_tablet_data_from_nsevent (GdkMacosSeat *self, + NSEvent *nsevent) +{ + GdkMacosTabletData *tablet = NULL; + + for (guint i = 0; i < self->tablets->len; i++) + { + GdkMacosTabletData *t = g_ptr_array_index (self->tablets, i); + + if (t->device_id == [nsevent deviceID]) + { + tablet = t; + break; + } + } + + if (!tablet) + tablet = create_tablet_data_from_nsevent (self, nsevent); + + return tablet; +} + +static void +device_tablet_clone_tool_axes (GdkMacosTabletData *tablet, + GdkDeviceTool *tool) +{ + int axis_pos; + + g_object_freeze_notify (G_OBJECT (tablet->stylus_device)); + _gdk_device_reset_axes (tablet->stylus_device); + + _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_X, 0, 0, 0); + _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_Y, 0, 0, 0); + + if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT)) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_XTILT, -1.0, 1.0, 0); + tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos; + + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_YTILT, -1.0, 1.0, 0); + tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos; + } + + if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_PRESSURE, 0.0, 1.0, 0); + tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos; + } + + if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_ROTATION, 0.0, 1.0, 0); + tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos; + } + + g_object_thaw_notify (G_OBJECT (tablet->stylus_device)); +} + +static void +mimic_device_axes (GdkDevice *logical, + GdkDevice *physical) +{ + double axis_min, axis_max, axis_resolution; + GdkAxisUse axis_use; + int axis_count; + + g_object_freeze_notify (G_OBJECT (logical)); + _gdk_device_reset_axes (logical); + axis_count = gdk_device_get_n_axes (physical); + + for (int i = 0; i < axis_count; i++) + { + _gdk_device_get_axis_info (physical, i, &axis_use, &axis_min, + &axis_max, &axis_resolution); + _gdk_device_add_axis (logical, axis_use, axis_min, + axis_max, axis_resolution); + } + + g_object_thaw_notify (G_OBJECT (logical)); +} + +void +_gdk_macos_seat_handle_tablet_tool_event (GdkMacosSeat *seat, + NSEvent *nsevent) +{ + GdkDeviceToolType tool_type; + GdkMacosTabletData *tablet; + GdkDeviceTool *tool; + + g_return_if_fail (GDK_IS_MACOS_SEAT (seat)); + g_return_if_fail (nsevent != NULL); + + tablet = get_tablet_data_from_nsevent (seat, nsevent); + + tool_type = get_device_tool_type_from_nsevent (nsevent); + + if (tool_type == GDK_DEVICE_TOOL_TYPE_UNKNOWN) + { + g_warning ("Unknown device tool detected"); + return; + } + + tool = gdk_seat_get_tool (GDK_SEAT (seat), [nsevent tabletID], [nsevent deviceID], tool_type); + + if ([nsevent isEnteringProximity]) + { + if (!tool) + { + tool = gdk_device_tool_new ([nsevent tabletID], [nsevent vendorID], tool_type, + get_device_tool_axes_from_nsevent (nsevent)); + g_ptr_array_add (seat->tools, tool); + } + + gdk_device_update_tool (tablet->stylus_device, tool); + tablet->current_tool = tool; + device_tablet_clone_tool_axes (tablet, tool); + mimic_device_axes (tablet->logical_device, tablet->stylus_device); + seat->current_tablet = tablet; + } + else + { + gdk_device_update_tool (tablet->stylus_device, NULL); + tablet->current_tool = NULL; + seat->current_tablet = NULL; + } +} + +gboolean +_gdk_macos_seat_get_tablet (GdkMacosSeat *seat, + GdkDevice **logical_device, + GdkDeviceTool **tool) +{ + g_return_val_if_fail (GDK_IS_MACOS_SEAT (seat), FALSE); + + if (!seat->current_tablet) + return FALSE; + + *logical_device = seat->current_tablet->logical_device; + *tool = seat->current_tablet->current_tool; + + return TRUE; +} + +double * +_gdk_macos_seat_get_tablet_axes_from_nsevent (GdkMacosSeat *seat, + NSEvent *nsevent) +{ + GdkMacosTabletData *tablet; + int axis_index; + + g_return_val_if_fail (GDK_IS_MACOS_SEAT (seat), NULL); + g_return_val_if_fail (nsevent != NULL, NULL); + + tablet = seat->current_tablet; + if (!tablet || !tablet->current_tool) + return NULL; + + if (tablet->current_tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT)) + { + axis_index = tablet->axis_indices[GDK_AXIS_XTILT]; + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + [nsevent tilt].x, &tablet->axes[GDK_AXIS_XTILT]); + + axis_index = tablet->axis_indices[GDK_AXIS_YTILT]; + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + [nsevent tilt].y, &tablet->axes[GDK_AXIS_YTILT]); + } - seat = gdk_seat_default_new_for_logical_pair (core_pointer, core_keyboard); + if (tablet->current_tool->tool_axes & GDK_AXIS_FLAG_PRESSURE) + { + axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE]; + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + [nsevent pressure], &tablet->axes[GDK_AXIS_PRESSURE]); + } - g_object_unref (core_pointer); - g_object_unref (core_keyboard); + if (tablet->current_tool->tool_axes & GDK_AXIS_FLAG_ROTATION) + { + axis_index = tablet->axis_indices[GDK_AXIS_ROTATION]; + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + [nsevent rotation], &tablet->axes[GDK_AXIS_ROTATION]); + } - return g_steal_pointer (&seat); + return g_memdup (tablet->axes, + sizeof (double) * GDK_AXIS_LAST); } diff --git a/gdk/macos/gdkmacosseat.h b/gdk/macos/gdkmacosseat.h new file mode 100644 index 0000000000..e09c01c995 --- /dev/null +++ b/gdk/macos/gdkmacosseat.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2021 Amazon.com, Inc. and its affiliates. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define GDK_TYPE_MACOS_SEAT (gdk_macos_seat_get_type ()) +#define GDK_MACOS_SEAT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_MACOS_SEAT, GdkMacosSeat)) +#define GDK_IS_MACOS_SEAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_MACOS_SEAT)) + +typedef struct _GdkMacosSeat GdkMacosSeat; +typedef struct _GdkMacosSeatClass GdkMacosSeatClass; + +GDK_AVAILABLE_IN_ALL +GType gdk_macos_seat_get_type (void) G_GNUC_CONST; + +G_END_DECLS diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build index 1b8d205055..943fb84457 100644 --- a/gdk/macos/meson.build +++ b/gdk/macos/meson.build @@ -33,6 +33,7 @@ gdk_macos_public_headers = files([ 'gdkmacosglcontext.h', 'gdkmacoskeymap.h', 'gdkmacosmonitor.h', + 'gdkmacosseat.h', 'gdkmacossurface.h', ]) -- cgit v1.2.1