grabs.c revision 6747b715
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    if (pGrab->modifiersDetail.pMask != NULL)
121	free(pGrab->modifiersDetail.pMask);
122
123    if (pGrab->detail.pMask != NULL)
124	free(pGrab->detail.pMask);
125
126    if (pGrab->cursor)
127	FreeCursor(pGrab->cursor, (Cursor)0);
128
129    free(pGrab);
130}
131
132int
133DeletePassiveGrab(pointer value, XID id)
134{
135    GrabPtr g, prev;
136    GrabPtr pGrab = (GrabPtr)value;
137
138    /* it is OK if the grab isn't found */
139    prev = 0;
140    for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
141    {
142	if (pGrab == g)
143	{
144	    if (prev)
145		prev->next = g->next;
146	    else
147		if (!(pGrab->window->optional->passiveGrabs = g->next))
148		    CheckWindowOptionalNeed (pGrab->window);
149	    break;
150	}
151	prev = g;
152    }
153    FreeGrab(pGrab);
154    return Success;
155}
156
157static Mask *
158DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail)
159{
160    Mask *mask;
161    int i;
162
163    mask = malloc(sizeof(Mask) * MasksPerDetailMask);
164    if (mask)
165    {
166	if (pDetailMask)
167	    for (i = 0; i < MasksPerDetailMask; i++)
168		mask[i]= pDetailMask[i];
169	else
170	    for (i = 0; i < MasksPerDetailMask; i++)
171		mask[i]= ~0L;
172	BITCLEAR(mask, detail);
173    }
174    return mask;
175}
176
177static Bool
178IsInGrabMask(
179    DetailRec firstDetail,
180    DetailRec secondDetail,
181    unsigned int exception)
182{
183    if (firstDetail.exact == exception)
184    {
185	if (firstDetail.pMask == NULL)
186	    return TRUE;
187
188	/* (at present) never called with two non-null pMasks */
189	if (secondDetail.exact == exception)
190	    return FALSE;
191
192 	if (GETBIT(firstDetail.pMask, secondDetail.exact))
193	    return TRUE;
194    }
195
196    return FALSE;
197}
198
199static Bool
200IdenticalExactDetails(
201    unsigned int firstExact,
202    unsigned int secondExact,
203    unsigned int exception)
204{
205    if ((firstExact == exception) || (secondExact == exception))
206	return FALSE;
207
208    if (firstExact == secondExact)
209	return TRUE;
210
211    return FALSE;
212}
213
214static Bool
215DetailSupersedesSecond(
216    DetailRec firstDetail,
217    DetailRec secondDetail,
218    unsigned int exception)
219{
220    if (IsInGrabMask(firstDetail, secondDetail, exception))
221	return TRUE;
222
223    if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
224			      exception))
225	return TRUE;
226
227    return FALSE;
228}
229
230static Bool
231GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
232{
233    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
234                                (unsigned int)XIAnyModifier :
235                                (unsigned int)AnyModifier;
236    if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
237				pSecondGrab->modifiersDetail,
238				any_modifier))
239	return FALSE;
240
241    if (DetailSupersedesSecond(pFirstGrab->detail,
242			       pSecondGrab->detail, (unsigned int)AnyKey))
243	return TRUE;
244
245    return FALSE;
246}
247
248/**
249 * Compares two grabs and returns TRUE if the first grab matches the second
250 * grab.
251 *
252 * A match is when
253 *  - the devices set for the grab are equal (this is optional).
254 *  - the event types for both grabs are equal.
255 *  - XXX
256 *
257 * @param ignoreDevice TRUE if the device settings on the grabs are to be
258 * ignored.
259 * @return TRUE if the grabs match or FALSE otherwise.
260 */
261Bool
262GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice)
263{
264    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
265                                (unsigned int)XIAnyModifier :
266                                (unsigned int)AnyModifier;
267
268    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
269        return FALSE;
270
271    if (pFirstGrab->grabtype == GRABTYPE_XI2)
272    {
273        if (pFirstGrab->device == inputInfo.all_devices ||
274            pSecondGrab->device == inputInfo.all_devices)
275        {
276            /* do nothing */
277        } else if (pFirstGrab->device == inputInfo.all_master_devices)
278        {
279            if (pSecondGrab->device != inputInfo.all_master_devices &&
280                !IsMaster(pSecondGrab->device))
281                return FALSE;
282        } else if (pSecondGrab->device == inputInfo.all_master_devices)
283        {
284            if (pFirstGrab->device != inputInfo.all_master_devices &&
285                !IsMaster(pFirstGrab->device))
286                return FALSE;
287        } else if (pSecondGrab->device != pFirstGrab->device)
288            return FALSE;
289    } else if (!ignoreDevice &&
290            ((pFirstGrab->device != pSecondGrab->device) ||
291             (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice)))
292            return FALSE;
293
294    if (pFirstGrab->type != pSecondGrab->type)
295	return FALSE;
296
297    if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
298	GrabSupersedesSecond(pSecondGrab, pFirstGrab))
299	return TRUE;
300
301    if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
302			       (unsigned int)AnyKey)
303	&&
304	DetailSupersedesSecond(pFirstGrab->modifiersDetail,
305			       pSecondGrab->modifiersDetail,
306			       any_modifier))
307	return TRUE;
308
309    if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
310			       (unsigned int)AnyKey)
311	&&
312	DetailSupersedesSecond(pSecondGrab->modifiersDetail,
313			       pFirstGrab->modifiersDetail,
314			       any_modifier))
315	return TRUE;
316
317    return FALSE;
318}
319
320static Bool
321GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
322{
323    unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ?
324                                (unsigned int)XIAnyModifier :
325                                (unsigned int)AnyModifier;
326
327    if (pFirstGrab->grabtype != pSecondGrab->grabtype)
328        return FALSE;
329
330    if (pFirstGrab->device != pSecondGrab->device ||
331	(pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
332	(pFirstGrab->type != pSecondGrab->type))
333	return FALSE;
334
335    if (!(DetailSupersedesSecond(pFirstGrab->detail,
336                               pSecondGrab->detail,
337                               (unsigned int)AnyKey) &&
338        DetailSupersedesSecond(pSecondGrab->detail,
339                               pFirstGrab->detail,
340                               (unsigned int)AnyKey)))
341        return FALSE;
342
343
344    if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
345                               pSecondGrab->modifiersDetail,
346                               any_modifier) &&
347        DetailSupersedesSecond(pSecondGrab->modifiersDetail,
348                               pFirstGrab->modifiersDetail,
349                               any_modifier)))
350        return FALSE;
351
352    return TRUE;
353}
354
355
356/**
357 * Prepend the new grab to the list of passive grabs on the window.
358 * Any previously existing grab that matches the new grab will be removed.
359 * Adding a new grab that would override another client's grab will result in
360 * a BadAccess.
361 *
362 * @return Success or X error code on failure.
363 */
364int
365AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab)
366{
367    GrabPtr grab;
368    Mask access_mode = DixGrabAccess;
369    int rc;
370
371    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
372    {
373	if (GrabMatchesSecond(pGrab, grab, FALSE))
374	{
375	    if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
376	    {
377		FreeGrab(pGrab);
378		return BadAccess;
379	    }
380	}
381    }
382
383    if (pGrab->keyboardMode == GrabModeSync||pGrab->pointerMode == GrabModeSync)
384	access_mode |= DixFreezeAccess;
385    rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode);
386    if (rc != Success)
387	return rc;
388
389    /* Remove all grabs that match the new one exactly */
390    for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
391    {
392	if (GrabsAreIdentical(pGrab, grab))
393	{
394            DeletePassiveGrabFromList(grab);
395            break;
396	}
397    }
398
399    if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
400    {
401	FreeGrab(pGrab);
402	return BadAlloc;
403    }
404
405    pGrab->next = pGrab->window->optional->passiveGrabs;
406    pGrab->window->optional->passiveGrabs = pGrab;
407    if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
408	return Success;
409    return BadAlloc;
410}
411
412/* the following is kinda complicated, because we need to be able to back out
413 * if any allocation fails
414 */
415
416Bool
417DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
418{
419    GrabPtr grab;
420    GrabPtr *deletes, *adds;
421    Mask ***updates, **details;
422    int i, ndels, nadds, nups;
423    Bool ok;
424    unsigned int any_modifier;
425    unsigned int any_key;
426
427#define UPDATE(mask,exact) \
428	if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
429	  ok = FALSE; \
430	else \
431	  updates[nups++] = &(mask)
432
433    i = 0;
434    for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
435	i++;
436    if (!i)
437	return TRUE;
438    deletes = malloc(i * sizeof(GrabPtr));
439    adds = malloc(i * sizeof(GrabPtr));
440    updates = malloc(i * sizeof(Mask **));
441    details = malloc(i * sizeof(Mask *));
442    if (!deletes || !adds || !updates || !details)
443    {
444	free(details);
445	free(updates);
446	free(adds);
447	free(deletes);
448	return FALSE;
449    }
450
451    any_modifier = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
452                   (unsigned int)XIAnyModifier : (unsigned int)AnyModifier;
453    any_key = (pMinuendGrab->grabtype == GRABTYPE_XI2) ?
454                   (unsigned int)XIAnyKeycode : (unsigned int)AnyKey;
455    ndels = nadds = nups = 0;
456    ok = TRUE;
457    for (grab = wPassiveGrabs(pMinuendGrab->window);
458	 grab && ok;
459	 grab = grab->next)
460    {
461	if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
462	    !GrabMatchesSecond(grab, pMinuendGrab,
463                               (grab->grabtype == GRABTYPE_CORE)))
464	    continue;
465	if (GrabSupersedesSecond(pMinuendGrab, grab))
466	{
467	    deletes[ndels++] = grab;
468	}
469	else if ((grab->detail.exact == any_key)
470		 && (grab->modifiersDetail.exact != any_modifier))
471	{
472	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
473	}
474	else if ((grab->modifiersDetail.exact == any_modifier)
475		 && (grab->detail.exact != any_key))
476	{
477	    UPDATE(grab->modifiersDetail.pMask,
478		   pMinuendGrab->modifiersDetail.exact);
479	}
480	else if ((pMinuendGrab->detail.exact != any_key)
481		 && (pMinuendGrab->modifiersDetail.exact != any_modifier))
482	{
483	    GrabPtr pNewGrab;
484            GrabParameters param;
485
486	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
487
488            memset(&param, 0, sizeof(param));
489            param.ownerEvents = grab->ownerEvents;
490            param.this_device_mode = grab->keyboardMode;
491            param.other_devices_mode = grab->pointerMode;
492            param.modifiers = any_modifier;
493
494	    pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
495				  grab->modifierDevice, grab->window,
496                                  grab->grabtype,
497				  (GrabMask*)&grab->eventMask,
498                                  &param, (int)grab->type,
499				  pMinuendGrab->detail.exact,
500				  grab->confineTo, grab->cursor);
501	    if (!pNewGrab)
502		ok = FALSE;
503	    else if (!(pNewGrab->modifiersDetail.pMask =
504		       DeleteDetailFromMask(grab->modifiersDetail.pMask,
505					 pMinuendGrab->modifiersDetail.exact))
506		     ||
507		     (!pNewGrab->window->optional &&
508		      !MakeWindowOptional(pNewGrab->window)))
509	    {
510		FreeGrab(pNewGrab);
511		ok = FALSE;
512	    }
513	    else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
514				  (pointer)pNewGrab))
515		ok = FALSE;
516	    else
517		adds[nadds++] = pNewGrab;
518	}
519	else if (pMinuendGrab->detail.exact == any_key)
520	{
521	    UPDATE(grab->modifiersDetail.pMask,
522		   pMinuendGrab->modifiersDetail.exact);
523	}
524	else
525	{
526	    UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
527	}
528    }
529
530    if (!ok)
531    {
532	for (i = 0; i < nadds; i++)
533	    FreeResource(adds[i]->resource, RT_NONE);
534	for (i = 0; i < nups; i++)
535	    free(details[i]);
536    }
537    else
538    {
539	for (i = 0; i < ndels; i++)
540	    FreeResource(deletes[i]->resource, RT_NONE);
541	for (i = 0; i < nadds; i++)
542	{
543	    grab = adds[i];
544	    grab->next = grab->window->optional->passiveGrabs;
545	    grab->window->optional->passiveGrabs = grab;
546	}
547	for (i = 0; i < nups; i++)
548	{
549	    free(*updates[i]);
550	    *updates[i] = details[i];
551	}
552    }
553    free(details);
554    free(updates);
555    free(adds);
556    free(deletes);
557    return ok;
558
559#undef UPDATE
560}
561