[gtk+/gtk-2-24] Bug 663990 - Tablet pressure is broken on MacOSX



commit ffd949132a06760bee81f1a1eb9d9f5fbfc0a899
Author: Daniel Sabo <DanielSabo gmail com>
Date:   Tue May 22 02:10:00 2012 -0700

    Bug 663990 - Tablet pressure is broken on MacOSX
    
    Add extended input support to GDK Quartz.

 gdk/quartz/gdkevents-quartz.c |   19 ++
 gdk/quartz/gdkinput.c         |  369 ++++++++++++++++++++++++++++++++++++-----
 gdk/quartz/gdkinputprivate.h  |   11 +-
 3 files changed, 354 insertions(+), 45 deletions(-)
---
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index f853392..53f1962 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -32,6 +32,7 @@
 #include "gdkscreen.h"
 #include "gdkkeysyms.h"
 #include "gdkprivate-quartz.h"
+#include "gdkinputprivate.h"
 
 #define GRIP_WIDTH 15
 #define GRIP_HEIGHT 15
@@ -1278,6 +1279,7 @@ gdk_event_translate (GdkEvent *event,
   int x, y;
   int x_root, y_root;
   gboolean return_val;
+  GdkEvent *input_event;
 
   /* There is no support for real desktop wide grabs, so we break
    * grabs when the application loses focus (gets deactivated).
@@ -1428,6 +1430,12 @@ gdk_event_translate (GdkEvent *event,
     case NSRightMouseUp:
     case NSOtherMouseUp:
       fill_button_event (window, event, nsevent, x, y, x_root, y_root);
+
+      input_event = gdk_event_new (GDK_NOTHING);
+      if (_gdk_input_fill_quartz_input_event (event, nsevent, input_event))
+        append_event (input_event, TRUE);
+      else
+        gdk_event_free (input_event);
       break;
 
     case NSLeftMouseDragged:
@@ -1435,6 +1443,12 @@ gdk_event_translate (GdkEvent *event,
     case NSOtherMouseDragged:
     case NSMouseMoved:
       fill_motion_event (window, event, nsevent, x, y, x_root, y_root);
+
+      input_event = gdk_event_new (GDK_NOTHING);
+      if (_gdk_input_fill_quartz_input_event (event, nsevent, input_event))
+        append_event (input_event, TRUE);
+      else
+        gdk_event_free (input_event);
       break;
 
     case NSScrollWheel:
@@ -1484,6 +1498,11 @@ gdk_event_translate (GdkEvent *event,
       }
       break;
 
+    case NSTabletProximity:
+      _gdk_input_quartz_tablet_proximity ([nsevent pointingDeviceType]);
+      return_val = FALSE;
+      break;
+
     default:
       /* Ignore everything elsee. */
       return_val = FALSE;
diff --git a/gdk/quartz/gdkinput.c b/gdk/quartz/gdkinput.c
index 0fc9f72..6f5f8ea 100644
--- a/gdk/quartz/gdkinput.c
+++ b/gdk/quartz/gdkinput.c
@@ -27,42 +27,58 @@
 #include "config.h"
 #include <stdlib.h>
 
+#import <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
+
 #include "gdkprivate-quartz.h"
+#include "gdkscreen-quartz.h"
 #include "gdkinput.h"
 #include "gdkprivate.h"
 #include "gdkinputprivate.h"
 
+
+#define N_CORE_POINTER_AXES 2
+#define N_INPUT_DEVICE_AXES 5
+
+
 static GdkDeviceAxis gdk_input_core_axes[] = {
   { GDK_AXIS_X, 0, 0 },
   { GDK_AXIS_Y, 0, 0 }
 };
 
-GdkDevice *_gdk_core_pointer = NULL;
+static GdkDeviceAxis gdk_quartz_pen_axes[] = {
+  { GDK_AXIS_X, 0, 0 },
+  { GDK_AXIS_Y, 0, 0 },
+  { GDK_AXIS_PRESSURE, 0, 1 },
+  { GDK_AXIS_XTILT, -1, 1 },
+  { GDK_AXIS_YTILT, -1, 1 }
+};
 
-/* Global variables  */
+static GdkDeviceAxis gdk_quartz_cursor_axes[] = {
+  { GDK_AXIS_X, 0, 0 },
+  { GDK_AXIS_Y, 0, 0 },
+  { GDK_AXIS_PRESSURE, 0, 1 },
+  { GDK_AXIS_XTILT, -1, 1 },
+  { GDK_AXIS_YTILT, -1, 1 }
+};
 
-gchar            *_gdk_input_gxid_host;
-gint              _gdk_input_gxid_port;
-gint              _gdk_input_ignore_core;
-GList            *_gdk_input_windows;
-GList            *_gdk_input_devices;
+static GdkDeviceAxis gdk_quartz_eraser_axes[] = {
+  { GDK_AXIS_X, 0, 0 },
+  { GDK_AXIS_Y, 0, 0 },
+  { GDK_AXIS_PRESSURE, 0, 1 },
+  { GDK_AXIS_XTILT, -1, 1 },
+  { GDK_AXIS_YTILT, -1, 1 }
+};
 
-void
-_gdk_init_input_core (void)
-{
-  _gdk_core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
-  
-  _gdk_core_pointer->name = "Core Pointer";
-  _gdk_core_pointer->source = GDK_SOURCE_MOUSE;
-  _gdk_core_pointer->mode = GDK_MODE_SCREEN;
-  _gdk_core_pointer->has_cursor = TRUE;
-  _gdk_core_pointer->num_axes = 2;
-  _gdk_core_pointer->axes = gdk_input_core_axes;
-  _gdk_core_pointer->num_keys = 0;
-  _gdk_core_pointer->keys = NULL;
 
-  _gdk_display->core_pointer = _gdk_core_pointer;
-}
+/* Global variables  */
+static GList     *_gdk_input_windows = NULL;
+static GList     *_gdk_input_devices = NULL;
+static GdkDevice *_gdk_core_pointer = NULL;
+static GdkDevice *_gdk_quartz_pen = NULL;
+static GdkDevice *_gdk_quartz_cursor = NULL;
+static GdkDevice *_gdk_quartz_eraser = NULL;
+static GdkDevice *active_device = NULL;
 
 static void
 gdk_device_finalize (GObject *object)
@@ -216,9 +232,11 @@ gdk_device_get_n_axes (GdkDevice *device)
 
 void
 gdk_device_set_axis_use (GdkDevice   *device,
-			 guint        index,
-			 GdkAxisUse   use)
+                         guint        index,
+                         GdkAxisUse   use)
 {
+#if 0
+  /* Remapping axes is unsupported for now */
   g_return_if_fail (device != NULL);
   g_return_if_fail (index < device->num_axes);
 
@@ -241,24 +259,67 @@ gdk_device_set_axis_use (GdkDevice   *device,
       device->axes[index].max = 1;
       break;
     }
+#endif
 }
 
