diff options
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkgesture.c | 63 | ||||
-rw-r--r-- | gtk/gtkgesture.h | 7 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 124 |
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); + } } |