[mutter] barrier: Add support for new barrier features in XInput 2.3
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] barrier: Add support for new barrier features in XInput 2.3
- Date: Fri, 8 Feb 2013 19:26:29 +0000 (UTC)
commit 57c31a56f42d502e72e9af9366da9459df22d98e
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 | 12 ++++
src/core/display.c | 60 ++++++++++++++++-
src/core/screen.c | 10 +++
src/meta/barrier.h | 41 ++++++++++++
src/meta/display.h | 1 +
7 files changed, 278 insertions(+), 3 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..b50a50e 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);
+
+ g_hash_table_insert (priv->display->window_ids, &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));
}
@@ -233,7 +310,10 @@ meta_barrier_destroy (MetaBarrier *barrier)
return;
XFixesDestroyPointerBarrier (dpy, priv->xbarrier);
+ g_hash_table_remove (priv->display->window_ids, &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 = g_hash_table_lookup (display->window_ids, &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..cec849c 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
@@ -449,4 +456,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..334427c 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -590,7 +590,7 @@ meta_display_open (void)
the_display->window_ids = g_hash_table_new (meta_unsigned_long_hash,
meta_unsigned_long_equal);
-
+
i = 0;
while (i < N_IGNORED_CROSSING_SERIALS)
{
@@ -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)
@@ -1001,6 +1009,9 @@ meta_display_list_windows (MetaDisplay *display,
{
MetaWindow *window = value;
+ if (!META_IS_WINDOW (window))
+ continue;
+
if (!window->override_redirect ||
(flags & META_LIST_INCLUDE_OVERRIDE_REDIRECT) != 0)
winlist = g_slist_prepend (winlist, window);
@@ -1832,6 +1843,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 +2412,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 +2950,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 +3230,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)
@@ -5687,6 +5724,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 8ee4470..6d52555 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -758,6 +758,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 |
@@ -1230,6 +1237,9 @@ meta_screen_foreach_window (MetaScreen *screen,
{
MetaWindow *window = tmp->data;
+ if (!META_IS_WINDOW (window))
+ continue;
+
if (window->screen == screen && !window->override_redirect)
(* func) (screen, window, data);
}
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]