[mutter/wip/barriers-corruption: 2/2] barrier: Add support for new barrier features in XInput 2.3



commit 9b4f9b90df84eba4f8af3333e82dc952b4432564
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Jul 30 15:57:53 2012 -0300

    barrier: Add support for new barrier features in XInput 2.3
    
    XInput 2.3 adds support for "barrier events", which let us know when
    a pointer barrier has been hit, and when the pointer has stopped
    hitting the barrier, and lets us "release" the barrier, temporarily
    letting the pointer pass through the barrier. These features can be
    combined to allow for certain pointer gestures, such as "pushing"
    against the bottom of the screen, or stopping the pointer on monitor
    edges while dragging slowly for increased edge precision.
    
    This commit should allow graceful fallback if servers with
    XInput 2.3 aren't supported.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=677215

 configure.ac               |    3 +
 src/core/barrier.c         |  154 ++++++++++++++++++++++++++++++++++++++++++++
 src/core/display-private.h |   20 ++++++
 src/core/display.c         |   81 ++++++++++++++++++++++-
 src/core/screen.c          |    7 ++
 src/meta/barrier.h         |   41 ++++++++++++
 src/meta/display.h         |    1 +
 7 files changed, 305 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 44aa59f..45cc3f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -201,6 +201,9 @@ fi
 
 PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
 
+PKG_CHECK_EXISTS([xi >= 1.6.99.1],
+                 AC_DEFINE([HAVE_XI23],[1],[Define if you have support for XInput 2.3 or greater]))
+
 # This is used for plugins
 AC_SUBST(CLUTTER_PACKAGE)
 PKG_CHECK_MODULES(CLUTTER, $CLUTTER_PACKAGE)
diff --git a/src/core/barrier.c b/src/core/barrier.c
index 69db69e..e471efa 100644
--- a/src/core/barrier.c
+++ b/src/core/barrier.c
@@ -4,6 +4,7 @@
 
 #include <glib-object.h>
 
+#include <X11/extensions/XInput2.h>
 #include <X11/extensions/Xfixes.h>
 #include <meta/util.h>
 #include <meta/barrier.h>
@@ -29,6 +30,15 @@ enum {
 
 static GParamSpec *obj_props[PROP_LAST];
 
+enum {
+  HIT,
+  LEFT,
+
+  LAST_SIGNAL,
+};
+
+static guint obj_signals[LAST_SIGNAL];
+
 struct _MetaBarrierPrivate
 {
   MetaDisplay *display;
@@ -133,6 +143,31 @@ meta_barrier_is_active (MetaBarrier *barrier)
   return barrier->priv->xbarrier != 0;
 }
 
+/**
+ * meta_barrier_release:
+ * @barrier: The barrier to release
+ * @event: The event to release the pointer for
+ *
+ * In XI2.3, pointer barriers provide a feature where they can
+ * be temporarily released so that the pointer goes through
+ * them. Pass a #MetaBarrierEvent to release the barrier for
+ * this event sequence.
+ */
+void
+meta_barrier_release (MetaBarrier      *barrier,
+                      MetaBarrierEvent *event)
+{
+#ifdef HAVE_XI23
+  MetaBarrierPrivate *priv = barrier->priv;
+  if (META_DISPLAY_HAS_XINPUT_23 (priv->display))
+    {
+      XIBarrierReleasePointer (priv->display->xdisplay,
+                               META_VIRTUAL_CORE_POINTER_ID,
+                               priv->xbarrier, event->event_id);
+    }
+#endif /* HAVE_XI23 */
+}
+
 static void
 meta_barrier_constructed (GObject *object)
 {
@@ -157,6 +192,12 @@ meta_barrier_constructed (GObject *object)
                                                priv->x2, priv->y2,
                                                priv->directions, 0, NULL);
 
+  /* Take a ref that we'll release when the XID dies inside destroy(),
+   * so that the object stays alive and doesn't get GC'd. */
+  g_object_ref (barrier);
+
+  meta_display_register_x_barrier (priv->display, &priv->xbarrier, barrier);
+
   G_OBJECT_CLASS (meta_barrier_parent_class)->constructed (object);
 }
 
@@ -215,6 +256,42 @@ meta_barrier_class_init (MetaBarrierClass *klass)
 
   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 
