diff options
-rw-r--r-- | gtk/gtkgesture.c | 37 | ||||
-rw-r--r-- | gtk/gtkgestureprivate.h | 4 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 126 |
3 files changed, 145 insertions, 22 deletions
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c index 0f0fb9a84e..c6bd6583c2 100644 --- a/gtk/gtkgesture.c +++ b/gtk/gtkgesture.c @@ -1161,3 +1161,40 @@ _gtk_gesture_handled_sequence_press (GtkGesture *gesture, return data->press_handled; } + +gboolean +_gtk_gesture_get_pointer_emulating_sequence (GtkGesture *gesture, + GdkEventSequence **sequence) +{ + GtkGesturePrivate *priv; + GdkEventSequence *seq; + GHashTableIter iter; + PointData *data; + + g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE); + + priv = gtk_gesture_get_instance_private (gesture); + g_hash_table_iter_init (&iter, priv->points); + + while (g_hash_table_iter_next (&iter, (gpointer*) &seq, (gpointer*) &data)) + { + switch (data->event->type) + { + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + if (!data->event->touch.emulating_pointer) + continue; + /* Fall through */ + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_MOTION_NOTIFY: + *sequence = seq; + return TRUE; + default: + break; + } + } + + return FALSE; +} diff --git a/gtk/gtkgestureprivate.h b/gtk/gtkgestureprivate.h index d60eaf10d5..ae4a9c44e7 100644 --- a/gtk/gtkgestureprivate.h +++ b/gtk/gtkgestureprivate.h @@ -27,6 +27,10 @@ G_BEGIN_DECLS gboolean _gtk_gesture_handled_sequence_press (GtkGesture *gesture, GdkEventSequence *sequence); +gboolean _gtk_gesture_get_pointer_emulating_sequence + (GtkGesture *gesture, + GdkEventSequence **sequence); + G_END_DECLS #endif /* __GTK_GESTURE_PRIVATE_H__ */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 641965d725..efffd05b88 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4121,26 +4121,60 @@ _gtk_widget_emulate_press (GtkWidget *widget, gdk_event_free (press); } +static const GdkEvent * +_gtk_widget_get_last_event (GtkWidget *widget, + GdkEventSequence *sequence) +{ + GtkWidgetPrivate *priv = widget->priv; + EventControllerData *data; + const GdkEvent *event; + GList *l; + + for (l = priv->event_controllers; l; l = l->next) + { + data = l->data; + event = gtk_gesture_get_last_event (data->controller, sequence); + if (event) + return event; + } + + return NULL; +} + static gboolean _gtk_widget_set_sequence_state_internal (GtkWidget *widget, GdkEventSequence *sequence, - GtkEventSequenceState state) + GtkEventSequenceState state, + gboolean emulates_pointer) { + gboolean retval, sequence_handled, handled = FALSE; GtkWidgetPrivate *priv = widget->priv; - const GdkEvent *mimic_event = NULL; - gboolean retval, handled = FALSE; + const GdkEvent *mimic_event; + gboolean send_event = FALSE; EventControllerData *data; + GdkEventSequence *seq; GList *l; + if (!priv->event_controllers && state != GTK_EVENT_SEQUENCE_CLAIMED) + return TRUE; + + mimic_event = _gtk_widget_get_last_event (widget, sequence); + for (l = priv->event_controllers; l; l = l->next) { + seq = sequence; data = l->data; - if (!GTK_IS_GESTURE (data->controller)) + if (seq && emulates_pointer && + !gtk_gesture_handles_sequence (data->controller, seq)) + seq = NULL; + + if (!gtk_gesture_handles_sequence (data->controller, seq)) continue; - retval = gtk_gesture_set_sequence_state (GTK_GESTURE (data->controller), - sequence, state); + sequence_handled = + _gtk_gesture_handled_sequence_press (data->controller, seq); + retval = gtk_gesture_set_sequence_state (data->controller, seq, state); handled |= retval; /* If the sequence goes denied, check whether this is a controller attached @@ -4148,56 +4182,103 @@ _gtk_widget_set_sequence_state_internal (GtkWidget *widget, * it was consumed), the corresponding press will be emulated for widgets * beneath, so the widgets beneath get a coherent stream of events from now on. */ - if (retval && !mimic_event && + if (retval && sequence_handled && data->propagation_phase == GTK_PHASE_CAPTURE && - state == GTK_EVENT_SEQUENCE_DENIED && - _gtk_gesture_handled_sequence_press (GTK_GESTURE (data->controller), - sequence)) - mimic_event = gtk_gesture_get_last_event (GTK_GESTURE (data->controller), - sequence); + state == GTK_EVENT_SEQUENCE_DENIED) + send_event = TRUE; } - if (mimic_event) + if (send_event && mimic_event) _gtk_widget_emulate_press (widget, mimic_event); return handled; } static gboolean -_gtk_widget_cancel_sequence (GtkWidget *widget, - GdkEventSequence *sequence) +_gtk_widget_cancel_sequence (GtkWidget *widget, + GdkEventSequence *sequence, + gboolean emulates_pointer) { GtkWidgetPrivate *priv = widget->priv; EventControllerData *data; gboolean handled = FALSE; + GdkEventSequence *seq; GList *l; for (l = priv->event_controllers; l; l = l->next) { + seq = sequence; data = l->data; - if (!GTK_IS_GESTURE (data->controller)) + if (seq && emulates_pointer && + !gtk_gesture_handles_sequence (data->controller, seq)) + seq = NULL; + + if (!gtk_gesture_handles_sequence (data->controller, seq)) continue; - handled |= gtk_gesture_cancel_sequence (GTK_GESTURE (data->controller), - sequence); + handled |= + gtk_gesture_cancel_sequence (data->controller, seq); } return handled; } static gboolean +_gtk_widget_get_emulating_sequence (GtkWidget *widget, + GdkEventSequence **sequence) +{ + GtkWidgetPrivate *priv = widget->priv; + EventControllerData *data; + GList *l; + + for (l = priv->event_controllers; l; l = l->next) + { + data = l->data; + + if (_gtk_gesture_get_pointer_emulating_sequence (data->controller, + sequence)) + return TRUE; + } + + return FALSE; +} + +static gboolean gtk_widget_real_sequence_state_changed (GtkWidget *widget, GtkWidget *changed_widget, GdkEventSequence *sequence, GtkEventSequenceState state) { GtkEventSequenceState changed_state; + gboolean emulates_pointer = FALSE; + const GdkEvent *last_event; + + if (!sequence) + { + if (!_gtk_widget_get_emulating_sequence (widget, &sequence)) + return FALSE; + } + else + { + last_event = _gtk_widget_get_last_event (changed_widget, sequence); + + if (!last_event) + return FALSE; + + if ((last_event->type == GDK_TOUCH_BEGIN || + last_event->type == GDK_TOUCH_UPDATE || + last_event->type == GDK_TOUCH_END) && + last_event->touch.emulating_pointer) + emulates_pointer = TRUE; + } 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); + return _gtk_widget_set_sequence_state_internal (widget, sequence, + state, emulates_pointer); + else if (state == GTK_EVENT_SEQUENCE_CLAIMED && + gtk_widget_is_ancestor (widget, changed_widget)) + return _gtk_widget_cancel_sequence (widget, sequence, emulates_pointer); else { changed_state = gtk_widget_get_sequence_state (changed_widget, sequence); @@ -4205,7 +4286,8 @@ gtk_widget_real_sequence_state_changed (GtkWidget *widget, 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); + GTK_EVENT_SEQUENCE_DENIED, + emulates_pointer); } return FALSE; |