grabs.c revision 4642e01f
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#define NEED_EVENTS
56#include <X11/Xproto.h>
57#include "windowstr.h"
58#include "inputstr.h"
59#include "cursorstr.h"
60#include "dixgrabs.h"
61#include "xace.h"
62
63#define BITMASK(i) (((Mask)1) << ((i) & 31))
64#define MASKIDX(i) ((i) >> 5)
65#define MASKWORD(buf, i) buf[MASKIDX(i)]
66#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
67#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
68#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
69
70GrabPtr
71CreateGrab(
72    int client,
73    DeviceIntPtr device,
74    WindowPtr window,
75    Mask eventMask,
76    Bool ownerEvents, Bool keyboardMode, Bool pointerMode,
77    DeviceIntPtr modDevice,
78    unsigned short modifiers,
79    int type,
80    KeyCode keybut,	/* key or button */
81    WindowPtr confineTo,
82    CursorPtr cursor)
83{
84    GrabPtr grab;
85
86    grab = (GrabPtr)xalloc(sizeof(GrabRec));
87    if (!grab)
88	return (GrabPtr)NULL;
89    grab->resource = FakeClientID(client);
90    grab->device = device;
91    grab->coreGrab = (type < LASTEvent);
92    grab->window = window;
93    grab->eventMask = eventMask;
94    grab->deviceMask = 0;
95    grab->ownerEvents = ownerEvents;
96    grab->keyboardMode = keyboardMode;
97    grab->pointerMode = pointerMode;
98    grab->modifiersDetail.exact = modifiers;
99    grab->modifiersDetail.pMask = NULL;
100    grab->modifierDevice = modDevice;
101    grab->coreMods = ((modDevice == inputInfo.keyboard) ||
102		      (modDevice == inputInfo.pointer));
103    grab->type = type;
104    grab->detail.exact = keybut;
105    grab->detail.pMask = NULL;
106    grab->confineTo = confineTo;
107    grab->cursor = cursor;
108    grab->genericMasks = NULL;
109    grab->next = NULL;
110    if (cursor)
111	cursor->refcnt++;
112    return grab;
113
114}
115
116static void
117FreeGrab(GrabPtr pGrab)
118{
119    if (pGrab->modifiersDetail.pMask != NULL)
120	xfree(pGrab->modifiersDetail.pMask);
121
122    if (pGrab->detail.pMask != NULL)
123	xfree(pGrab->detail.pMask);
124
125    if (pGrab->cursor)
126	FreeCursor(pGrab->cursor, (Cursor)0);
127
128    xfree(pGrab);
129}
130
131int
132DeletePassiveGrab(pointer value, XID id)
133{
134    GrabPtr g, prev;
135    GrabPtr pGrab = (GrabPtr)value;
136
137    /* it is OK if the grab isn't found */
138    prev = 0;
139    for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
140    {
141	if (pGrab == g)
142	{
143	    if (prev)
144		prev->next = g->next;
145	    else
146		if (!(pGrab->window->optional->passiveGrabs = g->next))
147		    CheckWindowOptionalNeed (pGrab->window);
148	    break;
149	}
150	prev = g;
151    }
152    FreeGrab(pGrab);
153    return Success;
154}
155
156static Mask *
157DeleteDetailFromMask(Mask *pDetailMask, unsigned short detail)
158{
159    Mask *mask;
160    int i;
161
162    mask = (Mask *)xalloc(sizeof(Mask) * MasksPerDetailMask);
163    if (mask)
164    {
165	if (pDetailMask)
166	    for (i = 0; i < MasksPerDetailMask; i++)
167		mask[i]= pDetailMask[i];
168	else
169	    for (i = 0; i < MasksPerDetailMask; i++)
170		mask[i]= ~0L;
171	BITCLEAR(mask, detail);
172    }
173    return mask;
174}
175
176static Bool
177IsInGrabMask(
178    DetailRec firstDetail,
179    DetailRec secondDetail,
180    unsigned short exception)
181{
182    if (firstDetail.exact == exception)
183    {
184	if (firstDetail.pMask == NULL)
185	    return TRUE;
186
187	/* (at present) never called with two non-null pMasks */
188	if (secondDetail.exact == exception)
189	    return FALSE;
190
191 	if (GETBIT(firstDetail.pMask, secondDetail.exact))
192	    return TRUE;
193    }
194
195    return FALSE;
196}
197
198static Bool
199IdenticalExactDetails(
200    unsigned short firstExact,
201    unsigned short secondExact,
202    unsigned short exception)
203{
204    if ((firstExact == exception) || (secondExact == exception))
205	return FALSE;
206
207    if (firstExact == secondExact)
208	return TRUE;
209
210    return FALSE;
211}
212
213static Bool
214DetailSupersedesSecond(
215    DetailRec firstDetail,
216    DetailRec secondDetail,
217    unsigned short exception)
218{
219    if (IsInGrabMask(firstDetail, secondDetail, exception))
220	return TRUE;
221
222    if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
223			      exception))
224	return TRUE;
225
226    return FALSE;
227}
228
229static Bool
230GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
231{
232    if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
233				pSecondGrab->modifiersDetail,
234				(unsigned short)AnyModifier))
235	return FALSE;
236
237    if (DetailSupersedesSecond(pFirstGrab->detail,
238			       pSecondGrab->detail, (unsigned short)AnyKey))
239	return TRUE;
240
241    return FALSE;
242}
243
244/**
245 * Compares two grabs and returns TRUE if the first grab matches the second
246 * grab.
247 *
248 * A match is when
249 *  - the devices set for the grab are equal (this is optional).
250 *  - the event types for both grabs are equal.
251 *  - XXX
252 *
253 * @param ignoreDevice TRUE if the device settings on the grabs are to be
254 * ignored.
255 * @return TRUE if the grabs match or FALSE otherwise.
256 */
257Bool
258GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
259{
260    if (!ignoreDevice &&
261            ((pFirstGrab->device != pSecondGrab->device) ||
262             (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
263            return FALSE;
264
265    if (pFirstGrab->type != pSecondGrab->type)
266	return FALSE;
267
268    if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
269	GrabSupersedesSecond(pSecondGrab, pFirstGrab))
270	return TRUE;
271
272    if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
273			       (unsigned short)AnyKey)
274	&&
275	DetailSupersedesSecond(pFirstGrab->modifiersDetail,
276			       pSecondGrab->modifiersDetail,
277			       (unsigned short)AnyModifier))
278	return TRUE;
279
280    if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
281			       (unsigned short)AnyKey)
282	&&
283	DetailSupersedesSecond(pSecondGrab->modifiersDetail,
284			       pFirstGrab->modifiersDetail,
285			       (unsigned short)AnyModifier))
286	return TRUE;
287
288    return FALSE;
289}
290
291static Bool
292GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
293{
294    if (pFirstGrab->device != pSecondGrab->device ||
295	(pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
296	(pFirstGrab->type != pSecondGrab->type))
297	return FALSE;
298
299    if (!(DetailSupersedesSecond(pFirstGrab->detail,
300                               pSecondGrab->detail,
301                               (unsigned short)AnyKey) &&
302        DetailSupersedesSecond(pSecondGrab->detail,
303                               pFirstGrab->detail,
304                               (unsigned short)AnyKey)))
305        return FALSE;
306
307    if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
308                               pSecondGrab->modifiersDetail,
309                               (unsigned short)AnyModifier) &&
310        DetailSupersedesSecond(pSecondGrab->modifiersDetail,
311                               pFirstGrab->modifiersDetail,
312                               (unsigned short)AnyModifier)))
313        return FALSE;
314
315    return TRUE;
316}
317
318
319/**
320 * Prepend the new grab to the list of passive grabs on the window.
321 * Any previously existing grab that matches the new grab will be removed.
322 * Adding a new grab that would override another client's grab will result in
323 * a BadAccess.
324 *
325 * @return Success or X error code on failure.
326 */
327int
328AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
329{
330    GrabPtr grab;
331    Mask access_mode = DixGrabAccess;
332    int rc;
333
334    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
335    {
336	if (GrabMatchesSecond(pGrab, grab, FALSE))
337	{
338	    if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
339	    {
340		FreeGrab(pGrab);
341		return BadAccess;
342	    }
343	}
344    }
345
346    if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
347	access_mode |= DixFreezeAccess;
348    rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
349    if (rc != Success)
350	return rc;
351
352    /* Remove all grabs that match the new one exactly */
353    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
354    {
355	if (GrabsAreIdentical(pGrab, grab))
356	{
357            DeletePassiveGrabFromList(grab);
358            break;
359	}
360    }
361
362    if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
363    {
364	FreeGrab(pGrab);
365	return BadAlloc;
366    }
367
368    pGrab->next = pGrab->window->optional->passiveGrabs;
369    pGrab->window->optional->passiveGrabs = pGrab;
370    if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
371	return Success;
372    return BadAlloc;
373}
374
375/* the following is kinda complicated, because we need to be able to back out
376 * if any allocation fails
377 */
378
379Bool
380DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
381{
382    GrabPtr grab;
383    GrabPtr *deletes, *adds;
384    Mask ***updates, **details;
385    int i, ndels, nadds, nups;
386    Bool ok;
387
388#define UPDATE(mask,exact) \
389	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
390	  ok = FALSE; \
391	else \
392	  updates[nups++] = &(mask)
393
394    i = 0;
395    for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
396	i++;
397    if (!i)
398	return TRUE;
399    deletes = (GrabPtr *)xalloc(i * sizeof(GrabPtr));
400    adds = (GrabPtr *)xalloc(i * sizeof(GrabPtr));
401    updates = (Mask ***)xalloc(i * sizeof(Mask **));
402    details = (Mask **)xalloc(i * sizeof(Mask *));
403    if (!deletes || !adds || !updates || !details)
404    {
405	if (details) xfree(details);
406	if (updates) xfree(updates);
407	if (adds) xfree(adds);
408	if (deletes) xfree(deletes);
409	return FALSE;
410    }
411    ndels = nadds = nups = 0;
412    ok = TRUE;
413    for (grab = wPassiveGrabs(pMinuendGrab->window);
414	 grab && ok;
415	 grab = grab->next)
416    {
417	if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
418	    !GrabMatchesSecond(grab, pMinuendGrab, (grab->coreGrab)))
419	    continue;
420	if (GrabSupersedesSecond(pMinuendGrab, grab))
421	{
422	    deletes[ndels++] = grab;
423	}
424	else if ((grab->detail.exact == AnyKey)
425		 && (grab->modifiersDetail.exact != AnyModifier))
426	{
427	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
428	}
429	else if ((grab->modifiersDetail.exact == AnyModifier)
430		 && (grab->detail.exact != AnyKey))
431	{
432	    UPDATE(grab->modifiersDetail.pMask,
433		   pMinuendGrab->modifiersDetail.exact);
434	}
435	else if ((pMinuendGrab->detail.exact != AnyKey)
436		 && (pMinuendGrab->modifiersDetail.exact != AnyModifier))
437	{
438	    GrabPtr pNewGrab;
439
440	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
441
442	    pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
443				  grab->window, (Mask)grab->eventMask,
444				  (Bool)grab->ownerEvents,
445				  (Bool)grab->keyboardMode,
446				  (Bool)grab->pointerMode,
447				  grab->modifierDevice,
448				  AnyModifier, (int)grab->type,
449				  pMinuendGrab->detail.exact,
450				  grab->confineTo, grab->cursor);
451	    if (!pNewGrab)
452		ok = FALSE;
453	    else if (!(pNewGrab->modifiersDetail.pMask =
454		       DeleteDetailFromMask(grab->modifiersDetail.pMask,
455					 pMinuendGrab->modifiersDetail.exact))
456		     ||
457		     (!pNewGrab->window->optional &&
458		      !MakeWindowOptional(pNewGrab->window)))
459	    {
460		FreeGrab(pNewGrab);
461		ok = FALSE;
462	    }
463	    else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
464				  (pointer)pNewGrab))
465		ok = FALSE;
466	    else
467		adds[nadds++] = pNewGrab;
468	}
469	else if (pMinuendGrab->detail.exact == AnyKey)
470	{
471	    UPDATE(grab->modifiersDetail.pMask,
472		   pMinuendGrab->modifiersDetail.exact);
473	}
474	else
475	{
476	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
477	}
478    }
479
480    if (!ok)
481    {
482	for (i = 0; i < nadds; i++)
483	    FreeResource(adds[i]->resource, RT_NONE);
484	for (i = 0; i < nups; i++)
485	    xfree(details[i]);
486    }
487    else
488    {
489	for (i = 0; i < ndels; i++)
490	    FreeResource(deletes[i]->resource, RT_NONE);
491	for (i = 0; i < nadds; i++)
492	{
493	    grab = adds[i];
494	    grab->next = grab->window->optional->passiveGrabs;
495	    grab->window->optional->passiveGrabs = grab;
496	}
497	for (i = 0; i < nups; i++)
498	{
499	    xfree(*updates[i]);
500	    *updates[i] = details[i];
501	}
502    }
503    xfree(details);
504    xfree(updates);
505    xfree(adds);
506    xfree(deletes);
507    return ok;
508
509#undef UPDATE
510}
511