1706f2543Smrg/*
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included
12706f2543Smrgin all copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17706f2543SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543SmrgOTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg
22706f2543SmrgExcept as contained in this notice, the name of The Open Group shall
23706f2543Smrgnot be used in advertising or otherwise to promote the sale, use or
24706f2543Smrgother dealings in this Software without prior written authorization
25706f2543Smrgfrom The Open Group.
26706f2543Smrg
27706f2543Smrg
28706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
29706f2543Smrg
30706f2543Smrg                        All Rights Reserved
31706f2543Smrg
32706f2543SmrgPermission to use, copy, modify, and distribute this software and its
33706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
34706f2543Smrgprovided that the above copyright notice appear in all copies and that
35706f2543Smrgboth that copyright notice and this permission notice appear in
36706f2543Smrgsupporting documentation, and that the name of Digital not be
37706f2543Smrgused in advertising or publicity pertaining to distribution of the
38706f2543Smrgsoftware without specific, written prior permission.
39706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43706f2543SmrgWHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45706f2543SmrgSOFTWARE.
46706f2543Smrg
47706f2543Smrg*/
48706f2543Smrg
49706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
50706f2543Smrg#include <dix-config.h>
51706f2543Smrg#endif
52706f2543Smrg
53706f2543Smrg#include <X11/X.h>
54706f2543Smrg#include "misc.h"
55706f2543Smrg#include <X11/Xproto.h>
56706f2543Smrg#include <X11/extensions/XI2.h>
57706f2543Smrg#include "windowstr.h"
58706f2543Smrg#include "inputstr.h"
59706f2543Smrg#include "cursorstr.h"
60706f2543Smrg#include "dixgrabs.h"
61706f2543Smrg#include "xace.h"
62706f2543Smrg#include "exevents.h"
63706f2543Smrg
64706f2543Smrg#define BITMASK(i) (((Mask)1) << ((i) & 31))
65706f2543Smrg#define MASKIDX(i) ((i) >> 5)
66706f2543Smrg#define MASKWORD(buf, i) buf[MASKIDX(i)]
67706f2543Smrg#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
68706f2543Smrg#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
69706f2543Smrg#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
70706f2543Smrg
71706f2543SmrgGrabPtr
72706f2543SmrgCreateGrab(
73706f2543Smrg    int client,
74706f2543Smrg    DeviceIntPtr device,
75706f2543Smrg    DeviceIntPtr modDevice,
76706f2543Smrg    WindowPtr window,
77706f2543Smrg    GrabType grabtype,
78706f2543Smrg    GrabMask *mask,
79706f2543Smrg    GrabParameters *param,
80706f2543Smrg    int type,
81706f2543Smrg    KeyCode keybut,	/* key or button */
82706f2543Smrg    WindowPtr confineTo,
83706f2543Smrg    CursorPtr cursor)
84706f2543Smrg{
85706f2543Smrg    GrabPtr grab;
86706f2543Smrg
87706f2543Smrg    grab = calloc(1, sizeof(GrabRec));
88706f2543Smrg    if (!grab)
89706f2543Smrg	return (GrabPtr)NULL;
90706f2543Smrg    grab->resource = FakeClientID(client);
91706f2543Smrg    grab->device = device;
92706f2543Smrg    grab->window = window;
93706f2543Smrg    grab->eventMask = mask->core; /* same for XI */
94706f2543Smrg    grab->deviceMask = 0;
95706f2543Smrg    grab->ownerEvents = param->ownerEvents;
96706f2543Smrg    grab->keyboardMode = param->this_device_mode;
97706f2543Smrg    grab->pointerMode = param->other_devices_mode;
98706f2543Smrg    grab->modifiersDetail.exact = param->modifiers;
99706f2543Smrg    grab->modifiersDetail.pMask = NULL;
100706f2543Smrg    grab->modifierDevice = modDevice;
101706f2543Smrg    grab->type = type;
102706f2543Smrg    grab->grabtype = grabtype;
103706f2543Smrg    grab->detail.exact = keybut;
104706f2543Smrg    grab->detail.pMask = NULL;
105706f2543Smrg    grab->confineTo = confineTo;
106706f2543Smrg    grab->cursor = cursor;
107706f2543Smrg    grab->next = NULL;
108706f2543Smrg
109706f2543Smrg    if (grabtype == GRABTYPE_XI2)
110706f2543Smrg        memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask));
111706f2543Smrg    if (cursor)
112706f2543Smrg	cursor->refcnt++;
113706f2543Smrg    return grab;
114706f2543Smrg
115706f2543Smrg}
116706f2543Smrg
117706f2543Smrgstatic void
118706f2543SmrgFreeGrab(GrabPtr pGrab)
119706f2543Smrg{
120706f2543Smrg    free(pGrab->modifiersDetail.pMask);
121706f2543Smrg    free(pGrab->detail.pMask);
122706f2543Smrg
123706f2543Smrg    if (pGrab->cursor)
124706f2543Smrg	FreeCursor(pGrab->cursor, (Cursor)0);
125706f2543Smrg
126706f2543Smrg    free(pGrab);
127706f2543Smrg}
128706f2543Smrg
129706f2543Smrgint
130706f2543SmrgDeletePassiveGrab(pointer value, XID id)
131706f2543Smrg{
132706f2543Smrg    GrabPtr g, prev;
133706f2543Smrg    GrabPtr pGrab = (GrabPtr)value;
134706f2543Smrg
135706f2543Smrg    /* it is OK if the grab isn't found */
136706f2543Smrg    prev = 0;
137706f2543Smrg    for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
138706f2543Smrg    {
139706f2543Smrg	if (pGrab == g)
140706f2543Smrg	{
141706f2543Smrg	    if (prev)
142706f2543Smrg		prev->next = g->next;
143706f2543Smrg	    else
144706f2543Smrg		if (!(pGrab->window->optional->passiveGrabs = g->next))
145706f2543Smrg		    CheckWindowOptionalNeed (pGrab->window);
146706f2543Smrg	    break;
147706f2543Smrg	}
148706f2543Smrg	prev = g;
149706f2543Smrg    }
150706f2543Smrg    FreeGrab(pGrab);
151706f2543Smrg    return Success;
152706f2543Smrg}
153706f2543Smrg
154706f2543Smrgstatic Mask *
155706f2543SmrgDeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
156706f2543Smrg{
157706f2543Smrg    Mask *mask;
158706f2543Smrg    int i;
159706f2543Smrg
160706f2543Smrg    mask = malloc(sizeof(Mask) * MasksPerDetailMask);
161706f2543Smrg    if (mask)
162706f2543Smrg    {
163706f2543Smrg	if (pDetailMask)
164706f2543Smrg	    for (i = 0; i < MasksPerDetailMask; i++)
165706f2543Smrg		mask[i]= pDetailMask[i];
166706f2543Smrg	else
167706f2543Smrg	    for (i = 0; i < MasksPerDetailMask; i++)
168706f2543Smrg		mask[i]= ~0L;
169706f2543Smrg	BITCLEAR(mask, detail);
170706f2543Smrg    }
171706f2543Smrg    return mask;
172706f2543Smrg}
173706f2543Smrg
174706f2543Smrgstatic Bool
175706f2543SmrgIsInGrabMask(
176706f2543Smrg    DetailRec firstDetail,
177706f2543Smrg    DetailRec secondDetail,
178706f2543Smrg    unsigned int exception)
179706f2543Smrg{
180706f2543Smrg    if (firstDetail.exact == exception)
181706f2543Smrg    {
182706f2543Smrg	if (firstDetail.pMask == NULL)
183706f2543Smrg	    return TRUE;
184706f2543Smrg
185706f2543Smrg	/* (at present) never called with two non-null pMasks */
186706f2543Smrg	if (secondDetail.exact == exception)
187706f2543Smrg	    return FALSE;
188706f2543Smrg
189706f2543Smrg 	if (GETBIT(firstDetail.pMask, secondDetail.exact))
190706f2543Smrg	    return TRUE;
191706f2543Smrg    }
192706f2543Smrg
193706f2543Smrg    return FALSE;
194706f2543Smrg}
195706f2543Smrg
196706f2543Smrgstatic Bool
197706f2543SmrgIdenticalExactDetails(
198706f2543Smrg    unsigned int firstExact,
199706f2543Smrg    unsigned int secondExact,
200706f2543Smrg    unsigned int exception)
201706f2543Smrg{
202706f2543Smrg    if ((firstExact == exception) || (secondExact == exception))
203706f2543Smrg	return FALSE;
204706f2543Smrg
205706f2543Smrg    if (firstExact == secondExact)
206706f2543Smrg	return TRUE;
207706f2543Smrg
208706f2543Smrg    return FALSE;
209706f2543Smrg}
210706f2543Smrg
211706f2543Smrgstatic Bool
212706f2543SmrgDetailSupersedesSecond(
213706f2543Smrg    DetailRec firstDetail,
214706f2543Smrg    DetailRec secondDetail,
215706f2543Smrg    unsigned int exception)
216706f2543Smrg{
217706f2543Smrg    if (IsInGrabMask(firstDetail, secondDetail, exception))
218706f2543Smrg	return TRUE;
219706f2543Smrg
220706f2543Smrg    if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
221706f2543Smrg			      exception))
222706f2543Smrg	return TRUE;
223706f2543Smrg
224706f2543Smrg    return FALSE;
225706f2543Smrg}
226706f2543Smrg
227706f2543Smrgstatic Bool
228706f2543SmrgGrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
229706f2543Smrg{
230706f2543Smrg    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
231706f2543Smrg                                (unsigned int)XIAnyModifier :
232706f2543Smrg                                (unsigned int)AnyModifier;
233706f2543Smrg    if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
234706f2543Smrg				pSecondGrab->modifiersDetail,
235706f2543Smrg				any_modifier))
236706f2543Smrg	return FALSE;
237706f2543Smrg
238706f2543Smrg    if (DetailSupersedesSecond(pFirstGrab->detail,
239706f2543Smrg			       pSecondGrab->detail, (unsigned int)AnyKey))
240706f2543Smrg	return TRUE;
241706f2543Smrg
242706f2543Smrg    return FALSE;
243706f2543Smrg}
244706f2543Smrg
245706f2543Smrg/**
246706f2543Smrg * Compares two grabs and returns TRUE if the first grab matches the second
247706f2543Smrg * grab.
248706f2543Smrg *
249706f2543Smrg * A match is when
250706f2543Smrg *  - the devices set for the grab are equal (this is optional).
251706f2543Smrg *  - the event types for both grabs are equal.
252706f2543Smrg *  - XXX
253706f2543Smrg *
254706f2543Smrg * @param ignoreDevice TRUE if the device settings on the grabs are to be
255706f2543Smrg * ignored.
256706f2543Smrg * @return TRUE if the grabs match or FALSE otherwise.
257706f2543Smrg */
258706f2543SmrgBool
259706f2543SmrgGrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
260706f2543Smrg{
261706f2543Smrg    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
262706f2543Smrg                                (unsigned int)XIAnyModifier :
263706f2543Smrg                                (unsigned int)AnyModifier;
264706f2543Smrg
265706f2543Smrg    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
266706f2543Smrg        return FALSE;
267706f2543Smrg
268706f2543Smrg    if (pFirstGrab->grabtype == GRABTYPE_XI2)
269706f2543Smrg    {
270706f2543Smrg        if (pFirstGrab->device == inputInfo.all_devices ||
271706f2543Smrg            pSecondGrab->device == inputInfo.all_devices)
272706f2543Smrg        {
273706f2543Smrg            /* do nothing */
274706f2543Smrg        } else if (pFirstGrab->device == inputInfo.all_master_devices)
275706f2543Smrg        {
276706f2543Smrg            if (pSecondGrab->device != inputInfo.all_master_devices &&
277706f2543Smrg                !IsMaster(pSecondGrab->device))
278706f2543Smrg                return FALSE;
279706f2543Smrg        } else if (pSecondGrab->device == inputInfo.all_master_devices)
280706f2543Smrg        {
281706f2543Smrg            if (pFirstGrab->device != inputInfo.all_master_devices &&
282706f2543Smrg                !IsMaster(pFirstGrab->device))
283706f2543Smrg                return FALSE;
284706f2543Smrg        } else if (pSecondGrab->device != pFirstGrab->device)
285706f2543Smrg            return FALSE;
286706f2543Smrg    } else if (!ignoreDevice &&
287706f2543Smrg            ((pFirstGrab->device != pSecondGrab->device) ||
288706f2543Smrg             (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
289706f2543Smrg            return FALSE;
290706f2543Smrg
291706f2543Smrg    if (pFirstGrab->type != pSecondGrab->type)
292706f2543Smrg	return FALSE;
293706f2543Smrg
294706f2543Smrg    if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
295706f2543Smrg	GrabSupersedesSecond(pSecondGrab, pFirstGrab))
296706f2543Smrg	return TRUE;
297706f2543Smrg
298706f2543Smrg    if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
299706f2543Smrg			       (unsigned int)AnyKey)
300706f2543Smrg	&&
301706f2543Smrg	DetailSupersedesSecond(pFirstGrab->modifiersDetail,
302706f2543Smrg			       pSecondGrab->modifiersDetail,
303706f2543Smrg			       any_modifier))
304706f2543Smrg	return TRUE;
305706f2543Smrg
306706f2543Smrg    if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
307706f2543Smrg			       (unsigned int)AnyKey)
308706f2543Smrg	&&
309706f2543Smrg	DetailSupersedesSecond(pSecondGrab->modifiersDetail,
310706f2543Smrg			       pFirstGrab->modifiersDetail,
311706f2543Smrg			       any_modifier))
312706f2543Smrg	return TRUE;
313706f2543Smrg
314706f2543Smrg    return FALSE;
315706f2543Smrg}
316706f2543Smrg
317706f2543Smrgstatic Bool
318706f2543SmrgGrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
319706f2543Smrg{
320706f2543Smrg    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
321706f2543Smrg                                (unsigned int)XIAnyModifier :
322706f2543Smrg                                (unsigned int)AnyModifier;
323706f2543Smrg
324706f2543Smrg    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
325706f2543Smrg        return FALSE;
326706f2543Smrg
327706f2543Smrg    if (pFirstGrab->device != pSecondGrab->device ||
328706f2543Smrg	(pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
329706f2543Smrg	(pFirstGrab->type != pSecondGrab->type))
330706f2543Smrg	return FALSE;
331706f2543Smrg
332706f2543Smrg    if (!(DetailSupersedesSecond(pFirstGrab->detail,
333706f2543Smrg                               pSecondGrab->detail,
334706f2543Smrg                               (unsigned int)AnyKey) &&
335706f2543Smrg        DetailSupersedesSecond(pSecondGrab->detail,
336706f2543Smrg                               pFirstGrab->detail,
337706f2543Smrg                               (unsigned int)AnyKey)))
338706f2543Smrg        return FALSE;
339706f2543Smrg
340706f2543Smrg
341706f2543Smrg    if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
342706f2543Smrg                               pSecondGrab->modifiersDetail,
343706f2543Smrg                               any_modifier) &&
344706f2543Smrg        DetailSupersedesSecond(pSecondGrab->modifiersDetail,
345706f2543Smrg                               pFirstGrab->modifiersDetail,
346706f2543Smrg                               any_modifier)))
347706f2543Smrg        return FALSE;
348706f2543Smrg
349706f2543Smrg    return TRUE;
350706f2543Smrg}
351706f2543Smrg
352706f2543Smrg
353706f2543Smrg/**
354706f2543Smrg * Prepend the new grab to the list of passive grabs on the window.
355706f2543Smrg * Any previously existing grab that matches the new grab will be removed.
356706f2543Smrg * Adding a new grab that would override another client's grab will result in
357706f2543Smrg * a BadAccess.
358706f2543Smrg *
359706f2543Smrg * @return Success or X error code on failure.
360706f2543Smrg */
361706f2543Smrgint
362706f2543SmrgAddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
363706f2543Smrg{
364706f2543Smrg    GrabPtr grab;
365706f2543Smrg    Mask access_mode = DixGrabAccess;
366706f2543Smrg    int rc;
367706f2543Smrg
368706f2543Smrg    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
369706f2543Smrg    {
370706f2543Smrg	if (GrabMatchesSecond(pGrab, grab, FALSE))
371706f2543Smrg	{
372706f2543Smrg	    if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
373706f2543Smrg	    {
374706f2543Smrg		FreeGrab(pGrab);
375706f2543Smrg		return BadAccess;
376706f2543Smrg	    }
377706f2543Smrg	}
378706f2543Smrg    }
379706f2543Smrg
380706f2543Smrg    if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
381706f2543Smrg	access_mode |= DixFreezeAccess;
382706f2543Smrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
383706f2543Smrg    if (rc != Success)
384706f2543Smrg	return rc;
385706f2543Smrg
386706f2543Smrg    /* Remove all grabs that match the new one exactly */
387706f2543Smrg    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
388706f2543Smrg    {
389706f2543Smrg	if (GrabsAreIdentical(pGrab, grab))
390706f2543Smrg	{
391706f2543Smrg            DeletePassiveGrabFromList(grab);
392706f2543Smrg            break;
393706f2543Smrg	}
394706f2543Smrg    }
395706f2543Smrg
396706f2543Smrg    if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
397706f2543Smrg    {
398706f2543Smrg	FreeGrab(pGrab);
399706f2543Smrg	return BadAlloc;
400706f2543Smrg    }
401706f2543Smrg
402706f2543Smrg    pGrab->next = pGrab->window->optional->passiveGrabs;
403706f2543Smrg    pGrab->window->optional->passiveGrabs = pGrab;
404706f2543Smrg    if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
405706f2543Smrg	return Success;
406706f2543Smrg    return BadAlloc;
407706f2543Smrg}
408706f2543Smrg
409706f2543Smrg/* the following is kinda complicated, because we need to be able to back out
410706f2543Smrg * if any allocation fails
411706f2543Smrg */
412706f2543Smrg
413706f2543SmrgBool
414706f2543SmrgDeletePassiveGrabFromList(GrabPtr pMinuendGrab)
415706f2543Smrg{
416706f2543Smrg    GrabPtr grab;
417706f2543Smrg    GrabPtr *deletes, *adds;
418706f2543Smrg    Mask ***updates, **details;
419706f2543Smrg    int i, ndels, nadds, nups;
420706f2543Smrg    Bool ok;
421706f2543Smrg    unsigned int any_modifier;
422706f2543Smrg    unsigned int any_key;
423706f2543Smrg
424706f2543Smrg#define UPDATE(mask,exact) \
425706f2543Smrg	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
426706f2543Smrg	  ok = FALSE; \
427706f2543Smrg	else \
428706f2543Smrg	  updates[nups++] = &(mask)
429706f2543Smrg
430706f2543Smrg    i = 0;
431706f2543Smrg    for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
432706f2543Smrg	i++;
433706f2543Smrg    if (!i)
434706f2543Smrg	return TRUE;
435706f2543Smrg    deletes = malloc(i * sizeof(GrabPtr));
436706f2543Smrg    adds = malloc(i * sizeof(GrabPtr));
437706f2543Smrg    updates = malloc(i * sizeof(Mask **));
438706f2543Smrg    details = malloc(i * sizeof(Mask *));
439706f2543Smrg    if (!deletes || !adds || !updates || !details)
440706f2543Smrg    {
441706f2543Smrg	free(details);
442706f2543Smrg	free(updates);
443706f2543Smrg	free(adds);
444706f2543Smrg	free(deletes);
445706f2543Smrg	return FALSE;
446706f2543Smrg    }
447706f2543Smrg
448706f2543Smrg    any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
449706f2543Smrg                   (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
450706f2543Smrg    any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
451706f2543Smrg                   (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
452706f2543Smrg    ndels = nadds = nups = 0;
453706f2543Smrg    ok = TRUE;
454706f2543Smrg    for (grab = wPassiveGrabs(pMinuendGrab->window);
455706f2543Smrg	 grab && ok;
456706f2543Smrg	 grab = grab->next)
457706f2543Smrg    {
458706f2543Smrg	if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
459706f2543Smrg	    !GrabMatchesSecond(grab, pMinuendGrab,
460706f2543Smrg                               (grab->grabtype == GRABTYPE_CORE)))
461706f2543Smrg	    continue;
462706f2543Smrg	if (GrabSupersedesSecond(pMinuendGrab, grab))
463706f2543Smrg	{
464706f2543Smrg	    deletes[ndels++] = grab;
465706f2543Smrg	}
466706f2543Smrg	else if ((grab->detail.exact == any_key)
467706f2543Smrg		 && (grab->modifiersDetail.exact != any_modifier))
468706f2543Smrg	{
469706f2543Smrg	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
470706f2543Smrg	}
471706f2543Smrg	else if ((grab->modifiersDetail.exact == any_modifier)
472706f2543Smrg		 && (grab->detail.exact != any_key))
473706f2543Smrg	{
474706f2543Smrg	    UPDATE(grab->modifiersDetail.pMask,
475706f2543Smrg		   pMinuendGrab->modifiersDetail.exact);
476706f2543Smrg	}
477706f2543Smrg	else if ((pMinuendGrab->detail.exact != any_key)
478706f2543Smrg		 && (pMinuendGrab->modifiersDetail.exact != any_modifier))
479706f2543Smrg	{
480706f2543Smrg	    GrabPtr pNewGrab;
481706f2543Smrg            GrabParameters param;
482706f2543Smrg
483706f2543Smrg	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
484706f2543Smrg
485706f2543Smrg            memset(&param, 0, sizeof(param));
486706f2543Smrg            param.ownerEvents = grab->ownerEvents;
487706f2543Smrg            param.this_device_mode = grab->keyboardMode;
488706f2543Smrg            param.other_devices_mode = grab->pointerMode;
489706f2543Smrg            param.modifiers = any_modifier;
490706f2543Smrg
491706f2543Smrg	    pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
492706f2543Smrg				  grab->modifierDevice, grab->window,
493706f2543Smrg                                  grab->grabtype,
494706f2543Smrg				  (GrabMask*)&grab->eventMask,
495706f2543Smrg                                  &param, (int)grab->type,
496706f2543Smrg				  pMinuendGrab->detail.exact,
497706f2543Smrg				  grab->confineTo, grab->cursor);
498706f2543Smrg	    if (!pNewGrab)
499706f2543Smrg		ok = FALSE;
500706f2543Smrg	    else if (!(pNewGrab->modifiersDetail.pMask =
501706f2543Smrg		       DeleteDetailFromMask(grab->modifiersDetail.pMask,
502706f2543Smrg					 pMinuendGrab->modifiersDetail.exact))
503706f2543Smrg		     ||
504706f2543Smrg		     (!pNewGrab->window->optional &&
505706f2543Smrg		      !MakeWindowOptional(pNewGrab->window)))
506706f2543Smrg	    {
507706f2543Smrg		FreeGrab(pNewGrab);
508706f2543Smrg		ok = FALSE;
509706f2543Smrg	    }
510706f2543Smrg	    else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
511706f2543Smrg				  (pointer)pNewGrab))
512706f2543Smrg		ok = FALSE;
513706f2543Smrg	    else
514706f2543Smrg		adds[nadds++] = pNewGrab;
515706f2543Smrg	}
516706f2543Smrg	else if (pMinuendGrab->detail.exact == any_key)
517706f2543Smrg	{
518706f2543Smrg	    UPDATE(grab->modifiersDetail.pMask,
519706f2543Smrg		   pMinuendGrab->modifiersDetail.exact);
520706f2543Smrg	}
521706f2543Smrg	else
522706f2543Smrg	{
523706f2543Smrg	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
524706f2543Smrg	}
525706f2543Smrg    }
526706f2543Smrg
527706f2543Smrg    if (!ok)
528706f2543Smrg    {
529706f2543Smrg	for (i = 0; i < nadds; i++)
530706f2543Smrg	    FreeResource(adds[i]->resource, RT_NONE);
531706f2543Smrg	for (i = 0; i < nups; i++)
532706f2543Smrg	    free(details[i]);
533706f2543Smrg    }
534706f2543Smrg    else
535706f2543Smrg    {
536706f2543Smrg	for (i = 0; i < ndels; i++)
537706f2543Smrg	    FreeResource(deletes[i]->resource, RT_NONE);
538706f2543Smrg	for (i = 0; i < nadds; i++)
539706f2543Smrg	{
540706f2543Smrg	    grab = adds[i];
541706f2543Smrg	    grab->next = grab->window->optional->passiveGrabs;
542706f2543Smrg	    grab->window->optional->passiveGrabs = grab;
543706f2543Smrg	}
544706f2543Smrg	for (i = 0; i < nups; i++)
545706f2543Smrg	{
546706f2543Smrg	    free(*updates[i]);
547706f2543Smrg	    *updates[i] = details[i];
548706f2543Smrg	}
549706f2543Smrg    }
550706f2543Smrg    free(details);
551706f2543Smrg    free(updates);
552706f2543Smrg    free(adds);
553706f2543Smrg    free(deletes);
554706f2543Smrg    return ok;
555706f2543Smrg
556706f2543Smrg#undef UPDATE
557706f2543Smrg}
558