-void 
+/**
+ * gdk_input_set_device_state:
+ * @device: The devices to set
+ * @mask: The new button mask
+ * @axes: The new axes values
+ *
+ * Set the state of a device's inputs for later
+ * retrieval by gdk_device_get_state.
+ */
+static void
+gdk_input_set_device_state (GdkDevice *device,
+                            GdkModifierType mask,
+                            gdouble *axes)
+{
+  GdkDevicePrivate *priv;
+  gint i;
+
+  if (device != _gdk_core_pointer)
+    {
+      priv = (GdkDevicePrivate *)device;
+      priv->last_state = mask;
+
+      for (i = 0; i < device->num_axes; ++i)
+        priv->last_axes_state[i] = axes[i];
+    }
+}
+
+void
 gdk_device_get_state (GdkDevice       *device,
                       GdkWindow       *window,
                       gdouble         *axes,
                       GdkModifierType *mask)
 {
-  gint x_int, y_int;
+  GdkDevicePrivate *priv;
+  gint i;
 
-  g_assert (device == _gdk_core_pointer);
-      
-  gdk_window_get_pointer (window, &x_int, &y_int, mask);
+  if (device == _gdk_core_pointer)
+    {
+      gint x_int, y_int;
 
-  if (axes)
+      gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+      if (axes)
+        {
+          axes[0] = x_int;
+          axes[1] = y_int;
+        }
+    }
+  else
     {
-      axes[0] = x_int;
-      axes[1] = y_int;
+      priv = (GdkDevicePrivate *)device;
+
+      if (mask)
+        *mask = priv->last_state;
+
+      if (axes)
+        for (i = 0; i < device->num_axes; ++i)
+          axes[i] = priv->last_axes_state[i];
     }
 }
 
