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