1/*
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27
28Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
29
30                        All Rights Reserved
31
32Permission to use, copy, modify, and distribute this software and its
33documentation for any purpose and without fee is hereby granted,
34provided that the above copyright notice appear in all copies and that
35both that copyright notice and this permission notice appear in
36supporting documentation, and that the name of Digital not be
37used in advertising or publicity pertaining to distribution of the
38software without specific, written prior permission.
39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45SOFTWARE.
46
47*/
48
49#ifdef HAVE_DIX_CONFIG_H
50#include <dix-config.h>
51#endif
52
53#include <X11/X.h>
54#include "misc.h"
55#include <X11/Xproto.h>
56#include <X11/extensions/XI2.h>
57#include "windowstr.h"
58#include "inputstr.h"
59#include "cursorstr.h"
60#include "dixgrabs.h"
61#include "xace.h"
62#include "exevents.h"
63
64#define BITMASK(i) (((Mask)1) << ((i) & 31))
65#define MASKIDX(i) ((i) >> 5)
66#define MASKWORD(buf, i) buf[MASKIDX(i)]
67#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
68#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
69#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
70
71GrabPtr
72CreateGrab(
73    int client,
74    DeviceIntPtr device,
75    DeviceIntPtr modDevice,
76    WindowPtr window,
77    GrabType grabtype,
78    GrabMask *mask,
79    GrabParameters *param,
80    int type,
81    KeyCode keybut,	/* key or button */
82    WindowPtr confineTo,
83    CursorPtr cursor)
84{
85    GrabPtr grab;
86
87    grab = calloc(1, sizeof(GrabRec));
88    if (!grab)
89	return (GrabPtr)NULL;
90    grab->resource = FakeClientID(client);
91    grab->device = device;
92    grab->window = window;
93    grab->eventMask = mask->core; /* same for XI */
94    grab->deviceMask = 0;
95    grab->ownerEvents = param->ownerEvents;
96    grab->keyboardMode = param->this_device_mode;
97    grab->pointerMode = param->other_devices_mode;
98    grab->modifiersDetail.exact = param->modifiers;
99    grab->modifiersDetail.pMask = NULL;
100    grab->modifierDevice = modDevice;
101    grab->type = type;
102    grab->grabtype = grabtype;
103    grab->detail.exact = keybut;
104    grab->detail.pMask = NULL;
105    grab->confineTo = confineTo;
106    grab->cursor = cursor;
107    grab->next = NULL;
108
109    if (grabtype == GRABTYPE_XI2)
110        memcpy(grab->xi2mask, mask->xi2mask, sizeof(mask->xi2mask));
111    if (cursor)
112	cursor->refcnt++;
113    return grab;
114
115}
116
117static void
118FreeGrab(GrabPtr pGrab)
119{
120    free(pGrab->modifiersDetail.pMask);
121    free(pGrab->detail.pMask);
122
123    if (pGrab->cursor)
124	FreeCursor(pGrab->cursor, (Cursor)0);
125
126    free(pGrab);
127}
128
129int
130DeletePassiveGrab(pointer value, XID id)
131{
132    GrabPtr g, prev;
133    GrabPtr pGrab = (GrabPtr)value;
134
135    /* it is OK if the grab isn't found */
136    prev = 0;
137    for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
138    {
139	if (pGrab == g)
140	{
141	    if (prev)
142		prev->next = g->next;
143	    else
144		if (!(pGrab->window->optional->passiveGrabs = g->next))
145		    CheckWindowOptionalNeed (pGrab->window);
146	    break;
147	}
148	prev = g;
149    }
150    FreeGrab(pGrab);
151    return Success;
152}
153
154static Mask *
155DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
156{
157    Mask *mask;
158    int i;
159
160    mask = malloc(sizeof(Mask) * MasksPerDetailMask);
161    if (mask)
162    {
163	if (pDetailMask)
164	    for (i = 0; i < MasksPerDetailMask; i++)
165		mask[i]= pDetailMask[i];
166	else
167	    for (i = 0; i < MasksPerDetailMask; i++)
168		mask[i]= ~0L;
169	BITCLEAR(mask, detail);
170    }
171    return mask;
172}
173
174static Bool
175IsInGrabMask(
176    DetailRec firstDetail,
177    DetailRec secondDetail,
178    unsigned int exception)
179{
180    if (firstDetail.exact == exception)
181    {
182	if (firstDetail.pMask == NULL)
183	    return TRUE;
184
185	/* (at present) never called with two non-null pMasks */
186	if (secondDetail.exact == exception)
187	    return FALSE;
188
189 	if (GETBIT(firstDetail.pMask, secondDetail.exact))
190	    return TRUE;
191    }
192
193    return FALSE;
194}
195
196static Bool
197IdenticalExactDetails(
198    unsigned int firstExact,
199    unsigned int secondExact,
200    unsigned int exception)
201{
202    if ((firstExact == exception) || (secondExact == exception))
203	return FALSE;
204
205    if (firstExact == secondExact)
206	return TRUE;
207
208    return FALSE;
209}
210
211static Bool
212DetailSupersedesSecond(
213    DetailRec firstDetail,
214    DetailRec secondDetail,
215    unsigned int exception)
216{
217    if (IsInGrabMask(firstDetail, secondDetail, exception))
218	return TRUE;
219
220    if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
221			      exception))
222	return TRUE;
223
224    return FALSE;
225}
226
227static Bool
228GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
229{
230    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
231                                (unsigned int)XIAnyModifier :
232                                (unsigned int)AnyModifier;
233    if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
234				pSecondGrab->modifiersDetail,
235				any_modifier))
236	return FALSE;
237
238    if (DetailSupersedesSecond(pFirstGrab->detail,
239			       pSecondGrab->detail, (unsigned int)AnyKey))
240	return TRUE;
241
242    return FALSE;
243}
244
245/**
246 * Compares two grabs and returns TRUE if the first grab matches the second
247 * grab.
248 *
249 * A match is when
250 *  - the devices set for the grab are equal (this is optional).
251 *  - the event types for both grabs are equal.
252 *  - XXX
253 *
254 * @param ignoreDevice TRUE if the device settings on the grabs are to be
255 * ignored.
256 * @return TRUE if the grabs match or FALSE otherwise.
257 */
258Bool
259GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
260{
261    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
262                                (unsigned int)XIAnyModifier :
263                                (unsigned int)AnyModifier;
264
265    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
266        return FALSE;
267
268    if (pFirstGrab->grabtype == GRABTYPE_XI2)
269    {
270        if (pFirstGrab->device == inputInfo.all_devices ||
271            pSecondGrab->device == inputInfo.all_devices)
272        {
273            /* do nothing */
274        } else if (pFirstGrab->device == inputInfo.all_master_devices)
275        {
276            if (pSecondGrab->device != inputInfo.all_master_devices &&
277                !IsMaster(pSecondGrab->device))
278                return FALSE;
279        } else if (pSecondGrab->device == inputInfo.all_master_devices)
280        {
281            if (pFirstGrab->device != inputInfo.all_master_devices &&
282                !IsMaster(pFirstGrab->device))
283                return FALSE;
284        } else if (pSecondGrab->device != pFirstGrab->device)
285            return FALSE;
286    } else if (!ignoreDevice &&
287            ((pFirstGrab->device != pSecondGrab->device) ||
288             (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
289            return FALSE;
290
291    if (pFirstGrab->type != pSecondGrab->type)
292	return FALSE;
293
294    if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
295	GrabSupersedesSecond(pSecondGrab, pFirstGrab))
296	return TRUE;
297
298    if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
299			       (unsigned int)AnyKey)
300	&&
301	DetailSupersedesSecond(pFirstGrab->modifiersDetail,
302			       pSecondGrab->modifiersDetail,
303			       any_modifier))
304	return TRUE;
305
306    if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
307			       (unsigned int)AnyKey)
308	&&
309	DetailSupersedesSecond(pSecondGrab->modifiersDetail,
310			       pFirstGrab->modifiersDetail,
311			       any_modifier))
312	return TRUE;
313
314    return FALSE;
315}
316
317static Bool
318GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
319{
320    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
321                                (unsigned int)XIAnyModifier :
322                                (unsigned int)AnyModifier;
323
324    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
325        return FALSE;
326
327    if (pFirstGrab->device != pSecondGrab->device ||
328	(pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
329	(pFirstGrab->type != pSecondGrab->type))
330	return FALSE;
331
332    if (!(DetailSupersedesSecond(pFirstGrab->detail,
333                               pSecondGrab->detail,
334                               (unsigned int)AnyKey) &&
335        DetailSupersedesSecond(pSecondGrab->detail,
336                               pFirstGrab->detail,
337                               (unsigned int)AnyKey)))
338        return FALSE;
339
340
341    if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
342                               pSecondGrab->modifiersDetail,
343                               any_modifier) &&
344        DetailSupersedesSecond(pSecondGrab->modifiersDetail,
345                               pFirstGrab->modifiersDetail,
346                               any_modifier)))
347        return FALSE;
348
349    return TRUE;
350}
351
352
353/**
354 * Prepend the new grab to the list of passive grabs on the window.
355 * Any previously existing grab that matches the new grab will be removed.
356 * Adding a new grab that would override another client's grab will result in
357 * a BadAccess.
358 *
359 * @return Success or X error code on failure.
360 */
361int
362AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
363{
364    GrabPtr grab;
365    Mask access_mode = DixGrabAccess;
366    int rc;
367
368    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
369    {
370	if (GrabMatchesSecond(pGrab, grab, FALSE))
371	{
372	    if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
373	    {
374		FreeGrab(pGrab);
375		return BadAccess;
376	    }
377	}
378    }
379
380    if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
381	access_mode |= DixFreezeAccess;
382    rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
383    if (rc != Success)
384	return rc;
385
386    /* Remove all grabs that match the new one exactly */
387    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
388    {
389	if (GrabsAreIdentical(pGrab, grab))
390	{
391            DeletePassiveGrabFromList(grab);
392            break;
393	}
394    }
395
396    if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
397    {
398	FreeGrab(pGrab);
399	return BadAlloc;
400    }
401
402    pGrab->next = pGrab->window->optional->passiveGrabs;
403    pGrab->window->optional->passiveGrabs = pGrab;
404    if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
405	return Success;
406    return BadAlloc;
407}
408
409/* the following is kinda complicated, because we need to be able to back out
410 * if any allocation fails
411 */
412
413Bool
414DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
415{
416    GrabPtr grab;
417    GrabPtr *deletes, *adds;
418    Mask ***updates, **details;
419    int i, ndels, nadds, nups;
420    Bool ok;
421    unsigned int any_modifier;
422    unsigned int any_key;
423
424#define UPDATE(mask,exact) \
425	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
426	  ok = FALSE; \
427	else \
428	  updates[nups++] = &(mask)
429
430    i = 0;
431    for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
432	i++;
433    if (!i)
434	return TRUE;
435    deletes = malloc(i * sizeof(GrabPtr));
436    adds = malloc(i * sizeof(GrabPtr));
437    updates = malloc(i * sizeof(Mask **));
438    details = malloc(i * sizeof(Mask *));
439    if (!deletes || !adds || !updates || !details)
440    {
441	free(details);
442	free(updates);
443	free(adds);
444	free(deletes);
445	return FALSE;
446    }
447
448    any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
449                   (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
450    any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
451                   (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
452    ndels = nadds = nups = 0;
453    ok = TRUE;
454    for (grab = wPassiveGrabs(pMinuendGrab->window);
455	 grab && ok;
456	 grab = grab->next)
457    {
458	if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
459	    !GrabMatchesSecond(grab, pMinuendGrab,
460                               (grab->grabtype == GRABTYPE_CORE)))
461	    continue;
462	if (GrabSupersedesSecond(pMinuendGrab, grab))
463	{
464	    deletes[ndels++] = grab;
465	}
466	else if ((grab->detail.exact == any_key)
467		 && (grab->modifiersDetail.exact != any_modifier))
468	{
469	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
470	}
471	else if ((grab->modifiersDetail.exact == any_modifier)
472		 && (grab->detail.exact != any_key))
473	{
474	    UPDATE(grab->modifiersDetail.pMask,
475		   pMinuendGrab->modifiersDetail.exact);
476	}
477	else if ((pMinuendGrab->detail.exact != any_key)
478		 && (pMinuendGrab->modifiersDetail.exact != any_modifier))
479	{
480	    GrabPtr pNewGrab;
481            GrabParameters param;
482
483	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
484
485            memset(&param, 0, sizeof(param));
486            param.ownerEvents = grab->ownerEvents;
487            param.this_device_mode = grab->keyboardMode;
488            param.other_devices_mode = grab->pointerMode;
489            param.modifiers = any_modifier;
490
491	    pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
492				  grab->modifierDevice, grab->window,
493                                  grab->grabtype,
494				  (GrabMask*)&grab->eventMask,
495                                  &param, (int)grab->type,
496				  pMinuendGrab->detail.exact,
497				  grab->confineTo, grab->cursor);
498	    if (!pNewGrab)
499		ok = FALSE;
500	    else if (!(pNewGrab->modifiersDetail.pMask =
501		       DeleteDetailFromMask(grab->modifiersDetail.pMask,
502					 pMinuendGrab->modifiersDetail.exact))
503		     ||
504		     (!pNewGrab->window->optional &&
505		      !MakeWindowOptional(pNewGrab->window)))
506	    {
507		FreeGrab(pNewGrab);
508		ok = FALSE;
509	    }
510	    else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
511				  (pointer)pNewGrab))
512		ok = FALSE;
513	    else
514		adds[nadds++] = pNewGrab;
515	}
516	else if (pMinuendGrab->detail.exact == any_key)
517	{
518	    UPDATE(grab->modifiersDetail.pMask,
519		   pMinuendGrab->modifiersDetail.exact);
520	}
521	else
522	{
523	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
524	}
525    }
526
527    if (!ok)
528    {
529	for (i = 0; i < nadds; i++)
530	    FreeResource(adds[i]->resource, RT_NONE);
531	for (i = 0; i < nups; i++)
532	    free(details[i]);
533    }
534    else
535    {
536	for (i = 0; i < ndels; i++)
537	    FreeResource(deletes[i]->resource, RT_NONE);
538	for (i = 0; i < nadds; i++)
539	{
540	    grab = adds[i];
541	    grab->next = grab->window->optional->passiveGrabs;
542	    grab->window->optional->passiveGrabs = grab;
543	}
544	for (i = 0; i < nups; i++)
545	{
546	    free(*updates[i]);
547	    *updates[i] = details[i];
548	}
549    }
550    free(details);
551    free(updates);
552    free(adds);
553    free(deletes);
554    return ok;
555
556#undef UPDATE
557}
558