diff options
author | marha <marha@users.sourceforge.net> | 2009-09-09 05:23:48 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2009-09-09 05:23:48 +0000 |
commit | 81f91c615982e50bb62708201569c33a3cd3d973 (patch) | |
tree | 4f32ecc48a3b7b5e76642f3792338263c53879bd /xorg-server/dix/events.c | |
parent | b571a562410f565af2bdde52d9f7f9a23ffae04f (diff) | |
parent | a915739887477b28d924ecc8417ee107d125bd6c (diff) | |
download | vcxsrv-81f91c615982e50bb62708201569c33a3cd3d973.tar.gz vcxsrv-81f91c615982e50bb62708201569c33a3cd3d973.tar.bz2 vcxsrv-81f91c615982e50bb62708201569c33a3cd3d973.zip |
svn merge https://vcxsrv.svn.sourceforge.net/svnroot/vcxsrv/branches/released .
Diffstat (limited to 'xorg-server/dix/events.c')
-rw-r--r-- | xorg-server/dix/events.c | 3179 |
1 files changed, 1655 insertions, 1524 deletions
diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index f9448ba76..0d01df512 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -107,7 +107,7 @@ of the copyright holder. ******************************************************************/ -/** @file +/** @file events.c * This file handles event delivery and a big part of the server-side protocol * handling (the parts for input devices). */ @@ -117,11 +117,8 @@ of the copyright holder. #endif #include <X11/X.h> -#include <X11/keysym.h> #include "misc.h" #include "resource.h" -#define NEED_EVENTS -#define NEED_REPLIES #include <X11/Xproto.h> #include "windowstr.h" #include "inputstr.h" @@ -135,12 +132,8 @@ of the copyright holder. #endif #include "globals.h" -#ifdef XKB #include <X11/extensions/XKBproto.h> -#include <xkbsrv.h> -extern Bool XkbFilterEvents(ClientPtr, int, xEvent *); -#endif - +#include "xkbsrv.h" #include "xace.h" #ifdef XSERVER_DTRACE @@ -150,7 +143,9 @@ typedef const char *string; #endif #include <X11/extensions/XIproto.h> +#include <X11/extensions/XI2proto.h> #include <X11/extensions/XI.h> +#include <X11/extensions/XI2.h> #include "exglobals.h" #include "exevents.h" #include "exglobals.h" @@ -164,11 +159,11 @@ typedef const char *string; #include "geext.h" #include "geint.h" +#include "eventstr.h" #include "enterleave.h" +#include "eventconvert.h" -/** - * Extension events type numbering starts at EXTENSION_EVENT_BASE. - */ +/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ #define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ #define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) #define AllButtonsMask ( \ @@ -188,20 +183,22 @@ typedef const char *string; #define AllModifiersMask ( \ ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ Mod3Mask | Mod4Mask | Mod5Mask ) -#define AllEventMasks (lastEventMask|(lastEventMask-1)) +#define LastEventMask OwnerGrabButtonMask +#define AllEventMasks (LastEventMask|(LastEventMask-1)) + + +#define CORE_EVENT(event) \ + (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ + (event)->u.u.type != GenericEvent) +#define XI2_EVENT(event) \ + (((event)->u.u.type == GenericEvent) && \ + ((xGenericEvent*)(event))->extension == IReqCode) /** * Used to indicate a implicit passive grab created by a ButtonPress event. * See DeliverEventsToWindow(). */ #define ImplicitGrabMask (1 << 7) -/* - * The following relies on the fact that the Button<n>MotionMasks are equal - * to the corresponding Button<n>Masks from the current modifier/button state. - */ -#define Motion_Filter(class) (PointerMotionMask | \ - (class)->state | (class)->motionMask) - #define WID(w) ((w) ? ((w)->drawable.id) : 0) @@ -210,21 +207,33 @@ typedef const char *string; #define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) -_X_EXPORT CallbackListPtr EventCallback; -_X_EXPORT CallbackListPtr DeviceEventCallback; +CallbackListPtr EventCallback; +CallbackListPtr DeviceEventCallback; #define DNPMCOUNT 8 Mask DontPropagateMasks[DNPMCOUNT]; static int DontPropagateRefCnts[DNPMCOUNT]; +static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); +static void CheckPhysLimits(DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, + ScreenPtr pScreen); +static Bool CheckPassiveGrabsOnWindow(WindowPtr pWin, + DeviceIntPtr device, + DeviceEvent *event, + BOOL checkCore); + +/** Key repeat hack. Do not use but in TryClientEvents */ +extern BOOL EventIsKeyRepeat(xEvent *event); /** * Main input device struct. * inputInfo.pointer * is the core pointer. Referred to as "virtual core pointer", "VCP", - * "core pointer" or inputInfo.pointer. There is exactly one core pointer, - * but multiple devices may send core events. The VCP is the first master + * "core pointer" or inputInfo.pointer. The VCP is the first master * pointer device and cannot be deleted. * * inputInfo.keyboard @@ -239,45 +248,69 @@ static int DontPropagateRefCnts[DNPMCOUNT]; * * inputInfo.numDevices * Total number of devices. + * + * inputInfo.all_devices + * Virtual device used for XIAllDevices passive grabs. This device is + * not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + * + * inputInfo.all_master_devices + * Virtual device used for XIAllMasterDevices passive grabs. This device + * is not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. */ -_X_EXPORT InputInfo inputInfo; +InputInfo inputInfo; /** * syncEvents is the global structure for queued events. + * * Devices can be frozen through GrabModeSync pointer grabs. If this is the * case, events from these devices are added to "pending" instead of being * processed normally. When the device is unfrozen, events in "pending" are * replayed and processed as if they would come from the device directly. - * - * pending ... list of queued events - * pendtail ... last event in list - * replayDev ... The device to replay events for. Only set in AllowEvents, in - * which case it is set to the device specified in the request. - * replayWin ... the window the events are supposed to be replayed on. This - * window may be set to the grab's window (but only when - * Replay{Pointer|Keyboard} is given in the XAllowEvents - * request. - * playingEvents ... flag to indicate whether we're in the process of - * replaying events. Only set in ComputeFreezes(). */ static struct { - QdEventPtr pending, *pendtail; + QdEventPtr pending, /**< list of queued events */ + *pendtail; /**< last event in list */ + /** The device to replay events for. Only set in AllowEvents(), in which + * case it is set to the device specified in the request. */ DeviceIntPtr replayDev; /* kludgy rock to put flag for */ + + /** + * The window the events are supposed to be replayed on. + * This window may be set to the grab's window (but only when + * Replay{Pointer|Keyboard} is given in the XAllowEvents() + * request. */ WindowPtr replayWin; /* ComputeFreezes */ + /** + * Flag to indicate whether we're in the process of + * replaying events. Only set in ComputeFreezes(). */ Bool playingEvents; TimeStamp time; } syncEvents; +/** + * The root window the given device is currently on. + */ #define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] static xEvent* swapEvent = NULL; static int swapEventLen = 0; +void +NotImplemented(xEvent *from, xEvent *to) +{ + FatalError("Not implemented"); +} + /** * Convert the given event type from an XI event to a core event. + * @param[in] The XI 1.x event type. * @return The matching core event type or 0 if there is none. */ -_X_EXPORT int +int XItoCoreType(int xitype) { int coretype = 0; @@ -296,36 +329,43 @@ XItoCoreType(int xitype) } /** - * True if device owns a cursor, false if device shares a cursor sprite with - * another device. + * @return true if the device owns a cursor, false if device shares a cursor + * sprite with another device. */ -_X_EXPORT Bool +Bool DevHasCursor(DeviceIntPtr pDev) { return pDev->spriteInfo->spriteOwner; } /* - * Return true if a device is a pointer, check is the same as used by XI to + * @return true if a device is a pointer, check is the same as used by XI to * fill the 'use' field. */ -_X_EXPORT Bool +Bool IsPointerDevice(DeviceIntPtr dev) { - return (dev->valuator && dev->button); + return (dev->type == MASTER_POINTER) || (dev->valuator && dev->button); } /* - * Return true if a device is a keyboard, check is the same as used by XI to + * @return true if a device is a keyboard, check is the same as used by XI to * fill the 'use' field. * * Some pointer devices have keys as well (e.g. multimedia keys). Try to not * count them as keyboard devices. */ -_X_EXPORT Bool +Bool IsKeyboardDevice(DeviceIntPtr dev) { - return (dev->key && dev->kbdfeed) && !IsPointerDevice(dev); + return (dev->type == MASTER_KEYBOARD) || + ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); +} + +Bool +IsMaster(DeviceIntPtr dev) +{ + return (dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD); } static WindowPtr XYToWindow( @@ -339,15 +379,22 @@ static WindowPtr XYToWindow( */ extern int lastEvent; -static Mask lastEventMask; - extern int DeviceMotionNotify; +#define CantBeFiltered NoEventMask /** - * Event filters. One set of filters for each device, but only the first layer + * Event masks for each event type. + * + * One set of filters for each device, but only the first layer * is initialized. The rest is memcpy'd in InitEvents. + * + * Filters are used whether a given event may be delivered to a client, + * usually in the form of if (window-event-mask & filter); then deliver event. + * + * One notable filter is for PointerMotion/DevicePointerMotion events. Each + * time a button is pressed, the filter is modified to also contain the + * matching ButtonXMotion mask. */ -#define CantBeFiltered NoEventMask static Mask filters[MAXDEVICES][128] = { { NoSuchEvent, /* 0 */ @@ -387,28 +434,90 @@ static Mask filters[MAXDEVICES][128] = { CantBeFiltered /* MappingNotify */ }}; +/** + * For the given event, return the matching event filter. This filter may then + * be AND'ed with the selected event mask. + * + * For XI2 events, the returned filter is simply the byte containing the event + * mask we're interested in. E.g. for a mask of (1 << 13), this would be + * byte[1]. + * + * @param[in] dev The device the event belongs to, may be NULL. + * @param[in] event The event to get the filter for. Only the type of the + * event matters, or the extension + evtype for GenericEvents. + * @return The filter mask for the given event. + * + * @see GetEventMask + */ +Mask +GetEventFilter(DeviceIntPtr dev, xEvent *event) +{ + if (event->u.u.type != GenericEvent) + return filters[dev ? dev->id : 0][event->u.u.type]; + else if (XI2_EVENT(event)) + return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); + ErrorF("[dix] Unknown device type %d. No filter\n", event->u.u.type); + return 0; +} /** - * same principle as filters, but one set of filters for each extension. - * The extension is responsible for setting the filters by calling - * SetGenericFilter(). + * Return the windows complete XI2 mask for the given XI2 event type. */ -static Mask* generic_filters[MAXEXTENSIONS]; +Mask +GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) +{ + OtherInputMasks *inputMasks = wOtherInputMasks(win); + int filter; + int evtype; + + if (!inputMasks || !XI2_EVENT(ev)) + return 0; + + evtype = ((xGenericEvent*)ev)->evtype; + filter = GetEventFilter(dev, ev); + + return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || + inputMasks->xi2mask[XIAllDevices][evtype/8] || + (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); +} + +static Mask +GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) +{ + /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ + if (XI2_EVENT(event)) + { + int byte = ((xGenericEvent*)event)->evtype / 8; + return (other->xi2mask[dev->id][byte] | + other->xi2mask[XIAllDevices][byte] | + (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); + } else if (CORE_EVENT(event)) + return other->mask[XIAllDevices]; + else + return other->mask[dev->id]; +} + static CARD8 criticalEvents[32] = { 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ }; +static void +SyntheticMotion(DeviceIntPtr dev, int x, int y) { + int screenno = 0; + #ifdef PANORAMIX -static void PostNewCursor(DeviceIntPtr pDev); + if (!noPanoramiXExtension) + screenno = dev->spriteInfo->sprite->screen->myNum; +#endif + PostSyntheticMotion(dev, x, y, screenno, + (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); -#define SyntheticMotion(dev, x, y) \ - PostSyntheticMotion(dev, x, y, noPanoramiXExtension ? 0 : \ - dev->spriteInfo->sprite->screen->myNum, \ - syncEvents.playingEvents ? \ - syncEvents.time.milliseconds : \ - currentTime.milliseconds); +} + +#ifdef PANORAMIX +static void PostNewCursor(DeviceIntPtr pDev); static Bool XineramaSetCursorPosition( @@ -475,49 +584,6 @@ XineramaConstrainCursor(DeviceIntPtr pDev) (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); } -static void -XineramaCheckPhysLimits( - DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents -){ - HotSpot new; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (!cursor) - return; - - new = pSprite->hotPhys; - - /* I don't care what the DDX has to say about it */ - pSprite->physLimits = pSprite->hotLimits; - - /* constrain the pointer to those limits */ - if (new.x < pSprite->physLimits.x1) - new.x = pSprite->physLimits.x1; - else - if (new.x >= pSprite->physLimits.x2) - new.x = pSprite->physLimits.x2 - 1; - if (new.y < pSprite->physLimits.y1) - new.y = pSprite->physLimits.y1; - else - if (new.y >= pSprite->physLimits.y2) - new.y = pSprite->physLimits.y2 - 1; - - if (pSprite->hotShape) /* more work if the shape is a mess */ - ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); - - if((new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) - { - XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); - if (!generateEvents) - SyntheticMotion(pDev, new.x, new.y); - } - - /* Tell DDX what the limits are */ - XineramaConstrainCursor(pDev); -} - static Bool XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) @@ -529,16 +595,17 @@ XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) PanoramiXNumScreens*sizeof(WindowPtr)); } else { PanoramiXRes *win; - int i; + int rc, i; - win = (PanoramiXRes*)LookupIDByType(pWin->drawable.id, XRT_WINDOW); - - if(!win) + rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, + XRT_WINDOW, serverClient, DixReadAccess); + if (rc != Success) return FALSE; for(i = 0; i < PanoramiXNumScreens; i++) { - pSprite->windows[i] = LookupIDByType(win->info[i].id, RT_WINDOW); - if(!pSprite->windows[i]) /* window is being unmapped */ + rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, + serverClient, DixReadAccess); + if (rc != Success) /* window is being unmapped */ return FALSE; } } @@ -546,251 +613,76 @@ XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) } static void -XineramaCheckVirtualMotion( - DeviceIntPtr pDev, - QdEventPtr qe, - WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (qe) - { - pSprite->hot.pScreen = qe->pScreen; /* should always be Screen 0 */ - pSprite->hot.x = qe->event->u.keyButtonPointer.rootX; - pSprite->hot.y = qe->event->u.keyButtonPointer.rootY; - pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : - NullWindow; - } - if (pWin) - { - int x, y, off_x, off_y, i; - BoxRec lims; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - REGION_COPY(pSprite->screen, &pSprite->Reg2, - &pSprite->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(pSprite->screen, &pSprite->Reg2, x, y); - - REGION_UNION(pSprite->screen, &pSprite->Reg2, &pSprite->Reg2, - &pSprite->windows[i]->borderSize); - - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - } - - lims = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg2); - - if (pSprite->hot.x < lims.x1) - pSprite->hot.x = lims.x1; - else if (pSprite->hot.x >= lims.x2) - pSprite->hot.x = lims.x2 - 1; - if (pSprite->hot.y < lims.y1) - pSprite->hot.y = lims.y1; - else if (pSprite->hot.y >= lims.y2) - pSprite->hot.y = lims.y2 - 1; - - if (REGION_NUM_RECTS(&pSprite->Reg2) > 1) - ConfineToShape(pDev, &pSprite->Reg2, - &pSprite->hot.x, &pSprite->hot.y); - - if (qe) - { - qe->pScreen = pSprite->hot.pScreen; - qe->event->u.keyButtonPointer.rootX = pSprite->hot.x; - qe->event->u.keyButtonPointer.rootY = pSprite->hot.y; - } - } -} - - -static Bool -XineramaCheckMotion(xEvent *xE, DeviceIntPtr pDev) -{ - WindowPtr prevSpriteWin; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - prevSpriteWin = pSprite->win; - - if (xE && !syncEvents.playingEvents) - { - /* GetPointerEvents() guarantees that pointer events have the correct - rootX/Y set already. */ - switch(xE->u.u.type) - { - case ButtonPress: - case ButtonRelease: - case MotionNotify: - break; - default: - if (xE->u.u.type == DeviceButtonPress || - xE->u.u.type == DeviceButtonRelease || - xE->u.u.type == DeviceMotionNotify) - break; - /* all other events return FALSE */ - return FALSE; - } - - /* 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[pSprite->screen->myNum].x - - panoramiXdataPtr[0].x; - XE_KBPTR.rootY += panoramiXdataPtr[pSprite->screen->myNum].y - - panoramiXdataPtr[0].y; - pSprite->hot.x = XE_KBPTR.rootX; - pSprite->hot.y = XE_KBPTR.rootY; - if (pSprite->hot.x < pSprite->physLimits.x1) - pSprite->hot.x = pSprite->physLimits.x1; - else if (pSprite->hot.x >= pSprite->physLimits.x2) - pSprite->hot.x = pSprite->physLimits.x2 - 1; - if (pSprite->hot.y < pSprite->physLimits.y1) - pSprite->hot.y = pSprite->physLimits.y1; - else if (pSprite->hot.y >= pSprite->physLimits.y2) - pSprite->hot.y = pSprite->physLimits.y2 - 1; - - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); - - pSprite->hotPhys = pSprite->hot; - if ((pSprite->hotPhys.x != XE_KBPTR.rootX) || - (pSprite->hotPhys.y != XE_KBPTR.rootY)) - { - XineramaSetCursorPosition( - pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } - XE_KBPTR.rootX = pSprite->hot.x; - XE_KBPTR.rootY = pSprite->hot.y; - } - - pSprite->win = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); - - if (pSprite->win != prevSpriteWin) - { - if (prevSpriteWin != NullWindow) { - if (!xE) - UpdateCurrentTimeIf(); - DoEnterLeaveEvents(pDev, prevSpriteWin, pSprite->win, - NotifyNormal); - } - PostNewCursor(pDev); - return FALSE; - } - return TRUE; -} - - -static void XineramaConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents) { SpritePtr pSprite = pDev->spriteInfo->sprite; - if (syncEvents.playingEvents) - { - XineramaCheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); - SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); - } - else - { - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; + int x, y, off_x, off_y, i; - REGION_COPY(pSprite->screen, &pSprite->Reg1, - &pSprite->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(!XineramaSetWindowPntrs(pDev, pWin)) + return; - if(x || y) - REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, x, y); + i = PanoramiXNumScreens - 1; - REGION_UNION(pSprite->screen, &pSprite->Reg1, &pSprite->Reg1, - &pSprite->windows[i]->borderSize); + REGION_COPY(pSprite->screen, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; - off_x = panoramiXdataPtr[i].x; - off_y = panoramiXdataPtr[i].y; - } + while(i--) { + x = off_x - panoramiXdataPtr[i].x; + y = off_y - panoramiXdataPtr[i].y; - pSprite->hotLimits = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg1); + if(x || y) + REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, x, y); - if(REGION_NUM_RECTS(&pSprite->Reg1) > 1) - pSprite->hotShape = &pSprite->Reg1; - else - pSprite->hotShape = NullRegion; + REGION_UNION(pSprite->screen, &pSprite->Reg1, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); - pSprite->confined = FALSE; - pSprite->confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin; - - XineramaCheckPhysLimits(pDev, pSprite->current, - generateEvents); + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; } -} + pSprite->hotLimits = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg1); -static void -XineramaChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; + if(REGION_NUM_RECTS(&pSprite->Reg1) > 1) + pSprite->hotShape = &pSprite->Reg1; + else + pSprite->hotShape = NullRegion; - if (cursor != pSprite->current) - { - if ((pSprite->current->bits->xhot != cursor->bits->xhot) || - (pSprite->current->bits->yhot != cursor->bits->yhot)) - XineramaCheckPhysLimits(pDev, cursor, FALSE); - (*pSprite->screen->DisplayCursor)(pDev, pSprite->screen, cursor); - FreeCursor(pSprite->current, (Cursor)0); - pSprite->current = cursor; - pSprite->current->refcnt++; - } -} + pSprite->confined = FALSE; + pSprite->confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin; -#else -#define SyntheticMotion(dev, x, y) \ - PostSyntheticMotion(dev, x, y, \ - 0, \ - syncEvents.playingEvents ? \ - syncEvents.time.milliseconds : \ - currentTime.milliseconds); + CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); +} #endif /* PANORAMIX */ +/** + * Modifies the filter for the given protocol event type to the given masks. + * + * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). + * The latter initialises masks for the matching XI events, it's a once-off + * setting. + * UDS however changes the mask for MotionNotify and DeviceMotionNotify each + * time a button is pressed to include the matching ButtonXMotion mask in the + * filter. + * + * @param[in] deviceid The device to modify the filter for. + * @param[in] mask The new filter mask. + * @param[in] event Protocol event type. + */ void SetMaskForEvent(int deviceid, Mask mask, int event) { - int coretype; if (deviceid < 0 || deviceid >= MAXDEVICES) FatalError("SetMaskForEvent: bogus device id"); - if ((event < LASTEvent) || (event >= 128)) - FatalError("SetMaskForEvent: bogus event number"); filters[deviceid][event] = mask; - - /* Need to change the mask for the core events too */ - coretype = XItoCoreType(event); - if (coretype) - filters[deviceid][coretype] = mask; } -_X_EXPORT void +void SetCriticalEvent(int event) { if (event >= 128) @@ -841,8 +733,8 @@ CheckPhysLimits( DeviceIntPtr pDev, CursorPtr cursor, Bool generateEvents, - Bool confineToScreen, - ScreenPtr pScreen) + Bool confineToScreen, /* unused if PanoramiX on */ + ScreenPtr pScreen) /* unused if PanoramiX on */ { HotSpot new; SpritePtr pSprite = pDev->spriteInfo->sprite; @@ -850,14 +742,24 @@ CheckPhysLimits( if (!cursor) return; new = pSprite->hotPhys; - if (pScreen) - new.pScreen = pScreen; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + /* I don't care what the DDX has to say about it */ + pSprite->physLimits = pSprite->hotLimits; else - pScreen = new.pScreen; - (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = confineToScreen; - (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); +#endif + { + if (pScreen) + new.pScreen = pScreen; + else + pScreen = new.pScreen; + (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = confineToScreen; + (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); + } + + /* constrain the pointer to those limits */ if (new.x < pSprite->physLimits.x1) new.x = pSprite->physLimits.x1; else @@ -873,13 +775,26 @@ CheckPhysLimits( if ((pScreen != pSprite->hotPhys.pScreen) || (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) { - if (pScreen != pSprite->hotPhys.pScreen) - pSprite->hotPhys = new; - (*pScreen->SetCursorPosition) - (pDev, pScreen, new.x, new.y, generateEvents); +#ifdef PANORAMIX + if (!noPanoramiXExtension) + XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); + else +#endif + { + if (pScreen != pSprite->hotPhys.pScreen) + pSprite->hotPhys = new; + (*pScreen->SetCursorPosition) + (pDev, pScreen, new.x, new.y, generateEvents); + } if (!generateEvents) - SyntheticMotion(pDev, new.x, new.y); + SyntheticMotion(pDev, new.x, new.y); } + +#ifdef PANORAMIX + /* Tell DDX what the limits are */ + if (!noPanoramiXExtension) + XineramaConstrainCursor(pDev); +#endif } static void @@ -889,29 +804,71 @@ CheckVirtualMotion( WindowPtr pWin) { SpritePtr pSprite = pDev->spriteInfo->sprite; + RegionPtr reg = NULL; + DeviceEvent *ev = NULL; -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaCheckVirtualMotion(pDev, qe, pWin); - return; - } -#endif if (qe) { - pSprite->hot.pScreen = qe->pScreen; - pSprite->hot.x = qe->event->u.keyButtonPointer.rootX; - pSprite->hot.y = qe->event->u.keyButtonPointer.rootY; - pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; + ev = (DeviceEvent*)qe->event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + pSprite->hot.pScreen = qe->pScreen; + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; + break; + default: + break; + } } if (pWin) { BoxRec lims; - if (pSprite->hot.pScreen != pWin->drawable.pScreen) - { - pSprite->hot.pScreen = pWin->drawable.pScreen; - pSprite->hot.x = pSprite->hot.y = 0; - } +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + REGION_COPY(pSprite->screen, &pSprite->Reg2, + &pSprite->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(pSprite->screen, &pSprite->Reg2, x, y); + + REGION_UNION(pSprite->screen, &pSprite->Reg2, &pSprite->Reg2, + &pSprite->windows[i]->borderSize); + + off_x = panoramiXdataPtr[i].x; + off_y = panoramiXdataPtr[i].y; + } + } else +#endif + { + if (pSprite->hot.pScreen != pWin->drawable.pScreen) + { + pSprite->hot.pScreen = pWin->drawable.pScreen; + pSprite->hot.x = pSprite->hot.y = 0; + } + } + lims = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin->borderSize); if (pSprite->hot.x < lims.x1) pSprite->hot.x = lims.x1; @@ -921,17 +878,34 @@ CheckVirtualMotion( pSprite->hot.y = lims.y1; else if (pSprite->hot.y >= lims.y2) pSprite->hot.y = lims.y2 - 1; - if (wBoundingShape(pWin)) - ConfineToShape(pDev, &pWin->borderSize, - &pSprite->hot.x, &pSprite->hot.y); - if (qe) + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (REGION_NUM_RECTS(&pSprite->Reg2) > 1) + reg = &pSprite->Reg2; + + } else +#endif + { + if (wBoundingShape(pWin)) + reg = &pWin->borderSize; + } + + if (reg) + ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); + + if (qe && ev) { qe->pScreen = pSprite->hot.pScreen; - qe->event->u.keyButtonPointer.rootX = pSprite->hot.x; - qe->event->u.keyButtonPointer.rootY = pSprite->hot.y; + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; } } - RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; +#ifdef PANORAMIX + if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ +#endif + RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; } static void @@ -940,13 +914,6 @@ ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bo ScreenPtr pScreen = pWin->drawable.pScreen; SpritePtr pSprite = pDev->spriteInfo->sprite; -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaConfineCursorToWindow(pDev, pWin, generateEvents); - return; - } -#endif - if (syncEvents.playingEvents) { CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); @@ -954,6 +921,12 @@ ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bo } else { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + XineramaConfineCursorToWindow(pDev, pWin, generateEvents); + return; + } +#endif pSprite->hotLimits = *REGION_EXTENTS( pScreen, &pWin->borderSize); pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize : NullRegion; @@ -962,7 +935,7 @@ ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bo } } -_X_EXPORT Bool +Bool PointerConfinedToScreen(DeviceIntPtr pDev) { return pDev->spriteInfo->sprite->confined; @@ -979,13 +952,7 @@ static void ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) { SpritePtr pSprite = pDev->spriteInfo->sprite; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaChangeToCursor(pDev, cursor); - return; - } -#endif + ScreenPtr pScreen; if (cursor != pSprite->current) { @@ -993,9 +960,15 @@ ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) (pSprite->current->bits->yhot != cursor->bits->yhot)) CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, (ScreenPtr)NULL); - (*pSprite->hotPhys.pScreen->DisplayCursor) (pDev, - pSprite->hotPhys.pScreen, - cursor); +#ifdef PANORAMIX + /* XXX: is this really necessary?? (whot) */ + if (!noPanoramiXExtension) + pScreen = pSprite->screen; + else +#endif + pScreen = pSprite->hotPhys.pScreen; + + (*pScreen->DisplayCursor)(pDev, pScreen, cursor); FreeCursor(pSprite->current, (Cursor)0); pSprite->current = cursor; pSprite->current->refcnt++; @@ -1063,7 +1036,7 @@ PostNewCursor(DeviceIntPtr pDev) * @param dev device which you want to know its current root window * @return root window where dev's sprite is located */ -_X_EXPORT WindowPtr +WindowPtr GetCurrentRootWindow(DeviceIntPtr dev) { return RootWindow(dev); @@ -1072,7 +1045,7 @@ GetCurrentRootWindow(DeviceIntPtr dev) /** * @return window underneath the cursor sprite. */ -_X_EXPORT WindowPtr +WindowPtr GetSpriteWindow(DeviceIntPtr pDev) { return pDev->spriteInfo->sprite->win; @@ -1081,7 +1054,7 @@ GetSpriteWindow(DeviceIntPtr pDev) /** * @return current sprite cursor. */ -_X_EXPORT CursorPtr +CursorPtr GetSpriteCursor(DeviceIntPtr pDev) { return pDev->spriteInfo->sprite->current; @@ -1090,7 +1063,7 @@ GetSpriteCursor(DeviceIntPtr pDev) /** * Set x/y current sprite position in screen coordinates. */ -_X_EXPORT void +void GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) { SpritePtr pSprite = pDev->spriteInfo->sprite; @@ -1099,7 +1072,7 @@ GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) } #ifdef PANORAMIX -_X_EXPORT int +int XineramaGetCursorScreen(DeviceIntPtr pDev) { if(!noPanoramiXExtension) { @@ -1113,29 +1086,32 @@ XineramaGetCursorScreen(DeviceIntPtr pDev) #define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ static void -MonthChangedOrBadTime(xEvent *xE) +MonthChangedOrBadTime(InternalEvent *ev) { /* 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) + if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) currentTime.months++; else - XE_KBPTR.time = currentTime.milliseconds; + ev->any.time = currentTime.milliseconds; } -#define NoticeTime(xE) { \ - if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \ - MonthChangedOrBadTime(xE); \ - currentTime.milliseconds = (xE)->u.keyButtonPointer.time; \ - lastDeviceEventTime = currentTime; } +static void +NoticeTime(InternalEvent *ev) +{ + if (ev->any.time < currentTime.milliseconds) + MonthChangedOrBadTime(ev); + currentTime.milliseconds = ev->any.time; + lastDeviceEventTime = currentTime; +} void -NoticeEventTime(xEvent *xE) +NoticeEventTime(InternalEvent *ev) { if (!syncEvents.playingEvents) - NoticeTime(xE); + NoticeTime(ev); } /************************************************************************** @@ -1148,23 +1124,23 @@ NoticeEventTime(xEvent *xE) * linked list for later delivery. */ void -EnqueueEvent(xEvent *xE, DeviceIntPtr device, int count) +EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) { QdEventPtr tail = *syncEvents.pendtail; QdEventPtr qe; SpritePtr pSprite = device->spriteInfo->sprite; int eventlen; + DeviceEvent *event = (DeviceEvent*)ev; + NoticeTime((InternalEvent*)event); - NoticeTime(xE); - -#ifdef XKB /* Fix for key repeating bug. */ if (device->key != NULL && device->key->xkbInfo != NULL && - (xE->u.u.type == KeyRelease || xE->u.u.type == DeviceKeyRelease)) - AccessXCancelRepeatKey(device->key->xkbInfo, xE->u.u.detail); -#endif + event->type == ET_KeyRelease) + AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); +#if 0 + /* FIXME: I'm broken now. Please fix me. */ if (DeviceEventCallback) { DeviceEventInfoRec eventinfo; @@ -1181,59 +1157,48 @@ EnqueueEvent(xEvent *xE, DeviceIntPtr device, int count) XE_KBPTR.root = WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id; eventinfo.events = xE; - eventinfo.count = count; + eventinfo.count = nevents; CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); } - if (xE->u.u.type == DeviceMotionNotify) +#endif + if (event->type == ET_Motion) { #ifdef PANORAMIX if(!noPanoramiXExtension) { - XE_KBPTR.rootX += panoramiXdataPtr[pSprite->screen->myNum].x - + event->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - panoramiXdataPtr[0].x; - XE_KBPTR.rootY += panoramiXdataPtr[pSprite->screen->myNum].y - + event->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - panoramiXdataPtr[0].y; } #endif - pSprite->hotPhys.x = XE_KBPTR.rootX; - pSprite->hotPhys.y = XE_KBPTR.rootY; + pSprite->hotPhys.x = event->root_x; + pSprite->hotPhys.y = event->root_y; /* do motion compression, but not if from different devices */ if (tail && - (tail->event->u.u.type == DeviceMotionNotify) && + (tail->event->any.type == ET_Motion) && (tail->device == device) && (tail->pScreen == pSprite->hotPhys.pScreen)) { - tail->event->u.keyButtonPointer.rootX = pSprite->hotPhys.x; - tail->event->u.keyButtonPointer.rootY = pSprite->hotPhys.y; - tail->event->u.keyButtonPointer.time = XE_KBPTR.time; + DeviceEvent *tailev = (DeviceEvent*)tail->event; + tailev->root_x = pSprite->hotPhys.x; + tailev->root_y = pSprite->hotPhys.y; + tailev->time = event->time; tail->months = currentTime.months; return; } } - eventlen = count * sizeof(xEvent); - if (xE->u.u.type == GenericEvent) /* count is 1 for GenericEvents */ - eventlen += ((xGenericEvent*)xE)->length * 4; + eventlen = event->length; - qe = (QdEventPtr)xalloc(sizeof(QdEventRec) + eventlen); + qe = xalloc(sizeof(QdEventRec) + eventlen); if (!qe) return; qe->next = (QdEventPtr)NULL; qe->device = device; qe->pScreen = pSprite->hotPhys.pScreen; qe->months = currentTime.months; - qe->event = (xEvent *)(qe + 1); - qe->evcount = count; - if (xE->u.u.type == GenericEvent) - { - memcpy(qe->event, xE, eventlen); - } else - { - xEvent *qxE; - for (qxE = qe->event; --count >= 0; qxE++, xE++) - { - *qxE = *xE; - } - } + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); if (tail) syncEvents.pendtail = &tail->next; *syncEvents.pendtail = qe; @@ -1254,7 +1219,6 @@ PlayReleasedEvents(void) QdEventPtr *prev, qe; DeviceIntPtr dev; DeviceIntPtr pDev; - static CARD32 lastKnownMillis = 0; /* Hack, see comment below */ prev = &syncEvents.pending; while ( (qe = *prev) ) @@ -1265,36 +1229,37 @@ PlayReleasedEvents(void) pDev = qe->device; if (*syncEvents.pendtail == *prev) syncEvents.pendtail = prev; - if (qe->event->u.u.type == DeviceMotionNotify) + if (qe->event->any.type == ET_Motion) CheckVirtualMotion(pDev, qe, NullWindow); syncEvents.time.months = qe->months; - /* XXX: Hack! We can't reliably get the time from GenericEvents, - since we don't know which struct it may be. So we store the time - when we know it, and re-use it when we can't get it. */ - if (qe->event->u.u.type == GenericEvent) - { - syncEvents.time.milliseconds = lastKnownMillis; - } else - { - syncEvents.time.milliseconds = qe->event->u.keyButtonPointer.time; - lastKnownMillis = syncEvents.time.milliseconds; - } + syncEvents.time.milliseconds = qe->event->any.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 */ - /* XXX: we can't do that for generic events */ if(!noPanoramiXExtension) { - qe->event->u.keyButtonPointer.rootX += - panoramiXdataPtr[0].x - - panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].x; - qe->event->u.keyButtonPointer.rootY += - panoramiXdataPtr[0].y - - panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].y; + DeviceEvent *ev = (DeviceEvent*)(qe->event); + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + ev->root_x += panoramiXdataPtr[0].x - + panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].x; + ev->root_y += panoramiXdataPtr[0].y - + panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].y; + break; + default: + break; + } + } #endif - (*qe->device->public.processInputProc)(qe->event, qe->device, - qe->evcount); + (*qe->device->public.processInputProc)(qe->event, qe->device); xfree(qe); for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) ; @@ -1334,9 +1299,6 @@ FreezeThaw(DeviceIntPtr dev, Bool frozen) * runs up the sprite tree (spriteTrace) and searches for the window to replay * the events from. If it is found, it checks for passive grabs one down from * the window or delivers the events. - * - * Since the events in the EQ are always XI events, we need to emulate core - * events here. */ static void ComputeFreezes(void) @@ -1344,8 +1306,6 @@ ComputeFreezes(void) DeviceIntPtr replayDev = syncEvents.replayDev; int i; WindowPtr w; - xEvent *xE; - int count; GrabPtr grab; DeviceIntPtr dev; @@ -1357,31 +1317,32 @@ ComputeFreezes(void) syncEvents.playingEvents = TRUE; if (replayDev) { - xE = replayDev->deviceGrab.sync.event; - count = replayDev->deviceGrab.sync.evcount; + DeviceEvent* event = replayDev->deviceGrab.sync.event; + syncEvents.replayDev = (DeviceIntPtr)NULL; - w = XYToWindow(replayDev, XE_KBPTR.rootX, XE_KBPTR.rootY); + w = XYToWindow(replayDev, event->root_x, event->root_y); for (i = 0; i < replayDev->spriteInfo->sprite->spriteTraceGood; i++) { if (syncEvents.replayWin == replayDev->spriteInfo->sprite->spriteTrace[i]) { - if (!CheckDeviceGrabs(replayDev, xE, i+1, count)) { - if (replayDev->focus && !IsPointerEvent(xE)) - DeliverFocusedEvent(replayDev, xE, w, count); + if (!CheckDeviceGrabs(replayDev, event, i+1)) { + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); else - DeliverDeviceEvents(w, xE, NullGrab, NullWindow, - replayDev, count); + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); } goto playmore; } } /* must not still be in the same stack */ - if (replayDev->focus && !IsPointerEvent(xE)) - DeliverFocusedEvent(replayDev, xE, w, count); + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); else - DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count); + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); } playmore: for (dev = inputInfo.devices; dev; dev = dev->next) @@ -1467,7 +1428,7 @@ CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) The correct thing to do would be to freeze all SDs attached to the paired master device. */ - if (thisDev->isMaster) + if (IsMaster(thisDev)) { dev = GetPairedDevice(thisDev); if (otherMode == GrabModeSync) @@ -1483,6 +1444,54 @@ CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) ComputeFreezes(); } +/* Only ever used if a grab is called on an attached slave device. */ +static int GrabPrivateKeyIndex; +static DevPrivateKey GrabPrivateKey = &GrabPrivateKeyIndex; + +/** + * Save the device's master device in the devPrivates. This needs to be done + * if a client directly grabs a slave device that is attached to a master. For + * the duration of the grab, the device is detached, ungrabbing re-attaches it + * though. + * + * We store the ID of the master device only in case the master disappears + * while the device has a grab. + */ +static void +DetachFromMaster(DeviceIntPtr dev) +{ + int id; + if (!dev->u.master) + return; + + id = dev->u.master->id; + + dixSetPrivate(&dev->devPrivates, GrabPrivateKey, (void *)id); + AttachDevice(NULL, dev, NULL); +} + +static void +ReattachToOldMaster(DeviceIntPtr dev) +{ + int id; + void *p; + DeviceIntPtr master = NULL; + + if (IsMaster(dev)) + return; + + + p = dixLookupPrivate(&dev->devPrivates, GrabPrivateKey); + id = (int)p; /* silence gcc warnings */ + dixLookupDevice(&master, id, serverClient, DixUseAccess); + + if (master) + { + AttachDevice(serverClient, dev, master); + dixSetPrivate(&dev->devPrivates, GrabPrivateKey, NULL); + } +} + /** * Activate a pointer grab on the given device. A pointer grab will cause all * core pointer events of this device to be delivered to the grabbing client only. @@ -1508,6 +1517,11 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, : mouse->spriteInfo->sprite->win; Bool isPassive = autoGrab & ~ImplicitGrabMask; + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) + DetachFromMaster(mouse); + if (grab->confineTo) { if (grab->confineTo->drawable.pScreen @@ -1516,7 +1530,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, mouse->spriteInfo->sprite->hotPhys.y = 0; ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); } - DoEnterLeaveEvents(mouse, oldWin, grab->window, NotifyGrab); + DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); mouse->valuator->motionHintWindow = NullWindow; if (syncEvents.playingEvents) grabinfo->grabTime = syncEvents.time; @@ -1542,25 +1556,20 @@ DeactivatePointerGrab(DeviceIntPtr mouse) { GrabPtr grab = mouse->deviceGrab.grab; DeviceIntPtr dev; + Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && + mouse->deviceGrab.implicitGrab); mouse->valuator->motionHintWindow = NullWindow; mouse->deviceGrab.grab = NullGrab; mouse->deviceGrab.sync.state = NOT_GRABBED; mouse->deviceGrab.fromPassiveGrab = FALSE; - /* make sure the potential XGE event mask is freed too*/ - if (grab->genericMasks) - { - xfree(grab->genericMasks); - grab->genericMasks = NULL; - } - for (dev = inputInfo.devices; dev; dev = dev->next) { if (dev->deviceGrab.sync.other == grab) dev->deviceGrab.sync.other = NullGrab; } - DoEnterLeaveEvents(mouse, grab->window, + DoEnterLeaveEvents(mouse, mouse->id, grab->window, mouse->spriteInfo->sprite->win, NotifyUngrab); if (grab->confineTo) ConfineCursorToWindow(mouse, RootWindow(mouse), FALSE, FALSE); @@ -1568,6 +1577,9 @@ DeactivatePointerGrab(DeviceIntPtr mouse) if (grab->cursor) FreeCursor(grab->cursor, (Cursor)0); + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + ComputeFreezes(); } @@ -1582,6 +1594,12 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool pass GrabInfoPtr grabinfo = &keybd->deviceGrab; WindowPtr oldWin; + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(passive & ImplicitGrabMask) && + !IsMaster(keybd)) + DetachFromMaster(keybd); + if (grabinfo->grab) oldWin = grabinfo->grab->window; else if (keybd->focus) @@ -1589,7 +1607,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool pass else oldWin = keybd->spriteInfo->sprite->win; if (oldWin == FollowKeyboardWin) - oldWin = inputInfo.keyboard->focus->win; + oldWin = keybd->focus->win; if (keybd->valuator) keybd->valuator->motionHintWindow = NullWindow; DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); @@ -1600,6 +1618,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool pass grabinfo->activeGrab = *grab; grabinfo->grab = &grabinfo->activeGrab; grabinfo->fromPassiveGrab = passive; + grabinfo->implicitGrab = passive & ImplicitGrabMask; CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); } @@ -1613,6 +1632,8 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd) DeviceIntPtr dev; WindowPtr focusWin = keybd->focus ? keybd->focus->win : keybd->spriteInfo->sprite->win; + Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && + keybd->deviceGrab.implicitGrab); if (focusWin == FollowKeyboardWin) focusWin = inputInfo.keyboard->focus->win; @@ -1621,11 +1642,6 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd) keybd->deviceGrab.grab = NullGrab; keybd->deviceGrab.sync.state = NOT_GRABBED; keybd->deviceGrab.fromPassiveGrab = FALSE; - if (grab->genericMasks) - { - xfree(grab->genericMasks); - grab->genericMasks = NULL; - } for (dev = inputInfo.devices; dev; dev = dev->next) { @@ -1634,6 +1650,9 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd) } DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(keybd); + ComputeFreezes(); } @@ -1641,8 +1660,7 @@ void AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, - int newState, - Bool core) + int newState) { Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; TimeStamp grabTime; @@ -1748,7 +1766,7 @@ AllowSome(ClientPtr client, { if (dev == thisDev) continue; - devgrabinfo = (core) ? &dev->deviceGrab : &dev->deviceGrab; + devgrabinfo = &dev->deviceGrab; if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) devgrabinfo->sync.state = THAWED; @@ -1784,28 +1802,28 @@ ProcAllowEvents(ClientPtr client) switch (stuff->mode) { case ReplayPointer: - AllowSome(client, time, mouse, NOT_GRABBED, True); + AllowSome(client, time, mouse, NOT_GRABBED); break; case SyncPointer: - AllowSome(client, time, mouse, FREEZE_NEXT_EVENT, True); + AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); break; case AsyncPointer: - AllowSome(client, time, mouse, THAWED, True); + AllowSome(client, time, mouse, THAWED); break; case ReplayKeyboard: - AllowSome(client, time, keybd, NOT_GRABBED, True); + AllowSome(client, time, keybd, NOT_GRABBED); break; case SyncKeyboard: - AllowSome(client, time, keybd, FREEZE_NEXT_EVENT, True); + AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); break; case AsyncKeyboard: - AllowSome(client, time, keybd, THAWED, True); + AllowSome(client, time, keybd, THAWED); break; case SyncBoth: - AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT, True); + AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); break; case AsyncBoth: - AllowSome(client, time, keybd, THAWED_BOTH, True); + AllowSome(client, time, keybd, THAWED_BOTH); break; default: client->errorValue = stuff->mode; @@ -1868,7 +1886,7 @@ ReleaseActiveGrabs(ClientPtr client) * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the * client. */ -_X_EXPORT int +int TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, int count, Mask mask, Mask filter, GrabPtr grab) { @@ -1876,70 +1894,124 @@ TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, int type; #ifdef DEBUG_EVENTS - ErrorF("[dix] Event([%d, %d], mask=0x%x), client=%d", - pEvents->u.u.type, pEvents->u.u.detail, mask, client->index); + ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", + pEvents->u.u.type, pEvents->u.u.detail, mask, + client ? client->index : -1, + (client && client->clientGone) ? " (gone)" : ""); #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(dev->valuator->motionHintWindow) == - pEvents->u.keyButtonPointer.event) - { + + if (!client || client == serverClient || client->clientGone) { #ifdef DEBUG_EVENTS - ErrorF("[dix] \n"); - ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); + ErrorF(" not delivered to fake/dead client\n"); #endif - return 1; /* don't send, but pretend we did */ - } - pEvents->u.u.detail = NotifyHint; - } - else - { - pEvents->u.u.detail = NotifyNormal; - } - } - else - { - if ((type == DeviceMotionNotify) && - MaybeSendDeviceMotionNotifyHint - ((deviceKeyButtonPointer*)pEvents, mask) != 0) - return 1; - } - 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; - } + return 0; + } - if (BitIsOn(criticalEvents, type)) - { - if (client->smart_priority < SMART_MAX_PRIORITY) - client->smart_priority++; - SetCriticalOutputPending(); - } + if (filter != CantBeFiltered && !(mask & filter)) + { + #ifdef DEBUG_EVENTS + ErrorF(" filtered\n"); + #endif + return 0; + } + + if (grab && !SameClient(grab, client)) + { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered due to grab\n"); +#endif + return -1; /* don't send, but notify caller */ + } - WriteEventsToClient(client, count, pEvents); + type = pEvents->u.u.type; + if (type == MotionNotify) + { + if (mask & PointerMotionHintMask) + { + if (WID(dev->valuator->motionHintWindow) == + pEvents->u.keyButtonPointer.event) + { #ifdef DEBUG_EVENTS - ErrorF("[dix] delivered\n"); + ErrorF("[dix] \n"); + ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); #endif - return 1; + return 1; /* don't send, but pretend we did */ + } + pEvents->u.u.detail = NotifyHint; + } + else + { + pEvents->u.u.detail = NotifyNormal; + } } - else + else if (type == DeviceMotionNotify) + { + if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, + mask) != 0) + return 1; + } else if (type == KeyPress) { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + xEvent release = *pEvents; + release.u.u.type = KeyRelease; + release.u.u.sequenceNumber = client->sequence; + WriteEventsToClient(client, 1, &release); #ifdef DEBUG_EVENTS - ErrorF("[dix] \n"); + ErrorF(" (plus fake core release for repeat)"); #endif - return 0; + } else + { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + + } else if (type == DeviceKeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; + release.type = DeviceKeyRelease; + release.sequenceNumber = client->sequence; +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake xi1 release for repeat)"); +#endif + WriteEventsToClient(client, 1, (xEvent *) &release); + } + else { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#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)) + { + if (client->smart_priority < SMART_MAX_PRIORITY) + client->smart_priority++; + SetCriticalOutputPending(); + } + + WriteEventsToClient(client, count, pEvents); +#ifdef DEBUG_EVENTS + ErrorF("[dix] delivered\n"); +#endif + return 1; } /** @@ -1959,13 +2031,12 @@ TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, * @param count Number of elements in pEvents. * @param filter Mask based on event type. * @param grab Possible grab on the device that caused the event. - * @param mskidx Mask index, depending on device that caused event. * * @return Number of events delivered to various clients. */ int DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent - *pEvents, int count, Mask filter, GrabPtr grab, int mskidx) + *pEvents, int count, Mask filter, GrabPtr grab) { int deliveries = 0, nondeliveries = 0; int attempt; @@ -1975,17 +2046,16 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent 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) && type != GenericEvent)) + + /* Deliver to window owner */ + if ((filter == CantBeFiltered) || CORE_EVENT(pEvents)) { /* if nobody ever wants to see this event, skip some work */ if (filter != CantBeFiltered && !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) return 0; - if (!(type & EXTENSION_EVENT_BASE) && - IsInterferingGrab(wClient(pWin), pDev, pEvents)) + if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) return 0; if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) @@ -2003,80 +2073,51 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent nondeliveries--; } } + + /* CantBeFiltered means only window owner gets the event */ if (filter != CantBeFiltered) { - /* Handle generic events */ - if (type == GenericEvent) + if (CORE_EVENT(pEvents)) + other = (InputClients *)wOtherClients(pWin); + else if (XI2_EVENT(pEvents)) { - GenericMaskPtr gmask; - /* We don't do more than one GenericEvent at a time. */ - if (count > 1) - { - ErrorF("[dix] Do not send more than one GenericEvent at a time!\n"); + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!GetWindowXI2Mask(pDev, pWin, pEvents)) return 0; - } - - /* if we get here, filter should be set to the GE specific mask. - check if any client wants it */ - if (!GEDeviceMaskIsSet(pWin, pDev, GEEXT(pEvents), filter)) + other = inputMasks->inputClients; + } else { + OtherInputMasks *inputMasks = wOtherInputMasks(pWin); + /* Has any client selected for the event? */ + if (!inputMasks || + !(inputMasks->inputEvents[pDev->id] & filter)) return 0; - /* run through all clients, deliver event */ - for (gmask = GECLIENT(pWin); gmask; gmask = gmask->next) - { - if (gmask->eventMask[GEEXTIDX(pEvents)] & filter) - { - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(gmask), pWin, - pEvents, count)) - /* do nothing */; - else if (TryClientEvents(rClient(gmask), pDev, - pEvents, count, - gmask->eventMask[GEEXTIDX(pEvents)], - filter, grab) > 0) - { - deliveries++; - } else - nondeliveries--; - } - } + other = inputMasks->inputClients; } - else { - /* Traditional event */ - 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) + for (; other; other = other->next) + { + Mask mask; + if (IsInterferingGrab(rClient(other), pDev, pEvents)) + continue; + + mask = GetEventMask(pDev, pEvents, other); + + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, + pEvents, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(rClient(other), pDev, + pEvents, count, + mask, filter, grab)) ) { - /* core event? check for grab interference */ - if (!(type & EXTENSION_EVENT_BASE) && - IsInterferingGrab(rClient(other), pDev, pEvents)) - continue; - - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, - pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(rClient(other), pDev, - pEvents, count, - other->mask[mskidx], - filter, grab)) ) + if (attempt > 0) { - if (attempt > 0) - { - deliveries++; - client = rClient(other); - deliveryMask = other->mask[mskidx]; - } else - nondeliveries--; - } + deliveries++; + client = rClient(other); + deliveryMask = mask; + } else + nondeliveries--; } } } @@ -2084,13 +2125,15 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent * Note that since core events are delivered first, an implicit grab may * be activated on a core grab, stopping the XI events. */ - if ((type == DeviceButtonPress || type == ButtonPress) + if ((type == DeviceButtonPress || type == ButtonPress || + ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) && deliveries && (!grab)) { GrabRec tempGrab; OtherInputMasks *inputMasks; + memset(&tempGrab, 0, sizeof(GrabRec)); tempGrab.next = NULL; tempGrab.device = pDev; tempGrab.resource = client->clientAsMask; @@ -2101,27 +2144,25 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent tempGrab.pointerMode = GrabModeAsync; tempGrab.confineTo = NullWindow; tempGrab.cursor = NullCursor; - tempGrab.coreGrab = (type == ButtonPress); + tempGrab.type = type; + if (type == ButtonPress) + tempGrab.grabtype = GRABTYPE_CORE; + else if (type == DeviceButtonPress) + tempGrab.grabtype = GRABTYPE_XI; + else + { + tempGrab.type = ((xGenericEvent*)pEvents)->evtype; + tempGrab.grabtype = GRABTYPE_XI2; + } - /* get the XI device mask */ + /* get the XI and XI2 device mask */ inputMasks = wOtherInputMasks(pWin); tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; - /* get the XGE event mask. */ - tempGrab.genericMasks = NULL; - if (pWin->optional && pWin->optional->geMasks) - { - GenericClientMasksPtr gemasks = pWin->optional->geMasks; - GenericMaskPtr geclient = gemasks->geClients; - while(geclient && rClient(geclient) != client) - geclient = geclient->next; - if (geclient) - { - tempGrab.genericMasks = xcalloc(1, sizeof(GenericMaskRec)); - *tempGrab.genericMasks = *geclient; - tempGrab.genericMasks->next = NULL; - } - } + if (inputMasks) + memcpy(tempGrab.xi2mask, inputMasks->xi2mask, + sizeof(tempGrab.xi2mask)); + (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, currentTime, TRUE | ImplicitGrabMask); } @@ -2129,11 +2170,8 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent pDev->valuator->motionHintWindow = pWin; else { - if (((type == DeviceMotionNotify) -#ifdef XKB - || (type == DeviceButtonPress) -#endif - ) && deliveries) + if ((type == DeviceMotionNotify || type == DeviceButtonPress) && + deliveries) CheckDeviceGrabAndHintWindow (pWin, type, (deviceKeyButtonPointer*) pEvents, grab, client, deliveryMask); @@ -2217,6 +2255,37 @@ MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, return 2; } +static Window FindChildForEvent(DeviceIntPtr dev, WindowPtr event) +{ + SpritePtr pSprite = dev->spriteInfo->sprite; + WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; + Window child = None; + + /* 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 == event) + { + child = None; + break; + } + + if (w->parent == event) + { + child = w->drawable.id; + break; + } + w = w->parent; + } + return child; +} + /** * Adjust event fields to comply with the window properties. * @@ -2225,7 +2294,7 @@ MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, * @param child Child window setting for event (if applicable) * @param calcChild If True, calculate the child window. */ -static void +void FixUpEventFromWindow( DeviceIntPtr pDev, xEvent *xE, @@ -2235,59 +2304,141 @@ FixUpEventFromWindow( { SpritePtr pSprite = pDev->spriteInfo->sprite; - if (xE->u.u.type == GenericEvent) /* just a safety barrier */ - return; - if (calcChild) + child = FindChildForEvent(pDev, pWin); + + if (XI2_EVENT(xE)) { - WindowPtr w= pSprite->spriteTrace[pSprite->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. */ + xXIDeviceEvent* event = (xXIDeviceEvent*)xE; + + if (event->evtype == XI_RawKeyPress || + event->evtype == XI_RawKeyRelease || + event->evtype == XI_RawButtonPress || + event->evtype == XI_RawButtonRelease || + event->evtype == XI_RawMotion || + event->evtype == XI_DeviceChanged || + event->evtype == XI_HierarchyChanged || + event->evtype == XI_PropertyEvent) + return; - while (w) + event->root = RootWindow(pDev)->drawable.id; + event->event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); + event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); + event->child = child; + } else { - /* 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. */ + event->event_x = 0; + event->event_y = 0; + event->child = None; + } - if (w == pWin) - { - child = None; - break; - } + if (event->evtype == XI_Enter || event->evtype == XI_Leave || + event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) + ((xXIEnterEvent*)event)->same_screen = + (pSprite->hot.pScreen == pWin->drawable.pScreen); - if (w->parent == pWin) - { - child = w->drawable.id; - break; - } - w = w->parent; - } - } - XE_KBPTR.root = RootWindow(pDev)->drawable.id; - XE_KBPTR.event = pWin->drawable.id; - if (pSprite->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 + } else { - XE_KBPTR.sameScreen = xFalse; - XE_KBPTR.child = None; - XE_KBPTR.eventX = 0; - XE_KBPTR.eventY = 0; + XE_KBPTR.root = RootWindow(pDev)->drawable.id; + XE_KBPTR.event = pWin->drawable.id; + if (pSprite->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; + } } } /** - * Deliver events caused by input devices. Called for both core input events - * and XI events. + * Return masks for EventIsDeliverable. + * @defgroup EventIsDeliverable return flags + * @{ + */ +#define XI_MASK (1 << 0) /**< XI mask set on window */ +#define CORE_MASK (1 << 1) /**< Core mask set on window */ +#define DONT_PROPAGATE_MASK (1 << 2) /**< DontPropagate mask set on window */ +#define XI2_MASK (1 << 3) /**< XI2 mask set on window */ +/* @} */ + +/** + * Check if a given event is deliverable at all on a given window. + * + * This function only checks if any client wants it, not for a specific + * client. + * + * @param[in] dev The device this event is being sent for. + * @param[in] event The event that is to be sent. + * @param[in] win The current event window. + * + * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and + * ::DONT_PROPAGATE_MASK. + */ +static int +EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) +{ + int rc = 0; + int filter = 0; + int type; + OtherInputMasks *inputMasks = wOtherInputMasks(win); + xEvent ev; + + /* XXX: this makes me gag */ + type = GetXI2Type(event); + ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ + ((xGenericEvent*)&ev)->extension = IReqCode; + ((xGenericEvent*)&ev)->evtype = type; + filter = GetEventFilter(dev, &ev); + if (type && inputMasks && + ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || + ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || + (inputMasks->xi2mask[dev->id][type/8] & filter))) + rc |= XI2_MASK; + + type = GetXIType(event); + ev.u.u.type = type; + filter = GetEventFilter(dev, &ev); + + /* Check for XI mask */ + if (type && inputMasks && + (inputMasks->deliverableEvents[dev->id] & filter) && + (inputMasks->inputEvents[dev->id] & filter)) + rc |= XI_MASK; + + /* Check for XI DontPropagate mask */ + if (type && inputMasks && + (inputMasks->dontPropagateMask[dev->id] & filter)) + rc |= DONT_PROPAGATE_MASK; + + /* Check for core mask */ + type = GetCoreType(event); + if (type && (win->deliverableEvents & filter) && + ((wOtherEventMasks(win) | win->eventMask) & filter)) + rc |= CORE_MASK; + + /* Check for core DontPropagate mask */ + if (type && (filter & wDontPropagateMask(win))) + rc |= DONT_PROPAGATE_MASK; + + return rc; +} + +/** + * Deliver events caused by input devices. + * * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is * called directly from the processInputProc. * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call @@ -2296,112 +2447,108 @@ FixUpEventFromWindow( * DeliverDeviceEvents. * * @param pWin Window to deliver event to. - * @param xE Events to deliver. + * @param event The events to deliver, not yet in wire format. * @param grab Possible grab on a device. * @param stopAt Don't recurse up to the root window. * @param dev The device that is responsible for the event. - * @param count number of events in xE. * * @see DeliverGrabbedEvent * @see DeliverFocusedEvent */ int -DeliverDeviceEvents(WindowPtr pWin, xEvent *xE, GrabPtr grab, - WindowPtr stopAt, DeviceIntPtr dev, int count) +DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, + WindowPtr stopAt, DeviceIntPtr dev) { Window child = None; - int type = xE->u.u.type; - Mask filter = filters[dev->id][type]; + Mask filter; int deliveries = 0; - OtherInputMasks *inputMasks; - int mskidx = dev->id; xEvent core; + xEvent *xE = NULL; + int rc, mask, count = 0; - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count)) - return 0; + CHECKEVENT(event); - /* handle generic events */ - /* XXX: Generic events aren't quite handled correctly yet. They should - * eventually fit in with the rest of the stuff - */ - if (type == GenericEvent) + while (pWin) { - WindowPtr win = pWin; - xGenericEvent* ge = (xGenericEvent*)xE; - - if (count > 1) + if ((mask = EventIsDeliverable(dev, event, pWin))) { - ErrorF("[dix] Do not send more than one GenericEvent at a time!\n"); - return 0; - } - filter = generic_filters[GEEXTIDX(xE)][ge->evtype]; - - while(win) - { - if (GEDeviceMaskIsSet(win, dev, GEEXT(xE), filter)) + /* XI2 events first */ + if (mask & XI2_MASK) { - if (GEExtensions[GEEXTIDX(xE)].evfill) - GEExtensions[GEEXTIDX(xE)].evfill(ge, dev, win, grab); - deliveries = DeliverEventsToWindow(dev, win, xE, count, - filter, grab, 0); - if (deliveries > 0) - return deliveries; + xEvent *xi2 = NULL; + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + filter = GetEventFilter(dev, xi2); + FixUpEventFromWindow(dev, xi2, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, + filter, grab); + xfree(xi2); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", + dev->name, rc); } - win = win->parent; - } - } - - while (pWin && type != GenericEvent) - { - if (!dev->isMaster) - { - inputMasks = wOtherInputMasks(pWin); - if (inputMasks && (filter & inputMasks->deliverableEvents[mskidx])) + /* XI events */ + if (mask & XI_MASK) { - - if (inputMasks && (inputMasks->inputEvents[mskidx] & filter)) + rc = EventToXI(event, &xE, &count); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { + filter = GetEventFilter(dev, xE); FixUpEventFromWindow(dev, xE, pWin, child, FALSE); deliveries = DeliverEventsToWindow(dev, pWin, xE, count, - filter, grab, mskidx); + filter, grab); if (deliveries > 0) - return deliveries; - } + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", + dev->name, event->any.type, rc); } - if ((deliveries < 0) || (pWin == stopAt) || - (inputMasks && (filter & inputMasks->dontPropagateMask[mskidx]))) - return 0; - } else - { - core = *xE; - core.u.u.type = XItoCoreType(xE->u.u.type); - - if (core.u.u.type && filter & pWin->deliverableEvents) + /* Core event */ + if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) { - if ((wOtherEventMasks(pWin)|pWin->eventMask) & filter) + rc = EventToCore(event, &core); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { + filter = GetEventFilter(dev, &core); FixUpEventFromWindow(dev, &core, pWin, child, FALSE); deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, - filter, grab, 0); + filter, grab); if (deliveries > 0) - return deliveries; - } + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", + dev->name, event->any.type, rc); } if ((deliveries < 0) || (pWin == stopAt) || - (filter & wDontPropagateMask(pWin))) - return 0; + (mask & DONT_PROPAGATE_MASK)) + { + deliveries = 0; + goto unwind; + } } child = pWin->drawable.id; pWin = pWin->parent; } - return 0; +unwind: + xfree(xE); + return deliveries; } +#undef XI_MASK +#undef CORE_MASK +#undef DONT_PROPAGATE_MASK + /** * Deliver event to a window and it's immediate parent. Used for most window * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that @@ -2415,12 +2562,13 @@ DeliverDeviceEvents(WindowPtr pWin, xEvent *xE, GrabPtr grab, * @param count number of events in xE. * @param otherParent Used for ReparentNotify events. */ -_X_EXPORT int +int DeliverEvents(WindowPtr pWin, xEvent *xE, int count, WindowPtr otherParent) { Mask filter; int deliveries; + DeviceIntRec dummy; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) @@ -2429,27 +2577,26 @@ DeliverEvents(WindowPtr pWin, xEvent *xE, int count, if (!count) return 0; - /* We don't know a device here. However, this should only ever be called - for a non-device event so we are safe to use 0*/ - filter = filters[0][xE->u.u.type]; + + dummy.id = XIAllDevices; + filter = GetEventFilter(&dummy, xE); if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) xE->u.destroyNotify.event = pWin->drawable.id; if (filter != StructureAndSubMask) - return DeliverEventsToWindow(inputInfo.pointer, pWin, xE, count, filter, NullGrab, 0); - deliveries = DeliverEventsToWindow(inputInfo.pointer, pWin, xE, count, StructureNotifyMask, - NullGrab, 0); + return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); + deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, + StructureNotifyMask, NullGrab); if (pWin->parent) { xE->u.destroyNotify.event = pWin->parent->drawable.id; - deliveries += DeliverEventsToWindow(inputInfo.pointer, pWin->parent, xE, count, - SubstructureNotifyMask, NullGrab, - 0); + deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, + SubstructureNotifyMask, NullGrab); if (xE->u.u.type == ReparentNotify) { xE->u.destroyNotify.event = otherParent->drawable.id; - deliveries += DeliverEventsToWindow(inputInfo.pointer, + deliveries += DeliverEventsToWindow(&dummy, otherParent, xE, count, SubstructureNotifyMask, - NullGrab, 0); + NullGrab); } } return deliveries; @@ -2548,6 +2695,85 @@ XYToWindow(DeviceIntPtr pDev, int x, int y) } /** + * Ungrab a currently FocusIn grabbed device and grab the device on the + * given window. If the win given is the NoneWin, the device is ungrabbed if + * applicable and FALSE is returned. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +BOOL +ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab && + dev->deviceGrab.fromPassiveGrab && + dev->deviceGrab.grab->type == XI_Enter) + { + if (dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + if (win == NoneWin || win == PointerRootWin) + return FALSE; + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_FocusIn; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +} + +/** + * Ungrab a currently Enter grabbed device and grab the device for the given + * window. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +static BOOL +ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab && + dev->deviceGrab.fromPassiveGrab && + dev->deviceGrab.grab->type == XI_Enter) + { + if (dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_Enter; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = CheckPassiveGrabsOnWindow(win, dev, &event, FALSE); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + + return rc; +} + +/** * Update the sprite coordinates based on the event. Update the cursor * position, then update the event with the new coordinates that may have been * changed. If the window underneath the sprite has changed, change to new @@ -2559,51 +2785,53 @@ XYToWindow(DeviceIntPtr pDev, int x, int y) * @return TRUE if the sprite has moved or FALSE otherwise. */ Bool -CheckMotion(xEvent *xE, DeviceIntPtr pDev) +CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) { - INT16 *rootX, *rootY; - WindowPtr prevSpriteWin; + WindowPtr prevSpriteWin, newSpriteWin; SpritePtr pSprite = pDev->spriteInfo->sprite; - prevSpriteWin = pSprite->win; + CHECKEVENT(ev); -#ifdef PANORAMIX - if(!noPanoramiXExtension) - return XineramaCheckMotion(xE, pDev); -#endif + prevSpriteWin = pSprite->win; - if (xE && !syncEvents.playingEvents) + if (ev && !syncEvents.playingEvents) { /* GetPointerEvents() guarantees that pointer events have the correct rootX/Y set already. */ - switch(xE->u.u.type) + switch (ev->type) { - case ButtonPress: - case ButtonRelease: - case MotionNotify: - rootX = &XE_KBPTR.rootX; - rootY = &XE_KBPTR.rootY; + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: break; default: - if (xE->u.u.type == DeviceButtonPress || - xE->u.u.type == DeviceButtonRelease || - xE->u.u.type == DeviceMotionNotify) - { - rootX = &((deviceKeyButtonPointer*)xE)->root_x; - rootY = &((deviceKeyButtonPointer*)xE)->root_y; - break; - } /* all other events return FALSE */ return FALSE; } - if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* Motion events entering DIX get translated to Screen 0 + coordinates. Replayed events have already been + translated since they've entered DIX before */ + ev->root_x += panoramiXdataPtr[pSprite->screen->myNum].x - + panoramiXdataPtr[0].x; + ev->root_y += panoramiXdataPtr[pSprite->screen->myNum].y - + panoramiXdataPtr[0].y; + } else +#endif { - pSprite->hot.pScreen = pSprite->hotPhys.pScreen; - RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; + if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) + { + pSprite->hot.pScreen = pSprite->hotPhys.pScreen; + RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum]; + } } - pSprite->hot.x = *rootX; - pSprite->hot.y = *rootY; + + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; if (pSprite->hot.x < pSprite->physLimits.x1) pSprite->hot.x = pSprite->physLimits.x1; else if (pSprite->hot.x >= pSprite->physLimits.x2) @@ -2616,36 +2844,48 @@ CheckMotion(xEvent *xE, DeviceIntPtr pDev) ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); pSprite->hotPhys = pSprite->hot; - if ((pSprite->hotPhys.x != *rootX) || - (pSprite->hotPhys.y != *rootY)) + if ((pSprite->hotPhys.x != ev->root_x) || + (pSprite->hotPhys.y != ev->root_y)) { - (*pSprite->hotPhys.pScreen->SetCursorPosition)( - pDev, pSprite->hotPhys.pScreen, - pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + XineramaSetCursorPosition( + pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } else +#endif + { + (*pSprite->hotPhys.pScreen->SetCursorPosition)( + pDev, pSprite->hotPhys.pScreen, + pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } } - *rootX = pSprite->hot.x; - *rootY = pSprite->hot.y; + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; } - pSprite->win = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); -#ifdef notyet - if (!(pSprite->win->deliverableEvents & - Motion_Filter(pDev->button)) - !syncEvents.playingEvents) - { - /* XXX Do PointerNonInterestBox here */ - } -#endif - if (pSprite->win != prevSpriteWin) + newSpriteWin = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y); + + if (newSpriteWin != prevSpriteWin) { + int sourceid; + if (!ev) { + UpdateCurrentTimeIf(); + sourceid = pDev->id; /* when from WindowsRestructured */ + } else + sourceid = ev->sourceid; + if (prevSpriteWin != NullWindow) { - if (!xE) - UpdateCurrentTimeIf(); - DoEnterLeaveEvents(pDev, prevSpriteWin, pSprite->win, - NotifyNormal); + if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) + DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, + newSpriteWin, NotifyNormal); } - PostNewCursor(pDev); + /* set pSprite->win after ActivateEnterGrab, otherwise + sprite window == grab_window and no enter/leave events are + sent. */ + pSprite->win = newSpriteWin; + PostNewCursor(pDev); return FALSE; } return TRUE; @@ -2661,7 +2901,7 @@ WindowsRestructured(void) DeviceIntPtr pDev = inputInfo.devices; while(pDev) { - if (pDev->isMaster || !pDev->u.master) + if (IsMaster(pDev) || !pDev->u.master) CheckMotion(NULL, pDev); pDev = pDev->next; } @@ -2722,17 +2962,6 @@ void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) #endif /** - * Called from main() with the root window on the first screen. Used to do a - * lot more when MPX wasn't around yet. Things change. - * - * Should delete this now? -ds - */ -void -DefineInitialRootWindow(WindowPtr win) -{ -} - -/** * Initialize a sprite for the given device and set it to some sane values. If * the device already has a sprite alloc'd, don't realloc but just reset to * default values. @@ -2925,7 +3154,7 @@ WindowHasNewCursor(WindowPtr pWin) PostNewCursor(pDev); } -_X_EXPORT void +void NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) { SpritePtr pSprite = pDev->spriteInfo->sprite; @@ -3090,22 +3319,22 @@ ProcWarpPointer(ClientPtr client) WindowPtr dest = NULL; int x, y, rc; ScreenPtr newScreen; - DeviceIntPtr dev; + DeviceIntPtr dev, tmp; SpritePtr pSprite; REQUEST(xWarpPointerReq); REQUEST_SIZE_MATCH(xWarpPointerReq); - /* XXX XACE ??*/ - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { + dev = PickPointer(client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); if (rc != Success) return rc; } } - dev = PickPointer(client); if (dev->u.lastSlave) dev = dev->u.lastSlave; pSprite = dev->spriteInfo->sprite; @@ -3213,113 +3442,130 @@ BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) * * @param pWin The window that may be subject to a passive grab. * @param device Device that caused the event. - * @param xE List of events (multiple ones for DeviceMotionNotify) - * @param count number of elements in xE. - * @param store The event that will be stored on the device (always XI) - * @param scount number of elements in store. + * @param event The current device event. + * @param checkCore Check for core grabs too. */ static Bool CheckPassiveGrabsOnWindow( WindowPtr pWin, DeviceIntPtr device, - xEvent *xE, - int count, - xEvent *store, - int scount) + DeviceEvent *event, + BOOL checkCore) { GrabPtr grab = wPassiveGrabs(pWin); GrabRec tempGrab; GrabInfoPtr grabinfo; - xEvent *dxE; +#define CORE_MATCH 0x1 +#define XI_MATCH 0x2 +#define XI2_MATCH 0x4 + int match = 0; + + if (device->deviceGrab.grab) + return FALSE; if (!grab) return FALSE; + /* Fill out the grab details, but leave the type for later before + * comparing */ tempGrab.window = pWin; tempGrab.device = device; - tempGrab.type = xE->u.u.type; - tempGrab.detail.exact = xE->u.u.detail; + tempGrab.detail.exact = event->detail.key; tempGrab.detail.pMask = NULL; tempGrab.modifiersDetail.pMask = NULL; tempGrab.next = NULL; for (; grab; grab = grab->next) { -#ifdef XKB DeviceIntPtr gdev; XkbSrvInfoPtr xkbi = NULL; + Mask mask = 0; gdev= grab->modifierDevice; - if (grab->coreGrab) + if (grab->grabtype == GRABTYPE_CORE) { if (IsPointerDevice(device)) gdev = GetPairedDevice(device); else gdev = device; + } else if (grab->grabtype == GRABTYPE_XI2) + { + /* if the device is an attached slave device, gdev must be the + * attached master keyboard. Since the slave may have been + * reattached after the grab, the modifier device may not be the + * same. */ + if (!IsMaster(grab->device) && device->u.master) + gdev = GetMaster(device, MASTER_KEYBOARD); } + + if (gdev && gdev->key) xkbi= gdev->key->xkbInfo; -#endif tempGrab.modifierDevice = grab->modifierDevice; - if ((device == grab->modifierDevice) && - ((xE->u.u.type == KeyPress) || (xE->u.u.type == DeviceKeyPress))) - tempGrab.modifiersDetail.exact = -#ifdef XKB - (noXkbExtension) ? - ((gdev) ? gdev->key->prev_state : 0) : - ((xkbi) ? xkbi->state.grab_mods : 0); -#else - (gdev) ? gdev->key->prev_state : 0; -#endif - else - tempGrab.modifiersDetail.exact = -#ifdef XKB - (noXkbExtension) ? - ((gdev) ? gdev->key->state : 0) : - ((xkbi) ? xkbi->state.grab_mods : 0); -#else - (gdev) ? gdev->key->state : 0; -#endif - /* ignore the device for core events when comparing grabs */ - if (GrabMatchesSecond(&tempGrab, grab, (xE->u.u.type < LASTEvent)) && - (!grab->confineTo || + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ + tempGrab.type = GetXI2Type((InternalEvent*)event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + + tempGrab.detail.exact = event->detail.key; + if (!match) + { + tempGrab.type = GetXIType((InternalEvent*)event); + tempGrab.grabtype = GRABTYPE_XI; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI_MATCH; + } + + /* Check for a core grab (ignore the device when comparing) */ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; + if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + + if (match && (!grab->confineTo || (grab->confineTo->realized && BorderSizeNotEmpty(device, grab->confineTo)))) { -#ifdef XKB - if (!noXkbExtension) { - XE_KBPTR.state &= 0x1f00; - XE_KBPTR.state |= - tempGrab.modifiersDetail.exact&(~0x1f00); - } -#endif - grabinfo = &device->deviceGrab; - /* A passive grab may have been created for a different device - than it is assigned to at this point in time. - Update the grab's device and modifier device to reflect the - current state. - Since XGrabDeviceButton requires to specify the - modifierDevice explicitly, we don't override this choice. - */ - if (xE->u.u.type < LASTEvent) - { - grab->device = device; - grab->modifierDevice = GetPairedDevice(device); - } + int rc, count = 0; + xEvent *xE = NULL; + xEvent core; + event->corestate &= 0x1f00; + event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); + grabinfo = &device->deviceGrab; /* In some cases a passive core grab may exist, but the client * already has a core grab on some other device. In this case we * must not get the grab, otherwise we may never ungrab the * device. */ - if (grab->coreGrab) + if (grab->grabtype == GRABTYPE_CORE) { DeviceIntPtr other; BOOL interfering = FALSE; + + /* A passive grab may have been created for a different device + than it is assigned to at this point in time. + Update the grab's device and modifier device to reflect the + current state. + Since XGrabDeviceButton requires to specify the + modifierDevice explicitly, we don't override this choice. + */ + if (tempGrab.type < GenericEvent) + { + grab->device = device; + grab->modifierDevice = GetPairedDevice(device); + } + for (other = inputInfo.devices; other; other = other->next) { GrabPtr othergrab = other->deviceGrab.grab; - if (othergrab && othergrab->coreGrab && + if (othergrab && othergrab->grabtype == GRABTYPE_CORE && SameClient(grab, rClient(othergrab)) && ((IsPointerDevice(grab->device) && IsPointerDevice(othergrab->device)) || @@ -3335,31 +3581,80 @@ CheckPassiveGrabsOnWindow( } + if (match & CORE_MATCH) + { + rc = EventToCore((InternalEvent*)event, &core); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + xE = &core; + count = 1; + mask = grab->eventMask; + } else if (match & XI2_MATCH) + { + rc = EventToXI2((InternalEvent*)event, &xE); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + count = 1; + + /* FIXME: EventToXI2 returns NULL for enter events, so + * dereferencing the event is bad. Internal event types are + * aligned with core events, so the else clause is valid. + * long-term we should use internal events for enter/focus + * as well */ + if (xE) + mask = grab->xi2mask[device->id][((xGenericEvent*)xE)->evtype/8]; + else if (event->type == XI_Enter || event->type == XI_FocusIn) + mask = grab->xi2mask[device->id][event->type/8]; + } else + { + rc = EventToXI((InternalEvent*)event, &xE, &count); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->type, rc); + continue; + } + mask = grab->eventMask; + } + (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); - FixUpEventFromWindow(device, xE, grab->window, None, TRUE); + if (xE) + { + FixUpEventFromWindow(device, xE, grab->window, None, TRUE); - (void) TryClientEvents(rClient(grab), device, xE, count, - filters[device->id][xE->u.u.type], - filters[device->id][xE->u.u.type], grab); + TryClientEvents(rClient(grab), device, xE, count, mask, + GetEventFilter(device, xE), grab); + } if (grabinfo->sync.state == FROZEN_NO_EVENT) { - if (grabinfo->sync.evcount < scount) - { - grabinfo->sync.event = xrealloc(grabinfo->sync.event, - scount * sizeof(xEvent)); - } - grabinfo->sync.evcount = scount; - /* we always store the XI event, never the core event */ - for (dxE = grabinfo->sync.event; --scount >= 0; dxE++, store++) - *dxE = *store; + if (!grabinfo->sync.event) + grabinfo->sync.event = xcalloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = *event; grabinfo->sync.state = FROZEN_WITH_EVENT; } + + if (match & (XI_MATCH | XI2_MATCH)) + xfree(xE); /* on core match xE == &core */ return TRUE; } } return FALSE; +#undef CORE_MATCH +#undef XI_MATCH +#undef XI2_MATCH } /** @@ -3389,33 +3684,20 @@ CheckPassiveGrabsOnWindow( */ Bool -CheckDeviceGrabs(DeviceIntPtr device, xEvent *xE, - int checkFirst, int count) +CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, int checkFirst) { int i; WindowPtr pWin = NULL; - FocusClassPtr focus = IsPointerEvent(xE) ? NULL : device->focus; - xEvent core; - BOOL sendCore = (device->isMaster && device->coreEvents); - - if ((xE->u.u.type == DeviceButtonPress) - && (device->button->buttonsDown != 1)) - return FALSE; + FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); - if (xE->u.u.type < EXTENSION_EVENT_BASE) - { - ErrorF("[dix] Core event passed into CheckDeviceGrabs.\n"); + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) return FALSE; - } - - if (sendCore) - { - core = *xE; - core.u.u.type = XItoCoreType(xE->u.u.type); - if(!core.u.u.type) /* probably a Proximity event, can't grab for those */ - return FALSE; - } + if (event->type == ET_ButtonPress + && (device->button->buttonsDown != 1)) + return FALSE; i = checkFirst; @@ -3424,11 +3706,8 @@ CheckDeviceGrabs(DeviceIntPtr device, xEvent *xE, for (; i < focus->traceGood; i++) { pWin = focus->trace[i]; - /* XI grabs have precendence */ if (pWin->optional && - (CheckPassiveGrabsOnWindow(pWin, device, xE, count, xE, count) - || (sendCore && CheckPassiveGrabsOnWindow(pWin, device, &core, - 1, xE, count)))) + CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) return TRUE; } @@ -3443,9 +3722,7 @@ CheckDeviceGrabs(DeviceIntPtr device, xEvent *xE, { pWin = device->spriteInfo->sprite->spriteTrace[i]; if (pWin->optional && - (CheckPassiveGrabsOnWindow(pWin, device, xE, count, xE, count) || - (sendCore && CheckPassiveGrabsOnWindow(pWin, device, &core, 1, - xE, count)))) + CheckPassiveGrabsOnWindow(pWin, device, event, sendCore)) return TRUE; } @@ -3454,21 +3731,24 @@ CheckDeviceGrabs(DeviceIntPtr device, xEvent *xE, /** * Called for keyboard events to deliver event to whatever client owns the - * focus. Event is delivered to the keyboard's focus window, the root window - * or to the window owning the input focus. + * focus. + * + * The event is delivered to the keyboard's focus window, the root window or + * to the window owning the input focus. * * @param keybd The keyboard originating the event. - * @param xE The event list. + * @param event The event, not yet in wire format. * @param window Window underneath the sprite. - * @param count number of events in xE. */ void -DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count) +DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) { - DeviceIntPtr pointer; + DeviceIntPtr ptr; WindowPtr focus = keybd->focus->win; - BOOL sendCore = (keybd->isMaster && keybd->coreEvents); + BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); xEvent core; + xEvent *xE = NULL, *xi2 = NULL; + int count, rc; int deliveries = 0; if (focus == FollowKeyboardWin) @@ -3477,40 +3757,69 @@ DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count) return; if (focus == PointerRootWin) { - DeliverDeviceEvents(window, xE, NullGrab, NullWindow, keybd, count); + DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); return; } if ((focus == window) || IsParent(focus, window)) { - if (DeliverDeviceEvents(window, xE, NullGrab, focus, keybd, count)) + if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) return; } - pointer = GetPairedDevice(keybd); - if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count)) - return; - - if (sendCore) - { - core = *xE; - core.u.u.type = XItoCoreType(xE->u.u.type); - } /* just deliver it to the focus window */ - FixUpEventFromWindow(pointer, xE, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xE, count, - filters[keybd->id][xE->u.u.type], - NullGrab, keybd->id); - - if (deliveries > 0) - return; + ptr = GetPairedDevice(keybd); + + + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + int filter = GetEventFilter(keybd, xi2); + FixUpEventFromWindow(ptr, xi2, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, + filter, NullGrab); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + rc = EventToXI(event, &xE, &count); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) + { + FixUpEventFromWindow(ptr, xE, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xE, count, + GetEventFilter(keybd, xE), + NullGrab); + + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); - if (sendCore && core.u.u.type) + if (sendCore) { - FixUpEventFromWindow(keybd, &core, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, - filters[keybd->id][xE->u.u.type], - NullGrab, 0); - } + rc = EventToCore(event, &core); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) + { + FixUpEventFromWindow(keybd, &core, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, + GetEventFilter(keybd, &core), + NullGrab); + } else if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + } + +unwind: + if (xE) + xfree(xE); + if (xi2) + xfree(xi2); + return; } /** @@ -3521,16 +3830,18 @@ DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count) * @param deactivateGrab True if the device's grab should be deactivated. */ void -DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev, - Bool deactivateGrab, int count) +DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, + Bool deactivateGrab) { GrabPtr grab; GrabInfoPtr grabinfo; int deliveries = 0; DeviceIntPtr dev; - xEvent *dxE, core; SpritePtr pSprite = thisDev->spriteInfo->sprite; BOOL sendCore = FALSE; + int rc, count = 0; + xEvent *xi = NULL; + xEvent *xi2 = NULL; grabinfo = &thisDev->deviceGrab; grab = grabinfo->grab; @@ -3543,14 +3854,9 @@ DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev, * for the type of event, to see if we really want to deliver it to * the focus window. For pointer events, the answer is no. */ - if (xE->u.u.type == DeviceButtonPress || - xE->u.u.type == DeviceButtonRelease || - xE->u.u.type == DeviceMotionNotify || - xE->u.u.type == ProximityIn || - xE->u.u.type == ProximityOut) - { + if (IsPointerEvent(event)) focus = PointerRootWin; - } else if (thisDev->focus) + else if (thisDev->focus) { focus = thisDev->focus->win; if (focus == FollowKeyboardWin) @@ -3559,75 +3865,112 @@ DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev, else focus = PointerRootWin; if (focus == PointerRootWin) - deliveries = DeliverDeviceEvents(pSprite->win, xE, grab, - NullWindow, thisDev, count); + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, + NullWindow, thisDev); else if (focus && (focus == pSprite->win || IsParent(focus, pSprite->win))) - deliveries = DeliverDeviceEvents(pSprite->win, xE, grab, focus, - thisDev, count); + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, + thisDev); else if (focus) - deliveries = DeliverDeviceEvents(focus, xE, grab, focus, - thisDev, count); + deliveries = DeliverDeviceEvents(focus, event, grab, focus, + thisDev); } if (!deliveries) { + Mask mask; + + /* XXX: In theory, we could pass the internal events through to + * everything and only convert just before hitting the wire. We can't + * do that yet, so DGE is the last stop for internal events. From here + * onwards, we deal with core/XI events. + */ + + mask = grab->eventMask; + + sendCore = (IsMaster(thisDev) && thisDev->coreEvents); + /* try core event */ + if (sendCore && grab->grabtype == GRABTYPE_CORE) { - Mask mask = grab->eventMask; + xEvent core; - if (thisDev->isMaster) + rc = EventToCore(event, &core); + if (rc == Success) { - core = *xE; - core.u.u.type = XItoCoreType(xE->u.u.type); - if(core.u.u.type) { - FixUpEventFromWindow(thisDev, &core, grab->window, - None, TRUE); - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, &core, 1) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, &core, 1)) - deliveries = 1; /* don't send, but pretend we did */ - else if (!IsInterferingGrab(rClient(grab), thisDev, - &core)) - { - deliveries = TryClientEvents(rClient(grab), thisDev, - &core, 1, mask, - filters[thisDev->id][core.u.u.type], - grab); - } + FixUpEventFromWindow(thisDev, &core, grab->window, + None, TRUE); + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, &core, 1) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, &core, 1)) + deliveries = 1; /* don't send, but pretend we did */ + else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) + { + deliveries = TryClientEvents(rClient(grab), thisDev, + &core, 1, mask, + GetEventFilter(thisDev, &core), + grab); } - } else + } else if (rc != BadMatch) + ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); + } + + if (!deliveries) + { + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + int evtype = ((xGenericEvent*)xi2)->evtype; + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(thisDev, xi2, grab->window, None, TRUE); + /* XXX: XACE */ + deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, + GetEventFilter(thisDev, xi2), grab); + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (!deliveries) + { + rc = EventToXI(event, &xi, &count); + if (rc == Success) { /* try XI event */ if (grabinfo->fromPassiveGrab && - grabinfo->implicitGrab && - (xE->u.u.type & EXTENSION_EVENT_BASE)) + grabinfo->implicitGrab) mask = grab->deviceMask; - FixUpEventFromWindow(thisDev, xE, grab->window, + else + mask = grab->eventMask; + + FixUpEventFromWindow(thisDev, xi, grab->window, None, TRUE); if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, xE, count) || + grab->window, xi, count) || XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, xE, count)) + grab->window, xi, count)) deliveries = 1; /* don't send, but pretend we did */ else { deliveries = TryClientEvents(rClient(grab), thisDev, - xE, count, + xi, count, mask, - filters[thisDev->id][xE->u.u.type], + GetEventFilter(thisDev, xi), grab); } - - } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); } - if (deliveries && (xE->u.u.type == MotionNotify - || xE->u.u.type == DeviceMotionNotify)) + + if (deliveries && (event->any.type == ET_Motion)) thisDev->valuator->motionHintWindow = grab->window; } - if (deliveries && !deactivateGrab && - (xE->u.u.type != MotionNotify && xE->u.u.type != DeviceMotionNotify)) + if (deliveries && !deactivateGrab && event->any.type != ET_Motion) { switch (grabinfo->sync.state) { @@ -3637,250 +3980,57 @@ DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev, if (dev == thisDev) continue; FreezeThaw(dev, TRUE); - if ((grabinfo->sync.state == FREEZE_BOTH_NEXT_EVENT) && + if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && (CLIENT_BITS(grab->resource) == - CLIENT_BITS(grab->resource))) - grabinfo->sync.state = FROZEN_NO_EVENT; + CLIENT_BITS(dev->deviceGrab.sync.other->resource))) + dev->deviceGrab.sync.state = FROZEN_NO_EVENT; else - grabinfo->sync.other = grab; + dev->deviceGrab.sync.other = grab; } /* fall through */ case FREEZE_NEXT_EVENT: grabinfo->sync.state = FROZEN_WITH_EVENT; FreezeThaw(thisDev, TRUE); - if (grabinfo->sync.evcount < count) - { - grabinfo->sync.event = xrealloc(grabinfo->sync.event, - count * sizeof(xEvent)); - } - grabinfo->sync.evcount = count; - for (dxE = grabinfo->sync.event; --count >= 0; dxE++, xE++) - *dxE = *xE; + if (!grabinfo->sync.event) + grabinfo->sync.event = xcalloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = *(DeviceEvent*)event; break; } } -} -/** - * Main keyboard event processing function for core keyboard events. - * Updates the events fields from the current pointer state and delivers the - * event. - * - * For key events, xE will always be a single event. - * - * @param xE Event list - * @param keybd The device that caused an event. - * @param count Number of elements in xE. - */ -void -#ifdef XKB -CoreProcessKeyboardEvent (xEvent *xE, DeviceIntPtr keybd, int count) -#else -ProcessKeyboardEvent (xEvent *xE, DeviceIntPtr keybd, int count) -#endif -{ - int key, bit; - BYTE *kptr; - CARD8 modifiers; - GrabPtr grab; - GrabInfoPtr grabinfo; - Bool deactivateGrab = FALSE; - KeyClassPtr keyc = keybd->key; - - grabinfo = &keybd->deviceGrab; - grab = grabinfo->grab; - - if (!syncEvents.playingEvents) - { - NoticeTime(xE); - if (DeviceEventCallback) - { - DeviceEventInfoRec eventinfo; - eventinfo.events = xE; - eventinfo.count = count; - CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); - } - } - /* ProcessOtherEvent already updated the keyboard's state, so we need to - * access prev_state here! */ - XE_KBPTR.state = (keyc->prev_state | GetPairedDevice(keybd)->button->state); - XE_KBPTR.rootX = keybd->spriteInfo->sprite->hot.x; - XE_KBPTR.rootY = keybd->spriteInfo->sprite->hot.y; - key = xE->u.u.detail; - kptr = &keyc->down[key >> 3]; - bit = 1 << (key & 7); - modifiers = keyc->modifierMap[key]; - - switch (xE->u.u.type) - { - case KeyPress: - /* We MUST NOT change the device itself here. All device state - * changes must be performed in ProcessOtherEvents. We're dealing - * with the same device struct, so if we change it in POE and - * here, we've just screwed up the state by setting it twice. - * - * Devices may not send core events but always send XI events, so - * the state must be changed in POE, not here. - */ - if (!grab && CheckDeviceGrabs(keybd, xE, 0, count)) - { - grabinfo->activatingKey = key; - return; - } - break; - case KeyRelease: - if (!(*kptr & bit)) /* guard against duplicates */ - return; - /* No device state changes, see comment for KeyPress */ - if (grabinfo->fromPassiveGrab && (key == grabinfo->activatingKey)) - deactivateGrab = TRUE; - break; - default: - FatalError("Impossible keyboard event"); - } - if (grab) - DeliverGrabbedEvent(xE, keybd, deactivateGrab, count); - else - DeliverFocusedEvent(keybd, xE, keybd->spriteInfo->sprite->win, count); - if (deactivateGrab) - (*grabinfo->DeactivateGrab)(keybd); - - XaceHook(XACE_KEY_AVAIL, xE, keybd, count); + if (xi) + xfree(xi); + if (xi2) + xfree(xi2); } -#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 the device's processInputProc to be called, as in for example Mouse Keys. */ void -FixKeyState (xEvent *xE, DeviceIntPtr keybd) +FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) { int key, bit; BYTE *kptr; KeyClassPtr keyc = keybd->key; - key = xE->u.u.detail; + key = event->detail.key; kptr = &keyc->down[key >> 3]; bit = 1 << (key & 7); - if (((xE->u.u.type==KeyPress)||(xE->u.u.type==KeyRelease)|| - (xE->u.u.type==DeviceKeyPress)||(xE->u.u.type==DeviceKeyRelease)) - ) { + if (event->type == ET_KeyPress) { DebugF("FixKeyState: Key %d %s\n",key, - (((xE->u.u.type==KeyPress)||(xE->u.u.type==DeviceKeyPress))?"down":"up")); + ((event->type == ET_KeyPress) ? "down" : "up")); } - if (xE->u.u.type == KeyPress || xE->u.u.type == DeviceKeyPress) + if (event->type == ET_KeyPress) *kptr |= bit; - else if (xE->u.u.type == KeyRelease || xE->u.u.type == DeviceKeyRelease) + else if (event->type == ET_KeyRelease) *kptr &= ~bit; else FatalError("Impossible keyboard event"); } -#endif - -/** - * Main pointer event processing function for core pointer events. - * For motion events: update the sprite. - * For all other events: Update the event fields based on the current sprite - * state. - * - * For core pointer events, xE will always be a single event. - * - * @param xE Event list - * @param mouse The device that caused an event. - * @param count Number of elements in xE. - */ -void -#ifdef XKB -CoreProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count) -#else -ProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count) -#endif -{ - GrabPtr grab = mouse->deviceGrab.grab; - Bool deactivateGrab = FALSE; - ButtonClassPtr butc = mouse->button; - SpritePtr pSprite = mouse->spriteInfo->sprite; - -#ifdef XKB - XkbSrvInfoPtr xkbi= GetPairedDevice(mouse)->key->xkbInfo; -#endif - - 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[pSprite->hotPhys.pScreen->myNum]->drawable.id; - eventinfo.events = xE; - eventinfo.count = count; - CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); - } - } - /* We need to call CheckMotion for each event. It doesn't really give us - any benefit for relative devices, but absolute devices may not send - button events to the right position otherwise. */ - if (!CheckMotion(xE, mouse) && xE->u.u.type == MotionNotify) - return; - if (xE->u.u.type != MotionNotify) - { - int key; - - XE_KBPTR.rootX = pSprite->hot.x; - XE_KBPTR.rootY = pSprite->hot.y; - - key = xE->u.u.detail; - switch (xE->u.u.type) - { - case ButtonPress: - /* - * We rely on the fact that ButtonMotionMask is the same as - * DeviceButtonMotionMask, so setting the motionMask - * to this value ensures correctness for both XI and core events. - */ - if (xE->u.u.detail == 0) - return; - filters[mouse->id][Motion_Filter(butc)] = MotionNotify; - if (!grab) - if (CheckDeviceGrabs(mouse, xE, 0, count)) - return; - break; - case ButtonRelease: - if (xE->u.u.detail == 0) - return; - filters[mouse->id][Motion_Filter(butc)] = MotionNotify; - if (!butc->buttonsDown && mouse->deviceGrab.fromPassiveGrab) - deactivateGrab = TRUE; - break; - default: - FatalError("bogus pointer event from ddx. Type %d\n", xE->u.u.type); - } - } - - if (grab) - DeliverGrabbedEvent(xE, mouse, deactivateGrab, count); - else - DeliverDeviceEvents(pSprite->win, xE, NullGrab, NullWindow, - mouse, count); - if (deactivateGrab) - (*mouse->deviceGrab.DeactivateGrab)(mouse); -} #define AtMostOneClient \ (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) @@ -3895,13 +4045,12 @@ ProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count) * The otherEventMasks on a WindowOptional is the combination of all event * masks set by all clients on the window. * deliverableEventMask is the combination of the eventMask and the - * otherEventMask. + * otherEventMask plus the events that may be propagated to the parent. * * Traverses to siblings and parents of the window. */ void -RecalculateDeliverableEvents(pWin) - WindowPtr pWin; +RecalculateDeliverableEvents(WindowPtr pWin) { OtherClients *others; WindowPtr pChild; @@ -4030,7 +4179,7 @@ EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) check = 0; if (!pWin->optional && !MakeWindowOptional (pWin)) return BadAlloc; - others = (OtherClients *) xalloc(sizeof(OtherClients)); + others = xalloc(sizeof(OtherClients)); if (!others) return BadAlloc; others->mask = mask; @@ -4144,6 +4293,7 @@ CoreEnterLeaveEvent( mask = pWin->eventMask | wOtherEventMasks(pWin); } + memset(&event, 0, sizeof(xEvent)); event.u.u.type = type; event.u.u.detail = detail; event.u.enterLeave.time = currentTime.milliseconds; @@ -4155,18 +4305,10 @@ CoreEnterLeaveEvent( 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; - if (keybd) - event.u.enterLeave.state |= + event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0; + if (keybd) + event.u.enterLeave.state |= XkbGrabStateFromRec(&keybd->key->xkbInfo->state); - } else -#endif - { - event.u.enterLeave.state = (keybd) ? keybd->key->state : 0; - event.u.enterLeave.state |= mouse->button->state; - } event.u.enterLeave.mode = mode; focus = (keybd) ? keybd->focus->win : None; if ((focus != NoneWin) && @@ -4174,21 +4316,21 @@ CoreEnterLeaveEvent( IsParent(focus, pWin))) event.u.enterLeave.flags |= ELFlagFocus; - if ((mask & filters[mouse->id][type])) + if ((mask & GetEventFilter(mouse, &event))) { if (grab) TryClientEvents(rClient(grab), mouse, &event, 1, mask, - filters[mouse->id][type], grab); + GetEventFilter(mouse, &event), grab); else DeliverEventsToWindow(mouse, pWin, &event, 1, - filters[mouse->id][type], NullGrab, 0); + GetEventFilter(mouse, &event), + NullGrab); } if ((type == EnterNotify) && (mask & KeymapStateMask)) { xKeymapEvent ke; - ClientPtr client = grab ? rClient(grab) - : clients[CLIENT_ID(pWin->drawable.id)]; + ClientPtr client = grab ? rClient(grab) : wClient(pWin); if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) bzero((char *)&ke.map[0], 31); else @@ -4200,8 +4342,83 @@ CoreEnterLeaveEvent( mask, KeymapStateMask, grab); else DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab, 0); + KeymapStateMask, NullGrab); + } +} + +void +DeviceEnterLeaveEvent( + DeviceIntPtr mouse, + int sourceid, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + GrabPtr grab = mouse->deviceGrab.grab; + xXIEnterEvent *event; + int filter; + int btlen, len, i; + DeviceIntPtr kbd; + + if ((mode == XINotifyPassiveGrab && type == XI_Leave) || + (mode == XINotifyPassiveUngrab && type == XI_Enter)) + return; + + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIEnterEvent) + btlen * 4; + + event = xcalloc(1, len); + event->type = GenericEvent; + event->extension = IReqCode; + event->evtype = type; + event->length = (len - sizeof(xEvent))/4; + event->buttons_len = btlen; + event->detail = detail; + event->time = currentTime.milliseconds; + event->deviceid = mouse->id; + event->sourceid = sourceid; + event->mode = mode; + event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&event[1], i); + + kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; + if (kbd && kbd->key) + { + event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; + event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; + event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; + + event->group.base_group = kbd->key->xkbInfo->state.base_group; + event->group.latched_group = kbd->key->xkbInfo->state.latched_group; + event->group.locked_group = kbd->key->xkbInfo->state.locked_group; } + + FixUpEventFromWindow(mouse, (xEvent*)event, pWin, None, FALSE); + + filter = GetEventFilter(mouse, (xEvent*)event); + + if (grab) + { + Mask mask; + mask = grab->xi2mask[XIAllDevices][type/8] | + grab->xi2mask[XIAllMasterDevices][type/8] | + grab->xi2mask[mouse->id][type/8]; + TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, + filter, grab); + } else { + if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) + return; + DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, + NullGrab); + } + xfree(event); } void @@ -4209,25 +4426,27 @@ CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) { xEvent event; + memset(&event, 0, sizeof(xEvent)); event.u.focus.mode = mode; event.u.u.type = type; event.u.u.detail = detail; event.u.focus.window = pWin->drawable.id; - (void)DeliverEventsToWindow(dev, pWin, &event, 1, - filters[dev->id][type], NullGrab, 0); + + DeliverEventsToWindow(dev, pWin, &event, 1, + GetEventFilter(dev, &event), NullGrab); if ((type == FocusIn) && ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) { xKeymapEvent ke; - ClientPtr client = clients[CLIENT_ID(pWin->drawable.id)]; + ClientPtr client = wClient(pWin); if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) bzero((char *)&ke.map[0], 31); else memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); ke.type = KeymapNotify; - (void)DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab, 0); + DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); } } @@ -4305,9 +4524,14 @@ SetInputFocus( return Success; mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; if (focus->win == FollowKeyboardWin) - DoFocusEvents(dev, keybd->focus->win, focusWin, mode); - else - DoFocusEvents(dev, focus->win, focusWin, mode); + { + if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) + DoFocusEvents(dev, keybd->focus->win, focusWin, mode); + } else + { + if (!ActivateFocusInGrab(dev, focus->win, focusWin)) + DoFocusEvents(dev, focus->win, focusWin, mode); + } focus->time = time; focus->revert = revertTo; if (focusID == FollowKeyboard) @@ -4341,8 +4565,7 @@ SetInputFocus( * Sets the input focus for the virtual core keyboard. */ int -ProcSetInputFocus(client) - ClientPtr client; +ProcSetInputFocus(ClientPtr client) { DeviceIntPtr kbd = PickKeyboard(client); REQUEST(xSetInputFocusReq); @@ -4373,6 +4596,7 @@ ProcGetInputFocus(ClientPtr client) if (rc != Success) return rc; + memset(&rep, 0, sizeof(xGetInputFocusReply)); rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; @@ -4398,40 +4622,22 @@ ProcGrabPointer(ClientPtr client) xGrabPointerReply rep; DeviceIntPtr device = PickPointer(client); GrabPtr grab; - WindowPtr pWin, confineTo; - CursorPtr cursor, oldCursor; + GrabMask mask; + WindowPtr confineTo; + CursorPtr oldCursor; REQUEST(xGrabPointerReq); TimeStamp time; - Mask access_mode = DixGrabAccess; int rc; 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) { client->errorValue = stuff->eventMask; return BadValue; } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; + if (stuff->confineTo == None) confineTo = NullWindow; else @@ -4441,81 +4647,34 @@ ProcGrabPointer(ClientPtr client) if (rc != Success) return rc; } - if (stuff->cursor == None) - cursor = NullCursor; - else + + memset(&rep, 0, sizeof(xGrabPointerReply)); + oldCursor = NullCursor; + grab = device->deviceGrab.grab; + + if (grab) { - rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return (rc == BadValue) ? BadCursor : rc; - } - access_mode |= DixForceAccess; + if (grab->confineTo && !confineTo) + ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE); + oldCursor = grab->cursor; } - if (stuff->pointerMode == GrabModeSync || - stuff->keyboardMode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, device, access_mode); + + mask.core = stuff->eventMask; + + rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, + stuff->grabWindow, stuff->ownerEvents, stuff->time, + &mask, GRABTYPE_CORE, stuff->cursor, + stuff->confineTo, &rep.status); if (rc != Success) - return rc; + return rc; + + if (oldCursor && rep.status == GrabSuccess) + FreeCursor (oldCursor, (Cursor)0); - /* 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->deviceGrab.grab; - /* check for - 1. other client has a grab on the device already. - 2. window is viewable - 3. other client has this device as frozen "other" device - 4. times are screwed. - */ - if ((grab) && !SameClient(grab, client)) - rep.status = AlreadyGrabbed; - else if ((!pWin->realized) || - (confineTo && - !(confineTo->realized - && BorderSizeNotEmpty(device, confineTo)))) - rep.status = GrabNotViewable; - else if (device->deviceGrab.sync.frozen && - device->deviceGrab.sync.other && - !SameClient(device->deviceGrab.sync.other, client)) - rep.status = GrabFrozen; - else if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) - rep.status = GrabInvalidTime; - else - { - GrabRec tempGrab; - - oldCursor = NullCursor; - if (grab) - { - if (grab->confineTo && !confineTo) - ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE); - oldCursor = grab->cursor; - } - tempGrab.next = NULL; - 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; - tempGrab.coreGrab = True; - tempGrab.genericMasks = NULL; - (*device->deviceGrab.ActivateGrab)(device, &tempGrab, time, FALSE); - if (oldCursor) - FreeCursor (oldCursor, (Cursor)0); - rep.status = GrabSuccess; - } WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); return Success; } @@ -4621,26 +4780,27 @@ ProcUngrabPointer(ClientPtr client) */ int GrabDevice(ClientPtr client, DeviceIntPtr dev, - unsigned this_mode, unsigned other_mode, Window grabWindow, - unsigned ownerEvents, Time ctime, Mask mask, CARD8 *status, - Bool coreGrab) + unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, + unsigned ownerEvents, Time ctime, GrabMask *mask, + int grabtype, Cursor curs, Window confineToWin, CARD8 *status) { - WindowPtr pWin; + WindowPtr pWin, confineTo; GrabPtr grab; TimeStamp time; Mask access_mode = DixGrabAccess; int rc; GrabInfoPtr grabInfo = &dev->deviceGrab; + CursorPtr cursor; UpdateCurrentTime(); - if ((this_mode != GrabModeSync) && (this_mode != GrabModeAsync)) + if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) { - client->errorValue = this_mode; + client->errorValue = keyboard_mode; return BadValue; } - if ((other_mode != GrabModeSync) && (other_mode != GrabModeAsync)) + if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) { - client->errorValue = other_mode; + client->errorValue = pointer_mode; return BadValue; } if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) @@ -4652,7 +4812,32 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); if (rc != Success) return rc; - if (this_mode == GrabModeSync || other_mode == GrabModeSync) + + if (confineToWin == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, confineToWin, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + if (curs == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = curs; + return (rc == BadValue) ? BadCursor : rc; + } + access_mode |= DixForceAccess; + } + + if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) access_mode |= DixFreezeAccess; rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); if (rc != Success) @@ -4660,9 +4845,14 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, time = ClientTimeToServerTime(ctime); grab = grabInfo->grab; + if (grab && grab->grabtype != grabtype) + *status = AlreadyGrabbed; if (grab && !SameClient(grab, client)) *status = AlreadyGrabbed; - else if (!pWin->realized) + else if ((!pWin->realized) || + (confineTo && + !(confineTo->realized + && BorderSizeNotEmpty(dev, confineTo)))) *status = GrabNotViewable; else if ((CompareTimeStamps(time, currentTime) == LATER) || (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) @@ -4681,14 +4871,18 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, tempGrab.window = pWin; tempGrab.resource = client->clientAsMask; tempGrab.ownerEvents = ownerEvents; - tempGrab.keyboardMode = this_mode; - tempGrab.pointerMode = other_mode; - tempGrab.eventMask = mask; + tempGrab.keyboardMode = keyboard_mode; + tempGrab.pointerMode = pointer_mode; + if (grabtype == GRABTYPE_CORE) + tempGrab.eventMask = mask->core; + else if (grabtype == GRABTYPE_XI) + tempGrab.eventMask = mask->xi; + else + memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); tempGrab.device = dev; - tempGrab.cursor = NULL; - tempGrab.coreGrab = coreGrab; - tempGrab.genericMasks = NULL; - + tempGrab.cursor = cursor; + tempGrab.confineTo = confineTo; + tempGrab.grabtype = grabtype; (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); *status = GrabSuccess; } @@ -4707,13 +4901,17 @@ ProcGrabKeyboard(ClientPtr client) REQUEST(xGrabKeyboardReq); int result; DeviceIntPtr keyboard = PickKeyboard(client); + GrabMask mask; REQUEST_SIZE_MATCH(xGrabKeyboardReq); - result = GrabDevice(client, keyboard, stuff->keyboardMode, - stuff->pointerMode, stuff->grabWindow, - stuff->ownerEvents, stuff->time, - KeyPressMask | KeyReleaseMask, &rep.status, TRUE); + memset(&rep, 0, sizeof(xGrabKeyboardReply)); + mask.core = KeyPressMask | KeyReleaseMask; + + result = GrabDevice(client, keyboard, stuff->pointerMode, + stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, + stuff->time, &mask, GRABTYPE_CORE, None, None, + &rep.status); if (result != Success) return result; @@ -4745,7 +4943,7 @@ ProcUngrabKeyboard(ClientPtr client) time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client) && grab->coreGrab) + (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) (*device->deviceGrab.DeactivateGrab)(device); return Success; } @@ -4762,6 +4960,7 @@ ProcQueryPointer(ClientPtr client) xQueryPointerReply rep; WindowPtr pWin, t; DeviceIntPtr mouse = PickPointer(client); + DeviceIntPtr keyboard; SpritePtr pSprite; int rc; REQUEST(xResourceReq); @@ -4774,12 +4973,16 @@ ProcQueryPointer(ClientPtr client) if (rc != Success) return rc; + keyboard = GetPairedDevice(mouse); + pSprite = mouse->spriteInfo->sprite; if (mouse->valuator->motionHintWindow) MaybeStopHint(mouse, client); + memset(&rep, 0, sizeof(xQueryPointerReply)); rep.type = X_Reply; rep.sequenceNumber = client->sequence; - rep.mask = mouse->button->state | inputInfo.keyboard->key->state; + rep.mask = mouse->button ? (mouse->button->state) : 0; + rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); rep.length = 0; rep.root = (RootWindow(mouse))->drawable.id; rep.rootX = pSprite->hot.x; @@ -4834,7 +5037,8 @@ InitEvents(void) inputInfo.off_devices = (DeviceIntPtr)NULL; inputInfo.keyboard = (DeviceIntPtr)NULL; inputInfo.pointer = (DeviceIntPtr)NULL; - lastEventMask = OwnerGrabButtonMask; + /* The mask for pointer motion events may have changed in the last server + * generation. See comment above definition of filters. */ filters[0][PointerMotionMask] = MotionNotify; for (i = 1; i < MAXDEVICES; i++) { @@ -4889,7 +5093,9 @@ ProcSendEvent(ClientPtr client) { WindowPtr pWin; WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + DeviceIntPtr dev = PickPointer(client); + DeviceIntPtr keybd = GetPairedDevice(dev); + SpritePtr pSprite = dev->spriteInfo->sprite; REQUEST(xSendEventReq); REQUEST_SIZE_MATCH(xSendEventReq); @@ -4923,7 +5129,7 @@ ProcSendEvent(ClientPtr client) pWin = pSprite->win; else if (stuff->destination == InputFocus) { - WindowPtr inputFocus = inputInfo.keyboard->focus->win; + WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; if (inputFocus == NoneWin) return Success; @@ -4959,8 +5165,8 @@ ProcSendEvent(ClientPtr client) if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) return Success; - if (DeliverEventsToWindow(PickPointer(client), pWin, - &stuff->event, 1, stuff->eventMask, NullGrab, 0)) + if (DeliverEventsToWindow(dev, pWin, + &stuff->event, 1, stuff->eventMask, NullGrab)) return Success; if (pWin == effectiveFocus) return Success; @@ -4970,8 +5176,8 @@ ProcSendEvent(ClientPtr client) } } else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) - (void)DeliverEventsToWindow(PickPointer(client), pWin, &stuff->event, - 1, stuff->eventMask, NullGrab, 0); + DeliverEventsToWindow(dev, pWin, &stuff->event, + 1, stuff->eventMask, NullGrab); return Success; } @@ -4991,12 +5197,12 @@ ProcUngrabKey(ClientPtr client) int rc; REQUEST_SIZE_MATCH(xUngrabKeyReq); - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); if (rc != Success) return rc; - if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) || - (stuff->key < keybd->key->curKeySyms.minKeyCode)) + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) && (stuff->key != AnyKey)) { client->errorValue = stuff->key; @@ -5013,8 +5219,9 @@ ProcUngrabKey(ClientPtr client) tempGrab.window = pWin; tempGrab.modifiersDetail.exact = stuff->modifiers; tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = inputInfo.keyboard; + tempGrab.modifierDevice = GetPairedDevice(keybd); tempGrab.type = KeyPress; + tempGrab.grabtype = GRABTYPE_CORE; tempGrab.detail.exact = stuff->key; tempGrab.detail.pMask = NULL; tempGrab.next = NULL; @@ -5038,47 +5245,38 @@ ProcGrabKey(ClientPtr client) GrabPtr grab; DeviceIntPtr keybd = PickKeyboard(client); int rc; + GrabParameters param; + GrabMask mask; 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)) + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + rc = CheckGrabValues(client, ¶m); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) && (stuff->key != AnyKey)) { client->errorValue = stuff->key; return BadValue; } - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); if (rc != Success) return rc; - 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); + + mask.core = (KeyPressMask | KeyReleaseMask); + + grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, + ¶m, KeyPress, stuff->key, NullWindow, NullCursor); if (!grab) return BadAlloc; return AddPassiveGrabToList(client, grab); @@ -5100,6 +5298,8 @@ ProcGrabButton(ClientPtr client) GrabPtr grab; DeviceIntPtr ptr, modifierDevice; Mask access_mode = DixGrabAccess; + GrabMask mask; + GrabParameters param; int rc; REQUEST_SIZE_MATCH(xGrabButtonReq); @@ -5166,11 +5366,18 @@ ProcGrabButton(ClientPtr client) if (rc != Success) return rc; - grab = CreateGrab(client->index, ptr, pWin, - (Mask)stuff->eventMask, (Bool)stuff->ownerEvents, - (Bool) stuff->keyboardMode, (Bool)stuff->pointerMode, - modifierDevice, stuff->modifiers, ButtonPress, - stuff->button, confineTo, cursor); + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + mask.core = stuff->eventMask; + + grab = CreateGrab(client->index, ptr, modifierDevice, pWin, + GRABTYPE_CORE, &mask, ¶m, ButtonPress, + stuff->button, confineTo, cursor); if (!grab) return BadAlloc; return AddPassiveGrabToList(client, grab); @@ -5188,6 +5395,7 @@ ProcUngrabButton(ClientPtr client) WindowPtr pWin; GrabRec tempGrab; int rc; + DeviceIntPtr ptr; REQUEST_SIZE_MATCH(xUngrabButtonReq); if ((stuff->modifiers != AnyModifier) && @@ -5199,14 +5407,18 @@ ProcUngrabButton(ClientPtr client) rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); if (rc != Success) return rc; + + ptr = PickPointer(client); + tempGrab.resource = client->clientAsMask; - tempGrab.device = PickPointer(client); + tempGrab.device = ptr; tempGrab.window = pWin; tempGrab.modifiersDetail.exact = stuff->modifiers; tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = inputInfo.keyboard; + tempGrab.modifierDevice = GetPairedDevice(ptr); tempGrab.type = ButtonPress; tempGrab.detail.exact = stuff->button; + tempGrab.grabtype = GRABTYPE_CORE; tempGrab.detail.pMask = NULL; tempGrab.next = NULL; @@ -5299,15 +5511,17 @@ DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) to None */ #ifdef NOTDEF - || clients[CLIENT_ID(parent->drawable.id)]->clientGone + || wClient(parent)->clientGone #endif ); - DoFocusEvents(keybd, pWin, parent, focusEventMode); + if (!ActivateFocusInGrab(keybd, pWin, parent)) + DoFocusEvents(keybd, pWin, parent, focusEventMode); focus->win = parent; focus->revert = RevertToNone; break; case RevertToPointerRoot: - DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); + if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) + DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); focus->win = PointerRootWin; focus->traceGood = 0; break; @@ -5340,7 +5554,7 @@ DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) * there is a grab on the window, the cursor will be re-confined into the * window. */ -_X_EXPORT void +void CheckCursorConfinement(WindowPtr pWin) { GrabPtr grab; @@ -5359,7 +5573,7 @@ CheckCursorConfinement(WindowPtr pWin) if (grab && (confineTo = grab->confineTo)) { if (!BorderSizeNotEmpty(pDev, confineTo)) - (*inputInfo.pointer->deviceGrab.DeactivateGrab)(pDev); + (*pDev->deviceGrab.DeactivateGrab)(pDev); else if ((pWin == confineTo) || IsParent(pWin, confineTo)) ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE); } @@ -5441,7 +5655,7 @@ ProcRecolorCursor(ClientPtr client) * @param count Number of events. * @param events The event list. */ -_X_EXPORT void +void WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) { #ifdef PANORAMIX @@ -5451,10 +5665,8 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) int i, eventlength = sizeof(xEvent); -#ifdef XKB - if ((!noXkbExtension)&&(!XkbFilterEvents(pClient, count, events))) - return; -#endif + /* Let XKB rewrite the state, as it depends on client preferences. */ + XkbFilterEvents(pClient, count, events); #ifdef PANORAMIX if(!noPanoramiXExtension && @@ -5545,7 +5757,7 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) (*EventSwapVector[eventFrom->u.u.type & 0177]) (eventFrom, eventTo); - (void)WriteToClient(pClient, eventlength, (char *)eventTo); + WriteToClient(pClient, eventlength, (char *)eventTo); } } else @@ -5553,13 +5765,12 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) /* only one GenericEvent, remember? that means either count is 1 and * eventlength is arbitrary or eventlength is 32 and count doesn't * matter. And we're all set. Woohoo. */ - (void)WriteToClient(pClient, count * eventlength, (char *) events); + WriteToClient(pClient, count * eventlength, (char *) events); } } /* - * Set the client pointer for the given client. Second parameter setter could - * be used in the future to determine access rights. Unused for now. + * Set the client pointer for the given client. * * A client can have exactly one ClientPointer. Each time a * request/reply/event is processed and the choice of devices is ambiguous @@ -5567,21 +5778,25 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) * PickPointer()). * If a keyboard is needed, the first keyboard paired with the CP is used. */ -_X_EXPORT Bool -SetClientPointer(ClientPtr client, ClientPtr setter, DeviceIntPtr device) +int +SetClientPointer(ClientPtr client, DeviceIntPtr device) { - if (!device->isMaster) + int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); + if (rc != Success) + return rc; + + if (!IsMaster(device)) { ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); - return FALSE; + return BadDevice; } else if (!device->spriteInfo->spriteOwner) { ErrorF("[dix] Device %d does not have a sprite. " "Cannot be ClientPointer\n", device->id); - return FALSE; + return BadDevice; } client->clientPtr = device; - return TRUE; + return Success; } /* PickPointer will pick an appropriate pointer for the given client. @@ -5591,7 +5806,7 @@ SetClientPointer(ClientPtr client, ClientPtr setter, DeviceIntPtr device) * 2) A device set as ClientPointer for the given client. * 3) The first master device. */ -_X_EXPORT DeviceIntPtr +DeviceIntPtr PickPointer(ClientPtr client) { DeviceIntPtr it = inputInfo.devices; @@ -5601,10 +5816,9 @@ PickPointer(ClientPtr client) for(it = inputInfo.devices; it; it = it->next) { GrabPtr grab = it->deviceGrab.grab; - if (grab && grab->coreGrab && SameClient(grab, client)) + if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) { - if (!IsPointerDevice(it)) - it = GetPairedDevice(it); + it = GetMaster(it, MASTER_POINTER); return it; /* Always return a core grabbed device */ } } @@ -5614,7 +5828,7 @@ PickPointer(ClientPtr client) DeviceIntPtr it = inputInfo.devices; while (it) { - if (it->isMaster && it->spriteInfo->spriteOwner) + if (IsMaster(it) && it->spriteInfo->spriteOwner) { client->clientPtr = it; break; @@ -5629,11 +5843,11 @@ PickPointer(ClientPtr client) * searching the list of devices for the keyboard device that is paired with * the client's pointer. */ -_X_EXPORT DeviceIntPtr +DeviceIntPtr PickKeyboard(ClientPtr client) { DeviceIntPtr ptr = PickPointer(client); - DeviceIntPtr kbd = ptr->spriteInfo->paired; + DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); if (!kbd) { @@ -5657,9 +5871,6 @@ IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) { DeviceIntPtr it = inputInfo.devices; - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - return FALSE; - switch(event->u.u.type) { case KeyPress: @@ -5674,6 +5885,9 @@ IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) return FALSE; } + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + return FALSE; + while(it) { if (it != dev) @@ -5692,86 +5906,3 @@ IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) return FALSE; } -/** - * Set the filters for a extension. - * The filters array needs to contain the Masks that are applicable for each - * event type for the given extension. - * e.g. if generic event type 2 should be let through for windows with - * MyExampleMask set, make sure that filters[2] == MyExampleMask. - */ -_X_EXPORT void -SetGenericFilter(int extension, Mask* filters) -{ - generic_filters[extension & 0x7f] = filters; -} - - -/** - * Grab a device for XI events and XGE events. - * grabmode is used to ungrab a device. - */ -_X_EXPORT int -ExtGrabDevice(ClientPtr client, - DeviceIntPtr dev, - int device_mode, - WindowPtr grabWindow, - WindowPtr confineTo, - TimeStamp ctime, - Bool ownerEvents, - CursorPtr cursor, - Mask xi_mask, - GenericMaskPtr ge_masks) -{ - GrabInfoPtr grabinfo; - GrabRec newGrab; - - UpdateCurrentTime(); - - grabinfo = &dev->deviceGrab; - - if (grabinfo->grab && !SameClient(grabinfo->grab, client)) - return AlreadyGrabbed; - - if (!grabWindow->realized) - return GrabNotViewable; - - if ((CompareTimeStamps(ctime, currentTime) == LATER) || - (CompareTimeStamps(ctime, grabinfo->grabTime) == EARLIER)) - return GrabInvalidTime; - - if (grabinfo->sync.frozen && grabinfo->sync.other && - !SameClient(grabinfo->sync.other, client)) - return GrabFrozen; - - memset(&newGrab, 0, sizeof(GrabRec)); - newGrab.window = grabWindow; - newGrab.resource = client->clientAsMask; - newGrab.ownerEvents = ownerEvents; - newGrab.device = dev; - newGrab.cursor = cursor; - newGrab.confineTo = confineTo; - newGrab.eventMask = xi_mask; - newGrab.genericMasks = NULL; - newGrab.next = NULL; - - if (ge_masks) - { - newGrab.genericMasks = xcalloc(1, sizeof(GenericMaskRec)); - *newGrab.genericMasks = *ge_masks; - newGrab.genericMasks->next = NULL; - } - - if (IsPointerDevice(dev)) - { - newGrab.keyboardMode = GrabModeAsync; - newGrab.pointerMode = device_mode; - } else - { - newGrab.keyboardMode = device_mode; - newGrab.pointerMode = GrabModeAsync; - } - - (*grabinfo->ActivateGrab)(dev, &newGrab, ctime, FALSE); - return GrabSuccess; -} - |