xserver: Branch 'mpx' - 4 commits

Peter Hutterer whot at kemper.freedesktop.org
Tue Aug 7 20:49:17 PDT 2007


 dix/events.c       |  202 +++++++++++++++++++++++++++++++++++++++++++++++++----
 dix/grabs.c        |   31 ++++++--
 include/dixgrabs.h |    3 
 mi/mieq.c          |   12 ++-
 4 files changed, 225 insertions(+), 23 deletions(-)

New commits:
diff-tree c02128532e910e813fba94983733942d30c2d5cb (from b8abeaf74ee8296d4bc3164a5a253624f984a6d4)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Aug 8 13:10:00 2007 +0930

    dix: Allow flexible devices for passive core grabs.
    
    A passive core grab doesn't specify the device, and is thus created with the
    ClientPointer as device.  When this grab is activated later, don't actually
    activate the grab on the grab device, but rather change the device to the one
    that caused the grab to activate. Same procedure for keyboards.
    
    Makes core apps _A LOT_ more useable and reduces the need to set the
    ClientPointer.
    
    Only applies to core grabs!

diff --git a/dix/events.c b/dix/events.c
index faf8eed..7627f4e 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1685,17 +1685,45 @@ AllowSome(ClientPtr client, 
  * Server-side protocol handling for AllowEvents request.
  *
  * Release some events from a frozen device. 
+ * 
+ * In some cases, the grab the client has is not on the ClientPointer but on
+ * some other device (see ProcGrabPointer comments). To cover this case, we
+ * need to run through all devices to ensure we don't forget the device we
+ * actually have a grab on.
  */
 int
 ProcAllowEvents(ClientPtr client)
 {
     TimeStamp		time;
-    DeviceIntPtr	mouse = PickPointer(client);
-    DeviceIntPtr	keybd = PickKeyboard(client);
+    DeviceIntPtr	mouse = NULL,
+			grabbed;
+    DeviceIntPtr	keybd = NULL;
+    GrabPtr		grab;
     REQUEST(xAllowEventsReq);
 
     REQUEST_SIZE_MATCH(xAllowEventsReq);
     time = ClientTimeToServerTime(stuff->time);
+
+    for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+    {
+        grab = grabbed->deviceGrab.grab;
+        if (grab && grab->coreGrab && SameClient(grab, client))
+        {
+            if (IsPointerDevice(grabbed))
+                mouse = grabbed;
+            else if (IsKeyboardDevice(grabbed))
+                keybd = grabbed;
+
+	    if (mouse && keybd) 
+		break;
+        }
+    }
+
+    if (!mouse)
+        mouse = PickPointer(client);
+    if (!keybd)
+        keybd = PickKeyboard(client);
+
     switch (stuff->mode)
     {
 	case ReplayPointer:
@@ -3104,7 +3132,8 @@ CheckPassiveGrabsOnWindow(
 #else
 		grab->modifierDevice->key->state;
 #endif
-	if (GrabMatchesSecond(&tempGrab, grab) &&
+            /* ignore the device for core events when comparing grabs */
+	if (GrabMatchesSecond(&tempGrab, grab, (xE->u.u.type < LASTEvent)) &&
 	    (!grab->confineTo ||
 	     (grab->confineTo->realized && 
 				BorderSizeNotEmpty(device, grab->confineTo))))
@@ -3119,6 +3148,23 @@ CheckPassiveGrabsOnWindow(
 	    }
 #endif
             grabinfo = &device->deviceGrab;
+            /* A passive grab may have been created for a different device
+               than it is assigned to at this point in time.
+               Update the grab's device and modifier device to reflect the
+               current state.
+               XXX: Since XGrabDeviceButton requires to specify the
+               modifierDevice explicitly, we don't override this choice.
+               This essentially requires a client to re-create all
+               passiveGrabs when the pairing changes... oh well.
+             */ 
+            if (xE->u.u.type < LASTEVENT)
+            {
+                grab->device = device; 
+                grab->modifierDevice = GetPairedKeyboard(device);
+                if (!grab->modifierDevice)
+                    grab->modifierDevice = inputInfo.keyboard;
+            }
+
 	    (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE);
  
 	    FixUpEventFromWindow(device, xE, grab->window, None, TRUE);
@@ -4607,10 +4653,16 @@ ProcGetInputFocus(ClientPtr client)
 }
 
 /**
- * Server-side protocol handling for Grabpointer request.
+ * Server-side protocol handling for GrabPointer request.
  *
  * Sets an active grab on the client's ClientPointer and returns success
  * status to client.
+ *
+ * A special case of GrabPointer is when there is already a grab on some
+ * device (by the same client). In this case, this grab is overwritten, and
+ * the device stays as it is. This case can happen when a client has a passive
+ * grab and then grabs the pointer, or when the client already has an active
+ * grab and the ClientPointer was changed since.
  */
 int
 ProcGrabPointer(ClientPtr client)
@@ -4623,6 +4675,7 @@ ProcGrabPointer(ClientPtr client)
     REQUEST(xGrabPointerReq);
     TimeStamp time;
     int rc;
+    DeviceIntPtr grabbed = NULL;
 
     REQUEST_SIZE_MATCH(xGrabPointerReq);
     UpdateCurrentTime();
@@ -4677,6 +4730,21 @@ ProcGrabPointer(ClientPtr client)
     rep.type = X_Reply;
     rep.sequenceNumber = client->sequence;
     rep.length = 0;
+
+    /* Check if a the client already has a grab on a device */
+    for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+    {
+        if (IsPointerDevice(grabbed))
+        {
+            grab = grabbed->deviceGrab.grab;
+            if (grab && grab->coreGrab && SameClient(grab, client))
+            {
+                device = grabbed;
+                break;
+            }
+        }
+    }
+
     grab = device->deviceGrab.grab;
     if ((grab) && !SameClient(grab, client))
 	rep.status = AlreadyGrabbed;
@@ -4720,6 +4788,7 @@ ProcGrabPointer(ClientPtr client)
 	    FreeCursor (oldCursor, (Cursor)0);
 	rep.status = GrabSuccess;
 
+        /* guarantee only one core pointer grab at a time by this client */
         RemoveOtherCoreGrabs(client, device);
     }
     WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep);
@@ -4732,12 +4801,14 @@ ProcGrabPointer(ClientPtr client)
  * Changes properties of the grab hold by the client. If the client does not
  * hold an active grab on the device, nothing happens. 
  *
- * Works on the client's ClientPointer.
+ * Works on the client's ClientPointer, but in some cases the client may have
+ * a grab on a device that isn't the ClientPointer (see ProcGrabPointer
+ * comments). 
  */
 int
 ProcChangeActivePointerGrab(ClientPtr client)
 {
-    DeviceIntPtr device = PickPointer(client);
+    DeviceIntPtr device, grabbed;
     GrabPtr      grab = device->deviceGrab.grab;
     CursorPtr newCursor, oldCursor;
     REQUEST(xChangeActivePointerGrabReq);
@@ -4761,6 +4832,31 @@ ProcChangeActivePointerGrab(ClientPtr cl
 	    return BadCursor;
 	}
     }
+    if (!grab && !SameClient(grab, client))
+    {
+        /* no grab on ClientPointer, or some other client has a grab on our
+         * ClientPointer, let's check if we have a pointer grab on some other
+         * device. */
+        for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+        {
+            if (IsPointerDevice(grabbed))
+            {
+                grab = grabbed->deviceGrab.grab;
+                if (grab && grab->coreGrab && SameClient(grab, client))
+                {
+                    device = grabbed;
+                    break;
+                }
+            }
+        }
+        /* nope. no grab on any actual device */
+        if (!grabbed)
+        {
+            device = inputInfo.pointer;
+            grab = inputInfo.pointer->deviceGrab.grab;
+        }
+    }
+
     if (!grab)
 	return Success;
     if (!SameClient(grab, client))
@@ -4783,12 +4879,17 @@ ProcChangeActivePointerGrab(ClientPtr cl
 /**
  * Server-side protocol handling for UngrabPointer request.
  *
- * Deletes the pointer grab on the client's ClientPointer device.
+ * Deletes a pointer grab on a device the client has grabbed. This should be
+ * the ClientPointer, but may not be. So we search the device list for a
+ * device we have a pointer grab on and then ungrab this device. (see
+ * ProcGrabPointer comments). We are guaranteed that the client doesn't have
+ * more than one core pointer grab at a time.
  */
 int
 ProcUngrabPointer(ClientPtr client)
 {
-    DeviceIntPtr device = PickPointer(client);
+    DeviceIntPtr device = PickPointer(client),
+                 grabbed;
     GrabPtr grab;
     TimeStamp time;
     REQUEST(xResourceReq);
@@ -4796,6 +4897,31 @@ ProcUngrabPointer(ClientPtr client)
     REQUEST_SIZE_MATCH(xResourceReq);
     UpdateCurrentTime();
     grab = device->deviceGrab.grab;
+
+    if (!grab || !grab->coreGrab || !SameClient(grab, client))
+    {
+        /* No pointer grab on ClientPointer. May be a pointer grab on some
+         * other device */
+        for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+        {
+            if (IsPointerDevice(grabbed))
+            {
+                grab = grabbed->deviceGrab.grab;
+                if (grab && grab->coreGrab && SameClient(grab, client))
+                {
+                    device = grabbed;
+                    break;
+                }
+            }
+        }
+        /* nope. no grab on any actual device */
+        if (!grabbed)
+        {
+            device = inputInfo.pointer;
+            grab = inputInfo.pointer->deviceGrab.grab;
+        }
+    }
+
     time = ClientTimeToServerTime(stuff->id);
     if ((CompareTimeStamps(time, currentTime) != LATER) &&
 	    (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
@@ -4935,6 +5061,15 @@ RemoveOtherCoreGrabs(ClientPtr client, D
  * Server-side protocol handling for GrabKeyboard request.
  *
  * Grabs the client's keyboard and returns success status to client.
+ *
+ * In some special cases the client may already have a grab on a keyboard that
+ * is not the one that is paired with the ClientPointer. This can happen when
+ * the client alreay has a passive grab on some keyboard device, or when the
+ * client actively grabbed the keyboard and the ClientPointer or keyboard
+ * pairing was changed since.
+ * Therefore, we need to run through all the keyboards available and check if
+ * there's already a grab on it from our client. The client will only ever
+ * have one core keyboard grab at a time.
  */
 int
 ProcGrabKeyboard(ClientPtr client)
@@ -4942,16 +5077,32 @@ ProcGrabKeyboard(ClientPtr client)
     xGrabKeyboardReply rep;
     REQUEST(xGrabKeyboardReq);
     int result;
-    DeviceIntPtr keyboard = PickKeyboard(client);
+    DeviceIntPtr keyboard = PickKeyboard(client),
+                 grabbed;
+    GrabPtr      grab;
 
     REQUEST_SIZE_MATCH(xGrabKeyboardReq);
 
+    for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+    {
+	if (IsKeyboardDevice(grabbed))
+	{
+	    grab = grabbed->deviceGrab.grab;
+	    if (grab && grab->coreGrab && SameClient(grab, client))
+	    {
+		keyboard = grabbed;
+		break;
+	    }
+	}
+    }
+
     if (XaceHook(XACE_DEVICE_ACCESS, client, keyboard, TRUE))
     {
 	result = GrabDevice(client, keyboard, stuff->keyboardMode,
 			    stuff->pointerMode, stuff->grabWindow,
 			    stuff->ownerEvents, stuff->time,
 			    KeyPressMask | KeyReleaseMask, &rep.status, TRUE);
+        /* ensure only one core keyboard grab by this client */
         RemoveOtherCoreGrabs(client, keyboard);
     }
     else {
@@ -4972,18 +5123,40 @@ ProcGrabKeyboard(ClientPtr client)
  * Server-side protocol handling for UngrabKeyboard request.
  *
  * Deletes a possible grab on the client's keyboard.
+ *
+ * We may have a grab on a keyboard that isn't the ClientPointer's keyboard.
+ * Thus we need to check all keyboar devices for a grab. (see ProcGrabKeyboard
+ * comments)
  */
 int
 ProcUngrabKeyboard(ClientPtr client)
 {
-    DeviceIntPtr device = PickKeyboard(client);
+    DeviceIntPtr device = PickKeyboard(client),
+		 grabbed;
     GrabPtr grab;
     TimeStamp time;
     REQUEST(xResourceReq);
 
     REQUEST_SIZE_MATCH(xResourceReq);
     UpdateCurrentTime();
+
+    if (!grab || !grab->coreGrab || !SameClient(grab, client))
+    {
+	for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
+	{
+	    if (IsKeyboardDevice(grabbed))
+	    {
+		grab = device->deviceGrab.grab;
+		if (grab && grab->coreGrab && SameClient(grab, client))
+		{
+		    device = grabbed;
+		    break;
+		}
+	    }
+	}
+    }
     grab = device->deviceGrab.grab;
+
     time = ClientTimeToServerTime(stuff->id);
     if ((CompareTimeStamps(time, currentTime) != LATER) &&
 	(CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
diff --git a/dix/grabs.c b/dix/grabs.c
index 9150c3c..01f4b64 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -240,12 +240,28 @@ GrabSupersedesSecond(GrabPtr pFirstGrab,
     return FALSE;
 }
 
+/**
+ * Compares two grabs and returns TRUE if the first grab matches the second
+ * grab. 
+ * 
+ * A match is when 
+ *  - the devices set for the grab are equal (this is optional).
+ *  - the event types for both grabs are equal.
+ *  - XXX
+ *
+ * @param ignoreDevice TRUE if the device settings on the grabs are to be
+ * ignored.
+ * @return TRUE if the grabs match or FALSE otherwise.
+ */
 Bool
-GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
+GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
 {
-    if ((pFirstGrab->device != pSecondGrab->device) ||
-	(pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
-	(pFirstGrab->type != pSecondGrab->type))
+    if (!ignoreDevice &&
+            ((pFirstGrab->device != pSecondGrab->device) ||
+             (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
+            return FALSE;
+
+    if (pFirstGrab->type != pSecondGrab->type)
 	return FALSE;
 
     if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
@@ -278,7 +294,7 @@ AddPassiveGrabToList(GrabPtr pGrab)
 
     for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
     {
-	if (GrabMatchesSecond(pGrab, grab))
+	if (GrabMatchesSecond(pGrab, grab, FALSE))
 	{
 	    if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
 	    {
@@ -343,7 +359,7 @@ DeletePassiveGrabFromList(GrabPtr pMinue
 	 grab = grab->next)
     {
 	if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
-	    !GrabMatchesSecond(grab, pMinuendGrab))
+	    !GrabMatchesSecond(grab, pMinuendGrab, FALSE))
 	    continue;
 	if (GrabSupersedesSecond(pMinuendGrab, grab))
 	{
diff --git a/include/dixgrabs.h b/include/dixgrabs.h
index 2d66d6b..b237ab3 100644
--- a/include/dixgrabs.h
+++ b/include/dixgrabs.h
@@ -47,7 +47,8 @@ extern int DeletePassiveGrab(
 
 extern Bool GrabMatchesSecond(
 	GrabPtr /* pFirstGrab */,
-	GrabPtr /* pSecondGrab */);
+	GrabPtr /* pSecondGrab */,
+	Bool /*ignoreDevice*/);
 
 extern int AddPassiveGrabToList(
 	GrabPtr /* pGrab */);
diff-tree b8abeaf74ee8296d4bc3164a5a253624f984a6d4 (from a0b87f87fb8753955505958bf3d438eef191302d)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Aug 7 12:32:46 2007 +0930

    dix: get the paired keyboard for a passive grab (ProcGrabButton).
    
    Taking the VCK is only correct if no physical device is connected, and even
    then it's not really a good idea.

diff --git a/dix/events.c b/dix/events.c
index 7de8d2e..faf8eed 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -5326,6 +5326,7 @@ ProcGrabButton(ClientPtr client)
     REQUEST(xGrabButtonReq);
     CursorPtr cursor;
     GrabPtr grab;
+    DeviceIntPtr pointer, modifierDevice;
     int rc;
 
     REQUEST_SIZE_MATCH(xGrabButtonReq);
@@ -5381,11 +5382,15 @@ ProcGrabButton(ClientPtr client)
 	}
     }
 
+    pointer = PickPointer(client);
+    modifierDevice = GetPairedKeyboard(pointer);
+    if (!modifierDevice)
+        modifierDevice = inputInfo.keyboard;
 
-    grab = CreateGrab(client->index, PickPointer(client), pWin, 
+    grab = CreateGrab(client->index, pointer, pWin, 
         (Mask)stuff->eventMask, (Bool)stuff->ownerEvents,
         (Bool) stuff->keyboardMode, (Bool)stuff->pointerMode,
-        inputInfo.keyboard, stuff->modifiers, ButtonPress,
+        modifierDevice, stuff->modifiers, ButtonPress,
         stuff->button, confineTo, cursor);
     if (!grab)
 	return BadAlloc;
diff-tree a0b87f87fb8753955505958bf3d438eef191302d (from 9eddede039f6cbcc323b7e3e4e841c43d3ed4f43)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Aug 7 10:49:33 2007 +0930

    dix: check for core event to determine if grab is a core grab (CreateGrab).
    
    Checking for VCP/VCK is simply not a safe way to check if a grab is a core grab.

diff --git a/dix/grabs.c b/dix/grabs.c
index af471eb..9150c3c 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -87,8 +87,7 @@ CreateGrab(
 	return (GrabPtr)NULL;
     grab->resource = FakeClientID(client);
     grab->device = device;
-    grab->coreGrab = ((device == inputInfo.keyboard) ||
-		      (device == inputInfo.pointer));
+    grab->coreGrab = (type < LASTEvent);
     grab->window = window;
     grab->eventMask = eventMask;
     grab->deviceMask = 0;
diff-tree 9eddede039f6cbcc323b7e3e4e841c43d3ed4f43 (from ffdf8f3e452638e6b050fccabee465d6c0300f45)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Mon Jul 16 18:01:00 2007 +0930

    mieqEnqueue: Don't try to update the time for GenericEvents.
    
    Doing so may overwrite the event's length field and cause havoc. Also check if
    realloc'd memory did actually return valid pointer.

diff --git a/mi/mieq.c b/mi/mieq.c
index 4b29950..c3f63fb 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -184,6 +184,11 @@ mieqEnqueue(DeviceIntPtr pDev, xEvent *e
     {
         evt->evlen = evlen;
         evt->event = xrealloc(evt->event, evt->evlen);
+        if (!evt->event)
+        {
+            ErrorF("Running out of memory. Tossing event.\n");
+            return;
+        }
     }
 
     memcpy(evt->event, e, evlen);
@@ -191,8 +196,9 @@ mieqEnqueue(DeviceIntPtr pDev, xEvent *e
 
     /* Make sure that event times don't go backwards - this
      * is "unnecessary", but very useful. */
-    if (e->u.keyButtonPointer.time < miEventQueue.lastEventTime &&
-	miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000)
+    if (e->u.u.type != GenericEvent &&
+        e->u.keyButtonPointer.time < miEventQueue.lastEventTime &&
+            miEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000)
         evt->event->u.keyButtonPointer.time = miEventQueue.lastEventTime;
 
     miEventQueue.lastEventTime = evt->event->u.keyButtonPointer.time;
@@ -293,7 +299,9 @@ mieqProcessInputEvents(void)
                     memcpy(&event[i], e->events[i].event, sizeof(xEvent));
             }
             else 
+            {
                 event = e->events->event;
+            }
 
             /* MPX devices send both core and Xi events. 
              * Use dev to get the correct processing function but supply


More information about the xorg-commit mailing list