11477040fSmrg/*
21477040fSmrg
3fdf6a26fSmrgCopyright (c) 1993, Oracle and/or its affiliates.
41477040fSmrg
51477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
61477040fSmrgcopy of this software and associated documentation files (the "Software"),
71477040fSmrgto deal in the Software without restriction, including without limitation
81477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
91477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
101477040fSmrgSoftware is furnished to do so, subject to the following conditions:
111477040fSmrg
121477040fSmrgThe above copyright notice and this permission notice (including the next
131477040fSmrgparagraph) shall be included in all copies or substantial portions of the
141477040fSmrgSoftware.
15444c061aSmrg
161477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
211477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
221477040fSmrgDEALINGS IN THE SOFTWARE.
231477040fSmrg
241477040fSmrg*/
25444c061aSmrg/********************************************************
26444c061aSmrg
27444c061aSmrgCopyright 1988 by Hewlett-Packard Company
28444c061aSmrgCopyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts
29444c061aSmrg
30444c061aSmrgPermission to use, copy, modify, and distribute this software
31444c061aSmrgand its documentation for any purpose and without fee is hereby
32444c061aSmrggranted, provided that the above copyright notice appear in all
33444c061aSmrgcopies and that both that copyright notice and this permission
34444c061aSmrgnotice appear in supporting documentation, and that the names of
351477040fSmrgHewlett-Packard or Digital not be used in advertising or
36444c061aSmrgpublicity pertaining to distribution of the software without specific,
37444c061aSmrgwritten prior permission.
38444c061aSmrg
39444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45444c061aSmrgSOFTWARE.
46444c061aSmrg
47444c061aSmrg********************************************************/
48444c061aSmrg
49444c061aSmrg/*
50444c061aSmrg
51444c061aSmrgCopyright 1987, 1988, 1989, 1990, 1994, 1998  The Open Group
52444c061aSmrg
53444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
54444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
55444c061aSmrgthe above copyright notice appear in all copies and that both that
56444c061aSmrgcopyright notice and this permission notice appear in supporting
57444c061aSmrgdocumentation.
58444c061aSmrg
59444c061aSmrgThe above copyright notice and this permission notice shall be included in
60444c061aSmrgall copies or substantial portions of the Software.
61444c061aSmrg
62444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
65444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
66444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
67444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68444c061aSmrg
69444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
70444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
71444c061aSmrgin this Software without prior written authorization from The Open Group.
72444c061aSmrg
73444c061aSmrg*/
74444c061aSmrg
75444c061aSmrg#ifdef HAVE_CONFIG_H
76444c061aSmrg#include <config.h>
77444c061aSmrg#endif
78444c061aSmrg#include "IntrinsicI.h"
79444c061aSmrg#include "StringDefs.h"
80444c061aSmrg#include "PassivGraI.h"
81444c061aSmrg
82444c061aSmrg/* typedef unsigned long Mask; */
83444c061aSmrg#define BITMASK(i) (((Mask)1) << ((i) & 31))
84444c061aSmrg#define MASKIDX(i) ((i) >> 5)
85444c061aSmrg#define MASKWORD(buf, i) buf[MASKIDX(i)]
86444c061aSmrg#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
87444c061aSmrg#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
88444c061aSmrg#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
89444c061aSmrg#define MasksPerDetailMask 8
90444c061aSmrg
91444c061aSmrg#define pDisplay(grabPtr) (((grabPtr)->widget)->core.screen->display)
92444c061aSmrg#define pWindow(grabPtr) (((grabPtr)->widget)->core.window)
93444c061aSmrg
94444c061aSmrg/***************************************************************************/
95444c061aSmrg/*********************** Internal Support Routines *************************/
96444c061aSmrg/***************************************************************************/
97444c061aSmrg
98444c061aSmrg/*
99444c061aSmrg * Turn off (clear) the bit in the specified detail mask which is associated
100444c061aSmrg * with the detail.
101444c061aSmrg */
102444c061aSmrg
103a3bd7f05Smrgstatic void
104a3bd7f05SmrgDeleteDetailFromMask(Mask **ppDetailMask, unsigned short detail)
105444c061aSmrg{
106444c061aSmrg    Mask *pDetailMask = *ppDetailMask;
107444c061aSmrg
108444c061aSmrg    if (!pDetailMask) {
109a3bd7f05Smrg        int i;
110a3bd7f05Smrg
111fdf6a26fSmrg        pDetailMask = XtMallocArray(MasksPerDetailMask, (Cardinal) sizeof(Mask));
112a3bd7f05Smrg        for (i = MasksPerDetailMask; --i >= 0;)
113a3bd7f05Smrg            pDetailMask[i] = (unsigned long) (~0);
114a3bd7f05Smrg        *ppDetailMask = pDetailMask;
115444c061aSmrg    }
116444c061aSmrg    BITCLEAR((pDetailMask), detail);
117444c061aSmrg}
118444c061aSmrg
119444c061aSmrg/*
120444c061aSmrg * Make an exact copy of the specified detail mask.
121444c061aSmrg */
122444c061aSmrg
123a3bd7f05Smrgstatic Mask *
124fdf6a26fSmrgCopyDetailMask(const Mask *pOriginalDetailMask)
125444c061aSmrg{
126444c061aSmrg    Mask *pTempMask;
127444c061aSmrg    int i;
128444c061aSmrg
129444c061aSmrg    if (!pOriginalDetailMask)
130a3bd7f05Smrg        return NULL;
131444c061aSmrg
132fdf6a26fSmrg    pTempMask = XtMallocArray(MasksPerDetailMask, (Cardinal) sizeof(Mask));
133444c061aSmrg
134a3bd7f05Smrg    for (i = 0; i < MasksPerDetailMask; i++)
135a3bd7f05Smrg        pTempMask[i] = pOriginalDetailMask[i];
136444c061aSmrg
137444c061aSmrg    return pTempMask;
138444c061aSmrg}
139444c061aSmrg
140444c061aSmrg/*
141444c061aSmrg * Allocate a new grab entry, and fill in all of the fields using the
142444c061aSmrg * specified parameters.
143444c061aSmrg */
144444c061aSmrg
145a3bd7f05Smrgstatic XtServerGrabPtr
146a3bd7f05SmrgCreateGrab(Widget widget,
147a3bd7f05Smrg           Boolean ownerEvents,
148a3bd7f05Smrg           Modifiers modifiers,
149a3bd7f05Smrg           KeyCode keybut,
150a3bd7f05Smrg           int pointer_mode,
151a3bd7f05Smrg           int keyboard_mode,
152a3bd7f05Smrg           Mask event_mask,
153a3bd7f05Smrg           Window confine_to,
154a3bd7f05Smrg           Cursor cursor,
155a3bd7f05Smrg           Boolean need_ext)
156444c061aSmrg{
157444c061aSmrg    XtServerGrabPtr grab;
158444c061aSmrg
159444c061aSmrg    if (confine_to || cursor)
160a3bd7f05Smrg        need_ext = True;
161a3bd7f05Smrg    grab = (XtServerGrabPtr) __XtMalloc(sizeof(XtServerGrabRec) +
162a3bd7f05Smrg                                        (need_ext ? sizeof(XtServerGrabExtRec)
163a3bd7f05Smrg                                         : 0));
164444c061aSmrg    grab->next = NULL;
165444c061aSmrg    grab->widget = widget;
1660568f49bSmrg    XtSetBit(grab->ownerEvents, ownerEvents);
1670568f49bSmrg    XtSetBit(grab->pointerMode, pointer_mode);
1680568f49bSmrg    XtSetBit(grab->keyboardMode, keyboard_mode);
169a3bd7f05Smrg    grab->eventMask = (unsigned short) event_mask;
1700568f49bSmrg    XtSetBit(grab->hasExt, need_ext);
171a3bd7f05Smrg    grab->confineToIsWidgetWin = (XtWindow(widget) == confine_to);
1720568f49bSmrg    grab->modifiers = (unsigned short) modifiers;
173444c061aSmrg    grab->keybut = keybut;
174444c061aSmrg    if (need_ext) {
175a3bd7f05Smrg        XtServerGrabExtPtr ext = GRABEXT(grab);
176a3bd7f05Smrg
177a3bd7f05Smrg        ext->pModifiersMask = NULL;
178a3bd7f05Smrg        ext->pKeyButMask = NULL;
179a3bd7f05Smrg        ext->confineTo = confine_to;
180a3bd7f05Smrg        ext->cursor = cursor;
181444c061aSmrg    }
182444c061aSmrg    return grab;
183444c061aSmrg}
184444c061aSmrg
185444c061aSmrg/*
186444c061aSmrg * Free up the space occupied by a grab entry.
187444c061aSmrg */
188444c061aSmrg
189a3bd7f05Smrgstatic void
190a3bd7f05SmrgFreeGrab(XtServerGrabPtr pGrab)
191444c061aSmrg{
192444c061aSmrg    if (pGrab->hasExt) {
193444c061aSmrg	XtServerGrabExtPtr ext = GRABEXT(pGrab);
194a3bd7f05Smrg	XtFree((char *)ext->pModifiersMask);
195a3bd7f05Smrg	XtFree((char *)ext->pKeyButMask);
196444c061aSmrg    }
197a3bd7f05Smrg    XtFree((char *) pGrab);
198444c061aSmrg}
199444c061aSmrg
200444c061aSmrgtypedef struct _DetailRec {
201a3bd7f05Smrg    unsigned short exact;
202a3bd7f05Smrg    Mask *pMask;
203444c061aSmrg} DetailRec, *DetailPtr;
204444c061aSmrg
205444c061aSmrg/*
206444c061aSmrg * If the first detail is set to 'exception' and the second detail
207444c061aSmrg * is contained in the mask of the first, then TRUE is returned.
208444c061aSmrg */
209444c061aSmrg
210a3bd7f05Smrgstatic Bool
211a3bd7f05SmrgIsInGrabMask(register DetailPtr firstDetail,
212a3bd7f05Smrg             register DetailPtr secondDetail,
213a3bd7f05Smrg             unsigned short exception)
214444c061aSmrg{
215444c061aSmrg    if (firstDetail->exact == exception) {
216a3bd7f05Smrg        if (!firstDetail->pMask)
217a3bd7f05Smrg            return TRUE;
218444c061aSmrg
219a3bd7f05Smrg        /* (at present) never called with two non-null pMasks */
220a3bd7f05Smrg        if (secondDetail->exact == exception)
221a3bd7f05Smrg            return FALSE;
222444c061aSmrg
223a3bd7f05Smrg        if (GETBIT(firstDetail->pMask, secondDetail->exact))
224a3bd7f05Smrg            return TRUE;
225444c061aSmrg    }
226444c061aSmrg
227444c061aSmrg    return FALSE;
228444c061aSmrg}
229444c061aSmrg
230444c061aSmrg/*
231444c061aSmrg * If neither of the details is set to 'exception', and they match
232444c061aSmrg * exactly, then TRUE is returned.
233444c061aSmrg */
234444c061aSmrg
235a3bd7f05Smrgstatic Bool
236a3bd7f05SmrgIdenticalExactDetails(unsigned short firstExact,
237a3bd7f05Smrg                      unsigned short secondExact,
238a3bd7f05Smrg                      unsigned short exception)
239444c061aSmrg{
240444c061aSmrg    if ((firstExact == exception) || (secondExact == exception))
241a3bd7f05Smrg        return FALSE;
242444c061aSmrg
243444c061aSmrg    if (firstExact == secondExact)
244a3bd7f05Smrg        return TRUE;
245444c061aSmrg
246444c061aSmrg    return FALSE;
247444c061aSmrg}
248444c061aSmrg
249444c061aSmrg/*
250444c061aSmrg * If the first detail is set to 'exception', and its mask has the bit
251444c061aSmrg * enabled which corresponds to the second detail, OR if neither of the
252444c061aSmrg * details is set to 'exception' and the details match exactly, then
253444c061aSmrg * TRUE is returned.
254444c061aSmrg */
255444c061aSmrg
256a3bd7f05Smrgstatic Bool
257a3bd7f05SmrgDetailSupersedesSecond(register DetailPtr firstDetail,
258a3bd7f05Smrg                       register DetailPtr secondDetail,
259a3bd7f05Smrg                       unsigned short exception)
260444c061aSmrg{
261444c061aSmrg    if (IsInGrabMask(firstDetail, secondDetail, exception))
262a3bd7f05Smrg        return TRUE;
263444c061aSmrg
264444c061aSmrg    if (IdenticalExactDetails(firstDetail->exact, secondDetail->exact,
265a3bd7f05Smrg                              exception))
266a3bd7f05Smrg        return TRUE;
267444c061aSmrg
268444c061aSmrg    return FALSE;
269444c061aSmrg}
270444c061aSmrg
271444c061aSmrg/*
272444c061aSmrg * If the two grab events match exactly, or if the first grab entry
273444c061aSmrg * 'encompasses' the second grab entry, then TRUE is returned.
274444c061aSmrg */
275444c061aSmrg
276a3bd7f05Smrgstatic Bool
277a3bd7f05SmrgGrabSupersedesSecond(register XtServerGrabPtr pFirstGrab,
278a3bd7f05Smrg                     register XtServerGrabPtr pSecondGrab)
279444c061aSmrg{
280444c061aSmrg    DetailRec first, second;
281444c061aSmrg
282444c061aSmrg    first.exact = pFirstGrab->modifiers;
283444c061aSmrg    if (pFirstGrab->hasExt)
284a3bd7f05Smrg        first.pMask = GRABEXT(pFirstGrab)->pModifiersMask;
285444c061aSmrg    else
286a3bd7f05Smrg        first.pMask = NULL;
287444c061aSmrg    second.exact = pSecondGrab->modifiers;
288444c061aSmrg    if (pSecondGrab->hasExt)
289a3bd7f05Smrg        second.pMask = GRABEXT(pSecondGrab)->pModifiersMask;
290444c061aSmrg    else
291a3bd7f05Smrg        second.pMask = NULL;
292a3bd7f05Smrg    if (!DetailSupersedesSecond(&first, &second, (unsigned short) AnyModifier))
293a3bd7f05Smrg        return FALSE;
294444c061aSmrg
295444c061aSmrg    first.exact = pFirstGrab->keybut;
296444c061aSmrg    if (pFirstGrab->hasExt)
297a3bd7f05Smrg        first.pMask = GRABEXT(pFirstGrab)->pKeyButMask;
298444c061aSmrg    else
299a3bd7f05Smrg        first.pMask = NULL;
300444c061aSmrg    second.exact = pSecondGrab->keybut;
301444c061aSmrg    if (pSecondGrab->hasExt)
302a3bd7f05Smrg        second.pMask = GRABEXT(pSecondGrab)->pKeyButMask;
303444c061aSmrg    else
304a3bd7f05Smrg        second.pMask = NULL;
305a3bd7f05Smrg    if (DetailSupersedesSecond(&first, &second, (unsigned short) AnyKey))
306a3bd7f05Smrg        return TRUE;
307444c061aSmrg
308444c061aSmrg    return FALSE;
309444c061aSmrg}
310444c061aSmrg
311444c061aSmrg/*
312444c061aSmrg * Two grabs are considered to be matching if either of the following are true:
313444c061aSmrg *
314444c061aSmrg * 1) The two grab entries match exactly, or the first grab entry
315444c061aSmrg *    encompasses the second grab entry.
316444c061aSmrg * 2) The second grab entry encompasses the first grab entry.
317444c061aSmrg * 3) The keycodes match exactly, and one entry's modifiers encompasses
318444c061aSmrg *    the others.
319444c061aSmrg * 4) The keycode for one entry encompasses the other, and the detail
320444c061aSmrg *    for the other entry encompasses the first.
321444c061aSmrg */
322444c061aSmrg
323a3bd7f05Smrgstatic Bool
324a3bd7f05SmrgGrabMatchesSecond(register XtServerGrabPtr pFirstGrab,
325a3bd7f05Smrg                  register XtServerGrabPtr pSecondGrab)
326444c061aSmrg{
327444c061aSmrg    DetailRec firstD, firstM, secondD, secondM;
328444c061aSmrg
329444c061aSmrg    if (pDisplay(pFirstGrab) != pDisplay(pSecondGrab))
330a3bd7f05Smrg        return FALSE;
331444c061aSmrg
332444c061aSmrg    if (GrabSupersedesSecond(pFirstGrab, pSecondGrab))
333a3bd7f05Smrg        return TRUE;
334444c061aSmrg
335444c061aSmrg    if (GrabSupersedesSecond(pSecondGrab, pFirstGrab))
336a3bd7f05Smrg        return TRUE;
337444c061aSmrg
338444c061aSmrg    firstD.exact = pFirstGrab->keybut;
339444c061aSmrg    firstM.exact = pFirstGrab->modifiers;
340444c061aSmrg    if (pFirstGrab->hasExt) {
341a3bd7f05Smrg        firstD.pMask = GRABEXT(pFirstGrab)->pKeyButMask;
342a3bd7f05Smrg        firstM.pMask = GRABEXT(pFirstGrab)->pModifiersMask;
343a3bd7f05Smrg    }
344a3bd7f05Smrg    else {
345a3bd7f05Smrg        firstD.pMask = NULL;
346a3bd7f05Smrg        firstM.pMask = NULL;
347444c061aSmrg    }
348444c061aSmrg    secondD.exact = pSecondGrab->keybut;
349444c061aSmrg    secondM.exact = pSecondGrab->modifiers;
350444c061aSmrg    if (pSecondGrab->hasExt) {
351a3bd7f05Smrg        secondD.pMask = GRABEXT(pSecondGrab)->pKeyButMask;
352a3bd7f05Smrg        secondM.pMask = GRABEXT(pSecondGrab)->pModifiersMask;
353a3bd7f05Smrg    }
354a3bd7f05Smrg    else {
355a3bd7f05Smrg        secondD.pMask = NULL;
356a3bd7f05Smrg        secondM.pMask = NULL;
357444c061aSmrg    }
358444c061aSmrg
359a3bd7f05Smrg    if (DetailSupersedesSecond(&secondD, &firstD, (unsigned short) AnyKey) &&
360a3bd7f05Smrg        DetailSupersedesSecond(&firstM, &secondM, (unsigned short) AnyModifier))
361a3bd7f05Smrg        return TRUE;
362444c061aSmrg
363a3bd7f05Smrg    if (DetailSupersedesSecond(&firstD, &secondD, (unsigned short) AnyKey) &&
364a3bd7f05Smrg        DetailSupersedesSecond(&secondM, &firstM, (unsigned short) AnyModifier))
365a3bd7f05Smrg        return TRUE;
366444c061aSmrg
367444c061aSmrg    return FALSE;
368444c061aSmrg}
369444c061aSmrg
370444c061aSmrg/*
371444c061aSmrg * Delete a grab combination from the passive grab list.  Each entry will
372444c061aSmrg * be checked to see if it is affected by the grab being deleted.  This
373444c061aSmrg * may result in multiple entries being modified/deleted.
374444c061aSmrg */
375444c061aSmrg
376a3bd7f05Smrgstatic void
377a3bd7f05SmrgDeleteServerGrabFromList(XtServerGrabPtr *passiveListPtr,
378a3bd7f05Smrg                         XtServerGrabPtr pMinuendGrab)
379444c061aSmrg{
380444c061aSmrg    register XtServerGrabPtr *next;
381444c061aSmrg    register XtServerGrabPtr grab;
382444c061aSmrg    register XtServerGrabExtPtr ext;
383444c061aSmrg
384a3bd7f05Smrg    for (next = passiveListPtr; (grab = *next);) {
385a3bd7f05Smrg        if (GrabMatchesSecond(grab, pMinuendGrab) &&
386a3bd7f05Smrg            (pDisplay(grab) == pDisplay(pMinuendGrab))) {
387a3bd7f05Smrg            if (GrabSupersedesSecond(pMinuendGrab, grab)) {
388a3bd7f05Smrg                /*
389a3bd7f05Smrg                 * The entry being deleted encompasses the list entry,
390a3bd7f05Smrg                 * so delete the list entry.
391a3bd7f05Smrg                 */
392a3bd7f05Smrg                *next = grab->next;
393a3bd7f05Smrg                FreeGrab(grab);
394a3bd7f05Smrg                continue;
395a3bd7f05Smrg            }
396a3bd7f05Smrg
397a3bd7f05Smrg            if (!grab->hasExt) {
398a3bd7f05Smrg                grab = (XtServerGrabPtr)
399a3bd7f05Smrg                    XtRealloc((char *) grab, (sizeof(XtServerGrabRec) +
400a3bd7f05Smrg                                              sizeof(XtServerGrabExtRec)));
401a3bd7f05Smrg                *next = grab;
402a3bd7f05Smrg                grab->hasExt = True;
403a3bd7f05Smrg                ext = GRABEXT(grab);
404a3bd7f05Smrg                ext->pKeyButMask = NULL;
405a3bd7f05Smrg                ext->pModifiersMask = NULL;
406a3bd7f05Smrg                ext->confineTo = None;
407a3bd7f05Smrg                ext->cursor = None;
408a3bd7f05Smrg            }
409a3bd7f05Smrg            else
410a3bd7f05Smrg                ext = GRABEXT(grab);
411a3bd7f05Smrg            if ((grab->keybut == AnyKey) && (grab->modifiers != AnyModifier)) {
412a3bd7f05Smrg                /*
413a3bd7f05Smrg                 * If the list entry has the key detail of AnyKey, and
414a3bd7f05Smrg                 * a modifier detail not set to AnyModifier, then we
415a3bd7f05Smrg                 * simply need to turn off the key detail bit in the
416a3bd7f05Smrg                 * list entry's key detail mask.
417a3bd7f05Smrg                 */
418a3bd7f05Smrg                DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
419a3bd7f05Smrg            }
420a3bd7f05Smrg            else if ((grab->modifiers == AnyModifier) &&
421a3bd7f05Smrg                     (grab->keybut != AnyKey)) {
422a3bd7f05Smrg                /*
423a3bd7f05Smrg                 * The list entry has a specific key detail, but its
424a3bd7f05Smrg                 * modifier detail is set to AnyModifier; so, we only
425a3bd7f05Smrg                 * need to turn off the specified modifier combination
426a3bd7f05Smrg                 * in the list entry's modifier mask.
427a3bd7f05Smrg                 */
428a3bd7f05Smrg                DeleteDetailFromMask(&ext->pModifiersMask,
429a3bd7f05Smrg                                     pMinuendGrab->modifiers);
430a3bd7f05Smrg            }
431a3bd7f05Smrg            else if ((pMinuendGrab->keybut != AnyKey) &&
432a3bd7f05Smrg                     (pMinuendGrab->modifiers != AnyModifier)) {
433a3bd7f05Smrg                /*
434a3bd7f05Smrg                 * The list entry has a key detail of AnyKey and a
435a3bd7f05Smrg                 * modifier detail of AnyModifier; the entry being
436a3bd7f05Smrg                 * deleted has a specific key and a specific modifier
437a3bd7f05Smrg                 * combination.  Therefore, we need to mask off the
438a3bd7f05Smrg                 * keycode from the list entry, and also create a
439a3bd7f05Smrg                 * new entry for this keycode, which has a modifier
440a3bd7f05Smrg                 * mask set to AnyModifier & ~(deleted modifiers).
441a3bd7f05Smrg                 */
442a3bd7f05Smrg                XtServerGrabPtr pNewGrab;
443a3bd7f05Smrg
444a3bd7f05Smrg                DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
445a3bd7f05Smrg                pNewGrab = CreateGrab(grab->widget,
446a3bd7f05Smrg                                      (Boolean) grab->ownerEvents,
447a3bd7f05Smrg                                      (Modifiers) AnyModifier,
448a3bd7f05Smrg                                      pMinuendGrab->keybut,
449a3bd7f05Smrg                                      (int) grab->pointerMode,
450a3bd7f05Smrg                                      (int) grab->keyboardMode,
451a3bd7f05Smrg                                      (Mask) 0, (Window) 0, (Cursor) 0, True);
452a3bd7f05Smrg                GRABEXT(pNewGrab)->pModifiersMask =
453a3bd7f05Smrg                    CopyDetailMask(ext->pModifiersMask);
454a3bd7f05Smrg
455a3bd7f05Smrg                DeleteDetailFromMask(&GRABEXT(pNewGrab)->pModifiersMask,
456a3bd7f05Smrg                                     pMinuendGrab->modifiers);
457a3bd7f05Smrg
458a3bd7f05Smrg                pNewGrab->next = *passiveListPtr;
459a3bd7f05Smrg                *passiveListPtr = pNewGrab;
460a3bd7f05Smrg            }
461a3bd7f05Smrg            else if (pMinuendGrab->keybut == AnyKey) {
462a3bd7f05Smrg                /*
463a3bd7f05Smrg                 * The list entry has keycode AnyKey and modifier
464a3bd7f05Smrg                 * AnyModifier; the entry being deleted has
465a3bd7f05Smrg                 * keycode AnyKey and specific modifiers.  So we
466a3bd7f05Smrg                 * simply need to mask off the specified modifier
467a3bd7f05Smrg                 * combination.
468a3bd7f05Smrg                 */
469a3bd7f05Smrg                DeleteDetailFromMask(&ext->pModifiersMask,
470a3bd7f05Smrg                                     pMinuendGrab->modifiers);
471a3bd7f05Smrg            }
472a3bd7f05Smrg            else {
473a3bd7f05Smrg                /*
474a3bd7f05Smrg                 * The list entry has keycode AnyKey and modifier
475a3bd7f05Smrg                 * AnyModifier; the entry being deleted has a
476a3bd7f05Smrg                 * specific keycode and modifier AnyModifier.  So
477a3bd7f05Smrg                 * we simply need to mask off the specified
478a3bd7f05Smrg                 * keycode.
479a3bd7f05Smrg                 */
480a3bd7f05Smrg                DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
481a3bd7f05Smrg            }
482a3bd7f05Smrg        }
483a3bd7f05Smrg        next = &(*next)->next;
484444c061aSmrg    }
485444c061aSmrg}
486444c061aSmrg
487a3bd7f05Smrgstatic void
488a3bd7f05SmrgDestroyPassiveList(XtServerGrabPtr *passiveListPtr)
489444c061aSmrg{
490a3bd7f05Smrg    XtServerGrabPtr next, grab;
491444c061aSmrg
492a3bd7f05Smrg    for (next = *passiveListPtr; next;) {
493a3bd7f05Smrg        grab = next;
494a3bd7f05Smrg        next = grab->next;
495444c061aSmrg
496a3bd7f05Smrg        /* not necessary to explicitly ungrab key or button;
497a3bd7f05Smrg         * window is being destroyed so server will take care of it.
498a3bd7f05Smrg         */
499444c061aSmrg
500a3bd7f05Smrg        FreeGrab(grab);
501444c061aSmrg    }
502444c061aSmrg}
503444c061aSmrg
504444c061aSmrg/*
505444c061aSmrg * This function is called at widget destroy time to clean up
506444c061aSmrg */
507a3bd7f05Smrgvoid
508a3bd7f05Smrg_XtDestroyServerGrabs(Widget w,
509a3bd7f05Smrg                      XtPointer closure,
510a3bd7f05Smrg                      XtPointer call_data _X_UNUSED)
511444c061aSmrg{
512a3bd7f05Smrg    XtPerWidgetInput pwi = (XtPerWidgetInput) closure;
513a3bd7f05Smrg    XtPerDisplayInput pdi;
514444c061aSmrg
515444c061aSmrg    LOCK_PROCESS;
516444c061aSmrg    pdi = _XtGetPerDisplayInput(XtDisplay(w));
517444c061aSmrg    _XtClearAncestorCache(w);
518444c061aSmrg    UNLOCK_PROCESS;
519444c061aSmrg
520444c061aSmrg    /* Remove the active grab, if necessary */
521444c061aSmrg    if ((pdi->keyboard.grabType != XtNoServerGrab) &&
522a3bd7f05Smrg        (pdi->keyboard.grab.widget == w)) {
523a3bd7f05Smrg        pdi->keyboard.grabType = XtNoServerGrab;
524a3bd7f05Smrg        pdi->activatingKey = (KeyCode) 0;
525444c061aSmrg    }
526444c061aSmrg    if ((pdi->pointer.grabType != XtNoServerGrab) &&
527a3bd7f05Smrg        (pdi->pointer.grab.widget == w))
528a3bd7f05Smrg        pdi->pointer.grabType = XtNoServerGrab;
529444c061aSmrg
530444c061aSmrg    DestroyPassiveList(&pwi->keyList);
531444c061aSmrg    DestroyPassiveList(&pwi->ptrList);
532444c061aSmrg
533444c061aSmrg    _XtFreePerWidgetInput(w, pwi);
534444c061aSmrg}
535444c061aSmrg
536444c061aSmrg/*
537444c061aSmrg * If the incoming event is on the passive grab list, then activate
538444c061aSmrg * the grab.  The grab will remain in effect until the key is released.
539444c061aSmrg */
540444c061aSmrg
541a3bd7f05SmrgXtServerGrabPtr
542a3bd7f05Smrg_XtCheckServerGrabsOnWidget(XEvent *event, Widget widget, _XtBoolean isKeyboard)
543444c061aSmrg{
544444c061aSmrg    register XtServerGrabPtr grab;
545a3bd7f05Smrg    XtServerGrabRec tempGrab;
546a3bd7f05Smrg    XtServerGrabPtr *passiveListPtr;
547a3bd7f05Smrg    XtPerWidgetInput pwi;
548444c061aSmrg
549444c061aSmrg    LOCK_PROCESS;
550444c061aSmrg    pwi = _XtGetPerWidgetInput(widget, FALSE);
551444c061aSmrg    UNLOCK_PROCESS;
552444c061aSmrg    if (!pwi)
553a3bd7f05Smrg        return (XtServerGrabPtr) NULL;
554444c061aSmrg    if (isKeyboard)
555a3bd7f05Smrg        passiveListPtr = &pwi->keyList;
556444c061aSmrg    else
557a3bd7f05Smrg        passiveListPtr = &pwi->ptrList;
558444c061aSmrg
559444c061aSmrg    /*
560444c061aSmrg     * if either there is no entry in the context manager or the entry
561fdf6a26fSmrg     * is empty, or the keyboard is grabbed, then no work to be done
562444c061aSmrg     */
563444c061aSmrg    if (!*passiveListPtr)
564a3bd7f05Smrg        return (XtServerGrabPtr) NULL;
565444c061aSmrg
566444c061aSmrg    /* Take only the lower thirteen bits as modifier state.  The X Keyboard
567444c061aSmrg     * Extension may be representing keyboard group state in two upper bits.
568444c061aSmrg     */
569444c061aSmrg    tempGrab.widget = widget;
570a3bd7f05Smrg    tempGrab.keybut = (KeyCode) event->xkey.keycode;    /* also xbutton.button */
571a3bd7f05Smrg    tempGrab.modifiers = event->xkey.state & 0x1FFF;    /*also xbutton.state */
572444c061aSmrg    tempGrab.hasExt = False;
573444c061aSmrg
574444c061aSmrg    for (grab = *passiveListPtr; grab; grab = grab->next) {
575a3bd7f05Smrg        if (GrabMatchesSecond(&tempGrab, grab))
576a3bd7f05Smrg            return (grab);
577444c061aSmrg    }
578a3bd7f05Smrg    return (XtServerGrabPtr) NULL;
579444c061aSmrg}
580444c061aSmrg
581444c061aSmrg/*
582444c061aSmrg * This handler is needed to guarantee that we see releases on passive
583444c061aSmrg * button grabs for widgets that haven't selected for button release.
584444c061aSmrg */
585444c061aSmrg
586a3bd7f05Smrgstatic void
587a3bd7f05SmrgActiveHandler(Widget widget _X_UNUSED,
588a3bd7f05Smrg              XtPointer pdi _X_UNUSED,
589a3bd7f05Smrg              XEvent *event _X_UNUSED,
590a3bd7f05Smrg              Boolean *cont _X_UNUSED)
591444c061aSmrg{
592444c061aSmrg    /* nothing */
593444c061aSmrg}
594444c061aSmrg
595444c061aSmrg/*
596a3bd7f05Smrg *      MakeGrab
597444c061aSmrg */
598a3bd7f05Smrgstatic void
599a3bd7f05SmrgMakeGrab(XtServerGrabPtr grab,
600a3bd7f05Smrg         XtServerGrabPtr *passiveListPtr,
601a3bd7f05Smrg         Boolean isKeyboard,
602a3bd7f05Smrg         XtPerDisplayInput pdi,
603a3bd7f05Smrg         XtPerWidgetInput pwi)
604444c061aSmrg{
605444c061aSmrg    if (!isKeyboard && !pwi->active_handler_added) {
606a3bd7f05Smrg        XtAddEventHandler(grab->widget, ButtonReleaseMask, FALSE,
607a3bd7f05Smrg                          ActiveHandler, (XtPointer) pdi);
608a3bd7f05Smrg        pwi->active_handler_added = TRUE;
609444c061aSmrg    }
610444c061aSmrg
611444c061aSmrg    if (isKeyboard) {
612a3bd7f05Smrg        XGrabKey(pDisplay(grab),
613a3bd7f05Smrg                 grab->keybut, grab->modifiers,
614a3bd7f05Smrg                 pWindow(grab), grab->ownerEvents,
615a3bd7f05Smrg                 grab->pointerMode, grab->keyboardMode);
616a3bd7f05Smrg    }
617a3bd7f05Smrg    else {
618a3bd7f05Smrg        Window confineTo = None;
619a3bd7f05Smrg        Cursor cursor = None;
620a3bd7f05Smrg
621a3bd7f05Smrg        if (grab->hasExt) {
622a3bd7f05Smrg            if (grab->confineToIsWidgetWin)
623a3bd7f05Smrg                confineTo = XtWindow(grab->widget);
624a3bd7f05Smrg            else
625a3bd7f05Smrg                confineTo = GRABEXT(grab)->confineTo;
626a3bd7f05Smrg            cursor = GRABEXT(grab)->cursor;
627a3bd7f05Smrg        }
628a3bd7f05Smrg        XGrabButton(pDisplay(grab),
629a3bd7f05Smrg                    grab->keybut, grab->modifiers,
630a3bd7f05Smrg                    pWindow(grab), grab->ownerEvents, grab->eventMask,
631a3bd7f05Smrg                    grab->pointerMode, grab->keyboardMode, confineTo, cursor);
632444c061aSmrg    }
633444c061aSmrg
634444c061aSmrg    /* Add the new grab entry to the passive key grab list */
635444c061aSmrg    grab->next = *passiveListPtr;
636444c061aSmrg    *passiveListPtr = grab;
637444c061aSmrg}
638444c061aSmrg
639a3bd7f05Smrgstatic void
640a3bd7f05SmrgMakeGrabs(XtServerGrabPtr *passiveListPtr,
641a3bd7f05Smrg          Boolean isKeyboard,
642a3bd7f05Smrg          XtPerDisplayInput pdi)
643444c061aSmrg{
644a3bd7f05Smrg    XtServerGrabPtr next = *passiveListPtr;
645a3bd7f05Smrg
646444c061aSmrg    /*
647444c061aSmrg     * make MakeGrab build a new list that has had the merge
648444c061aSmrg     * processing done on it. Start with an empty list
649444c061aSmrg     * (passiveListPtr).
650444c061aSmrg     */
651444c061aSmrg    LOCK_PROCESS;
652444c061aSmrg    *passiveListPtr = NULL;
653a3bd7f05Smrg    while (next) {
654a3bd7f05Smrg        XtServerGrabPtr grab;
655a3bd7f05Smrg        XtPerWidgetInput pwi;
656a3bd7f05Smrg
657a3bd7f05Smrg        grab = next;
658a3bd7f05Smrg        next = grab->next;
659a3bd7f05Smrg        pwi = _XtGetPerWidgetInput(grab->widget, FALSE);
660a3bd7f05Smrg        MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi);
661a3bd7f05Smrg    }
662444c061aSmrg    UNLOCK_PROCESS;
663444c061aSmrg}
664444c061aSmrg
665444c061aSmrg/*
666444c061aSmrg * This function is the event handler attached to the associated widget
667444c061aSmrg * when grabs need to be added, but the widget is not yet realized.  When
668444c061aSmrg * it is first mapped, this handler will be invoked, and it will add all
669444c061aSmrg * needed grabs.
670444c061aSmrg */
671444c061aSmrg
672a3bd7f05Smrgstatic void
673a3bd7f05SmrgRealizeHandler(Widget widget,
674a3bd7f05Smrg               XtPointer closure,
675a3bd7f05Smrg               XEvent *event _X_UNUSED,
676a3bd7f05Smrg               Boolean *cont _X_UNUSED)
677444c061aSmrg{
678a3bd7f05Smrg    XtPerWidgetInput pwi = (XtPerWidgetInput) closure;
679a3bd7f05Smrg    XtPerDisplayInput pdi;
680444c061aSmrg
681444c061aSmrg    LOCK_PROCESS;
682444c061aSmrg    pdi = _XtGetPerDisplayInput(XtDisplay(widget));
683444c061aSmrg    UNLOCK_PROCESS;
684444c061aSmrg    MakeGrabs(&pwi->keyList, KEYBOARD, pdi);
685444c061aSmrg    MakeGrabs(&pwi->ptrList, POINTER, pdi);
686444c061aSmrg
687444c061aSmrg    XtRemoveEventHandler(widget, XtAllEvents, True,
688a3bd7f05Smrg                         RealizeHandler, (XtPointer) pwi);
689444c061aSmrg    pwi->realize_handler_added = FALSE;
690444c061aSmrg}
691444c061aSmrg
692444c061aSmrg/***************************************************************************/
693444c061aSmrg/**************************** Global Routines ******************************/
694444c061aSmrg/***************************************************************************/
695444c061aSmrg
696444c061aSmrg/*
697444c061aSmrg * Routine used by an application to set up a passive grab for a key/modifier
698444c061aSmrg * combination.
699444c061aSmrg */
700444c061aSmrg
701a3bd7f05Smrgstatic void
702a3bd7f05SmrgGrabKeyOrButton(Widget widget,
703a3bd7f05Smrg                KeyCode keyOrButton,
704a3bd7f05Smrg                Modifiers modifiers,
705a3bd7f05Smrg                Boolean owner_events,
706a3bd7f05Smrg                int pointer_mode,
707a3bd7f05Smrg                int keyboard_mode,
708a3bd7f05Smrg                Mask event_mask,
709a3bd7f05Smrg                Window confine_to,
710a3bd7f05Smrg                Cursor cursor,
711a3bd7f05Smrg                Boolean isKeyboard)
712444c061aSmrg{
713a3bd7f05Smrg    XtServerGrabPtr *passiveListPtr;
714a3bd7f05Smrg    XtServerGrabPtr newGrab;
715a3bd7f05Smrg    XtPerWidgetInput pwi;
716a3bd7f05Smrg    XtPerDisplayInput pdi;
717444c061aSmrg
718444c061aSmrg    XtCheckSubclass(widget, coreWidgetClass, "in XtGrabKey or XtGrabButton");
719444c061aSmrg    LOCK_PROCESS;
720444c061aSmrg    pwi = _XtGetPerWidgetInput(widget, TRUE);
721444c061aSmrg    if (isKeyboard)
722a3bd7f05Smrg        passiveListPtr = &pwi->keyList;
723444c061aSmrg    else
724a3bd7f05Smrg        passiveListPtr = &pwi->ptrList;
725444c061aSmrg    pdi = _XtGetPerDisplayInput(XtDisplay(widget));
726444c061aSmrg    UNLOCK_PROCESS;
727444c061aSmrg    newGrab = CreateGrab(widget, owner_events, modifiers,
728a3bd7f05Smrg                         keyOrButton, pointer_mode, keyboard_mode,
729a3bd7f05Smrg                         event_mask, confine_to, cursor, False);
730444c061aSmrg    /*
731444c061aSmrg     *  if the widget is realized then process the entry into the grab
732444c061aSmrg     * list. else if the list is empty (i.e. first time) then add the
733444c061aSmrg     * event handler. then add the raw entry to the list for processing
734444c061aSmrg     * in the handler at realize time.
735444c061aSmrg     */
736444c061aSmrg    if (XtIsRealized(widget))
737a3bd7f05Smrg        MakeGrab(newGrab, passiveListPtr, isKeyboard, pdi, pwi);
738444c061aSmrg    else {
739a3bd7f05Smrg        if (!pwi->realize_handler_added) {
740a3bd7f05Smrg            XtAddEventHandler(widget, StructureNotifyMask, FALSE,
741a3bd7f05Smrg                              RealizeHandler, (XtPointer) pwi);
742a3bd7f05Smrg            pwi->realize_handler_added = TRUE;
743a3bd7f05Smrg        }
744a3bd7f05Smrg
745a3bd7f05Smrg        while (*passiveListPtr)
746a3bd7f05Smrg            passiveListPtr = &(*passiveListPtr)->next;
747a3bd7f05Smrg        *passiveListPtr = newGrab;
748444c061aSmrg    }
749444c061aSmrg}
750444c061aSmrg
751a3bd7f05Smrgstatic void
752a3bd7f05SmrgUngrabKeyOrButton(Widget widget,
753a3bd7f05Smrg                  int keyOrButton,
754a3bd7f05Smrg                  Modifiers modifiers,
755a3bd7f05Smrg                  Boolean isKeyboard)
756444c061aSmrg{
757a3bd7f05Smrg    XtServerGrabRec tempGrab;
758a3bd7f05Smrg    XtPerWidgetInput pwi;
759444c061aSmrg
760444c061aSmrg    XtCheckSubclass(widget, coreWidgetClass,
761a3bd7f05Smrg                    "in XtUngrabKey or XtUngrabButton");
762444c061aSmrg
763444c061aSmrg    /* Build a temporary grab list entry */
764444c061aSmrg    tempGrab.widget = widget;
7650568f49bSmrg    tempGrab.modifiers = (unsigned short) modifiers;
7660568f49bSmrg    tempGrab.keybut = (KeyCode) keyOrButton;
767444c061aSmrg    tempGrab.hasExt = False;
768444c061aSmrg
769444c061aSmrg    LOCK_PROCESS;
770444c061aSmrg    pwi = _XtGetPerWidgetInput(widget, FALSE);
771444c061aSmrg    UNLOCK_PROCESS;
772444c061aSmrg    /*
773444c061aSmrg     * if there is no entry in the context manager then somethings wrong
774444c061aSmrg     */
775a3bd7f05Smrg    if (!pwi) {
776a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
777a3bd7f05Smrg                        "invalidGrab", "ungrabKeyOrButton", XtCXtToolkitError,
778a3bd7f05Smrg                        "Attempt to remove nonexistent passive grab",
779a3bd7f05Smrg                        NULL, NULL);
780a3bd7f05Smrg        return;
781a3bd7f05Smrg    }
782444c061aSmrg
783a3bd7f05Smrg    if (XtIsRealized(widget)) {
784a3bd7f05Smrg        if (isKeyboard)
785a3bd7f05Smrg            XUngrabKey(widget->core.screen->display,
786a3bd7f05Smrg                       keyOrButton, (unsigned int) modifiers,
787a3bd7f05Smrg                       widget->core.window);
788a3bd7f05Smrg        else
789a3bd7f05Smrg            XUngrabButton(widget->core.screen->display,
790a3bd7f05Smrg                          (unsigned) keyOrButton, (unsigned int) modifiers,
791a3bd7f05Smrg                          widget->core.window);
792a3bd7f05Smrg    }
793444c061aSmrg
794444c061aSmrg    /* Delete all entries which are encompassed by the specified grab. */
795444c061aSmrg    DeleteServerGrabFromList(isKeyboard ? &pwi->keyList : &pwi->ptrList,
796a3bd7f05Smrg                             &tempGrab);
797444c061aSmrg}
798444c061aSmrg
799a3bd7f05Smrgvoid
800a3bd7f05SmrgXtGrabKey(Widget widget,
801a3bd7f05Smrg          _XtKeyCode keycode,
802a3bd7f05Smrg          Modifiers modifiers,
803a3bd7f05Smrg          _XtBoolean owner_events,
804a3bd7f05Smrg          int pointer_mode,
805a3bd7f05Smrg          int keyboard_mode)
806444c061aSmrg{
807444c061aSmrg    WIDGET_TO_APPCON(widget);
808444c061aSmrg
809444c061aSmrg    LOCK_APP(app);
810a3bd7f05Smrg    GrabKeyOrButton(widget, (KeyCode) keycode, modifiers,
811a3bd7f05Smrg                    (Boolean) owner_events, pointer_mode, keyboard_mode,
812a3bd7f05Smrg                    (Mask) 0, (Window) None, (Cursor) None, KEYBOARD);
813444c061aSmrg    UNLOCK_APP(app);
814444c061aSmrg}
815444c061aSmrg
816a3bd7f05Smrgvoid
817a3bd7f05SmrgXtGrabButton(Widget widget,
818a3bd7f05Smrg             int button,
819a3bd7f05Smrg             Modifiers modifiers,
820a3bd7f05Smrg             _XtBoolean owner_events,
821a3bd7f05Smrg             unsigned int event_mask,
822a3bd7f05Smrg             int pointer_mode,
823a3bd7f05Smrg             int keyboard_mode,
824a3bd7f05Smrg             Window confine_to,
825a3bd7f05Smrg             Cursor cursor)
826444c061aSmrg{
827444c061aSmrg    WIDGET_TO_APPCON(widget);
828444c061aSmrg
829444c061aSmrg    LOCK_APP(app);
830a3bd7f05Smrg    GrabKeyOrButton(widget, (KeyCode) button, modifiers, (Boolean) owner_events,
831a3bd7f05Smrg                    pointer_mode, keyboard_mode,
832a3bd7f05Smrg                    (Mask) event_mask, confine_to, cursor, POINTER);
833444c061aSmrg    UNLOCK_APP(app);
834444c061aSmrg}
835444c061aSmrg
836444c061aSmrg/*
837444c061aSmrg * Routine used by an application to clear a passive grab for a key/modifier
838444c061aSmrg * combination.
839444c061aSmrg */
840444c061aSmrg
841a3bd7f05Smrgvoid
842a3bd7f05SmrgXtUngrabKey(Widget widget, _XtKeyCode keycode, Modifiers modifiers)
843444c061aSmrg{
844444c061aSmrg    WIDGET_TO_APPCON(widget);
845444c061aSmrg
846444c061aSmrg    LOCK_APP(app);
847a3bd7f05Smrg    UngrabKeyOrButton(widget, (int) keycode, modifiers, KEYBOARD);
848444c061aSmrg    UNLOCK_APP(app);
849444c061aSmrg}
850444c061aSmrg
851a3bd7f05Smrgvoid
852a3bd7f05SmrgXtUngrabButton(Widget widget, unsigned int button, Modifiers modifiers)
853444c061aSmrg{
854444c061aSmrg    WIDGET_TO_APPCON(widget);
855444c061aSmrg
856444c061aSmrg    LOCK_APP(app);
857a3bd7f05Smrg    UngrabKeyOrButton(widget, (KeyCode) button, modifiers, POINTER);
858444c061aSmrg    UNLOCK_APP(app);
859444c061aSmrg}
860444c061aSmrg
861444c061aSmrg/*
862fdf6a26fSmrg * Active grab of Device. clear any client side grabs so we don't lock
863444c061aSmrg */
864a3bd7f05Smrgstatic int
865a3bd7f05SmrgGrabDevice(Widget widget,
866a3bd7f05Smrg           Boolean owner_events,
867a3bd7f05Smrg           int pointer_mode,
868a3bd7f05Smrg           int keyboard_mode,
869a3bd7f05Smrg           Mask event_mask,
870a3bd7f05Smrg           Window confine_to,
871a3bd7f05Smrg           Cursor cursor,
872a3bd7f05Smrg           Time time,
873a3bd7f05Smrg           Boolean isKeyboard)
874444c061aSmrg{
875a3bd7f05Smrg    XtPerDisplayInput pdi;
876a3bd7f05Smrg    int returnVal;
877444c061aSmrg
878444c061aSmrg    XtCheckSubclass(widget, coreWidgetClass,
879a3bd7f05Smrg                    "in XtGrabKeyboard or XtGrabPointer");
880444c061aSmrg    if (!XtIsRealized(widget))
881a3bd7f05Smrg        return GrabNotViewable;
882444c061aSmrg    LOCK_PROCESS;
883444c061aSmrg    pdi = _XtGetPerDisplayInput(XtDisplay(widget));
884444c061aSmrg    UNLOCK_PROCESS;
885444c061aSmrg    if (!isKeyboard)
886a3bd7f05Smrg        returnVal = XGrabPointer(XtDisplay(widget), XtWindow(widget),
887a3bd7f05Smrg                                 owner_events, (unsigned) event_mask,
888a3bd7f05Smrg                                 pointer_mode, keyboard_mode,
889a3bd7f05Smrg                                 confine_to, cursor, time);
890444c061aSmrg    else
891a3bd7f05Smrg        returnVal = XGrabKeyboard(XtDisplay(widget), XtWindow(widget),
892a3bd7f05Smrg                                  owner_events, pointer_mode,
893a3bd7f05Smrg                                  keyboard_mode, time);
894444c061aSmrg
895444c061aSmrg    if (returnVal == GrabSuccess) {
896a3bd7f05Smrg        XtDevice device;
897a3bd7f05Smrg
898a3bd7f05Smrg        device = isKeyboard ? &pdi->keyboard : &pdi->pointer;
899a3bd7f05Smrg
900a3bd7f05Smrg        /* fill in the server grab rec */
901a3bd7f05Smrg        device->grab.widget = widget;
902a3bd7f05Smrg        device->grab.modifiers = 0;
903a3bd7f05Smrg        device->grab.keybut = 0;
904a3bd7f05Smrg        XtSetBit(device->grab.ownerEvents, owner_events);
905a3bd7f05Smrg        XtSetBit(device->grab.pointerMode, pointer_mode);
906a3bd7f05Smrg        XtSetBit(device->grab.keyboardMode, keyboard_mode);
907a3bd7f05Smrg        device->grab.hasExt = False;
908a3bd7f05Smrg        device->grabType = XtActiveServerGrab;
909a3bd7f05Smrg        pdi->activatingKey = (KeyCode) 0;
910a3bd7f05Smrg    }
911444c061aSmrg    return returnVal;
912444c061aSmrg}
913444c061aSmrg
914a3bd7f05Smrgstatic void
915a3bd7f05SmrgUngrabDevice(Widget widget, Time time, Boolean isKeyboard)
916444c061aSmrg{
917444c061aSmrg    XtPerDisplayInput pdi;
918444c061aSmrg    XtDevice device;
919444c061aSmrg
920444c061aSmrg    LOCK_PROCESS;
921444c061aSmrg    pdi = _XtGetPerDisplayInput(XtDisplay(widget));
922444c061aSmrg    UNLOCK_PROCESS;
923444c061aSmrg    device = isKeyboard ? &pdi->keyboard : &pdi->pointer;
924a3bd7f05Smrg
925444c061aSmrg    XtCheckSubclass(widget, coreWidgetClass,
926a3bd7f05Smrg                    "in XtUngrabKeyboard or XtUngrabPointer");
927444c061aSmrg
928444c061aSmrg    if (device->grabType != XtNoServerGrab) {
929444c061aSmrg
930a3bd7f05Smrg        if (device->grabType != XtPseudoPassiveServerGrab
931a3bd7f05Smrg            && XtIsRealized(widget)) {
932a3bd7f05Smrg            if (isKeyboard)
933a3bd7f05Smrg                XUngrabKeyboard(XtDisplay(widget), time);
934a3bd7f05Smrg            else
935a3bd7f05Smrg                XUngrabPointer(XtDisplay(widget), time);
936a3bd7f05Smrg        }
937a3bd7f05Smrg        device->grabType = XtNoServerGrab;
938a3bd7f05Smrg        pdi->activatingKey = (KeyCode) 0;
939444c061aSmrg    }
940444c061aSmrg}
941444c061aSmrg
942444c061aSmrg/*
943fdf6a26fSmrg * Active grab of keyboard. clear any client side grabs so we don't lock
944444c061aSmrg */
945a3bd7f05Smrgint
946a3bd7f05SmrgXtGrabKeyboard(Widget widget,
947a3bd7f05Smrg               _XtBoolean owner_events,
948a3bd7f05Smrg               int pointer_mode,
949a3bd7f05Smrg               int keyboard_mode,
950a3bd7f05Smrg               Time time)
951444c061aSmrg{
952444c061aSmrg    int retval;
953a3bd7f05Smrg
954444c061aSmrg    WIDGET_TO_APPCON(widget);
955444c061aSmrg
956444c061aSmrg    LOCK_APP(app);
957a3bd7f05Smrg    retval = GrabDevice(widget, (Boolean) owner_events,
958a3bd7f05Smrg                        pointer_mode, keyboard_mode,
959a3bd7f05Smrg                        (Mask) 0, (Window) None, (Cursor) None, time, KEYBOARD);
960444c061aSmrg    UNLOCK_APP(app);
961444c061aSmrg    return retval;
962444c061aSmrg}
963444c061aSmrg
964444c061aSmrg/*
965444c061aSmrg * Ungrab the keyboard
966444c061aSmrg */
967444c061aSmrg
968a3bd7f05Smrgvoid
969a3bd7f05SmrgXtUngrabKeyboard(Widget widget, Time time)
970444c061aSmrg{
971444c061aSmrg    WIDGET_TO_APPCON(widget);
972444c061aSmrg
973444c061aSmrg    LOCK_APP(app);
974444c061aSmrg    UngrabDevice(widget, time, KEYBOARD);
975444c061aSmrg    UNLOCK_APP(app);
976444c061aSmrg}
977444c061aSmrg
978444c061aSmrg/*
979444c061aSmrg * grab the pointer
980444c061aSmrg */
981a3bd7f05Smrgint
982a3bd7f05SmrgXtGrabPointer(Widget widget,
983a3bd7f05Smrg              _XtBoolean owner_events,
984a3bd7f05Smrg              unsigned int event_mask,
985a3bd7f05Smrg              int pointer_mode,
986a3bd7f05Smrg              int keyboard_mode,
987a3bd7f05Smrg              Window confine_to,
988a3bd7f05Smrg              Cursor cursor,
989a3bd7f05Smrg              Time time)
990444c061aSmrg{
991444c061aSmrg    int retval;
992a3bd7f05Smrg
993444c061aSmrg    WIDGET_TO_APPCON(widget);
994444c061aSmrg
995444c061aSmrg    LOCK_APP(app);
996a3bd7f05Smrg    retval = GrabDevice(widget, (Boolean) owner_events,
997a3bd7f05Smrg                        pointer_mode, keyboard_mode,
998a3bd7f05Smrg                        (Mask) event_mask, confine_to, cursor, time, POINTER);
999444c061aSmrg    UNLOCK_APP(app);
1000444c061aSmrg    return retval;
1001444c061aSmrg}
1002444c061aSmrg
1003444c061aSmrg/*
1004444c061aSmrg * Ungrab the pointer
1005444c061aSmrg */
1006444c061aSmrg
1007a3bd7f05Smrgvoid
1008a3bd7f05SmrgXtUngrabPointer(Widget widget, Time time)
1009444c061aSmrg{
1010444c061aSmrg    WIDGET_TO_APPCON(widget);
1011444c061aSmrg
1012444c061aSmrg    LOCK_APP(app);
1013444c061aSmrg    UngrabDevice(widget, time, POINTER);
1014444c061aSmrg    UNLOCK_APP(app);
1015444c061aSmrg}
1016444c061aSmrg
1017a3bd7f05Smrgvoid
1018a3bd7f05Smrg_XtRegisterPassiveGrabs(Widget widget)
1019444c061aSmrg{
1020a3bd7f05Smrg    XtPerWidgetInput pwi = _XtGetPerWidgetInput(widget, FALSE);
1021444c061aSmrg
1022444c061aSmrg    if (pwi != NULL && !pwi->realize_handler_added) {
1023a3bd7f05Smrg        XtAddEventHandler(widget, StructureNotifyMask, FALSE,
1024a3bd7f05Smrg                          RealizeHandler, (XtPointer) pwi);
1025a3bd7f05Smrg        pwi->realize_handler_added = TRUE;
1026444c061aSmrg    }
1027444c061aSmrg}
1028