/dix/events.c
C | 6184 lines | 4419 code | 702 blank | 1063 comment | 1321 complexity | 9707a71ff000d6a5869e2fec4712e88d MD5 | raw file
Possible License(s): MIT
Large files files are truncated, but you can click here to view the full file
- /************************************************************
- Copyright 1987, 1998 The Open Group
- Permission to use, copy, modify, distribute, and sell this software and its
- documentation for any purpose is hereby granted without fee, provided that
- the above copyright notice appear in all copies and that both that
- copyright notice and this permission notice appear in supporting
- documentation.
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of The Open Group shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from The Open Group.
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- ********************************************************/
- /* The panoramix components contained the following notice */
- /*****************************************************************
- Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software.
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
- BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of Digital Equipment Corporation
- shall not be used in advertising or otherwise to promote the sale, use or other
- dealings in this Software without prior written authorization from Digital
- Equipment Corporation.
- ******************************************************************/
- /*
- * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- /** @file events.c
- * This file handles event delivery and a big part of the server-side protocol
- * handling (the parts for input devices).
- */
- #ifdef HAVE_DIX_CONFIG_H
- #include <dix-config.h>
- #endif
- #include <X11/X.h>
- #include "misc.h"
- #include "resource.h"
- #include <X11/Xproto.h>
- #include "windowstr.h"
- #include "inputstr.h"
- #include "inpututils.h"
- #include "scrnintstr.h"
- #include "cursorstr.h"
- #include "dixstruct.h"
- #ifdef PANORAMIX
- #include "panoramiX.h"
- #include "panoramiXsrv.h"
- #endif
- #include "globals.h"
- #include <X11/extensions/XKBproto.h>
- #include "xkbsrv.h"
- #include "xace.h"
- #ifdef XSERVER_DTRACE
- #include <sys/types.h>
- typedef const char *string;
- #include "Xserver-dtrace.h"
- #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 "extnsionst.h"
- #include "dixevents.h"
- #include "dixgrabs.h"
- #include "dispatch.h"
- #include <X11/extensions/ge.h>
- #include "geext.h"
- #include "geint.h"
- #include "eventstr.h"
- #include "enterleave.h"
- #include "eventconvert.h"
- #include "mi.h"
- /* Extension events type numbering starts at EXTENSION_EVENT_BASE. */
- #define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */
- #define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
- #define AllButtonsMask ( \
- Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
- #define MotionMask ( \
- PointerMotionMask | Button1MotionMask | \
- Button2MotionMask | Button3MotionMask | Button4MotionMask | \
- Button5MotionMask | ButtonMotionMask )
- #define PropagateMask ( \
- KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
- MotionMask )
- #define PointerGrabMask ( \
- ButtonPressMask | ButtonReleaseMask | \
- EnterWindowMask | LeaveWindowMask | \
- PointerMotionHintMask | KeymapStateMask | \
- MotionMask )
- #define AllModifiersMask ( \
- ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
- Mod3Mask | Mod4Mask | Mod5Mask )
- #define LastEventMask OwnerGrabButtonMask
- #define AllEventMasks (LastEventMask|(LastEventMask-1))
- /* @return the core event type or 0 if the event is not a core event */
- static inline int
- core_get_type(const xEvent *event)
- {
- int type = event->u.u.type;
- return ((type & EXTENSION_EVENT_BASE) || type == GenericEvent) ? 0 : type;
- }
- /* @return the XI2 event type or 0 if the event is not a XI2 event */
- static inline int
- xi2_get_type(const xEvent *event)
- {
- const xGenericEvent *e = (const xGenericEvent *) event;
- return (e->type != GenericEvent ||
- e->extension != IReqCode) ? 0 : e->evtype;
- }
- /**
- * Used to indicate a implicit passive grab created by a ButtonPress event.
- * See DeliverEventsToWindow().
- */
- #define ImplicitGrabMask (1 << 7)
- #define WID(w) ((w) ? ((w)->drawable.id) : 0)
- #define XE_KBPTR (xE->u.keyButtonPointer)
- 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 IsWrongPointerBarrierClient(ClientPtr client,
- DeviceIntPtr dev,
- xEvent *event);
- /** 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. The VCP is the first master
- * pointer device and cannot be deleted.
- *
- * inputInfo.keyboard
- * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard").
- * See inputInfo.pointer.
- *
- * inputInfo.devices
- * linked list containing all devices including VCP and VCK.
- *
- * inputInfo.off_devices
- * Devices that have not been initialized and are thus turned off.
- *
- * 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.
- */
- InputInfo inputInfo;
- EventSyncInfoRec syncEvents;
- static struct DeviceEventTime {
- Bool reset;
- TimeStamp time;
- } lastDeviceEventTime[MAXDEVICES];
- /**
- * The root window the given device is currently on.
- */
- #define RootWindow(sprite) 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.
- */
- int
- XItoCoreType(int xitype)
- {
- int coretype = 0;
- if (xitype == DeviceMotionNotify)
- coretype = MotionNotify;
- else if (xitype == DeviceButtonPress)
- coretype = ButtonPress;
- else if (xitype == DeviceButtonRelease)
- coretype = ButtonRelease;
- else if (xitype == DeviceKeyPress)
- coretype = KeyPress;
- else if (xitype == DeviceKeyRelease)
- coretype = KeyRelease;
- return coretype;
- }
- /**
- * @return true if the device owns a cursor, false if device shares a cursor
- * sprite with another device.
- */
- 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
- * fill the 'use' field.
- */
- Bool
- IsPointerDevice(DeviceIntPtr dev)
- {
- return (dev->type == MASTER_POINTER) ||
- (dev->valuator && dev->button) || (dev->valuator && !dev->key);
- }
- /*
- * @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.
- */
- Bool
- IsKeyboardDevice(DeviceIntPtr 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;
- }
- Bool
- IsFloating(DeviceIntPtr dev)
- {
- return !IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == NULL;
- }
- /**
- * Max event opcode.
- */
- extern int lastEvent;
- #define CantBeFiltered NoEventMask
- /**
- * Event masks for each event type.
- *
- * One set of filters for each device, initialized by memcpy of
- * default_filter 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.
- */
- Mask event_filters[MAXDEVICES][MAXEVENTS];
- static const Mask default_filter[MAXEVENTS] = {
- NoSuchEvent, /* 0 */
- NoSuchEvent, /* 1 */
- KeyPressMask, /* KeyPress */
- KeyReleaseMask, /* KeyRelease */
- ButtonPressMask, /* ButtonPress */
- ButtonReleaseMask, /* ButtonRelease */
- PointerMotionMask, /* MotionNotify (initial state) */
- EnterWindowMask, /* EnterNotify */
- LeaveWindowMask, /* LeaveNotify */
- FocusChangeMask, /* FocusIn */
- FocusChangeMask, /* FocusOut */
- KeymapStateMask, /* KeymapNotify */
- ExposureMask, /* Expose */
- CantBeFiltered, /* GraphicsExpose */
- CantBeFiltered, /* NoExpose */
- VisibilityChangeMask, /* VisibilityNotify */
- SubstructureNotifyMask, /* CreateNotify */
- StructureAndSubMask, /* DestroyNotify */
- StructureAndSubMask, /* UnmapNotify */
- StructureAndSubMask, /* MapNotify */
- SubstructureRedirectMask, /* MapRequest */
- StructureAndSubMask, /* ReparentNotify */
- StructureAndSubMask, /* ConfigureNotify */
- SubstructureRedirectMask, /* ConfigureRequest */
- StructureAndSubMask, /* GravityNotify */
- ResizeRedirectMask, /* ResizeRequest */
- StructureAndSubMask, /* CirculateNotify */
- SubstructureRedirectMask, /* CirculateRequest */
- PropertyChangeMask, /* PropertyNotify */
- CantBeFiltered, /* SelectionClear */
- CantBeFiltered, /* SelectionRequest */
- CantBeFiltered, /* SelectionNotify */
- ColormapChangeMask, /* ColormapNotify */
- CantBeFiltered, /* ClientMessage */
- CantBeFiltered /* MappingNotify */
- };
- /**
- * 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)
- {
- int evtype = 0;
- if (event->u.u.type != GenericEvent)
- return event_get_filter_from_type(dev, event->u.u.type);
- else if ((evtype = xi2_get_type(event)))
- return event_get_filter_from_xi2type(evtype);
- ErrorF("[dix] Unknown event type %d. No filter\n", event->u.u.type);
- return 0;
- }
- /**
- * Return the single byte of the device's XI2 mask that contains the mask
- * for the event_type.
- */
- int
- GetXI2MaskByte(XI2Mask *mask, DeviceIntPtr dev, int event_type)
- {
- /* we just return the matching filter because that's the only use
- * for this mask anyway.
- */
- if (xi2mask_isset(mask, dev, event_type))
- return event_get_filter_from_xi2type(event_type);
- else
- return 0;
- }
- /**
- * @return TRUE if the mask is set for this event from this device on the
- * window, or FALSE otherwise.
- */
- Bool
- WindowXI2MaskIsset(DeviceIntPtr dev, WindowPtr win, xEvent *ev)
- {
- OtherInputMasks *inputMasks = wOtherInputMasks(win);
- int evtype;
- if (!inputMasks || xi2_get_type(ev) == 0)
- return 0;
- evtype = ((xGenericEvent *) ev)->evtype;
- return xi2mask_isset(inputMasks->xi2mask, dev, evtype);
- }
- Mask
- GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients * other)
- {
- int evtype;
- /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */
- if ((evtype = xi2_get_type(event))) {
- return GetXI2MaskByte(other->xi2mask, dev, evtype);
- }
- else if (core_get_type(event) != 0)
- 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
- if (!noPanoramiXExtension)
- screenno = dev->spriteInfo->sprite->screen->myNum;
- #endif
- PostSyntheticMotion(dev, x, y, screenno,
- (syncEvents.playingEvents) ? syncEvents.time.
- milliseconds : currentTime.milliseconds);
- }
- #ifdef PANORAMIX
- static void PostNewCursor(DeviceIntPtr pDev);
- static Bool
- XineramaSetCursorPosition(DeviceIntPtr pDev, int x, int y, Bool generateEvent)
- {
- ScreenPtr pScreen;
- int i;
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- /* x,y are in Screen 0 coordinates. We need to decide what Screen
- to send the message too and what the coordinates relative to
- that screen are. */
- pScreen = pSprite->screen;
- x += screenInfo.screens[0]->x;
- y += screenInfo.screens[0]->y;
- if (!point_on_screen(pScreen, x, y)) {
- FOR_NSCREENS(i) {
- if (i == pScreen->myNum)
- continue;
- if (point_on_screen(screenInfo.screens[i], x, y)) {
- pScreen = screenInfo.screens[i];
- break;
- }
- }
- }
- pSprite->screen = pScreen;
- pSprite->hotPhys.x = x - screenInfo.screens[0]->x;
- pSprite->hotPhys.y = y - screenInfo.screens[0]->y;
- x -= pScreen->x;
- y -= pScreen->y;
- return (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
- }
- static void
- XineramaConstrainCursor(DeviceIntPtr pDev)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- ScreenPtr pScreen;
- BoxRec newBox;
- pScreen = pSprite->screen;
- newBox = pSprite->physLimits;
- /* Translate the constraining box to the screen
- the sprite is actually on */
- newBox.x1 += screenInfo.screens[0]->x - pScreen->x;
- newBox.x2 += screenInfo.screens[0]->x - pScreen->x;
- newBox.y1 += screenInfo.screens[0]->y - pScreen->y;
- newBox.y2 += screenInfo.screens[0]->y - pScreen->y;
- (*pScreen->ConstrainCursor) (pDev, pScreen, &newBox);
- }
- static Bool
- XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- if (pWin == screenInfo.screens[0]->root) {
- int i;
- FOR_NSCREENS(i)
- pSprite->windows[i] = screenInfo.screens[i]->root;
- }
- else {
- PanoramiXRes *win;
- int rc, i;
- rc = dixLookupResourceByType((void **) &win, pWin->drawable.id,
- XRT_WINDOW, serverClient, DixReadAccess);
- if (rc != Success)
- return FALSE;
- FOR_NSCREENS(i) {
- rc = dixLookupWindow(pSprite->windows + i, win->info[i].id,
- serverClient, DixReadAccess);
- if (rc != Success) /* window is being unmapped */
- return FALSE;
- }
- }
- return TRUE;
- }
- static void
- XineramaConfineCursorToWindow(DeviceIntPtr pDev,
- WindowPtr pWin, Bool generateEvents)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- int x, y, off_x, off_y, i;
- if (!XineramaSetWindowPntrs(pDev, pWin))
- return;
- i = PanoramiXNumScreens - 1;
- RegionCopy(&pSprite->Reg1, &pSprite->windows[i]->borderSize);
- off_x = screenInfo.screens[i]->x;
- off_y = screenInfo.screens[i]->y;
- while (i--) {
- x = off_x - screenInfo.screens[i]->x;
- y = off_y - screenInfo.screens[i]->y;
- if (x || y)
- RegionTranslate(&pSprite->Reg1, x, y);
- RegionUnion(&pSprite->Reg1, &pSprite->Reg1,
- &pSprite->windows[i]->borderSize);
- off_x = screenInfo.screens[i]->x;
- off_y = screenInfo.screens[i]->y;
- }
- pSprite->hotLimits = *RegionExtents(&pSprite->Reg1);
- if (RegionNumRects(&pSprite->Reg1) > 1)
- pSprite->hotShape = &pSprite->Reg1;
- else
- pSprite->hotShape = NullRegion;
- pSprite->confined = FALSE;
- pSprite->confineWin =
- (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin;
- 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)
- {
- if (deviceid < 0 || deviceid >= MAXDEVICES)
- FatalError("SetMaskForEvent: bogus device id");
- event_filters[deviceid][event] = mask;
- }
- void
- SetCriticalEvent(int event)
- {
- if (event >= MAXEVENTS)
- FatalError("SetCriticalEvent: bogus event number");
- criticalEvents[event >> 3] |= 1 << (event & 7);
- }
- void
- ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py)
- {
- BoxRec box;
- int x = *px, y = *py;
- int incx = 1, incy = 1;
- if (RegionContainsPoint(shape, x, y, &box))
- return;
- box = *RegionExtents(shape);
- /* this is rather crude */
- do {
- x += incx;
- if (x >= box.x2) {
- incx = -1;
- x = *px - 1;
- }
- else if (x < box.x1) {
- incx = 1;
- x = *px;
- y += incy;
- if (y >= box.y2) {
- incy = -1;
- y = *py - 1;
- }
- else if (y < box.y1)
- return; /* should never get here! */
- }
- } while (!RegionContainsPoint(shape, x, y, &box));
- *px = x;
- *py = y;
- }
- static void
- CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor, Bool generateEvents,
- Bool confineToScreen, /* unused if PanoramiX on */
- ScreenPtr pScreen) /* unused if PanoramiX on */
- {
- HotSpot new;
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- if (!cursor)
- return;
- new = pSprite->hotPhys;
- #ifdef PANORAMIX
- if (!noPanoramiXExtension)
- /* I don't care what the DDX has to say about it */
- pSprite->physLimits = pSprite->hotLimits;
- else
- #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 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)
- ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
- if ((
- #ifdef PANORAMIX
- noPanoramiXExtension &&
- #endif
- (pScreen != pSprite->hotPhys.pScreen)) ||
- (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) {
- #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);
- }
- #ifdef PANORAMIX
- /* Tell DDX what the limits are */
- if (!noPanoramiXExtension)
- XineramaConstrainCursor(pDev);
- #endif
- }
- static void
- CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- RegionPtr reg = NULL;
- DeviceEvent *ev = NULL;
- if (qe) {
- ev = &qe->event->device_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;
- #ifdef PANORAMIX
- if (!noPanoramiXExtension) {
- int x, y, off_x, off_y, i;
- if (!XineramaSetWindowPntrs(pDev, pWin))
- return;
- i = PanoramiXNumScreens - 1;
- RegionCopy(&pSprite->Reg2, &pSprite->windows[i]->borderSize);
- off_x = screenInfo.screens[i]->x;
- off_y = screenInfo.screens[i]->y;
- while (i--) {
- x = off_x - screenInfo.screens[i]->x;
- y = off_y - screenInfo.screens[i]->y;
- if (x || y)
- RegionTranslate(&pSprite->Reg2, x, y);
- RegionUnion(&pSprite->Reg2, &pSprite->Reg2,
- &pSprite->windows[i]->borderSize);
- off_x = screenInfo.screens[i]->x;
- off_y = screenInfo.screens[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 = *RegionExtents(&pWin->borderSize);
- 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;
- #ifdef PANORAMIX
- if (!noPanoramiXExtension) {
- if (RegionNumRects(&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;
- ev->root_x = pSprite->hot.x;
- ev->root_y = pSprite->hot.y;
- }
- }
- #ifdef PANORAMIX
- if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */
- #endif
- RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root;
- }
- static void
- ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents,
- Bool confineToScreen)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- if (syncEvents.playingEvents) {
- CheckVirtualMotion(pDev, (QdEventPtr) NULL, pWin);
- SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
- }
- else {
- #ifdef PANORAMIX
- if (!noPanoramiXExtension) {
- XineramaConfineCursorToWindow(pDev, pWin, generateEvents);
- return;
- }
- #endif
- pSprite->hotLimits = *RegionExtents(&pWin->borderSize);
- pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize
- : NullRegion;
- CheckPhysLimits(pDev, pSprite->current, generateEvents,
- confineToScreen, pWin->drawable.pScreen);
- }
- }
- Bool
- PointerConfinedToScreen(DeviceIntPtr pDev)
- {
- return pDev->spriteInfo->sprite->confined;
- }
- /**
- * Update the sprite cursor to the given cursor.
- *
- * ChangeToCursor() will display the new cursor and free the old cursor (if
- * applicable). If the provided cursor is already the updated cursor, nothing
- * happens.
- */
- static void
- ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- ScreenPtr pScreen;
- if (cursor != pSprite->current) {
- if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
- (pSprite->current->bits->yhot != cursor->bits->yhot))
- CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined,
- (ScreenPtr) NULL);
- #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 = RefCursor(cursor);
- }
- }
- /**
- * @returns true if b is a descendent of a
- */
- Bool
- IsParent(WindowPtr a, WindowPtr b)
- {
- for (b = b->parent; b; b = b->parent)
- if (b == a)
- return TRUE;
- return FALSE;
- }
- /**
- * Update the cursor displayed on the screen.
- *
- * Called whenever a cursor may have changed shape or position.
- */
- static void
- PostNewCursor(DeviceIntPtr pDev)
- {
- WindowPtr win;
- GrabPtr grab = pDev->deviceGrab.grab;
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- CursorPtr pCursor;
- if (syncEvents.playingEvents)
- return;
- if (grab) {
- if (grab->cursor) {
- ChangeToCursor(pDev, grab->cursor);
- return;
- }
- if (IsParent(grab->window, pSprite->win))
- win = pSprite->win;
- else
- win = grab->window;
- }
- else
- win = pSprite->win;
- for (; win; win = win->parent) {
- if (win->optional) {
- pCursor = WindowGetDeviceCursor(win, pDev);
- if (!pCursor && win->optional->cursor != NullCursor)
- pCursor = win->optional->cursor;
- if (pCursor) {
- ChangeToCursor(pDev, pCursor);
- return;
- }
- }
- }
- }
- /**
- * @param dev device which you want to know its current root window
- * @return root window where dev's sprite is located
- */
- WindowPtr
- GetCurrentRootWindow(DeviceIntPtr dev)
- {
- return RootWindow(dev->spriteInfo->sprite);
- }
- /**
- * @return window underneath the cursor sprite.
- */
- WindowPtr
- GetSpriteWindow(DeviceIntPtr pDev)
- {
- return pDev->spriteInfo->sprite->win;
- }
- /**
- * @return current sprite cursor.
- */
- CursorPtr
- GetSpriteCursor(DeviceIntPtr pDev)
- {
- return pDev->spriteInfo->sprite->current;
- }
- /**
- * Set x/y current sprite position in screen coordinates.
- */
- void
- GetSpritePosition(DeviceIntPtr pDev, int *px, int *py)
- {
- SpritePtr pSprite = pDev->spriteInfo->sprite;
- *px = pSprite->hotPhys.x;
- *py = pSprite->hotPhys.y;
- }
- #ifdef PANORAMIX
- int
- XineramaGetCursorScreen(DeviceIntPtr pDev)
- {
- if (!noPanoramiXExtension) {
- return pDev->spriteInfo->sprite->screen->myNum;
- }
- else {
- return 0;
- }
- }
- #endif /* PANORAMIX */
- #define TIMESLOP (5 * 60 * 1000) /* 5 minutes */
- static void
- MonthChangedOrBadTime(CARD32 *ms)
- {
- /* 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 - *ms) > TIMESLOP)
- currentTime.months++;
- else
- *ms = currentTime.milliseconds;
- }
- void
- NoticeTime(const DeviceIntPtr dev, TimeStamp time)
- {
- lastDeviceEventTime[XIAllDevices].time = currentTime;
- lastDeviceEventTime[dev->id].time = currentTime;
- LastEventTimeToggleResetFlag(dev->id, TRUE);
- LastEventTimeToggleResetFlag(XIAllDevices, TRUE);
- }
- static void
- NoticeTimeMillis(const DeviceIntPtr dev, CARD32 *ms)
- {
- TimeStamp time;
- if (*ms < currentTime.milliseconds)
- MonthChangedOrBadTime(ms);
- time.months = currentTime.months;
- time.milliseconds = *ms;
- NoticeTime(dev, time);
- }
- void
- NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev)
- {
- if (!syncEvents.playingEvents)
- NoticeTimeMillis(dev, &ev->any.time);
- }
- TimeStamp
- LastEventTime(int deviceid)
- {
- return lastDeviceEventTime[deviceid].time;
- }
- Bool
- LastEventTimeWasReset(int deviceid)
- {
- return lastDeviceEventTime[deviceid].reset;
- }
- void
- LastEventTimeToggleResetFlag(int deviceid, Bool state)
- {
- lastDeviceEventTime[deviceid].reset = state;
- }
- void
- LastEventTimeToggleResetAll(Bool state)
- {
- DeviceIntPtr dev;
- nt_list_for_each_entry(dev, inputInfo.devices, next) {
- LastEventTimeToggleResetFlag(dev->id, FALSE);
- }
- LastEventTimeToggleResetFlag(XIAllDevices, FALSE);
- LastEventTimeToggleResetFlag(XIAllMasterDevices, FALSE);
- }
- /**************************************************************************
- * The following procedures deal with synchronous events *
- **************************************************************************/
- /**
- * EnqueueEvent is a device's processInputProc if a device is frozen.
- * Instead of delivering the events to the client, the event is tacked onto a
- * linked list for later delivery.
- */
- void
- EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
- {
- QdEventPtr tail = NULL;
- QdEventPtr qe;
- SpritePtr pSprite = device->spriteInfo->sprite;
- int eventlen;
- DeviceEvent *event = &ev->device_event;
- if (!xorg_list_is_empty(&syncEvents.pending))
- tail = xorg_list_last_entry(&syncEvents.pending, QdEventRec, next);
- NoticeTimeMillis(device, &ev->any.time);
- /* Fix for key repeating bug. */
- if (device->key != NULL && device->key->xkbInfo != NULL &&
- event->type == ET_KeyRelease)
- AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key);
- if (DeviceEventCallback) {
- DeviceEventInfoRec eventinfo;
- /* The RECORD spec says that the root window field of motion events
- * must be valid. At this point, it hasn't been filled in yet, so
- * we do it here. The long expression below is necessary to get
- * the current root window; the apparently reasonable alternative
- * GetCurrentRootWindow()->drawable.id doesn't give you the right
- * answer on the first motion event after a screen change because
- * the data that GetCurrentRootWindow relies on hasn't been
- * updated yet.
- */
- if (ev->any.type == ET_Motion)
- ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
- eventinfo.event = ev;
- eventinfo.device = device;
- CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
- }
- if (event->type == ET_Motion) {
- #ifdef PANORAMIX
- if (!noPanoramiXExtension) {
- event->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
- event->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
- }
- #endif
- 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->any.type == ET_Motion) &&
- (tail->device == device) &&
- (tail->pScreen == pSprite->hotPhys.pScreen)) {
- DeviceEvent *tailev = &tail->event->device_event;
- tailev->root_x = pSprite->hotPhys.x;
- tailev->root_y = pSprite->hotPhys.y;
- tailev->time = event->time;
- tail->months = currentTime.months;
- return;
- }
- }
- eventlen = event->length;
- qe = malloc(sizeof(QdEventRec) + eventlen);
- if (!qe)
- return;
- xorg_list_init(&qe->next);
- qe->device = device;
- qe->pScreen = pSprite->hotPhys.pScreen;
- qe->months = currentTime.months;
- qe->event = (InternalEvent *) (qe + 1);
- memcpy(qe->event, event, eventlen);
- xorg_list_append(&qe->next, &syncEvents.pending);
- }
- /**
- * Run through the list of events queued up in syncEvents.
- * For each event do:
- * If the device for this event is not frozen anymore, take it and process it
- * as usually.
- * After that, check if there's any devices in the list that are not frozen.
- * If there is none, we're done. If there is at least one device that is not
- * frozen, then re-run from the beginning of the event queue.
- */
- void
- PlayReleasedEvents(void)
- {
- QdEventPtr tmp;
- QdEventPtr qe;
- DeviceIntPtr dev;
- DeviceIntPtr pDev;
- restart:
- xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) {
- if (!qe->device->deviceGrab.sync.frozen) {
- xorg_list_del(&qe->next);
- pDev = qe->device;
- if (qe->event->any.type == ET_Motion)
- CheckVirtualMotion(pDev, qe, NullWindow);
- syncEvents.time.months = qe->months;
- 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 */
- if (!noPanoramiXExtension) {
- DeviceEvent *ev = &qe->event->device_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:
- case ET_TouchBegin:
- case ET_TouchUpdate:
- case ET_TouchEnd:
- ev->root_x += screenInfo.screens[0]->x -
- pDev->spriteInfo->sprite->screen->x;
- ev->root_y += screenInfo.screens[0]->y -
- pDev->spriteInfo->sprite->screen->y;
- break;
- default:
- break;
- }
- }
- #endif
- (*qe->device->public.processInputProc) (qe->event, qe->device);
- free(qe);
- for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen;
- dev = dev->next);
- if (!dev)
- break;
- /* Playing the event may have unfrozen another device. */
- /* So to play it safe, restart at the head of the queue */
- goto restart;
- }
- }
- }
- /**
- * Freeze or thaw the given devices. The device's processing proc is
- * switched to either the real processing proc (in case of thawing) or an
- * enqueuing processing proc (usually EnqueueEvent()).
- *
- * @param dev The device to freeze/thaw
- * @param frozen True to freeze or false to thaw.
- */
- static void
- FreezeThaw(DeviceIntPtr dev, Bool frozen)
- {
- dev->deviceGrab.sync.frozen = frozen;
- if (frozen)
- dev->public.processInputProc = dev->public.enqueueInputProc;
- else
- dev->public.processInputProc = dev->public.realInputProc;
- }
- /**
- * Unfreeze devices and replay all events to the respective clients.
- *
- * ComputeFreezes takes the first event in the device's frozen event queue. It
- * 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.
- */
- static void
- ComputeFreezes(void)
- {
- DeviceIntPtr replayDev = syncEvents.replayDev;
- WindowPtr w;
- GrabPtr grab;
- DeviceIntPtr dev;
- for (dev = inputInfo.devices; dev; dev = dev->next)
- FreezeThaw(dev, dev->deviceGrab.sync.other ||
- (dev->deviceGrab.sync.state >= FROZEN));
- if (syncEvents.playingEvents ||
- (!replayDev && xorg_list_is_empty(&syncEvents.pending)))
- return;
- syncEvents.playingEvents = TRUE;
- if (replayDev) {
- DeviceEvent *event = replayDev->deviceGrab.sync.event;
- syncEvents.replayDev = (DeviceIntPtr) NULL;
- w = XYToWindow(replayDev->spriteInfo->sprite,
- event->root_x, event->root_y);
- if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) {
- if (IsTouchEvent((InternalEvent *) event)) {
- TouchPointInfoPtr ti =
- TouchFindByClientID(replayDev, event->touchid);
- BUG_WARN(!ti);
- TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
- }
- else if (replayDev->focus &&
- !IsPointerEvent((InternalEvent *) event))
- DeliverFocusedEvent(replayDev, (InternalEvent *) event, w);
- else
- DeliverDeviceEvents(w, (InternalEvent *) event, NullGrab,
- NullWindow, replayDev);
- }
- }
- for (dev = inputInfo.devices; dev; dev = dev->next) {
- if (!dev->deviceGrab.sync.frozen) {
- PlayReleasedEvents();
- break;
- }
- }
- syncEvents.playingEvents = FALSE;
- for (dev = inputInfo.devices; dev; dev = dev->next) {
- if (DevHasCursor(dev)) {
- /* the following may have been skipped during replay,
- so do it now */
- if ((grab = dev->deviceGrab.grab) && grab->confineTo) {
- if (grab->confineTo->drawable.pScreen !=
- dev->spriteInfo->sprite->hotPhys.pScreen)
- dev->spriteInfo->sprite->hotPhys.x =
- dev->spriteInfo->sprite->hotPhys.y = 0;
- ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE);
- }
- else
- ConfineCursorToWindow(dev,
- dev->spriteInfo->sprite->hotPhys.pScreen->
- root, TRUE, FALSE);
- PostNewCursor(dev);
- }
- }
- }
- #ifdef RANDR
- void
- ScreenRestructured(ScreenPtr pScreen)
- {
- GrabPtr grab;
- DeviceIntPtr pDev;
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
- if (!IsFloating(pDev) && !DevHasCursor(pDev))
- continue;
- /* GrabDevice doesn't have a confineTo field, so we don't need to
- * worry about it. */
- if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
- if (grab->confineTo->drawable.pScreen
- != pDev->spriteInfo->sprite->hotPhys.pScreen)
- pDev->spriteInfo->sprite->hotPhys.x =
- pDev->spriteInfo->sprite->hotPhys.y = 0;
- ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
- }
- else
- ConfineCursorToWindow(pDev,
- pDev->spriteInfo->sprite->hotPhys.pScreen->
- root, TRUE, FALSE);
- }
- }
- #endif
- static void
- CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
- {
- GrabPtr grab = thisDev->deviceGrab.grab;
- DeviceIntPtr dev;
- if (thisMode == GrabModeSync)
- thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT;
- else { /* free both if same client owns both */
- thisDev->deviceGrab.sync.state = THAWED;
- if (thisDev->deviceGrab.sync.other &&
- (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) ==
- CLIENT_BITS(grab->resource)))
- thisDev->deviceGrab.sync.other = NullGrab;
- }
- if (IsMaster(thisDev)) {
- dev = GetPairedDevice(thisDev);
- if (otherMode == GrabModeSync)
- dev->deviceGrab.sync.other = grab;
- else { /* free both if same client owns both */
- if (dev->deviceGrab.sync.other &&
- (CLIENT_BITS(dev->deviceGrab.sync.other->resource) ==
- CLIENT_BITS(grab->resource)))
- dev->deviceGrab.sync.other = NullGrab;
- }
- }
- ComputeFreezes();
- }
- /**
- * Save the device's master device id. 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)
- {
- if (IsFloating(dev))
- return;
- dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id;
- AttachDevice(NULL, dev, NULL);
- }
- static void
- ReattachToOldMaster(DeviceIntPtr dev)
- {
- DeviceIntPtr master = NULL;
- if (IsMaster(dev))
- return;
- dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess);
- if (master) {
- AttachDevice(serverClient, dev, master);
- dev->saved_master_id = 0;
- }
- }
- /**
- * Update touch records when an explicit grab is activated. Any touches owned by
- * the grabbing client are updated so the listener state reflects the new grab.
- */
- static void
- UpdateTouchesForGrab(DeviceIntPtr mouse)
- {
- int i;
- if (!mouse->touch || mouse->deviceGrab.fromPassiveGrab)
- return;
- for (i = 0; i < mouse->touch->num_touches; i++) {
- TouchPointInfoPtr ti = mouse->touch->touches + i;
- TouchListener *listener = &ti->listeners[0];
- GrabPtr grab = mouse->deviceGrab.grab;
- if (ti->active &&
- CLIENT_BITS(listener->listener) == grab->resource) {
- listener->listener = grab->resource;
- listener->level = grab->grabtype;
- listener->state = LISTENER_IS_OWNER;
- listener->window = grab->window;
- if (grab->grabtype == CORE || grab->grabtype == XI ||
- !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
- listener->type = LISTENER_POINTER_GRAB;
- else
- listener->type = LISTENER_GRAB;
- if (listener->grab)
- FreeGrab(listener->grab);
- listener->grab = AllocGrab(grab);
- }
- }
- }
- /**
- * 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.
- * No other device will send core events to the grab client while the grab is
- * on, but core events will be sent to other clients.
- * Can cause the cursor to change if a grab cursor is set.
- *
- * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab
- * is an implicit grab caused by a ButtonPress event.
- *
- * @param mouse The device to grab.
- * @param grab The grab structure, needs to be setup.
- * @param autoGrab True if the grab was caused by a button down event and not
- * explicitely by a client.
- */
- void
- ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
- TimeStamp time, Bool autoGrab)
- {
- GrabInfoPtr grabinfo = &mouse->deviceGrab;
- GrabPtr oldgrab = grabinfo->grab;
- WindowPtr oldWin = (grabinfo->grab) ?
- grabinfo->grab->window : mouse->spriteInfo->sprite->win;
- Bool isPassive = autoGrab & ~ImplicitGrabMask;
- /* slave devices need to float for the duration of the grab. */
- if (grab->grabtype == XI2 &&
- !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse))
- DetachFromMaster(mouse);
- if (grab->confineTo) {
- if (grab->confineTo->drawable.pScreen
- != mouse->spriteInfo->sprite->hotPhys.pScreen)
- mouse->spriteInfo->sprite->hotPhys.x =
- mouse->spriteInfo->sprite->hotPhys.y = 0;
- ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE);
- }
- DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab);
- mouse->valuator->motionHintWindow = NullWindow;
- if (syncEvents.playingEvents)
- grabinfo->grabTime = syncEvents.time;
- else
- grabinfo->grabTime = time;
- grabinfo->grab = AllocGrab(grab);
- grabinfo->fromPassiveGrab = isPassive;
- grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
- PostNewCursor(mouse);
- UpdateTouchesForGrab(mouse);
- CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
- (Bool) grab->keyboardMode);
- if (oldgrab)
- FreeGrab(oldgrab);
- }
- /**
- * Delete grab on given device, update the sprite.
- *
- * Extension devices are set up for ActivateKeyboardGrab().
- */
- void
- DeactivatePointerGrab(DeviceIntPtr mouse)
- {
- GrabPtr grab = mouse->deviceGrab.grab;
- DeviceIntPtr dev;
- Bool wasPassive = mouse->deviceGrab.fromPassiveGrab;
- Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
- mouse->deviceGrab.implicitGrab);
- XID grab_resource = grab->resource;
- int i;
- /* If an explicit grab was deactivated, we must remove it from the head of
- * all the touches' listener lists. */
- for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
- TouchPointInfoPtr ti = mouse->touch->touches + i;
- if (ti->active && TouchResourceIsOwner(ti, grab_resource)) {
- int mode = XIRejectTouch;
- /* Rejecting will generate a TouchEnd, but we must not
- emulate a ButtonRelease here. So pretend the listener
- already has the end event */
- if (grab->grabtype == CORE || grab->grabtype == XI ||
- …
Large files files are truncated, but you can click here to view the full file