#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "IntrinsicI.h"
#include "StringDefs.h"
#include "PassivGraI.h"
#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)
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);
}
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;
}
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;
}
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;
static Bool IsInGrabMask(
register DetailPtr firstDetail,
register DetailPtr secondDetail,
unsigned short exception)
{
if (firstDetail->exact == exception) {
if (!firstDetail->pMask)
return TRUE;
if (secondDetail->exact == exception)
return FALSE;
if (GETBIT(firstDetail->pMask, secondDetail->exact))
return TRUE;
}
return FALSE;
}
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;
}
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;
}
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;
}
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;
}
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))
{
*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))
{
DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut);
} else if ((grab->modifiers == AnyModifier) &&
(grab->keybut != AnyKey)) {
DeleteDetailFromMask(&ext->pModifiersMask,
pMinuendGrab->modifiers);
} else if ((pMinuendGrab->keybut != AnyKey) &&
(pMinuendGrab->modifiers != AnyModifier)) {
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) {
DeleteDetailFromMask(&ext->pModifiersMask,
pMinuendGrab->modifiers);
} else {
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;
FreeGrab(grab);
}
}
void _XtDestroyServerGrabs(
Widget w,
XtPointer closure,
XtPointer call_data)
{
XtPerWidgetInput pwi = (XtPerWidgetInput)closure;
XtPerDisplayInput pdi;
LOCK_PROCESS;
pdi = _XtGetPerDisplayInput(XtDisplay(w));
_XtClearAncestorCache(w);
UNLOCK_PROCESS;
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);
}
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 (!*passiveListPtr)
return (XtServerGrabPtr)NULL;
tempGrab.widget = widget;
tempGrab.keybut = event->xkey.keycode;
tempGrab.modifiers = event->xkey.state & 0x1FFF;
tempGrab.hasExt = False;
for (grab = *passiveListPtr; grab; grab = grab->next) {
if (GrabMatchesSecond(&tempGrab, grab))
return (grab);
}
return (XtServerGrabPtr)NULL;
}
static void ActiveHandler (
Widget widget,
XtPointer pdi,
XEvent *event,
Boolean *cont)
{
}
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);
}
grab->next = *passiveListPtr;
*passiveListPtr = grab;
}
static void MakeGrabs(
XtServerGrabPtr *passiveListPtr,
Boolean isKeyboard,
XtPerDisplayInput pdi)
{
XtServerGrabPtr next = *passiveListPtr;
XtServerGrabPtr grab;
XtPerWidgetInput pwi;
LOCK_PROCESS;
*passiveListPtr = NULL;
while (next)
{
grab = next;
next = grab->next;
pwi = _XtGetPerWidgetInput(grab->widget, FALSE);
MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi);
}
UNLOCK_PROCESS;
}
static void RealizeHandler (
Widget widget,
XtPointer closure,
XEvent *event,
Boolean *cont)
{
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;
}
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 (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");
tempGrab.widget = widget;
tempGrab.modifiers = modifiers;
tempGrab.keybut = keyOrButton;
tempGrab.hasExt = False;
LOCK_PROCESS;
pwi = _XtGetPerWidgetInput(widget, FALSE);
UNLOCK_PROCESS;
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);
}
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);
}
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);
}
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;
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;
}
}
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;
}
void XtUngrabKeyboard(
Widget widget,
Time time)
{
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
UngrabDevice(widget, time, KEYBOARD);
UNLOCK_APP(app);
}
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;
}
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;
}
}