x11: Discard the LeaveNotify for off-stage ButtonRelease
authorEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 9 Dec 2009 00:03:13 +0000 (00:03 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 20 Jan 2010 00:38:09 +0000 (00:38 +0000)
If the user presses a button on a pointer device and then moves out the
Stage X11 will emit the following events:

  LeaveNotify ➔ MotionNotify ... ➔ ButtonRelease ➔ LeaveNotify

The second LeaveNotify differs from the first by the state field.

Unfortunately, ClutterCrossingEvent doesn't have a modifier_state field
like other events, so we cannot provide a way for programmatically
distinguishing them from a Clutter perspective. This is also an X11-ism
we might not even want to replicate on every backend with sane
enter/leave semantics.

For this reason we should check inside the X11 event processing if the
pointer device has already left the Stage and ignore the second
LeaveNotify.

clutter/x11/clutter-event-x11.c

index 6a1eab7..549fef0 100644 (file)
@@ -417,6 +417,7 @@ event_translate (ClutterBackend *backend,
   gboolean res, not_yet_handled = FALSE;
   Window xwindow, stage_xwindow;
   ClutterDeviceManager *manager;
+  ClutterInputDevice *device;
 
   backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
@@ -674,12 +675,11 @@ event_translate (ClutterBackend *backend,
     {
       if (!clutter_x11_has_xinput ())
         {
+          device = clutter_device_manager_get_device (manager, 0);
+
           /* Regular X event */
           switch (xevent->type)
             {
-                       /* KeyPress / KeyRelease should reside here if XInput
-             * worked properly
-             */
             case ButtonPress:
               switch (xevent->xbutton.button)
                 {
@@ -702,8 +702,7 @@ event_translate (ClutterBackend *backend,
                   event->scroll.x = xevent->xbutton.x;
                   event->scroll.y = xevent->xbutton.y;
                   event->scroll.modifier_state = xevent->xbutton.state;
-                  event->scroll.device =
-                    clutter_device_manager_get_device (manager, 0);
+                  event->scroll.device = device;
                   break;
 
                 default:
@@ -713,8 +712,7 @@ event_translate (ClutterBackend *backend,
                   event->button.y = xevent->xbutton.y;
                   event->button.modifier_state = xevent->xbutton.state;
                   event->button.button = xevent->xbutton.button;
-                  event->button.device =
-                    clutter_device_manager_get_device (manager, 0);
+                  event->button.device = device;
                   break;
                 }
 
@@ -738,8 +736,7 @@ event_translate (ClutterBackend *backend,
               event->button.y = xevent->xbutton.y;
               event->button.modifier_state = xevent->xbutton.state;
               event->button.button = xevent->xbutton.button;
-              event->button.device =
-                clutter_device_manager_get_device (manager, 0);
+              event->button.device = device;
               break;
               
             case MotionNotify:
@@ -748,8 +745,7 @@ event_translate (ClutterBackend *backend,
               event->motion.x = xevent->xmotion.x;
               event->motion.y = xevent->xmotion.y;
               event->motion.modifier_state = xevent->xmotion.state;
-              event->motion.device =
-                clutter_device_manager_get_device (manager, 0);
+              event->motion.device = device;
               break;
 
             case EnterNotify:
@@ -760,25 +756,35 @@ event_translate (ClutterBackend *backend,
               event->motion.x = xevent->xcrossing.x;
               event->motion.y = xevent->xcrossing.y;
               event->motion.modifier_state = xevent->xcrossing.state;
-              event->motion.device =
-                clutter_device_manager_get_device (manager, 0);
+              event->motion.source = CLUTTER_ACTOR (stage);
+              event->motion.device = device;
 
               /* we know that we are entering the stage here */
-              _clutter_input_device_set_stage (event->motion.device, stage);
+              _clutter_input_device_set_stage (device, stage);
               CLUTTER_NOTE (EVENT, "Entering the stage");
               break;
 
             case LeaveNotify:
+              if (device->stage == NULL)
+                {
+                  CLUTTER_NOTE (EVENT,
+                                "Discarding LeaveNotify for ButtonRelease "
+                                "event off-stage");
+                  res = FALSE;
+                  break;
+                }
+
               event->crossing.type = event->type = CLUTTER_LEAVE;
               event->crossing.time = xevent->xcrossing.time;
               event->crossing.x = xevent->xcrossing.x;
               event->crossing.y = xevent->xcrossing.y;
-              event->crossing.device =
-                clutter_device_manager_get_device (manager, 0);
+              event->crossing.source = CLUTTER_ACTOR (stage);
+              event->crossing.device = device;
 
               /* we know that we are leaving the stage here */
-              _clutter_input_device_set_stage (event->crossing.device, NULL);
-              CLUTTER_NOTE (EVENT, "Leaving the stage");
+              _clutter_input_device_set_stage (device, NULL);
+              CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
+                            event->crossing.time);
               break;
 
             default:
@@ -804,6 +810,8 @@ event_translate (ClutterBackend *backend,
             {
               XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent;
 
+              device = _clutter_x11_get_device_for_xid (xbev->deviceid);
+
               CLUTTER_NOTE (EVENT,
                             "XINPUT Button press event for %li at %d, %d",
                             xbev->deviceid,
@@ -831,8 +839,7 @@ event_translate (ClutterBackend *backend,
                   event->scroll.x = xbev->x;
                   event->scroll.y = xbev->y;
                   event->scroll.modifier_state = xbev->state;
-                  event->scroll.device =
-                    _clutter_x11_get_device_for_xid (xbev->deviceid);
+                  event->scroll.device = device;
                   break;
 
                 default:
@@ -842,8 +849,7 @@ event_translate (ClutterBackend *backend,
                   event->button.y = xbev->y;
                   event->button.modifier_state = xbev->state;
                   event->button.button = xbev->button;
-                  event->button.device =
-                    _clutter_x11_get_device_for_xid (xbev->deviceid);
+                  event->button.device = device;
                   break;
                 }
 
@@ -853,6 +859,8 @@ event_translate (ClutterBackend *backend,
             {
               XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
 
+              device = _clutter_x11_get_device_for_xid (xbev->deviceid);
+
               CLUTTER_NOTE (EVENT, "XINPUT Button release event for %li at %d, %d",
                             xbev->deviceid,
                             xbev->x,
@@ -873,12 +881,14 @@ event_translate (ClutterBackend *backend,
               event->button.y = xbev->y;
               event->button.modifier_state = xbev->state;
               event->button.button = xbev->button;
-              event->button.device = _clutter_x11_get_device_for_xid (xbev->deviceid);
+              event->button.device = device;
             } 
           else if (xevent->type == motion_notify)
             {
               XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
 
+              device = _clutter_x11_get_device_for_xid (xmev->deviceid);
+
               CLUTTER_NOTE(EVENT, "XINPUT Motion event for %li at %d, %d",
                            xmev->deviceid,
                            xmev->x,
@@ -889,7 +899,7 @@ event_translate (ClutterBackend *backend,
               event->motion.x = xmev->x;
               event->motion.y = xmev->y;
               event->motion.modifier_state = xmev->state;
-              event->motion.device = _clutter_x11_get_device_for_xid (xmev->deviceid);
+              event->motion.device = device;
             } 
 #if 0
         /* the Xinput handling of key presses/releases disabled for now since