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