[mutter/wip/wayland-work: 18/22] wayland: add support for pointer barriers



commit e27bcc20c3b7afab120b2d9f23af630111d8f5ee
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Fri Sep 6 14:14:31 2013 +0200

    wayland: add support for pointer barriers
    
    Use the clutter pointer constrain callback and a lot of copypasted
    code from Xorg to implement reactive pointer barriers and pointer
    barrier events.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706655

 src/Makefile.am                    |    1 +
 src/core/barrier-private.h         |   39 +++
 src/core/barrier.c                 |  528 ++++++++++++++++++++++++++++++++++--
 src/core/display.c                 |    2 +-
 src/meta/barrier.h                 |    1 +
 src/wayland/meta-wayland-pointer.c |   33 ++-
 6 files changed, 567 insertions(+), 37 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 2917202..b63fa17 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,7 @@ libmutter_wayland_la_SOURCES =                        \
        core/async-getprop.h                    \
        core/barrier.c                          \
        meta/barrier.h                          \
+       core/barrier-private.h                  \
        core/bell.c                             \
        core/bell.h                             \
        core/boxes.c                            \
diff --git a/src/core/barrier-private.h b/src/core/barrier-private.h
new file mode 100644
index 0000000..e8a2e7a
--- /dev/null
+++ b/src/core/barrier-private.h
@@ -0,0 +1,39 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+
+/* 
+ * Copyright 2012, 2013 Red Hat Inc.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors: Jaster St. Pierre <jstpierr redhat com>
+ *          Giovanni Campagna <gcampagn redhat com>
+ */
+
+#ifndef BARRIER_PRIVATE_H
+#define BARRIER_PRIVATE_H
+
+typedef struct _MetaBarrierManager MetaBarrierManager;
+
+MetaBarrierManager *meta_barrier_manager_get (void);
+
+void meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager,
+                                           guint32             time,
+                                           float               current_x,
+                                           float               current_y,
+                                           float              *new_x,
+                                           float              *new_y);
+
+#endif
diff --git a/src/core/barrier.c b/src/core/barrier.c
index 643b26e..ff1f436 100644
--- a/src/core/barrier.c
+++ b/src/core/barrier.c
@@ -1,5 +1,27 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 
+/* 
+ * Copyright 2012, 2013 Red Hat Inc.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors: Jaster St. Pierre <jstpierr redhat com>
+ *          Giovanni Campagna <gcampagn redhat com>
+ */
+
 /**
  * SECTION:barrier
  * @Title: MetaBarrier
@@ -9,6 +31,7 @@
 #include "config.h"
 
 #include <glib-object.h>
+#include <math.h>
 
 #include <X11/extensions/XInput2.h>
 #include <X11/extensions/Xfixes.h>
@@ -16,6 +39,7 @@
 #include <meta/barrier.h>
 #include "display-private.h"
 #include "mutter-enum-types.h"
+#include "barrier-private.h"
 #include "core.h"
 
 G_DEFINE_TYPE (MetaBarrier, meta_barrier, G_TYPE_OBJECT)
@@ -56,9 +80,23 @@ struct _MetaBarrierPrivate
 
   MetaBarrierDirection directions;
 
+  /* x11 */
   PointerBarrier xbarrier;
+
+  /* wayland */
+  gboolean active;
+  gboolean seen, hit;
+
+  int barrier_event_id;
+  int release_event_id;
+  guint32 last_timestamp;
 };
 
+struct _MetaBarrierManager
+{
+  GList *barriers;
+} *global_barrier_manager;
+
 static void meta_barrier_event_unref (MetaBarrierEvent *event);
 
 static void
