Commit 8e1d5f98 authored by Carlos Garnacho's avatar Carlos Garnacho

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.
parent c49ac323
......@@ -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;
}
......@@ -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__ */
......@@ -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,44 +4182,68 @@ _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,
......@@ -4193,11 +4251,34 @@ gtk_widget_real_sequence_state_changed (GtkWidget *widget,
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment