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