@@ -148,7 +186,10 @@ meta_barrier_dispose (GObject *object)
 gboolean
 meta_barrier_is_active (MetaBarrier *barrier)
 {
-  return barrier->priv->xbarrier != 0;
+  if (meta_is_wayland_compositor ())
+    return barrier->priv->active;
+  else
+    return barrier->priv->xbarrier != 0;
 }
 
 /**
@@ -165,15 +206,25 @@ void
 meta_barrier_release (MetaBarrier      *barrier,
                       MetaBarrierEvent *event)
 {
-#ifdef HAVE_XI23
-  MetaBarrierPrivate *priv = barrier->priv;
-  if (META_DISPLAY_HAS_XINPUT_23 (priv->display))
+  MetaBarrierPrivate *priv;
+
+  priv = barrier->priv;
+
+  if (meta_is_wayland_compositor ())
     {
-      XIBarrierReleasePointer (priv->display->xdisplay,
-                               META_VIRTUAL_CORE_POINTER_ID,
-                               priv->xbarrier, event->event_id);
+      priv->release_event_id = event->event_id;
     }
+  else
+    {
+#ifdef HAVE_XI23
+      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
@@ -192,19 +243,29 @@ meta_barrier_constructed (GObject *object)
       return;
     }
 
-  dpy = priv->display->xdisplay;
-  root = DefaultRootWindow (dpy);
+  if (meta_is_wayland_compositor ())
+    {
+      MetaBarrierManager *manager = meta_barrier_manager_get ();
 
-  priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
-                                               priv->x1, priv->y1,
-                                               priv->x2, priv->y2,
-                                               priv->directions, 0, NULL);
+      manager->barriers = g_list_prepend (manager->barriers, g_object_ref (barrier));
+      priv->active = TRUE;
+    }
+  else
+    {
+      dpy = priv->display->xdisplay;
+      root = DefaultRootWindow (dpy);
 
-  /* 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);
+      priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
+                                                   priv->x1, priv->y1,
+                                                   priv->x2, priv->y2,
+                                                   priv->directions, 0, NULL);
 
-  g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier);
+      /* 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);
+
+      g_hash_table_insert (priv->display->xids, &priv->xbarrier, barrier);
+    }
 
   G_OBJECT_CLASS (meta_barrier_parent_class)->constructed (object);
 }
@@ -312,16 +373,26 @@ meta_barrier_destroy (MetaBarrier *barrier)
   if (priv->display == NULL)
     return;
 
-  dpy = priv->display->xdisplay;
+  if (meta_is_wayland_compositor ())
+    {
+      MetaBarrierManager *manager = meta_barrier_manager_get ();
 
-  if (!meta_barrier_is_active (barrier))
-    return;
+      manager->barriers = g_list_remove (manager->barriers, barrier);
+      g_object_unref (barrier);
+    }
+  else
+    {
+      dpy = priv->display->xdisplay;
+
+      if (!meta_barrier_is_active (barrier))
+        return;
 
-  XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
-  g_hash_table_remove (priv->display->xids, &priv->xbarrier);
-  priv->xbarrier = 0;
+      XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
+      g_hash_table_remove (priv->display->xids, &priv->xbarrier);
+      priv->xbarrier = 0;
 
-  g_object_unref (barrier);
+      g_object_unref (barrier);
+    }
 }
 
 static void
@@ -371,6 +442,9 @@ meta_display_process_barrier_event (MetaDisplay    *display,
 {
   MetaBarrier *barrier;
 
+  if (meta_is_wayland_compositor ())
+    return FALSE;
+
   barrier = g_hash_table_lookup (display->xids, &xev->barrier);
   if (barrier != NULL)
     {
@@ -382,6 +456,405 @@ meta_display_process_barrier_event (MetaDisplay    *display,
 }
 #endif /* HAVE_XI23 */
 
