719 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			719 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| 
 | |
| Copyright 1987, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included
 | |
| in all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | |
| IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
| OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall
 | |
| not be used in advertising or otherwise to promote the sale, use or
 | |
| other dealings in this Software without prior written authorization
 | |
| from The Open Group.
 | |
| 
 | |
| Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
 | |
| 
 | |
|                         All Rights Reserved
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software and its 
 | |
| documentation for any purpose and without fee is hereby granted, 
 | |
| provided that the above copyright notice appear in all copies and that
 | |
| both that copyright notice and this permission notice appear in 
 | |
| supporting documentation, and that the name of Digital not be
 | |
| used in advertising or publicity pertaining to distribution of the
 | |
| software without specific, written prior permission.  
 | |
| DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 | |
| ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 | |
| DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 | |
| ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 | |
| WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | |
| ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | |
| SOFTWARE.
 | |
| 
 | |
| */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include "misc.h"
 | |
| #include <X11/Xproto.h>
 | |
| #include <X11/extensions/XI2.h>
 | |
| #include "windowstr.h"
 | |
| #include "inputstr.h"
 | |
| #include "cursorstr.h"
 | |
| #include "dixgrabs.h"
 | |
| #include "xace.h"
 | |
| #include "exevents.h"
 | |
| #include "exglobals.h"
 | |
| #include "inpututils.h"
 | |
| #include "client.h"
 | |
| 
 | |
| #define BITMASK(i) (((Mask)1) << ((i) & 31))
 | |
| #define MASKIDX(i) ((i) >> 5)
 | |
| #define MASKWORD(buf, i) buf[MASKIDX(i)]
 | |
| #define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
 | |
| #define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
 | |
| #define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
 | |
| 
 | |
| void
 | |
| PrintDeviceGrabInfo(DeviceIntPtr dev)
 | |
