[gtk+/gestures: 3/16] Add GtkGesture
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gestures: 3/16] Add GtkGesture
- Date: Thu, 27 Feb 2014 17:35:58 +0000 (UTC)
commit c6dda2e5cff24e244600e9fac30d9e196a515810
Author: Carlos Garnacho <carlosg gnome org>
Date: Thu Jan 17 20:59:07 2013 +0100
Add GtkGesture
This a more specific abstract type that handles one or multiple
streams of pointer/touch events.
gtk/Makefile.am | 2 +
gtk/gtk.h | 1 +
gtk/gtkenums.h | 7 +
gtk/gtkgesture.c | 921 ++++++++++++++++++++++++++++++++++++++++++++++++
gtk/gtkgesture.h | 130 +++++++
gtk/gtkmarshalers.list | 1 +
6 files changed, 1062 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 4823cbd..90db345 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -257,6 +257,7 @@ gtk_public_h_sources = \
gtkfontchooserdialog.h \
gtkfontchooserwidget.h \
gtkframe.h \
+ gtkgesture.h \
gtkgrid.h \
gtkheaderbar.h \
gtkicontheme.h \
@@ -741,6 +742,7 @@ gtk_base_c_sources = \
gtkfontchooserwidget.c \
gtkframe.c \
gtkgladecatalog.c \
+ gtkgesture.c \
gtkgrid.c \
gtkheaderbar.c \
gtkhsla.c \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 1b74eaf..f1a60ef 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -107,6 +107,7 @@
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkframe.h>
+#include <gtk/gtkgesture.h>
#include <gtk/gtkgrid.h>
#include <gtk/gtkheaderbar.h>
#include <gtk/gtkicontheme.h>
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 48414b8..74ff8e0 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -1266,4 +1266,11 @@ typedef enum
GTK_INPUT_HINT_INHIBIT_OSK = 1 << 7
} GtkInputHints;
+typedef enum
+{
+ GTK_EVENT_SEQUENCE_NONE,
+ GTK_EVENT_SEQUENCE_CLAIMED,
+ GTK_EVENT_SEQUENCE_DENIED
+} GtkEventSequenceState;
+
#endif /* __GTK_ENUMS_H__ */
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c
new file mode 100644
index 0000000..2dfc601
--- /dev/null
+++ b/gtk/gtkgesture.c
@@ -0,0 +1,921 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2012, One Laptop Per Child.
+ * Copyright (C) 2014, Red Hat, Inc.
+ *
+ * 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 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg gnome org>
+ */
+#include "config.h"
+#include <gtk/gtkgesture.h>
+#include "gtktypebuiltins.h"
+#include "gtkprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+
+typedef struct _GtkGesturePrivate GtkGesturePrivate;
+typedef struct _PointData PointData;
+
+enum {
+ PROP_N_POINTS = 1,
+ PROP_TOUCH_ONLY,
+};
+
+enum {
+ CHECK,
+ BEGIN,
+ END,
+ UPDATE,
+ SEQUENCE_STATE_CHANGED,
+ N_SIGNALS
+};
+
+struct _PointData
+{
+ GdkEvent *event;
+ guint state : 2;
+};
+
+struct _GtkGesturePrivate
+{
+ GHashTable *points;
+ GdkEventSequence *last_sequence;
+ GdkWindow *window;
+ GdkDevice *device;
+ guint n_points;
+ guint recognized : 1;
+ guint touch_only : 1;
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+#define BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkGesture, gtk_gesture, GTK_TYPE_EVENT_CONTROLLER)
+
+static void
+gtk_gesture_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkGesturePrivate *priv = gtk_gesture_get_instance_private (GTK_GESTURE (object));
+
+ switch (prop_id)
+ {
+ case PROP_N_POINTS:
+ g_value_set_uint (value, priv->n_points);
+ break;
+ case PROP_TOUCH_ONLY:
+ g_value_set_boolean (value, priv->touch_only);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_gesture_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkGesturePrivate *priv = gtk_gesture_get_instance_private (GTK_GESTURE (object));
+
+ switch (prop_id)
+ {
+ case PROP_N_POINTS:
+ priv->n_points = g_value_get_uint (value);
+ break;
+ case PROP_TOUCH_ONLY:
+ gtk_gesture_set_touch_only (GTK_GESTURE (object),
+ g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_gesture_finalize (GObject *object)
+{
+ GtkGesturePrivate *priv = gtk_gesture_get_instance_private (GTK_GESTURE (object));
+
+ g_hash_table_destroy (priv->points);
+
+ G_OBJECT_CLASS (gtk_gesture_parent_class)->finalize (object);
+}
+
+static guint
+_gtk_gesture_effective_n_points (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+ GHashTableIter iter;
+ guint n_points = 0;
+ PointData *data;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ g_hash_table_iter_init (&iter, priv->points);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
+ {
+ if (data->state == GTK_EVENT_SEQUENCE_DENIED)
+ continue;
+ if (data->event->type == GDK_TOUCH_END ||
+ data->event->type == GDK_BUTTON_RELEASE)
+ continue;
+
+ n_points++;
+ }
+
+ return n_points;
+}
+
+static gboolean
+gtk_gesture_check_impl (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+ guint n_points;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ n_points = _gtk_gesture_effective_n_points (gesture);
+
+ return n_points == priv->n_points;
+}
+
+static void
+_gtk_gesture_set_recognized (GtkGesture *gesture,
+ gboolean recognized,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ if (priv->recognized == recognized)
+ return;
+
+ priv->recognized = recognized;
+
+ if (recognized)
+ g_signal_emit (gesture, signals[BEGIN], 0, sequence);
+ else
+ g_signal_emit (gesture, signals[END], 0, sequence);
+}
+
+static gboolean
+_gtk_gesture_do_check (GtkGesture *gesture)
+{
+ gboolean retval;
+
+ g_signal_emit (G_OBJECT (gesture), signals[CHECK], 0, &retval);
+ retval = retval != FALSE;
+
+ return retval;
+}
+
+static gboolean
+_gtk_gesture_check_recognized (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv = gtk_gesture_get_instance_private (gesture);
+ guint current_n_points;
+
+ current_n_points = _gtk_gesture_effective_n_points (gesture);
+
+ if (priv->recognized && current_n_points != priv->n_points)
+ _gtk_gesture_set_recognized (gesture, FALSE, sequence);
+ else if (!priv->recognized &&
+ current_n_points == priv->n_points &&
+ _gtk_gesture_do_check (gesture))
+ _gtk_gesture_set_recognized (gesture, TRUE, sequence);
+
+ return priv->recognized;
+}
+
+static gboolean
+_gtk_gesture_update_point (GtkGesture *gesture,
+ const GdkEvent *event,
+ gboolean add)
+{
+ GdkEventSequence *sequence;
+ GtkGesturePrivate *priv;
+ GdkDevice *device;
+ PointData *data;
+ gdouble x, y;
+
+ if (!gdk_event_get_coords (event, &x, &y))
+ return FALSE;
+
+ device = gdk_event_get_device (event);
+
+ if (!device)
+ return FALSE;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ if (priv->device && priv->device != device)
+ return FALSE;
+
+ sequence = gdk_event_get_event_sequence (event);
+
+ if (!g_hash_table_lookup_extended (priv->points, sequence,
+ NULL, (gpointer *) &data))
+ {
+ if (!add)
+ return FALSE;
+
+ if (g_hash_table_size (priv->points) == 0)
+ {
+ priv->window = event->any.window;
+ priv->device = device;
+ }
+
+ data = g_new0 (PointData, 1);
+ g_hash_table_insert (priv->points, sequence, data);
+ }
+
+ if (data->event)
+ gdk_event_free (data->event);
+
+ data->event = gdk_event_copy (event);
+
+ return TRUE;
+}
+
+static void
+_gtk_gesture_remove_point (GtkGesture *gesture,
+ const GdkEvent *event)
+{
+ GdkEventSequence *sequence;
+ GtkGesturePrivate *priv;
+ GdkDevice *device;
+
+ sequence = gdk_event_get_event_sequence (event);
+ device = gdk_event_get_device (event);
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ g_hash_table_remove (priv->points, sequence);
+
+ if (device == priv->device &&
+ g_hash_table_size (priv->points) == 0)
+ {
+ priv->window = NULL;
+ priv->device = NULL;
+ }
+}
+
+static gboolean
+gtk_gesture_handle_event (GtkEventController *controller,
+ const GdkEvent *event)
+{
+ GtkGesture *gesture = GTK_GESTURE (controller);
+ GdkEventSequence *sequence;
+ GtkGesturePrivate *priv;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ sequence = gdk_event_get_event_sequence (event);
+ priv->last_sequence = sequence;
+
+#if 0
+ if (event->any.window != priv->window)
+ return FALSE;
+#endif
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ if (priv->touch_only)
+ break;
+ /* Fall through */
+ case GDK_TOUCH_BEGIN:
+ if (_gtk_gesture_update_point (gesture, event, TRUE))
+ _gtk_gesture_check_recognized (gesture, sequence);
+ //g_signal_emit (gesture, signals[UPDATE], 0, sequence);
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (priv->touch_only)
+ break;
+ /* Fall through */
+ case GDK_TOUCH_END:
+ if (_gtk_gesture_update_point (gesture, event, FALSE))
+ {
+ if (_gtk_gesture_check_recognized (gesture, sequence))
+ g_signal_emit (gesture, signals[UPDATE], 0, sequence);
+
+ _gtk_gesture_remove_point (gesture, event);
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (priv->touch_only)
+ break;
+ if ((event->motion.state & BUTTONS_MASK) == 0)
+ break;
+
+ if (event->motion.is_hint)
+ gdk_event_request_motions (&event->motion);
+
+ /* Fall through */
+ case GDK_TOUCH_UPDATE:
+ if (_gtk_gesture_update_point (gesture, event, TRUE) &&
+ _gtk_gesture_check_recognized (gesture, sequence))
+ g_signal_emit (gesture, signals[UPDATE], 0, sequence);
+ break;
+ default:
+ break;
+ }
+
+ if (gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_CLAIMED)
+ return FALSE;
+
+ return priv->recognized;
+}
+
+static void
+gtk_gesture_class_init (GtkGestureClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
+
+ object_class->get_property = gtk_gesture_get_property;
+ object_class->set_property = gtk_gesture_set_property;
+ object_class->finalize = gtk_gesture_finalize;
+
+ controller_class->handle_event = gtk_gesture_handle_event;
+
+ klass->check = gtk_gesture_check_impl;
+
+ g_object_class_install_property (object_class,
+ PROP_N_POINTS,
+ g_param_spec_uint ("n-points",
+ P_("Number of points"),
+ P_("Number of points needed "
+ "to trigger the gesture"),
+ 1, G_MAXUINT, 1,
+ GTK_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_TOUCH_ONLY,
+ g_param_spec_boolean ("touch-only",
+ P_("Handle only touch events"),
+ P_("Whether the gesture handles"
+ " only touch events"),
+ TRUE,
+ GTK_PARAM_READWRITE));
+
+ signals[CHECK] =
+ g_signal_new ("check",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, check),
+ g_signal_accumulator_true_handled,
+ NULL, NULL,
+ G_TYPE_BOOLEAN, 0);
+ signals[BEGIN] =
+ g_signal_new ("begin",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, begin),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[END] =
+ g_signal_new ("end",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, end),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[UPDATE] =
+ g_signal_new ("update",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, update),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[SEQUENCE_STATE_CHANGED] =
+ g_signal_new ("sequence-state-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, sequence_state_changed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_POINTER,
+ GTK_TYPE_EVENT_SEQUENCE_STATE);
+}
+
+static void
+gtk_gesture_init (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ priv->points = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) g_free);
+
+ if (g_getenv ("GTK_TEST_TOUCHSCREEN"))
+ priv->touch_only = FALSE;
+ else
+ priv->touch_only = TRUE;
+}
+
+/**
+ * gtk_gesture_get_device:
+ * @gesture: a #GtkGesture
+ *
+ * Returns the master #GdkDevice that is currently operating
+ * on @gesture, or %NULL if the gesture is not being interacted.
+ *
+ * Returns: a #GdkDevice, or %NULL.
+ *
+ * Since: 3.14
+ **/
+GdkDevice *
+gtk_gesture_get_device (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return priv->device;
+}
+
+/**
+ * gtk_gesture_get_sequence_state:
+ * @gesture: a #GtkGesture
+ * @sequence: a #GdkEventSequence
+ *
+ * Returns the @sequence state, as seen by @gesture.
+ *
+ * Returns: The sequence state in @gesture.
+ *
+ * Since: 3.14
+ **/
+GtkEventSequenceState
+gtk_gesture_get_sequence_state (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture),
+ GTK_EVENT_SEQUENCE_NONE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ data = g_hash_table_lookup (priv->points, sequence);
+
+ if (!data)
+ return GTK_EVENT_SEQUENCE_NONE;
+
+ return data->state;
+}
+
+/**
+ * gtk_gesture_set_sequence_state:
+ * @gesture: a #GtkGesture
+ * @sequence: a #GdkEventSequence
+ * @state: the sequence state
+ *
+ * Sets the state of @sequence in @gesture.
+ *
+ * Returns: #TRUE if @sequence is handled by @gesture.
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_set_sequence_state (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ GtkEventSequenceState state)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+ guint old_state;
+
+ g_return_if_fail (GTK_IS_GESTURE (gesture));
+ g_return_if_fail (state >= GTK_EVENT_SEQUENCE_NONE &&
+ state <= GTK_EVENT_SEQUENCE_DENIED);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ data = g_hash_table_lookup (priv->points, sequence);
+
+ if (!data || data->state == state)
+ return FALSE;
+
+ old_state = data->state;
+ data->state = state;
+ g_signal_emit (gesture, signals[SEQUENCE_STATE_CHANGED], 0,
+ sequence, old_state);
+ return TRUE;
+}
+
+/**
+ * gtk_gesture_get_sequences:
+ * @gesture: a #GtkGesture
+ *
+ * Returns the list of #GdkEventSequence<!-- -->s currently being interpreted
+ * by @gesture
+ *
+ * Returns: (transfer container) (element-type:Gdk.EventSequence): A list
+ * of #GdkEventSequence<!-- -->s, the list elements are owned by GTK+
+ * and must not be freed or modified, the list itself must be deleted
+ * through g_list_free()
+ **/
+GList *
+gtk_gesture_get_sequences (GtkGesture *gesture)
+{
+ GdkEventSequence *sequence;
+ GtkGesturePrivate *priv;
+ GList *sequences = NULL;
+ GHashTableIter iter;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ g_hash_table_iter_init (&iter, priv->points);
+
+ while (g_hash_table_iter_next (&iter, (gpointer *) &sequence, (gpointer *) &data))
+ {
+ if (data->state == GTK_EVENT_SEQUENCE_DENIED)
+ continue;
+ if (data->event->type == GDK_TOUCH_END ||
+ data->event->type == GDK_BUTTON_RELEASE)
+ continue;
+
+ sequences = g_list_prepend (sequences, sequence);
+ }
+
+ return sequences;
+}
+
+/**
+ * gtk_gesture_get_last_updated_sequence:
+ * @gesture: a #GtkGesture
+ *
+ * Returns the #GdkEventSequence that was last updated on @gesture.
+ *
+ * Returns: The last updated sequence.
+ *
+ * Since: 3.14
+ **/
+GdkEventSequence *
+gtk_gesture_get_last_updated_sequence (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return priv->last_sequence;
+}
+
+const GdkEvent *
+gtk_gesture_get_last_event (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), NULL);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ data = g_hash_table_lookup (priv->points, sequence);
+
+ if (!data)
+ return NULL;
+
+ return data->event;
+}
+
+/**
+ * gtk_gesture_get_point:
+ * @gesture: a #GtkGesture
+ * @sequence: (allow-none): a #GdkEventSequence, or %NULL for pointer events
+ * @x: (out) (allow-none): return location for X axis of the sequence coordinates
+ * @y: (out) (allow-none): return location for Y axis of the sequence coordinates
+ *
+ * If @sequence is currently being interpreted by @gesture, this
+ * function returns %TRUE and fills in @x and @y with the last coordinates
+ * stored for that event sequence.
+ *
+ * Returns: %TRUE if @sequence is currently interpreted
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_get_point (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ gdouble *x,
+ gdouble *y)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ if (!g_hash_table_lookup_extended (priv->points, sequence,
+ NULL, (gpointer *) &data))
+ return FALSE;
+
+ return gdk_event_get_coords (data->event, x, y);
+}
+
+/**
+ * gtk_gesture_get_last_update_time:
+ * @gesture: a #GtkGesture
+ * @sequence: (allow-none): a #GdkEventSequence, or %NULL for pointer events
+ * @evtime: (out) (allow-none): return location for last update time
+ *
+ * If @sequence is being interpreted by @gesture, this function
+ * returns %TRUE and fills @evtime with the last event time it
+ * received from that @sequence.
+ *
+ * Returns: %TRUE if @sequence is currently interpreted
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_get_last_update_time (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ guint32 *evtime)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ if (!g_hash_table_lookup_extended (priv->points, sequence,
+ NULL, (gpointer *) &data))
+ return FALSE;
+
+ if (evtime)
+ *evtime = gdk_event_get_time (data->event);
+
+ return TRUE;
+};
+
+/**
+ * gtk_gesture_get_last_event_type:
+ * @gesture: a #GtkGesture
+ * @sequence: a #GdkEventSequence
+ *
+ * Returns the last event type that was processed for @sequence.
+ *
+ * Returns: the last event type.
+ *
+ * Since: 3.14
+ **/
+GdkEventType
+gtk_gesture_get_last_event_type (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), GDK_NOTHING);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ if (!g_hash_table_lookup_extended (priv->points, sequence,
+ NULL, (gpointer *) &data))
+ return GDK_NOTHING;
+
+ return data->event->type;
+}
+
+/**
+ * gtk_gesture_get_bounding_box:
+ * @gesture: a #GtkGesture
+ * @rect: (out): bounding box containing all active touches.
+ *
+ * If there are touch sequences being currently handled by @gesture,
+ * this function returns #TRUE and fills in @rect with the bounding
+ * box containing all active touches. Otherwise, #FALSE will be
+ * returned.
+ *
+ * Returns: #TRUE if there are active touches, #FALSE otherwise
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_get_bounding_box (GtkGesture *gesture,
+ GdkRectangle *rect)
+{
+ GtkGesturePrivate *priv;
+ gdouble x1, y1, x2, y2;
+ GHashTableIter iter;
+ guint n_points = 0;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+ g_return_val_if_fail (rect != NULL, FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ x1 = y1 = G_MAXDOUBLE;
+ x2 = y2 = -G_MAXDOUBLE;
+
+ g_hash_table_iter_init (&iter, priv->points);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
+ {
+ gdouble x, y;
+
+ if (data->state == GTK_EVENT_SEQUENCE_DENIED)
+ continue;
+ if (data->event->type == GDK_TOUCH_END ||
+ data->event->type == GDK_BUTTON_RELEASE)
+ continue;
+
+ gdk_event_get_coords (data->event, &x, &y);
+ n_points++;
+ x1 = MIN (x1, x);
+ y1 = MIN (y1, y);
+ x2 = MAX (x2, x);
+ y2 = MAX (y2, y);
+ }
+
+ if (n_points == 0)
+ return FALSE;
+
+ rect->x = x1;
+ rect->y = y1;
+ rect->width = x2 - x1;
+ rect->height = y2 - y1;
+
+ return TRUE;
+}
+
+
+/**
+ * gtk_gesture_get_bounding_box_center:
+ * @gesture: a #GtkGesture
+ * @x: (out): X coordinate for the bounding box center
+ * @y: (out): Y coordinate for the bounding box center
+ *
+ * If there are touch sequences being currently handled by @gesture,
+ * this function returns #TRUE and fills in @x and @y with the center
+ * of the bounding box containing all active touches. Otherwise, #FALSE
+ * will be returned.
+ *
+ * Returns: #FALSE if no active touches are present, #TRUE otherwise
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_get_bounding_box_center (GtkGesture *gesture,
+ gdouble *x,
+ gdouble *y)
+{
+ GdkRectangle rect;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+ g_return_val_if_fail (x != NULL && y != NULL, FALSE);
+
+ if (!gtk_gesture_get_bounding_box (gesture, &rect))
+ return FALSE;
+
+ *x = rect.x + rect.width / 2;
+ *y = rect.y + rect.height / 2;
+ return TRUE;
+}
+
+/**
+ * gtk_gesture_is_active:
+ * @gesture: a #GtkGesture
+ *
+ * Returns %TRUE if the gesture is currently active.
+ * A gesture is active if there are as many interacting
+ * touch sequences as required by @gesture, and @gesture
+ * is interpreting those to potentially trigger an action.
+ *
+ * Returns: %TRUE if gesture is active.
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_is_active (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return priv->recognized;
+}
+
+/**
+ * gtk_gesture_check:
+ * @gesture: a #GtkGesture
+ *
+ * Triggers a check on the @gesture, this should be rarely needed,
+ * as the gesture will check the state after handling any event.
+ *
+ * Returns: #TRUE if the gesture is recognized.
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_check (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return _gtk_gesture_check_recognized (gesture, priv->last_sequence);
+}
+
+/**
+ * gtk_gesture_get_touch_only:
+ * @gesture: a #GtkGesture
+ *
+ * Returns #TRUE if the gesture is only triggered by touch events.
+ *
+ * Returns: #TRUE if the gesture only handles touch events.
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_get_touch_only (GtkGesture *gesture)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return priv->touch_only;
+}
+
+/**
+ * gtk_gesture_set_touch_only:
+ * @gesture: a #GtkGesture
+ * @touch_only: whether @gesture handles only touch events
+ *
+ * If @touch_only is #TRUE, @gesture will only handle events of type
+ * #GDK_TOUCH_BEGIN, #GDK_TOUCH_UPDATE or #GDK_TOUCH_END. If #FALSE,
+ * mouse events will be handled too.
+ *
+ * Since: 3.14
+ **/
+void
+gtk_gesture_set_touch_only (GtkGesture *gesture,
+ gboolean touch_only)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ touch_only = touch_only != FALSE;
+
+ if (priv->touch_only == touch_only)
+ return;
+
+ priv->touch_only = touch_only;
+ g_object_notify (G_OBJECT (gesture), "touch-only");
+}
+
+/**
+ * gtk_gesture_handles_sequence:
+ * @gesture: a #GtkGesture
+ * @sequence: a #GdkEventSequence
+ *
+ * Returns #TRUE if @gesture is currently handling events corresponding to
+ * @sequence.
+ *
+ * Returns: #TRUE if @gesture is handling @sequence.
+ *
+ * Since: 3.14
+ **/
+gboolean
+gtk_gesture_handles_sequence (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+
+ return g_hash_table_contains (priv->points, sequence);
+}
diff --git a/gtk/gtkgesture.h b/gtk/gtkgesture.h
new file mode 100644
index 0000000..31762db
--- /dev/null
+++ b/gtk/gtkgesture.h
@@ -0,0 +1,130 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2012, One Laptop Per Child.
+ * Copyright (C) 2014, Red Hat, Inc.
+ *
+ * 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 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Carlos Garnacho <carlosg gnome org>
+ */
+#ifndef __GTK_GESTURE_H__
+#define __GTK_GESTURE_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkeventcontroller.h>
+#include <gtk/gtkeventcontroller.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_GESTURE (gtk_gesture_get_type ())
+#define GTK_GESTURE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURE, GtkGesture))
+#define GTK_GESTURE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_GESTURE, GtkGestureClass))
+#define GTK_IS_GESTURE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURE))
+#define GTK_IS_GESTURE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_GESTURE))
+#define GTK_GESTURE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURE, GtkGestureClass))
+
+typedef struct _GtkGesture GtkGesture;
+typedef struct _GtkGestureClass GtkGestureClass;
+
+struct _GtkGesture
+{
+ GtkEventController parent_instance;
+};
+
+struct _GtkGestureClass
+{
+ GtkEventControllerClass parent_class;
+
+ gboolean (* check) (GtkGesture *gesture);
+
+ void (* begin) (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+ void (* update) (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+ void (* end) (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+
+ void (* sequence_state_changed) (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ GtkEventSequenceState state);
+
+ /*< private >*/
+ gpointer padding[10];
+};
+
+GDK_AVAILABLE_IN_3_14
+GType gtk_gesture_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_14
+GdkDevice * gtk_gesture_get_device (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+GtkEventSequenceState
+ gtk_gesture_get_sequence_state (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_set_sequence_state (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ GtkEventSequenceState state);
+GDK_AVAILABLE_IN_3_14
+GList * gtk_gesture_get_sequences (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+GdkEventSequence * gtk_gesture_get_last_updated_sequence
+ (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_handles_sequence (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+
+GDK_AVAILABLE_IN_3_14
+const GdkEvent *
+ gtk_gesture_get_last_event (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_get_point (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ gdouble *x,
+ gdouble *y);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_get_last_update_time (GtkGesture *gesture,
+ GdkEventSequence *sequence,
+ guint32 *evtime);
+
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_get_bounding_box (GtkGesture *gesture,
+ GdkRectangle *rect);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_get_bounding_box_center
+ (GtkGesture *gesture,
+ gdouble *x,
+ gdouble *y);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_is_active (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_check (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_get_touch_only (GtkGesture *gesture);
+
+GDK_AVAILABLE_IN_3_14
+void gtk_gesture_set_touch_only (GtkGesture *gesture,
+ gboolean touch_only);
+
+G_END_DECLS
+
+#endif /* __GTK_GESTURE_H__ */
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 31977fe..ab6983d 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -52,6 +52,7 @@ OBJECT:VOID
STRING:DOUBLE
STRING:STRING
VOID:DOUBLE
+VOID:DOUBLE,DOUBLE
VOID:BOOLEAN
VOID:BOOLEAN,BOOLEAN,BOOLEAN
VOID:BOXED
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]