+/*
+ * The following code was copied and adapted from the X server (Xi/xibarriers.c)
+ *
+ * Copyright 2012 Red Hat, Inc.
+ * Copyright © 2002 Keith Packard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+static gboolean
+barrier_is_horizontal(MetaBarrier *barrier)
+{
+  return barrier->priv->y1 == barrier->priv->y2;
+}
+
+static gboolean
+barrier_is_vertical(MetaBarrier *barrier)
+{
+  return barrier->priv->x1 == barrier->priv->x2;
+}
+
+/*
+ * @return The set of barrier movement directions the movement vector
+ * x1/y1 → x2/y2 represents.
+ */
+static int
+barrier_get_direction(int x1, int y1, int x2, int y2)
+{
+  int direction = 0;
+
+  /* which way are we trying to go */
+  if (x2 > x1)
+    direction |= META_BARRIER_DIRECTION_POSITIVE_X;
+  if (x2 < x1)
+    direction |= META_BARRIER_DIRECTION_NEGATIVE_X;
+  if (y2 > y1)
+    direction |= META_BARRIER_DIRECTION_POSITIVE_Y;
+  if (y2 < y1)
+    direction |= META_BARRIER_DIRECTION_NEGATIVE_Y;
+
+  return direction;
+}
+
+/*
+ * Test if the barrier may block movement in the direction defined by
+ * x1/y1 → x2/y2. This function only tests whether the directions could be
+ * blocked, it does not test if the barrier actually blocks the movement.
+ *
+ * @return TRUE if the barrier blocks the direction of movement or FALSE
+ * otherwise.
+ */
+static gboolean
+barrier_is_blocking_direction(MetaBarrier          *barrier,
+                              MetaBarrierDirection  direction)
+{
+  /* Barriers define which way is ok, not which way is blocking */
+  return (barrier->priv->directions & direction) != direction;
+}
+
+static gboolean
+inside_segment(int v, int v1, int v2)
+{
+  if (v1 < 0 && v2 < 0) /* line */
+    return TRUE;
+  else if (v1 < 0)      /* ray */
+    return v <= v2;
+  else if (v2 < 0)      /* ray */
+    return v >= v1;
+  else                  /* line segment */
+    return v >= v1 && v <= v2;
+}
+
+#define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
+#define F(t, a, b) ((t) * ((a) - (b)) + (a))
+
+/*
+ * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
+ * barrier. A movement vector with the startpoint or endpoint adjacent to
+ * the barrier itself counts as intersecting.
+ *
+ * @param x1 X start coordinate of movement vector
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @param[out] distance The distance between the start point and the
+ * intersection with the barrier (if applicable).
+ * @return TRUE if the barrier intersects with the given vector
+ */
+static gboolean
+barrier_is_blocking(MetaBarrier *barrier,
+                    int x1, int y1, int x2, int y2, double *distance)
+{
+  if (barrier_is_vertical (barrier))
+    {
+      float t, y;
+      t = T (barrier->priv->x1, x1, x2);
+      if (t < 0 || t > 1)
+        return FALSE;
+
+      /* Edge case: moving away from barrier. */
+      if (x2 > x1 && t == 0)
+        return FALSE;
+
+      y = F (t, y1, y2);
+      if (!inside_segment (y, barrier->priv->y1, barrier->priv->y2))
+        return FALSE;
+
+      *distance = sqrt ((y - y1) * (y - y1) + (barrier->priv->x1 - x1) * (barrier->priv->x1 - x1));
+      return TRUE;
+    }
+  else
+    {
+      float t, x;
+      t = T (barrier->priv->y1, y1, y2);
+      if (t < 0 || t > 1)
+        return FALSE;
+
+      /* Edge case: moving away from barrier. */
+      if (y2 > y1 && t == 0)
+        return FALSE;
+
+      x = F(t, x1, x2);
+      if (!inside_segment (x, barrier->priv->x1, barrier->priv->x2))
+        return FALSE;
+
+      *distance = sqrt ((x - x1) * (x - x1) + (barrier->priv->y1 - y1) * (barrier->priv->y1 - y1));
+      return TRUE;
+    }
+}
+
+#define HIT_EDGE_EXTENTS 2
+static gboolean
+barrier_inside_hit_box(MetaBarrier *barrier, int x, int y)
+{
+  int x1, x2, y1, y2;
+  int dir;
+
+  x1 = barrier->priv->x1;
+  x2 = barrier->priv->x2;
+  y1 = barrier->priv->y1;
+  y2 = barrier->priv->y2;
+  dir = ~(barrier->priv->directions);
+
+  if (barrier_is_vertical (barrier))
+    {
+      if (dir & META_BARRIER_DIRECTION_POSITIVE_X)
+        x1 -= HIT_EDGE_EXTENTS;
+      if (dir & META_BARRIER_DIRECTION_NEGATIVE_X)
+        x2 += HIT_EDGE_EXTENTS;
+    }
+  if (barrier_is_horizontal (barrier))
+    {
+      if (dir & META_BARRIER_DIRECTION_POSITIVE_Y)
+        y1 -= HIT_EDGE_EXTENTS;
+      if (dir & META_BARRIER_DIRECTION_NEGATIVE_Y)
+        y2 += HIT_EDGE_EXTENTS;
+    }
+
+  return x >= x1 && x <= x2 && y >= y1 && y <= y2;
+}
+
+/*
+ * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
+ *
+ * @param dir Only barriers blocking movement in direction dir are checked
+ * @param x1 X start coordinate of movement vector
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @return The barrier nearest to the movement origin that blocks this movement.
+ */
+static MetaBarrier *
+barrier_find_nearest(MetaBarrierManager *manager,
+                     int                 dir,
+                     int                 x1,
+                     int                 y1,
+                     int                 x2,
+                     int                 y2)
+{
+  GList *iter;
+  MetaBarrier *nearest = NULL;
+  double min_distance = INT_MAX;      /* can't get higher than that in X anyway */
+
+  for (iter = manager->barriers; iter; iter = iter->next)
+    {
+      MetaBarrier *b = iter->data;
+      double distance;
+
+      if (b->priv->seen || !b->priv->active)
+        continue;
+
+      if (!barrier_is_blocking_direction (b, dir))
+        continue;
+
+      if (barrier_is_blocking (b, x1, y1, x2, y2, &distance))
+        {
+          if (min_distance > distance)
+            {
+              min_distance = distance;
+              nearest = b;
+            }
+        }
+    }
+
+  return nearest;
+}
+
+/*
+ * Clamp to the given barrier given the movement direction specified in dir.
+ *
+ * @param barrier The barrier to clamp to
+ * @param dir The movement direction
+ * @param[out] x The clamped x coordinate.
+ * @param[out] y The clamped x coordinate.
+ */
+static void
+barrier_clamp_to_barrier(MetaBarrier *barrier,
+                         int          dir,
+                         float       *x,
+                         float       *y)
+{
+  if (barrier_is_vertical (barrier))
+    {
+      if ((dir & META_BARRIER_DIRECTION_NEGATIVE_X) & ~barrier->priv->directions)
+        *x = barrier->priv->x1;
+      if ((dir & META_BARRIER_DIRECTION_POSITIVE_X) & ~barrier->priv->directions)
+        *x = barrier->priv->x1 - 1;
+    }
+  if (barrier_is_horizontal (barrier))
+    {
+      if ((dir & META_BARRIER_DIRECTION_NEGATIVE_Y) & ~barrier->priv->directions)
+        *y = barrier->priv->y1;
+      if ((dir & META_BARRIER_DIRECTION_POSITIVE_Y) & ~barrier->priv->directions)
+        *y = barrier->priv->y1 - 1;
+    }
+}
+
+static gboolean
+emit_hit_event (gpointer data)
+{
+  MetaBarrierEvent *event = data;
+
+  g_signal_emit (event->barrier, obj_signals[HIT], 0, event);
+
+  meta_barrier_event_unref (event);
+  return FALSE;
+}
+
+static gboolean
+emit_left_event (gpointer data)
+{
+  MetaBarrierEvent *event = data;
+
+  g_signal_emit (event->barrier, obj_signals[LEFT], 0, event);
+
+  meta_barrier_event_unref (event);
+  return FALSE;
+}
+
+void
+meta_barrier_manager_constrain_cursor (MetaBarrierManager *manager,
+                                       guint32             time,
+                                       float               current_x,
+                                       float               current_y,
+                                       float              *new_x,
+                                       float              *new_y)
+{
+  float x = *new_x;
+  float y = *new_y;
+  int dir;
+  MetaBarrier *nearest = NULL;
+  GList *iter;
+  float dx = x - current_x;
+  float dy = y - current_y;
+
+  /* How this works:
+   * Given the origin and the movement vector, get the nearest barrier
+   * to the origin that is blocking the movement.
+   * Clamp to that barrier.
+   * Then, check from the clamped intersection to the original
+   * destination, again finding the nearest barrier and clamping.
+   */
+  dir = barrier_get_direction (current_x, current_y, x, y);
+
+  while (dir != 0)
+    {
+      MetaBarrierEvent *event;
+      gboolean new_sequence;
+
+      nearest = barrier_find_nearest (manager, dir, current_x, current_y, x, y);
+      if (!nearest)
+        break;
+
+      new_sequence = !nearest->priv->hit;
+
+      nearest->priv->seen = TRUE;
+      nearest->priv->hit = TRUE;
+
+      if (nearest->priv->barrier_event_id == nearest->priv->release_event_id)
+        continue;
+
+      barrier_clamp_to_barrier (nearest, dir, &x, &y);
+
+      if (barrier_is_vertical (nearest))
+        {
+          dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_X | META_BARRIER_DIRECTION_POSITIVE_X);
+          current_x = x;
+        }
+      else if (barrier_is_horizontal (nearest))
+        {
+          dir &= ~(META_BARRIER_DIRECTION_NEGATIVE_Y | META_BARRIER_DIRECTION_POSITIVE_Y);
+          current_y = y;
+        }
+
+      event = g_slice_new0 (MetaBarrierEvent);
+
+      event->ref_count = 1;
+      event->barrier = g_object_ref (nearest);
+      event->event_id = nearest->priv->barrier_event_id;
+      event->time = time;
+      event->dt = new_sequence ? 0 : time - nearest->priv->last_timestamp;
+      event->x = current_x;
+      event->y = current_y;
+      event->dx = dx;
+      event->dy = dy;
+      event->released = FALSE;
+      event->grabbed = FALSE;
+
+      g_idle_add (emit_hit_event, event);
+    }
+
+  for (iter = manager->barriers; iter; iter = iter->next)
+    {
+      MetaBarrierEvent *event;
+      MetaBarrier *barrier = iter->data;
+
+      if (!barrier->priv->active)
+        continue;
+
+      barrier->priv->seen = FALSE;
+      if (!barrier->priv->hit)
+        continue;
+
+      if (barrier_inside_hit_box (barrier, x, y))
+        continue;
+
+      barrier->priv->hit = FALSE;
+
+      event = g_slice_new0 (MetaBarrierEvent);
+
+      event->ref_count = 1;
+      event->barrier = g_object_ref (barrier);
+      event->event_id = barrier->priv->barrier_event_id;
+      event->time = time;
+      event->dt = time - barrier->priv->last_timestamp;
+      event->x = current_x;
+      event->y = current_y;
+      event->dx = dx;
+      event->dy = dy;
+      event->released = barrier->priv->barrier_event_id == barrier->priv->release_event_id;
+      event->grabbed = FALSE;
+
+      g_idle_add (emit_left_event, event);
+
+      /* If we've left the hit box, this is the
+       * start of a new event ID. */
+      barrier->priv->barrier_event_id++;
+    }
+
+  *new_x = x;
+  *new_y = y;
+}
+
+MetaBarrierManager *
+meta_barrier_manager_get (void)
+{
+  if (!global_barrier_manager)
+    global_barrier_manager = g_new0 (MetaBarrierManager, 1);
+
+  return global_barrier_manager;
+}
+
 static MetaBarrierEvent *
 meta_barrier_event_ref (MetaBarrierEvent *event)
 {
@@ -399,7 +872,12 @@ meta_barrier_event_unref (MetaBarrierEvent *event)
   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);
