/************************************************************ Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 Digital or MIT 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. ********************************************************/ /* $Header: events.c,v 1.76 87/06/24 14:48:52 swick Exp $ */ #include "X.h" #include "misc.h" #include "resource.h" #define NEED←EVENTS #define NEED←REPLIES #include "Xproto.h" #include "windowstr.h" #include "inputstr.h" #include "scrnintstr.h" #include "cursorstr.h" #include "dixstruct.h" #include "opaque.h" extern WindowRec WindowTable[]; extern int swappedClients[]; extern void EnqueueEvent(); extern void NoticeTimeAndState(); extern Bool CheckDeviceGrabs(); extern WindowPtr CheckMotion(); extern void FixUpEventFromWindow(); extern void DeactivatePointerGrab(); extern WindowPtr RootForWindow(); extern void ActivatePointerGrab(); extern void ChangeToCursor(); extern void PostNewCursor(); extern void ActivateKeyboardGrab(); extern void DeactivateKeyboardGrab(); extern int DeliverEventsToWindow(); extern int (* EventSwapVector[128]) (); extern void (* ReplySwapVector[256]) (); #define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ #define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) #define AllButtonsMask ( \ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) #define MotionMask ( \ PointerMotionMask | PointerMotionHintMask | Button1MotionMask | \ Button2MotionMask | Button3MotionMask | Button4MotionMask | \ Button5MotionMask | ButtonMotionMask ) #define PropagateMask ( \ KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ MotionMask ) #define AllModifiersMask ( \ ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ Mod3Mask | Mod4Mask | Mod5Mask ) #define Motion←Filter(state) (PointerMotionMask | \ (AllButtonsMask & state) | buttonMotionMask); #define WID(w) ((w) ? ((w)->wid) : 0) #define BitOn(ptr, bit) \ ((BYTE *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7)) #define BitOff(ptr, bit) \ ((BYTE *) (ptr))[(bit)>>3] &= ~(1 << ((bit) & 7)) #define IsOn(ptr, bit) \ (((BYTE *) (ptr))[(bit)>>3] & (1 << ((bit) & 7))) extern debug←events; extern InputInfo inputInfo; extern KeySymsRec curKeySyms; extern GrabRec keybdGrab; /* used for active grabs */ extern GrabRec ptrGrab; #define MAX←QUEUED←EVENTS 100 extern struct { unsigned int num; QdEventRec pending, free; /* only forw, back used */ DeviceIntPtr replayDev; /* kludgy rock to put flag for */ WindowPtr replayWin; /* ComputeFreezes */ Bool playingEvents; } syncEvents; /* * The window trace information is used to avoid having to compute all the * windows between the root and the current pointer window each time a button * or key goes down. The grabs on each of those windows must be checked. */ extern WindowPtr *spriteTrace; #define ROOT spriteTrace[0] extern int spriteTraceSize; extern int spriteTraceGood; extern WindowPtr *focusTrace; extern int focusTraceSize; extern int focusTraceGood; extern CARD16 keyButtonState; extern int buttonsDown; /* number of buttons currently down */ extern Mask buttonMotionMask; typedef struct { int x, y; } HotSpot; extern struct { CursorPtr current; BoxRec hotLimits; /* logical constraints */ BoxRec physLimits; /* of hot spot due to hardware limits */ WindowPtr win; HotSpot hot; } sprite; /* info about the cursor sprite */ extern Bool lastWasMotion; extern void DoEnterLeaveEvents(); /* merely forward declarations */ extern WindowPtr XYToWindow(); extern Bool CheckKeyboardGrabs(); extern void NormalKeyboardEvent(); extern int DeliverDeviceEvents(); extern ScreenPtr currentScreen; extern CARD16 stateMasks[MAP←LENGTH]; /* only for default keyboard ? XXX */ extern int lastEventMask; #define CantBeFiltered NoEventMask extern int filters[128]; void ProcessPointerEvent (xE, mouse) register xEvent *xE; register DeviceIntPtr mouse; { Mask filterToUse; register int key; register GrabPtr grab = mouse->grab; WindowPtr pWin; Bool moveIt = FALSE; Bool deactivateGrab = FALSE; if (xE->u.keyButtonPointer.rootX < sprite.physLimits.x1) { xE->u.keyButtonPointer.rootX = sprite.physLimits.x1; moveIt = TRUE; } else if (xE->u.keyButtonPointer.rootX >= sprite.physLimits.x2) { xE->u.keyButtonPointer.rootX = sprite.physLimits.x2 - 1; moveIt = TRUE; } if (xE->u.keyButtonPointer.rootY < sprite.physLimits.y1) { xE->u.keyButtonPointer.rootY = sprite.physLimits.y1; moveIt = TRUE; } else if (xE->u.keyButtonPointer.rootY >= sprite.physLimits.y2) { xE->u.keyButtonPointer.rootY = sprite.physLimits.y2 - 1; moveIt = TRUE; } if (moveIt) (*currentScreen->SetCursorPosition)( currentScreen, xE->u.keyButtonPointer.rootX, xE->u.keyButtonPointer.rootY); if (mouse->sync.frozen) { EnqueueEvent(mouse, xE); return; } NoticeTimeAndState(xE); key = xE->u.u.detail; pWin = sprite.win; switch (xE->u.u.type) { case ButtonPress: lastWasMotion = FALSE; buttonsDown++; filterToUse = filters[ButtonPress]; xE->u.u.detail = mouse->u.ptr.map[key]; if (xE->u.u.detail <= 5) keyButtonState |= stateMasks[xE->u.u.detail]; if (!grab) if (CheckDeviceGrabs(mouse, xE, 0, FALSE)) return; break; case ButtonRelease: lastWasMotion = FALSE; buttonsDown--; filterToUse = filters[ButtonRelease]; xE->u.u.detail = mouse->u.ptr.map[key]; if (xE->u.u.detail <= 5) keyButtonState &= ~stateMasks[xE->u.u.detail]; if ((!(keyButtonState & AllButtonsMask)) && (mouse->u.ptr.autoReleaseGrab)) deactivateGrab = TRUE; break; case MotionNotify: pWin = CheckMotion( xE->u.keyButtonPointer.rootX, xE->u.keyButtonPointer.rootY, FALSE); if (!pWin) return ; filterToUse = Motion←Filter(keyButtonState); break; default: FatalError("bogus pointer event from ddx"); } buttonMotionMask = (buttonsDown) ? ButtonMotionMask : 0; if (grab) { Bool syncIt; if ((!grab->ownerEvents) || (!(syncIt = DeliverDeviceEvents(pWin, xE, grab, NullWindow)))) { FixUpEventFromWindow(xE, grab->window, None, TRUE); syncIt = TryClientEvents( grab->client, xE, 1, grab->eventMask, filterToUse, grab); } if (syncIt && (mouse->sync.state == FREEZE←NEXT←EVENT)) { mouse->sync.state = FROZEN←WITH←EVENT; mouse->sync.frozen = TRUE; mouse->sync.event = *xE; } } else DeliverDeviceEvents(pWin, xE, NullGrab, NullWindow); if (deactivateGrab) DeactivatePointerGrab(mouse); } void ProcessOtherEvent (xE, pDevice) xEvent *xE; DevicePtr pDevice; { /* XXX What should be done here ? Bool propogate = filters[xE->type]; */ } #define AtMostOneClient \ (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) void RecalculateDeliverableEvents(pWin) WindowPtr pWin; { OtherClients * others; WindowPtr child; Mask hintMask; pWin->allEventMasks = pWin->eventMask; hintMask = pWin->eventMask & PointerMotionHintMask; for (others = OTHERCLIENTS(pWin); others; others = others->next) { pWin->allEventMasks |= others->mask; /* hintMask &= (others->mask & PointerMotionHintMask); */ } /* if (!hintMask) pWin->allEventMasks &= ~PointerMotionHintMask; */ if (pWin->parent) pWin->deliverableEvents = pWin->allEventMasks | (pWin->parent->deliverableEvents & ~pWin->dontPropagateMask & PropagateMask); else pWin->deliverableEvents = pWin->allEventMasks; for (child = pWin->firstChild; child; child = child->nextSib) RecalculateDeliverableEvents(child); } static int OtherClientGone(pWin, id) WindowPtr pWin; long id; { register OtherClientsPtr *next; register OtherClientsPtr other; for (next = (OtherClientsPtr *)&(pWin->otherClients); *next; next = &((*next)->next)) { if ((other = *next)->resource == id) { *next = other->next; Xfree(other); RecalculateDeliverableEvents(pWin); return; } } FatalError("client not on event list"); } int PassiveClientGone(pWin, id) WindowPtr pWin; long id; { register GrabPtr *next; register GrabPtr grab; for (next = (GrabPtr *)&(pWin->passiveGrabs); *next; next = &((*next)->next)) { if ((grab = *next)->resource == id) { *next = grab->next; Xfree(grab); return; } } FatalError("client not on passive grab list"); } int EventSelectForWindow(pWin, client, mask) WindowPtr pWin; ClientPtr client; Mask mask; { Mask check; OtherClients * others; check = (mask & AtMostOneClient); if (check & pWin->allEventMasks) { /* It is illegal for two different clients to select on any of the events for AtMostOneClient. However, it is OK, for some client to continue selecting on one of those events. */ if ((pWin->client != client) && (check & pWin->eventMask)) return BadAccess; for (others = OTHERCLIENTS(pWin); others; others = others->next) { if ((others->client != client) && (check & others->mask)) return BadAccess; } } if (pWin->client == client) pWin->eventMask = mask; else { for (others = OTHERCLIENTS(pWin); others; others = others->next) { if (others->client == client) { if (mask == 0) { FreeResource(others->resource, RC←NONE); return Success; } else others->mask = mask; goto maskSet; } } others = (OtherClients *) Xalloc(sizeof(OtherClients)); others->client = client; others->mask = mask; others->resource = FakeClientID((int)client->index); others->next = OTHERCLIENTS(pWin); pWin->otherClients = (pointer)others; AddResource(others->resource, RT←FAKE, (pointer) pWin, OtherClientGone, RC←CORE); } maskSet: RecalculateDeliverableEvents(pWin); return Success; } int EventSuppressForWindow(pWin, client, mask) WindowPtr pWin; ClientPtr client; Mask mask; { pWin->dontPropagateMask = mask; RecalculateDeliverableEvents(pWin); return Success; } /* returns true if b is a descendent of a */ Bool IsParent(a, b) register WindowPtr a, b; { for (b = b->parent; b; b = b->parent) if (b == a) return TRUE; return FALSE; } static WindowPtr CommonAncestor(a, b) register WindowPtr a, b; { for (b = b->parent; b; b = b->parent) if (IsParent(b, a)) return b; return NullWindow; } static void EnterLeaveEvent(type, mode, detail, pWin) int type, mode, detail; WindowPtr pWin; { xEvent event; DeviceIntPtr keybd = inputInfo.keyboard; WindowPtr focus = keybd->u.keybd.focus.win; event.u.u.type = type; event.u.u.detail = detail; event.u.enterLeave.time = currentTime.milliseconds; event.u.enterLeave.rootX = sprite.hot.x; event.u.enterLeave.rootY = sprite.hot.y; FixUpEventFromWindow(&event, pWin, None, TRUE); /* This call counts on same initial structure beween enter & button events */ event.u.enterLeave.state = keyButtonState; event.u.enterLeave.mode = mode; event.u.enterLeave.flags = ELFlagSameScreen; /* XXX */ if ((focus != NoneWin) && ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin))) event.u.enterLeave.flags |= ELFlagFocus; DeliverEventsToWindow(pWin, &event, 1, (Mask)filters[type], NullGrab); if (type == EnterNotify) { xKeymapEvent ke; ke.type = KeymapNotify; bcopy(&keybd->down[1], &ke.map[0], 31); } } static void EnterNotifies(ancestor, child, mode, detail) WindowPtr ancestor, child; int mode, detail; { if (!child || (ancestor == child)) return; EnterNotifies(ancestor, child->parent, mode, detail); EnterLeaveEvent(EnterNotify, mode, detail, child); } /* dies horribly if ancestor is not an ancestor of child */ static void LeaveNotifies(child, ancestor, mode, detail, doAncestor) WindowPtr child, ancestor; int detail, mode; { register WindowPtr pWin; if (ancestor == child) return; for (pWin = child->parent; pWin != ancestor; pWin = pWin->parent) EnterLeaveEvent(LeaveNotify, mode, detail, pWin); if (doAncestor) EnterLeaveEvent(LeaveNotify, mode, detail, ancestor); } void DoEnterLeaveEvents(fromWin, toWin, mode) WindowPtr fromWin, toWin; int mode; { if (fromWin == toWin) return; if (IsParent(fromWin, toWin)) { EnterLeaveEvent(LeaveNotify, mode, NotifyInferior, fromWin); EnterNotifies(fromWin, toWin->parent, mode, NotifyVirtual); EnterLeaveEvent(EnterNotify, mode, NotifyAncestor, toWin); } else if (IsParent(toWin, fromWin)) { EnterLeaveEvent(LeaveNotify, mode, NotifyAncestor, fromWin); LeaveNotifies(fromWin, toWin, mode, NotifyVirtual, FALSE); EnterLeaveEvent(EnterNotify, mode, NotifyInferior, toWin); } else { /* neither fromWin nor toWin is descendent of the other */ WindowPtr common = CommonAncestor(toWin, fromWin); /* common == NullWindow ==> different screens */ EnterLeaveEvent(LeaveNotify, mode, NotifyNonlinear, fromWin); if (common) { LeaveNotifies( fromWin, common, mode, NotifyNonlinearVirtual, FALSE); EnterNotifies(common, toWin->parent, mode, NotifyNonlinearVirtual); } else { LeaveNotifies( fromWin, RootForWindow(fromWin), mode, NotifyNonlinearVirtual, TRUE); EnterNotifies( RootForWindow(toWin), toWin->parent, mode, NotifyNonlinearVirtual); } EnterLeaveEvent(EnterNotify, mode, NotifyNonlinear, toWin); } } static void FocusEvent(type, mode, detail, pWin) int type, mode, detail; WindowPtr pWin; { xEvent event; DeviceIntPtr keybd = inputInfo.keyboard; event.u.focus.mode = mode; event.u.u.type = type; event.u.u.detail = detail; event.u.focus.window = pWin->wid; DeliverEventsToWindow(pWin, &event, 1, (Mask)filters[type], NullGrab); if (type == FocusIn) { xKeymapEvent ke; ke.type = KeymapNotify; bcopy(keybd->down, &ke.map[0], 31); DeliverEventsToWindow(pWin, &event, 1, KeymapStateMask, NullGrab); } } /* * recursive because it is easier * no-op if child not descended from ancestor */ static Bool FocusInEvents(ancestor, child, skipChild, mode, detail, doAncestor) WindowPtr ancestor, child, skipChild; int mode, detail; Bool doAncestor; { if (child == NullWindow) return FALSE; if (ancestor == child) { if (doAncestor) FocusEvent(FocusIn, mode, detail, child); return TRUE; } if (FocusInEvents( ancestor, child->parent, skipChild, mode, detail, doAncestor)) { if (child != skipChild) FocusEvent(FocusIn, mode, detail, child); return TRUE; } return FALSE; } /* dies horribly if ancestor is not an ancestor of child */ static void FocusOutEvents(child, ancestor, mode, detail, doAncestor) WindowPtr child, ancestor; int detail; Bool doAncestor; { register WindowPtr pWin; for (pWin = child; pWin != ancestor; pWin = pWin->parent) FocusEvent(FocusOut, mode, detail, pWin); if (doAncestor) FocusEvent(FocusOut, mode, detail, ancestor); } void DoFocusEvents(fromWin, toWin, mode) WindowPtr fromWin, toWin; int mode; { int out, in; /* for holding details for to/from PointerRoot/None */ out = (fromWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; in = (toWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; /* wrong values if neither, but then not referenced */ if ((toWin == NullWindow) || (toWin == PointerRootWin)) { if ((fromWin == NullWindow) || (fromWin == PointerRootWin)) FocusEvent(FocusOut, mode, out, ROOT); else { if (IsParent(fromWin, sprite.win)) FocusOutEvents(sprite.win, fromWin, mode, NotifyPointer, FALSE); FocusEvent(FocusOut, mode, NotifyNonlinear, fromWin); FocusOutEvents( fromWin->parent, ROOT, mode, NotifyNonlinearVirtual, TRUE); } FocusEvent(FocusIn, mode, in, ROOT); } else { if ((fromWin == NullWindow) || (fromWin == PointerRootWin)) { FocusEvent(FocusOut, mode, out, ROOT); FocusInEvents( ROOT, toWin, toWin, mode, NotifyNonlinearVirtual, TRUE); FocusEvent(FocusIn, mode, NotifyNonlinear, toWin); FocusInEvents( toWin, sprite.win, NullWindow, mode, NotifyPointer, FALSE); } else { if (IsParent(toWin, fromWin)) { FocusEvent(FocusOut, mode, NotifyAncestor, fromWin); FocusOutEvents( fromWin->parent, toWin, mode, NotifyVirtual, FALSE); FocusEvent(FocusIn, mode, NotifyInferior, toWin); if ((IsParent(toWin, sprite.win)) && (sprite.win != fromWin) && (!IsParent(fromWin, sprite.win)) && (!IsParent(sprite.win, fromWin))) FocusInEvents( toWin, sprite.win, NullWindow, mode, NotifyPointer, FALSE); } else if (IsParent(fromWin, toWin)) { if ((IsParent(fromWin, sprite.win)) && (sprite.win != fromWin) && (!IsParent(toWin, sprite.win)) && (!IsParent(sprite.win, toWin))) FocusOutEvents( sprite.win, fromWin, mode, NotifyPointer, FALSE); FocusEvent(FocusOut, mode, NotifyInferior, fromWin); FocusInEvents( toWin, fromWin, fromWin, mode, NotifyVirtual, FALSE); FocusEvent(FocusIn, mode, NotifyAncestor, toWin); } else { /* neither fromWin or toWin is child of other */ WindowPtr common = CommonAncestor(toWin, fromWin); /* common == NullWindow ==> different screens XXX */ if (IsParent(fromWin, sprite.win)) FocusOutEvents( sprite.win, fromWin, mode, NotifyPointer, FALSE); FocusEvent(FocusOut, mode, NotifyNonlinear, fromWin); FocusOutEvents( fromWin->parent, common, mode, NotifyNonlinearVirtual, FALSE); FocusInEvents( common, toWin, toWin, mode, NotifyNonlinearVirtual, FALSE); FocusEvent(FocusIn, mode, NotifyNonlinear, toWin); if (IsParent(toWin, sprite.win)) FocusInEvents( toWin, sprite.win, NullWindow, mode, NotifyPointer, FALSE); } } } } /* XXX SetInputFocus does not enumerate all roots, handle screen crossings */ int ProcSetInputFocus(client) ClientPtr client; { TimeStamp time; WindowPtr focusWin; int mode; register DeviceIntPtr kbd = inputInfo.keyboard; register FocusPtr focus = &kbd->u.keybd.focus; REQUEST(xSetInputFocusReq); REQUEST←SIZE←MATCH(xSetInputFocusReq); if ((stuff->revertTo != RevertToParent) && (stuff->revertTo != RevertToPointerRoot) && (stuff->revertTo != RevertToNone)) { client->errorValue = stuff->revertTo; return BadValue; } time = ClientTimeToServerTime(stuff->time); if ((stuff->focus == None) || (stuff->focus == PointerRoot)) focusWin = (WindowPtr)(stuff->focus); else if (!(focusWin = (WindowPtr)LookupID( stuff->focus, RT←WINDOW, RC←CORE))) { client->errorValue = stuff->focus; return BadWindow; } if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, focus->time) == EARLIER)) return Success; mode = (kbd->grab) ? NotifyWhileGrabbed : NotifyNormal; DoFocusEvents(focus->win, focusWin, mode); focus->time = time; focus->revert = stuff->revertTo; focus->win = focusWin; if (focusWin == NoneWin) focusTraceGood = 0; else if (focusWin == PointerRootWin) { focusTraceGood = 1; focusTrace[0] = ROOT; } else { int depth=0; WindowPtr pWin; for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; if (depth > focusTraceSize) { focusTraceSize = depth+1; focusTrace = (WindowPtr *)Xrealloc( focusTrace, focusTraceSize*sizeof(WindowPtr)); } for (pWin = focusWin; pWin; pWin = pWin->parent, depth--) focusTrace[depth] = pWin; } return Success; } int ProcGetInputFocus(client) ClientPtr client; { xGetInputFocusReply rep; REQUEST(xReq); FocusPtr focus = &(inputInfo.keyboard->u.keybd.focus); REQUEST←SIZE←MATCH(xReq); rep.type = X←Reply; rep.length = 0; rep.sequenceNumber = client->sequence; if (focus->win == NoneWin) rep.focus = None; else if (focus->win == PointerRootWin) rep.focus = PointerRoot; else rep.focus = focus->win->wid; rep.revertTo = focus->revert; WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); return Success; } int ProcGrabPointer(client) ClientPtr client; { xGrabPointerReply rep; DeviceIntPtr device = inputInfo.pointer; GrabPtr grab = device->grab; WindowPtr pWin, confineTo; CursorPtr cursor; REQUEST(xGrabPointerReq); TimeStamp time; REQUEST←SIZE←MATCH(xGrabPointerReq); if ((stuff->pointerMode != GrabModeSync) && (stuff->pointerMode != GrabModeAsync) && (stuff->keyboardMode != GrabModeSync) && (stuff->keyboardMode != GrabModeAsync)) return BadValue; pWin = (WindowPtr)LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE); if (!pWin) { client->errorValue = stuff->grabWindow; return BadWindow; } if (stuff->confineTo == None) confineTo = NullWindow; else { confineTo = (WindowPtr)LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE); if (!confineTo) { client->errorValue = stuff->grabWindow; return BadWindow; } } if (stuff->cursor == None) cursor = NullCursor; else { cursor = (CursorPtr)LookupID(stuff->cursor, RT←CURSOR, RC←CORE); if (!cursor) return BadCursor; } /* at this point, some sort of reply is guaranteed. */ time = ClientTimeToServerTime(stuff->time); rep.type = X←Reply; rep.sequenceNumber = client->sequence; rep.length = 0; if ((grab) && (grab->client != client)) rep.status = AlreadyGrabbed; else if (!pWin->realized) rep.status = GrabNotViewable; else if (device->sync.frozen && ((device->sync.other && (device->sync.other->client != client)) || ((device->sync.state >= FROZEN) && (device->grab->client != client)))) rep.status = GrabFrozen; else if ((CompareTimeStamps(time, currentTime) == LATER) || (device->grab && (CompareTimeStamps(time, device->grabTime) == EARLIER))) rep.status = GrabInvalidTime; else { ptrGrab.u.ptr.cursor = cursor; ptrGrab.client = client; ptrGrab.ownerEvents = stuff->ownerEvents; ptrGrab.eventMask = stuff->eventMask; ptrGrab.u.ptr.confineTo = confineTo; ptrGrab.window = pWin; ptrGrab.keyboardMode = stuff->keyboardMode; ptrGrab.pointerMode = stuff->pointerMode; ptrGrab.device = inputInfo.pointer; ActivatePointerGrab(inputInfo.pointer, &ptrGrab, time, FALSE); rep.status = GrabSuccess; } WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); if (cursor) ChangeToCursor(cursor); return Success; } int ProcChangeActivePointerGrab(client) ClientPtr client; { DeviceIntPtr device = inputInfo.pointer; register GrabPtr grab = device->grab; CursorPtr newCursor; REQUEST(xChangeActivePointerGrabReq); TimeStamp time; REQUEST←SIZE←MATCH(xChangeActivePointerGrabReq); if (!grab) return Success; if (grab->client != client) return BadAccess; if (stuff->cursor == None) grab->u.ptr.cursor = NullCursor; else { newCursor = (CursorPtr)LookupID(stuff->cursor, RT←CURSOR, RC←CORE); if (!newCursor) return BadCursor; } time = ClientTimeToServerTime(stuff->time); if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, device->grabTime) == EARLIER)) return Success; grab->u.ptr.cursor = newCursor; PostNewCursor(); /* if mouse motion is newly turned on, it should probably send a motion event */ grab->eventMask = stuff->eventMask; return Success; } int ProcUngrabPointer(client) ClientPtr client; { DeviceIntPtr device = inputInfo.pointer; GrabPtr grab = device->grab; TimeStamp time; REQUEST(xResourceReq); REQUEST←SIZE←MATCH(xResourceReq); time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->grabTime) != EARLIER) && (grab) && (grab->client == client)) DeactivatePointerGrab(inputInfo.pointer); return Success; } int ProcGrabKeyboard(client) ClientPtr client; { xGrabKeyboardReply rep; DeviceIntPtr device = inputInfo.keyboard; GrabPtr grab = device->grab; WindowPtr pWin; TimeStamp time; REQUEST(xGrabKeyboardReq); REQUEST←SIZE←MATCH(xGrabKeyboardReq); if ((stuff->pointerMode != GrabModeSync) && (stuff->pointerMode != GrabModeAsync) && (stuff->keyboardMode != GrabModeSync) && (stuff->keyboardMode != GrabModeAsync)) return BadValue; pWin = (WindowPtr) LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE); if (!pWin) { client->errorValue = stuff->grabWindow; return BadWindow; } time = ClientTimeToServerTime(stuff->time); rep.type = X←Reply; rep.sequenceNumber = client->sequence; rep.length = 0; if ((grab) && (grab->client != client)) rep.status = AlreadyGrabbed; else if (!pWin->realized) rep.status = GrabNotViewable; else if ((CompareTimeStamps(time, currentTime) == LATER) || (device->grab && (CompareTimeStamps(time, device->grabTime) == EARLIER))) rep.status = GrabInvalidTime; else if (device->sync.frozen && ((device->sync.other && (device->sync.other->client != client)) || ((device->sync.state >= FROZEN) && (device->grab->client != client)))) rep.status = GrabFrozen; else { keybdGrab.window = pWin; keybdGrab.client = client; keybdGrab.keyboardMode = stuff->keyboardMode; keybdGrab.pointerMode = stuff->pointerMode; keybdGrab.eventMask = KeyPressMask | KeyReleaseMask; keybdGrab.device = inputInfo.keyboard; ActivateKeyboardGrab( device, &keybdGrab, ClientTimeToServerTime(stuff->time), FALSE); DoFocusEvents(device->u.keybd.focus.win, pWin, NotifyGrab); rep.status = GrabSuccess; } WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); return Success; } int ProcUngrabKeyboard(client) ClientPtr client; { DeviceIntPtr device = inputInfo.keyboard; GrabPtr grab = device->grab; TimeStamp time; REQUEST(xResourceReq); REQUEST←SIZE←MATCH(xResourceReq); time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->grabTime) != EARLIER) && (grab) && (grab->client == client)) { DoFocusEvents(grab->window, device->u.keybd.focus.win, NotifyUngrab); DeactivateKeyboardGrab(device); } return Success; } void SetPointerStateMasks(ptr) DevicePtr ptr; { /* all have to be defined since some button might be mapped here */ stateMasks[1] = Button1Mask; stateMasks[2] = Button2Mask; stateMasks[3] = Button3Mask; stateMasks[4] = Button4Mask; stateMasks[5] = Button5Mask; } void SetKeyboardStateMasks(keybd) DeviceIntPtr keybd; { #define SET←MOD←STATE(entry, mask) \ if (keybd->u.keybd.modMap.entry != NoSymbol)\ stateMasks[keybd->u.keybd.modMap.entry] = mask; /* Note that 1-5 entries are buttons */ int i; for (i = 8; i < MAP←LENGTH; i++) stateMasks[i] = 0; SET←MOD←STATE(lock, LockMask); SET←MOD←STATE(shiftA, ShiftMask); SET←MOD←STATE(shiftB, ShiftMask); SET←MOD←STATE(controlA, ControlMask); SET←MOD←STATE(controlB, ControlMask); SET←MOD←STATE(mod1A, Mod1Mask); SET←MOD←STATE(mod1B, Mod1Mask); SET←MOD←STATE(mod2A, Mod2Mask); SET←MOD←STATE(mod2B, Mod2Mask); SET←MOD←STATE(mod3A, Mod3Mask); SET←MOD←STATE(mod3B, Mod3Mask); SET←MOD←STATE(mod4A, Mod4Mask); SET←MOD←STATE(mod4B, Mod4Mask); SET←MOD←STATE(mod5A, Mod5Mask); SET←MOD←STATE(mod5B, Mod5Mask); #undef SET←MOD←STATE } DevicePtr AddInputDevice(deviceProc, autoStart) DeviceProc deviceProc; Bool autoStart; { DeviceIntPtr d; if (inputInfo.numDevices == inputInfo.arraySize) { inputInfo.arraySize += 5; inputInfo.devices = (DeviceIntPtr *)Xrealloc( inputInfo.devices, inputInfo.arraySize * sizeof(DeviceIntPtr)); } d = (DeviceIntPtr) Xalloc(sizeof(DeviceIntRec)); inputInfo.devices[inputInfo.numDevices++] = d; d->public.on = FALSE; d->public.processInputProc = NoopDDA; d->deviceProc = deviceProc; d->startup = autoStart; d->sync.frozen = FALSE; d->sync.other = NullGrab; d->sync.state = NOT←GRABBED; return &d->public; } DevicesDescriptor GetInputDevices() { DevicesDescriptor devs; devs.count = inputInfo.numDevices; devs.devices = (DevicePtr *)inputInfo.devices; return devs; } void InitEvents() { curKeySyms.map = (KeySym *)NULL; curKeySyms.minKeyCode = 0; curKeySyms.maxKeyCode = 0; curKeySyms.mapWidth = 0; currentScreen = &screenInfo.screen[0]; inputInfo.numDevices = 0; if (spriteTraceSize == 0) { spriteTraceSize = 20; spriteTrace = (WindowPtr *)Xalloc(20*sizeof(WindowPtr)); } spriteTraceGood = 0; if (focusTraceSize == 0) { focusTraceSize = 20; focusTrace = (WindowPtr *)Xalloc(20*sizeof(WindowPtr)); } focusTraceGood = 0; lastEventMask = OwnerGrabButtonMask; sprite.win = NullWindow; sprite.current = NullCursor; sprite.hotLimits.x1 = 0; sprite.hotLimits.y1 = 0; sprite.hotLimits.x2 = currentScreen->width; sprite.hotLimits.y2 = currentScreen->height; lastWasMotion = FALSE; syncEvents.replayDev = (DeviceIntPtr)NULL; syncEvents.pending.forw = &syncEvents.pending; syncEvents.pending.back = &syncEvents.pending; syncEvents.free.forw = &syncEvents.free; syncEvents.free.back = &syncEvents.free; syncEvents.num = 0; syncEvents.playingEvents = FALSE; currentTime.months = 0; currentTime.milliseconds = GetTimeInMillis(); } int InitAndStartDevices(argc, argv) int argc; char *argv[]; { int i; DeviceIntPtr d; for (i = 0; i < inputInfo.numDevices; i++) { d = inputInfo.devices[i]; if ((*d->deviceProc) (d, DEVICE←INIT, argc, argv) == Success) d->inited = TRUE; else d->inited = FALSE; } /* do not turn any devices on until all have been inited */ for (i = 0; i < inputInfo.numDevices; i++) { d = inputInfo.devices[i]; if ((d->startup) && (d->inited)) (*d->deviceProc) (d, DEVICE←ON, argc, argv); } if (inputInfo.pointer && inputInfo.pointer->inited && inputInfo.keyboard && inputInfo.keyboard->inited) return Success; return BadImplementation; } void CloseDownDevices(argc, argv) int argc; char *argv[]; { int i; DeviceIntPtr d; Xfree(curKeySyms.map); for (i = inputInfo.numDevices - 1; i >= 0; i--) { d = inputInfo.devices[i]; if (d->inited) (*d->deviceProc) (d, DEVICE←CLOSE, argc, argv); Xfree(inputInfo.devices[i]); } } int NumMotionEvents() { return inputInfo.numMotionEvents; } void RegisterPointerDevice(device, numMotionEvents) DevicePtr device; int numMotionEvents; { inputInfo.pointer = (DeviceIntPtr)device; inputInfo.numMotionEvents = numMotionEvents; device->processInputProc = ProcessPointerEvent; } void RegisterKeyboardDevice(device) DevicePtr device; { inputInfo.keyboard = (DeviceIntPtr)device; device->processInputProc = ProcessKeyboardEvent; }