diff options
Diffstat (limited to 'libXt/src/PassivGrab.c')
-rw-r--r-- | libXt/src/PassivGrab.c | 1053 |
1 files changed, 1053 insertions, 0 deletions
diff --git a/libXt/src/PassivGrab.c b/libXt/src/PassivGrab.c new file mode 100644 index 000000000..377efdcd5 --- /dev/null +++ b/libXt/src/PassivGrab.c @@ -0,0 +1,1053 @@ +/* $Xorg: PassivGrab.c,v 1.5 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/******************************************************** + +Copyright 1988 by Hewlett-Packard Company +Copyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of +Hewlett-Packard, Digital, or Sun not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ +/* $XFree86$ */ + +/* + +Copyright 1987, 1988, 1989, 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "PassivGraI.h" + +/* typedef unsigned long Mask; */ +#define BITMASK(i) (((Mask)1) << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) +#define MasksPerDetailMask 8 + +#define pDisplay(grabPtr) (((grabPtr)->widget)->core.screen->display) +#define pWindow(grabPtr) (((grabPtr)->widget)->core.window) + + +/***************************************************************************/ +/*********************** Internal Support Routines *************************/ +/***************************************************************************/ + +/* + * Turn off (clear) the bit in the specified detail mask which is associated + * with the detail. + */ + +static void DeleteDetailFromMask( + Mask **ppDetailMask, + unsigned short detail) +{ + Mask *pDetailMask = *ppDetailMask; + + if (!pDetailMask) { + int i; + pDetailMask = (Mask *)__XtMalloc(sizeof(Mask) * MasksPerDetailMask); + for (i = MasksPerDetailMask; --i >= 0; ) + pDetailMask[i] = ~0; + *ppDetailMask = pDetailMask; + } + BITCLEAR((pDetailMask), detail); +} + + +/* + * Make an exact copy of the specified detail mask. + */ + +static Mask *CopyDetailMask( + Mask *pOriginalDetailMask) +{ + Mask *pTempMask; + int i; + + if (!pOriginalDetailMask) + return NULL; + + pTempMask = (Mask *)__XtMalloc(sizeof(Mask) * MasksPerDetailMask); + + for ( i = 0; i < MasksPerDetailMask; i++) + pTempMask[i]= pOriginalDetailMask[i]; + + return pTempMask; +} + + +/* + * Allocate a new grab entry, and fill in all of the fields using the + * specified parameters. + */ + +static XtServerGrabPtr CreateGrab( + Widget widget, + Boolean ownerEvents, + Modifiers modifiers, + KeyCode keybut, + int pointer_mode, + int keyboard_mode, + Mask event_mask, + Window confine_to, + Cursor cursor, + Boolean need_ext) +{ + XtServerGrabPtr grab; + + if (confine_to || cursor) + need_ext = True; + grab = (XtServerGrabPtr)__XtMalloc(sizeof(XtServerGrabRec) + + (need_ext ? sizeof(XtServerGrabExtRec) + : 0)); + grab->next = NULL; + grab->widget = widget; + grab->ownerEvents = ownerEvents; + grab->pointerMode = pointer_mode; + grab->keyboardMode = keyboard_mode; + grab->eventMask = event_mask; + grab->hasExt = need_ext; + grab->confineToIsWidgetWin = (XtWindow (widget) == confine_to); + grab->modifiers = modifiers; + grab->keybut = keybut; + if (need_ext) { + XtServerGrabExtPtr ext = GRABEXT(grab); + ext->pModifiersMask = NULL; + ext->pKeyButMask = NULL; + ext->confineTo = confine_to; + ext->cursor = cursor; + } + return grab; +} + + +/* + * Free up the space occupied by a grab entry. + */ + +static void FreeGrab( + XtServerGrabPtr pGrab) +{ + if (pGrab->hasExt) { + XtServerGrabExtPtr ext = GRABEXT(pGrab); + if (ext->pModifiersMask) + XtFree((char *)ext->pModifiersMask); + if (ext->pKeyButMask) + XtFree((char *)ext->pKeyButMask); + } + XtFree((char *)pGrab); +} + +typedef struct _DetailRec { + unsigned short exact; + Mask *pMask; +} DetailRec, *DetailPtr; + +/* + * If the first detail is set to 'exception' and the second detail + * is contained in the mask of the first, then TRUE is returned. + */ + +static Bool IsInGrabMask( + register DetailPtr firstDetail, + register DetailPtr secondDetail, + unsigned short exception) +{ + if (firstDetail->exact == exception) { + if (!firstDetail->pMask) + return TRUE; + + /* (at present) never called with two non-null pMasks */ + if (secondDetail->exact == exception) + return FALSE; + + if (GETBIT(firstDetail->pMask, secondDetail->exact)) + return TRUE; + } + + return FALSE; +} + + +/* + * If neither of the details is set to 'exception', and they match + * exactly, then TRUE is returned. + */ + +static Bool IdenticalExactDetails( + unsigned short firstExact, + unsigned short secondExact, + unsigned short exception) +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + + +/* + * If the first detail is set to 'exception', and its mask has the bit + * enabled which corresponds to the second detail, OR if neither of the + * details is set to 'exception' and the details match exactly, then + * TRUE is returned. + */ + +static Bool DetailSupersedesSecond( + register DetailPtr firstDetail, + register DetailPtr secondDetail, + unsigned short exception) +{ + if (IsInGrabMask(firstDetail, secondDetail, exception)) + return TRUE; + + if (IdenticalExactDetails(firstDetail->exact, secondDetail->exact, + exception)) + return TRUE; + + return FALSE; +} + + +/* + * If the two grab events match exactly, or if the first grab entry + * 'encompasses' the second grab entry, then TRUE is returned. + */ + +static Bool GrabSupersedesSecond( + register XtServerGrabPtr pFirstGrab, + register XtServerGrabPtr pSecondGrab) +{ + DetailRec first, second; + + first.exact = pFirstGrab->modifiers; + if (pFirstGrab->hasExt) + first.pMask = GRABEXT(pFirstGrab)->pModifiersMask; + else + first.pMask = NULL; + second.exact = pSecondGrab->modifiers; + if (pSecondGrab->hasExt) + second.pMask = GRABEXT(pSecondGrab)->pModifiersMask; + else + second.pMask = NULL; + if (!DetailSupersedesSecond(&first, &second, (unsigned short)AnyModifier)) + return FALSE; + + first.exact = pFirstGrab->keybut; + if (pFirstGrab->hasExt) + first.pMask = GRABEXT(pFirstGrab)->pKeyButMask; + else + first.pMask = NULL; + second.exact = pSecondGrab->keybut; + if (pSecondGrab->hasExt) + second.pMask = GRABEXT(pSecondGrab)->pKeyButMask; + else + second.pMask = NULL; + if (DetailSupersedesSecond(&first, &second, (unsigned short)AnyKey)) + return TRUE; + + return FALSE; +} + + +/* + * Two grabs are considered to be matching if either of the following are true: + * + * 1) The two grab entries match exactly, or the first grab entry + * encompasses the second grab entry. + * 2) The second grab entry encompasses the first grab entry. + * 3) The keycodes match exactly, and one entry's modifiers encompasses + * the others. + * 4) The keycode for one entry encompasses the other, and the detail + * for the other entry encompasses the first. + */ + +static Bool GrabMatchesSecond( + register XtServerGrabPtr pFirstGrab, + register XtServerGrabPtr pSecondGrab) +{ + DetailRec firstD, firstM, secondD, secondM; + + if (pDisplay(pFirstGrab) != pDisplay(pSecondGrab)) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab)) + return TRUE; + + if (GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + firstD.exact = pFirstGrab->keybut; + firstM.exact = pFirstGrab->modifiers; + if (pFirstGrab->hasExt) { + firstD.pMask = GRABEXT(pFirstGrab)->pKeyButMask; + firstM.pMask = GRABEXT(pFirstGrab)->pModifiersMask; + } else { + firstD.pMask = NULL; + firstM.pMask = NULL; + } + secondD.exact = pSecondGrab->keybut; + secondM.exact = pSecondGrab->modifiers; + if (pSecondGrab->hasExt) { + secondD.pMask = GRABEXT(pSecondGrab)->pKeyButMask; + secondM.pMask = GRABEXT(pSecondGrab)->pModifiersMask; + } else { + secondD.pMask = NULL; + secondM.pMask = NULL; + } + + if (DetailSupersedesSecond(&secondD, &firstD, (unsigned short)AnyKey) && + DetailSupersedesSecond(&firstM, &secondM, (unsigned short)AnyModifier)) + return TRUE; + + if (DetailSupersedesSecond(&firstD, &secondD, (unsigned short)AnyKey) && + DetailSupersedesSecond(&secondM, &firstM, (unsigned short)AnyModifier)) + return TRUE; + + return FALSE; +} + + +/* + * Delete a grab combination from the passive grab list. Each entry will + * be checked to see if it is affected by the grab being deleted. This + * may result in multiple entries being modified/deleted. + */ + +static void DeleteServerGrabFromList( + XtServerGrabPtr *passiveListPtr, + XtServerGrabPtr pMinuendGrab) +{ + register XtServerGrabPtr *next; + register XtServerGrabPtr grab; + register XtServerGrabExtPtr ext; + + for (next = passiveListPtr; (grab = *next); ) + { + if (GrabMatchesSecond(grab, pMinuendGrab) && + (pDisplay(grab) == pDisplay(pMinuendGrab))) + { + if (GrabSupersedesSecond(pMinuendGrab, grab)) + { + /* + * The entry being deleted encompasses the list entry, + * so delete the list entry. + */ + *next = grab->next; + FreeGrab(grab); + continue; + } + + if (!grab->hasExt) { + grab = (XtServerGrabPtr) + XtRealloc((char *)grab, (sizeof(XtServerGrabRec) + + sizeof(XtServerGrabExtRec))); + *next = grab; + grab->hasExt = True; + ext = GRABEXT(grab); + ext->pKeyButMask = NULL; + ext->pModifiersMask = NULL; + ext->confineTo = None; + ext->cursor = None; + } else + ext = GRABEXT(grab); + if ((grab->keybut == AnyKey) && (grab->modifiers != AnyModifier)) + { + /* + * If the list entry has the key detail of AnyKey, and + * a modifier detail not set to AnyModifier, then we + * simply need to turn off the key detail bit in the + * list entry's key detail mask. + */ + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + } else if ((grab->modifiers == AnyModifier) && + (grab->keybut != AnyKey)) { + /* + * The list entry has a specific key detail, but its + * modifier detail is set to AnyModifier; so, we only + * need to turn off the specified modifier combination + * in the list entry's modifier mask. + */ + DeleteDetailFromMask(&ext->pModifiersMask, + pMinuendGrab->modifiers); + } else if ((pMinuendGrab->keybut != AnyKey) && + (pMinuendGrab->modifiers != AnyModifier)) { + /* + * The list entry has a key detail of AnyKey and a + * modifier detail of AnyModifier; the entry being + * deleted has a specific key and a specific modifier + * combination. Therefore, we need to mask off the + * keycode from the list entry, and also create a + * new entry for this keycode, which has a modifier + * mask set to AnyModifier & ~(deleted modifiers). + */ + XtServerGrabPtr pNewGrab; + + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + pNewGrab = CreateGrab(grab->widget, + (Boolean)grab->ownerEvents, + (Modifiers)AnyModifier, + pMinuendGrab->keybut, + (int)grab->pointerMode, + (int)grab->keyboardMode, + (Mask)0, (Window)0, (Cursor)0, True); + GRABEXT(pNewGrab)->pModifiersMask = + CopyDetailMask(ext->pModifiersMask); + + DeleteDetailFromMask(&GRABEXT(pNewGrab)->pModifiersMask, + pMinuendGrab->modifiers); + + pNewGrab->next = *passiveListPtr; + *passiveListPtr = pNewGrab; + } else if (pMinuendGrab->keybut == AnyKey) { + /* + * The list entry has keycode AnyKey and modifier + * AnyModifier; the entry being deleted has + * keycode AnyKey and specific modifiers. So we + * simply need to mask off the specified modifier + * combination. + */ + DeleteDetailFromMask(&ext->pModifiersMask, + pMinuendGrab->modifiers); + } else { + /* + * The list entry has keycode AnyKey and modifier + * AnyModifier; the entry being deleted has a + * specific keycode and modifier AnyModifier. So + * we simply need to mask off the specified + * keycode. + */ + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + } + } + next = &(*next)->next; + } +} + +static void DestroyPassiveList( + XtServerGrabPtr *passiveListPtr) +{ + XtServerGrabPtr next, grab; + + for (next = *passiveListPtr; next; ) { + grab = next; + next = grab->next; + + /* not necessary to explicitly ungrab key or button; + * window is being destroyed so server will take care of it. + */ + + FreeGrab(grab); + } +} + + +/* + * This function is called at widget destroy time to clean up + */ +/*ARGSUSED*/ +void _XtDestroyServerGrabs( + Widget w, + XtPointer closure, + XtPointer call_data) /* unused */ +{ + XtPerWidgetInput pwi = (XtPerWidgetInput)closure; + XtPerDisplayInput pdi; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(w)); + _XtClearAncestorCache(w); + UNLOCK_PROCESS; + + /* Remove the active grab, if necessary */ + if ((pdi->keyboard.grabType != XtNoServerGrab) && + (pdi->keyboard.grab.widget == w)) { + pdi->keyboard.grabType = XtNoServerGrab; + pdi->activatingKey = (KeyCode)0; + } + if ((pdi->pointer.grabType != XtNoServerGrab) && + (pdi->pointer.grab.widget == w)) + pdi->pointer.grabType = XtNoServerGrab; + + DestroyPassiveList(&pwi->keyList); + DestroyPassiveList(&pwi->ptrList); + + _XtFreePerWidgetInput(w, pwi); +} + +/* + * If the incoming event is on the passive grab list, then activate + * the grab. The grab will remain in effect until the key is released. + */ + +XtServerGrabPtr _XtCheckServerGrabsOnWidget ( + XEvent *event, + Widget widget, + _XtBoolean isKeyboard) +{ + register XtServerGrabPtr grab; + XtServerGrabRec tempGrab; + XtServerGrabPtr *passiveListPtr; + XtPerWidgetInput pwi; + + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, FALSE); + UNLOCK_PROCESS; + if (!pwi) + return (XtServerGrabPtr)NULL; + if (isKeyboard) + passiveListPtr = &pwi->keyList; + else + passiveListPtr = &pwi->ptrList; + + /* + * if either there is no entry in the context manager or the entry + * is empty, or the keyboard is grabed, then no work to be done + */ + if (!*passiveListPtr) + return (XtServerGrabPtr)NULL; + + /* Take only the lower thirteen bits as modifier state. The X Keyboard + * Extension may be representing keyboard group state in two upper bits. + */ + tempGrab.widget = widget; + tempGrab.keybut = event->xkey.keycode; /* also xbutton.button */ + tempGrab.modifiers = event->xkey.state & 0x1FFF; /*also xbutton.state*/ + tempGrab.hasExt = False; + + for (grab = *passiveListPtr; grab; grab = grab->next) { + if (GrabMatchesSecond(&tempGrab, grab)) + return (grab); + } + return (XtServerGrabPtr)NULL; +} + +/* + * This handler is needed to guarantee that we see releases on passive + * button grabs for widgets that haven't selected for button release. + */ + +/*ARGSUSED*/ +static void ActiveHandler ( + Widget widget, + XtPointer pdi, + XEvent *event, + Boolean *cont) +{ + /* nothing */ +} + + +/* + * MakeGrab + */ +static void MakeGrab( + XtServerGrabPtr grab, + XtServerGrabPtr *passiveListPtr, + Boolean isKeyboard, + XtPerDisplayInput pdi, + XtPerWidgetInput pwi) +{ + if (!isKeyboard && !pwi->active_handler_added) { + XtAddEventHandler(grab->widget, ButtonReleaseMask, FALSE, + ActiveHandler, (XtPointer)pdi); + pwi->active_handler_added = TRUE; + } + + if (isKeyboard) { + XGrabKey(pDisplay(grab), + grab->keybut, grab->modifiers, + pWindow(grab), grab->ownerEvents, + grab->pointerMode, grab->keyboardMode); + } else { + Window confineTo = None; + Cursor cursor = None; + + if (grab->hasExt) { + if (grab->confineToIsWidgetWin) + confineTo = XtWindow (grab->widget); + else + confineTo = GRABEXT(grab)->confineTo; + cursor = GRABEXT(grab)->cursor; + } + XGrabButton(pDisplay(grab), + grab->keybut, grab->modifiers, + pWindow(grab), grab->ownerEvents, grab->eventMask, + grab->pointerMode, grab->keyboardMode, + confineTo, cursor); + } + + /* Add the new grab entry to the passive key grab list */ + grab->next = *passiveListPtr; + *passiveListPtr = grab; +} + +static void MakeGrabs( + XtServerGrabPtr *passiveListPtr, + Boolean isKeyboard, + XtPerDisplayInput pdi) +{ + XtServerGrabPtr next = *passiveListPtr; + XtServerGrabPtr grab; + XtPerWidgetInput pwi; + /* + * make MakeGrab build a new list that has had the merge + * processing done on it. Start with an empty list + * (passiveListPtr). + */ + LOCK_PROCESS; + *passiveListPtr = NULL; + while (next) + { + grab = next; + next = grab->next; + pwi = _XtGetPerWidgetInput(grab->widget, FALSE); + MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi); + } + UNLOCK_PROCESS; +} + +/* + * This function is the event handler attached to the associated widget + * when grabs need to be added, but the widget is not yet realized. When + * it is first mapped, this handler will be invoked, and it will add all + * needed grabs. + */ + +/*ARGSUSED*/ +static void RealizeHandler ( + Widget widget, + XtPointer closure, + XEvent *event, /* unused */ + Boolean *cont) /* unused */ +{ + XtPerWidgetInput pwi = (XtPerWidgetInput)closure; + XtPerDisplayInput pdi; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + MakeGrabs(&pwi->keyList, KEYBOARD, pdi); + MakeGrabs(&pwi->ptrList, POINTER, pdi); + + XtRemoveEventHandler(widget, XtAllEvents, True, + RealizeHandler, (XtPointer)pwi); + pwi->realize_handler_added = FALSE; +} + +/***************************************************************************/ +/**************************** Global Routines ******************************/ +/***************************************************************************/ + + +/* + * Routine used by an application to set up a passive grab for a key/modifier + * combination. + */ + +static +void GrabKeyOrButton ( + Widget widget, + KeyCode keyOrButton, + Modifiers modifiers, + Boolean owner_events, + int pointer_mode, + int keyboard_mode, + Mask event_mask, + Window confine_to, + Cursor cursor, + Boolean isKeyboard) +{ + XtServerGrabPtr *passiveListPtr; + XtServerGrabPtr newGrab; + XtPerWidgetInput pwi; + XtPerDisplayInput pdi; + + + XtCheckSubclass(widget, coreWidgetClass, "in XtGrabKey or XtGrabButton"); + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, TRUE); + if (isKeyboard) + passiveListPtr = &pwi->keyList; + else + passiveListPtr = &pwi->ptrList; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + newGrab = CreateGrab(widget, owner_events, modifiers, + keyOrButton, pointer_mode, keyboard_mode, + event_mask, confine_to, cursor, False); + /* + * if the widget is realized then process the entry into the grab + * list. else if the list is empty (i.e. first time) then add the + * event handler. then add the raw entry to the list for processing + * in the handler at realize time. + */ + if (XtIsRealized(widget)) + MakeGrab(newGrab, passiveListPtr, isKeyboard, pdi, pwi); + else { + if (!pwi->realize_handler_added) + { + XtAddEventHandler(widget, StructureNotifyMask, FALSE, + RealizeHandler, + (XtPointer)pwi); + pwi->realize_handler_added = TRUE; + } + + while (*passiveListPtr) + passiveListPtr = &(*passiveListPtr)->next; + *passiveListPtr = newGrab; + } +} + + +static +void UngrabKeyOrButton ( + Widget widget, + int keyOrButton, + Modifiers modifiers, + Boolean isKeyboard) +{ + XtServerGrabRec tempGrab; + XtPerWidgetInput pwi; + + XtCheckSubclass(widget, coreWidgetClass, + "in XtUngrabKey or XtUngrabButton"); + + /* Build a temporary grab list entry */ + tempGrab.widget = widget; + tempGrab.modifiers = modifiers; + tempGrab.keybut = keyOrButton; + tempGrab.hasExt = False; + + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, FALSE); + UNLOCK_PROCESS; + /* + * if there is no entry in the context manager then somethings wrong + */ + if (!pwi) + { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidGrab", "ungrabKeyOrButton", XtCXtToolkitError, + "Attempt to remove nonexistent passive grab", + (String *)NULL, (Cardinal *)NULL); + return; + } + + if (XtIsRealized(widget)) + { + if (isKeyboard) + XUngrabKey(widget->core.screen->display, + keyOrButton, (unsigned int)modifiers, + widget->core.window); + else + XUngrabButton(widget->core.screen->display, + keyOrButton, (unsigned int)modifiers, + widget->core.window); + } + + + /* Delete all entries which are encompassed by the specified grab. */ + DeleteServerGrabFromList(isKeyboard ? &pwi->keyList : &pwi->ptrList, + &tempGrab); +} + +void XtGrabKey ( + Widget widget, + _XtKeyCode keycode, + Modifiers modifiers, + _XtBoolean owner_events, + int pointer_mode, + int keyboard_mode) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + GrabKeyOrButton(widget, (KeyCode)keycode, modifiers, owner_events, + pointer_mode, keyboard_mode, + (Mask)0, (Window)None, (Cursor)None, KEYBOARD); + UNLOCK_APP(app); +} + +void XtGrabButton( + Widget widget, + int button, + Modifiers modifiers, + _XtBoolean owner_events, + unsigned int event_mask, + int pointer_mode, + int keyboard_mode, + Window confine_to, + Cursor cursor) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + GrabKeyOrButton(widget, (KeyCode)button, modifiers, owner_events, + pointer_mode, keyboard_mode, + (Mask)event_mask, confine_to, cursor, POINTER); + UNLOCK_APP(app); +} + + +/* + * Routine used by an application to clear a passive grab for a key/modifier + * combination. + */ + +void XtUngrabKey ( + Widget widget, + _XtKeyCode keycode, + Modifiers modifiers) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabKeyOrButton(widget, (int)keycode, modifiers, KEYBOARD); + UNLOCK_APP(app); +} + +void XtUngrabButton ( + Widget widget, + unsigned int button, + Modifiers modifiers) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabKeyOrButton(widget, (KeyCode)button, modifiers, POINTER); + UNLOCK_APP(app); +} + +/* + * Active grab of Device. clear any client side grabs so we dont lock + */ +static int GrabDevice ( + Widget widget, + Boolean owner_events, + int pointer_mode, + int keyboard_mode, + Mask event_mask, + Window confine_to, + Cursor cursor, + Time time, + Boolean isKeyboard) +{ + XtPerDisplayInput pdi; + int returnVal; + + XtCheckSubclass(widget, coreWidgetClass, + "in XtGrabKeyboard or XtGrabPointer"); + if (!XtIsRealized(widget)) + return GrabNotViewable; + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + if (!isKeyboard) + returnVal = XGrabPointer(XtDisplay(widget), XtWindow(widget), + owner_events, event_mask, + pointer_mode, keyboard_mode, + confine_to, cursor, time); + else + returnVal = XGrabKeyboard(XtDisplay(widget), XtWindow(widget), + owner_events, pointer_mode, + keyboard_mode, time); + + if (returnVal == GrabSuccess) { + XtDevice device; + + device = isKeyboard ? &pdi->keyboard : &pdi->pointer; + /* fill in the server grab rec */ + device->grab.widget = widget; + device->grab.modifiers = 0; + device->grab.keybut = 0; + device->grab.ownerEvents = owner_events; + device->grab.pointerMode = pointer_mode; + device->grab.keyboardMode = keyboard_mode; + device->grab.hasExt = False; + device->grabType = XtActiveServerGrab; + pdi->activatingKey = (KeyCode)0; + } + return returnVal; +} + +static void UngrabDevice( + Widget widget, + Time time, + Boolean isKeyboard) +{ + XtPerDisplayInput pdi; + XtDevice device; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + device = isKeyboard ? &pdi->keyboard : &pdi->pointer; + XtCheckSubclass(widget, coreWidgetClass, + "in XtUngrabKeyboard or XtUngrabPointer"); + + if (device->grabType != XtNoServerGrab) { + + if (device->grabType != XtPseudoPassiveServerGrab + && XtIsRealized(widget)) { + if (isKeyboard) + XUngrabKeyboard(XtDisplay(widget), time); + else + XUngrabPointer(XtDisplay(widget), time); + } + device->grabType = XtNoServerGrab; + pdi->activatingKey = (KeyCode)0; + } +} + + +/* + * Active grab of keyboard. clear any client side grabs so we dont lock + */ +int XtGrabKeyboard ( + Widget widget, + _XtBoolean owner_events, + int pointer_mode, + int keyboard_mode, + Time time) +{ + int retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = GrabDevice (widget, owner_events, + pointer_mode, keyboard_mode, + (Mask)0, (Window)None, (Cursor)None, time, KEYBOARD); + UNLOCK_APP(app); + return retval; +} + + +/* + * Ungrab the keyboard + */ + +void XtUngrabKeyboard( + Widget widget, + Time time) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabDevice(widget, time, KEYBOARD); + UNLOCK_APP(app); +} + + + + +/* + * grab the pointer + */ +int XtGrabPointer ( + Widget widget, + _XtBoolean owner_events, + unsigned int event_mask, + int pointer_mode, + int keyboard_mode, + Window confine_to, + Cursor cursor, + Time time) +{ + int retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = GrabDevice (widget, owner_events, + pointer_mode, keyboard_mode, + (Mask)event_mask, confine_to, + cursor, time, POINTER); + UNLOCK_APP(app); + return retval; +} + + +/* + * Ungrab the pointer + */ + +void XtUngrabPointer( + Widget widget, + Time time) +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabDevice(widget, time, POINTER); + UNLOCK_APP(app); +} + + +void _XtRegisterPassiveGrabs ( + Widget widget) +{ + XtPerWidgetInput pwi = _XtGetPerWidgetInput (widget, FALSE); + + if (pwi != NULL && !pwi->realize_handler_added) { + XtAddEventHandler(widget, StructureNotifyMask, FALSE, + RealizeHandler, + (XtPointer)pwi); + pwi->realize_handler_added = TRUE; + } +} |