event: Unify the off-stage motion events delivery behaviour

When we disable the per-actor events delivery Clutter replicates the X11
implicit soft grab for motion events with off-stage. The implicit grab
is done whenever the pointer of a device leaves a window with a button
still pressed; with the implicit grab in place the window still receives
motion events even after the LeaveNotify - until the button is released.

The implicit grab is not honoured in the per-actor event deliver case,
though, so we have a mismatch between two in theory equivalent cases.

Luckily, the fix is pretty trivial: when we check for a motion event
with a stage set but without an actor set, and that has off-stage
coordinates, we arbitrarily set the source to be the stage of the event
and emit the pointer event.
This commit is contained in:
Emmanuele Bassi 2010-02-01 15:47:50 +00:00
parent 46d6697b91
commit 521d71d4bc

View File

@ -2240,6 +2240,17 @@ emit_keyboard_event (ClutterEvent *event)
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
}
static gboolean
is_off_stage (ClutterActor *stage,
gfloat x,
gfloat y)
{
return (x < 0 ||
y < 0 ||
x >= clutter_actor_get_width (stage) ||
y >= clutter_actor_get_height (stage));
}
/**
* clutter_do_event
* @event: a #ClutterEvent.
@ -2360,10 +2371,14 @@ _clutter_process_event_details (ClutterActor *stage,
*/
if (event->any.source == NULL)
{
/* Handle release off stage */
if ((x >= clutter_actor_get_width (stage) ||
y >= clutter_actor_get_height (stage) ||
x < 0 || y < 0))
/* emulate X11 the implicit soft grab; the implicit soft grab
* keeps relaying motion events when the stage is left with a
* pointer button pressed. since this is what happens when we
* disable per-actor motion events we need to maintain the same
* behaviour when the per-actor motion events are enabled as
* well
*/
if (is_off_stage (stage, x, y))
{
if (event->type == CLUTTER_BUTTON_RELEASE)
{
@ -2373,8 +2388,20 @@ _clutter_process_event_details (ClutterActor *stage,
event->button.source = stage;
event->button.click_count = 1;
emit_pointer_event (event, device);
}
else if (event->type == CLUTTER_MOTION)
{
CLUTTER_NOTE (EVENT,
"Motion off stage received at %.2f, %2.f",
x, y);
event->motion.source = stage;
emit_pointer_event (event, device);
}
break;
}
@ -2393,9 +2420,10 @@ _clutter_process_event_details (ClutterActor *stage,
CLUTTER_PICK_REACTIVE);
}
event->any.source = actor;
if (event->any.source == NULL)
if (actor == NULL)
break;
event->any.source = actor;
}
else
{