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); 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 * clutter_do_event
* @event: a #ClutterEvent. * @event: a #ClutterEvent.
@ -2360,10 +2371,14 @@ _clutter_process_event_details (ClutterActor *stage,
*/ */
if (event->any.source == NULL) if (event->any.source == NULL)
{ {
/* Handle release off stage */ /* emulate X11 the implicit soft grab; the implicit soft grab
if ((x >= clutter_actor_get_width (stage) || * keeps relaying motion events when the stage is left with a
y >= clutter_actor_get_height (stage) || * pointer button pressed. since this is what happens when we
x < 0 || y < 0)) * 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) if (event->type == CLUTTER_BUTTON_RELEASE)
{ {
@ -2373,8 +2388,20 @@ _clutter_process_event_details (ClutterActor *stage,
event->button.source = stage; event->button.source = stage;
event->button.click_count = 1; event->button.click_count = 1;
emit_pointer_event (event, device); 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; break;
} }
@ -2393,9 +2420,10 @@ _clutter_process_event_details (ClutterActor *stage,
CLUTTER_PICK_REACTIVE); CLUTTER_PICK_REACTIVE);
} }
event->any.source = actor; if (actor == NULL)
if (event->any.source == NULL)
break; break;
event->any.source = actor;
} }
else else
{ {