First import
[xorg_rtime.git] / xorg-server-1.4 / dix / grabs.c
blob2210cd05e52696e7c48beedb11d1ea4f89a22ea2
1 /*
3 Copyright 1987, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
28 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
30 All Rights Reserved
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted,
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in
36 supporting documentation, and that the name of Digital not be
37 used in advertising or publicity pertaining to distribution of the
38 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
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"
62 #define BITMASK(i) (((Mask)1) << ((i) & 31))
63 #define MASKIDX(i) ((i) >> 5)
64 #define MASKWORD(buf, i) buf[MASKIDX(i)]
65 #define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
66 #define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
67 #define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
69 GrabPtr
70 CreateGrab(
71 int client,
72 DeviceIntPtr device,
73 WindowPtr window,
74 Mask eventMask,
75 Bool ownerEvents, Bool keyboardMode, Bool pointerMode,
76 DeviceIntPtr modDevice,
77 unsigned short modifiers,
78 int type,
79 KeyCode keybut, /* key or button */
80 WindowPtr confineTo,
81 CursorPtr cursor)
83 GrabPtr grab;
85 grab = (GrabPtr)xalloc(sizeof(GrabRec));
86 if (!grab)
87 return (GrabPtr)NULL;
88 grab->resource = FakeClientID(client);
89 grab->device = device;
90 grab->coreGrab = ((device == inputInfo.keyboard) ||
91 (device == inputInfo.pointer));
92 grab->window = window;
93 grab->eventMask = eventMask;
94 grab->ownerEvents = ownerEvents;
95 grab->keyboardMode = keyboardMode;
96 grab->pointerMode = pointerMode;
97 grab->modifiersDetail.exact = modifiers;
98 grab->modifiersDetail.pMask = NULL;
99 grab->modifierDevice = modDevice;
100 grab->coreMods = ((modDevice == inputInfo.keyboard) ||
101 (modDevice == inputInfo.pointer));
102 grab->type = type;
103 grab->detail.exact = keybut;
104 grab->detail.pMask = NULL;
105 grab->confineTo = confineTo;
106 grab->cursor = cursor;
107 if (cursor)
108 cursor->refcnt++;
109 return grab;
113 static void
114 FreeGrab(GrabPtr pGrab)
116 if (pGrab->modifiersDetail.pMask != NULL)
117 xfree(pGrab->modifiersDetail.pMask);
119 if (pGrab->detail.pMask != NULL)
120 xfree(pGrab->detail.pMask);
122 if (pGrab->cursor)
123 FreeCursor(pGrab->cursor, (Cursor)0);
125 xfree(pGrab);
129 DeletePassiveGrab(pointer value, XID id)
131 GrabPtr g, prev;
132 GrabPtr pGrab = (GrabPtr)value;
134 /* it is OK if the grab isn't found */
135 prev = 0;
136 for (g = (wPassiveGrabs (pGrab->window)); g; g = g->next)
138 if (pGrab == g)
140 if (prev)
141 prev->next = g->next;
142 else
143 if (!(pGrab->window->optional->passiveGrabs = g->next))
144 CheckWindowOptionalNeed (pGrab->window);
145 break;
147 prev = g;
149 FreeGrab(pGrab);
150 return Success;
153 static Mask *
154 DeleteDetailFromMask(Mask *pDetailMask, unsigned short detail)
156 Mask *mask;
157 int i;
159 mask = (Mask *)xalloc(sizeof(Mask) * MasksPerDetailMask);
160 if (mask)
162 if (pDetailMask)
163 for (i = 0; i < MasksPerDetailMask; i++)
164 mask[i]= pDetailMask[i];
165 else
166 for (i = 0; i < MasksPerDetailMask; i++)
167 mask[i]= ~0L;
168 BITCLEAR(mask, detail);
170 return mask;
173 static Bool
174 IsInGrabMask(
175 DetailRec firstDetail,
176 DetailRec secondDetail,
177 unsigned short exception)
179 if (firstDetail.exact == exception)
181 if (firstDetail.pMask == NULL)
182 return TRUE;
184 /* (at present) never called with two non-null pMasks */
185 if (secondDetail.exact == exception)
186 return FALSE;
188 if (GETBIT(firstDetail.pMask, secondDetail.exact))
189 return TRUE;
192 return FALSE;
195 static Bool
196 IdenticalExactDetails(
197 unsigned short firstExact,
198 unsigned short secondExact,
199 unsigned short exception)
201 if ((firstExact == exception) || (secondExact == exception))
202 return FALSE;
204 if (firstExact == secondExact)
205 return TRUE;
207 return FALSE;
210 static Bool
211 DetailSupersedesSecond(
212 DetailRec firstDetail,
213 DetailRec secondDetail,
214 unsigned short exception)
216 if (IsInGrabMask(firstDetail, secondDetail, exception))
217 return TRUE;
219 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact,
220 exception))
221 return TRUE;
223 return FALSE;
226 static Bool
227 GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
229 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail,
230 pSecondGrab->modifiersDetail,
231 (unsigned short)AnyModifier))
232 return FALSE;
234 if (DetailSupersedesSecond(pFirstGrab->detail,
235 pSecondGrab->detail, (unsigned short)AnyKey))
236 return TRUE;
238 return FALSE;
241 Bool
242 GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
244 if ((pFirstGrab->device != pSecondGrab->device) ||
245 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
246 (pFirstGrab->type != pSecondGrab->type))
247 return FALSE;
249 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) ||
250 GrabSupersedesSecond(pSecondGrab, pFirstGrab))
251 return TRUE;
253 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail,
254 (unsigned short)AnyKey)
256 DetailSupersedesSecond(pFirstGrab->modifiersDetail,
257 pSecondGrab->modifiersDetail,
258 (unsigned short)AnyModifier))
259 return TRUE;
261 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail,
262 (unsigned short)AnyKey)
264 DetailSupersedesSecond(pSecondGrab->modifiersDetail,
265 pFirstGrab->modifiersDetail,
266 (unsigned short)AnyModifier))
267 return TRUE;
269 return FALSE;
272 static Bool
273 GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab)
275 if (pFirstGrab->device != pSecondGrab->device ||
276 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) ||
277 (pFirstGrab->type != pSecondGrab->type))
278 return FALSE;
280 if (!(DetailSupersedesSecond(pFirstGrab->detail,
281 pSecondGrab->detail,
282 (unsigned short)AnyKey) &&
283 DetailSupersedesSecond(pSecondGrab->detail,
284 pFirstGrab->detail,
285 (unsigned short)AnyKey)))
286 return FALSE;
288 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail,
289 pSecondGrab->modifiersDetail,
290 (unsigned short)AnyModifier) &&
291 DetailSupersedesSecond(pSecondGrab->modifiersDetail,
292 pFirstGrab->modifiersDetail,
293 (unsigned short)AnyModifier)))
294 return FALSE;
296 return TRUE;
301 * Prepend the new grab to the list of passive grabs on the window.
302 * Any previously existing grab that matches the new grab will be removed.
303 * Adding a new grab that would override another client's grab will result in
304 * a BadAccess.
306 * @return Success or X error code on failure.
309 AddPassiveGrabToList(GrabPtr pGrab)
311 GrabPtr grab;
313 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
315 if (GrabMatchesSecond(pGrab, grab))
317 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource))
319 FreeGrab(pGrab);
320 return BadAccess;
325 /* Remove all grabs that match the new one exactly */
326 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next)
328 if (GrabsAreIdentical(pGrab, grab))
330 DeletePassiveGrabFromList(grab);
331 break;
335 if (!pGrab->window->optional && !MakeWindowOptional (pGrab->window))
337 FreeGrab(pGrab);
338 return BadAlloc;
341 pGrab->next = pGrab->window->optional->passiveGrabs;
342 pGrab->window->optional->passiveGrabs = pGrab;
343 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer)pGrab))
344 return Success;
345 return BadAlloc;
348 /* the following is kinda complicated, because we need to be able to back out
349 * if any allocation fails
352 Bool
353 DeletePassiveGrabFromList(GrabPtr pMinuendGrab)
355 GrabPtr grab;
356 GrabPtr *deletes, *adds;
357 Mask ***updates, **details;
358 int i, ndels, nadds, nups;
359 Bool ok;
361 #define UPDATE(mask,exact) \
362 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \
363 ok = FALSE; \
364 else \
365 updates[nups++] = &(mask)
367 i = 0;
368 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next)
369 i++;
370 if (!i)
371 return TRUE;
372 deletes = (GrabPtr *)ALLOCATE_LOCAL(i * sizeof(GrabPtr));
373 adds = (GrabPtr *)ALLOCATE_LOCAL(i * sizeof(GrabPtr));
374 updates = (Mask ***)ALLOCATE_LOCAL(i * sizeof(Mask **));
375 details = (Mask **)ALLOCATE_LOCAL(i * sizeof(Mask *));
376 if (!deletes || !adds || !updates || !details)
378 if (details) DEALLOCATE_LOCAL(details);
379 if (updates) DEALLOCATE_LOCAL(updates);
380 if (adds) DEALLOCATE_LOCAL(adds);
381 if (deletes) DEALLOCATE_LOCAL(deletes);
382 return FALSE;
384 ndels = nadds = nups = 0;
385 ok = TRUE;
386 for (grab = wPassiveGrabs(pMinuendGrab->window);
387 grab && ok;
388 grab = grab->next)
390 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) ||
391 !GrabMatchesSecond(grab, pMinuendGrab))
392 continue;
393 if (GrabSupersedesSecond(pMinuendGrab, grab))
395 deletes[ndels++] = grab;
397 else if ((grab->detail.exact == AnyKey)
398 && (grab->modifiersDetail.exact != AnyModifier))
400 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
402 else if ((grab->modifiersDetail.exact == AnyModifier)
403 && (grab->detail.exact != AnyKey))
405 UPDATE(grab->modifiersDetail.pMask,
406 pMinuendGrab->modifiersDetail.exact);
408 else if ((pMinuendGrab->detail.exact != AnyKey)
409 && (pMinuendGrab->modifiersDetail.exact != AnyModifier))
411 GrabPtr pNewGrab;
413 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
415 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device,
416 grab->window, (Mask)grab->eventMask,
417 (Bool)grab->ownerEvents,
418 (Bool)grab->keyboardMode,
419 (Bool)grab->pointerMode,
420 grab->modifierDevice,
421 AnyModifier, (int)grab->type,
422 pMinuendGrab->detail.exact,
423 grab->confineTo, grab->cursor);
424 if (!pNewGrab)
425 ok = FALSE;
426 else if (!(pNewGrab->modifiersDetail.pMask =
427 DeleteDetailFromMask(grab->modifiersDetail.pMask,
428 pMinuendGrab->modifiersDetail.exact))
430 (!pNewGrab->window->optional &&
431 !MakeWindowOptional(pNewGrab->window)))
433 FreeGrab(pNewGrab);
434 ok = FALSE;
436 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB,
437 (pointer)pNewGrab))
438 ok = FALSE;
439 else
440 adds[nadds++] = pNewGrab;
442 else if (pMinuendGrab->detail.exact == AnyKey)
444 UPDATE(grab->modifiersDetail.pMask,
445 pMinuendGrab->modifiersDetail.exact);
447 else
449 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact);
453 if (!ok)
455 for (i = 0; i < nadds; i++)
456 FreeResource(adds[i]->resource, RT_NONE);
457 for (i = 0; i < nups; i++)
458 xfree(details[i]);
460 else
462 for (i = 0; i < ndels; i++)
463 FreeResource(deletes[i]->resource, RT_NONE);
464 for (i = 0; i < nadds; i++)
466 grab = adds[i];
467 grab->next = grab->window->optional->passiveGrabs;
468 grab->window->optional->passiveGrabs = grab;
470 for (i = 0; i < nups; i++)
472 xfree(*updates[i]);
473 *updates[i] = details[i];
476 DEALLOCATE_LOCAL(details);
477 DEALLOCATE_LOCAL(updates);
478 DEALLOCATE_LOCAL(adds);
479 DEALLOCATE_LOCAL(deletes);
480 return ok;
482 #undef UPDATE