@@ -296,6 +357,14 @@ gboolean
 gdk_device_set_mode (GdkDevice   *device,
                      GdkInputMode mode)
 {
+  /* FIXME: Window mode isn't supported yet */
+  if (device != _gdk_core_pointer &&
+      (mode == GDK_MODE_DISABLED || mode == GDK_MODE_SCREEN))
+    {
+      device->mode = mode;
+      return TRUE;
+    }
+
   return FALSE;
 }
 
@@ -408,9 +477,67 @@ _gdk_input_window_destroy (GdkWindow *window)
 void
 _gdk_input_init (void)
 {
-  _gdk_init_input_core ();
+  GdkDevicePrivate *priv;
+
+  _gdk_core_pointer = g_object_new (GDK_TYPE_DEVICE, NULL);
+  _gdk_core_pointer->name = "Core Pointer";
+  _gdk_core_pointer->source = GDK_SOURCE_MOUSE;
+  _gdk_core_pointer->mode = GDK_MODE_SCREEN;
+  _gdk_core_pointer->has_cursor = TRUE;
+  _gdk_core_pointer->num_axes = N_CORE_POINTER_AXES;
+  _gdk_core_pointer->axes = gdk_input_core_axes;
+  _gdk_core_pointer->num_keys = 0;
+  _gdk_core_pointer->keys = NULL;
+
+  _gdk_display->core_pointer = _gdk_core_pointer;
   _gdk_input_devices = g_list_append (NULL, _gdk_core_pointer);
-  _gdk_input_ignore_core = FALSE;
+
+  _gdk_quartz_pen = g_object_new (GDK_TYPE_DEVICE, NULL);
+  _gdk_quartz_pen->name = "Quartz Pen";
+  _gdk_quartz_pen->source = GDK_SOURCE_PEN;
+  _gdk_quartz_pen->mode = GDK_MODE_SCREEN;
+  _gdk_quartz_pen->has_cursor = TRUE;
+  _gdk_quartz_pen->num_axes = N_INPUT_DEVICE_AXES;
+  _gdk_quartz_pen->axes = gdk_quartz_pen_axes;
+  _gdk_quartz_pen->num_keys = 0;
+  _gdk_quartz_pen->keys = NULL;
+
+  priv = (GdkDevicePrivate *)_gdk_quartz_pen;
+  priv->last_axes_state = g_malloc_n (_gdk_quartz_pen->num_axes, sizeof (gdouble));
+
+  _gdk_input_devices = g_list_append (_gdk_input_devices, _gdk_quartz_pen);
+
+  _gdk_quartz_cursor = g_object_new (GDK_TYPE_DEVICE, NULL);
+  _gdk_quartz_cursor->name = "Quartz Cursor";
+  _gdk_quartz_cursor->source = GDK_SOURCE_CURSOR;
+  _gdk_quartz_cursor->mode = GDK_MODE_SCREEN;
+  _gdk_quartz_cursor->has_cursor = TRUE;
+  _gdk_quartz_cursor->num_axes = N_INPUT_DEVICE_AXES;
+  _gdk_quartz_cursor->axes = gdk_quartz_cursor_axes;
+  _gdk_quartz_cursor->num_keys = 0;
+  _gdk_quartz_cursor->keys = NULL;
+
+  priv = (GdkDevicePrivate *)_gdk_quartz_cursor;
+  priv->last_axes_state = g_malloc_n (_gdk_quartz_cursor->num_axes, sizeof (gdouble));
+
+  _gdk_input_devices = g_list_append (_gdk_input_devices, _gdk_quartz_cursor);
+
+  _gdk_quartz_eraser = g_object_new (GDK_TYPE_DEVICE, NULL);
+  _gdk_quartz_eraser->name = "Quartz Eraser";
+  _gdk_quartz_eraser->source = GDK_SOURCE_ERASER;
+  _gdk_quartz_eraser->mode = GDK_MODE_SCREEN;
+  _gdk_quartz_eraser->has_cursor = TRUE;
+  _gdk_quartz_eraser->num_axes = N_INPUT_DEVICE_AXES;
+  _gdk_quartz_eraser->axes = gdk_quartz_eraser_axes;
+  _gdk_quartz_eraser->num_keys = 0;
+  _gdk_quartz_eraser->keys = NULL;
+
+  priv = (GdkDevicePrivate *)_gdk_quartz_eraser;
+  priv->last_axes_state = g_malloc_n (_gdk_quartz_eraser->num_axes, sizeof (gdouble));
+
+  _gdk_input_devices = g_list_append (_gdk_input_devices, _gdk_quartz_eraser);
+
+  active_device = _gdk_core_pointer;
 }
 
 void
