/* $XdotOrg: xc/programs/Xserver/dix/events.c,v 1.6.4.1.10.2 2005/01/12 00:37:52 deronj Exp $ */ /* $XFree86: xc/programs/Xserver/dix/events.c,v 3.51 2004/01/12 17:04:52 tsi Exp $ */ /************************************************************ Copyright (c) 2004, Sun Microsystems, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. Copyright 1987, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. Copyright 1987 by Digital Equipment Corporation, Maynard, 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 name of Digital 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. ********************************************************/ /* The panoramix components contained the following notice */ /***************************************************************** Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of Digital Equipment Corporation shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Digital Equipment Corporation. ******************************************************************/ /* $Xorg: events.c,v 1.4 2001/02/09 02:04:40 xorgcvs 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" #ifdef PANORAMIX #include "panoramiX.h" #include "panoramiXsrv.h" #endif #include "globals.h" #ifdef XKB #include "XKBsrv.h" extern Bool XkbFilterEvents(ClientPtr, int, xEvent *); #endif #ifdef XCSECURITY #define _SECURITY_SERVER #include "security.h" #endif #ifdef XEVIE extern WindowPtr *WindowTable; extern int xevieFlag; extern int xevieClientIndex; extern DeviceIntPtr xeviemouse; extern DeviceIntPtr xeviekb; extern Mask xevieMask; extern Mask xevieFilters[128]; extern int xevieEventSent; extern int xevieKBEventSent; int xeviegrabState = 0; xEvent *xeviexE; #endif #include "XIproto.h" #include "exevents.h" #include "extnsionst.h" #include "dixevents.h" #include "dixgrabs.h" #include "dispatch.h" #ifdef LG3D /* Enable one or the other, but not both */ #undef LG3D_EVENT_TEST_LATENCY #undef LG3D_EVENT_TEST_THROUGHPUT #include "damagewire.h" #include "../Xext/lgeint.h" extern int lgeTryClientEvents (ClientPtr client, xEvent *pEvents, int count, Mask mask, Mask filter, GrabPtr grab); extern WindowPtr XYToSubWindow (WindowPtr pWin, int x, int y, int *xWinRel, int *yWinRel); extern Bool PointInBorderSize(WindowPtr pWin, int x, int y); #endif /* LG3D */ #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 XE_KBPTR (xE->u.keyButtonPointer) #define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) CallbackListPtr EventCallback; CallbackListPtr DeviceEventCallback; #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. */ #ifdef LG3D WindowPtr *spriteTrace = (WindowPtr *)NULL; #define ROOT spriteTrace[0] int spriteTraceSize = 0; int spriteTraceGood; #else static WindowPtr *spriteTrace = (WindowPtr *)NULL; #define ROOT spriteTrace[0] static int spriteTraceSize = 0; static int spriteTraceGood; #endif /* LG3D */ static struct { CursorPtr current; BoxRec hotLimits; /* logical constraints of hot spot */ Bool confined; /* confined to screen */ #if defined(SHAPE) || defined(PANORAMIX) 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 */ #ifdef PANORAMIX ScreenPtr screen; /* all others are in Screen 0 coordinates */ RegionRec Reg1; /* Region 1 for confining motion */ RegionRec Reg2; /* Region 2 for confining virtual motion */ WindowPtr windows[MAXSCREENS]; WindowPtr confineWin; /* confine window */ #endif } sprite; /* info about the cursor sprite */ #ifdef LG3D typedef struct virtual_sprite { WindowPtr win; /* The top-level window the sprite is in (or PRW) */ HotSpot hot; /* Sprite location relative to win */ } VirtualSprite; static VirtualSprite virtualSprite; #endif /* LG3D */ #ifdef XEVIE WindowPtr xeviewin; HotSpot xeviehot; #endif static void DoEnterLeaveEvents( WindowPtr /*fromWin*/, WindowPtr /*toWin*/, int /*mode*/ ); static WindowPtr XYToWindow( int /*x*/, int /*y*/ ); extern int lastEvent; static Mask lastEventMask; #ifdef XINPUT extern int DeviceMotionNotify; #endif #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] = { 0x7c /* key and button events */ }; #ifdef PANORAMIX static void ConfineToShape(RegionPtr shape, int *px, int *py); static void SyntheticMotion(int x, int y); static void PostNewCursor(void); static Bool XineramaSetCursorPosition( int x, int y, Bool generateEvent ){ ScreenPtr pScreen; BoxRec box; int i; /* x,y are in Screen 0 coordinates. We need to decide what Screen to send the message too and what the coordinates relative to that screen are. */ pScreen = sprite.screen; x += panoramiXdataPtr[0].x; y += panoramiXdataPtr[0].y; if(!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum], x, y, &box)) { FOR_NSCREENS(i) { if(i == pScreen->myNum) continue; if(POINT_IN_REGION(pScreen, &XineramaScreenRegions[i], x, y, &box)) { pScreen = screenInfo.screens[i]; break; } } } sprite.screen = pScreen; sprite.hotPhys.x = x - panoramiXdataPtr[0].x; sprite.hotPhys.y = y - panoramiXdataPtr[0].y; x -= panoramiXdataPtr[pScreen->myNum].x; y -= panoramiXdataPtr[pScreen->myNum].y; return (*pScreen->SetCursorPosition)(pScreen, x, y, generateEvent); } static void XineramaConstrainCursor(void) { ScreenPtr pScreen = sprite.screen; BoxRec newBox = sprite.physLimits; /* Translate the constraining box to the screen the sprite is actually on */ newBox.x1 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; newBox.x2 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x; newBox.y1 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; newBox.y2 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y; (* pScreen->ConstrainCursor)(pScreen, &newBox); } static void XineramaCheckPhysLimits( CursorPtr cursor, Bool generateEvents ){ HotSpot new; if (!cursor) return; new = sprite.hotPhys; /* I don't care what the DDX has to say about it */ sprite.physLimits = sprite.hotLimits; /* constrain the pointer to those limits */ 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; if (sprite.hotShape) /* more work if the shape is a mess */ ConfineToShape(sprite.hotShape, &new.x, &new.y); if((new.x != sprite.hotPhys.x) || (new.y != sprite.hotPhys.y)) { XineramaSetCursorPosition (new.x, new.y, generateEvents); if (!generateEvents) SyntheticMotion(new.x, new.y); } /* Tell DDX what the limits are */ XineramaConstrainCursor(); } static Bool XineramaSetWindowPntrs(WindowPtr pWin) { if(pWin == WindowTable[0]) { memcpy(sprite.windows, WindowTable, PanoramiXNumScreens*sizeof(WindowPtr)); } else { PanoramiXRes *win; int i; win = (PanoramiXRes*)LookupIDByType(pWin->drawable.id, XRT_WINDOW); if(!win) return FALSE; for(i = 0; i < PanoramiXNumScreens; i++) { sprite.windows[i] = LookupIDByType(win->info[i].id, RT_WINDOW); if(!sprite.windows[i]) /* window is being unmapped */ return FALSE; } } return TRUE; } static void XineramaCheckVirtualMotion( QdEventPtr qe, WindowPtr pWin ){ if (qe) { sprite.hot.pScreen = qe->pScreen; /* should always be Screen 0 */ 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) { int x, y, off_x, off_y, i; BoxRec lims; if(!XineramaSetWindowPntrs(pWin)) return; i = PanoramiXNumScreens - 1; REGION_COPY(sprite.screen, &sprite.Reg2, &sprite.windows[i]->borderSize); off_x = panoramiXdataPtr[i].x; off_y = panoramiXdataPtr[i].y; while(i--) { x = off_x - panoramiXdataPtr[i].x; y = off_y - panoramiXdataPtr[i].y; if(x || y) REGION_TRANSLATE(sprite.screen, &sprite.Reg2, x, y); REGION_UNION(sprite.screen, &sprite.Reg2, &sprite.Reg2, &sprite.windows[i]->borderSize); off_x = panoramiXdataPtr[i].x; off_y = panoramiXdataPtr[i].y; } lims = *REGION_EXTENTS(sprite.screen, &sprite.Reg2); 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; if (REGION_NUM_RECTS(&sprite.Reg2) > 1) ConfineToShape(&sprite.Reg2, &sprite.hot.x, &sprite.hot.y); if (qe) { qe->pScreen = sprite.hot.pScreen; qe->event->u.keyButtonPointer.rootX = sprite.hot.x; qe->event->u.keyButtonPointer.rootY = sprite.hot.y; } } } static Bool XineramaCheckMotion(xEvent *xE) { WindowPtr prevSpriteWin = sprite.win; if (xE && !syncEvents.playingEvents) { /* Motion events entering DIX get translated to Screen 0 coordinates. Replayed events have already been translated since they've entered DIX before */ XE_KBPTR.rootX += panoramiXdataPtr[sprite.screen->myNum].x - panoramiXdataPtr[0].x; XE_KBPTR.rootY += panoramiXdataPtr[sprite.screen->myNum].y - panoramiXdataPtr[0].y; sprite.hot.x = XE_KBPTR.rootX; sprite.hot.y = XE_KBPTR.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; if (sprite.hotShape) ConfineToShape(sprite.hotShape, &sprite.hot.x, &sprite.hot.y); sprite.hotPhys = sprite.hot; if ((sprite.hotPhys.x != XE_KBPTR.rootX) || (sprite.hotPhys.y != XE_KBPTR.rootY)) { XineramaSetCursorPosition( sprite.hotPhys.x, sprite.hotPhys.y, FALSE); } XE_KBPTR.rootX = sprite.hot.x; XE_KBPTR.rootY = sprite.hot.y; } sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); if (sprite.win != prevSpriteWin) { if (prevSpriteWin != NullWindow) { if (!xE) UpdateCurrentTimeIf(); DoEnterLeaveEvents(prevSpriteWin, sprite.win, NotifyNormal); } PostNewCursor(); return FALSE; } return TRUE; } static void XineramaConfineCursorToWindow(WindowPtr pWin, Bool generateEvents) { if (syncEvents.playingEvents) { XineramaCheckVirtualMotion((QdEventPtr)NULL, pWin); SyntheticMotion(sprite.hot.x, sprite.hot.y); } else { int x, y, off_x, off_y, i; if(!XineramaSetWindowPntrs(pWin)) return; i = PanoramiXNumScreens - 1; REGION_COPY(sprite.screen, &sprite.Reg1, &sprite.windows[i]->borderSize); off_x = panoramiXdataPtr[i].x; off_y = panoramiXdataPtr[i].y; while(i--) { x = off_x - panoramiXdataPtr[i].x; y = off_y - panoramiXdataPtr[i].y; if(x || y) REGION_TRANSLATE(sprite.screen, &sprite.Reg1, x, y); REGION_UNION(sprite.screen, &sprite.Reg1, &sprite.Reg1, &sprite.windows[i]->borderSize); off_x = panoramiXdataPtr[i].x; off_y = panoramiXdataPtr[i].y; } sprite.hotLimits = *REGION_EXTENTS(sprite.screen, &sprite.Reg1); if(REGION_NUM_RECTS(&sprite.Reg1) > 1) sprite.hotShape = &sprite.Reg1; else sprite.hotShape = NullRegion; sprite.confined = FALSE; sprite.confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin; XineramaCheckPhysLimits(sprite.current, generateEvents); } } static void XineramaChangeToCursor(CursorPtr cursor) { #ifndef LG3D if (cursor != sprite.current) { #endif /* ! LG3D */ if ((sprite.current->bits->xhot != cursor->bits->xhot) || (sprite.current->bits->yhot != cursor->bits->yhot)) XineramaCheckPhysLimits(cursor, FALSE); (*sprite.screen->DisplayCursor)(sprite.screen, cursor); sprite.current = cursor; #ifndef LG3D } #endif /* ! LG3D */ } #endif /* PANORAMIX */ 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(int x, int y) { xEvent xE; #ifdef PANORAMIX /* Translate back to the sprite screen since processInputProc will translate from sprite screen to screen 0 upon reentry to the DIX layer */ if(!noPanoramiXExtension) { x += panoramiXdataPtr[0].x - panoramiXdataPtr[sprite.screen->myNum].x; y += panoramiXdataPtr[0].y - panoramiXdataPtr[sprite.screen->myNum].y; } #endif 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(RegionPtr shape, int *px, int *py) { BoxRec box; int x = *px, y = *py; int incx = 1, incy = 1; if (POINT_IN_REGION(sprite.hot.pScreen, shape, x, y, &box)) return; box = *REGION_EXTENTS(sprite.hot.pScreen, 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 (!POINT_IN_REGION(sprite.hot.pScreen, shape, x, y, &box)); *px = x; *py = y; } #endif static void CheckPhysLimits( CursorPtr cursor, Bool generateEvents, Bool confineToScreen, 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); sprite.confined = confineToScreen; (* pScreen->ConstrainCursor)(pScreen, &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( register QdEventPtr qe, register WindowPtr pWin) { #ifdef PANORAMIX if(!noPanoramiXExtension) { XineramaCheckVirtualMotion(qe, pWin); return; } #endif 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 = *REGION_EXTENTS(pWin->drawable.pScreen, &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(WindowPtr pWin, Bool generateEvents, Bool confineToScreen) { ScreenPtr pScreen = pWin->drawable.pScreen; #ifdef PANORAMIX if(!noPanoramiXExtension) { XineramaConfineCursorToWindow(pWin, generateEvents); return; } #endif if (syncEvents.playingEvents) { CheckVirtualMotion((QdEventPtr)NULL, pWin); SyntheticMotion(sprite.hot.x, sprite.hot.y); } else { sprite.hotLimits = *REGION_EXTENTS( pScreen, &pWin->borderSize); #ifdef SHAPE sprite.hotShape = wBoundingShape(pWin) ? &pWin->borderSize : NullRegion; #endif CheckPhysLimits(sprite.current, generateEvents, confineToScreen, pScreen); } } Bool PointerConfinedToScreen() { return sprite.confined; } static void ChangeToCursor(CursorPtr cursor) { #ifdef PANORAMIX if(!noPanoramiXExtension) { XineramaChangeToCursor(cursor); return; } #endif #ifndef LG3D if (cursor != sprite.current) { #endif /* ! LG3D */ if ((sprite.current->bits->xhot != cursor->bits->xhot) || (sprite.current->bits->yhot != cursor->bits->yhot)) CheckPhysLimits(cursor, FALSE, sprite.confined, (ScreenPtr)NULL); (*sprite.hotPhys.pScreen->DisplayCursor) (sprite.hotPhys.pScreen, cursor); sprite.current = cursor; #ifndef LG3D } #endif /* ! LG3D */ } /* 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(void) { 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; } CursorPtr GetSpriteCursor() { return sprite.current; } void GetSpritePosition(px, py) int *px, *py; { *px = sprite.hotPhys.x; *py = sprite.hotPhys.y; } #ifdef PANORAMIX int XineramaGetCursorScreen() { if(!noPanoramiXExtension) { return sprite.screen->myNum; } else { return 0; } } #endif /* PANORAMIX */ #define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ static void MonthChangedOrBadTime(register xEvent *xE) { /* If the ddx/OS is careless about not processing timestamped events from * different sources in sorted order, then it's possible for time to go * backwards when it should not. Here we ensure a decent time. */ if ((currentTime.milliseconds - XE_KBPTR.time) > TIMESLOP) currentTime.months++; else XE_KBPTR.time = currentTime.milliseconds; } #define NoticeTime(xE) { \ if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \ MonthChangedOrBadTime(xE); \ currentTime.milliseconds = (xE)->u.keyButtonPointer.time; \ lastDeviceEventTime = currentTime; } void NoticeEventTime(xE) register xEvent *xE; { if (!syncEvents.playingEvents) NoticeTime(xE); } /************************************************************************** * The following procedures deal with synchronous events * **************************************************************************/ #ifdef LG3D #define SEND_TO_ALLGRAB_CLIENT 0 #define SEND_TO_NORMAL_CLIENT 1 #define SEND_TO_BOTH_CLIENTS 2 /* ** Given an event, returns a code specifying to whom the event ** should be sent. In the case where DS cares, this routine returns the event's ** destination window in the win argument. */ static int lgeDSCaresAboutEvent (xEvent *pEvent, Window *win) { int dest; switch (pEvent->u.u.type) { case KeyPress: case KeyRelease: case ButtonPress: case ButtonRelease: case MotionNotify: *win = pEvent->u.keyButtonPointer.event; dest = SEND_TO_ALLGRAB_CLIENT; break; case EnterNotify: case LeaveNotify: *win = pEvent->u.enterLeave.event; dest = SEND_TO_ALLGRAB_CLIENT; break; case FocusIn: case FocusOut: dest = SEND_TO_ALLGRAB_CLIENT; *win = pEvent->u.focus.window; break; case ConfigureNotify: dest = SEND_TO_BOTH_CLIENTS; *win = pEvent->u.configureNotify.window; break; default: /* The above events are the only one the DS cares about */ /* Note: XDamageNotify is handled specially by client == NULL */ dest = SEND_TO_NORMAL_CLIENT; } return dest; } /* ** If lgeGrabAllWindowEvents is active, send all events that the ** LG DS cares that are destined for the grab window to the grab client. ** ** HACK ALERT: the current lgeGrabAllWindowEvents is somewhat of a hack. It ** was done because there is no method in the standard X11 protocol for ** directing all events to a particular client. The main reason why this ** is necessary in LG3D is because there are problems in the Display Server ** with Java AWT. The first problem is that X display connections in multiple ** threads don't work properly (or, at least, we couldn't get it to work). ** The second is that eventually AWT needs to be upgraded to handle extension ** events such as DamageNotify and CursorImageNotify. There wasn't time to do ** this, so we opted to use lgeGrabAllWindowEvents to keep events from going ** to AWT at all. */ int lgeTryClientEvents (ClientPtr client, xEvent *pEvents, int count, Mask mask, Mask filter, GrabPtr grab) { int status = 1; int i; if (!lgeGrabAllWindowEvents.active) { return TryClientEvents (client, pEvents, count, mask, filter, grab); } for (i = 0; i < count; i++) { Window win; int destination; destination = lgeDSCaresAboutEvent (pEvents, &win); if (destination != SEND_TO_NORMAL_CLIENT && win == lgeGrabAllWindowEvents.window) { /* ** Send events to grabbing client client. Use a null grab pointer ** in order to sure that the event isn't eaten by any grabs; we want ** all input events to get to be sent to the all-grab client. */ status = TryClientEvents (lgeGrabAllWindowEvents.pClient, pEvents, 1, mask, filter, NULL); /*ErrorF("Sent to allgrab client, type = %d\n", pEvents->u.u.type);*/ if (destination == SEND_TO_BOTH_CLIENTS) { status = TryClientEvents (client, pEvents, 1, mask, filter, grab); } } else { /* Send events to normal destination client only*/ status = TryClientEvents (client, pEvents, 1, mask, filter, grab); } pEvents++; } return status; } #endif /* LG3D */ void EnqueueEvent(xE, device, count) xEvent *xE; DeviceIntPtr device; int count; { register QdEventPtr tail = *syncEvents.pendtail; register QdEventPtr qe; xEvent *qxE; NoticeTime(xE); #ifdef XKB /* Fix for key repeating bug. */ if (device->key != NULL && device->key->xkbInfo != NULL && xE->u.u.type == KeyRelease) AccessXCancelRepeatKey(device->key->xkbInfo, xE->u.u.detail); #endif if (DeviceEventCallback) { DeviceEventInfoRec eventinfo; /* The RECORD spec says that the root window field of motion events * must be valid. At this point, it hasn't been filled in yet, so * we do it here. The long expression below is necessary to get * the current root window; the apparently reasonable alternative * GetCurrentRootWindow()->drawable.id doesn't give you the right * answer on the first motion event after a screen change because * the data that GetCurrentRootWindow relies on hasn't been * updated yet. */ if (xE->u.u.type == MotionNotify) XE_KBPTR.root = WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id; eventinfo.events = xE; eventinfo.count = count; CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); } if (xE->u.u.type == MotionNotify) { #ifdef PANORAMIX if(!noPanoramiXExtension) { XE_KBPTR.rootX += panoramiXdataPtr[sprite.screen->myNum].x - panoramiXdataPtr[0].x; XE_KBPTR.rootY += panoramiXdataPtr[sprite.screen->myNum].y - panoramiXdataPtr[0].y; } #endif sprite.hotPhys.x = XE_KBPTR.rootX; sprite.hotPhys.y = XE_KBPTR.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; tail->event->u.keyButtonPointer.time = XE_KBPTR.time; tail->months = currentTime.months; 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(void) { register QdEventPtr *prev, qe; register DeviceIntPtr dev; prev = &syncEvents.pending; while ( (qe = *prev) ) { if (!qe->device->sync.frozen) { *prev = qe->next; if (*syncEvents.pendtail == *prev) 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; #ifdef PANORAMIX /* Translate back to the sprite screen since processInputProc will translate from sprite screen to screen 0 upon reentry to the DIX layer */ if(!noPanoramiXExtension) { qe->event->u.keyButtonPointer.rootX += panoramiXdataPtr[0].x - panoramiXdataPtr[sprite.screen->myNum].x; qe->event->u.keyButtonPointer.rootY += panoramiXdataPtr[0].y - panoramiXdataPtr[sprite.screen->myNum].y; } #endif (*qe->device->public.processInputProc)(qe->event, qe->device, qe->evcount); xfree(qe); for (dev = inputInfo.devices; dev && dev->sync.frozen; dev = dev->next) ; if (!dev) 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(register DeviceIntPtr dev, Bool frozen) { dev->sync.frozen = frozen; if (frozen) dev->public.processInputProc = dev->public.enqueueInputProc; 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_KBPTR.rootX, XE_KBPTR.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, TRUE); } else ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], TRUE, FALSE); PostNewCursor(); } #ifdef RANDR void ScreenRestructured (ScreenPtr pScreen) { GrabPtr grab; 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, TRUE); } else ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], TRUE, FALSE); } #endif 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, TRUE); } 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, FALSE); PostNewCursor(); if (grab->cursor) FreeCursor(grab->cursor, (Cursor)0); ComputeFreezes(); } void ActivateKeyboardGrab(keybd, grab, time, passive) register DeviceIntPtr keybd; GrabPtr grab; TimeStamp time; Bool passive; { WindowPtr oldWin; if (keybd->grab) oldWin = keybd->grab->window; else if (keybd->focus) oldWin = keybd->focus->win; else oldWin = sprite.win; if (oldWin == FollowKeyboardWin) oldWin = inputInfo.keyboard->focus->win; if (keybd->valuator) keybd->valuator->motionHintWindow = NullWindow; 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; register WindowPtr focusWin = keybd->focus ? keybd->focus->win : sprite.win; if (focusWin == FollowKeyboardWin) focusWin = inputInfo.keyboard->focus->win; if (keybd->valuator) keybd->valuator->motionHintWindow = NullWindow; 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, focusWin, 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 (!dev->sync.other || !SameClient(dev->sync.other, client)) 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; if (dev->sync.other && SameClient(dev->sync.other, client)) 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; if (dev->sync.other && SameClient(dev->sync.other, client)) dev->sync.other = NullGrab; } ComputeFreezes(); } break; case NOT_GRABBED: /* Replay */ if (thisGrabbed && thisDev->sync.state == FROZEN_WITH_EVENT) { if (thisSynced) thisDev->sync.other = NullGrab; 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; if (dev->sync.other && SameClient(dev->sync.other, client)) 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; Bool done; /* XXX CloseDownClient should remove passive grabs before * releasing active grabs. */ do { done = TRUE; for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->grab && SameClient(dev->grab, client)) { (*dev->DeactivateGrab)(dev); done = FALSE; } } } while (!done); } /************************************************************************** * 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"); fprintf(stderr,"motionHintWindow == keyButtonPointer.event\n"); #endif return 1; /* don't send, but pretend we did */ } pEvents->u.u.detail = NotifyHint; } else { pEvents->u.u.detail = NotifyNormal; } } #ifdef XINPUT else { if ((type == DeviceMotionNotify) && MaybeSendDeviceMotionNotifyHint ((deviceKeyButtonPointer*)pEvents, mask) != 0) return 1; } #endif 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)) { #ifdef SMART_SCHEDULE if (client->smart_priority < SMART_MAX_PRIORITY) client->smart_priority++; #endif 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 = 0; /* 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; #ifdef LG3D if ( (attempt = lgeTryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, grab)) ) #else if ( (attempt = TryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, grab)) ) #endif /* LG3D */ { 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) { #ifdef LG3D if ( (attempt = lgeTryClientEvents(rClient(other), pEvents, count, other->mask[mskidx], filter, grab)) ) #else if ( (attempt = TryClientEvents(rClient(other), pEvents, count, other->mask[mskidx], filter, grab)) ) #endif /* LG3D */ { 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; #ifdef XINPUT else { if (((type == DeviceMotionNotify) #ifdef XKB || (type == DeviceButtonPress) #endif ) && deliveries) CheckDeviceGrabAndHintWindow (pWin, type, (deviceKeyButtonPointer*) pEvents, grab, client, deliveryMask); } #endif 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. */ #ifdef PANORAMIX static int XineramaTryClientEventsResult( ClientPtr client, GrabPtr grab, Mask mask, Mask filter ){ if ((client) && (client != serverClient) && (!client->clientGone) && ((filter == CantBeFiltered) || (mask & filter))) { if (grab && !SameClient(grab, client)) return -1; else return 1; } return 0; } #endif 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; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return XineramaTryClientEventsResult( wClient(pWin), NullGrab, pWin->eventMask, filter); #endif #ifdef LG3D return lgeTryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, NullGrab); #else return TryClientEvents(wClient(pWin), pEvents, count, pWin->eventMask, filter, NullGrab); #endif /* LG3D */ } for (other = wOtherClients(pWin); other; other = other->next) { if (other->mask & filter) { if (SameClient(other, dontClient)) return 0; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return XineramaTryClientEventsResult( rClient(other), NullGrab, other->mask, filter); #endif #ifdef LG3D return lgeTryClientEvents(rClient(other), pEvents, count, other->mask, filter, NullGrab); #else return TryClientEvents(rClient(other), pEvents, count, other->mask, filter, NullGrab); #endif /* LG3D */ } } return 2; } #ifdef LG3D /* ** Returns true if the event type is one which was generated ** by an input device. These are the only types of events ** which been sent to the Display Server so they are the only ** types of events which have the event field already set. ** ** TODO: this macro does not yet support XINPUT devices. */ #define EVENT_IS_DEVICE_EVENT(e) \ ((e)->u.u.type == KeyPress || \ (e)->u.u.type == KeyRelease || \ (e)->u.u.type == ButtonPress || \ (e)->u.u.type == ButtonRelease || \ (e)->u.u.type == MotionNotify) /* Returns True if the event occurred above a 3D object rather than a native window */ #define EVENT_IS_3D(e) \ (EVENT_IS_DEVICE_EVENT(e) && (e)->u.keyButtonPointer.event == lgeDisplayServerPRW) /* TODO: it's not clear whether this routine deals with grabs properly. Must handle the following cases: 2D event grabbed and forced to go to 2D win 2D event grabbed and forced to go to 3D win 3D event grabbed and forced to go to 2D win 3D event grabbed and forced to go to 3D win */ static void lgeFixUpEventFromWindow( xEvent *xE, WindowPtr pWin, Window child, Bool calcChild) { Window eventWindowOld = INVALID; /* ErrorF("Enter FixUpEventFromWindow, event type = %d\n", xE->u.u.type); if (EVENT_IS_3D(xE)) { ErrorF("Event is 3D\n"); } else { ErrorF("Event is 2D\n"); } ErrorF("old event window = %d\n", XE_KBPTR.event); ErrorF("old child window = %d\n", XE_KBPTR.child); ErrorF("old eventxy = %d, %d\n", XE_KBPTR.eventX, XE_KBPTR.eventY); */ /* TODO: This is merely an optimization; it is no longer functionally necessary */ if (EVENT_IS_3D(xE)) { calcChild = False; } if (calcChild) { /*ErrorF("Calculating child\n");*/ 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_KBPTR.root = ROOT->drawable.id; /* Set event field (only for non-3D events) */ if (!EVENT_IS_3D(xE)) { eventWindowOld = XE_KBPTR.event; XE_KBPTR.event = pWin->drawable.id; /*ErrorF("new event window = %d\n", XE_KBPTR.event);*/ } if (sprite.hot.pScreen != pWin->drawable.pScreen) { XE_KBPTR.sameScreen = xFalse; XE_KBPTR.child = None; XE_KBPTR.eventX = 0; XE_KBPTR.eventY = 0; return; } XE_KBPTR.sameScreen = xTrue; /* Set various fields (only for non-3D events) */ if (!EVENT_IS_3D(xE)) { XE_KBPTR.child = child; /*ErrorF("new child window = %d\n", XE_KBPTR.child);*/ /* ** The only events needing fixup at this point are mouse events ** where the event window has been changed. */ if ((xE->u.u.type == ButtonPress || xE->u.u.type == ButtonRelease || xE->u.u.type == MotionNotify) && eventWindowOld != XE_KBPTR.event) { /* TODO: it would be good to avoid a resource lookup here. Some sort of caching might optimize this */ WindowPtr pOuterWin = (WindowPtr) LookupIDByType(eventWindowOld, RT_WINDOW); if (pOuterWin == NULL) { /* ** This can happen if the window has died since the pick on the window ** occurred. So we don't need to be verbose about it. ErrorF("Error: FixupEventFromWindow: outer window %d, not found. No XY fix up occuring.\n", eventWindowOld); */ } else { /* ** Make the event coords relative to the destination window ** instead of relative to the outer window. */ XE_KBPTR.eventX -= pWin->drawable.x - pOuterWin->drawable.x; XE_KBPTR.eventY -= pWin->drawable.y - pOuterWin->drawable.y; /*ErrorF("new eventxy = %d, %d", XE_KBPTR.eventX, XE_KBPTR.eventY);*/ } } } } #endif /* LG3D */ static void FixUpEventFromWindow( xEvent *xE, WindowPtr pWin, Window child, Bool calcChild) { #ifdef LG3D if (lgeDisplayServerIsAlive) { lgeFixUpEventFromWindow(xE, pWin, child, calcChild); return; } #endif /* LG3D */ 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_KBPTR.root = ROOT->drawable.id; XE_KBPTR.event = pWin->drawable.id; if (sprite.hot.pScreen == pWin->drawable.pScreen) { XE_KBPTR.sameScreen = xTrue; XE_KBPTR.child = child; XE_KBPTR.eventX = XE_KBPTR.rootX - pWin->drawable.x; XE_KBPTR.eventY = XE_KBPTR.rootY - pWin->drawable.y; } else { XE_KBPTR.sameScreen = xFalse; XE_KBPTR.child = None; XE_KBPTR.eventX = 0; XE_KBPTR.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) { if (inputMasks && (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) || #ifdef LG3D /* ** Stop propogating when the parent of the window is the PRW. ** This prevents events that are not caught by any X11 window from ** being sent back to the the Display Server, because the DS can ** misinterpret these. ** TODO: we need to decide if a server change is the best way to ** deal with this problem, or whether the DS or WM can do something ** about it. */ (lgeDisplayServerIsAlive && pWin->parent->drawable.id == lgeDisplayServerPRW) || #endif /* LG3D */ (inputMasks && (filter & inputMasks->dontPropagateMask[mskidx]))) return 0; child = pWin->drawable.id; pWin = pWin->parent; if (pWin) 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) || #ifdef LG3D /* See comment above */ (lgeDisplayServerIsAlive && pWin->parent->drawable.id == lgeDisplayServerPRW) || #endif /* LG3D */ (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; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return count; #endif 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; } #ifdef LG3D Bool #else static Bool #endif /* LG3D */ PointInBorderSize(WindowPtr pWin, int x, int y) { BoxRec box; if(POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderSize, x, y, &box)) return TRUE; #ifdef PANORAMIX if(!noPanoramiXExtension && XineramaSetWindowPntrs(pWin)) { int i; for(i = 1; i < PanoramiXNumScreens; i++) { if(POINT_IN_REGION(sprite.screen, &sprite.windows[i]->borderSize, x + panoramiXdataPtr[0].x - panoramiXdataPtr[i].x, y + panoramiXdataPtr[0].y - panoramiXdataPtr[i].y, &box)) return TRUE; } } #endif return FALSE; } static WindowPtr XYToWindow(int x, int y) { register WindowPtr pWin; 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) || PointInBorderSize(pWin, x, y)) #endif ) { if (spriteTraceGood >= spriteTraceSize) { spriteTraceSize += 10; Must_have_memory = TRUE; /* XXX */ spriteTrace = (WindowPtr *)xrealloc( spriteTrace, spriteTraceSize*sizeof(WindowPtr)); Must_have_memory = FALSE; /* XXX */ } spriteTrace[spriteTraceGood++] = pWin; pWin = pWin->firstChild; } else pWin = pWin->nextSib; } return spriteTrace[spriteTraceGood-1]; } static Bool CheckMotion(xEvent *xE) { WindowPtr prevSpriteWin = sprite.win; #ifdef PANORAMIX if(!noPanoramiXExtension) return XineramaCheckMotion(xE); #endif 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_KBPTR.rootX; sprite.hot.y = XE_KBPTR.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_KBPTR.rootX) || (sprite.hotPhys.y != XE_KBPTR.rootY)) { (*sprite.hotPhys.pScreen->SetCursorPosition)( sprite.hotPhys.pScreen, sprite.hotPhys.x, sprite.hotPhys.y, FALSE); } XE_KBPTR.rootX = sprite.hot.x; XE_KBPTR.rootY = sprite.hot.y; } #ifdef LG3D if (lgeDisplayServerIsAlive) { if (xE == NULL) { /* WindowsRestructured case */ /* TODO: this may change */ sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); virtualSprite.hot.x = sprite.hot.x - sprite.win->drawable.x; virtualSprite.hot.y = sprite.hot.y - sprite.win->drawable.y; } else if (XE_KBPTR.event == lgeDisplayServerPRW) { /* 3D Event */ sprite.win = pLgeDisplayServerPRWWin; virtualSprite.hot.x = sprite.hot.x; virtualSprite.hot.y = sprite.hot.y; } else { /* Normal X Event */ WindowPtr pEventWin = (WindowPtr) LookupIDByType(XE_KBPTR.event, RT_WINDOW); if (pEventWin == NULL) { /* This might happen if the window has been destroyed */ sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); virtualSprite.hot.x = sprite.hot.x - sprite.win->drawable.x; virtualSprite.hot.y = sprite.hot.y - sprite.win->drawable.y; return TRUE; } sprite.win = XYToSubWindow(pEventWin, XE_KBPTR.eventX, XE_KBPTR.eventY, &virtualSprite.hot.x, &virtualSprite.hot.y); } virtualSprite.win = sprite.win; } else { sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); } #else sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); #endif /* LG3D */ #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; } void WindowsRestructured() { (void) CheckMotion((xEvent *)NULL); #ifdef xLG3D /* ** ** Bug: this code doesn't currently work. It messes up the sprite window. ** Test case: freecell: click New button. Cursor jumps to upper left hand ** corner because the button ends up getting sent to the DS! */ /* ** In addition, we need to send a synthetic motion event with the ** last physical sprite position to the Display Server so that it ** will notice that something has changed and recompute the current ** pointer window. ** ** Note: we cannot just skip the above call to CheckMotion and ** send this synthetic event alone. We must call CheckMotion(NULL) ** in order to the current sprite window to a valid window. Otherwise ** when the synthetic event comes back to us the prevSpriteWindow ** may still point to an invalid window and this will crash the server! */ xEvent xE; xE.u.u.type = MotionNotify; xE.u.keyButtonPointer.event = lgeDisplayServerPRW; xE.u.keyButtonPointer.rootX = sprite.hot.x; xE.u.keyButtonPointer.rootY = sprite.hot.y; xE.u.keyButtonPointer.time = GetTimeInMillis(); (*inputInfo.pointer->public.processInputProc)(&xE, inputInfo.pointer, 1); #endif /* LG3D */ } #ifdef PANORAMIX /* This was added to support reconfiguration under Xdmx. The problem is * that if the 0th screen (i.e., WindowTable[0]) is moved to an origin * other than 0,0, the information in the private sprite structure must * be updated accordingly, or XYToWindow (and other routines) will not * compute correctly. */ void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) { ScreenPtr pScreen = win->drawable.pScreen; GrabPtr grab; if (noPanoramiXExtension) return; sprite.hot.x -= xoff; sprite.hot.y -= yoff; sprite.hotPhys.x -= xoff; sprite.hotPhys.y -= yoff; sprite.hotLimits.x1 -= xoff; sprite.hotLimits.y1 -= yoff; sprite.hotLimits.x2 -= xoff; sprite.hotLimits.y2 -= yoff; if (REGION_NOTEMPTY(sprite.screen, &sprite.Reg1)) REGION_TRANSLATE(sprite.screen, &sprite.Reg1, xoff, yoff); if (REGION_NOTEMPTY(sprite.screen, &sprite.Reg2)) REGION_TRANSLATE(sprite.screen, &sprite.Reg2, xoff, yoff); /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ 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, TRUE); } else ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], TRUE, FALSE); } #endif 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); sprite.confined = FALSE; (*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits); (*pScreen->SetCursorPosition) (pScreen, sprite.hot.x, sprite.hot.y, FALSE); (*pScreen->DisplayCursor) (pScreen, sprite.current); #ifdef PANORAMIX if(!noPanoramiXExtension) { sprite.hotLimits.x1 = -panoramiXdataPtr[0].x; sprite.hotLimits.y1 = -panoramiXdataPtr[0].y; sprite.hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; sprite.hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; sprite.physLimits = sprite.hotLimits; sprite.confineWin = NullWindow; #ifdef SHAPE sprite.hotShape = NullRegion; #endif sprite.screen = pScreen; /* gotta UNINIT these someplace */ REGION_NULL(pScreen, &sprite.Reg1); REGION_NULL(pScreen, &sprite.Reg2); } #endif } /* * 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; #ifdef PANORAMIX if(!noPanoramiXExtension) { sprite.hotPhys.x += panoramiXdataPtr[newScreen->myNum].x - panoramiXdataPtr[0].x; sprite.hotPhys.y += panoramiXdataPtr[newScreen->myNum].y - panoramiXdataPtr[0].y; if (newScreen != sprite.screen) { sprite.screen = newScreen; /* Make sure we tell the DDX to update its copy of the screen */ if(sprite.confineWin) XineramaConfineCursorToWindow(sprite.confineWin, TRUE); else XineramaConfineCursorToWindow(WindowTable[0], TRUE); /* if the pointer wasn't confined, the DDX won't get told of the pointer warp so we reposition it here */ if(!syncEvents.playingEvents) (*sprite.screen->SetCursorPosition)(sprite.screen, sprite.hotPhys.x + panoramiXdataPtr[0].x - panoramiXdataPtr[sprite.screen->myNum].x, sprite.hotPhys.y + panoramiXdataPtr[0].y - panoramiXdataPtr[sprite.screen->myNum].y, FALSE); } } else #endif if (newScreen != sprite.hotPhys.pScreen) ConfineCursorToWindow(WindowTable[newScreen->myNum], TRUE, FALSE); } #ifdef PANORAMIX static Bool XineramaPointInWindowIsVisible( WindowPtr pWin, int x, int y ) { ScreenPtr pScreen = pWin->drawable.pScreen; BoxRec box; int i, xoff, yoff; if (!pWin->realized) return FALSE; if (POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box)) return TRUE; if(!XineramaSetWindowPntrs(pWin)) return FALSE; xoff = x + panoramiXdataPtr[0].x; yoff = y + panoramiXdataPtr[0].y; for(i = 1; i < PanoramiXNumScreens; i++) { pWin = sprite.windows[i]; pScreen = pWin->drawable.pScreen; x = xoff - panoramiXdataPtr[i].x; y = yoff - panoramiXdataPtr[i].y; if(POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box)) return TRUE; } return FALSE; } static int XineramaWarpPointer(ClientPtr client) { WindowPtr dest = NULL; int x, y; REQUEST(xWarpPointerReq); if (stuff->dstWid != None) { dest = SecurityLookupWindow(stuff->dstWid, client, SecurityReadAccess); if (!dest) return BadWindow; } x = sprite.hotPhys.x; y = sprite.hotPhys.y; if (stuff->srcWid != None) { int winX, winY; XID winID = stuff->srcWid; WindowPtr source; source = SecurityLookupWindow(winID, client, SecurityReadAccess); if (!source) return BadWindow; winX = source->drawable.x; winY = source->drawable.y; if(source == WindowTable[0]) { winX -= panoramiXdataPtr[0].x; winY -= panoramiXdataPtr[0].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) || !XineramaPointInWindowIsVisible(source, x, y)) return Success; } if (dest) { x = dest->drawable.x; y = dest->drawable.y; if(dest == WindowTable[0]) { x -= panoramiXdataPtr[0].x; y -= panoramiXdataPtr[0].y; } } x += stuff->dstX; y += stuff->dstY; 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; if (sprite.hotShape) ConfineToShape(sprite.hotShape, &x, &y); XineramaSetCursorPosition(x, y, TRUE); return Success; } #endif int ProcWarpPointer(client) ClientPtr client; { WindowPtr dest = NULL; int x, y; ScreenPtr newScreen; REQUEST(xWarpPointerReq); REQUEST_SIZE_MATCH(xWarpPointerReq); #ifdef PANORAMIX if(!noPanoramiXExtension) return XineramaWarpPointer(client); #endif if (stuff->dstWid != None) { dest = SecurityLookupWindow(stuff->dstWid, client, SecurityReadAccess); if (!dest) return BadWindow; } x = sprite.hotPhys.x; y = sprite.hotPhys.y; if (stuff->srcWid != None) { int winX, winY; XID winID = stuff->srcWid; WindowPtr source; source = SecurityLookupWindow(winID, client, SecurityReadAccess); if (!source) return BadWindow; winX = source->drawable.x; winY = source->drawable.y; if (source->drawable.pScreen != sprite.hotPhys.pScreen || 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; #if defined(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; } static Bool BorderSizeNotEmpty(WindowPtr pWin) { if(REGION_NOTEMPTY(sprite.hotPhys.pScreen, &pWin->borderSize)) return TRUE; #ifdef PANORAMIX if(!noPanoramiXExtension && XineramaSetWindowPntrs(pWin)) { int i; for(i = 1; i < PanoramiXNumScreens; i++) { if(REGION_NOTEMPTY(sprite.screen, &sprite.windows[i]->borderSize)) return TRUE; } } #endif return FALSE; } /* "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a passive grab set on the window to be activated. */ static Bool CheckPassiveGrabsOnWindow( 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) { #ifdef XKB DeviceIntPtr gdev; XkbSrvInfoPtr xkbi; gdev= grab->modifierDevice; xkbi= gdev->key->xkbInfo; #endif tempGrab.modifierDevice = grab->modifierDevice; if ((device == grab->modifierDevice) && ((xE->u.u.type == KeyPress) #if defined(XINPUT) && defined(XKB) || (xE->u.u.type == DeviceKeyPress) #endif )) tempGrab.modifiersDetail.exact = #ifdef XKB (noXkbExtension?gdev->key->prev_state:xkbi->state.grab_mods); #else grab->modifierDevice->key->prev_state; #endif else tempGrab.modifiersDetail.exact = #ifdef XKB (noXkbExtension ? gdev->key->state : xkbi->state.grab_mods); #else grab->modifierDevice->key->state; #endif if (GrabMatchesSecond(&tempGrab, grab) && (!grab->confineTo || (grab->confineTo->realized && BorderSizeNotEmpty(grab->confineTo)))) { #ifdef XCSECURITY if (!SecurityCheckDeviceAccess(wClient(pWin), device, FALSE)) return FALSE; #endif #ifdef XKB if (!noXkbExtension) { XE_KBPTR.state &= 0x1f00; XE_KBPTR.state |= tempGrab.modifiersDetail.exact&(~0x1f00); } #endif (*device->ActivateGrab)(device, grab, currentTime, TRUE); FixUpEventFromWindow(xE, grab->window, None, TRUE); #ifdef LG3D (void) lgeTryClientEvents(rClient(grab), xE, count, filters[xE->u.u.type], filters[xE->u.u.type], grab); #else (void) TryClientEvents(rClient(grab), xE, count, filters[xE->u.u.type], filters[xE->u.u.type], grab); #endif /* LG3D */ if (device->sync.state == FROZEN_NO_EVENT) { if (device->sync.evcount < count) { Must_have_memory = TRUE; /* XXX */ device->sync.event = (xEvent *)xrealloc(device->sync.event, count* sizeof(xEvent)); Must_have_memory = FALSE; /* XXX */ } 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 = NULL; register FocusClassPtr focus = device->focus; if (((xE->u.u.type == ButtonPress) #if defined(XINPUT) && defined(XKB) || (xE->u.u.type == DeviceButtonPress) #endif ) && (device->button->buttonsDown != 1)) return FALSE; 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 > checkFirst) && (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; int mskidx = 0; 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); if (xE->u.u.type & EXTENSION_EVENT_BASE) mskidx = keybd->id; (void)DeliverEventsToWindow(focus, xE, count, filters[xE->u.u.type], NullGrab, mskidx); } 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); #ifdef LG3D deliveries = lgeTryClientEvents(rClient(grab), xE, count, (Mask)grab->eventMask, filters[xE->u.u.type], grab); #else deliveries = TryClientEvents(rClient(grab), xE, count, (Mask)grab->eventMask, filters[xE->u.u.type], grab); #endif /* LG3D */ if (deliveries && (xE->u.u.type == MotionNotify #ifdef XINPUT || xE->u.u.type == DeviceMotionNotify #endif )) thisDev->valuator->motionHintWindow = grab->window; } if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify #ifdef XINPUT && xE->u.u.type != DeviceMotionNotify #endif )) 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); if (thisDev->sync.evcount < count) { Must_have_memory = TRUE; /* XXX */ thisDev->sync.event = (xEvent *)xrealloc(thisDev->sync.event, count*sizeof(xEvent)); Must_have_memory = FALSE; /* XXX */ } thisDev->sync.evcount = count; for (dxE = thisDev->sync.event; --count >= 0; dxE++, xE++) *dxE = *xE; break; } } void #ifdef XKB CoreProcessKeyboardEvent (xE, keybd, count) #else ProcessKeyboardEvent (xE, keybd, count) #endif 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; #ifdef XEVIE static Window rootWin = 0; if(!xeviegrabState && xevieFlag && clients[xevieClientIndex] && (xevieMask & xevieFilters[xE->u.u.type])) { key = xE->u.u.detail; kptr = &keyc->down[key >> 3]; bit = 1 << (key & 7); if((xE->u.u.type == KeyPress && (*kptr & bit)) || (xE->u.u.type == KeyRelease && !(*kptr & bit))) {} else { #ifdef XKB if(!noXkbExtension) xevieKBEventSent = 0; #endif if(!xevieKBEventSent) { xeviekb = keybd; if(!rootWin) { #ifdef LG3D /* TEMP Workaround */ WindowPtr pWin; if (lgeDisplayServerIsAlive) { xeviewin = pLgeDisplayServerPRWWin; } pWin = xeviewin->parent; #else WindowPtr pWin = xeviewin->parent; #endif /* LG3D */ while(pWin) { if(!pWin->parent) { rootWin = pWin->drawable.id; break; } pWin = pWin->parent; }; } xE->u.keyButtonPointer.event = xeviewin->drawable.id; xE->u.keyButtonPointer.root = rootWin; xE->u.keyButtonPointer.child = (xeviewin->firstChild) ? xeviewin->firstChild-> drawable.id:0; xE->u.keyButtonPointer.rootX = xeviehot.x; xE->u.keyButtonPointer.rootY = xeviehot.y; xE->u.keyButtonPointer.state = keyc->state; WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE); #ifdef XKB if(noXkbExtension) #endif return; }else { xevieKBEventSent = 0; } } } #endif if (!syncEvents.playingEvents) { NoticeTime(xE); if (DeviceEventCallback) { DeviceEventInfoRec eventinfo; eventinfo.events = xE; eventinfo.count = count; CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); } } XE_KBPTR.state = (keyc->state | inputInfo.pointer->button->state); XE_KBPTR.rootX = sprite.hot.x; XE_KBPTR.rootY = sprite.hot.y; key = xE->u.u.detail; kptr = &keyc->down[key >> 3]; bit = 1 << (key & 7); modifiers = keyc->modifierMap[key]; #ifdef DEBUG if ((xkbDebugFlags&0x4)&& ((xE->u.u.type==KeyPress)||(xE->u.u.type==KeyRelease))) { ErrorF("CoreProcessKbdEvent: Key %d %s\n",key, (xE->u.u.type==KeyPress?"down":"up")); } #endif switch (xE->u.u.type) { case KeyPress: if (*kptr & bit) /* allow ddx to generate multiple downs */ { if (!modifiers) { xE->u.u.type = KeyRelease; (*keybd->public.processInputProc)(xE, keybd, count); xE->u.u.type = KeyPress; /* release can have side effects, don't fall through */ (*keybd->public.processInputProc)(xE, keybd, count); } return; } inputInfo.pointer->valuator->motionHintWindow = NullWindow; *kptr |= bit; keyc->prev_state = keyc->state; 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; keyc->prev_state = keyc->state; 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); } #ifdef XKB /* This function is used to set the key pressed or key released state - this is only used when the pressing of keys does not cause CoreProcessKeyEvent to be called, as in for example Mouse Keys. */ void FixKeyState (xE, keybd) register xEvent *xE; register DeviceIntPtr keybd; { int key, bit; register BYTE *kptr; register KeyClassPtr keyc = keybd->key; key = xE->u.u.detail; kptr = &keyc->down[key >> 3]; bit = 1 << (key & 7); #ifdef DEBUG if ((xkbDebugFlags&0x4)&& ((xE->u.u.type==KeyPress)||(xE->u.u.type==KeyRelease))) { ErrorF("FixKeyState: Key %d %s\n",key, (xE->u.u.type==KeyPress?"down":"up")); } #endif switch (xE->u.u.type) { case KeyPress: *kptr |= bit; break; case KeyRelease: *kptr &= ~bit; break; default: FatalError("Impossible keyboard event"); } } #endif #if defined(LG3D_EVENT_TEST_LATENCY) || defined(LG3D_EVENT_TEST_THROUGHPUT) #include static int lg3dEventTestActive = 0; static struct timeval lg3dEventTestStartTV; #endif /* LG3D_EVENT_TEST_LATENCY || LG3D_EVENT_TEST_THROUGHPUT */ #ifdef LG3D_EVENT_TEST_LATENCY #include "statbuf.h" static StatBuf *lg3dEventTestSb = NULL; #endif /* LG3D_EVENT_TEST_LATENCY */ #ifdef LG3D_EVENT_TEST_THROUGHPUT static int lg3dEventTestReceived = 0; static int lg3dEventTestCount = 10000; #endif /* LG3D_EVENT_TEST_THROUGHPUT */ void #ifdef XKB CoreProcessPointerEvent (xE, mouse, count) #else ProcessPointerEvent (xE, mouse, count) #endif register xEvent *xE; register DeviceIntPtr mouse; int count; { register GrabPtr grab = mouse->grab; Bool deactivateGrab = FALSE; register ButtonClassPtr butc = mouse->button; #ifdef XKB XkbSrvInfoPtr xkbi= inputInfo.keyboard->key->xkbInfo; #endif #ifdef XEVIE if(xevieFlag && clients[xevieClientIndex] && !xeviegrabState && (xevieMask & xevieFilters[xE->u.u.type])) { if(xevieEventSent) xevieEventSent = 0; else { xeviemouse = mouse; #ifdef LG3D_EVENT_TEST_LATENCY /* For latency timing: send */ if (xE->u.u.type == ButtonPress) { ErrorF("Start Test\n"); if (lg3dEventTestSb == NULL) { lg3dEventTestSb = statBufCreate(); if (lg3dEventTestSb == NULL) { FatalError("LG3D Event Test: cannot create integer statistics buffer\n"); } } lg3dEventTestActive = 1; gettimeofday(&lg3dEventTestStartTV, 0); /*ErrorF("Start: sec = %d, usec = %d\n", lg3dEventTestStartTV.tv_sec, lg3dEventTestStartTV.tv_usec);*/ } if (lg3dEventTestActive) { struct timeval tv; int deltaSecs; gettimeofday(&tv, 0); deltaSecs = tv.tv_sec - lg3dEventTestStartTV.tv_sec; /*ErrorF("Send: deltaSecs = %d, usec = %d\n", deltaSecs, tv.tv_usec);*/ xE->u.keyButtonPointer.time = deltaSecs; xE->u.keyButtonPointer.child = tv.tv_usec; } #endif /* LG3D_EVENT_TEST_LATENCY */ #ifdef LG3D_EVENT_TEST_THROUGHPUT /* For throughput timing */ if (xE->u.u.type == ButtonPress) { int i; ErrorF("Start Test\n"); lg3dEventTestActive = 1; lg3dEventTestReceived = 0; gettimeofday(&lg3dEventTestStartTV, 0); for (i = 1; i <= lg3dEventTestCount; i++) { /*ErrorF("Sending event %d\n", i);*/ WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE); } } else #endif /* LG3D_EVENT_TEST_THROUGHPUT */ WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE); return; } } #endif #ifdef LG3D_EVENT_TEST_LATENCY /* For latency timing: receive */ if (lg3dEventTestActive) { struct timeval tv; int deltaSecs, deltaUsecs; float msecs; gettimeofday(&tv, 0); /*ErrorF("Receive: sec = %d, usec = %d\n", tv.tv_sec, tv.tv_usec);*/ tv.tv_sec -= lg3dEventTestStartTV.tv_sec; /* ErrorF("Receive: deltaSecs = %d, usec = %d\n", tv.tv_sec, tv.tv_usec); ErrorF("Receive: ev->time = %d, ev->child = %d\n", xE->u.keyButtonPointer.time, xE->u.keyButtonPointer.child); */ deltaSecs = tv.tv_sec - xE->u.keyButtonPointer.time; deltaUsecs = tv.tv_usec - xE->u.keyButtonPointer.child; /* ErrorF("Interval: deltaSecs = %d, deltaUsec = %d\n", deltaSecs, deltaUsecs); */ msecs = 1000.0f * deltaSecs + deltaUsecs / 1000.0f; /*ErrorF("Interval: msecs = %f\n", msecs);*/ statBufAdd(lg3dEventTestSb, msecs); /* Discard event to avoid the additional computational load of further processing */ return; } #endif /* LG3D_EVENT_TEST_LATENCY */ #ifdef LG3D_EVENT_TEST_THROUGHPUT if (lg3dEventTestActive) { lg3dEventTestReceived++; /*ErrorF("Received event %d\n", lg3dEventTestReceived);*/ if (lg3dEventTestReceived == lg3dEventTestCount) { struct timeval stopTV; gettimeofday(&stopTV, 0); int deltaSecs = stopTV.tv_sec - lg3dEventTestStartTV.tv_sec; int deltaUsecs = stopTV.tv_usec - lg3dEventTestStartTV.tv_usec; float msecs = deltaSecs * 1000.0f + deltaUsecs / 1000.0f; float msecsPerEvent = msecs / (float)lg3dEventTestCount; ErrorF("LG3D Event Test: %d events in %f ms (%f ms/event)\n", lg3dEventTestCount, msecs, msecsPerEvent); lg3dEventTestActive = 0; } } #endif /* LG3D_EVENT_TEST_THROUGHPUT */ if (!syncEvents.playingEvents) NoticeTime(xE) XE_KBPTR.state = (butc->state | ( #ifdef XKB (noXkbExtension ? inputInfo.keyboard->key->state : xkbi->state.grab_mods) #else inputInfo.keyboard->key->state #endif )); { NoticeTime(xE); if (DeviceEventCallback) { DeviceEventInfoRec eventinfo; /* see comment in EnqueueEvents regarding the next three lines */ if (xE->u.u.type == MotionNotify) XE_KBPTR.root = WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id; eventinfo.events = xE; eventinfo.count = count; CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); } } if (xE->u.u.type != MotionNotify) { register int key; register BYTE *kptr; int bit; XE_KBPTR.rootX = sprite.hot.x; XE_KBPTR.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; if (!(*kptr & bit)) butc->buttonsDown++; butc->motionMask = ButtonMotionMask; *kptr |= bit; #if !defined(XFree86Server) || !defined(XINPUT) xE->u.u.detail = butc->map[key]; #endif 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 (*kptr & bit) --butc->buttonsDown; if (!butc->buttonsDown) butc->motionMask = 0; *kptr &= ~bit; #if !defined(XFree86Server) || !defined(XINPUT) xE->u.u.detail = butc->map[key]; #endif 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) { if (pChild->optional) { pChild->optional->otherEventMasks = 0; for (others = wOtherClients(pChild); others; others = others->next) { 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(value, id) pointer value; /* must conform to DeleteType */ XID id; { register OtherClientsPtr other, prev; register WindowPtr pWin = (WindowPtr)value; 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*/ return -1; /* make compiler happy */ } 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; #ifdef SGIMISC pWin->eventMask = (mask & ~SGIMiscSpecialDestroyMask) | (pWin->eventMask & SGIMiscSpecialDestroyMask); #else pWin->eventMask = mask; #endif } else { for (others = wOtherClients (pWin); others; others = others->next) { if (SameClient(others, client)) { check = others->mask; #ifdef SGIMISC mask = (mask & ~SGIMiscSpecialDestroyMask) | (others->mask & SGIMiscSpecialDestroyMask); #endif 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( register WindowPtr a, register WindowPtr b) { for (b = b->parent; b; b = b->parent) if (IsParent(b, a)) return b; return NullWindow; } static void EnterLeaveEvent( int type, int mode, int detail, register WindowPtr pWin, Window child) { 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, FALSE); /* Enter/Leave events always set child */ event.u.enterLeave.child = child; event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? ELFlagSameScreen : 0; #ifdef XKB if (!noXkbExtension) { event.u.enterLeave.state = mouse->button->state & 0x1f00; event.u.enterLeave.state |= XkbGrabStateFromRec(&keybd->key->xkbInfo->state); } else #endif 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) #ifdef LG3D (void)lgeTryClientEvents(rClient(grab), &event, 1, mask, filters[type], grab); #else (void)TryClientEvents(rClient(grab), &event, 1, mask, filters[type], grab); #endif /* LG3D */ else (void)DeliverEventsToWindow(pWin, &event, 1, filters[type], NullGrab, 0); } if ((type == EnterNotify) && (mask & KeymapStateMask)) { xKeymapEvent ke; #ifdef XCSECURITY ClientPtr client = grab ? rClient(grab) : clients[CLIENT_ID(pWin->drawable.id)]; if (!SecurityCheckDeviceAccess(client, keybd, FALSE)) { bzero((char *)&ke.map[0], 31); } else #endif memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); ke.type = KeymapNotify; if (grab) #ifdef LG3D (void)lgeTryClientEvents(rClient(grab), (xEvent *)&ke, 1, mask, KeymapStateMask, grab); #else (void)TryClientEvents(rClient(grab), (xEvent *)&ke, 1, mask, KeymapStateMask, grab); #endif /* LG3D */ else (void)DeliverEventsToWindow(pWin, (xEvent *)&ke, 1, KeymapStateMask, NullGrab, 0); } } static void EnterNotifies(WindowPtr ancestor, WindowPtr child, int mode, int detail) { WindowPtr parent = child->parent; if (ancestor == parent) return; EnterNotifies(ancestor, parent, mode, detail); EnterLeaveEvent(EnterNotify, mode, detail, parent, child->drawable.id); } static void LeaveNotifies(WindowPtr child, WindowPtr ancestor, int mode, int detail) { register WindowPtr pWin; if (ancestor == child) return; for (pWin = child->parent; pWin != ancestor; pWin = pWin->parent) { EnterLeaveEvent(LeaveNotify, mode, detail, pWin, child->drawable.id); child = pWin; } } static void DoEnterLeaveEvents(WindowPtr fromWin, WindowPtr toWin, int mode) { if (fromWin == toWin) return; if (IsParent(fromWin, toWin)) { EnterLeaveEvent(LeaveNotify, mode, NotifyInferior, fromWin, None); EnterNotifies(fromWin, toWin, mode, NotifyVirtual); EnterLeaveEvent(EnterNotify, mode, NotifyAncestor, toWin, None); } else if (IsParent(toWin, fromWin)) { EnterLeaveEvent(LeaveNotify, mode, NotifyAncestor, fromWin, None); LeaveNotifies(fromWin, toWin, mode, NotifyVirtual); EnterLeaveEvent(EnterNotify, mode, NotifyInferior, toWin, None); } else { /* neither fromWin nor toWin is descendent of the other */ WindowPtr common = CommonAncestor(toWin, fromWin); /* common == NullWindow ==> different screens */ EnterLeaveEvent(LeaveNotify, mode, NotifyNonlinear, fromWin, None); LeaveNotifies(fromWin, common, mode, NotifyNonlinearVirtual); EnterNotifies(common, toWin, mode, NotifyNonlinearVirtual); EnterLeaveEvent(EnterNotify, mode, NotifyNonlinear, toWin, None); } } static void FocusEvent(DeviceIntPtr dev, int type, int mode, int 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; #ifdef XCSECURITY ClientPtr client = clients[CLIENT_ID(pWin->drawable.id)]; if (!SecurityCheckDeviceAccess(client, dev, FALSE)) { bzero((char *)&ke.map[0], 31); } else #endif memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); ke.type = KeymapNotify; (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( DeviceIntPtr dev, WindowPtr ancestor, WindowPtr child, WindowPtr skipChild, int mode, int 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( DeviceIntPtr dev, WindowPtr child, WindowPtr ancestor, int mode, 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 */ #ifdef PANORAMIX if ( !noPanoramiXExtension ) FocusEvent(dev, FocusOut, mode, out, WindowTable[0]); else #endif for (i=0; iparent, NullWindow, mode, NotifyNonlinearVirtual, FALSE); } /* Notify all the roots */ #ifdef PANORAMIX if ( !noPanoramiXExtension ) FocusEvent(dev, FocusIn, mode, in, WindowTable[0]); else #endif 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( ClientPtr client, DeviceIntPtr dev, Window focusID, CARD8 revertTo, Time ctime, Bool followOK) { register FocusClassPtr focus; register WindowPtr focusWin; int mode; TimeStamp time; UpdateCurrentTime(); if ((revertTo != RevertToParent) && (revertTo != RevertToPointerRoot) && (revertTo != RevertToNone) && ((revertTo != RevertToFollowKeyboard) || !followOK)) { client->errorValue = revertTo; return BadValue; } time = ClientTimeToServerTime(ctime); if ((focusID == None) || (focusID == PointerRoot)) focusWin = (WindowPtr)(long)focusID; else if ((focusID == FollowKeyboard) && followOK) focusWin = inputInfo.keyboard->focus->win; else if (!(focusWin = SecurityLookupWindow(focusID, client, SecurityReadAccess))) return BadWindow; else { /* It is a match error to try to set the input focus to an unviewable window. */ if(!focusWin->realized) return(BadMatch); } focus = dev->focus; if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, focus->time) == EARLIER)) return Success; mode = (dev->grab) ? NotifyWhileGrabbed : NotifyNormal; if (focus->win == FollowKeyboardWin) DoFocusEvents(dev, inputInfo.keyboard->focus->win, focusWin, mode); else DoFocusEvents(dev, focus->win, focusWin, mode); focus->time = time; focus->revert = revertTo; if (focusID == FollowKeyboard) focus->win = FollowKeyboardWin; else 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; Must_have_memory = TRUE; /* XXX */ focus->trace = (WindowPtr *)xrealloc(focus->trace, focus->traceSize * sizeof(WindowPtr)); Must_have_memory = FALSE; /* 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); #ifdef XCSECURITY if (!SecurityCheckDeviceAccess(client, inputInfo.keyboard, TRUE)) return Success; #endif 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; WindowPtr pWin, confineTo; CursorPtr cursor, oldCursor; 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 = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); if (!pWin) return BadWindow; if (stuff->confineTo == None) confineTo = NullWindow; else { confineTo = SecurityLookupWindow(stuff->confineTo, client, SecurityReadAccess); if (!confineTo) return BadWindow; } if (stuff->cursor == None) cursor = NullCursor; else { cursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor, RT_CURSOR, SecurityReadAccess); 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; grab = device->grab; if ((grab) && !SameClient(grab, client)) rep.status = AlreadyGrabbed; else if ((!pWin->realized) || (confineTo && !(confineTo->realized && BorderSizeNotEmpty(confineTo)))) rep.status = GrabNotViewable; else if (device->sync.frozen && device->sync.other && !SameClient(device->sync.other, client)) rep.status = GrabFrozen; else if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, device->grabTime) == EARLIER)) rep.status = GrabInvalidTime; else { GrabRec tempGrab; oldCursor = NullCursor; if (grab) { if (grab->confineTo && !confineTo) ConfineCursorToWindow(ROOT, FALSE, FALSE); oldCursor = grab->cursor; } 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 = device; (*device->ActivateGrab)(device, &tempGrab, time, FALSE); if (oldCursor) FreeCursor (oldCursor, (Cursor)0); 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, oldCursor; REQUEST(xChangeActivePointerGrabReq); TimeStamp time; REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); if ((stuff->eventMask & ~PointerGrabMask) && !permitOldBugs) { client->errorValue = stuff->eventMask; return BadValue; } if (stuff->cursor == None) newCursor = NullCursor; else { newCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor, RT_CURSOR, SecurityReadAccess); if (!newCursor) { client->errorValue = stuff->cursor; return BadCursor; } } if (!grab) return Success; if (!SameClient(grab, client)) return Success; time = ClientTimeToServerTime(stuff->time); if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, device->grabTime) == EARLIER)) return Success; oldCursor = grab->cursor; grab->cursor = newCursor; if (newCursor) newCursor->refcnt++; PostNewCursor(); if (oldCursor) FreeCursor(oldCursor, (Cursor)0); grab->eventMask = stuff->eventMask; return Success; } int ProcUngrabPointer(client) ClientPtr client; { DeviceIntPtr device = inputInfo.pointer; GrabPtr grab; TimeStamp time; REQUEST(xResourceReq); REQUEST_SIZE_MATCH(xResourceReq); UpdateCurrentTime(); grab = device->grab; time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->grabTime) != EARLIER) && (grab) && SameClient(grab, client)) (*device->DeactivateGrab)(device); return Success; } int GrabDevice(client, dev, this_mode, other_mode, grabWindow, ownerEvents, ctime, mask, status) register ClientPtr client; register DeviceIntPtr dev; unsigned this_mode; unsigned other_mode; Window grabWindow; unsigned ownerEvents; Time ctime; Mask mask; CARD8 *status; { register WindowPtr pWin; register GrabPtr grab; TimeStamp time; UpdateCurrentTime(); if ((this_mode != GrabModeSync) && (this_mode != GrabModeAsync)) { client->errorValue = this_mode; return BadValue; } if ((other_mode != GrabModeSync) && (other_mode != GrabModeAsync)) { client->errorValue = other_mode; return BadValue; } if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) { client->errorValue = ownerEvents; return BadValue; } pWin = SecurityLookupWindow(grabWindow, client, SecurityReadAccess); if (!pWin) return BadWindow; time = ClientTimeToServerTime(ctime); grab = dev->grab; if (grab && !SameClient(grab, client)) *status = AlreadyGrabbed; else if (!pWin->realized) *status = GrabNotViewable; else if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, dev->grabTime) == EARLIER)) *status = GrabInvalidTime; else if (dev->sync.frozen && dev->sync.other && !SameClient(dev->sync.other, 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 Success; } int ProcGrabKeyboard(client) ClientPtr client; { xGrabKeyboardReply rep; REQUEST(xGrabKeyboardReq); int result; REQUEST_SIZE_MATCH(xGrabKeyboardReq); #ifdef XCSECURITY if (!SecurityCheckDeviceAccess(client, inputInfo.keyboard, TRUE)) { result = Success; rep.status = AlreadyGrabbed; } else #endif result = GrabDevice(client, inputInfo.keyboard, stuff->keyboardMode, stuff->pointerMode, stuff->grabWindow, stuff->ownerEvents, stuff->time, KeyPressMask | KeyReleaseMask, &rep.status); if (result != Success) return result; rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.length = 0; WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); return Success; } int ProcUngrabKeyboard(client) ClientPtr client; { DeviceIntPtr device = inputInfo.keyboard; GrabPtr grab; TimeStamp time; REQUEST(xResourceReq); REQUEST_SIZE_MATCH(xResourceReq); UpdateCurrentTime(); grab = device->grab; 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 = SecurityLookupWindow(stuff->id, client, SecurityReadAccess); 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; #ifdef LG3D /* ** TODO: this only works when pWin is the top-level ** window (or a descendent of the top level window) ** of the current virtual sprite window. We haven't ** yet figured out what the semantics should be for ** the case where this is not true. */ if (lgeDisplayServerIsAlive) { rep.winX = virtualSprite.win->drawable.x + virtualSprite.hot.x - pWin->drawable.x; rep.winY = virtualSprite.win->drawable.y + virtualSprite.hot.y - pWin->drawable.y; } else { rep.winX = sprite.hot.x - pWin->drawable.x; rep.winY = sprite.hot.y - pWin->drawable.y; } #else rep.winX = sprite.hot.x - pWin->drawable.x; rep.winY = sprite.hot.y - pWin->drawable.y; #endif /* LG3D */ 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; } #ifdef PANORAMIX if(!noPanoramiXExtension) { rep.rootX += panoramiXdataPtr[0].x; rep.rootY += panoramiXdataPtr[0].y; if(stuff->id == rep.root) { rep.winX += panoramiXdataPtr[0].x; rep.winY += panoramiXdataPtr[0].y; } } #endif 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; sprite.confined = FALSE; syncEvents.replayDev = (DeviceIntPtr)NULL; syncEvents.replayWin = NullWindow; while (syncEvents.pending) { QdEventPtr next = syncEvents.pending->next; xfree(syncEvents.pending); syncEvents.pending = next; } syncEvents.pendtail = &syncEvents.pending; syncEvents.playingEvents = FALSE; syncEvents.time.months = 0; syncEvents.time.milliseconds = 0; /* hardly matters */ currentTime.months = 0; currentTime.milliseconds = GetTimeInMillis(); lastDeviceEventTime = currentTime; for (i = 0; i < DNPMCOUNT; i++) { DontPropagateMasks[i] = 0; DontPropagateRefCnts[i] = 0; } } void CloseDownEvents(void) { xfree(spriteTrace); spriteTrace = NULL; spriteTraceSize = 0; } int ProcSendEvent(client) ClientPtr client; { 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 > X_Reply && stuff->event.u.u.type < LASTEvent) || (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && stuff->event.u.u.type < (unsigned)lastEvent))) { client->errorValue = stuff->event.u.u.type; return BadValue; } if (stuff->event.u.u.type == ClientMessage && stuff->event.u.u.detail != 8 && stuff->event.u.u.detail != 16 && stuff->event.u.u.detail != 32 && !permitOldBugs) { client->errorValue = stuff->event.u.u.detail; return BadValue; } if ((stuff->eventMask & ~AllEventMasks) && !permitOldBugs) { 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 = SecurityLookupWindow(stuff->destination, client, SecurityReadAccess); 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); if (!stuff->eventMask) break; } } else (void)DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, NullGrab, 0); return Success; } int ProcUngrabKey(client) ClientPtr client; { REQUEST(xUngrabKeyReq); WindowPtr pWin; GrabRec tempGrab; DeviceIntPtr keybd = inputInfo.keyboard; REQUEST_SIZE_MATCH(xUngrabKeyReq); pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); if (!pWin) return BadWindow; 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; } tempGrab.resource = client->clientAsMask; tempGrab.device = keybd; 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->ownerEvents != xTrue) && (stuff->ownerEvents != xFalse)) { client->errorValue = stuff->ownerEvents; return(BadValue); } 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 = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); 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 = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); if (!pWin) return BadWindow; if (stuff->confineTo == None) confineTo = NullWindow; else { confineTo = SecurityLookupWindow(stuff->confineTo, client, SecurityReadAccess); if (!confineTo) return BadWindow; } if (stuff->cursor == None) cursor = NullCursor; else { cursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor, RT_CURSOR, SecurityReadAccess); 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 = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); 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 /* This would be a good protocol change -- windows being reparented during SaveSet processing would cause the focus to revert to the nearest enclosing window which will survive the death of the exiting client, instead of ending up reverting to a dying window and thence to None */ #ifdef NOTDEF || clients[CLIENT_ID(parent->drawable.id)]->clientGone #endif ); 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; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; #endif if (grab && (confineTo = grab->confineTo)) { if (!BorderSizeNotEmpty(confineTo)) (*inputInfo.pointer->DeactivateGrab)(inputInfo.pointer); else if ((pWin == confineTo) || IsParent(pWin, confineTo)) ConfineCursorToWindow(confineTo, TRUE, 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; Bool displayed; REQUEST(xRecolorCursorReq); REQUEST_SIZE_MATCH(xRecolorCursorReq); pCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor, RT_CURSOR, SecurityWriteAccess); 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]; #ifdef PANORAMIX if(!noPanoramiXExtension) displayed = (pscr == sprite.screen); else #endif displayed = (pscr == sprite.hotPhys.pScreen); ( *pscr->RecolorCursor)(pscr, pCursor, (pCursor == sprite.current) && displayed); } return (Success); } /*#define DEBUG*/ #if defined(LG3D) && defined (DEBUG) int print_events_all = 0; int print_events_to_ds = 0; int print_events_to_wm = 0; int print_events_to_app = 0; int damageEventsOnly = 0; int numDamageEvents = 0; /* TODO: for damage event debug only */ #include "damageproto.h" #endif /* LG3D && DEBUG */ void WriteEventsToClient(pClient, count, events) ClientPtr pClient; int count; xEvent *events; { #ifdef PANORAMIX xEvent eventCopy; #endif xEvent eventTo, *eventFrom; int i; #ifdef XKB if ((!noXkbExtension)&&(!XkbFilterEvents(pClient, count, events))) return; #endif #ifdef PANORAMIX if(!noPanoramiXExtension && (panoramiXdataPtr[0].x || panoramiXdataPtr[0].y)) { switch(events->u.u.type) { case MotionNotify: case ButtonPress: case ButtonRelease: case KeyPress: case KeyRelease: case EnterNotify: case LeaveNotify: /* When multiple clients want the same event DeliverEventsToWindow passes the same event structure multiple times so we can't modify the one passed to us */ count = 1; /* should always be 1 */ memcpy(&eventCopy, events, sizeof(xEvent)); eventCopy.u.keyButtonPointer.rootX += panoramiXdataPtr[0].x; eventCopy.u.keyButtonPointer.rootY += panoramiXdataPtr[0].y; if(eventCopy.u.keyButtonPointer.event == eventCopy.u.keyButtonPointer.root) { eventCopy.u.keyButtonPointer.eventX += panoramiXdataPtr[0].x; eventCopy.u.keyButtonPointer.eventY += panoramiXdataPtr[0].y; } events = &eventCopy; break; default: break; } } #endif if (EventCallback) { EventInfoRec eventinfo; eventinfo.client = pClient; eventinfo.events = events; eventinfo.count = count; CallCallbacks(&EventCallback, (pointer)&eventinfo); } #if defined(LG3D) && defined (DEBUG) if (print_events_all || /* TODO: these indices are now out of date; update them */ (print_events_to_ds && pClient->index == 4) || (print_events_to_wm && pClient->index == 9) || (print_events_to_app && pClient->index == 6)) { xEvent *ev; for(i = 0; i < count; i++) { ev = &events[i]; if (ev->u.u.type == 118) { xDamageNotifyEvent *damev = (xDamageNotifyEvent *) ev; ErrorF("Send damage event %d, to client %d, xywh = %d, %d, %d, %d\n", ++numDamageEvents, pClient->index, damev->area.x, damev->area.y, damev->area.width, damev->area.height); } else if (!damageEventsOnly) { ErrorF("Send event %d to client %d, xy = %d, %d, event win = %d\n", ev->u.u.type, pClient->index, ev->u.keyButtonPointer.eventX, ev->u.keyButtonPointer.eventY, ev->u.keyButtonPointer.event); if (ev->u.u.type == 4 || ev->u.u.type == 5) { ErrorF("Button detail = %d\n", ev->u.u.detail); } } } } #endif /* LG3D && DEBUG */ if(pClient->swapped) { 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); } }