1 /*
2
3 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice (including the next
13 paragraph) shall be included in all copies or substantial portions of the
14 Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23
24 */
25 /********************************************************
26
27 Copyright 1988 by Hewlett-Packard Company
28 Copyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts
29
30 Permission to use, copy, modify, and distribute this software
31 and its documentation for any purpose and without fee is hereby
32 granted, provided that the above copyright notice appear in all
33 copies and that both that copyright notice and this permission
34 notice appear in supporting documentation, and that the names of
35 Hewlett-Packard or Digital not be used in advertising or
36 publicity pertaining to distribution of the software without specific,
37 written prior permission.
38
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.
46
47 ********************************************************/
48
49 /*
50
51 Copyright 1987, 1988, 1989, 1990, 1994, 1998 The Open Group
52
53 Permission to use, copy, modify, distribute, and sell this software and its
54 documentation for any purpose is hereby granted without fee, provided that
55 the above copyright notice appear in all copies and that both that
56 copyright notice and this permission notice appear in supporting
57 documentation.
58
59 The above copyright notice and this permission notice shall be included in
60 all copies or substantial portions of the Software.
61
62 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
66 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
67 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68
69 Except as contained in this notice, the name of The Open Group shall not be
70 used in advertising or otherwise to promote the sale, use or other dealings
71 in this Software without prior written authorization from The Open Group.
72
73 */
74
75 #ifdef HAVE_CONFIG_H
76 #include <config.h>
77 #endif
78 #include "IntrinsicI.h"
79 #include "StringDefs.h"
80 #include "PassivGraI.h"
81
82 /* typedef unsigned long Mask; */
83 #define BITMASK(i) (((Mask)1) << ((i) & 31))
84 #define MASKIDX(i) ((i) >> 5)
85 #define MASKWORD(buf, i) buf[MASKIDX(i)]
86 #define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
87 #define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
88 #define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
89 #define MasksPerDetailMask 8
90
91 #define pDisplay(grabPtr) (((grabPtr)->widget)->core.screen->display)
92 #define pWindow(grabPtr) (((grabPtr)->widget)->core.window)
93
94 /***************************************************************************/
95 /*********************** Internal Support Routines *************************/
96 /***************************************************************************/
97
98 /*
99 * Turn off (clear) the bit in the specified detail mask which is associated
100 * with the detail.
101 */
102
103 static void
DeleteDetailFromMask(Mask ** ppDetailMask,unsigned short detail)104 DeleteDetailFromMask(Mask **ppDetailMask, unsigned short detail)
105 {
106 Mask *pDetailMask = *ppDetailMask;
107
108 if (!pDetailMask) {
109 int i;
110
111 pDetailMask = (Mask *) __XtMalloc(sizeof(Mask) * MasksPerDetailMask);
112 for (i = MasksPerDetailMask; --i >= 0;)
113 pDetailMask[i] = (unsigned long) (~0);
114 *ppDetailMask = pDetailMask;
115 }
116 BITCLEAR((pDetailMask), detail);
117 }
118
119 /*
120 * Make an exact copy of the specified detail mask.
121 */
122
123 static Mask *
CopyDetailMask(Mask * pOriginalDetailMask)124 CopyDetailMask(Mask *pOriginalDetailMask)
125 {
126 Mask *pTempMask;
127 int i;
128
129 if (!pOriginalDetailMask)
130 return NULL;
131
132 pTempMask = (Mask *) __XtMalloc(sizeof(Mask) * MasksPerDetailMask);
133
134 for (i = 0; i < MasksPerDetailMask; i++)
135 pTempMask[i] = pOriginalDetailMask[i];
136
137 return pTempMask;
138 }
139
140 /*
141 * Allocate a new grab entry, and fill in all of the fields using the
142 * specified parameters.
143 */
144
145 static XtServerGrabPtr
CreateGrab(Widget widget,Boolean ownerEvents,Modifiers modifiers,KeyCode keybut,int pointer_mode,int keyboard_mode,Mask event_mask,Window confine_to,Cursor cursor,Boolean need_ext)146 CreateGrab(Widget widget,
147 Boolean ownerEvents,
148 Modifiers modifiers,
149 KeyCode keybut,
150 int pointer_mode,
151 int keyboard_mode,
152 Mask event_mask,
153 Window confine_to,
154 Cursor cursor,
155 Boolean need_ext)
156 {
157 XtServerGrabPtr grab;
158
159 if (confine_to || cursor)
160 need_ext = True;
161 grab = (XtServerGrabPtr) __XtMalloc(sizeof(XtServerGrabRec) +
162 (need_ext ? sizeof(XtServerGrabExtRec)
163 : 0));
164 grab->next = NULL;
165 grab->widget = widget;
166 XtSetBit(grab->ownerEvents, ownerEvents);
167 XtSetBit(grab->pointerMode, pointer_mode);
168 XtSetBit(grab->keyboardMode, keyboard_mode);
169 grab->eventMask = (unsigned short) event_mask;
170 XtSetBit(grab->hasExt, need_ext);
171 grab->confineToIsWidgetWin = (XtWindow(widget) == confine_to);
172 grab->modifiers = (unsigned short) modifiers;
173 grab->keybut = keybut;
174 if (need_ext) {
175 XtServerGrabExtPtr ext = GRABEXT(grab);
176
177 ext->pModifiersMask = NULL;
178 ext->pKeyButMask = NULL;
179 ext->confineTo = confine_to;
180 ext->cursor = cursor;
181 }
182 return grab;
183 }
184
185 /*
186 * Free up the space occupied by a grab entry.
187 */
188
189 static void
FreeGrab(XtServerGrabPtr pGrab)190 FreeGrab(XtServerGrabPtr pGrab)
191 {
192 if (pGrab->hasExt) {
193 XtServerGrabExtPtr ext = GRABEXT(pGrab);
194 XtFree((char *)ext->pModifiersMask);
195 XtFree((char *)ext->pKeyButMask);
196 }
197 XtFree((char *) pGrab);
198 }
199
200 typedef struct _DetailRec {
201 unsigned short exact;
202 Mask *pMask;
203 } DetailRec, *DetailPtr;
204
205 /*
206 * If the first detail is set to 'exception' and the second detail
207 * is contained in the mask of the first, then TRUE is returned.
208 */
209
210 static Bool
IsInGrabMask(register DetailPtr firstDetail,register DetailPtr secondDetail,unsigned short exception)211 IsInGrabMask(register DetailPtr firstDetail,
212 register DetailPtr secondDetail,
213 unsigned short exception)
214 {
215 if (firstDetail->exact == exception) {
216 if (!firstDetail->pMask)
217 return TRUE;
218
219 /* (at present) never called with two non-null pMasks */
220 if (secondDetail->exact == exception)
221 return FALSE;
222
223 if (GETBIT(firstDetail->pMask, secondDetail->exact))
224 return TRUE;
225 }
226
227 return FALSE;
228 }
229
230 /*
231 * If neither of the details is set to 'exception', and they match
232 * exactly, then TRUE is returned.
233 */
234
235 static Bool
IdenticalExactDetails(unsigned short firstExact,unsigned short secondExact,unsigned short exception)236 IdenticalExactDetails(unsigned short firstExact,
237 unsigned short secondExact,
238 unsigned short exception)
239 {
240 if ((firstExact == exception) || (secondExact == exception))
241 return FALSE;
242
243 if (firstExact == secondExact)
244 return TRUE;
245
246 return FALSE;
247 }
248
249 /*
250 * If the first detail is set to 'exception', and its mask has the bit
251 * enabled which corresponds to the second detail, OR if neither of the
252 * details is set to 'exception' and the details match exactly, then
253 * TRUE is returned.
254 */
255
256 static Bool
DetailSupersedesSecond(register DetailPtr firstDetail,register DetailPtr secondDetail,unsigned short exception)257 DetailSupersedesSecond(register DetailPtr firstDetail,
258 register DetailPtr secondDetail,
259 unsigned short exception)
260 {
261 if (IsInGrabMask(firstDetail, secondDetail, exception))
262 return TRUE;
263
264 if (IdenticalExactDetails(firstDetail->exact, secondDetail->exact,
265 exception))
266 return TRUE;
267
268 return FALSE;
269 }
270
271 /*
272 * If the two grab events match exactly, or if the first grab entry
273 * 'encompasses' the second grab entry, then TRUE is returned.
274 */
275
276 static Bool
GrabSupersedesSecond(register XtServerGrabPtr pFirstGrab,register XtServerGrabPtr pSecondGrab)277 GrabSupersedesSecond(register XtServerGrabPtr pFirstGrab,
278 register XtServerGrabPtr pSecondGrab)
279 {
280 DetailRec first, second;
281
282 first.exact = pFirstGrab->modifiers;
283 if (pFirstGrab->hasExt)
284 first.pMask = GRABEXT(pFirstGrab)->pModifiersMask;
285 else
286 first.pMask = NULL;
287 second.exact = pSecondGrab->modifiers;
288 if (pSecondGrab->hasExt)
289 second.pMask = GRABEXT(pSecondGrab)->pModifiersMask;
290 else
291 second.pMask = NULL;
292 if (!DetailSupersedesSecond(&first, &second, (unsigned short) AnyModifier))
293 return FALSE;
294
295 first.exact = pFirstGrab->keybut;
296 if (pFirstGrab->hasExt)
297 first.pMask = GRABEXT(pFirstGrab)->pKeyButMask;
298 else
299 first.pMask = NULL;
300 second.exact = pSecondGrab->keybut;
301 if (pSecondGrab->hasExt)
302 second.pMask = GRABEXT(pSecondGrab)->pKeyButMask;
303 else
304 second.pMask = NULL;
305 if (DetailSupersedesSecond(&first, &second, (unsigned short) AnyKey))
306 return TRUE;
307
308 return FALSE;
309 }
310
311 /*
312 * Two grabs are considered to be matching if either of the following are true:
313 *
314 * 1) The two grab entries match exactly, or the first grab entry
315 * encompasses the second grab entry.
316 * 2) The second grab entry encompasses the first grab entry.
317 * 3) The keycodes match exactly, and one entry's modifiers encompasses
318 * the others.
319 * 4) The keycode for one entry encompasses the other, and the detail
320 * for the other entry encompasses the first.
321 */
322
323 static Bool
GrabMatchesSecond(register XtServerGrabPtr pFirstGrab,register XtServerGrabPtr pSecondGrab)324 GrabMatchesSecond(register XtServerGrabPtr pFirstGrab,
325 register XtServerGrabPtr pSecondGrab)
326 {
327 DetailRec firstD, firstM, secondD, secondM;
328
329 if (pDisplay(pFirstGrab) != pDisplay(pSecondGrab))
330 return FALSE;
331
332 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab))
333 return TRUE;
334
335 if (GrabSupersedesSecond(pSecondGrab, pFirstGrab))
336 return TRUE;
337
338 firstD.exact = pFirstGrab->keybut;
339 firstM.exact = pFirstGrab->modifiers;
340 if (pFirstGrab->hasExt) {
341 firstD.pMask = GRABEXT(pFirstGrab)->pKeyButMask;
342 firstM.pMask = GRABEXT(pFirstGrab)->pModifiersMask;
343 }
344 else {
345 firstD.pMask = NULL;
346 firstM.pMask = NULL;
347 }
348 secondD.exact = pSecondGrab->keybut;
349 secondM.exact = pSecondGrab->modifiers;
350 if (pSecondGrab->hasExt) {
351 secondD.pMask = GRABEXT(pSecondGrab)->pKeyButMask;
352 secondM.pMask = GRABEXT(pSecondGrab)->pModifiersMask;
353 }
354 else {
355 secondD.pMask = NULL;
356 secondM.pMask = NULL;
357 }
358
359 if (DetailSupersedesSecond(&secondD, &firstD, (unsigned short) AnyKey) &&
360 DetailSupersedesSecond(&firstM, &secondM, (unsigned short) AnyModifier))
361 return TRUE;
362
363 if (DetailSupersedesSecond(&firstD, &secondD, (unsigned short) AnyKey) &&
364 DetailSupersedesSecond(&secondM, &firstM, (unsigned short) AnyModifier))
365 return TRUE;
366
367 return FALSE;
368 }
369
370 /*
371 * Delete a grab combination from the passive grab list. Each entry will
372 * be checked to see if it is affected by the grab being deleted. This
373 * may result in multiple entries being modified/deleted.
374 */
375
376 static void
DeleteServerGrabFromList(XtServerGrabPtr * passiveListPtr,XtServerGrabPtr pMinuendGrab)377 DeleteServerGrabFromList(XtServerGrabPtr *passiveListPtr,
378 XtServerGrabPtr pMinuendGrab)
379 {
380 register XtServerGrabPtr *next;
381 register XtServerGrabPtr grab;
382 register XtServerGrabExtPtr ext;
383
384 for (next = passiveListPtr; (grab = *next);) {
385 if (GrabMatchesSecond(grab, pMinuendGrab) &&
386 (pDisplay(grab) == pDisplay(pMinuendGrab))) {
387 if (GrabSupersedesSecond(pMinuendGrab, grab)) {
388 /*
389 * The entry being deleted encompasses the list entry,
390 * so delete the list entry.
391 */
392 *next = grab->next;
393 FreeGrab(grab);
394 continue;
395 }
396
397 if (!grab->hasExt) {
398 grab = (XtServerGrabPtr)
399 XtRealloc((char *) grab, (sizeof(XtServerGrabRec) +
400 sizeof(XtServerGrabExtRec)));
401 *next = grab;
402 grab->hasExt = True;
403 ext = GRABEXT(grab);
404 ext->pKeyButMask = NULL;
405 ext->pModifiersMask = NULL;
406 ext->confineTo = None;
407 ext->cursor = None;
408 }
409 else
410 ext = GRABEXT(grab);
411 if ((grab->keybut == AnyKey) && (grab->modifiers != AnyModifier)) {
412 /*
413 * If the list entry has the key detail of AnyKey, and
414 * a modifier detail not set to AnyModifier, then we
415 * simply need to turn off the key detail bit in the
416 * list entry's key detail mask.
417 */
418 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
419 }
420 else if ((grab->modifiers == AnyModifier) &&
421 (grab->keybut != AnyKey)) {
422 /*
423 * The list entry has a specific key detail, but its
424 * modifier detail is set to AnyModifier; so, we only
425 * need to turn off the specified modifier combination
426 * in the list entry's modifier mask.
427 */
428 DeleteDetailFromMask(&ext->pModifiersMask,
429 pMinuendGrab->modifiers);
430 }
431 else if ((pMinuendGrab->keybut != AnyKey) &&
432 (pMinuendGrab->modifiers != AnyModifier)) {
433 /*
434 * The list entry has a key detail of AnyKey and a
435 * modifier detail of AnyModifier; the entry being
436 * deleted has a specific key and a specific modifier
437 * combination. Therefore, we need to mask off the
438 * keycode from the list entry, and also create a
439 * new entry for this keycode, which has a modifier
440 * mask set to AnyModifier & ~(deleted modifiers).
441 */
442 XtServerGrabPtr pNewGrab;
443
444 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
445 pNewGrab = CreateGrab(grab->widget,
446 (Boolean) grab->ownerEvents,
447 (Modifiers) AnyModifier,
448 pMinuendGrab->keybut,
449 (int) grab->pointerMode,
450 (int) grab->keyboardMode,
451 (Mask) 0, (Window) 0, (Cursor) 0, True);
452 GRABEXT(pNewGrab)->pModifiersMask =
453 CopyDetailMask(ext->pModifiersMask);
454
455 DeleteDetailFromMask(&GRABEXT(pNewGrab)->pModifiersMask,
456 pMinuendGrab->modifiers);
457
458 pNewGrab->next = *passiveListPtr;
459 *passiveListPtr = pNewGrab;
460 }
461 else if (pMinuendGrab->keybut == AnyKey) {
462 /*
463 * The list entry has keycode AnyKey and modifier
464 * AnyModifier; the entry being deleted has
465 * keycode AnyKey and specific modifiers. So we
466 * simply need to mask off the specified modifier
467 * combination.
468 */
469 DeleteDetailFromMask(&ext->pModifiersMask,
470 pMinuendGrab->modifiers);
471 }
472 else {
473 /*
474 * The list entry has keycode AnyKey and modifier
475 * AnyModifier; the entry being deleted has a
476 * specific keycode and modifier AnyModifier. So
477 * we simply need to mask off the specified
478 * keycode.
479 */
480 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
481 }
482 }
483 next = &(*next)->next;
484 }
485 }
486
487 static void
DestroyPassiveList(XtServerGrabPtr * passiveListPtr)488 DestroyPassiveList(XtServerGrabPtr *passiveListPtr)
489 {
490 XtServerGrabPtr next, grab;
491
492 for (next = *passiveListPtr; next;) {
493 grab = next;
494 next = grab->next;
495
496 /* not necessary to explicitly ungrab key or button;
497 * window is being destroyed so server will take care of it.
498 */
499
500 FreeGrab(grab);
501 }
502 }
503
504 /*
505 * This function is called at widget destroy time to clean up
506 */
507 void
_XtDestroyServerGrabs(Widget w,XtPointer closure,XtPointer call_data _X_UNUSED)508 _XtDestroyServerGrabs(Widget w,
509 XtPointer closure,
510 XtPointer call_data _X_UNUSED)
511 {
512 XtPerWidgetInput pwi = (XtPerWidgetInput) closure;
513 XtPerDisplayInput pdi;
514
515 LOCK_PROCESS;
516 pdi = _XtGetPerDisplayInput(XtDisplay(w));
517 _XtClearAncestorCache(w);
518 UNLOCK_PROCESS;
519
520 /* Remove the active grab, if necessary */
521 if ((pdi->keyboard.grabType != XtNoServerGrab) &&
522 (pdi->keyboard.grab.widget == w)) {
523 pdi->keyboard.grabType = XtNoServerGrab;
524 pdi->activatingKey = (KeyCode) 0;
525 }
526 if ((pdi->pointer.grabType != XtNoServerGrab) &&
527 (pdi->pointer.grab.widget == w))
528 pdi->pointer.grabType = XtNoServerGrab;
529
530 DestroyPassiveList(&pwi->keyList);
531 DestroyPassiveList(&pwi->ptrList);
532
533 _XtFreePerWidgetInput(w, pwi);
534 }
535
536 /*
537 * If the incoming event is on the passive grab list, then activate
538 * the grab. The grab will remain in effect until the key is released.
539 */
540
541 XtServerGrabPtr
_XtCheckServerGrabsOnWidget(XEvent * event,Widget widget,_XtBoolean isKeyboard)542 _XtCheckServerGrabsOnWidget(XEvent *event, Widget widget, _XtBoolean isKeyboard)
543 {
544 register XtServerGrabPtr grab;
545 XtServerGrabRec tempGrab;
546 XtServerGrabPtr *passiveListPtr;
547 XtPerWidgetInput pwi;
548
549 LOCK_PROCESS;
550 pwi = _XtGetPerWidgetInput(widget, FALSE);
551 UNLOCK_PROCESS;
552 if (!pwi)
553 return (XtServerGrabPtr) NULL;
554 if (isKeyboard)
555 passiveListPtr = &pwi->keyList;
556 else
557 passiveListPtr = &pwi->ptrList;
558
559 /*
560 * if either there is no entry in the context manager or the entry
561 * is empty, or the keyboard is grabed, then no work to be done
562 */
563 if (!*passiveListPtr)
564 return (XtServerGrabPtr) NULL;
565
566 /* Take only the lower thirteen bits as modifier state. The X Keyboard
567 * Extension may be representing keyboard group state in two upper bits.
568 */
569 tempGrab.widget = widget;
570 tempGrab.keybut = (KeyCode) event->xkey.keycode; /* also xbutton.button */
571 tempGrab.modifiers = event->xkey.state & 0x1FFF; /*also xbutton.state */
572 tempGrab.hasExt = False;
573
574 for (grab = *passiveListPtr; grab; grab = grab->next) {
575 if (GrabMatchesSecond(&tempGrab, grab))
576 return (grab);
577 }
578 return (XtServerGrabPtr) NULL;
579 }
580
581 /*
582 * This handler is needed to guarantee that we see releases on passive
583 * button grabs for widgets that haven't selected for button release.
584 */
585
586 static void
ActiveHandler(Widget widget _X_UNUSED,XtPointer pdi _X_UNUSED,XEvent * event _X_UNUSED,Boolean * cont _X_UNUSED)587 ActiveHandler(Widget widget _X_UNUSED,
588 XtPointer pdi _X_UNUSED,
589 XEvent *event _X_UNUSED,
590 Boolean *cont _X_UNUSED)
591 {
592 /* nothing */
593 }
594
595 /*
596 * MakeGrab
597 */
598 static void
MakeGrab(XtServerGrabPtr grab,XtServerGrabPtr * passiveListPtr,Boolean isKeyboard,XtPerDisplayInput pdi,XtPerWidgetInput pwi)599 MakeGrab(XtServerGrabPtr grab,
600 XtServerGrabPtr *passiveListPtr,
601 Boolean isKeyboard,
602 XtPerDisplayInput pdi,
603 XtPerWidgetInput pwi)
604 {
605 if (!isKeyboard && !pwi->active_handler_added) {
606 XtAddEventHandler(grab->widget, ButtonReleaseMask, FALSE,
607 ActiveHandler, (XtPointer) pdi);
608 pwi->active_handler_added = TRUE;
609 }
610
611 if (isKeyboard) {
612 XGrabKey(pDisplay(grab),
613 grab->keybut, grab->modifiers,
614 pWindow(grab), grab->ownerEvents,
615 grab->pointerMode, grab->keyboardMode);
616 }
617 else {
618 Window confineTo = None;
619 Cursor cursor = None;
620
621 if (grab->hasExt) {
622 if (grab->confineToIsWidgetWin)
623 confineTo = XtWindow(grab->widget);
624 else
625 confineTo = GRABEXT(grab)->confineTo;
626 cursor = GRABEXT(grab)->cursor;
627 }
628 XGrabButton(pDisplay(grab),
629 grab->keybut, grab->modifiers,
630 pWindow(grab), grab->ownerEvents, grab->eventMask,
631 grab->pointerMode, grab->keyboardMode, confineTo, cursor);
632 }
633
634 /* Add the new grab entry to the passive key grab list */
635 grab->next = *passiveListPtr;
636 *passiveListPtr = grab;
637 }
638
639 static void
MakeGrabs(XtServerGrabPtr * passiveListPtr,Boolean isKeyboard,XtPerDisplayInput pdi)640 MakeGrabs(XtServerGrabPtr *passiveListPtr,
641 Boolean isKeyboard,
642 XtPerDisplayInput pdi)
643 {
644 XtServerGrabPtr next = *passiveListPtr;
645
646 /*
647 * make MakeGrab build a new list that has had the merge
648 * processing done on it. Start with an empty list
649 * (passiveListPtr).
650 */
651 LOCK_PROCESS;
652 *passiveListPtr = NULL;
653 while (next) {
654 XtServerGrabPtr grab;
655 XtPerWidgetInput pwi;
656
657 grab = next;
658 next = grab->next;
659 pwi = _XtGetPerWidgetInput(grab->widget, FALSE);
660 MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi);
661 }
662 UNLOCK_PROCESS;
663 }
664
665 /*
666 * This function is the event handler attached to the associated widget
667 * when grabs need to be added, but the widget is not yet realized. When
668 * it is first mapped, this handler will be invoked, and it will add all
669 * needed grabs.
670 */
671
672 static void
RealizeHandler(Widget widget,XtPointer closure,XEvent * event _X_UNUSED,Boolean * cont _X_UNUSED)673 RealizeHandler(Widget widget,
674 XtPointer closure,
675 XEvent *event _X_UNUSED,
676 Boolean *cont _X_UNUSED)
677 {
678 XtPerWidgetInput pwi = (XtPerWidgetInput) closure;
679 XtPerDisplayInput pdi;
680
681 LOCK_PROCESS;
682 pdi = _XtGetPerDisplayInput(XtDisplay(widget));
683 UNLOCK_PROCESS;
684 MakeGrabs(&pwi->keyList, KEYBOARD, pdi);
685 MakeGrabs(&pwi->ptrList, POINTER, pdi);
686
687 XtRemoveEventHandler(widget, XtAllEvents, True,
688 RealizeHandler, (XtPointer) pwi);
689 pwi->realize_handler_added = FALSE;
690 }
691
692 /***************************************************************************/
693 /**************************** Global Routines ******************************/
694 /***************************************************************************/
695
696 /*
697 * Routine used by an application to set up a passive grab for a key/modifier
698 * combination.
699 */
700
701 static void
GrabKeyOrButton(Widget widget,KeyCode keyOrButton,Modifiers modifiers,Boolean owner_events,int pointer_mode,int keyboard_mode,Mask event_mask,Window confine_to,Cursor cursor,Boolean isKeyboard)702 GrabKeyOrButton(Widget widget,
703 KeyCode keyOrButton,
704 Modifiers modifiers,
705 Boolean owner_events,
706 int pointer_mode,
707 int keyboard_mode,
708 Mask event_mask,
709 Window confine_to,
710 Cursor cursor,
711 Boolean isKeyboard)
712 {
713 XtServerGrabPtr *passiveListPtr;
714 XtServerGrabPtr newGrab;
715 XtPerWidgetInput pwi;
716 XtPerDisplayInput pdi;
717
718 XtCheckSubclass(widget, coreWidgetClass, "in XtGrabKey or XtGrabButton");
719 LOCK_PROCESS;
720 pwi = _XtGetPerWidgetInput(widget, TRUE);
721 if (isKeyboard)
722 passiveListPtr = &pwi->keyList;
723 else
724 passiveListPtr = &pwi->ptrList;
725 pdi = _XtGetPerDisplayInput(XtDisplay(widget));
726 UNLOCK_PROCESS;
727 newGrab = CreateGrab(widget, owner_events, modifiers,
728 keyOrButton, pointer_mode, keyboard_mode,
729 event_mask, confine_to, cursor, False);
730 /*
731 * if the widget is realized then process the entry into the grab
732 * list. else if the list is empty (i.e. first time) then add the
733 * event handler. then add the raw entry to the list for processing
734 * in the handler at realize time.
735 */
736 if (XtIsRealized(widget))
737 MakeGrab(newGrab, passiveListPtr, isKeyboard, pdi, pwi);
738 else {
739 if (!pwi->realize_handler_added) {
740 XtAddEventHandler(widget, StructureNotifyMask, FALSE,
741 RealizeHandler, (XtPointer) pwi);
742 pwi->realize_handler_added = TRUE;
743 }
744
745 while (*passiveListPtr)
746 passiveListPtr = &(*passiveListPtr)->next;
747 *passiveListPtr = newGrab;
748 }
749 }
750
751 static void
UngrabKeyOrButton(Widget widget,int keyOrButton,Modifiers modifiers,Boolean isKeyboard)752 UngrabKeyOrButton(Widget widget,
753 int keyOrButton,
754 Modifiers modifiers,
755 Boolean isKeyboard)
756 {
757 XtServerGrabRec tempGrab;
758 XtPerWidgetInput pwi;
759
760 XtCheckSubclass(widget, coreWidgetClass,
761 "in XtUngrabKey or XtUngrabButton");
762
763 /* Build a temporary grab list entry */
764 tempGrab.widget = widget;
765 tempGrab.modifiers = (unsigned short) modifiers;
766 tempGrab.keybut = (KeyCode) keyOrButton;
767 tempGrab.hasExt = False;
768
769 LOCK_PROCESS;
770 pwi = _XtGetPerWidgetInput(widget, FALSE);
771 UNLOCK_PROCESS;
772 /*
773 * if there is no entry in the context manager then somethings wrong
774 */
775 if (!pwi) {
776 XtAppWarningMsg(XtWidgetToApplicationContext(widget),
777 "invalidGrab", "ungrabKeyOrButton", XtCXtToolkitError,
778 "Attempt to remove nonexistent passive grab",
779 NULL, NULL);
780 return;
781 }
782
783 if (XtIsRealized(widget)) {
784 if (isKeyboard)
785 XUngrabKey(widget->core.screen->display,
786 keyOrButton, (unsigned int) modifiers,
787 widget->core.window);
788 else
789 XUngrabButton(widget->core.screen->display,
790 (unsigned) keyOrButton, (unsigned int) modifiers,
791 widget->core.window);
792 }
793
794 /* Delete all entries which are encompassed by the specified grab. */
795 DeleteServerGrabFromList(isKeyboard ? &pwi->keyList : &pwi->ptrList,
796 &tempGrab);
797 }
798
799 void
XtGrabKey(Widget widget,_XtKeyCode keycode,Modifiers modifiers,_XtBoolean owner_events,int pointer_mode,int keyboard_mode)800 XtGrabKey(Widget widget,
801 _XtKeyCode keycode,
802 Modifiers modifiers,
803 _XtBoolean owner_events,
804 int pointer_mode,
805 int keyboard_mode)
806 {
807 WIDGET_TO_APPCON(widget);
808
809 LOCK_APP(app);
810 GrabKeyOrButton(widget, (KeyCode) keycode, modifiers,
811 (Boolean) owner_events, pointer_mode, keyboard_mode,
812 (Mask) 0, (Window) None, (Cursor) None, KEYBOARD);
813 UNLOCK_APP(app);
814 }
815
816 void
XtGrabButton(Widget widget,int button,Modifiers modifiers,_XtBoolean owner_events,unsigned int event_mask,int pointer_mode,int keyboard_mode,Window confine_to,Cursor cursor)817 XtGrabButton(Widget widget,
818 int button,
819 Modifiers modifiers,
820 _XtBoolean owner_events,
821 unsigned int event_mask,
822 int pointer_mode,
823 int keyboard_mode,
824 Window confine_to,
825 Cursor cursor)
826 {
827 WIDGET_TO_APPCON(widget);
828
829 LOCK_APP(app);
830 GrabKeyOrButton(widget, (KeyCode) button, modifiers, (Boolean) owner_events,
831 pointer_mode, keyboard_mode,
832 (Mask) event_mask, confine_to, cursor, POINTER);
833 UNLOCK_APP(app);
834 }
835
836 /*
837 * Routine used by an application to clear a passive grab for a key/modifier
838 * combination.
839 */
840
841 void
XtUngrabKey(Widget widget,_XtKeyCode keycode,Modifiers modifiers)842 XtUngrabKey(Widget widget, _XtKeyCode keycode, Modifiers modifiers)
843 {
844 WIDGET_TO_APPCON(widget);
845
846 LOCK_APP(app);
847 UngrabKeyOrButton(widget, (int) keycode, modifiers, KEYBOARD);
848 UNLOCK_APP(app);
849 }
850
851 void
XtUngrabButton(Widget widget,unsigned int button,Modifiers modifiers)852 XtUngrabButton(Widget widget, unsigned int button, Modifiers modifiers)
853 {
854 WIDGET_TO_APPCON(widget);
855
856 LOCK_APP(app);
857 UngrabKeyOrButton(widget, (KeyCode) button, modifiers, POINTER);
858 UNLOCK_APP(app);
859 }
860
861 /*
862 * Active grab of Device. clear any client side grabs so we dont lock
863 */
864 static int
GrabDevice(Widget widget,Boolean owner_events,int pointer_mode,int keyboard_mode,Mask event_mask,Window confine_to,Cursor cursor,Time time,Boolean isKeyboard)865 GrabDevice(Widget widget,
866 Boolean owner_events,
867 int pointer_mode,
868 int keyboard_mode,
869 Mask event_mask,
870 Window confine_to,
871 Cursor cursor,
872 Time time,
873 Boolean isKeyboard)
874 {
875 XtPerDisplayInput pdi;
876 int returnVal;
877
878 XtCheckSubclass(widget, coreWidgetClass,
879 "in XtGrabKeyboard or XtGrabPointer");
880 if (!XtIsRealized(widget))
881 return GrabNotViewable;
882 LOCK_PROCESS;
883 pdi = _XtGetPerDisplayInput(XtDisplay(widget));
884 UNLOCK_PROCESS;
885 if (!isKeyboard)
886 returnVal = XGrabPointer(XtDisplay(widget), XtWindow(widget),
887 owner_events, (unsigned) event_mask,
888 pointer_mode, keyboard_mode,
889 confine_to, cursor, time);
890 else
891 returnVal = XGrabKeyboard(XtDisplay(widget), XtWindow(widget),
892 owner_events, pointer_mode,
893 keyboard_mode, time);
894
895 if (returnVal == GrabSuccess) {
896 XtDevice device;
897
898 device = isKeyboard ? &pdi->keyboard : &pdi->pointer;
899
900 /* fill in the server grab rec */
901 device->grab.widget = widget;
902 device->grab.modifiers = 0;
903 device->grab.keybut = 0;
904 XtSetBit(device->grab.ownerEvents, owner_events);
905 XtSetBit(device->grab.pointerMode, pointer_mode);
906 XtSetBit(device->grab.keyboardMode, keyboard_mode);
907 device->grab.hasExt = False;
908 device->grabType = XtActiveServerGrab;
909 pdi->activatingKey = (KeyCode) 0;
910 }
911 return returnVal;
912 }
913
914 static void
UngrabDevice(Widget widget,Time time,Boolean isKeyboard)915 UngrabDevice(Widget widget, Time time, Boolean isKeyboard)
916 {
917 XtPerDisplayInput pdi;
918 XtDevice device;
919
920 LOCK_PROCESS;
921 pdi = _XtGetPerDisplayInput(XtDisplay(widget));
922 UNLOCK_PROCESS;
923 device = isKeyboard ? &pdi->keyboard : &pdi->pointer;
924
925 XtCheckSubclass(widget, coreWidgetClass,
926 "in XtUngrabKeyboard or XtUngrabPointer");
927
928 if (device->grabType != XtNoServerGrab) {
929
930 if (device->grabType != XtPseudoPassiveServerGrab
931 && XtIsRealized(widget)) {
932 if (isKeyboard)
933 XUngrabKeyboard(XtDisplay(widget), time);
934 else
935 XUngrabPointer(XtDisplay(widget), time);
936 }
937 device->grabType = XtNoServerGrab;
938 pdi->activatingKey = (KeyCode) 0;
939 }
940 }
941
942 /*
943 * Active grab of keyboard. clear any client side grabs so we dont lock
944 */
945 int
XtGrabKeyboard(Widget widget,_XtBoolean owner_events,int pointer_mode,int keyboard_mode,Time time)946 XtGrabKeyboard(Widget widget,
947 _XtBoolean owner_events,
948 int pointer_mode,
949 int keyboard_mode,
950 Time time)
951 {
952 int retval;
953
954 WIDGET_TO_APPCON(widget);
955
956 LOCK_APP(app);
957 retval = GrabDevice(widget, (Boolean) owner_events,
958 pointer_mode, keyboard_mode,
959 (Mask) 0, (Window) None, (Cursor) None, time, KEYBOARD);
960 UNLOCK_APP(app);
961 return retval;
962 }
963
964 /*
965 * Ungrab the keyboard
966 */
967
968 void
XtUngrabKeyboard(Widget widget,Time time)969 XtUngrabKeyboard(Widget widget, Time time)
970 {
971 WIDGET_TO_APPCON(widget);
972
973 LOCK_APP(app);
974 UngrabDevice(widget, time, KEYBOARD);
975 UNLOCK_APP(app);
976 }
977
978 /*
979 * grab the pointer
980 */
981 int
XtGrabPointer(Widget widget,_XtBoolean owner_events,unsigned int event_mask,int pointer_mode,int keyboard_mode,Window confine_to,Cursor cursor,Time time)982 XtGrabPointer(Widget widget,
983 _XtBoolean owner_events,
984 unsigned int event_mask,
985 int pointer_mode,
986 int keyboard_mode,
987 Window confine_to,
988 Cursor cursor,
989 Time time)
990 {
991 int retval;
992
993 WIDGET_TO_APPCON(widget);
994
995 LOCK_APP(app);
996 retval = GrabDevice(widget, (Boolean) owner_events,
997 pointer_mode, keyboard_mode,
998 (Mask) event_mask, confine_to, cursor, time, POINTER);
999 UNLOCK_APP(app);
1000 return retval;
1001 }
1002
1003 /*
1004 * Ungrab the pointer
1005 */
1006
1007 void
XtUngrabPointer(Widget widget,Time time)1008 XtUngrabPointer(Widget widget, Time time)
1009 {
1010 WIDGET_TO_APPCON(widget);
1011
1012 LOCK_APP(app);
1013 UngrabDevice(widget, time, POINTER);
1014 UNLOCK_APP(app);
1015 }
1016
1017 void
_XtRegisterPassiveGrabs(Widget widget)1018 _XtRegisterPassiveGrabs(Widget widget)
1019 {
1020 XtPerWidgetInput pwi = _XtGetPerWidgetInput(widget, FALSE);
1021
1022 if (pwi != NULL && !pwi->realize_handler_added) {
1023 XtAddEventHandler(widget, StructureNotifyMask, FALSE,
1024 RealizeHandler, (XtPointer) pwi);
1025 pwi->realize_handler_added = TRUE;
1026 }
1027 }
1028