| {
 | |
|     ClientPtr client;
 | |
|     LocalClientCredRec *lcc;
 | |
|     int i, j;
 | |
|     GrabInfoPtr devGrab = &dev->deviceGrab;
 | |
|     GrabPtr grab = devGrab->grab;
 | |
|     Bool clientIdPrinted = FALSE;
 | |
| 
 | |
|     ErrorF("Active grab 0x%lx (%s) on device '%s' (%d):\n",
 | |
|            (unsigned long) grab->resource,
 | |
|            (grab->grabtype == XI2) ? "xi2" :
 | |
|            ((grab->grabtype == CORE) ? "core" : "xi1"), dev->name, dev->id);
 | |
| 
 | |
|     client = clients[CLIENT_ID(grab->resource)];
 | |
|     if (client) {
 | |
|         pid_t clientpid = GetClientPid(client);
 | |
|         const char *cmdname = GetClientCmdName(client);
 | |
|         const char *cmdargs = GetClientCmdArgs(client);
 | |
| 
 | |
|         if ((clientpid > 0) && (cmdname != NULL)) {
 | |
|             ErrorF("      client pid %ld %s %s\n",
 | |
|                    (long) clientpid, cmdname, cmdargs ? cmdargs : "");
 | |
|             clientIdPrinted = TRUE;
 | |
|         }
 | |
|         else if (GetLocalClientCreds(client, &lcc) != -1) {
 | |
|             ErrorF("      client pid %ld uid %ld gid %ld\n",
 | |
|                    (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0,
 | |
|                    (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0,
 | |
|                    (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0);
 | |
|             FreeLocalClientCreds(lcc);
 | |
|             clientIdPrinted = TRUE;
 | |
|         }
 | |
|     }
 | |
|     if (!clientIdPrinted) {
 | |
|         ErrorF("      (no client information available for client %d)\n",
 | |
|                CLIENT_ID(grab->resource));
 | |
|     }
 | |
| 
 | |
|     /* XXX is this even correct? */
 | |
|     if (devGrab->sync.other)
 | |
|         ErrorF("      grab ID 0x%lx from paired device\n",
 | |
|                (unsigned long) devGrab->sync.other->resource);
 | |
| 
 | |
|     ErrorF("      at %ld (from %s grab)%s (device %s, state %d)\n",
 | |
|            (unsigned long) devGrab->grabTime.milliseconds,
 | |
|            devGrab->fromPassiveGrab ? "passive" : "active",
 | |
|            devGrab->implicitGrab ? " (implicit)" : "",
 | |
|            devGrab->sync.frozen ? "frozen" : "thawed", devGrab->sync.state);
 | |
| 
 | |
|     if (grab->grabtype == CORE) {
 | |
|         ErrorF("        core event mask 0x%lx\n",
 | |
|                (unsigned long) grab->eventMask);
 | |
|     }
 | |
|     else if (grab->grabtype == XI) {
 | |
|         ErrorF("      xi1 event mask 0x%lx\n",
 | |
|                devGrab->implicitGrab ? (unsigned long) grab->deviceMask :
 | |
|                (unsigned long) grab->eventMask);
 | |
|     }
 | |
|     else if (grab->grabtype == XI2) {
 | |
|         for (i = 0; i < xi2mask_num_masks(grab->xi2mask); i++) {
 | |
|             const unsigned char *mask;
 | |
|             int print;
 | |
| 
 | |
|             print = 0;
 | |
|             for (j = 0; j < XI2MASKSIZE; j++) {
 | |
|                 mask = xi2mask_get_one_mask(grab->xi2mask, i);
 | |
|                 if (mask[j]) {
 | |
|                     print = 1;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             if (!print)
 | |
|                 continue;
 | |
|             ErrorF("      xi2 event mask for device %d: 0x", dev->id);
 | |
|             for (j = 0; j < xi2mask_mask_size(grab->xi2mask); j++)
 | |
|                 ErrorF("%x", mask[j]);
 | |
|             ErrorF("\n");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (devGrab->fromPassiveGrab) {
 | |
|         ErrorF("      passive grab type %d, detail 0x%x, "
 | |
|                "activating key %d\n", grab->type, grab->detail.exact,
 | |
|                devGrab->activatingKey);
 | |
|     }
 | |
| 
 | |
|     ErrorF("      owner-events %s, kb %d ptr %d, confine %lx, cursor 0x%lx\n",
 | |
|            grab->ownerEvents ? "true" : "false",
 | |
|            grab->keyboardMode, grab->pointerMode,
 | |
|            grab->confineTo ? (unsigned long) grab->confineTo->drawable.id : 0,
 | |
|            grab->cursor ? (unsigned long) grab->cursor->id : 0);
 | |
| }
 | |
| 
 | |
| void
 | |
| UngrabAllDevices(Bool kill_client)
 | |
| {
 | |
|     DeviceIntPtr dev;
 | |
|     ClientPtr client;
 | |
| 
 | |
|     ErrorF("Ungrabbing all devices%s; grabs listed below:\n",
 | |
|            kill_client ? " and killing their owners" : "");
 | |
| 
 | |
|     for (dev = inputInfo.devices; dev; dev = dev->next) {
 | |
|         if (!dev->deviceGrab.grab)
 | |
|             continue;
 | |
|         PrintDeviceGrabInfo(dev);
 | |
|         client = clients[CLIENT_ID(dev->deviceGrab.grab->resource)];
 | |
|         if (!kill_client || !client || client->clientGone)
 | |
|             dev->deviceGrab.DeactivateGrab(dev);
 | |
|         if (kill_client)
 | |
|             CloseDownClient(client);
 | |
|     }
 | |
| 
 | |
|     ErrorF("End list of ungrabbed devices\n");
 | |
| }
 | |
| 
 | |
| GrabPtr
 | |
| AllocGrab(const GrabPtr src)
 | |
| {
 | |
|     GrabPtr grab = calloc(1, sizeof(GrabRec));
 | |
| 
 | |
|     if (grab) {
 | |
|         grab->xi2mask = xi2mask_new();
 | |
|         if (!grab->xi2mask) {
 | |
|             free(grab);
 | |
|             grab = NULL;
 | |
|         }
 | |
|         else if (src && !CopyGrab(grab, src)) {
 | |
|             free(grab->xi2mask);
 | |
|             free(grab);
 | |
|             grab = NULL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return grab;
 | |
| }
 | |
| 
 | |
| GrabPtr
 | |
| CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
 | |
|            WindowPtr window, enum InputLevel grabtype, GrabMask *mask,
 | |
|            GrabParameters *param, int type,
 | |
|            KeyCode keybut,        /* key or button */
 | |
|            WindowPtr confineTo, CursorPtr cursor)
 | |
| {
 | |
|     GrabPtr grab;
 | |
| 
 | |
|     grab = AllocGrab(NULL);
 | |
|     if (!grab)
 | |
|         return (GrabPtr) NULL;
 | |
|     grab->resource = FakeClientID(client);
 | |
|     grab->device = device;
 | |
|     grab->window = window;
 | |
|     if (grabtype == CORE || grabtype == XI)
 | |
|         grab->eventMask = mask->core;       /* same for XI */
 | |
|     else
 | |
|         grab->eventMask = 0;
 | |
|     grab->deviceMask = 0;
 | |
|     grab->ownerEvents = param->ownerEvents;
 | |
|     grab->keyboardMode = param->this_device_mode;
 | |
|     grab->pointerMode = param->other_devices_mode;
 | |
|     grab->modifiersDetail.exact = param->modifiers;
 | |
|     grab->modifiersDetail.pMask = NULL;
 | |
|     grab->modifierDevice = modDevice;
 | |
|     grab->type = type;
 | |
|     grab->grabtype = grabtype;
 | |
|     grab->detail.exact = keybut;
 | |
|     grab->detail.pMask = NULL;
 | |
|     grab->confineTo = confineTo;
 | |
|     grab->cursor = RefCursor(cursor);
 | |
|     grab->next = NULL;
 | |
| 
 | |
|     if (grabtype == XI2)
 | |
|         xi2mask_merge(grab->xi2mask, mask->xi2mask);
 | |
|     return grab;
 | |
| 
 | |
| }
 | |
| 
 | |
| void
 | |
| FreeGrab(GrabPtr pGrab)
 | |
| {
 | |
|     BUG_RETURN(!pGrab);
 | |
| 
 | |
|     free(pGrab->modifiersDetail.pMask);
 | |
|     free(pGrab->detail.pMask);
 | |
| 
 | |
|     if (pGrab->cursor)
 | |
|         FreeCursor(pGrab->cursor, (Cursor) 0);
 | |
| 
 | |
|     xi2mask_free(&pGrab->xi2mask);
 | |
|     free(pGrab);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| CopyGrab(GrabPtr dst, const GrabPtr src)
 | |
| {
 | |
|     Mask *mdetails_mask = NULL;
 | |
|     Mask *details_mask = NULL;
 | |
|     XI2Mask *xi2mask;
 | |
| 
 | |
|     if (src->modifiersDetail.pMask) {
 | |
|         int len = MasksPerDetailMask * sizeof(Mask);
 | |
| 
 | |
|         mdetails_mask = malloc(len);
 | |
|         if (!mdetails_mask)
 | |
|             return FALSE;
 | |
|         memcpy(mdetails_mask, src->modifiersDetail.pMask, len);
 | |
|     }
 | |
| 
 | |
|     if (src->detail.pMask) {
 | |
|         int len = MasksPerDetailMask * sizeof(Mask);
 | |
| 
 | |
|         details_mask = malloc(len);
 | |
|         if (!details_mask) {
 | |
|             free(mdetails_mask);
 | |
|             return FALSE;
 | |
|         }
 | |
|         memcpy(details_mask, src->detail.pMask, len);
 | |
|     }
 | |
| 
 | |
|     if (!dst->xi2mask) {
 | |
|         xi2mask = xi2mask_new();
 | |
|         if (!xi2mask) {
 | |
|             free(mdetails_mask);
 | |
|             free(details_mask);
 | |
|             return FALSE;
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         xi2mask = dst->xi2mask;
 | |
|         xi2mask_zero(xi2mask, -1);
 | |
|     }
 | |
| 
 | |
|     *dst = *src;
 | |
|     dst->modifiersDetail.pMask = mdetails_mask;
 | |
|     dst->detail.pMask = details_mask;
 | |
|     dst->xi2mask = xi2mask;
 | |
|     dst->cursor = RefCursor(src->cursor);
 | |
| 
 | |
|     xi2mask_merge(dst->xi2mask, src->xi2mask);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| int
 | |
| DeletePassiveGrab(void *value, XID id)
 | |
| {
 | |
|     GrabPtr g, prev;
 | |
|     GrabPtr pGrab = (GrabPtr) value;
 | |
| 
 | |
|     /* it is OK if the grab isn't found */
 | |
|     prev = 0;
 | |
|     for (g = (wPassiveGrabs(pGrab->window)); g; g = g->next) {
 | |
|         if (pGrab == g) {
 | |
|             if (prev)
 | |
|                 prev->next = g->next;
 | |
|             else if (!(pGrab->window->optional->passiveGrabs = g->next))
 | |
|                 CheckWindowOptionalNeed(pGrab->window);
 | |
|             break;
 | |
|         }
 | |
|         prev = g;
 | |
|     }
 | |
|     FreeGrab(pGrab);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static Mask *
 | |
| DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
 | |
| {
 | |
|     Mask *mask;
 | |
|     int i;
 | |
| 
 | |
|     mask = malloc(sizeof(Mask) * MasksPerDetailMask);
 | |
|     if (mask) {
 | |
|         if (pDetailMask)
 | |
|             for (i = 0; i < MasksPerDetailMask; i++)
 | |
|                 mask[i] = pDetailMask[i];
 | |
|         else
 | |
|             for (i = 0; i < MasksPerDetailMask; i++)
 | |
|                 mask[i] = ~0L;
 | |
|         BITCLEAR(mask, detail);
 | |
|     }
 | |
|     return mask;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| IsInGrabMask(DetailRec firstDetail,
 | |
|              DetailRec secondDetail, unsigned int exception)
 | |
| {
 | |
|     if (firstDetail.exact == exception) {
 | |
|         if (firstDetail.pMask == NULL)
 | |
|             return TRUE;
 | |
| 
 | |
|         /* (at present) never called with two non-null pMasks */
 | |
|         if (secondDetail.exact == exception)
 | |
|             return FALSE;
 | |
| 
 | |
|         if (GETBIT(firstDetail.pMask, secondDetail.exact))
 | |
|             return TRUE;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| IdenticalExactDetails(unsigned int firstExact,
 | |
|                       unsigned int secondExact, unsigned int exception)
 | |
| {
 | |
|     if ((firstExact == exception) || (secondExact == exception))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (firstExact == secondExact)
 | |
|         return TRUE;
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| DetailSupersedesSecond(DetailRec firstDetail,
 | |
|                        DetailRec secondDetail, unsigned int exception)
 | |
| {
 | |
|     if (IsInGrabMask(firstDetail, secondDetail, exception))
 | |
|         return TRUE;
 | |
| 
 | |
|     if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, exception))
 | |
|         return TRUE;
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
 | |
| {
 | |
|     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
 | |
|         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
 | |
|     if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
 | |
|                                 pSecondGrab->modifiersDetail, any_modifier))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (DetailSupersedesSecond(pFirstGrab->detail,
 | |
|                                pSecondGrab->detail, (unsigned int) AnyKey))
 | |
|         return TRUE;
 | |
| 
 | |
|     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, Bool ignoreDevice)
 | |
| {
 | |
|     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
 | |
|         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
 | |
| 
 | |
|     if (pFirstGrab->grabtype != pSecondGrab->grabtype)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (pFirstGrab->grabtype == XI2) {
 | |
|         if (pFirstGrab->device == inputInfo.all_devices ||
 | |
|             pSecondGrab->device == inputInfo.all_devices) {
 | |
|             /* do nothing */
 | |
|         }
 | |
|         else if (pFirstGrab->device == inputInfo.all_master_devices) {
 | |
|             if (pSecondGrab->device != inputInfo.all_master_devices &&
 | |
|                 !IsMaster(pSecondGrab->device))
 | |
|                 return FALSE;
 | |
|         }
 | |
|         else if (pSecondGrab->device == inputInfo.all_master_devices) {
 | |
|             if (pFirstGrab->device != inputInfo.all_master_devices &&
 | |
|                 !IsMaster(pFirstGrab->device))
 | |
|                 return FALSE;
 | |
|         }
 | |
|         else if (pSecondGrab->device != pFirstGrab->device)
 | |
|             return FALSE;
 | |
|     }
 | |
|     else if (!ignoreDevice &&
 | |
|              ((pFirstGrab->device != pSecondGrab->device) ||
 | |
|               (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (pFirstGrab->type != pSecondGrab->type)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
 | |
|         GrabSupersedesSecond(pSecondGrab, pFirstGrab))
 | |
|         return TRUE;
 | |
| 
 | |
|     if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
 | |
|                                (unsigned int) AnyKey)
 | |
|         &&
 | |
|         DetailSupersedesSecond(pFirstGrab->modifiersDetail,
 | |
|                                pSecondGrab->modifiersDetail, any_modifier))
 | |
|         return TRUE;
 | |
| 
 | |
|     if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
 | |
|                                (unsigned int) AnyKey)
 | |
|         &&
 | |
|         DetailSupersedesSecond(pSecondGrab->modifiersDetail,
 | |
|                                pFirstGrab->modifiersDetail, any_modifier))
 | |
|         return TRUE;
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
 | |
| {
 | |
|     unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ?
 | |
|         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
 | |
| 
 | |
|     if (pFirstGrab->grabtype != pSecondGrab->grabtype)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (pFirstGrab->device != pSecondGrab->device ||
 | |
|         (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
 | |
|         (pFirstGrab->type != pSecondGrab->type))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!(DetailSupersedesSecond(pFirstGrab->detail,
 | |
|                                  pSecondGrab->detail,
 | |
|                                  (unsigned int) AnyKey) &&
 | |
|           DetailSupersedesSecond(pSecondGrab->detail,
 | |
|                                  pFirstGrab->detail, (unsigned int) AnyKey)))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
 | |
|                                  pSecondGrab->modifiersDetail,
 | |
|                                  any_modifier) &&
 | |
|           DetailSupersedesSecond(pSecondGrab->modifiersDetail,
 | |
|                                  pFirstGrab->modifiersDetail, any_modifier)))
 | |
|         return FALSE;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Prepend the new grab to the list of passive grabs on the window.
 | |
|  * Any previously existing grab that matches the new grab will be removed.
 | |
|  * Adding a new grab that would override another client's grab will result in
 | |
|  * a BadAccess.
 | |
|  * 
 | |
|  * @return Success or X error code on failure.
 | |
|  */
 | |
| int
 | |
| AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
 | |
| {
 | |
|     GrabPtr grab;
 | |
|     Mask access_mode = DixGrabAccess;
 | |
|     int rc;
 | |
| 
 | |
|     for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
 | |
|         if (GrabMatchesSecond(pGrab, grab, (pGrab->grabtype == CORE))) {
 | |
|             if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) {
 | |
|                 FreeGrab(pGrab);
 | |
|                 return BadAccess;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (pGrab->keyboardMode == GrabModeSync ||
 | |
|         pGrab->pointerMode == GrabModeSync)
 | |
|         access_mode |= DixFreezeAccess;
 | |
|     rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     /* Remove all grabs that match the new one exactly */
 | |
|     for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) {
 | |
|         if (GrabsAreIdentical(pGrab, grab)) {
 | |
|             DeletePassiveGrabFromList(grab);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!pGrab->window->optional && !MakeWindowOptional(pGrab->window)) {
 | |
|         FreeGrab(pGrab);
 | |
|         return BadAlloc;
 | |
|     }
 | |
| 
 | |
|     pGrab->next = pGrab->window->optional->passiveGrabs;
 | |
|     pGrab->window->optional->passiveGrabs = pGrab;
 | |
|     if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (void *) pGrab))
 | |
|         return Success;
 | |
|     return BadAlloc;
 | |
| }
 | |
| 
 | |
| /* the following is kinda complicated, because we need to be able to back out
 | |
|  * if any allocation fails
 | |
|  */
 | |
| 
 | |
| Bool
 | |
| DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
 | |
| {
 | |
|     GrabPtr grab;
 | |
|     GrabPtr *deletes, *adds;
 | |
|     Mask ***updates, **details;
 | |
|     int i, ndels, nadds, nups;
 | |
|     Bool ok;
 | |
|     unsigned int any_modifier;
 | |
|     unsigned int any_key;
 | |
| 
 | |
| #define UPDATE(mask,exact) \
 | |
| 	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
 | |
| 	  ok = FALSE; \
 | |
| 	else \
 | |
| 	  updates[nups++] = &(mask)
 | |
| 
 | |
|     i = 0;
 | |
|     for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
 | |
|         i++;
 | |
|     if (!i)
 | |
|         return TRUE;
 | |
|     deletes = malloc(i * sizeof(GrabPtr));
 | |
|     adds = malloc(i * sizeof(GrabPtr));
 | |
|     updates = malloc(i * sizeof(Mask **));
 | |
|     details = malloc(i * sizeof(Mask *));
 | |
|     if (!deletes || !adds || !updates || !details) {
 | |
|         free(details);
 | |
|         free(updates);
 | |
|         free(adds);
 | |
|         free(deletes);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     any_modifier = (pMinuendGrab->grabtype == XI2) ?
 | |
|         (unsigned int) XIAnyModifier : (unsigned int) AnyModifier;
 | |
|     any_key = (pMinuendGrab->grabtype == XI2) ?
 | |
|         (unsigned int) XIAnyKeycode : (unsigned int) AnyKey;
 | |
|     ndels = nadds = nups = 0;
 | |
|     ok = TRUE;
 | |
|     for (grab = wPassiveGrabs(pMinuendGrab->window);
 | |
|          grab && ok; grab = grab->next) {
 | |
|         if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource))
 | |
|             || !GrabMatchesSecond(grab, pMinuendGrab, (grab->grabtype == CORE)))
 | |
|             continue;
 | |
|         if (GrabSupersedesSecond(pMinuendGrab, grab)) {
 | |
|             deletes[ndels++] = grab;
 | |
|         }
 | |
|         else if ((grab->detail.exact == any_key)
 | |
|                  && (grab->modifiersDetail.exact != any_modifier)) {
 | |
|             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
 | |
|         }
 | |
|         else if ((grab->modifiersDetail.exact == any_modifier)
 | |
|                  && (grab->detail.exact != any_key)) {
 | |
|             UPDATE(grab->modifiersDetail.pMask,
 | |
|                    pMinuendGrab->modifiersDetail.exact);
 | |
|         }
 | |
|         else if ((pMinuendGrab->detail.exact != any_key)
 | |
|                  && (pMinuendGrab->modifiersDetail.exact != any_modifier)) {
 | |
|             GrabPtr pNewGrab;
 | |
|             GrabParameters param;
 | |
| 
 | |
|             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
 | |
| 
 | |
|             memset(¶m, 0, sizeof(param));
 | |
|             param.ownerEvents = grab->ownerEvents;
 | |
|             param.this_device_mode = grab->keyboardMode;
 | |
|             param.other_devices_mode = grab->pointerMode;
 | |
|             param.modifiers = any_modifier;
 | |
| 
 | |
|             pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
 | |
|                                   grab->modifierDevice, grab->window,
 | |
|                                   grab->grabtype,
 | |
|                                   (GrabMask *) &grab->eventMask,
 | |
|                                   ¶m, (int) grab->type,
 | |
|                                   pMinuendGrab->detail.exact,
 | |
|                                   grab->confineTo, grab->cursor);
 | |
|             if (!pNewGrab)
 | |
|                 ok = FALSE;
 | |
|             else if (!(pNewGrab->modifiersDetail.pMask =
 | |
|                        DeleteDetailFromMask(grab->modifiersDetail.pMask,
 | |
|                                             pMinuendGrab->modifiersDetail.
 | |
|                                             exact))
 | |
|                      || (!pNewGrab->window->optional &&
 | |
|                          !MakeWindowOptional(pNewGrab->window))) {
 | |
|                 FreeGrab(pNewGrab);
 | |
|                 ok = FALSE;
 | |
|             }
 | |
|             else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
 | |
|                                   (void *) pNewGrab))
 | |
|                 ok = FALSE;
 | |
|             else
 | |
|                 adds[nadds++] = pNewGrab;
 | |
|         }
 | |
|         else if (pMinuendGrab->detail.exact == any_key) {
 | |
|             UPDATE(grab->modifiersDetail.pMask,
 | |
|                    pMinuendGrab->modifiersDetail.exact);
 | |
|         }
 | |
|         else {
 | |
|             UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!ok) {
 | |
|         for (i = 0; i < nadds; i++)
 | |
|             FreeResource(adds[i]->resource, RT_NONE);
 | |
|         for (i = 0; i < nups; i++)
 | |
|             free(details[i]);
 | |
|     }
 | |
|     else {
 | |
|         for (i = 0; i < ndels; i++)
 | |
|             FreeResource(deletes[i]->resource, RT_NONE);
 | |
|         for (i = 0; i < nadds; i++) {
 | |
|             grab = adds[i];
 | |
|             grab->next = grab->window->optional->passiveGrabs;
 | |
|             grab->window->optional->passiveGrabs = grab;
 | |
|         }
 | |
|         for (i = 0; i < nups; i++) {
 | |
|             free(*updates[i]);
 | |
|             *updates[i] = details[i];
 | |
|         }
 | |
|     }
 | |
|     free(details);
 | |
|     free(updates);
 | |
|     free(adds);
 | |
|     free(deletes);
 | |
|     return ok;
 | |
| 
 | |
| #undef UPDATE
 | |
| }
 | |
| 
 | |
| Bool
 | |
| GrabIsPointerGrab(GrabPtr grab)
 | |
| {
 | |
|     return (grab->type == ButtonPress ||
 | |
|             grab->type == DeviceButtonPress || grab->type == XI_ButtonPress);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| GrabIsKeyboardGrab(GrabPtr grab)
 | |
| {
 | |
|     return (grab->type == KeyPress ||
 | |
|             grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
 | |
| }
 |