+    {
+      if (event->barrier)
+        g_object_unref (event->barrier);
+
+      g_slice_free (MetaBarrierEvent, event);
+    }
 }
 
 G_DEFINE_BOXED_TYPE (MetaBarrierEvent,
diff --git a/src/core/display.c b/src/core/display.c
index b493016..e8931ef 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -6050,7 +6050,7 @@ meta_display_get_xinput_opcode (MetaDisplay *display)
 gboolean
 meta_display_supports_extended_barriers (MetaDisplay *display)
 {
-  return META_DISPLAY_HAS_XINPUT_23 (display);
+  return meta_is_wayland_compositor () || META_DISPLAY_HAS_XINPUT_23 (display);
 }
 
 /**
diff --git a/src/meta/barrier.h b/src/meta/barrier.h
index d7b1666..7fb5457 100644
--- a/src/meta/barrier.h
+++ b/src/meta/barrier.h
@@ -94,6 +94,7 @@ typedef enum {
 struct _MetaBarrierEvent {
   /* < private > */
   volatile guint ref_count;
+  MetaBarrier *barrier;
 
   /* < public > */
   int event_id;
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
index cc4192c..6154c65 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -48,6 +48,7 @@
 
 #include "meta-wayland-pointer.h"
 #include "meta-wayland-private.h"
+#include "barrier-private.h"
 
 #include <string.h>
 
@@ -133,10 +134,10 @@ static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
  */
 
 static gboolean
-check_all_screen_monitors(MetaMonitorInfo *monitors,
-                         unsigned         n_monitors,
-                         float            x,
-                         float            y)
+check_all_screen_monitors (MetaMonitorInfo *monitors,
+                          unsigned         n_monitors,
+                          float            x,
+                          float            y)
 {
   unsigned int i;
 
@@ -161,14 +162,13 @@ static void
 constrain_all_screen_monitors (ClutterInputDevice *device,
                               MetaMonitorInfo    *monitors,
                               unsigned            n_monitors,
+                              float               current_x,
+                              float               current_y,
                               float              *x,
                               float              *y)
 {
-  ClutterPoint current;
   unsigned int i;
 
-  clutter_input_device_get_coords (device, NULL, &current);
-
   /* if we're trying to escape, clamp to the CRTC we're coming from */
   for (i = 0; i < n_monitors; i++)
     {
@@ -181,8 +181,8 @@ constrain_all_screen_monitors (ClutterInputDevice *device,
       top = monitor->rect.y;
       bottom = left + monitor->rect.height;
 
-      nx = current.x;
-      ny = current.y;
+      nx = current_x;
+      ny = current_y;
 
       if ((nx >= left) && (nx < right) && (ny >= top) && (ny < bottom))
        {
@@ -207,21 +207,32 @@ pointer_constrain_callback (ClutterInputDevice *device,
                            float              *new_y,
                            gpointer            user_data)
 {
+  MetaBarrierManager *barrier_manager;
   MetaMonitorManager *monitor_manager;
   MetaMonitorInfo *monitors;
   unsigned int n_monitors;
   gboolean ret;
+  ClutterPoint current;
 
+  clutter_input_device_get_coords (device, NULL, &current);
+
+  barrier_manager = meta_barrier_manager_get ();
   monitor_manager = meta_monitor_manager_get ();
   monitors = meta_monitor_manager_get_monitor_infos (monitor_manager, &n_monitors);
 
+  meta_barrier_manager_constrain_cursor (barrier_manager, time,
+                                        current.x, current.y,
+                                        new_x, new_y);
+
   /* if we're moving inside a monitor, we're fine */
   ret = check_all_screen_monitors(monitors, n_monitors, *new_x, *new_y);
-  if (ret == TRUE)
+  if (ret)
     return;
 
   /* if we're trying to escape, clamp to the CRTC we're coming from */
-  constrain_all_screen_monitors(device, monitors, n_monitors, new_x, new_y);
+  constrain_all_screen_monitors(device, monitors, n_monitors,
+                               current.x, current.y,
+                               new_x, new_y);
 }
 
 void


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