+  /**
+   * MetaBarrier::hit:
+   * @barrier: The #MetaBarrier that was hit
+   * @event: A #MetaBarrierEvent that has the details of how
+   * the barrier was hit.
+   *
+   * When a pointer barrier is hit, this will trigger. This
+   * requires an XI2-enabled server.
+   */
+  obj_signals[HIT] =
+    g_signal_new ("hit",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_FIRST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  META_TYPE_BARRIER_EVENT);
+
+  /**
+   * MetaBarrier::left:
+   * @barrier: The #MetaBarrier that was left
+   * @event: A #MetaBarrierEvent that has the details of how
+   * the barrier was left.
+   *
+   * When a pointer barrier hitbox was left, this will trigger.
+   * This requires an XI2-enabled server.
+   */
+  obj_signals[LEFT] =
+    g_signal_new ("left",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_FIRST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  META_TYPE_BARRIER_EVENT);
+
   g_type_class_add_private (object_class, sizeof(MetaBarrierPrivate));
 }
 
@@ -232,8 +309,11 @@ meta_barrier_destroy (MetaBarrier *barrier)
   if (!meta_barrier_is_active (barrier))
     return;
 
+  meta_display_unregister_x_barrier (priv->display, priv->xbarrier);
   XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
   priv->xbarrier = 0;
+
+  g_object_unref (barrier);
 }
 
 static void
@@ -241,3 +321,77 @@ meta_barrier_init (MetaBarrier *barrier)
 {
   barrier->priv = G_TYPE_INSTANCE_GET_PRIVATE (barrier, META_TYPE_BARRIER, MetaBarrierPrivate);
 }
+
+#ifdef HAVE_XI23
+static void
+meta_barrier_fire_event (MetaBarrier    *barrier,
+                         XIBarrierEvent *xevent)
+{
+  MetaBarrierEvent *event = g_slice_new0 (MetaBarrierEvent);
+
+  event->ref_count = 1;
+  event->event_id = xevent->eventid;
+  event->dt = xevent->dtime;
+
+  event->x = xevent->root_x;
+  event->y = xevent->root_y;
+  event->dx = xevent->dx;
+  event->dy = xevent->dy;
+
+  event->released = (xevent->flags & XIBarrierPointerReleased) != 0;
+  event->grabbed = (xevent->flags & XIBarrierDeviceIsGrabbed) != 0;
+
+  switch (xevent->evtype)
+    {
+    case XI_BarrierHit:
+      g_signal_emit (barrier, obj_signals[HIT], 0, event);
+      break;
+    case XI_BarrierLeave:
+      g_signal_emit (barrier, obj_signals[LEFT], 0, event);
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+gboolean
+meta_display_process_barrier_event (MetaDisplay    *display,
+                                    XIBarrierEvent *xev)
+{
+  MetaBarrier *barrier;
+
+  barrier = meta_display_lookup_x_barrier (display, xev->barrier);
+  if (barrier != NULL)
+    {
+      meta_barrier_fire_event (barrier, xev);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+#endif /* HAVE_XI23 */
+
+static MetaBarrierEvent *
+meta_barrier_event_ref (MetaBarrierEvent *event)
+{
+  g_return_val_if_fail (event != NULL, NULL);
+  g_return_val_if_fail (event->ref_count > 0, NULL);
+
+  g_atomic_int_inc ((volatile int *)&event->ref_count);
+  return event;
+}
+
+static void
+meta_barrier_event_unref (MetaBarrierEvent *event)
+{
+  g_return_if_fail (event != NULL);
+  g_return_if_fail (event->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test ((volatile int *)&event->ref_count))
+    g_slice_free (MetaBarrierEvent, event);
+}
+
+G_DEFINE_BOXED_TYPE (MetaBarrierEvent,
+                     meta_barrier_event,
+                     meta_barrier_event_ref,
+                     meta_barrier_event_unref)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 82bb2ea..a7b5d0c 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -39,6 +39,7 @@
 #include <meta/display.h>
 #include "keybindings-private.h"
 #include <meta/prefs.h>
+#include <meta/barrier.h>
 
 #ifdef HAVE_STARTUP_NOTIFICATION
 #include <libsn/sn.h>
@@ -317,6 +318,12 @@ struct _MetaDisplay
   unsigned int have_damage : 1;
 #define META_DISPLAY_HAS_COMPOSITE(display) ((display)->have_composite)
 #define META_DISPLAY_HAS_DAMAGE(display) ((display)->have_damage)
+#ifdef HAVE_XI23
+  gboolean have_xinput_23 : 1;
+#define META_DISPLAY_HAS_XINPUT_23(display) ((display)->have_xinput_23)
+#else
+#define META_DISPLAY_HAS_XINPUT_23(display) FALSE
+#endif /* HAVE_XI23 */
 };
 
 struct _MetaDisplayClass
@@ -371,6 +378,14 @@ void        meta_display_unregister_x_window (MetaDisplay *display,
 void        meta_display_notify_window_created (MetaDisplay  *display,
                                                 MetaWindow   *window);
 
+MetaBarrier* meta_display_lookup_x_barrier     (MetaDisplay    *display,
+                                                PointerBarrier  xbarrier);
+void        meta_display_register_x_barrier   (MetaDisplay   *display,
+                                              PointerBarrier *xbarrierp,
+                                              MetaBarrier  *barrier);
+void        meta_display_unregister_x_barrier (MetaDisplay    *display,
+                                               PointerBarrier  xbarrier);
+
 GSList*     meta_display_list_windows        (MetaDisplay          *display,
                                               MetaListWindowsFlags  flags);
 
@@ -449,4 +464,9 @@ void meta_display_overlay_key_activate (MetaDisplay *display);
 /* In above-tab-keycode.c */
 guint meta_display_get_above_tab_keycode (MetaDisplay *display);
 
+#ifdef HAVE_XI23
+gboolean meta_display_process_barrier_event (MetaDisplay    *display,
+                                             XIBarrierEvent *event);
+#endif /* HAVE_XI23 */
+
 #endif
diff --git a/src/core/display.c b/src/core/display.c
index c09b63e..001b860 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -790,8 +790,16 @@ meta_display_open (void)
                          &the_display->xinput_event_base))
       {
         if (XIQueryVersion (the_display->xdisplay, &major, &minor) == Success)
-          if (((major * 10) + minor) >= 22)
-            has_xi = TRUE;
+          {
+            int version = (major * 10) + minor;
+            if (version >= 22)
+              has_xi = TRUE;
+
+#ifdef HAVE_XI23
+            if (version >= 23)
+              the_display->have_xinput_23 = TRUE;
+#endif /* HAVE_XI23 */
+          }
       }
 
     if (!has_xi)
@@ -1832,6 +1840,12 @@ get_input_event (MetaDisplay *display,
         case XI_Leave:
           if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
             return input_event;
+          break;
+        case XI_BarrierHit:
+        case XI_BarrierLeave:
+          if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
+            return input_event;
+          break;
         default:
           break;
         }
@@ -2395,6 +2409,13 @@ event_callback (XEvent   *event,
 
             }
           break;
+#ifdef HAVE_XI23
+        case XI_BarrierHit:
+        case XI_BarrierLeave:
+          if (meta_display_process_barrier_event (display, (XIBarrierEvent *) input_event))
+            filter_out_event = bypass_compositor = TRUE;
+          break;
+#endif /* HAVE_XI23 */
         }
     }
   else
@@ -2926,6 +2947,11 @@ event_get_modified_window (MetaDisplay *display,
         case XI_Enter:
         case XI_Leave:
           return ((XIEnterEvent *) input_event)->event;
+#ifdef HAVE_XI23
+        case XI_BarrierHit:
+        case XI_BarrierLeave:
+          return ((XIBarrierEvent *) input_event)->event;
+#endif /* HAVE_XI23 */
         }
     }
 
@@ -3201,6 +3227,14 @@ meta_spew_xi2_event (MetaDisplay *display,
     case XI_Leave:
       name = "XI_Leave";
       break;
+#ifdef HAVE_XI23
+    case XI_BarrierHit:
+      name = "XI_BarrierHit";
+      break;
+    case XI_BarrierLeave:
+      name = "XI_BarrierLeave";
+      break;
+#endif /* HAVE_XI23 */
     }
 
   switch (input_event->evtype)
@@ -3564,6 +3598,32 @@ meta_display_notify_window_created (MetaDisplay  *display,
   g_signal_emit (display, display_signals[WINDOW_CREATED], 0, window);
 }
 
+MetaBarrier*
+meta_display_lookup_x_barrier (MetaDisplay    *display,
+                               PointerBarrier  xbarrier)
+{
+  return g_hash_table_lookup (display->window_ids, &xbarrier);
+}
+
+void
+meta_display_register_x_barrier (MetaDisplay    *display,
+                                 PointerBarrier *xbarrierp,
+                                 MetaBarrier    *barrier)
+{
+  g_return_if_fail (g_hash_table_lookup (display->window_ids, xbarrierp) == NULL);
+
+  /* g_hash_table_insert (display->window_ids, xbarrierp, barrier); */
+}
+
+void
+meta_display_unregister_x_barrier (MetaDisplay    *display,
+                                   PointerBarrier  xbarrier)
+{
+  g_return_if_fail (g_hash_table_lookup (display->window_ids, &xbarrier) != NULL);
+
+  g_hash_table_remove (display->window_ids, &xbarrier);
+}
+
 /**
  * meta_display_xwindow_is_a_no_focus_window:
  * @display: A #MetaDisplay
@@ -5687,6 +5747,23 @@ meta_display_get_xinput_opcode (MetaDisplay *display)
 }
 
 /**
+ * meta_display_supports_extended_barriers:
+ * @display: a #MetaDisplay
+ *
+ * Returns whether the X server supports extended barrier
+ * features as defined in version 2.3 of the XInput 2
+ * specification.
+ *
+ * Clients should use this method to determine whether their
+ * interfaces should depend on new barrier features.
+ */
+gboolean
+meta_display_supports_extended_barriers (MetaDisplay *display)
+{
+  return META_DISPLAY_HAS_XINPUT_23 (display);
+}
+
+/**
  * meta_display_get_xdisplay: (skip)
  *
  */
