[gtk+/gestures: 48/117] widget: Improve button press emulation on sequence denied
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gestures: 48/117] widget: Improve button press emulation on sequence denied
- Date: Thu, 10 Apr 2014 20:28:44 +0000 (UTC)
commit 92f7d0166eb0b01106f026631fd830ead1e7cdc8
Author: Carlos Garnacho <carlosg gnome org>
Date: Wed Mar 26 10:25:09 2014 +0100
widget: Improve button press emulation on sequence denied
Ensure that state being set on pointer emulating touches actually
gets propagated properly on widgets with gestures that only handle
pointer events.
gtk/gtkgesture.c | 37 ++++++++++++++
gtk/gtkgestureprivate.h | 4 ++
gtk/gtkwidget.c | 126 ++++++++++++++++++++++++++++++++++++++--------
3 files changed, 145 insertions(+), 22 deletions(-)
---
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c
index 0f0fb9a..c6bd658 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 d60eaf1..ae4a9c4 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 6da5e38..7c8c28b 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4086,26 +4086,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
@@ -4113,56 +4147,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);
@@ -4170,7 +4251,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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]