widget: Propagate touch/button press events when a sequence is denied

If the captured touch begin or button press event have been consumed
for the given sequence, propagate it upwards if the sequence goes from
claimed to denied, so the widgets on the way to the event widget receive
a coherent event stream now that they're going to receive events.
This commit is contained in:
Carlos Garnacho 2014-03-03 20:47:43 +01:00
parent 83dd050ab2
commit 36106c19d4

View File

@ -66,6 +66,7 @@
#include "gtktypebuiltins.h"
#include "a11y/gtkwidgetaccessible.h"
#include "gtkapplicationprivate.h"
#include "gtkgestureprivate.h"
/* for the use of round() */
#include "fallback-c89.c"
@ -4044,14 +4045,90 @@ gtk_widget_get_property (GObject *object,
}
}
static void
_gtk_widget_emulate_press (GtkWidget *widget,
const GdkEvent *event)
{
GtkWidget *event_widget, *next_child, *parent;
GdkEvent *press;
event_widget = gtk_get_event_widget ((GdkEvent *) event);
if (event_widget == widget)
return;
if (event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_TOUCH_UPDATE ||
event->type == GDK_TOUCH_END)
{
press = gdk_event_copy (event);
press->type = GDK_TOUCH_BEGIN;
}
else if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE)
{
press = gdk_event_copy (event);
press->type = GDK_BUTTON_PRESS;
}
else if (event->type == GDK_MOTION_NOTIFY)
{
press = gdk_event_new (GDK_BUTTON_PRESS);
press->button.window = g_object_ref (event->motion.window);
press->button.time = event->motion.time;
press->button.x = event->motion.x;
press->button.y = event->motion.y;
press->button.x_root = event->motion.x_root;
press->button.y_root = event->motion.y_root;
press->button.state = event->motion.state;
press->button.axes = g_memdup (event->motion.axes,
sizeof (gdouble) *
gdk_device_get_n_axes (event->motion.device));
if (event->motion.state & GDK_BUTTON3_MASK)
press->button.button = 3;
else if (event->motion.state & GDK_BUTTON2_MASK)
press->button.button = 2;
else
{
if ((event->motion.state & GDK_BUTTON1_MASK) == 0)
g_critical ("Guessing button number 1 on generated button press event");
press->button.button = 1;
}
gdk_event_set_device (press, gdk_event_get_device (event));
gdk_event_set_source_device (press, gdk_event_get_source_device (event));
}
else
return;
press->any.send_event = TRUE;
next_child = event_widget;
parent = gtk_widget_get_parent (next_child);
while (parent != widget)
{
next_child = parent;
parent = gtk_widget_get_parent (parent);
}
/* Perform propagation state starting from the next child in the chain */
if (!_gtk_propagate_captured_event (event_widget, press, next_child))
gtk_propagate_event (event_widget, press);
gdk_event_free (press);
}
static gboolean
_gtk_widget_set_sequence_state_internal (GtkWidget *widget,
GdkEventSequence *sequence,
GtkEventSequenceState state)
{
GtkWidgetPrivate *priv = widget->priv;
const GdkEvent *mimic_event = NULL;
gboolean retval, handled = FALSE;
EventControllerData *data;
gboolean handled = FALSE;
GList *l;
for (l = priv->event_controllers; l; l = l->next)
@ -4061,10 +4138,27 @@ _gtk_widget_set_sequence_state_internal (GtkWidget *widget,
if (!GTK_IS_GESTURE (data->controller))
continue;
handled |= gtk_gesture_set_sequence_state (GTK_GESTURE (data->controller),
sequence, state);
retval = gtk_gesture_set_sequence_state (GTK_GESTURE (data->controller),
sequence, state);
handled |= retval;
/* If the sequence goes denied, check whether this is a controller attached
* to the capture phase, that additionally handled the button/touch press (ie.
* 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 &&
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);
}
if (mimic_event)
_gtk_widget_emulate_press (widget, mimic_event);
return handled;
}