/************************************************************ 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. ********************************************************/ /* $XConsortium: events.c,v 5.12 89/10/09 15:52:22 rws 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" extern WindowPtr *WindowTable; extern void (* EventSwapVector[128]) (); extern void (* ReplySwapVector[256]) (); extern void SetCriticalOutputPending(); #define EXTENSION_EVENT_BASE 64 #define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ #define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) #define AllButtonsMask ( \ Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) #define MotionMask ( \ PointerMotionMask | Button1MotionMask | \ Button2MotionMask | Button3MotionMask | Button4MotionMask | \ Button5MotionMask | ButtonMotionMask ) #define PropagateMask ( \ KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ MotionMask ) #define PointerGrabMask ( \ ButtonPressMask | ButtonReleaseMask | \ EnterWindowMask | LeaveWindowMask | \ PointerMotionHintMask | KeymapStateMask | \ MotionMask ) #define AllModifiersMask ( \ ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ Mod3Mask | Mod4Mask | Mod5Mask ) #define AllEventMasks (lastEventMask|(lastEventMask-1)) /* * The following relies on the fact that the ButtonMotionMasks are equal * to the corresponding ButtonMasks from the current modifier/button state. */ #define Motion_Filter(class) (PointerMotionMask | \ (class)->state | (class)->motionMask) #define WID(w) ((w) ? ((w)->drawable.id) : 0) #define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) #define DNPMCOUNT 8 Mask DontPropagateMasks[DNPMCOUNT]; static int DontPropagateRefCnts[DNPMCOUNT]; #ifdef DEBUG static debug_events = 0; #endif InputInfo inputInfo; static struct { QdEventPtr pending, *pendtail; DeviceIntPtr replayDev; /* kludgy rock to put flag for */ WindowPtr replayWin; /* ComputeFreezes */ Bool playingEvents; TimeStamp time; } 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. */ static WindowPtr *spriteTrace = (WindowPtr *)NULL; #define ROOT spriteTrace[0] static int spriteTraceSize = 0; static int spriteTraceGood; typedef struct { int x, y; ScreenPtr pScreen; } HotSpot; static struct { CursorPtr current; BoxRec hotLimits; /* logical constraints of hot spot */ #ifdef SHAPE RegionPtr hotShape; /* additional logical shape constraint */ #endif BoxRec physLimits; /* physical constraints of hot spot */ WindowPtr win; /* window of logical position */ HotSpot hot; /* logical pointer position */ HotSpot hotPhys; /* physical pointer position */ } sprite; /* info about the cursor sprite */ static void DoEnterLeaveEvents(); /* merely forward declarations */ static WindowPtr XYToWindow(); void DeliverFocusedEvent(); int DeliverDeviceEvents(); void DoFocusEvents(); Mask EventMaskForClient(); void WriteEventsToClient(); Bool CheckDeviceGrabs(); void NewCurrentScreen(); static void EnqueueEvent(); extern void MaybeStopHint(); extern GrabPtr CreateGrab(); /* Defined in grabs.c */ extern Bool GrabMatchesSecond(); extern Bool DeletePassiveGrabFromList(); extern int AddPassiveGrabToList(); extern Bool permitOldBugs; static Mask lastEventMask; #define CantBeFiltered NoEventMask static Mask filters[128] = { NoSuchEvent, /* 0 */ NoSuchEvent, /* 1 */ KeyPressMask, /* KeyPress */ KeyReleaseMask, /* KeyRelease */ ButtonPressMask, /* ButtonPress */ ButtonReleaseMask, /* ButtonRelease */ PointerMotionMask, /* MotionNotify (initial state) */ EnterWindowMask, /* EnterNotify */ LeaveWindowMask, /* LeaveNotify */ FocusChangeMask, /* FocusIn */ FocusChangeMask, /* FocusOut */ KeymapStateMask, /* KeymapNotify */ ExposureMask, /* Expose */ CantBeFiltered, /* GraphicsExpose */ CantBeFiltered, /* NoExpose */ VisibilityChangeMask, /* VisibilityNotify */ SubstructureNotifyMask, /* CreateNotify */ StructureAndSubMask, /* DestroyNotify */ StructureAndSubMask, /* UnmapNotify */ StructureAndSubMask, /* MapNotify */ SubstructureRedirectMask, /* MapRequest */ StructureAndSubMask, /* ReparentNotify */ StructureAndSubMask, /* ConfigureNotify */ SubstructureRedirectMask, /* ConfigureRequest */ StructureAndSubMask, /* GravityNotify */ ResizeRedirectMask, /* ResizeRequest */ StructureAndSubMask, /* CirculateNotify */ SubstructureRedirectMask, /* CirculateRequest */ PropertyChangeMask, /* PropertyNotify */ CantBeFiltered, /* SelectionClear */ CantBeFiltered, /* SelectionRequest */ CantBeFiltered, /* SelectionNotify */ ColormapChangeMask, /* ColormapNotify */ CantBeFiltered, /* ClientMessage */ CantBeFiltered /* MappingNotify */ }; static CARD8 criticalEvents[32] = { 0x3c /* key and button events */ }; Mask GetNextEventMask() { lastEventMask <<= 1; return lastEventMask; } void SetMaskForEvent(mask, event) Mask mask; int event; { if ((event < LASTEvent) || (event >= 128)) FatalError("SetMaskForEvent: bogus event number"); filters[event] = mask; } void SetCriticalEvent(event) int event; { if (event >= 128) FatalError("SetCriticalEvent: bogus event number"); criticalEvents[event >> 3] |= 1 << (event & 7); } static void SyntheticMotion(x, y) int x, y; { xEvent xE; xE.u.keyButtonPointer.rootX = x; xE.u.keyButtonPointer.rootY = y; if (syncEvents.playingEvents) xE.u.keyButtonPointer.time = syncEvents.time.milliseconds; else xE.u.keyButtonPointer.time = currentTime.milliseconds; xE.u.u.type = MotionNotify; (*inputInfo.pointer->public.processInputProc)(&xE, inputInfo.pointer, 1); } #ifdef SHAPE static void ConfineToShape(shape, px, py) RegionPtr shape; int *px, *py; { BoxRec box; int x = *px, y = *py; int incx = 1, incy = 1; if ((*sprite.hot.pScreen->PointInRegion)(shape, x, y, &box)) return; box = *(*sprite.hot.pScreen->RegionExtents)(shape); /* this is rather crude */ do { x += incx; if (x >= box.x2) { incx = -1; x = *px - 1; } else if (x < box.x1) { incx = 1; x = *px; y += incy; if (y >= box.y2) { incy = -1; y = *py - 1; } else if (y < box.y1) return; /* should never get here! */ } } while (!(*sprite.hot.pScreen->PointInRegion)(shape, x, y, &box)); *px = x; *py = y; } #endif static void CheckPhysLimits(cursor, generateEvents, pScreen) CursorPtr cursor; Bool generateEvents; ScreenPtr pScreen; { HotSpot new; if (!cursor) return; new = sprite.hotPhys; if (pScreen) new.pScreen = pScreen; else pScreen = new.pScreen; (*pScreen->CursorLimits) (pScreen, cursor, &sprite.hotLimits, &sprite.physLimits); if (new.x < sprite.physLimits.x1) new.x = sprite.physLimits.x1; else if (new.x >= sprite.physLimits.x2) new.x = sprite.physLimits.x2 - 1; if (new.y < sprite.physLimits.y1) new.y = sprite.physLimits.y1; else if (new.y >= sprite.physLimits.y2) new.y = sprite.physLimits.y2 - 1; #ifdef SHAPE if (sprite.hotShape) ConfineToShape(sprite.hotShape, &new.x, &new.y); #endif if ((pScreen != sprite.hotPhys.pScreen) || (new.x != sprite.hotPhys.x) || (new.y != sprite.hotPhys.y)) { if (pScreen != sprite.hotPhys.pScreen) sprite.hotPhys = new; (*pScreen->SetCursorPosition) (pScreen, new.x, new.y, generateEvents); if (!generateEvents) SyntheticMotion(new.x, new.y); } } static void CheckVirtualMotion(qe, pWin) register QdEventPtr qe; register WindowPtr pWin; { if (qe) { sprite.hot.pScreen = qe->pScreen; sprite.hot.x = qe->event->u.keyButtonPointer.rootX; sprite.hot.y = qe->event->u.keyButtonPointer.rootY; pWin = inputInfo.pointer->grab ? inputInfo.pointer->grab->confineTo : NullWindow; } if (pWin) { BoxRec lims; if (sprite.hot.pScreen != pWin->drawable.pScreen) { sprite.hot.pScreen = pWin->drawable.pScreen; sprite.hot.x = sprite.hot.y = 0; } lims = *(*pWin->drawable.pScreen->RegionExtents)(&pWin->borderSize); if (sprite.hot.x < lims.x1) sprite.hot.x = lims.x1; else if (sprite.hot.x >= lims.x2) sprite.hot.x = lims.x2 - 1; if (sprite.hot.y < lims.y1) sprite.hot.y = lims.y1; else if (sprite.hot.y >= lims.y2) sprite.hot.y = lims.y2 - 1; #ifdef SHAPE if (wBoundingShape(pWin)) ConfineToShape(&pWin->borderSize, &sprite.hot.x, &sprite.hot.y); #endif if (qe) { qe->pScreen = sprite.hot.pScreen; qe->event->u.keyButtonPointer.rootX = sprite.hot.x; qe->event->u.keyButtonPointer.rootY = sprite.hot.y; } } ROOT = WindowTable[sprite.hot.pScreen->myNum]; } static void ConfineCursorToWindow(pWin, generateEvents) WindowPtr pWin; Bool generateEvents; { ScreenPtr pScreen = pWin->drawable.pScreen; if (syncEvents.playingEvents) { CheckVirtualMotion((QdEventPtr)NULL, pWin); SyntheticMotion(sprite.hot.x, sprite.hot.y); } else { sprite.hotLimits = *(* pScreen->RegionExtents)(&pWin->borderSize); #ifdef SHAPE sprite.hotShape = wBoundingShape(pWin) ? &pWin->borderSize : NullRegion; #endif CheckPhysLimits(sprite.current, generateEvents, pScreen); (* pScreen->ConstrainCursor)(pScreen, &sprite.physLimits); } } Bool PointerConfinedToScreen() { register GrabPtr grab = inputInfo.pointer->grab; return (grab && grab->confineTo); } static void ChangeToCursor(cursor) CursorPtr cursor; { if (cursor != sprite.current) { if ((sprite.current->bits->xhot != cursor->bits->xhot) || (sprite.current->bits->yhot != cursor->bits->yhot)) CheckPhysLimits(cursor, FALSE, (ScreenPtr)NULL); (*sprite.hotPhys.pScreen->DisplayCursor) (sprite.hotPhys.pScreen, cursor); sprite.current = cursor; } } /* 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 void PostNewCursor() { register WindowPtr win; register GrabPtr grab = inputInfo.pointer->grab; if (syncEvents.playingEvents) return; if (grab) { if (grab->cursor) { ChangeToCursor(grab->cursor); return; } if (IsParent(grab->window, sprite.win)) win = sprite.win; else win = grab->window; } else win = sprite.win; for (; win; win = win->parent) if (win->optional && win->optional->cursor != NullCursor) { ChangeToCursor(win->optional->cursor); return; } } WindowPtr GetCurrentRootWindow() { return ROOT; } WindowPtr GetSpriteWindow() { return sprite.win; } #define NoticeTime(xE) { \ if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \ currentTime.months++; \ currentTime.milliseconds = (xE)->u.keyButtonPointer.time; } void NoticeEventTime(xE) register xEvent *xE; { if (!syncEvents.playingEvents) NoticeTime(xE); } /************************************************************************** * The following procedures deal with synchronous events * **************************************************************************/ static void EnqueueEvent(xE, device, count) xEvent *xE; DeviceIntPtr device; int count; { register QdEventPtr tail = *syncEvents.pendtail; register QdEventPtr qe; xEvent *qxE; NoticeTime(xE) if (xE->u.u.type == MotionNotify) { sprite.hotPhys.x = xE->u.keyButtonPointer.rootX; sprite.hotPhys.y = xE->u.keyButtonPointer.rootY; /* do motion compression */ if (tail && (tail->event->u.u.type == MotionNotify) && (tail->pScreen == sprite.hotPhys.pScreen)) { tail->event->u.keyButtonPointer.rootX = sprite.hotPhys.x; tail->event->u.keyButtonPointer.rootY = sprite.hotPhys.y; return; } } qe = (QdEventPtr)xalloc(sizeof(QdEventRec) + (count * sizeof(xEvent))); if (!qe) return; qe->next = (QdEventPtr)NULL; qe->device = device; qe->pScreen = sprite.hotPhys.pScreen; qe->months = currentTime.months; qe->event = (xEvent *)(qe + 1); qe->evcount = count; for (qxE = qe->event; --count >= 0; qxE++, xE++) *qxE = *xE; if (tail) syncEvents.pendtail = &tail->next; *syncEvents.pendtail = qe; } static void PlayReleasedEvents() { register QdEventPtr *prev, qe; prev = &syncEvents.pending; while (qe = *prev) { if (!qe->device->sync.frozen) { *prev = qe->next; if (!qe->next) syncEvents.pendtail = prev; if (qe->event->u.u.type == MotionNotify) CheckVirtualMotion(qe, NullWindow); syncEvents.time.months = qe->months; syncEvents.time.milliseconds = qe->event->u.keyButtonPointer.time; (*qe->device->public.processInputProc)(qe->event, qe->device, qe->evcount); xfree(qe); if (inputInfo.pointer->sync.frozen && inputInfo.keyboard->sync.frozen) break; /* Playing the event may have unfrozen another device. */ /* So to play it safe, restart at the head of the queue */ prev = &syncEvents.pending; } else prev = &qe->next; } } static void FreezeThaw(dev, frozen) register DeviceIntPtr dev; Bool frozen; { dev->sync.frozen = frozen; if (frozen) dev->public.processInputProc = EnqueueEvent; else dev->public.processInputProc = dev->public.realInputProc; } void ComputeFreezes() { register DeviceIntPtr replayDev = syncEvents.replayDev; register int i; WindowPtr w; register xEvent *xE; int count; GrabPtr grab; register DeviceIntPtr dev; for (dev = inputInfo.devices; dev; dev = dev->next) FreezeThaw(dev, dev->sync.other || (dev->sync.state >= FROZEN)); if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) return; syncEvents.playingEvents = TRUE; if (replayDev) { xE = replayDev->sync.event; count = replayDev->sync.evcount; syncEvents.replayDev = (DeviceIntPtr)NULL; w = XYToWindow( xE->u.keyButtonPointer.rootX, xE->u.keyButtonPointer.rootY); for (i = 0; i < spriteTraceGood; i++) if (syncEvents.replayWin == spriteTrace[i]) { if (!CheckDeviceGrabs(replayDev, xE, i+1, count)) if (replayDev->focus) DeliverFocusedEvent(replayDev, xE, w, count); else DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count); goto playmore; } /* must not still be in the same stack */ if (replayDev->focus) DeliverFocusedEvent(replayDev, xE, w, count); else DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count); } playmore: for (dev = inputInfo.devices; dev; dev = dev->next) { if (!dev->sync.frozen) { PlayReleasedEvents(); break; } } syncEvents.playingEvents = FALSE; /* the following may have been skipped during replay, so do it now */ if ((grab = inputInfo.pointer->grab) && grab->confineTo) { if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) sprite.hotPhys.x = sprite.hotPhys.y = 0; ConfineCursorToWindow(grab->confineTo, TRUE); } else ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], TRUE); PostNewCursor(); } void CheckGrabForSyncs(thisDev, thisMode, otherMode) register DeviceIntPtr thisDev; Bool thisMode, otherMode; { register GrabPtr grab = thisDev->grab; register DeviceIntPtr dev; if (thisMode == GrabModeSync) thisDev->sync.state = FROZEN_NO_EVENT; else { /* free both if same client owns both */ thisDev->sync.state = THAWED; if (thisDev->sync.other && (CLIENT_BITS(thisDev->sync.other->resource) == CLIENT_BITS(grab->resource))) thisDev->sync.other = NullGrab; } for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev != thisDev) { if (otherMode == GrabModeSync) dev->sync.other = grab; else { /* free both if same client owns both */ if (dev->sync.other && (CLIENT_BITS(dev->sync.other->resource) == CLIENT_BITS(grab->resource))) dev->sync.other = NullGrab; } } } ComputeFreezes(); } void ActivatePointerGrab(mouse, grab, time, autoGrab) register GrabPtr grab; register DeviceIntPtr mouse; TimeStamp time; Bool autoGrab; { WindowPtr oldWin = (mouse->grab) ? mouse->grab->window : sprite.win; if (grab->confineTo) { if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) sprite.hotPhys.x = sprite.hotPhys.y = 0; ConfineCursorToWindow(grab->confineTo, FALSE); } DoEnterLeaveEvents(oldWin, grab->window, NotifyGrab); mouse->valuator->motionHintWindow = NullWindow; if (syncEvents.playingEvents) mouse->grabTime = syncEvents.time; else mouse->grabTime = time; if (grab->cursor) grab->cursor->refcnt++; mouse->activeGrab = *grab; mouse->grab = &mouse->activeGrab; mouse->fromPassiveGrab = autoGrab; PostNewCursor(); CheckGrabForSyncs(mouse, (Bool)grab->pointerMode, (Bool)grab->keyboardMode); } void DeactivatePointerGrab(mouse) register DeviceIntPtr mouse; { register GrabPtr grab = mouse->grab; register DeviceIntPtr dev; mouse->valuator->motionHintWindow = NullWindow; mouse->grab = NullGrab; mouse->sync.state = NOT_GRABBED; mouse->fromPassiveGrab = FALSE; for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->sync.other == grab) dev->sync.other = NullGrab; } DoEnterLeaveEvents(grab->window, sprite.win, NotifyUngrab); if (grab->confineTo) ConfineCursorToWindow(ROOT, FALSE); PostNewCursor(); if (grab->cursor) FreeCursor(grab->cursor, (Cursor)0); ComputeFreezes(); } void ActivateKeyboardGrab(keybd, grab, time, passive) GrabPtr grab; register DeviceIntPtr keybd; TimeStamp time; Bool passive; { WindowPtr oldWin = (keybd->grab) ? keybd->grab->window : keybd->focus->win; if (oldWin == FollowKeyboardWin) oldWin = inputInfo.keyboard->focus->win; DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); if (syncEvents.playingEvents) keybd->grabTime = syncEvents.time; else keybd->grabTime = time; keybd->activeGrab = *grab; keybd->grab = &keybd->activeGrab; keybd->fromPassiveGrab = passive; CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); } void DeactivateKeyboardGrab(keybd) register DeviceIntPtr keybd; { register GrabPtr grab = keybd->grab; register DeviceIntPtr dev; keybd->grab = NullGrab; keybd->sync.state = NOT_GRABBED; keybd->fromPassiveGrab = FALSE; for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->sync.other == grab) dev->sync.other = NullGrab; } DoFocusEvents(keybd, grab->window, keybd->focus->win, NotifyUngrab); ComputeFreezes(); } void AllowSome(client, time, thisDev, newState) ClientPtr client; TimeStamp time; register DeviceIntPtr thisDev; int newState; { Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; TimeStamp grabTime; register DeviceIntPtr dev; thisGrabbed = thisDev->grab && SameClient(thisDev->grab, client); thisSynced = FALSE; otherGrabbed = FALSE; othersFrozen = TRUE; grabTime = thisDev->grabTime; for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev == thisDev) continue; if (dev->grab && SameClient(dev->grab, client)) { if (!(thisGrabbed || otherGrabbed) || (CompareTimeStamps(dev->grabTime, grabTime) == LATER)) grabTime = dev->grabTime; otherGrabbed = TRUE; if (thisDev->sync.other == dev->grab) thisSynced = TRUE; if (dev->sync.state < FROZEN) othersFrozen = FALSE; } else if (!thisGrabbed || (dev->sync.other != thisDev->grab)) othersFrozen = FALSE; } if (!((thisGrabbed && thisDev->sync.state >= FROZEN) || thisSynced)) return; if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, grabTime) == EARLIER)) return; switch (newState) { case THAWED: /* Async */ if (thisGrabbed) thisDev->sync.state = THAWED; if (thisSynced) thisDev->sync.other = NullGrab; ComputeFreezes(); break; case FREEZE_NEXT_EVENT: /* Sync */ if (thisGrabbed) { thisDev->sync.state = FREEZE_NEXT_EVENT; if (thisSynced) thisDev->sync.other = NullGrab; ComputeFreezes(); } break; case THAWED_BOTH: /* AsyncBoth */ if (othersFrozen) { for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->grab && SameClient(dev->grab, client)) dev->sync.state = THAWED; else dev->sync.other = NullGrab; } ComputeFreezes(); } break; case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ if (othersFrozen) { for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->grab && SameClient(dev->grab, client)) dev->sync.state = FREEZE_BOTH_NEXT_EVENT; else dev->sync.other = NullGrab; } ComputeFreezes(); } break; case NOT_GRABBED: /* Replay */ if (thisGrabbed && thisDev->sync.state == FROZEN_WITH_EVENT) { syncEvents.replayDev = thisDev; syncEvents.replayWin = thisDev->grab->window; (*thisDev->DeactivateGrab)(thisDev); syncEvents.replayDev = (DeviceIntPtr)NULL; } break; case THAW_OTHERS: /* AsyncOthers */ if (othersFrozen) { for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev == thisDev) continue; if (dev->grab && SameClient(dev->grab, client)) dev->sync.state = THAWED; else dev->sync.other = NullGrab; } ComputeFreezes(); } break; } } int ProcAllowEvents(client) register ClientPtr client; { TimeStamp time; DeviceIntPtr mouse = inputInfo.pointer; DeviceIntPtr keybd = inputInfo.keyboard; REQUEST(xAllowEventsReq); REQUEST_SIZE_MATCH(xAllowEventsReq); time = ClientTimeToServerTime(stuff->time); switch (stuff->mode) { case ReplayPointer: AllowSome(client, time, mouse, NOT_GRABBED); break; case SyncPointer: AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); break; case AsyncPointer: AllowSome(client, time, mouse, THAWED); break; case ReplayKeyboard: AllowSome(client, time, keybd, NOT_GRABBED); break; case SyncKeyboard: AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); break; case AsyncKeyboard: AllowSome(client, time, keybd, THAWED); break; case SyncBoth: AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); break; case AsyncBoth: AllowSome(client, time, keybd, THAWED_BOTH); break; default: client->errorValue = stuff->mode; return BadValue; } return Success; } void ReleaseActiveGrabs(client) ClientPtr client; { register DeviceIntPtr dev; for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->grab && SameClient(dev->grab, client)) (*dev->DeactivateGrab)(dev); } } /************************************************************************** * The following procedures deal with delivering events * **************************************************************************/ int TryClientEvents (client, pEvents, count, mask, filter, grab) ClientPtr client; GrabPtr grab; xEvent *pEvents; int count; Mask mask, filter; { int i; int type; #ifdef DEBUG if (debug_events) ErrorF( "Event([%d, %d], mask=0x%x), client=%d", pEvents->u.u.type, pEvents->u.u.detail, mask, client->index); #endif if ((client) && (client != serverClient) && (!client->clientGone) && ((filter == CantBeFiltered) || (mask & filter))) { if (grab && !SameClient(grab, client)) return -1; /* don't send, but notify caller */ type = pEvents->u.u.type; if (type == MotionNotify) { if (mask & PointerMotionHintMask) { if (WID(inputInfo.pointer->valuator->motionHintWindow) == pEvents->u.keyButtonPointer.event) { #ifdef DEBUG if (debug_events) ErrorF("\n"); #endif return 1; /* don't send, but pretend we did */ } pEvents->u.u.detail = NotifyHint; } else { pEvents->u.u.detail = NotifyNormal; } } type &= 0177; if (type != KeymapNotify) { /* all extension events must have a sequence number */ for (i = 0; i < count; i++) pEvents[i].u.u.sequenceNumber = client->sequence; } if (BitIsOn(criticalEvents, type)) SetCriticalOutputPending(); WriteEventsToClient(client, count, pEvents); #ifdef DEBUG if (debug_events) ErrorF( " delivered\n"); #endif return 1; } else { #ifdef DEBUG if (debug_events) ErrorF("\n"); #endif return 0; } } int DeliverEventsToWindow(pWin, pEvents, count, filter, grab, mskidx) register WindowPtr pWin; GrabPtr grab; xEvent *pEvents; int count; Mask filter; int mskidx; { int deliveries = 0, nondeliveries = 0; int attempt; register InputClients *other; ClientPtr client = NullClient; Mask deliveryMask; /* If a grab occurs due to a button press, then this mask is the mask of the grab. */ int type = pEvents->u.u.type; /* CantBeFiltered means only window owner gets the event */ if ((filter == CantBeFiltered) || !(type & EXTENSION_EVENT_BASE)) { /* if nobody ever wants to see this event, skip some work */ if (filter != CantBeFiltered && !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) return 0; if (attempt = TryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, grab)) { if (attempt > 0) { deliveries++; client = wClient(pWin); deliveryMask = pWin->eventMask; } else nondeliveries--; } } if (filter != CantBeFiltered) { if (type & EXTENSION_EVENT_BASE) { OtherInputMasks *inputMasks; inputMasks = wOtherInputMasks(pWin); if (!inputMasks || !(inputMasks->inputEvents[mskidx] & filter)) return 0; other = inputMasks->inputClients; } else other = (InputClients *)wOtherClients(pWin); for (; other; other = other->next) { if (attempt = TryClientEvents(rClient(other), pEvents, count, other->mask[mskidx], filter, grab)) { if (attempt > 0) { deliveries++; client = rClient(other); deliveryMask = other->mask[mskidx]; } else nondeliveries--; } } } if ((type == ButtonPress) && deliveries && (!grab)) { GrabRec tempGrab; tempGrab.device = inputInfo.pointer; tempGrab.resource = client->clientAsMask; tempGrab.window = pWin; tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; tempGrab.eventMask = deliveryMask; tempGrab.keyboardMode = GrabModeAsync; tempGrab.pointerMode = GrabModeAsync; tempGrab.confineTo = NullWindow; tempGrab.cursor = NullCursor; (*inputInfo.pointer->ActivateGrab)(inputInfo.pointer, &tempGrab, currentTime, TRUE); } else if ((type == MotionNotify) && deliveries) inputInfo.pointer->valuator->motionHintWindow = pWin; if (deliveries) return deliveries; return nondeliveries; } /* If the event goes to dontClient, don't send it and return 0. if send works, return 1 or if send didn't work, return 2. Only works for core events. */ int MaybeDeliverEventsToClient(pWin, pEvents, count, filter, dontClient) register WindowPtr pWin; xEvent *pEvents; int count; Mask filter; ClientPtr dontClient; { register OtherClients *other; if (pWin->eventMask & filter) { if (wClient(pWin) == dontClient) return 0; return TryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, NullGrab); } for (other = wOtherClients(pWin); other; other = other->next) { if (other->mask & filter) { if (SameClient(other, dontClient)) return 0; return TryClientEvents(rClient(other), pEvents, count, other->mask, filter, NullGrab); } } return 2; } static void FixUpEventFromWindow(xE, pWin, child, calcChild) xEvent *xE; WindowPtr pWin; Window child; Bool calcChild; { if (calcChild) { WindowPtr w=spriteTrace[spriteTraceGood-1]; /* If the search ends up past the root should the child field be set to none or should the value in the argument be passed through. It probably doesn't matter since everyone calls this function with child == None anyway. */ while (w) { /* If the source window is same as event window, child should be none. Don't bother going all all the way back to the root. */ if (w == pWin) { child = None; break; } if (w->parent == pWin) { child = w->drawable.id; break; } w = w->parent; } } xE->u.keyButtonPointer.root = ROOT->drawable.id; xE->u.keyButtonPointer.event = pWin->drawable.id; if (sprite.hot.pScreen == pWin->drawable.pScreen) { xE->u.keyButtonPointer.sameScreen = xTrue; xE->u.keyButtonPointer.child = child; xE->u.keyButtonPointer.eventX = xE->u.keyButtonPointer.rootX - pWin->drawable.x; xE->u.keyButtonPointer.eventY = xE->u.keyButtonPointer.rootY - pWin->drawable.y; } else { xE->u.keyButtonPointer.sameScreen = xFalse; xE->u.keyButtonPointer.child = None; xE->u.keyButtonPointer.eventX = 0; xE->u.keyButtonPointer.eventY = 0; } } int DeliverDeviceEvents(pWin, xE, grab, stopAt, dev, count) register WindowPtr pWin, stopAt; register xEvent *xE; GrabPtr grab; DeviceIntPtr dev; int count; { Window child = None; int type = xE->u.u.type; Mask filter = filters[type]; int deliveries = 0; if (type & EXTENSION_EVENT_BASE) { register OtherInputMasks *inputMasks; int mskidx = dev->id; inputMasks = wOtherInputMasks(pWin); if (!inputMasks || !(filter & inputMasks->deliverableEvents[mskidx])) return 0; while (pWin && inputMasks) { if (inputMasks->inputEvents[mskidx] & filter) { FixUpEventFromWindow(xE, pWin, child, FALSE); deliveries = DeliverEventsToWindow(pWin, xE, count, filter, grab, mskidx); if (deliveries > 0) return deliveries; } if ((deliveries < 0) || (pWin == stopAt) || (filter & inputMasks->dontPropagateMask[mskidx])) return 0; child = pWin->drawable.id; pWin = pWin->parent; inputMasks = wOtherInputMasks(pWin); } } else { if (!(filter & pWin->deliverableEvents)) return 0; while (pWin) { if ((wOtherEventMasks(pWin)|pWin->eventMask) & filter) { FixUpEventFromWindow(xE, pWin, child, FALSE); deliveries = DeliverEventsToWindow(pWin, xE, count, filter, grab, 0); if (deliveries > 0) return deliveries; } if ((deliveries < 0) || (pWin == stopAt) || (filter & wDontPropagateMask(pWin))) return 0; child = pWin->drawable.id; pWin = pWin->parent; } } return 0; } /* not useful for events that propagate up the tree or extension events */ int DeliverEvents(pWin, xE, count, otherParent) register WindowPtr pWin, otherParent; register xEvent *xE; int count; { Mask filter; int deliveries; if (!count) return 0; filter = filters[xE->u.u.type]; if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) xE->u.destroyNotify.event = pWin->drawable.id; if (filter != StructureAndSubMask) return DeliverEventsToWindow(pWin, xE, count, filter, NullGrab, 0); deliveries = DeliverEventsToWindow(pWin, xE, count, StructureNotifyMask, NullGrab, 0); if (pWin->parent) { xE->u.destroyNotify.event = pWin->parent->drawable.id; deliveries += DeliverEventsToWindow(pWin->parent, xE, count, SubstructureNotifyMask, NullGrab, 0); if (xE->u.u.type == ReparentNotify) { xE->u.destroyNotify.event = otherParent->drawable.id; deliveries += DeliverEventsToWindow(otherParent, xE, count, SubstructureNotifyMask, NullGrab, 0); } } return deliveries; } static WindowPtr XYToWindow(x, y) int x, y; { register WindowPtr pWin; #ifdef SHAPE BoxRec box; #endif spriteTraceGood = 1; /* root window still there */ pWin = ROOT->firstChild; while (pWin) { if ((pWin->mapped) && (x >= pWin->drawable.x - wBorderWidth (pWin)) && (x < pWin->drawable.x + (int)pWin->drawable.width + wBorderWidth(pWin)) && (y >= pWin->drawable.y - wBorderWidth (pWin)) && (y < pWin->drawable.y + (int)pWin->drawable.height + wBorderWidth (pWin)) #ifdef SHAPE /* When a window is shaped, a further check * is made to see if the point is inside * borderSize */ && (!wBoundingShape(pWin) || (*pWin->drawable.pScreen->PointInRegion) (&pWin->borderSize, x, y, &box)) #endif ) { if (spriteTraceGood >= spriteTraceSize) { spriteTraceSize += 10; spriteTrace = (WindowPtr *)xrealloc( spriteTrace, spriteTraceSize*sizeof(WindowPtr)); if (!spriteTrace) FatalError("could not realloc spriteTrace"); /* XXX */ } spriteTrace[spriteTraceGood++] = pWin; pWin = pWin->firstChild; } else pWin = pWin->nextSib; } return spriteTrace[spriteTraceGood-1]; } static Bool CheckMotion(xE) xEvent *xE; { WindowPtr prevSpriteWin = sprite.win; if (xE && !syncEvents.playingEvents) { if (sprite.hot.pScreen != sprite.hotPhys.pScreen) { sprite.hot.pScreen = sprite.hotPhys.pScreen; ROOT = WindowTable[sprite.hot.pScreen->myNum]; } sprite.hot.x = xE->u.keyButtonPointer.rootX; sprite.hot.y = xE->u.keyButtonPointer.rootY; if (sprite.hot.x < sprite.physLimits.x1) sprite.hot.x = sprite.physLimits.x1; else if (sprite.hot.x >= sprite.physLimits.x2) sprite.hot.x = sprite.physLimits.x2 - 1; if (sprite.hot.y < sprite.physLimits.y1) sprite.hot.y = sprite.physLimits.y1; else if (sprite.hot.y >= sprite.physLimits.y2) sprite.hot.y = sprite.physLimits.y2 - 1; #ifdef SHAPE if (sprite.hotShape) ConfineToShape(sprite.hotShape, &sprite.hot.x, &sprite.hot.y); #endif sprite.hotPhys = sprite.hot; if ((sprite.hotPhys.x != xE->u.keyButtonPointer.rootX) || (sprite.hotPhys.y != xE->u.keyButtonPointer.rootY)) (*sprite.hotPhys.pScreen->SetCursorPosition)( sprite.hotPhys.pScreen, sprite.hotPhys.x, sprite.hotPhys.y, FALSE); xE->u.keyButtonPointer.rootX = sprite.hot.x; xE->u.keyButtonPointer.rootY = sprite.hot.y; } sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); #ifdef notyet if (!(sprite.win->deliverableEvents & Motion_Filter(inputInfo.pointer->button)) !syncEvents.playingEvents) { /* XXX Do PointerNonInterestBox here */ } #endif if (sprite.win != prevSpriteWin) { if (prevSpriteWin != NullWindow) { if (!xE) UpdateCurrentTimeIf(); DoEnterLeaveEvents(prevSpriteWin, sprite.win, NotifyNormal); } PostNewCursor(); return FALSE; } return TRUE; } WindowsRestructured() { (void) CheckMotion((xEvent *)NULL); } void DefineInitialRootWindow(win) register WindowPtr win; { register ScreenPtr pScreen = win->drawable.pScreen; sprite.hotPhys.pScreen = pScreen; sprite.hotPhys.x = pScreen->width / 2; sprite.hotPhys.y = pScreen->height / 2; sprite.hot = sprite.hotPhys; sprite.hotLimits.x2 = pScreen->width; sprite.hotLimits.y2 = pScreen->height; sprite.win = win; sprite.current = wCursor (win); spriteTraceGood = 1; ROOT = win; (*pScreen->CursorLimits) ( pScreen, sprite.current, &sprite.hotLimits, &sprite.physLimits); (*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits); (*pScreen->SetCursorPosition) (pScreen, sprite.hot.x, sprite.hot.y, FALSE); (*pScreen->DisplayCursor) (pScreen, sprite.current); } /* * This does not take any shortcuts, and even ignores its argument, since * it does not happen very often, and one has to walk up the tree since * this might be a newly instantiated cursor for an intermediate window * between the one the pointer is in and the one that the last cursor was * instantiated from. */ /*ARGSUSED*/ void WindowHasNewCursor(pWin) WindowPtr pWin; { PostNewCursor(); } void NewCurrentScreen(newScreen, x, y) ScreenPtr newScreen; int x,y; { sprite.hotPhys.x = x; sprite.hotPhys.y = y; if (newScreen != sprite.hotPhys.pScreen) ConfineCursorToWindow(WindowTable[newScreen->myNum], TRUE); } int ProcWarpPointer(client) ClientPtr client; { WindowPtr dest = NULL; int x, y; ScreenPtr newScreen; REQUEST(xWarpPointerReq); REQUEST_SIZE_MATCH(xWarpPointerReq); if (stuff->dstWid != None) { dest = LookupWindow(stuff->dstWid, client); if (!dest) return BadWindow; } x = sprite.hotPhys.x; y = sprite.hotPhys.y; if (stuff->srcWid != None) { int winX, winY; WindowPtr source = LookupWindow(stuff->srcWid, client); if (!source) return BadWindow; winX = source->drawable.x; winY = source->drawable.y; if ((x < (winX + stuff->srcX)) || (y < (winY + stuff->srcY)) || ((stuff->srcWidth != 0) && (winX + stuff->srcX + (int)stuff->srcWidth < x)) || ((stuff->srcHeight != 0) && (winY + stuff->srcY + (int)stuff->srcHeight < y)) || (!PointInWindowIsVisible(source, x, y))) return Success; } if (dest) { x = dest->drawable.x; y = dest->drawable.y; newScreen = dest->drawable.pScreen; } else newScreen = sprite.hotPhys.pScreen; x += stuff->dstX; y += stuff->dstY; if (x < 0) x = 0; else if (x >= newScreen->width) x = newScreen->width - 1; if (y < 0) y = 0; else if (y >= newScreen->height) y = newScreen->height - 1; if (newScreen == sprite.hotPhys.pScreen) { if (x < sprite.physLimits.x1) x = sprite.physLimits.x1; else if (x >= sprite.physLimits.x2) x = sprite.physLimits.x2 - 1; if (y < sprite.physLimits.y1) y = sprite.physLimits.y1; else if (y >= sprite.physLimits.y2) y = sprite.physLimits.y2 - 1; #ifdef SHAPE if (sprite.hotShape) ConfineToShape(sprite.hotShape, &x, &y); #endif (*newScreen->SetCursorPosition)(newScreen, x, y, TRUE); } else if (!PointerConfinedToScreen()) { NewCurrentScreen(newScreen, x, y); } return Success; } /* "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a passive grab set on the window to be activated. */ static Bool CheckPassiveGrabsOnWindow(pWin, device, xE, count) WindowPtr pWin; register DeviceIntPtr device; register xEvent *xE; int count; { register GrabPtr grab = wPassiveGrabs(pWin); GrabRec tempGrab; register xEvent *dxE; if (!grab) return FALSE; tempGrab.window = pWin; tempGrab.device = device; tempGrab.type = xE->u.u.type; tempGrab.detail.exact = xE->u.u.detail; tempGrab.detail.pMask = NULL; tempGrab.modifiersDetail.pMask = NULL; for (; grab; grab = grab->next) { tempGrab.modifierDevice = grab->modifierDevice; tempGrab.modifiersDetail.exact = grab->modifierDevice->key->state; if (GrabMatchesSecond(&tempGrab, grab)) { (*device->ActivateGrab)(device, grab, currentTime, TRUE); FixUpEventFromWindow(xE, grab->window, None, TRUE); (void) TryClientEvents(rClient(grab), xE, 1, filters[xE->u.u.type], filters[xE->u.u.type], grab); if (device->sync.state == FROZEN_NO_EVENT) { device->sync.event = (xEvent *)xrealloc(device->sync.event, count*sizeof(xEvent)); device->sync.evcount = count; for (dxE = device->sync.event; --count >= 0; dxE++, xE++) *dxE = *xE; device->sync.state = FROZEN_WITH_EVENT; } return TRUE; } } return FALSE; } /* "CheckDeviceGrabs" handles both keyboard and pointer events that may cause a passive grab to be activated. If the event is a keyboard event, the ancestors of the focus window are traced down and tried to see if they have any passive grabs to be activated. If the focus window itself is reached and it's descendants contain they pointer, the ancestors of the window that the pointer is in are then traced down starting at the focus window, otherwise no grabs are activated. If the event is a pointer event, the ancestors of the window that the pointer is in are traced down starting at the root until CheckPassiveGrabs causes a passive grab to activate or all the windows are tried. PRH */ Bool CheckDeviceGrabs(device, xE, checkFirst, count) register DeviceIntPtr device; register xEvent *xE; int checkFirst; int count; { register int i; register WindowPtr pWin; register FocusClassPtr focus = device->focus; i = checkFirst; if (focus) { for (; i < focus->traceGood; i++) { pWin = focus->trace[i]; if (pWin->optional && CheckPassiveGrabsOnWindow(pWin, device, xE, count)) return TRUE; } if ((focus->win == NoneWin) || (i >= spriteTraceGood) || ((i > 0) && (pWin != spriteTrace[i-1]))) return FALSE; } for (; i < spriteTraceGood; i++) { pWin = spriteTrace[i]; if (pWin->optional && CheckPassiveGrabsOnWindow(pWin, device, xE, count)) return TRUE; } return FALSE; } void DeliverFocusedEvent(keybd, xE, window, count) xEvent *xE; DeviceIntPtr keybd; WindowPtr window; int count; { WindowPtr focus = keybd->focus->win; if (focus == FollowKeyboardWin) focus = inputInfo.keyboard->focus->win; if (!focus) return; if (focus == PointerRootWin) { DeliverDeviceEvents(window, xE, NullGrab, NullWindow, keybd, count); return; } if ((focus == window) || IsParent(focus, window)) { if (DeliverDeviceEvents(window, xE, NullGrab, focus, keybd, count)) return; } /* just deliver it to the focus window */ FixUpEventFromWindow(xE, focus, None, FALSE); (void)DeliverEventsToWindow(focus, xE, count, filters[xE->u.u.type], NullGrab, 0); } void DeliverGrabbedEvent(xE, thisDev, deactivateGrab, count) register xEvent *xE; register DeviceIntPtr thisDev; Bool deactivateGrab; int count; { register GrabPtr grab = thisDev->grab; int deliveries = 0; register DeviceIntPtr dev; register xEvent *dxE; if (grab->ownerEvents) { WindowPtr focus; if (thisDev->focus) { focus = thisDev->focus->win; if (focus == FollowKeyboardWin) focus = inputInfo.keyboard->focus->win; } else focus = PointerRootWin; if (focus == PointerRootWin) deliveries = DeliverDeviceEvents(sprite.win, xE, grab, NullWindow, thisDev, count); else if (focus && (focus == sprite.win || IsParent(focus, sprite.win))) deliveries = DeliverDeviceEvents(sprite.win, xE, grab, focus, thisDev, count); else if (focus) deliveries = DeliverDeviceEvents(focus, xE, grab, focus, thisDev, count); } if (!deliveries) { FixUpEventFromWindow(xE, grab->window, None, TRUE); deliveries = TryClientEvents(rClient(grab), xE, 1, (Mask)grab->eventMask, filters[xE->u.u.type], grab); if (deliveries && (xE->u.u.type == MotionNotify)) thisDev->valuator->motionHintWindow = grab->window; } if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify)) switch (thisDev->sync.state) { case FREEZE_BOTH_NEXT_EVENT: for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev == thisDev) continue; FreezeThaw(dev, TRUE); if ((dev->sync.state == FREEZE_BOTH_NEXT_EVENT) && (CLIENT_BITS(dev->grab->resource) == CLIENT_BITS(thisDev->grab->resource))) dev->sync.state = FROZEN_NO_EVENT; else dev->sync.other = thisDev->grab; } /* fall through */ case FREEZE_NEXT_EVENT: thisDev->sync.state = FROZEN_WITH_EVENT; FreezeThaw(thisDev, TRUE); thisDev->sync.event = (xEvent *)xrealloc(thisDev->sync.event, count*sizeof(xEvent)); thisDev->sync.evcount = count; for (dxE = thisDev->sync.event; --count >= 0; dxE++, xE++) *dxE = *xE; break; } } void ProcessKeyboardEvent (xE, keybd, count) register xEvent *xE; register DeviceIntPtr keybd; int count; { int key, bit; register BYTE *kptr; register int i; register CARD8 modifiers; register CARD16 mask; GrabPtr grab = keybd->grab; Bool deactivateGrab = FALSE; register KeyClassPtr keyc = keybd->key; if (!syncEvents.playingEvents) NoticeTime(xE) xE->u.keyButtonPointer.state = (keyc->state | inputInfo.pointer->button->state); xE->u.keyButtonPointer.rootX = sprite.hot.x; xE->u.keyButtonPointer.rootY = sprite.hot.y; key = xE->u.u.detail; kptr = &keyc->down[key >> 3]; bit = 1 << (key & 7); modifiers = keyc->modifierMap[key]; switch (xE->u.u.type) { case KeyPress: if (*kptr & bit) /* allow ddx to generate multiple downs */ { if (!modifiers) { xE->u.u.type = KeyRelease; ProcessKeyboardEvent(xE, keybd, count); xE->u.u.type = KeyPress; /* release can have side effects, don't fall through */ ProcessKeyboardEvent(xE, keybd, count); } return; } inputInfo.pointer->valuator->motionHintWindow = NullWindow; *kptr |= bit; for (i = 0, mask = 1; modifiers; i++, mask <<= 1) { if (mask & modifiers) { /* This key affects modifier "i" */ keyc->modifierKeyCount[i]++; keyc->state |= mask; modifiers &= ~mask; } } if (!grab && CheckDeviceGrabs(keybd, xE, 0, count)) { keybd->activatingKey = key; return; } break; case KeyRelease: if (!(*kptr & bit)) /* guard against duplicates */ return; inputInfo.pointer->valuator->motionHintWindow = NullWindow; *kptr &= ~bit; for (i = 0, mask = 1; modifiers; i++, mask <<= 1) { if (mask & modifiers) { /* This key affects modifier "i" */ if (--keyc->modifierKeyCount[i] <= 0) { keyc->state &= ~mask; keyc->modifierKeyCount[i] = 0; } modifiers &= ~mask; } } if (keybd->fromPassiveGrab && (key == keybd->activatingKey)) deactivateGrab = TRUE; break; default: FatalError("Impossible keyboard event"); } if (grab) DeliverGrabbedEvent(xE, keybd, deactivateGrab, count); else DeliverFocusedEvent(keybd, xE, sprite.win, count); if (deactivateGrab) (*keybd->DeactivateGrab)(keybd); } void ProcessPointerEvent (xE, mouse, count) register xEvent *xE; register DeviceIntPtr mouse; int count; { register GrabPtr grab = mouse->grab; Bool deactivateGrab = FALSE; register ButtonClassPtr butc = mouse->button; if (!syncEvents.playingEvents) NoticeTime(xE) xE->u.keyButtonPointer.state = (butc->state | inputInfo.keyboard->key->state); if (xE->u.u.type != MotionNotify) { register int key; register BYTE *kptr; int bit; xE->u.keyButtonPointer.rootX = sprite.hot.x; xE->u.keyButtonPointer.rootY = sprite.hot.y; key = xE->u.u.detail; kptr = &butc->down[key >> 3]; bit = 1 << (key & 7); switch (xE->u.u.type) { case ButtonPress: mouse->valuator->motionHintWindow = NullWindow; butc->buttonsDown++; butc->motionMask = ButtonMotionMask; *kptr |= bit; xE->u.u.detail = butc->map[key]; if (xE->u.u.detail == 0) return; if (xE->u.u.detail <= 5) butc->state |= (Button1Mask >> 1) << xE->u.u.detail; filters[MotionNotify] = Motion_Filter(butc); if (!grab) if (CheckDeviceGrabs(mouse, xE, 0, count)) return; break; case ButtonRelease: mouse->valuator->motionHintWindow = NullWindow; if (!--butc->buttonsDown) butc->motionMask = 0; *kptr &= ~bit; xE->u.u.detail = butc->map[key]; if (xE->u.u.detail == 0) return; if (xE->u.u.detail <= 5) butc->state &= ~((Button1Mask >> 1) << xE->u.u.detail); filters[MotionNotify] = Motion_Filter(butc); if (!butc->state && mouse->fromPassiveGrab) deactivateGrab = TRUE; break; default: FatalError("bogus pointer event from ddx"); } } else if (!CheckMotion(xE)) return; if (grab) DeliverGrabbedEvent(xE, mouse, deactivateGrab, count); else DeliverDeviceEvents(sprite.win, xE, NullGrab, NullWindow, mouse, count); if (deactivateGrab) (*mouse->DeactivateGrab)(mouse); } #define AtMostOneClient \ (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) void RecalculateDeliverableEvents(pWin) register WindowPtr pWin; { register OtherClients *others; register WindowPtr pChild; pChild = pWin; while (1) { for (others = wOtherClients(pChild); others; others = others->next) { if (others->mask) pChild->optional->otherEventMasks |= others->mask; } pChild->deliverableEvents = pChild->eventMask| wOtherEventMasks(pChild); if (pChild->parent) pChild->deliverableEvents |= (pChild->parent->deliverableEvents & ~wDontPropagateMask(pChild) & PropagateMask); if (pChild->firstChild) { pChild = pChild->firstChild; continue; } while (!pChild->nextSib && (pChild != pWin)) pChild = pChild->parent; if (pChild == pWin) break; pChild = pChild->nextSib; } } int OtherClientGone(pWin, id) register WindowPtr pWin; XID id; { register OtherClientsPtr other, prev; prev = 0; for (other = wOtherClients(pWin); other; other = other->next) { if (other->resource == id) { if (prev) prev->next = other->next; else { if (!(pWin->optional->otherClients = other->next)) CheckWindowOptionalNeed (pWin); } xfree(other); RecalculateDeliverableEvents(pWin); return(Success); } prev = other; } FatalError("client not on event list"); /*NOTREACHED*/ } int EventSelectForWindow(pWin, client, mask) register WindowPtr pWin; register ClientPtr client; Mask mask; { Mask check; OtherClients * others; if (mask & ~AllEventMasks) { client->errorValue = mask; return BadValue; } check = (mask & AtMostOneClient); if (check & (pWin->eventMask|wOtherEventMasks(pWin))) { /* 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 ((wClient(pWin) != client) && (check & pWin->eventMask)) return BadAccess; for (others = wOtherClients (pWin); others; others = others->next) { if (!SameClient(others, client) && (check & others->mask)) return BadAccess; } } if (wClient (pWin) == client) { check = pWin->eventMask; pWin->eventMask = mask; } else { for (others = wOtherClients (pWin); others; others = others->next) { if (SameClient(others, client)) { check = others->mask; if (mask == 0) { FreeResource(others->resource, RT_NONE); return Success; } else others->mask = mask; goto maskSet; } } check = 0; if (!pWin->optional && !MakeWindowOptional (pWin)) return BadAlloc; others = (OtherClients *) xalloc(sizeof(OtherClients)); if (!others) return BadAlloc; others->mask = mask; others->resource = FakeClientID(client->index); others->next = pWin->optional->otherClients; pWin->optional->otherClients = others; if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin)) return BadAlloc; } maskSet: if ((inputInfo.pointer->valuator->motionHintWindow == pWin) && (mask & PointerMotionHintMask) && !(check & PointerMotionHintMask) && !inputInfo.pointer->grab) inputInfo.pointer->valuator->motionHintWindow = NullWindow; RecalculateDeliverableEvents(pWin); return Success; } /*ARGSUSED*/ int EventSuppressForWindow(pWin, client, mask, checkOptional) register WindowPtr pWin; register ClientPtr client; Mask mask; Bool *checkOptional; { register int i, free; if ((mask & ~PropagateMask) && !permitOldBugs) { client->errorValue = mask; return BadValue; } if (pWin->dontPropagate) DontPropagateRefCnts[pWin->dontPropagate]--; if (!mask) i = 0; else { for (i = DNPMCOUNT, free = 0; --i > 0; ) { if (!DontPropagateRefCnts[i]) free = i; else if (mask == DontPropagateMasks[i]) break; } if (!i && free) { i = free; DontPropagateMasks[i] = mask; } } if (i || !mask) { pWin->dontPropagate = i; if (i) DontPropagateRefCnts[i]++; if (pWin->optional) { pWin->optional->dontPropagateMask = mask; *checkOptional = TRUE; } } else { if (!pWin->optional && !MakeWindowOptional (pWin)) { if (pWin->dontPropagate) DontPropagateRefCnts[pWin->dontPropagate]++; return BadAlloc; } pWin->dontPropagate = 0; pWin->optional->dontPropagateMask = mask; } RecalculateDeliverableEvents(pWin); return Success; } 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; register WindowPtr pWin; { xEvent event; register DeviceIntPtr keybd = inputInfo.keyboard; WindowPtr focus; register DeviceIntPtr mouse = inputInfo.pointer; register GrabPtr grab = mouse->grab; Mask mask; if ((pWin == mouse->valuator->motionHintWindow) && (detail != NotifyInferior)) mouse->valuator->motionHintWindow = NullWindow; if (grab) { mask = (pWin == grab->window) ? grab->eventMask : 0; if (grab->ownerEvents) mask |= EventMaskForClient(pWin, rClient(grab)); } else { mask = pWin->eventMask | wOtherEventMasks(pWin); } if (mask & filters[type]) { 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; /* Counts on the same initial structure of crossing & button events! */ FixUpEventFromWindow(&event, pWin, None, TRUE); event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? ELFlagSameScreen : 0; event.u.enterLeave.state = keybd->key->state | mouse->button->state; event.u.enterLeave.mode = mode; focus = keybd->focus->win; if ((focus != NoneWin) && ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin))) event.u.enterLeave.flags |= ELFlagFocus; if (grab) (void)TryClientEvents(rClient(grab), &event, 1, mask, filters[type], grab); else (void)DeliverEventsToWindow(pWin, &event, 1, filters[type], NullGrab, 0); } if ((type == EnterNotify) && (mask & KeymapStateMask)) { xKeymapEvent ke; ke.type = KeymapNotify; bcopy((char *)&keybd->key->down[1], (char *)&ke.map[0], 31); if (grab) (void)TryClientEvents(rClient(grab), (xEvent *)&ke, 1, mask, KeymapStateMask, grab); else (void)DeliverEventsToWindow(pWin, (xEvent *)&ke, 1, KeymapStateMask, NullGrab, 0); } } 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); } static 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, WindowTable[fromWin->drawable.pScreen->myNum], mode, NotifyNonlinearVirtual, TRUE); EnterNotifies(WindowTable[toWin->drawable.pScreen->myNum], toWin->parent, mode, NotifyNonlinearVirtual); } EnterLeaveEvent(EnterNotify, mode, NotifyNonlinear, toWin); } } static void FocusEvent(dev, type, mode, detail, pWin) DeviceIntPtr dev; int type, mode, detail; register WindowPtr pWin; { xEvent event; #ifdef XINPUT if (dev != inputInfo.keyboard) { DeviceFocusEvent(dev, type, mode, detail, pWin); return; } #endif event.u.focus.mode = mode; event.u.u.type = type; event.u.u.detail = detail; event.u.focus.window = pWin->drawable.id; (void)DeliverEventsToWindow(pWin, &event, 1, filters[type], NullGrab, 0); if ((type == FocusIn) && ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) { xKeymapEvent ke; ke.type = KeymapNotify; bcopy((char *)dev->key->down, (char *)&ke.map[0], 31); (void)DeliverEventsToWindow(pWin, (xEvent *)&ke, 1, KeymapStateMask, NullGrab, 0); } } /* * recursive because it is easier * no-op if child not descended from ancestor */ static Bool FocusInEvents(dev, ancestor, child, skipChild, mode, detail, doAncestor) DeviceIntPtr dev; WindowPtr ancestor, child, skipChild; int mode, detail; Bool doAncestor; { if (child == NullWindow) return ancestor == NullWindow; if (ancestor == child) { if (doAncestor) FocusEvent(dev, FocusIn, mode, detail, child); return TRUE; } if (FocusInEvents(dev, ancestor, child->parent, skipChild, mode, detail, doAncestor)) { if (child != skipChild) FocusEvent(dev, FocusIn, mode, detail, child); return TRUE; } return FALSE; } /* dies horribly if ancestor is not an ancestor of child */ static void FocusOutEvents(dev, child, ancestor, mode, detail, doAncestor) DeviceIntPtr dev; WindowPtr child, ancestor; int detail; Bool doAncestor; { register WindowPtr pWin; for (pWin = child; pWin != ancestor; pWin = pWin->parent) FocusEvent(dev, FocusOut, mode, detail, pWin); if (doAncestor) FocusEvent(dev, FocusOut, mode, detail, ancestor); } void DoFocusEvents(dev, fromWin, toWin, mode) DeviceIntPtr dev; WindowPtr fromWin, toWin; int mode; { int out, in; /* for holding details for to/from PointerRoot/None */ int i; if (fromWin == toWin) return; 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)) { if (fromWin == PointerRootWin) FocusOutEvents(dev, sprite.win, ROOT, mode, NotifyPointer, TRUE); /* Notify all the roots */ for (i=0; iparent, NullWindow, mode, NotifyNonlinearVirtual, FALSE); } /* Notify all the roots */ for (i=0; iparent != NullWindow) (void)FocusInEvents(dev, ROOT, toWin, toWin, mode, NotifyNonlinearVirtual, TRUE); FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin); if (IsParent(toWin, sprite.win)) (void)FocusInEvents(dev, toWin, sprite.win, NullWindow, mode, NotifyPointer, FALSE); } else { if (IsParent(toWin, fromWin)) { FocusEvent(dev, FocusOut, mode, NotifyAncestor, fromWin); FocusOutEvents(dev, fromWin->parent, toWin, mode, NotifyVirtual, FALSE); FocusEvent(dev, FocusIn, mode, NotifyInferior, toWin); if ((IsParent(toWin, sprite.win)) && (sprite.win != fromWin) && (!IsParent(fromWin, sprite.win)) && (!IsParent(sprite.win, fromWin))) (void)FocusInEvents(dev, 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(dev, sprite.win, fromWin, mode, NotifyPointer, FALSE); FocusEvent(dev, FocusOut, mode, NotifyInferior, fromWin); (void)FocusInEvents(dev, fromWin, toWin, toWin, mode, NotifyVirtual, FALSE); FocusEvent(dev, FocusIn, mode, NotifyAncestor, toWin); } else { /* neither fromWin or toWin is child of other */ WindowPtr common = CommonAncestor(toWin, fromWin); /* common == NullWindow ==> different screens */ if (IsParent(fromWin, sprite.win)) FocusOutEvents(dev, sprite.win, fromWin, mode, NotifyPointer, FALSE); FocusEvent(dev, FocusOut, mode, NotifyNonlinear, fromWin); if (fromWin->parent != NullWindow) FocusOutEvents(dev, fromWin->parent, common, mode, NotifyNonlinearVirtual, FALSE); if (toWin->parent != NullWindow) (void)FocusInEvents(dev, common, toWin, toWin, mode, NotifyNonlinearVirtual, FALSE); FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin); if (IsParent(toWin, sprite.win)) (void)FocusInEvents(dev, toWin, sprite.win, NullWindow, mode, NotifyPointer, FALSE); } } } } int SetInputFocus(client, dev, focusID, revertTo, ctime, followOK) ClientPtr client; DeviceIntPtr dev; Window focusID; CARD8 revertTo; Time ctime; Bool followOK; { register FocusClassPtr focus = dev->focus; register WindowPtr focusWin; int mode; TimeStamp time; UpdateCurrentTime(); if ((revertTo != RevertToParent) && (revertTo != RevertToPointerRoot) && (revertTo != RevertToNone)) { client->errorValue = revertTo; return BadValue; } time = ClientTimeToServerTime(ctime); if ((focusID == None) || (focusID == PointerRoot)) focusWin = (WindowPtr)focusID; else if ((focusID == FollowKeyboard) && followOK) focusWin = inputInfo.keyboard->focus->win; else if (!(focusWin = LookupWindow(focusID, client))) return BadWindow; else { /* It is a match error to try to set the input focus to an unviewable window. */ if(!focusWin->realized) return(BadMatch); } if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, focus->time) == EARLIER)) return Success; mode = (dev->grab) ? NotifyWhileGrabbed : NotifyNormal; DoFocusEvents(dev, focus->win, focusWin, mode); focus->time = time; focus->revert = revertTo; focus->win = focusWin; if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) focus->traceGood = 0; else { int depth = 0; register WindowPtr pWin; for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; if (depth > focus->traceSize) { focus->traceSize = depth+1; focus->trace = (WindowPtr *)xrealloc(focus->trace, focus->traceSize * sizeof(WindowPtr)); if (!focus->trace) FatalError("could not realloc focus trace"); /* XXX */ } focus->traceGood = depth; for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) focus->trace[depth] = pWin; } return Success; } int ProcSetInputFocus(client) ClientPtr client; { REQUEST(xSetInputFocusReq); REQUEST_SIZE_MATCH(xSetInputFocusReq); return SetInputFocus(client, inputInfo.keyboard, stuff->focus, stuff->revertTo, stuff->time, FALSE); } int ProcGetInputFocus(client) ClientPtr client; { xGetInputFocusReply rep; REQUEST(xReq); FocusClassPtr focus = inputInfo.keyboard->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->drawable.id; 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); UpdateCurrentTime(); if ((stuff->pointerMode != GrabModeSync) && (stuff->pointerMode != GrabModeAsync)) { client->errorValue = stuff->pointerMode; return BadValue; } if ((stuff->keyboardMode != GrabModeSync) && (stuff->keyboardMode != GrabModeAsync)) { client->errorValue = stuff->keyboardMode; return BadValue; } if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) { client->errorValue = stuff->ownerEvents; return BadValue; } if ((stuff->eventMask & ~PointerGrabMask) && !permitOldBugs) { client->errorValue = stuff->eventMask; return BadValue; } pWin = LookupWindow(stuff->grabWindow, client); if (!pWin) return BadWindow; if (stuff->confineTo == None) confineTo = NullWindow; else { confineTo = LookupWindow(stuff->confineTo, client); if (!confineTo) return BadWindow; } if (stuff->cursor == None) cursor = NullCursor; else { cursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR); if (!cursor) { client->errorValue = stuff->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) && !SameClient(grab, client)) rep.status = AlreadyGrabbed; else if ((!pWin->realized) || (confineTo && !(confineTo->realized && (* confineTo->drawable.pScreen->RegionNotEmpty) (&confineTo->borderSize)))) rep.status = GrabNotViewable; else if (device->sync.frozen && ((device->sync.other && !SameClient(device->sync.other, client)) || ((device->sync.state >= FROZEN) && !SameClient(device->grab, client)))) rep.status = GrabFrozen; else if ((CompareTimeStamps(time, currentTime) == LATER) || (device->grab && (CompareTimeStamps(time, device->grabTime) == EARLIER))) rep.status = GrabInvalidTime; else { GrabRec tempGrab; if (grab && grab->confineTo && !confineTo) ConfineCursorToWindow(ROOT, FALSE); tempGrab.cursor = cursor; tempGrab.resource = client->clientAsMask; tempGrab.ownerEvents = stuff->ownerEvents; tempGrab.eventMask = stuff->eventMask; tempGrab.confineTo = confineTo; tempGrab.window = pWin; tempGrab.keyboardMode = stuff->keyboardMode; tempGrab.pointerMode = stuff->pointerMode; tempGrab.device = inputInfo.pointer; (*inputInfo.pointer->ActivateGrab)(inputInfo.pointer, &tempGrab, time, FALSE); rep.status = GrabSuccess; } WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); 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 (stuff->eventMask & ~PointerGrabMask) { client->errorValue = stuff->eventMask; return BadValue; } if (stuff->cursor == None) newCursor = NullCursor; else { newCursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR); if (!newCursor) { client->errorValue = stuff->cursor; return BadCursor; } } if (!grab) return Success; if (!SameClient(grab, client)) return BadAccess; time = ClientTimeToServerTime(stuff->time); if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, device->grabTime) == EARLIER)) return Success; if (grab->cursor) FreeCursor(grab->cursor, (Cursor)0); grab->cursor = newCursor; if (newCursor) newCursor->refcnt++; PostNewCursor(); 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); UpdateCurrentTime(); time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->grabTime) != EARLIER) && (grab) && SameClient(grab, client)) (*inputInfo.pointer->DeactivateGrab)(inputInfo.pointer); return Success; } int GrabDevice(client, dev, this_mode, other_mode, grabWindow, ownerEvents, ctime, mask) register ClientPtr client; register DeviceIntPtr dev; unsigned this_mode; unsigned other_mode; Window grabWindow; unsigned ownerEvents; Time ctime; Mask mask; { int status; register WindowPtr pWin; register GrabPtr grab = dev->grab; TimeStamp time; UpdateCurrentTime(); if ((this_mode != GrabModeSync) && (this_mode != GrabModeAsync)) { client->errorValue = this_mode; return -1; } if ((other_mode != GrabModeSync) && (other_mode != GrabModeAsync)) { client->errorValue = other_mode; return -1; } if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) { client->errorValue = ownerEvents; return -1; } pWin = LookupWindow(grabWindow, client); if (!pWin) return BadWindow; time = ClientTimeToServerTime(ctime); if (grab && !SameClient(grab, client)) status = AlreadyGrabbed; else if (!pWin->realized) status = GrabNotViewable; else if ((CompareTimeStamps(time, currentTime) == LATER) || (dev->grab && (CompareTimeStamps(time, dev->grabTime) == EARLIER))) status = GrabInvalidTime; else if (dev->sync.frozen && ((dev->sync.other && !SameClient(dev->sync.other, client)) || ((dev->sync.state >= FROZEN) && !SameClient(dev->grab, client)))) status = GrabFrozen; else { GrabRec tempGrab; tempGrab.window = pWin; tempGrab.resource = client->clientAsMask; tempGrab.ownerEvents = ownerEvents; tempGrab.keyboardMode = this_mode; tempGrab.pointerMode = other_mode; tempGrab.eventMask = mask; tempGrab.device = dev; (*dev->ActivateGrab)(dev, &tempGrab, time, FALSE); status = GrabSuccess; } return status; } int ProcGrabKeyboard(client) ClientPtr client; { xGrabKeyboardReply rep; REQUEST(xGrabKeyboardReq); int status; REQUEST_SIZE_MATCH(xGrabKeyboardReq); status = GrabDevice(client, inputInfo.keyboard, stuff->keyboardMode, stuff->pointerMode, stuff->grabWindow, stuff->ownerEvents, stuff->time, KeyPressMask | KeyReleaseMask); if (status < 0) return BadValue; rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.length = 0; rep.status = status; 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); UpdateCurrentTime(); time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->grabTime) != EARLIER) && (grab) && SameClient(grab, client)) (*device->DeactivateGrab)(device); return Success; } int ProcQueryPointer(client) ClientPtr client; { xQueryPointerReply rep; WindowPtr pWin, t; REQUEST(xResourceReq); DeviceIntPtr mouse = inputInfo.pointer; REQUEST_SIZE_MATCH(xResourceReq); pWin = LookupWindow(stuff->id, client); if (!pWin) return BadWindow; if (mouse->valuator->motionHintWindow) MaybeStopHint(mouse, client); rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.mask = mouse->button->state | inputInfo.keyboard->key->state; rep.length = 0; rep.root = (ROOT)->drawable.id; rep.rootX = sprite.hot.x; rep.rootY = sprite.hot.y; rep.child = None; if (sprite.hot.pScreen == pWin->drawable.pScreen) { rep.sameScreen = xTrue; rep.winX = sprite.hot.x - pWin->drawable.x; rep.winY = sprite.hot.y - pWin->drawable.y; for (t = sprite.win; t; t = t->parent) if (t->parent == pWin) { rep.child = t->drawable.id; break; } } else { rep.sameScreen = xFalse; rep.winX = 0; rep.winY = 0; } WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); return(Success); } void InitEvents() { int i; sprite.hot.pScreen = sprite.hotPhys.pScreen = (ScreenPtr)NULL; inputInfo.numDevices = 0; inputInfo.devices = (DeviceIntPtr)NULL; inputInfo.off_devices = (DeviceIntPtr)NULL; inputInfo.keyboard = (DeviceIntPtr)NULL; inputInfo.pointer = (DeviceIntPtr)NULL; if (spriteTraceSize == 0) { spriteTraceSize = 32; spriteTrace = (WindowPtr *)xalloc(32*sizeof(WindowPtr)); if (!spriteTrace) FatalError("failed to allocate spriteTrace"); } spriteTraceGood = 0; lastEventMask = OwnerGrabButtonMask; filters[MotionNotify] = PointerMotionMask; sprite.win = NullWindow; sprite.current = NullCursor; sprite.hotLimits.x1 = 0; sprite.hotLimits.y1 = 0; sprite.hotLimits.x2 = 0; sprite.hotLimits.y2 = 0; syncEvents.replayDev = (DeviceIntPtr)NULL; while (syncEvents.pending) { QdEventPtr next = syncEvents.pending->next; xfree(syncEvents.pending); syncEvents.pending = next; } syncEvents.pendtail = &syncEvents.pending; syncEvents.playingEvents = FALSE; currentTime.months = 0; currentTime.milliseconds = GetTimeInMillis(); for (i = 0; i < DNPMCOUNT; i++) { DontPropagateMasks[i] = 0; DontPropagateRefCnts[i] = 0; } } int ProcSendEvent(client) ClientPtr client; { extern int lastEvent; /* Defined in extension.c */ WindowPtr pWin; WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ REQUEST(xSendEventReq); REQUEST_SIZE_MATCH(xSendEventReq); /* The client's event type must be a core event type or one defined by an extension. */ if ( ! ((stuff->event.u.u.type < LASTEvent) || ((EXTENSION_EVENT_BASE <= stuff->event.u.u.type) && (stuff->event.u.u.type < lastEvent))) ) { client->errorValue = stuff->event.u.u.type; return BadValue; } if (stuff->eventMask & ~AllEventMasks) { client->errorValue = stuff->eventMask; return BadValue; } if (stuff->destination == PointerWindow) pWin = sprite.win; else if (stuff->destination == InputFocus) { WindowPtr inputFocus = inputInfo.keyboard->focus->win; if (inputFocus == NoneWin) return Success; /* If the input focus is PointerRootWin, send the event to where the pointer is if possible, then perhaps propogate up to root. */ if (inputFocus == PointerRootWin) inputFocus = ROOT; if (IsParent(inputFocus, sprite.win)) { effectiveFocus = inputFocus; pWin = sprite.win; } else effectiveFocus = pWin = inputFocus; } else pWin = LookupWindow(stuff->destination, client); if (!pWin) return BadWindow; if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) { client->errorValue = stuff->propagate; return BadValue; } stuff->event.u.u.type |= 0x80; if (stuff->propagate) { for (;pWin; pWin = pWin->parent) { if (DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, NullGrab, 0)) return Success; if (pWin == effectiveFocus) return Success; stuff->eventMask &= ~wDontPropagateMask(pWin); } } else (void)DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, NullGrab, 0); return Success; } int ProcUngrabKey(client) ClientPtr client; { REQUEST(xUngrabKeyReq); WindowPtr pWin; GrabRec tempGrab; REQUEST_SIZE_MATCH(xUngrabKeyReq); pWin = LookupWindow(stuff->grabWindow, client); if (!pWin) return BadWindow; if ((stuff->modifiers != AnyModifier) && (stuff->modifiers & ~AllModifiersMask)) { client->errorValue = stuff->modifiers; return BadValue; } tempGrab.resource = client->clientAsMask; tempGrab.device = inputInfo.keyboard; tempGrab.window = pWin; tempGrab.modifiersDetail.exact = stuff->modifiers; tempGrab.modifiersDetail.pMask = NULL; tempGrab.modifierDevice = inputInfo.keyboard; tempGrab.type = KeyPress; tempGrab.detail.exact = stuff->key; tempGrab.detail.pMask = NULL; if (!DeletePassiveGrabFromList(&tempGrab)) return(BadAlloc); return(Success); } int ProcGrabKey(client) ClientPtr client; { WindowPtr pWin; REQUEST(xGrabKeyReq); GrabPtr grab; DeviceIntPtr keybd = inputInfo.keyboard; REQUEST_SIZE_MATCH(xGrabKeyReq); if ((stuff->pointerMode != GrabModeSync) && (stuff->pointerMode != GrabModeAsync)) { client->errorValue = stuff->pointerMode; return BadValue; } if ((stuff->keyboardMode != GrabModeSync) && (stuff->keyboardMode != GrabModeAsync)) { client->errorValue = stuff->keyboardMode; return BadValue; } if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) || (stuff->key < keybd->key->curKeySyms.minKeyCode)) && (stuff->key != AnyKey)) { client->errorValue = stuff->key; return BadValue; } if ((stuff->modifiers != AnyModifier) && (stuff->modifiers & ~AllModifiersMask)) { client->errorValue = stuff->modifiers; return BadValue; } pWin = LookupWindow(stuff->grabWindow, client); if (!pWin) return BadWindow; grab = CreateGrab(client->index, keybd, pWin, (Mask)(KeyPressMask | KeyReleaseMask), (Bool)stuff->ownerEvents, (Bool)stuff->keyboardMode, (Bool)stuff->pointerMode, keybd, stuff->modifiers, KeyPress, stuff->key, NullWindow, NullCursor); if (!grab) return BadAlloc; return AddPassiveGrabToList(grab); } int ProcGrabButton(client) ClientPtr client; { WindowPtr pWin, confineTo; REQUEST(xGrabButtonReq); CursorPtr cursor; GrabPtr grab; REQUEST_SIZE_MATCH(xGrabButtonReq); if ((stuff->pointerMode != GrabModeSync) && (stuff->pointerMode != GrabModeAsync)) { client->errorValue = stuff->pointerMode; return BadValue; } if ((stuff->keyboardMode != GrabModeSync) && (stuff->keyboardMode != GrabModeAsync)) { client->errorValue = stuff->keyboardMode; return BadValue; } if ((stuff->modifiers != AnyModifier) && (stuff->modifiers & ~AllModifiersMask)) { client->errorValue = stuff->modifiers; return BadValue; } if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) { client->errorValue = stuff->ownerEvents; return BadValue; } if (stuff->eventMask & ~PointerGrabMask) { client->errorValue = stuff->eventMask; return BadValue; } pWin = LookupWindow(stuff->grabWindow, client); if (!pWin) return BadWindow; if (stuff->confineTo == None) confineTo = NullWindow; else { confineTo = LookupWindow(stuff->confineTo, client); if (!confineTo) return BadWindow; } if (stuff->cursor == None) cursor = NullCursor; else { cursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR); if (!cursor) { client->errorValue = stuff->cursor; return BadCursor; } } grab = CreateGrab(client->index, inputInfo.pointer, pWin, permitOldBugs ? (Mask)(stuff->eventMask | ButtonPressMask | ButtonReleaseMask) : (Mask)stuff->eventMask, (Bool)stuff->ownerEvents, (Bool) stuff->keyboardMode, (Bool)stuff->pointerMode, inputInfo.keyboard, stuff->modifiers, ButtonPress, stuff->button, confineTo, cursor); if (!grab) return BadAlloc; return AddPassiveGrabToList(grab); } int ProcUngrabButton(client) ClientPtr client; { REQUEST(xUngrabButtonReq); WindowPtr pWin; GrabRec tempGrab; REQUEST_SIZE_MATCH(xUngrabButtonReq); if ((stuff->modifiers != AnyModifier) && (stuff->modifiers & ~AllModifiersMask)) { client->errorValue = stuff->modifiers; return BadValue; } pWin = LookupWindow(stuff->grabWindow, client); if (!pWin) return BadWindow; tempGrab.resource = client->clientAsMask; tempGrab.device = inputInfo.pointer; tempGrab.window = pWin; tempGrab.modifiersDetail.exact = stuff->modifiers; tempGrab.modifiersDetail.pMask = NULL; tempGrab.modifierDevice = inputInfo.keyboard; tempGrab.type = ButtonPress; tempGrab.detail.exact = stuff->button; tempGrab.detail.pMask = NULL; if (!DeletePassiveGrabFromList(&tempGrab)) return(BadAlloc); return(Success); } void DeleteWindowFromAnyEvents(pWin, freeResources) WindowPtr pWin; Bool freeResources; { WindowPtr parent; DeviceIntPtr mouse = inputInfo.pointer; DeviceIntPtr keybd = inputInfo.keyboard; FocusClassPtr focus = keybd->focus; OtherClientsPtr oc; GrabPtr passive; /* Deactivate any grabs performed on this window, before making any input focus changes. */ if (mouse->grab && ((mouse->grab->window == pWin) || (mouse->grab->confineTo == pWin))) (*mouse->DeactivateGrab)(mouse); /* Deactivating a keyboard grab should cause focus events. */ if (keybd->grab && (keybd->grab->window == pWin)) (*keybd->DeactivateGrab)(keybd); /* If the focus window is a root window (ie. has no parent) then don't delete the focus from it. */ if ((pWin == focus->win) && (pWin->parent != NullWindow)) { int focusEventMode = NotifyNormal; /* If a grab is in progress, then alter the mode of focus events. */ if (keybd->grab) focusEventMode = NotifyWhileGrabbed; switch (focus->revert) { case RevertToNone: DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); focus->win = NoneWin; focus->traceGood = 0; break; case RevertToParent: parent = pWin; do { parent = parent->parent; focus->traceGood--; } while (!parent->realized); DoFocusEvents(keybd, pWin, parent, focusEventMode); focus->win = parent; focus->revert = RevertToNone; break; case RevertToPointerRoot: DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); focus->win = PointerRootWin; focus->traceGood = 0; break; } } if (mouse->valuator->motionHintWindow == pWin) mouse->valuator->motionHintWindow = NullWindow; if (freeResources) { if (pWin->dontPropagate) DontPropagateRefCnts[pWin->dontPropagate]--; while (oc = wOtherClients(pWin)) FreeResource(oc->resource, RT_NONE); while (passive = wPassiveGrabs(pWin)) FreeResource(passive->resource, RT_NONE); } #ifdef XINPUT DeleteWindowFromAnyExtEvents(pWin, freeResources); #endif } /* Call this whenever some window at or below pWin has changed geometry */ /*ARGSUSED*/ void CheckCursorConfinement(pWin) WindowPtr pWin; { GrabPtr grab = inputInfo.pointer->grab; WindowPtr confineTo; if (grab && (confineTo = grab->confineTo)) { if (!(* confineTo->drawable.pScreen->RegionNotEmpty) (&confineTo->borderSize)) (*inputInfo.pointer->DeactivateGrab)(inputInfo.pointer); else if ((pWin == confineTo) || IsParent(pWin, confineTo)) ConfineCursorToWindow(confineTo, TRUE); } } Mask EventMaskForClient(pWin, client) WindowPtr pWin; ClientPtr client; { register OtherClientsPtr other; if (wClient (pWin) == client) return pWin->eventMask; for (other = wOtherClients(pWin); other; other = other->next) { if (SameClient(other, client)) return other->mask; } return 0; } int ProcRecolorCursor(client) ClientPtr client; { CursorPtr pCursor; int nscr; ScreenPtr pscr; REQUEST(xRecolorCursorReq); REQUEST_SIZE_MATCH(xRecolorCursorReq); pCursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR); if ( !pCursor) { client->errorValue = stuff->cursor; return (BadCursor); } pCursor->foreRed = stuff->foreRed; pCursor->foreGreen = stuff->foreGreen; pCursor->foreBlue = stuff->foreBlue; pCursor->backRed = stuff->backRed; pCursor->backGreen = stuff->backGreen; pCursor->backBlue = stuff->backBlue; for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { pscr = screenInfo.screens[nscr]; ( *pscr->RecolorCursor)(pscr, pCursor, (pCursor == sprite.current) && (pscr == sprite.hotPhys.pScreen)); } return (Success); } void WriteEventsToClient(pClient, count, events) ClientPtr pClient; int count; xEvent *events; { if(pClient->swapped) { int i; xEvent eventTo, *eventFrom; for(i = 0; i < count; i++) { eventFrom = &events[i]; /* Remember to strip off the leading bit of type in case this event was sent with "SendEvent." */ (*EventSwapVector[eventFrom->u.u.type & 0177]) (eventFrom, &eventTo); (void)WriteToClient(pClient, sizeof(xEvent), (char *)&eventTo); } } else { (void)WriteToClient(pClient, count * sizeof(xEvent), (char *) events); } }