diff --git a/src/core/screen.c b/src/core/screen.c
index 4b41dc3..20970a2 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -755,6 +755,13 @@ meta_screen_new (MetaDisplay *display,
     XISetMask (mask.mask, XI_FocusIn);
     XISetMask (mask.mask, XI_FocusOut);
     XISetMask (mask.mask, XI_Motion);
+#ifdef HAVE_XI23
+    if (META_DISPLAY_HAS_XINPUT_23 (display))
+      {
+        XISetMask (mask.mask, XI_BarrierHit);
+        XISetMask (mask.mask, XI_BarrierLeave);
+      }
+#endif /* HAVE_XI23 */
     XISelectEvents (xdisplay, xroot, &mask, 1);
 
     event_mask = (SubstructureRedirectMask | SubstructureNotifyMask |
diff --git a/src/meta/barrier.h b/src/meta/barrier.h
index cf45daa..b571376 100644
--- a/src/meta/barrier.h
+++ b/src/meta/barrier.h
@@ -20,6 +20,8 @@ typedef struct _MetaBarrier        MetaBarrier;
 typedef struct _MetaBarrierClass   MetaBarrierClass;
 typedef struct _MetaBarrierPrivate MetaBarrierPrivate;
 
+typedef struct _MetaBarrierEvent   MetaBarrierEvent;
+
 struct _MetaBarrier
 {
   GObject parent;
@@ -36,6 +38,8 @@ GType meta_barrier_get_type (void) G_GNUC_CONST;
 
 gboolean meta_barrier_is_active (MetaBarrier *barrier);
 void meta_barrier_destroy (MetaBarrier *barrier);
+void meta_barrier_release (MetaBarrier      *barrier,
+                           MetaBarrierEvent *event);
 
 /* Keep in sync with XFixes */
 typedef enum {
@@ -45,6 +49,43 @@ typedef enum {
   META_BARRIER_DIRECTION_NEGATIVE_Y = 1 << 3,
 } MetaBarrierDirection;
 
+/**
+ * MetaBarrierEvent:
+ * @event_id: A unique integer ID identifying a
+ * consecutive series of motions at or along the barrier
+ * @dt: Server time, in milliseconds, since the last event
+ * sent for this barrier
+ * @x: The cursor X position in screen coordinates
+ * @y: The cursor Y position in screen coordinates.
+ * @dx: If the cursor hadn't been constrained, the delta
+ * of X movement past the barrier, in screen coordinates
+ * @dy: If the cursor hadn't been constrained, the delta
+ * of X movement past the barrier, in screen coordinates
+ * @released: A boolean flag, %TRUE if this event generated
+ * by the pointer leaving the barrier as a result of a client
+ * calling meta_barrier_release() (will be set only for
+ * MetaBarrier::leave signals)
+ * @grabbed: A boolean flag, %TRUE if the pointer was grabbed
+ * at the time this event was sent
+ */
+struct _MetaBarrierEvent {
+  /* < private > */
+  volatile guint ref_count;
+
+  /* < public > */
+  int event_id;
+  int dt;
+  double x;
+  double y;
+  double dx;
+  double dy;
+  gboolean released;
+  gboolean grabbed;
+};
+
+#define META_TYPE_BARRIER_EVENT (meta_barrier_event_get_type ())
+GType meta_barrier_event_get_type (void) G_GNUC_CONST;
+
 G_END_DECLS
 
 #endif /* __META_BARRIER_H__ */
diff --git a/src/meta/display.h b/src/meta/display.h
index ad1e2fd..b922b48 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -68,6 +68,7 @@ void meta_display_get_compositor_version (MetaDisplay *display,
                                           int         *major,
                                           int         *minor);
 int meta_display_get_xinput_opcode (MetaDisplay *display);
+gboolean meta_display_supports_extended_barriers (MetaDisplay *display);
 Display *meta_display_get_xdisplay (MetaDisplay *display);
 MetaCompositor *meta_display_get_compositor (MetaDisplay *display);
 GSList *meta_display_get_screens (MetaDisplay *display);



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