@@ -423,14 +550,15 @@ _gdk_input_exit (void)
     {
       gdkdev = (GdkDevicePrivate *)(tmp_list->data);
       if (gdkdev != (GdkDevicePrivate *)_gdk_core_pointer)
-	{
-	  gdk_device_set_mode ((GdkDevice *)gdkdev, GDK_MODE_DISABLED);
-
-	  g_free (gdkdev->info.name);
-	  g_free (gdkdev->info.axes);
-	  g_free (gdkdev->info.keys);
-	  g_free (gdkdev);
-	}
+        {
+          gdk_device_set_mode ((GdkDevice *)gdkdev, GDK_MODE_DISABLED);
+
+          g_free (gdkdev->info.name);
+          g_free (gdkdev->info.axes);
+          g_free (gdkdev->info.keys);
+          g_free (gdkdev->last_axes_state);
+          g_free (gdkdev);
+        }
     }
 
   g_list_free (_gdk_input_devices);
@@ -468,3 +596,160 @@ _gdk_input_window_crossing (GdkWindow *window,
                             gboolean   enter)
 {
 }
+
+/**
+ * _gdk_input_quartz_tablet_proximity:
+ * @deviceType: The result of [nsevent pointingDeviceType]
+ *
+ * Update the current active device based on a proximity event.
+ */
+void
+_gdk_input_quartz_tablet_proximity (NSPointingDeviceType deviceType)
+{
+  if (deviceType == NSPenPointingDevice)
+    active_device = _gdk_quartz_pen;
+  else if (deviceType == NSCursorPointingDevice)
+    active_device = _gdk_quartz_cursor;
+  else if (deviceType == NSEraserPointingDevice)
+    active_device = _gdk_quartz_eraser;
+  else
+    active_device = _gdk_core_pointer;
+}
+
+/**
+ * _gdk_input_fill_quartz_input_event:
+ * @event: The GDK mouse event.
+ * @nsevent: The NSEvent that generated the mouse event.
+ * @input_event: (out): Return location for the input event.
+ *
+ * Handle extended input for the passed event, the GdkEvent object
+ * passed in should be a filled mouse button or motion event.
+ *
+ * Return value: %TRUE if an extended input event was generated.
+ */
+gboolean
+_gdk_input_fill_quartz_input_event (GdkEvent *event,
+                                    NSEvent  *nsevent,
+                                    GdkEvent *input_event)
+{
+  gdouble *axes;
+  gint x, y;
+  gint x_target, y_target;
+  gdouble x_root, y_root;
+  gint state;
+  GdkInputWindow *iw;
+  GdkWindow *target_window;
+  GdkScreenQuartz *screen_quartz;
+
+  if ([nsevent subtype] == NSTabletProximityEventSubtype)
+    {
+      _gdk_input_quartz_tablet_proximity ([nsevent pointingDeviceType]);
+    }
+  else if (([nsevent subtype] != NSTabletPointEventSubtype) ||
+           (active_device == _gdk_core_pointer) ||
+           (active_device->mode == GDK_MODE_DISABLED))
+    {
+      _gdk_display->ignore_core_events = FALSE;
+      return FALSE;
+    }
+
+  switch (event->any.type)
+    {
+      case GDK_MOTION_NOTIFY:
+        x = event->motion.x;
+        y = event->motion.y;
+        state = event->motion.state;
+        break;
+      case GDK_BUTTON_PRESS:
+      case GDK_BUTTON_RELEASE:
+        x = event->button.x;
+        y = event->button.y;
+        state = event->button.state;
+        break;
+      default:
+        /* Not an input related event */
+        return FALSE;
+        break;
+    }
+
+  /* Input events won't be propagated through windows that aren't listening
+   * for input events, so _gdk_window_get_input_window_for_event finds the
+   * window to directly send the event to.
+   */
+  target_window = _gdk_window_get_input_window_for_event (event->any.window,
+                                                          event->any.type,
+                                                          0, x, y, 0);
+
+  iw = _gdk_input_window_find (target_window);
+
+  if (!iw)
+    {
+      /* Return if the target window doesn't have extended events enabled or
+       * hasn't asked for this type of event.
+       */
+      _gdk_display->ignore_core_events = FALSE;
+      return FALSE;
+    }
+
+  /* The cursor is inside an extended events window, block propagation of the
+   * core motion / button events
+   */
+  _gdk_display->ignore_core_events = TRUE;
+
+  axes = g_malloc_n (N_INPUT_DEVICE_AXES, sizeof (gdouble));
+
+  gdk_window_get_origin (target_window, &x_target, &y_target);
+
+  /* Equation for root x & y taken from _gdk_quartz_window_xy_to_gdk_xy
+   * recalculated here to get doubles instead of ints.
+   */
+  screen_quartz = GDK_SCREEN_QUARTZ (_gdk_screen);
+  x_root = [NSEvent mouseLocation].x - screen_quartz->min_x;
+  y_root = screen_quartz->height - [NSEvent mouseLocation].y + screen_quartz->min_y;
+
+  axes[0] = x_root - x_target;
+  axes[1] = y_root - y_target;
+  axes[2] = [nsevent pressure];
+  axes[3] = [nsevent tilt].x;
+  axes[4] = [nsevent tilt].y;
+
+  gdk_input_set_device_state (active_device, state, axes);
+
+  input_event->any.window     = target_window;
+  input_event->any.type       = event->any.type;
+  input_event->any.send_event = event->any.send_event;
+
+  switch (event->any.type)
+    {
+      case GDK_MOTION_NOTIFY:
+        input_event->motion.device = active_device;
+        input_event->motion.x      = axes[0];
+        input_event->motion.y      = axes[1];
+        input_event->motion.axes   = axes;
+        input_event->motion.x_root = x_root;
+        input_event->motion.y_root = y_root;
+
+        input_event->motion.time    = event->motion.time;
+        input_event->motion.state   = event->motion.state;
+        input_event->motion.is_hint = event->motion.is_hint;
+        break;
+      case GDK_BUTTON_PRESS:
+      case GDK_BUTTON_RELEASE:
+        input_event->button.device = active_device;
+        input_event->button.x      = axes[0];
+        input_event->button.y      = axes[1];
+        input_event->button.axes   = axes;
+        input_event->button.x_root = x_root;
+        input_event->button.y_root = y_root;
+
+        input_event->button.time   = event->button.time;
+        input_event->button.state  = event->button.state;
+        input_event->button.button = event->button.button;
+        break;
+      default:
+        return FALSE;
+        break;
+    }
+
+  return TRUE;
+}
diff --git a/gdk/quartz/gdkinputprivate.h b/gdk/quartz/gdkinputprivate.h
index b8f13ac..d2e72a0 100644
--- a/gdk/quartz/gdkinputprivate.h
+++ b/gdk/quartz/gdkinputprivate.h
@@ -95,6 +95,9 @@ struct _GdkAxisInfo
 
 struct _GdkDevicePrivate {
   GdkDevice  info;
+
+  gint last_state;
+  gdouble *last_axes_state;
 };
 
 struct _GdkDeviceClass
@@ -125,9 +128,6 @@ struct _GdkInputWindow
 /* Global data */
 
 extern const GdkDevice gdk_input_core_info;
-extern GdkDevice *_gdk_core_pointer;
-extern GList *_gdk_input_devices;
-extern GList *_gdk_input_windows;
 
 extern GdkInputVTable gdk_input_vtable;
 /* information about network port and host for gxid daemon */
@@ -150,6 +150,11 @@ void               _gdk_init_input_core      (void);
 void               _gdk_input_window_crossing (GdkWindow       *window,
                                                gboolean         enter);
 
+void               _gdk_input_quartz_tablet_proximity (NSPointingDeviceType deviceType);
+gboolean           _gdk_input_fill_quartz_input_event (GdkEvent  *event,
+                                                       NSEvent   *nsevent,
+                                                       GdkEvent  *input_event);
+
 void _gdk_input_exit           (void);
 
 #endif /* __GDK_INPUTPRIVATE_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]