summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkgesture.c63
-rw-r--r--gtk/gtkgesture.h7
-rw-r--r--gtk/gtkwidget.c124
3 files changed, 176 insertions, 18 deletions
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c
index 27cc1f5670..e86e6d4f0b 100644
--- a/gtk/gtkgesture.c
+++ b/gtk/gtkgesture.c
@@ -37,6 +37,7 @@ enum {
BEGIN,
END,
UPDATE,
+ CANCEL,
SEQUENCE_STATE_CHANGED,
N_SIGNALS
};
@@ -403,6 +404,13 @@ gtk_gesture_class_init (GtkGestureClass *klass)
G_STRUCT_OFFSET (GtkGestureClass, update),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[CANCEL] =
+ g_signal_new ("cancel",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkGestureClass, cancel),
+ 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),
@@ -505,9 +513,20 @@ gtk_gesture_get_sequence_state (GtkGesture *gesture,
* @sequence: a #GdkEventSequence
* @state: the sequence state
*
- * Sets the state of @sequence in @gesture.
+ * Sets the state of @sequence in @gesture. Sequences start
+ * in state #GTK_EVENT_SEQUENCE_NONE, and whenever they change
+ * state, they can never go back to that state. Likewise,
+ * sequences in state #GTK_EVENT_SEQUENCE_DENIED cannot turn
+ * back to a not denied state. With these rules, the lifetime
+ * of an event sequence is constrained to the next four:
*
- * Returns: #TRUE if @sequence is handled by @gesture.
+ * * None
+ * * None → Denied
+ * * None → Claimed
+ * * None → Claimed → Denied
+ *
+ * Returns: #TRUE if @sequence is handled by @gesture,
+ * and the state is changed successfully.
*
* Since: 3.14
**/
@@ -530,6 +549,15 @@ gtk_gesture_set_sequence_state (GtkGesture *gesture,
if (!data || data->state == state)
return FALSE;
+ /* denied sequences remain denied */
+ if (data->state == GTK_EVENT_SEQUENCE_DENIED)
+ return FALSE;
+
+ /* Sequences can't go from claimed/denied to none */
+ if (state == GTK_EVENT_SEQUENCE_NONE &&
+ data->state != GTK_EVENT_SEQUENCE_NONE)
+ return FALSE;
+
old_state = data->state;
data->state = state;
g_signal_emit (gesture, signals[SEQUENCE_STATE_CHANGED], 0,
@@ -962,3 +990,34 @@ gtk_gesture_handles_sequence (GtkGesture *gesture,
return g_hash_table_contains (priv->points, sequence);
}
+
+/**
+ * gtk_gesture_cancel_sequence:
+ * @gesture: a #GtkGesture
+ * @sequence: a #GdkEventSequence
+ *
+ * Cancels @sequence on @gesture, this emits #GtkGesture::cancel
+ * and forgets the sequence altogether.
+ *
+ * Returns: #TRUE if the sequence was being handled by gesture
+ **/
+gboolean
+gtk_gesture_cancel_sequence (GtkGesture *gesture,
+ GdkEventSequence *sequence)
+{
+ GtkGesturePrivate *priv;
+ PointData *data;
+
+ g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
+
+ priv = gtk_gesture_get_instance_private (gesture);
+ data = g_hash_table_lookup (priv->points, sequence);
+
+ if (!data)
+ return FALSE;
+
+ g_signal_emit (gesture, signals[CANCEL], 0, sequence);
+ _gtk_gesture_check_recognized (gesture, sequence);
+ _gtk_gesture_remove_point (gesture, data->event);
+ return TRUE;
+}
diff --git a/gtk/gtkgesture.h b/gtk/gtkgesture.h
index a9296c73fa..1d28000987 100644
--- a/gtk/gtkgesture.h
+++ b/gtk/gtkgesture.h
@@ -57,6 +57,9 @@ struct _GtkGestureClass
void (* end) (GtkGesture *gesture,
GdkEventSequence *sequence);
+ void (* cancel) (GtkGesture *gesture,
+ GdkEventSequence *sequence);
+
void (* sequence_state_changed) (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state);
@@ -89,7 +92,9 @@ GdkEventSequence * gtk_gesture_get_last_updated_sequence
GDK_AVAILABLE_IN_3_14
gboolean gtk_gesture_handles_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
-
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_gesture_cancel_sequence (GtkGesture *gesture,
+ GdkEventSequence *sequence);
GDK_AVAILABLE_IN_3_14
const GdkEvent *
gtk_gesture_get_last_event (GtkGesture *gesture,
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index b10f4ac619..13cbf3bb1c 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -592,6 +592,7 @@ enum {
DRAG_FAILED,
STYLE_UPDATED,
TOUCH_EVENT,
+ SEQUENCE_STATE_CHANGED,
LAST_SIGNAL
};
@@ -3427,6 +3428,14 @@ G_GNUC_END_IGNORE_DEPRECATIONS
_gtk_marshal_BOOLEAN__UINT,
G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
+ widget_signals[SEQUENCE_STATE_CHANGED] =
+ g_signal_new (I_("sequence-state-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0,
+ g_signal_accumulator_first_wins, NULL, NULL,
+ G_TYPE_BOOLEAN, 3, GTK_TYPE_WIDGET,
+ G_TYPE_POINTER, GTK_TYPE_EVENT_SEQUENCE_STATE);
+
binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK,
"popup-menu", 0);
@@ -4035,6 +4044,78 @@ gtk_widget_get_property (GObject *object,
}
}
+static gboolean
+_gtk_widget_set_sequence_state_internal (GtkWidget *widget,
+ GdkEventSequence *sequence,
+ GtkEventSequenceState state)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+ EventControllerData *data;
+ gboolean handled = FALSE;
+ GList *l;
+
+ for (l = priv->event_controllers; l; l = l->next)
+ {
+ data = l->data;
+
+ if (!GTK_IS_GESTURE (data->controller))
+ continue;
+
+ handled |= gtk_gesture_set_sequence_state (GTK_GESTURE (data->controller),
+ sequence, state);
+ }
+
+ return handled;
+}
+
+static gboolean
+_gtk_widget_cancel_sequence (GtkWidget *widget,
+ GdkEventSequence *sequence)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+ EventControllerData *data;
+ gboolean handled = FALSE;
+ GList *l;
+
+ for (l = priv->event_controllers; l; l = l->next)
+ {
+ data = l->data;
+
+ if (!GTK_IS_GESTURE (data->controller))
+ continue;
+
+ handled |= gtk_gesture_cancel_sequence (GTK_GESTURE (data->controller),
+ sequence);
+ }
+
+ return handled;
+}
+
+static gboolean
+gtk_widget_real_sequence_state_changed (GtkWidget *widget,
+ GtkWidget *changed_widget,
+ GdkEventSequence *sequence,
+ GtkEventSequenceState state)
+{
+ GtkEventSequenceState changed_state;
+
+ if (widget == changed_widget)
+ return _gtk_widget_set_sequence_state_internal (widget, sequence, state);
+ else if (gtk_widget_is_ancestor (widget, changed_widget))
+ return _gtk_widget_cancel_sequence (widget, sequence);
+ else
+ {
+ changed_state = gtk_widget_get_sequence_state (changed_widget, sequence);
+
+ if (state == GTK_EVENT_SEQUENCE_CLAIMED &&
+ changed_state == GTK_EVENT_SEQUENCE_CLAIMED)
+ return _gtk_widget_set_sequence_state_internal (widget, sequence,
+ GTK_EVENT_SEQUENCE_DENIED);
+ }
+
+ return FALSE;
+}
+
static void
gtk_widget_init (GtkWidget *widget)
{
@@ -4092,6 +4173,10 @@ gtk_widget_init (GtkWidget *widget)
priv->style = gtk_widget_get_default_style ();
G_GNUC_END_IGNORE_DEPRECATIONS;
g_object_ref (priv->style);
+
+ g_signal_connect (widget, "sequence-state-changed",
+ G_CALLBACK (gtk_widget_real_sequence_state_changed),
+ NULL);
}
@@ -16487,27 +16572,36 @@ gtk_widget_set_sequence_state (GtkWidget *widget,
{
EventControllerData *data;
gboolean handled = FALSE;
+ GtkWidget *event_widget;
GtkWidgetPrivate *priv;
- GList *l;
-
- g_return_val_if_fail (GTK_IS_WIDGET (widget),
- GTK_EVENT_SEQUENCE_NONE);
+ const GdkEvent *event;
- priv = widget->priv;
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (state >= GTK_EVENT_SEQUENCE_NONE &&
+ state <= GTK_EVENT_SEQUENCE_DENIED);
- for (l = priv->event_controllers; l; l = l->next)
- {
- data = l->data;
+ g_signal_emit (widget, widget_signals[SEQUENCE_STATE_CHANGED],
+ 0, widget, sequence, state, &handled);
- if (!GTK_IS_GESTURE (data->controller))
- continue;
+ if (!handled)
+ return;
- handled |= gtk_gesture_set_sequence_state (GTK_GESTURE (data->controller),
- sequence, state);
- }
+ priv = widget->priv;
+ data = priv->event_controllers->data;
+ event = gtk_gesture_get_last_event (GTK_GESTURE (data->controller), sequence);
- if (!handled)
+ if (!event)
return;
- /* FIXME: Propagate upwards/downwards */
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+ g_assert (widget == event_widget ||
+ gtk_widget_is_ancestor (event_widget, widget));
+
+ while (event_widget)
+ {
+ if (event_widget != widget)
+ g_signal_emit (event_widget, widget_signals[SEQUENCE_STATE_CHANGED],
+ 0, widget, sequence, state, &handled);
+ event_widget = gtk_widget_get_parent (event_widget);
+ }
}