event: Unify the off-stage motion events delivery behaviour
authorEmmanuele Bassi <ebassi@linux.intel.com>
Mon, 1 Feb 2010 15:47:50 +0000 (15:47 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Mon, 1 Feb 2010 16:36:36 +0000 (16:36 +0000)
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.

clutter/clutter-main.c

index 1ac393e..b73a9a6 100644 (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
             {