events.c revision 35c4bbdf
105b261ecSmrg/************************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
294642e01fSmrgPermission to use, copy, modify, and distribute this software and its
304642e01fSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
324642e01fSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
354642e01fSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg********************************************************/
4605b261ecSmrg
4705b261ecSmrg/* The panoramix components contained the following notice */
4805b261ecSmrg/*****************************************************************
4905b261ecSmrg
5005b261ecSmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
5105b261ecSmrg
5205b261ecSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
5305b261ecSmrgof this software and associated documentation files (the "Software"), to deal
5405b261ecSmrgin the Software without restriction, including without limitation the rights
5505b261ecSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5605b261ecSmrgcopies of the Software.
5705b261ecSmrg
5805b261ecSmrgThe above copyright notice and this permission notice shall be included in
5905b261ecSmrgall copies or substantial portions of the Software.
6005b261ecSmrg
6105b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6205b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6305b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6405b261ecSmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
6505b261ecSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
6605b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
6705b261ecSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6805b261ecSmrg
6905b261ecSmrgExcept as contained in this notice, the name of Digital Equipment Corporation
7005b261ecSmrgshall not be used in advertising or otherwise to promote the sale, use or other
7105b261ecSmrgdealings in this Software without prior written authorization from Digital
7205b261ecSmrgEquipment Corporation.
7305b261ecSmrg
7405b261ecSmrg******************************************************************/
7505b261ecSmrg
766747b715Smrg/*
779ace9065Smrg * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved.
786747b715Smrg *
796747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
806747b715Smrg * copy of this software and associated documentation files (the "Software"),
816747b715Smrg * to deal in the Software without restriction, including without limitation
826747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
836747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
846747b715Smrg * Software is furnished to do so, subject to the following conditions:
856747b715Smrg *
866747b715Smrg * The above copyright notice and this permission notice (including the next
876747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
886747b715Smrg * Software.
896747b715Smrg *
906747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
916747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
926747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
936747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
946747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
956747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
966747b715Smrg * DEALINGS IN THE SOFTWARE.
976747b715Smrg */
9805b261ecSmrg
996747b715Smrg/** @file events.c
10005b261ecSmrg * This file handles event delivery and a big part of the server-side protocol
10105b261ecSmrg * handling (the parts for input devices).
10205b261ecSmrg */
10305b261ecSmrg
10405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
10505b261ecSmrg#include <dix-config.h>
10605b261ecSmrg#endif
10705b261ecSmrg
10805b261ecSmrg#include <X11/X.h>
10905b261ecSmrg#include "misc.h"
11005b261ecSmrg#include "resource.h"
11105b261ecSmrg#include <X11/Xproto.h>
11205b261ecSmrg#include "windowstr.h"
11305b261ecSmrg#include "inputstr.h"
11435c4bbdfSmrg#include "inpututils.h"
11505b261ecSmrg#include "scrnintstr.h"
11605b261ecSmrg#include "cursorstr.h"
11705b261ecSmrg
11805b261ecSmrg#include "dixstruct.h"
11905b261ecSmrg#ifdef PANORAMIX
12005b261ecSmrg#include "panoramiX.h"
12105b261ecSmrg#include "panoramiXsrv.h"
12205b261ecSmrg#endif
12305b261ecSmrg#include "globals.h"
12405b261ecSmrg
12505b261ecSmrg#include <X11/extensions/XKBproto.h>
1266747b715Smrg#include "xkbsrv.h"
12705b261ecSmrg#include "xace.h"
12835c4bbdfSmrg#include "probes.h"
12905b261ecSmrg
13005b261ecSmrg#include <X11/extensions/XIproto.h>
1316747b715Smrg#include <X11/extensions/XI2proto.h>
1324642e01fSmrg#include <X11/extensions/XI.h>
1336747b715Smrg#include <X11/extensions/XI2.h>
13405b261ecSmrg#include "exglobals.h"
13505b261ecSmrg#include "exevents.h"
13605b261ecSmrg#include "extnsionst.h"
13705b261ecSmrg
13805b261ecSmrg#include "dixevents.h"
13905b261ecSmrg#include "dixgrabs.h"
14005b261ecSmrg#include "dispatch.h"
1414642e01fSmrg
1424642e01fSmrg#include <X11/extensions/ge.h>
1434642e01fSmrg#include "geext.h"
1444642e01fSmrg#include "geint.h"
1454642e01fSmrg
1466747b715Smrg#include "eventstr.h"
1474642e01fSmrg#include "enterleave.h"
1486747b715Smrg#include "eventconvert.h"
14935c4bbdfSmrg#include "mi.h"
1504642e01fSmrg
1516747b715Smrg/* Extension events type numbering starts at EXTENSION_EVENT_BASE.  */
15235c4bbdfSmrg#define NoSuchEvent 0x80000000  /* so doesn't match NoEventMask */
15305b261ecSmrg#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
15405b261ecSmrg#define AllButtonsMask ( \
15505b261ecSmrg	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
15605b261ecSmrg#define MotionMask ( \
15705b261ecSmrg	PointerMotionMask | Button1MotionMask | \
15805b261ecSmrg	Button2MotionMask | Button3MotionMask | Button4MotionMask | \
15905b261ecSmrg	Button5MotionMask | ButtonMotionMask )
16005b261ecSmrg#define PropagateMask ( \
16105b261ecSmrg	KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
16205b261ecSmrg	MotionMask )
16305b261ecSmrg#define PointerGrabMask ( \
16405b261ecSmrg	ButtonPressMask | ButtonReleaseMask | \
16505b261ecSmrg	EnterWindowMask | LeaveWindowMask | \
16605b261ecSmrg	PointerMotionHintMask | KeymapStateMask | \
16705b261ecSmrg	MotionMask )
16805b261ecSmrg#define AllModifiersMask ( \
16905b261ecSmrg	ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
17005b261ecSmrg	Mod3Mask | Mod4Mask | Mod5Mask )
1716747b715Smrg#define LastEventMask OwnerGrabButtonMask
1726747b715Smrg#define AllEventMasks (LastEventMask|(LastEventMask-1))
1736747b715Smrg
17435c4bbdfSmrg/* @return the core event type or 0 if the event is not a core event */
17535c4bbdfSmrgstatic inline int
17635c4bbdfSmrgcore_get_type(const xEvent *event)
17735c4bbdfSmrg{
17835c4bbdfSmrg    int type = event->u.u.type;
17935c4bbdfSmrg
18035c4bbdfSmrg    return ((type & EXTENSION_EVENT_BASE) || type == GenericEvent) ? 0 : type;
18135c4bbdfSmrg}
18235c4bbdfSmrg
18335c4bbdfSmrg/* @return the XI2 event type or 0 if the event is not a XI2 event */
18435c4bbdfSmrgstatic inline int
18535c4bbdfSmrgxi2_get_type(const xEvent *event)
18635c4bbdfSmrg{
18735c4bbdfSmrg    const xGenericEvent *e = (const xGenericEvent *) event;
1886747b715Smrg
18935c4bbdfSmrg    return (e->type != GenericEvent ||
19035c4bbdfSmrg            e->extension != IReqCode) ? 0 : e->evtype;
19135c4bbdfSmrg}
1924642e01fSmrg
1934642e01fSmrg/**
1944642e01fSmrg * Used to indicate a implicit passive grab created by a ButtonPress event.
1954642e01fSmrg * See DeliverEventsToWindow().
1964642e01fSmrg */
1974642e01fSmrg#define ImplicitGrabMask (1 << 7)
19805b261ecSmrg
19905b261ecSmrg#define WID(w) ((w) ? ((w)->drawable.id) : 0)
20005b261ecSmrg
20105b261ecSmrg#define XE_KBPTR (xE->u.keyButtonPointer)
20205b261ecSmrg
2036747b715SmrgCallbackListPtr EventCallback;
2046747b715SmrgCallbackListPtr DeviceEventCallback;
20505b261ecSmrg
20605b261ecSmrg#define DNPMCOUNT 8
20705b261ecSmrg
20805b261ecSmrgMask DontPropagateMasks[DNPMCOUNT];
20905b261ecSmrgstatic int DontPropagateRefCnts[DNPMCOUNT];
21005b261ecSmrg
21135c4bbdfSmrgstatic void CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe,
21235c4bbdfSmrg                               WindowPtr pWin);
21335c4bbdfSmrgstatic void CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor,
21435c4bbdfSmrg                            Bool generateEvents, Bool confineToScreen,
2156747b715Smrg                            ScreenPtr pScreen);
21635c4bbdfSmrgstatic Bool IsWrongPointerBarrierClient(ClientPtr client,
21735c4bbdfSmrg                                        DeviceIntPtr dev,
21835c4bbdfSmrg                                        xEvent *event);
2196747b715Smrg
2206747b715Smrg/** Key repeat hack. Do not use but in TryClientEvents */
2216747b715Smrgextern BOOL EventIsKeyRepeat(xEvent *event);
2224642e01fSmrg
22305b261ecSmrg/**
2244642e01fSmrg * Main input device struct.
2254642e01fSmrg *     inputInfo.pointer
22605b261ecSmrg *     is the core pointer. Referred to as "virtual core pointer", "VCP",
2276747b715Smrg *     "core pointer" or inputInfo.pointer. The VCP is the first master
2284642e01fSmrg *     pointer device and cannot be deleted.
2294642e01fSmrg *
23005b261ecSmrg *     inputInfo.keyboard
23105b261ecSmrg *     is the core keyboard ("virtual core keyboard", "VCK", "core keyboard").
23205b261ecSmrg *     See inputInfo.pointer.
2334642e01fSmrg *
23405b261ecSmrg *     inputInfo.devices
2354642e01fSmrg *     linked list containing all devices including VCP and VCK.
23605b261ecSmrg *
23705b261ecSmrg *     inputInfo.off_devices
23805b261ecSmrg *     Devices that have not been initialized and are thus turned off.
23905b261ecSmrg *
24005b261ecSmrg *     inputInfo.numDevices
24105b261ecSmrg *     Total number of devices.
2426747b715Smrg *
2436747b715Smrg *     inputInfo.all_devices
2446747b715Smrg *     Virtual device used for XIAllDevices passive grabs. This device is
2456747b715Smrg *     not part of the inputInfo.devices list and mostly unset except for
2466747b715Smrg *     the deviceid. It exists because passivegrabs need a valid device
2476747b715Smrg *     reference.
2486747b715Smrg *
2496747b715Smrg *     inputInfo.all_master_devices
2506747b715Smrg *     Virtual device used for XIAllMasterDevices passive grabs. This device
2516747b715Smrg *     is not part of the inputInfo.devices list and mostly unset except for
2526747b715Smrg *     the deviceid. It exists because passivegrabs need a valid device
2536747b715Smrg *     reference.
25405b261ecSmrg */
2556747b715SmrgInputInfo inputInfo;
2566747b715Smrg
2576747b715SmrgEventSyncInfoRec syncEvents;
25805b261ecSmrg
25935c4bbdfSmrgstatic struct DeviceEventTime {
26035c4bbdfSmrg    Bool reset;
26135c4bbdfSmrg    TimeStamp time;
26235c4bbdfSmrg} lastDeviceEventTime[MAXDEVICES];
26335c4bbdfSmrg
2644642e01fSmrg/**
2656747b715Smrg * The root window the given device is currently on.
2664642e01fSmrg */
2679ace9065Smrg#define RootWindow(sprite) sprite->spriteTrace[0]
2684642e01fSmrg
26935c4bbdfSmrgstatic xEvent *swapEvent = NULL;
2704642e01fSmrgstatic int swapEventLen = 0;
2714642e01fSmrg
2726747b715Smrgvoid
2736747b715SmrgNotImplemented(xEvent *from, xEvent *to)
2746747b715Smrg{
2756747b715Smrg    FatalError("Not implemented");
2766747b715Smrg}
2776747b715Smrg
2784642e01fSmrg/**
2794642e01fSmrg * Convert the given event type from an XI event to a core event.
2806747b715Smrg * @param[in] The XI 1.x event type.
2814642e01fSmrg * @return The matching core event type or 0 if there is none.
28205b261ecSmrg */
2836747b715Smrgint
2844642e01fSmrgXItoCoreType(int xitype)
2854642e01fSmrg{
2864642e01fSmrg    int coretype = 0;
28735c4bbdfSmrg
2884642e01fSmrg    if (xitype == DeviceMotionNotify)
2894642e01fSmrg        coretype = MotionNotify;
2904642e01fSmrg    else if (xitype == DeviceButtonPress)
2914642e01fSmrg        coretype = ButtonPress;
2924642e01fSmrg    else if (xitype == DeviceButtonRelease)
2934642e01fSmrg        coretype = ButtonRelease;
2944642e01fSmrg    else if (xitype == DeviceKeyPress)
2954642e01fSmrg        coretype = KeyPress;
2964642e01fSmrg    else if (xitype == DeviceKeyRelease)
2974642e01fSmrg        coretype = KeyRelease;
2984642e01fSmrg
2994642e01fSmrg    return coretype;
3004642e01fSmrg}
30105b261ecSmrg
30205b261ecSmrg/**
3036747b715Smrg * @return true if the device owns a cursor, false if device shares a cursor
3046747b715Smrg * sprite with another device.
30505b261ecSmrg */
3066747b715SmrgBool
3074642e01fSmrgDevHasCursor(DeviceIntPtr pDev)
3084642e01fSmrg{
3094642e01fSmrg    return pDev->spriteInfo->spriteOwner;
3104642e01fSmrg}
31105b261ecSmrg
3124642e01fSmrg/*
3136747b715Smrg * @return true if a device is a pointer, check is the same as used by XI to
3144642e01fSmrg * fill the 'use' field.
3154642e01fSmrg */
3166747b715SmrgBool
3174642e01fSmrgIsPointerDevice(DeviceIntPtr dev)
3184642e01fSmrg{
3196747b715Smrg    return (dev->type == MASTER_POINTER) ||
32035c4bbdfSmrg        (dev->valuator && dev->button) || (dev->valuator && !dev->key);
3214642e01fSmrg}
32205b261ecSmrg
3234642e01fSmrg/*
3246747b715Smrg * @return true if a device is a keyboard, check is the same as used by XI to
3254642e01fSmrg * fill the 'use' field.
3264642e01fSmrg *
3274642e01fSmrg * Some pointer devices have keys as well (e.g. multimedia keys). Try to not
3284642e01fSmrg * count them as keyboard devices.
3294642e01fSmrg */
3306747b715SmrgBool
3314642e01fSmrgIsKeyboardDevice(DeviceIntPtr dev)
3324642e01fSmrg{
3336747b715Smrg    return (dev->type == MASTER_KEYBOARD) ||
33435c4bbdfSmrg        ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev));
3356747b715Smrg}
3366747b715Smrg
3376747b715SmrgBool
3386747b715SmrgIsMaster(DeviceIntPtr dev)
3396747b715Smrg{
3406747b715Smrg    return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
3414642e01fSmrg}
34205b261ecSmrg
34335c4bbdfSmrgBool
34435c4bbdfSmrgIsFloating(DeviceIntPtr dev)
34535c4bbdfSmrg{
34635c4bbdfSmrg    return !IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == NULL;
34735c4bbdfSmrg}
34835c4bbdfSmrg
34905b261ecSmrg/**
35005b261ecSmrg * Max event opcode.
35105b261ecSmrg */
35205b261ecSmrgextern int lastEvent;
35305b261ecSmrg
3546747b715Smrg#define CantBeFiltered NoEventMask
3554642e01fSmrg/**
3566747b715Smrg * Event masks for each event type.
3576747b715Smrg *
35835c4bbdfSmrg * One set of filters for each device, initialized by memcpy of
35935c4bbdfSmrg * default_filter in InitEvents.
3606747b715Smrg *
3616747b715Smrg * Filters are used whether a given event may be delivered to a client,
3626747b715Smrg * usually in the form of if (window-event-mask & filter); then deliver event.
3636747b715Smrg *
3646747b715Smrg * One notable filter is for PointerMotion/DevicePointerMotion events. Each
3656747b715Smrg * time a button is pressed, the filter is modified to also contain the
3666747b715Smrg * matching ButtonXMotion mask.
3674642e01fSmrg */
36835c4bbdfSmrgMask event_filters[MAXDEVICES][MAXEVENTS];
36935c4bbdfSmrg
37035c4bbdfSmrgstatic const Mask default_filter[MAXEVENTS] = {
37135c4bbdfSmrg    NoSuchEvent,                /* 0 */
37235c4bbdfSmrg    NoSuchEvent,                /* 1 */
37335c4bbdfSmrg    KeyPressMask,               /* KeyPress */
37435c4bbdfSmrg    KeyReleaseMask,             /* KeyRelease */
37535c4bbdfSmrg    ButtonPressMask,            /* ButtonPress */
37635c4bbdfSmrg    ButtonReleaseMask,          /* ButtonRelease */
37735c4bbdfSmrg    PointerMotionMask,          /* MotionNotify (initial state) */
37835c4bbdfSmrg    EnterWindowMask,            /* EnterNotify */
37935c4bbdfSmrg    LeaveWindowMask,            /* LeaveNotify */
38035c4bbdfSmrg    FocusChangeMask,            /* FocusIn */
38135c4bbdfSmrg    FocusChangeMask,            /* FocusOut */
38235c4bbdfSmrg    KeymapStateMask,            /* KeymapNotify */
38335c4bbdfSmrg    ExposureMask,               /* Expose */
38435c4bbdfSmrg    CantBeFiltered,             /* GraphicsExpose */
38535c4bbdfSmrg    CantBeFiltered,             /* NoExpose */
38635c4bbdfSmrg    VisibilityChangeMask,       /* VisibilityNotify */
38735c4bbdfSmrg    SubstructureNotifyMask,     /* CreateNotify */
38835c4bbdfSmrg    StructureAndSubMask,        /* DestroyNotify */
38935c4bbdfSmrg    StructureAndSubMask,        /* UnmapNotify */
39035c4bbdfSmrg    StructureAndSubMask,        /* MapNotify */
39135c4bbdfSmrg    SubstructureRedirectMask,   /* MapRequest */
39235c4bbdfSmrg    StructureAndSubMask,        /* ReparentNotify */
39335c4bbdfSmrg    StructureAndSubMask,        /* ConfigureNotify */
39435c4bbdfSmrg    SubstructureRedirectMask,   /* ConfigureRequest */
39535c4bbdfSmrg    StructureAndSubMask,        /* GravityNotify */
39635c4bbdfSmrg    ResizeRedirectMask,         /* ResizeRequest */
39735c4bbdfSmrg    StructureAndSubMask,        /* CirculateNotify */
39835c4bbdfSmrg    SubstructureRedirectMask,   /* CirculateRequest */
39935c4bbdfSmrg    PropertyChangeMask,         /* PropertyNotify */
40035c4bbdfSmrg    CantBeFiltered,             /* SelectionClear */
40135c4bbdfSmrg    CantBeFiltered,             /* SelectionRequest */
40235c4bbdfSmrg    CantBeFiltered,             /* SelectionNotify */
40335c4bbdfSmrg    ColormapChangeMask,         /* ColormapNotify */
40435c4bbdfSmrg    CantBeFiltered,             /* ClientMessage */
40535c4bbdfSmrg    CantBeFiltered              /* MappingNotify */
40635c4bbdfSmrg};
4074642e01fSmrg
4086747b715Smrg/**
4096747b715Smrg * For the given event, return the matching event filter. This filter may then
4106747b715Smrg * be AND'ed with the selected event mask.
4116747b715Smrg *
4126747b715Smrg * For XI2 events, the returned filter is simply the byte containing the event
4136747b715Smrg * mask we're interested in. E.g. for a mask of (1 << 13), this would be
4146747b715Smrg * byte[1].
4156747b715Smrg *
4166747b715Smrg * @param[in] dev The device the event belongs to, may be NULL.
4176747b715Smrg * @param[in] event The event to get the filter for. Only the type of the
4186747b715Smrg *                  event matters, or the extension + evtype for GenericEvents.
4196747b715Smrg * @return The filter mask for the given event.
4206747b715Smrg *
4216747b715Smrg * @see GetEventMask
4226747b715Smrg */
4236747b715SmrgMask
4246747b715SmrgGetEventFilter(DeviceIntPtr dev, xEvent *event)
4256747b715Smrg{
42635c4bbdfSmrg    int evtype = 0;
42735c4bbdfSmrg
4286747b715Smrg    if (event->u.u.type != GenericEvent)
42935c4bbdfSmrg        return event_get_filter_from_type(dev, event->u.u.type);
43035c4bbdfSmrg    else if ((evtype = xi2_get_type(event)))
43135c4bbdfSmrg        return event_get_filter_from_xi2type(evtype);
4329ace9065Smrg    ErrorF("[dix] Unknown event type %d. No filter\n", event->u.u.type);
4336747b715Smrg    return 0;
4346747b715Smrg}
4354642e01fSmrg
4364642e01fSmrg/**
43735c4bbdfSmrg * Return the single byte of the device's XI2 mask that contains the mask
43835c4bbdfSmrg * for the event_type.
4394642e01fSmrg */
44035c4bbdfSmrgint
44135c4bbdfSmrgGetXI2MaskByte(XI2Mask *mask, DeviceIntPtr dev, int event_type)
44235c4bbdfSmrg{
44335c4bbdfSmrg    /* we just return the matching filter because that's the only use
44435c4bbdfSmrg     * for this mask anyway.
44535c4bbdfSmrg     */
44635c4bbdfSmrg    if (xi2mask_isset(mask, dev, event_type))
44735c4bbdfSmrg        return event_get_filter_from_xi2type(event_type);
44835c4bbdfSmrg    else
44935c4bbdfSmrg        return 0;
45035c4bbdfSmrg}
45135c4bbdfSmrg
45235c4bbdfSmrg/**
45335c4bbdfSmrg * @return TRUE if the mask is set for this event from this device on the
45435c4bbdfSmrg * window, or FALSE otherwise.
45535c4bbdfSmrg */
45635c4bbdfSmrgBool
45735c4bbdfSmrgWindowXI2MaskIsset(DeviceIntPtr dev, WindowPtr win, xEvent *ev)
4586747b715Smrg{
4596747b715Smrg    OtherInputMasks *inputMasks = wOtherInputMasks(win);
4606747b715Smrg    int evtype;
4616747b715Smrg
46235c4bbdfSmrg    if (!inputMasks || xi2_get_type(ev) == 0)
4636747b715Smrg        return 0;
4646747b715Smrg
46535c4bbdfSmrg    evtype = ((xGenericEvent *) ev)->evtype;
4666747b715Smrg
46735c4bbdfSmrg    return xi2mask_isset(inputMasks->xi2mask, dev, evtype);
4686747b715Smrg}
4696747b715Smrg
4709ace9065SmrgMask
47135c4bbdfSmrgGetEventMask(DeviceIntPtr dev, xEvent *event, InputClients * other)
4726747b715Smrg{
47335c4bbdfSmrg    int evtype;
47435c4bbdfSmrg
4756747b715Smrg    /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */
47635c4bbdfSmrg    if ((evtype = xi2_get_type(event))) {
47735c4bbdfSmrg        return GetXI2MaskByte(other->xi2mask, dev, evtype);
47835c4bbdfSmrg    }
47935c4bbdfSmrg    else if (core_get_type(event) != 0)
4806747b715Smrg        return other->mask[XIAllDevices];
4816747b715Smrg    else
4826747b715Smrg        return other->mask[dev->id];
4836747b715Smrg}
4846747b715Smrg
48535c4bbdfSmrgstatic CARD8 criticalEvents[32] = {
48635c4bbdfSmrg    0x7c, 0x30, 0x40            /* key, button, expose, and configure events */
48705b261ecSmrg};
48805b261ecSmrg
4896747b715Smrgstatic void
49035c4bbdfSmrgSyntheticMotion(DeviceIntPtr dev, int x, int y)
49135c4bbdfSmrg{
4926747b715Smrg    int screenno = 0;
4936747b715Smrg
4946747b715Smrg#ifdef PANORAMIX
4956747b715Smrg    if (!noPanoramiXExtension)
4966747b715Smrg        screenno = dev->spriteInfo->sprite->screen->myNum;
4976747b715Smrg#endif
4986747b715Smrg    PostSyntheticMotion(dev, x, y, screenno,
49935c4bbdfSmrg                        (syncEvents.playingEvents) ? syncEvents.time.
50035c4bbdfSmrg                        milliseconds : currentTime.milliseconds);
5016747b715Smrg
5026747b715Smrg}
5036747b715Smrg
50405b261ecSmrg#ifdef PANORAMIX
5054642e01fSmrgstatic void PostNewCursor(DeviceIntPtr pDev);
50605b261ecSmrg
5076747b715Smrgstatic Bool
50835c4bbdfSmrgXineramaSetCursorPosition(DeviceIntPtr pDev, int x, int y, Bool generateEvent)
5096747b715Smrg{
51005b261ecSmrg    ScreenPtr pScreen;
51105b261ecSmrg    int i;
5124642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
51305b261ecSmrg
51405b261ecSmrg    /* x,y are in Screen 0 coordinates.  We need to decide what Screen
5154642e01fSmrg       to send the message too and what the coordinates relative to
51605b261ecSmrg       that screen are. */
51705b261ecSmrg
5184642e01fSmrg    pScreen = pSprite->screen;
5196747b715Smrg    x += screenInfo.screens[0]->x;
5206747b715Smrg    y += screenInfo.screens[0]->y;
52105b261ecSmrg
52235c4bbdfSmrg    if (!point_on_screen(pScreen, x, y)) {
52335c4bbdfSmrg        FOR_NSCREENS(i) {
52435c4bbdfSmrg            if (i == pScreen->myNum)
52535c4bbdfSmrg                continue;
52635c4bbdfSmrg            if (point_on_screen(screenInfo.screens[i], x, y)) {
52735c4bbdfSmrg                pScreen = screenInfo.screens[i];
52835c4bbdfSmrg                break;
52935c4bbdfSmrg            }
53035c4bbdfSmrg        }
53105b261ecSmrg    }
53205b261ecSmrg
5334642e01fSmrg    pSprite->screen = pScreen;
5346747b715Smrg    pSprite->hotPhys.x = x - screenInfo.screens[0]->x;
5356747b715Smrg    pSprite->hotPhys.y = y - screenInfo.screens[0]->y;
5366747b715Smrg    x -= pScreen->x;
5376747b715Smrg    y -= pScreen->y;
53805b261ecSmrg
53935c4bbdfSmrg    return (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
54005b261ecSmrg}
54105b261ecSmrg
54205b261ecSmrgstatic void
5434642e01fSmrgXineramaConstrainCursor(DeviceIntPtr pDev)
54405b261ecSmrg{
5454642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
5464642e01fSmrg    ScreenPtr pScreen;
5474642e01fSmrg    BoxRec newBox;
5484642e01fSmrg
5494642e01fSmrg    pScreen = pSprite->screen;
5504642e01fSmrg    newBox = pSprite->physLimits;
55105b261ecSmrg
55205b261ecSmrg    /* Translate the constraining box to the screen
55305b261ecSmrg       the sprite is actually on */
5546747b715Smrg    newBox.x1 += screenInfo.screens[0]->x - pScreen->x;
5556747b715Smrg    newBox.x2 += screenInfo.screens[0]->x - pScreen->x;
5566747b715Smrg    newBox.y1 += screenInfo.screens[0]->y - pScreen->y;
5576747b715Smrg    newBox.y2 += screenInfo.screens[0]->y - pScreen->y;
55805b261ecSmrg
55935c4bbdfSmrg    (*pScreen->ConstrainCursor) (pDev, pScreen, &newBox);
56005b261ecSmrg}
56105b261ecSmrg
56205b261ecSmrgstatic Bool
5634642e01fSmrgXineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin)
56405b261ecSmrg{
5654642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
5664642e01fSmrg
56735c4bbdfSmrg    if (pWin == screenInfo.screens[0]->root) {
56835c4bbdfSmrg        int i;
56935c4bbdfSmrg
57035c4bbdfSmrg        FOR_NSCREENS(i)
57135c4bbdfSmrg            pSprite->windows[i] = screenInfo.screens[i]->root;
57235c4bbdfSmrg    }
57335c4bbdfSmrg    else {
57435c4bbdfSmrg        PanoramiXRes *win;
57535c4bbdfSmrg        int rc, i;
57635c4bbdfSmrg
57735c4bbdfSmrg        rc = dixLookupResourceByType((void **) &win, pWin->drawable.id,
57835c4bbdfSmrg                                     XRT_WINDOW, serverClient, DixReadAccess);
57935c4bbdfSmrg        if (rc != Success)
58035c4bbdfSmrg            return FALSE;
58135c4bbdfSmrg
58235c4bbdfSmrg        FOR_NSCREENS(i) {
58335c4bbdfSmrg            rc = dixLookupWindow(pSprite->windows + i, win->info[i].id,
58435c4bbdfSmrg                                 serverClient, DixReadAccess);
58535c4bbdfSmrg            if (rc != Success)  /* window is being unmapped */
58635c4bbdfSmrg                return FALSE;
58735c4bbdfSmrg        }
58805b261ecSmrg    }
58905b261ecSmrg    return TRUE;
59005b261ecSmrg}
59105b261ecSmrg
59205b261ecSmrgstatic void
5934642e01fSmrgXineramaConfineCursorToWindow(DeviceIntPtr pDev,
59435c4bbdfSmrg                              WindowPtr pWin, Bool generateEvents)
59505b261ecSmrg{
5964642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
59705b261ecSmrg
5986747b715Smrg    int x, y, off_x, off_y, i;
59905b261ecSmrg
60035c4bbdfSmrg    if (!XineramaSetWindowPntrs(pDev, pWin))
6016747b715Smrg        return;
6024642e01fSmrg
6036747b715Smrg    i = PanoramiXNumScreens - 1;
60405b261ecSmrg
60535c4bbdfSmrg    RegionCopy(&pSprite->Reg1, &pSprite->windows[i]->borderSize);
6066747b715Smrg    off_x = screenInfo.screens[i]->x;
6076747b715Smrg    off_y = screenInfo.screens[i]->y;
60805b261ecSmrg
60935c4bbdfSmrg    while (i--) {
6106747b715Smrg        x = off_x - screenInfo.screens[i]->x;
6116747b715Smrg        y = off_y - screenInfo.screens[i]->y;
61205b261ecSmrg
61335c4bbdfSmrg        if (x || y)
6146747b715Smrg            RegionTranslate(&pSprite->Reg1, x, y);
61505b261ecSmrg
6166747b715Smrg        RegionUnion(&pSprite->Reg1, &pSprite->Reg1,
61735c4bbdfSmrg                    &pSprite->windows[i]->borderSize);
6184642e01fSmrg
6196747b715Smrg        off_x = screenInfo.screens[i]->x;
6206747b715Smrg        off_y = screenInfo.screens[i]->y;
62105b261ecSmrg    }
62205b261ecSmrg
6236747b715Smrg    pSprite->hotLimits = *RegionExtents(&pSprite->Reg1);
62405b261ecSmrg
62535c4bbdfSmrg    if (RegionNumRects(&pSprite->Reg1) > 1)
6266747b715Smrg        pSprite->hotShape = &pSprite->Reg1;
6276747b715Smrg    else
6286747b715Smrg        pSprite->hotShape = NullRegion;
6294642e01fSmrg
6306747b715Smrg    pSprite->confined = FALSE;
63135c4bbdfSmrg    pSprite->confineWin =
63235c4bbdfSmrg        (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin;
63305b261ecSmrg
6346747b715Smrg    CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL);
6356747b715Smrg}
63605b261ecSmrg
63735c4bbdfSmrg#endif                          /* PANORAMIX */
63805b261ecSmrg
6396747b715Smrg/**
6406747b715Smrg * Modifies the filter for the given protocol event type to the given masks.
6416747b715Smrg *
6426747b715Smrg * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent().
6436747b715Smrg * The latter initialises masks for the matching XI events, it's a once-off
6446747b715Smrg * setting.
6456747b715Smrg * UDS however changes the mask for MotionNotify and DeviceMotionNotify each
6466747b715Smrg * time a button is pressed to include the matching ButtonXMotion mask in the
6476747b715Smrg * filter.
6486747b715Smrg *
6496747b715Smrg * @param[in] deviceid The device to modify the filter for.
6506747b715Smrg * @param[in] mask The new filter mask.
6516747b715Smrg * @param[in] event Protocol event type.
6526747b715Smrg */
65305b261ecSmrgvoid
6544642e01fSmrgSetMaskForEvent(int deviceid, Mask mask, int event)
65505b261ecSmrg{
65652397711Smrg    if (deviceid < 0 || deviceid >= MAXDEVICES)
6574642e01fSmrg        FatalError("SetMaskForEvent: bogus device id");
65835c4bbdfSmrg    event_filters[deviceid][event] = mask;
65905b261ecSmrg}
66005b261ecSmrg
6616747b715Smrgvoid
66205b261ecSmrgSetCriticalEvent(int event)
66305b261ecSmrg{
66435c4bbdfSmrg    if (event >= MAXEVENTS)
66535c4bbdfSmrg        FatalError("SetCriticalEvent: bogus event number");
66605b261ecSmrg    criticalEvents[event >> 3] |= 1 << (event & 7);
66705b261ecSmrg}
66805b261ecSmrg
6694642e01fSmrgvoid
6704642e01fSmrgConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py)
67105b261ecSmrg{
67205b261ecSmrg    BoxRec box;
67305b261ecSmrg    int x = *px, y = *py;
67405b261ecSmrg    int incx = 1, incy = 1;
67505b261ecSmrg
6766747b715Smrg    if (RegionContainsPoint(shape, x, y, &box))
67735c4bbdfSmrg        return;
6786747b715Smrg    box = *RegionExtents(shape);
67905b261ecSmrg    /* this is rather crude */
68005b261ecSmrg    do {
68135c4bbdfSmrg        x += incx;
68235c4bbdfSmrg        if (x >= box.x2) {
68335c4bbdfSmrg            incx = -1;
68435c4bbdfSmrg            x = *px - 1;
68535c4bbdfSmrg        }
68635c4bbdfSmrg        else if (x < box.x1) {
68735c4bbdfSmrg            incx = 1;
68835c4bbdfSmrg            x = *px;
68935c4bbdfSmrg            y += incy;
69035c4bbdfSmrg            if (y >= box.y2) {
69135c4bbdfSmrg                incy = -1;
69235c4bbdfSmrg                y = *py - 1;
69335c4bbdfSmrg            }
69435c4bbdfSmrg            else if (y < box.y1)
69535c4bbdfSmrg                return;         /* should never get here! */
69635c4bbdfSmrg        }
6976747b715Smrg    } while (!RegionContainsPoint(shape, x, y, &box));
69805b261ecSmrg    *px = x;
69905b261ecSmrg    *py = y;
70005b261ecSmrg}
70105b261ecSmrg
70205b261ecSmrgstatic void
70335c4bbdfSmrgCheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor, Bool generateEvents,
70435c4bbdfSmrg                Bool confineToScreen, /* unused if PanoramiX on */
70535c4bbdfSmrg                ScreenPtr pScreen)    /* unused if PanoramiX on */
70605b261ecSmrg{
70705b261ecSmrg    HotSpot new;
7084642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
70905b261ecSmrg
71005b261ecSmrg    if (!cursor)
71135c4bbdfSmrg        return;
7124642e01fSmrg    new = pSprite->hotPhys;
7136747b715Smrg#ifdef PANORAMIX
7146747b715Smrg    if (!noPanoramiXExtension)
7156747b715Smrg        /* I don't care what the DDX has to say about it */
7166747b715Smrg        pSprite->physLimits = pSprite->hotLimits;
71705b261ecSmrg    else
7186747b715Smrg#endif
7196747b715Smrg    {
7206747b715Smrg        if (pScreen)
7216747b715Smrg            new.pScreen = pScreen;
7226747b715Smrg        else
7236747b715Smrg            pScreen = new.pScreen;
7246747b715Smrg        (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits,
72535c4bbdfSmrg                                  &pSprite->physLimits);
7266747b715Smrg        pSprite->confined = confineToScreen;
72735c4bbdfSmrg        (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
7286747b715Smrg    }
7296747b715Smrg
7306747b715Smrg    /* constrain the pointer to those limits */
7314642e01fSmrg    if (new.x < pSprite->physLimits.x1)
73235c4bbdfSmrg        new.x = pSprite->physLimits.x1;
73335c4bbdfSmrg    else if (new.x >= pSprite->physLimits.x2)
73435c4bbdfSmrg        new.x = pSprite->physLimits.x2 - 1;
7354642e01fSmrg    if (new.y < pSprite->physLimits.y1)
73635c4bbdfSmrg        new.y = pSprite->physLimits.y1;
73735c4bbdfSmrg    else if (new.y >= pSprite->physLimits.y2)
73835c4bbdfSmrg        new.y = pSprite->physLimits.y2 - 1;
7394642e01fSmrg    if (pSprite->hotShape)
74035c4bbdfSmrg        ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
7416747b715Smrg    if ((
7426747b715Smrg#ifdef PANORAMIX
7436747b715Smrg            noPanoramiXExtension &&
7446747b715Smrg#endif
7456747b715Smrg            (pScreen != pSprite->hotPhys.pScreen)) ||
74635c4bbdfSmrg        (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) {
7476747b715Smrg#ifdef PANORAMIX
7486747b715Smrg        if (!noPanoramiXExtension)
74935c4bbdfSmrg            XineramaSetCursorPosition(pDev, new.x, new.y, generateEvents);
7506747b715Smrg        else
7516747b715Smrg#endif
7526747b715Smrg        {
7536747b715Smrg            if (pScreen != pSprite->hotPhys.pScreen)
7546747b715Smrg                pSprite->hotPhys = new;
7556747b715Smrg            (*pScreen->SetCursorPosition)
7566747b715Smrg                (pDev, pScreen, new.x, new.y, generateEvents);
7576747b715Smrg        }
7584642e01fSmrg        if (!generateEvents)
7596747b715Smrg            SyntheticMotion(pDev, new.x, new.y);
76005b261ecSmrg    }
7616747b715Smrg
7626747b715Smrg#ifdef PANORAMIX
7636747b715Smrg    /* Tell DDX what the limits are */
7646747b715Smrg    if (!noPanoramiXExtension)
7656747b715Smrg        XineramaConstrainCursor(pDev);
7666747b715Smrg#endif
76705b261ecSmrg}
76805b261ecSmrg
76905b261ecSmrgstatic void
77035c4bbdfSmrgCheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin)
77105b261ecSmrg{
7724642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
7736747b715Smrg    RegionPtr reg = NULL;
7746747b715Smrg    DeviceEvent *ev = NULL;
7754642e01fSmrg
77635c4bbdfSmrg    if (qe) {
7776747b715Smrg        ev = &qe->event->device_event;
77835c4bbdfSmrg        switch (ev->type) {
77935c4bbdfSmrg        case ET_Motion:
78035c4bbdfSmrg        case ET_ButtonPress:
78135c4bbdfSmrg        case ET_ButtonRelease:
78235c4bbdfSmrg        case ET_KeyPress:
78335c4bbdfSmrg        case ET_KeyRelease:
78435c4bbdfSmrg        case ET_ProximityIn:
78535c4bbdfSmrg        case ET_ProximityOut:
78635c4bbdfSmrg            pSprite->hot.pScreen = qe->pScreen;
78735c4bbdfSmrg            pSprite->hot.x = ev->root_x;
78835c4bbdfSmrg            pSprite->hot.y = ev->root_y;
78935c4bbdfSmrg            pWin =
79035c4bbdfSmrg                pDev->deviceGrab.grab ? pDev->deviceGrab.grab->
79135c4bbdfSmrg                confineTo : NullWindow;
79235c4bbdfSmrg            break;
79335c4bbdfSmrg        default:
79435c4bbdfSmrg            break;
7956747b715Smrg        }
79605b261ecSmrg    }
79735c4bbdfSmrg    if (pWin) {
79835c4bbdfSmrg        BoxRec lims;
79905b261ecSmrg
8006747b715Smrg#ifdef PANORAMIX
8016747b715Smrg        if (!noPanoramiXExtension) {
8026747b715Smrg            int x, y, off_x, off_y, i;
8036747b715Smrg
80435c4bbdfSmrg            if (!XineramaSetWindowPntrs(pDev, pWin))
8056747b715Smrg                return;
8066747b715Smrg
8076747b715Smrg            i = PanoramiXNumScreens - 1;
8086747b715Smrg
80935c4bbdfSmrg            RegionCopy(&pSprite->Reg2, &pSprite->windows[i]->borderSize);
8106747b715Smrg            off_x = screenInfo.screens[i]->x;
8116747b715Smrg            off_y = screenInfo.screens[i]->y;
8126747b715Smrg
81335c4bbdfSmrg            while (i--) {
8146747b715Smrg                x = off_x - screenInfo.screens[i]->x;
8156747b715Smrg                y = off_y - screenInfo.screens[i]->y;
8166747b715Smrg
81735c4bbdfSmrg                if (x || y)
8186747b715Smrg                    RegionTranslate(&pSprite->Reg2, x, y);
8196747b715Smrg
8206747b715Smrg                RegionUnion(&pSprite->Reg2, &pSprite->Reg2,
82135c4bbdfSmrg                            &pSprite->windows[i]->borderSize);
8226747b715Smrg
8236747b715Smrg                off_x = screenInfo.screens[i]->x;
8246747b715Smrg                off_y = screenInfo.screens[i]->y;
8256747b715Smrg            }
82635c4bbdfSmrg        }
82735c4bbdfSmrg        else
8286747b715Smrg#endif
8296747b715Smrg        {
83035c4bbdfSmrg            if (pSprite->hot.pScreen != pWin->drawable.pScreen) {
8316747b715Smrg                pSprite->hot.pScreen = pWin->drawable.pScreen;
8326747b715Smrg                pSprite->hot.x = pSprite->hot.y = 0;
8336747b715Smrg            }
8346747b715Smrg        }
8356747b715Smrg
83635c4bbdfSmrg        lims = *RegionExtents(&pWin->borderSize);
83735c4bbdfSmrg        if (pSprite->hot.x < lims.x1)
83835c4bbdfSmrg            pSprite->hot.x = lims.x1;
83935c4bbdfSmrg        else if (pSprite->hot.x >= lims.x2)
84035c4bbdfSmrg            pSprite->hot.x = lims.x2 - 1;
84135c4bbdfSmrg        if (pSprite->hot.y < lims.y1)
84235c4bbdfSmrg            pSprite->hot.y = lims.y1;
84335c4bbdfSmrg        else if (pSprite->hot.y >= lims.y2)
84435c4bbdfSmrg            pSprite->hot.y = lims.y2 - 1;
8456747b715Smrg
8466747b715Smrg#ifdef PANORAMIX
84735c4bbdfSmrg        if (!noPanoramiXExtension) {
8486747b715Smrg            if (RegionNumRects(&pSprite->Reg2) > 1)
8496747b715Smrg                reg = &pSprite->Reg2;
8506747b715Smrg
85135c4bbdfSmrg        }
85235c4bbdfSmrg        else
8536747b715Smrg#endif
8546747b715Smrg        {
8556747b715Smrg            if (wBoundingShape(pWin))
8566747b715Smrg                reg = &pWin->borderSize;
8576747b715Smrg        }
8586747b715Smrg
8596747b715Smrg        if (reg)
8606747b715Smrg            ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y);
8616747b715Smrg
86235c4bbdfSmrg        if (qe && ev) {
86335c4bbdfSmrg            qe->pScreen = pSprite->hot.pScreen;
86435c4bbdfSmrg            ev->root_x = pSprite->hot.x;
86535c4bbdfSmrg            ev->root_y = pSprite->hot.y;
86635c4bbdfSmrg        }
86705b261ecSmrg    }
8686747b715Smrg#ifdef PANORAMIX
86935c4bbdfSmrg    if (noPanoramiXExtension)   /* No typo. Only set the root win if disabled */
8706747b715Smrg#endif
8719ace9065Smrg        RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root;
87205b261ecSmrg}
87305b261ecSmrg
87405b261ecSmrgstatic void
87535c4bbdfSmrgConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents,
87635c4bbdfSmrg                      Bool confineToScreen)
87705b261ecSmrg{
8784642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
87905b261ecSmrg
88035c4bbdfSmrg    if (syncEvents.playingEvents) {
88135c4bbdfSmrg        CheckVirtualMotion(pDev, (QdEventPtr) NULL, pWin);
88235c4bbdfSmrg        SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
88305b261ecSmrg    }
88435c4bbdfSmrg    else {
8856747b715Smrg#ifdef PANORAMIX
88635c4bbdfSmrg        if (!noPanoramiXExtension) {
8876747b715Smrg            XineramaConfineCursorToWindow(pDev, pWin, generateEvents);
8886747b715Smrg            return;
8896747b715Smrg        }
8906747b715Smrg#endif
89135c4bbdfSmrg        pSprite->hotLimits = *RegionExtents(&pWin->borderSize);
89235c4bbdfSmrg        pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize
89335c4bbdfSmrg            : NullRegion;
8944642e01fSmrg        CheckPhysLimits(pDev, pSprite->current, generateEvents,
8956747b715Smrg                        confineToScreen, pWin->drawable.pScreen);
89605b261ecSmrg    }
89705b261ecSmrg}
89805b261ecSmrg
8996747b715SmrgBool
9004642e01fSmrgPointerConfinedToScreen(DeviceIntPtr pDev)
90105b261ecSmrg{
9024642e01fSmrg    return pDev->spriteInfo->sprite->confined;
90305b261ecSmrg}
90405b261ecSmrg
90505b261ecSmrg/**
90605b261ecSmrg * Update the sprite cursor to the given cursor.
90705b261ecSmrg *
90805b261ecSmrg * ChangeToCursor() will display the new cursor and free the old cursor (if
90905b261ecSmrg * applicable). If the provided cursor is already the updated cursor, nothing
91005b261ecSmrg * happens.
91105b261ecSmrg */
91205b261ecSmrgstatic void
9134642e01fSmrgChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
91405b261ecSmrg{
9154642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
9166747b715Smrg    ScreenPtr pScreen;
91705b261ecSmrg
91835c4bbdfSmrg    if (cursor != pSprite->current) {
91935c4bbdfSmrg        if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
92035c4bbdfSmrg            (pSprite->current->bits->yhot != cursor->bits->yhot))
92135c4bbdfSmrg            CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined,
92235c4bbdfSmrg                            (ScreenPtr) NULL);
9236747b715Smrg#ifdef PANORAMIX
9246747b715Smrg        /* XXX: is this really necessary?? (whot) */
9256747b715Smrg        if (!noPanoramiXExtension)
9266747b715Smrg            pScreen = pSprite->screen;
9276747b715Smrg        else
9286747b715Smrg#endif
9296747b715Smrg            pScreen = pSprite->hotPhys.pScreen;
9306747b715Smrg
93135c4bbdfSmrg        (*pScreen->DisplayCursor) (pDev, pScreen, cursor);
93235c4bbdfSmrg        FreeCursor(pSprite->current, (Cursor) 0);
93335c4bbdfSmrg        pSprite->current = RefCursor(cursor);
93405b261ecSmrg    }
93505b261ecSmrg}
93605b261ecSmrg
93705b261ecSmrg/**
9384642e01fSmrg * @returns true if b is a descendent of a
93905b261ecSmrg */
94005b261ecSmrgBool
94105b261ecSmrgIsParent(WindowPtr a, WindowPtr b)
94205b261ecSmrg{
94305b261ecSmrg    for (b = b->parent; b; b = b->parent)
94435c4bbdfSmrg        if (b == a)
94535c4bbdfSmrg            return TRUE;
94605b261ecSmrg    return FALSE;
94705b261ecSmrg}
94805b261ecSmrg
94905b261ecSmrg/**
95005b261ecSmrg * Update the cursor displayed on the screen.
95105b261ecSmrg *
9524642e01fSmrg * Called whenever a cursor may have changed shape or position.
95305b261ecSmrg */
95405b261ecSmrgstatic void
9554642e01fSmrgPostNewCursor(DeviceIntPtr pDev)
95605b261ecSmrg{
95705b261ecSmrg    WindowPtr win;
9584642e01fSmrg    GrabPtr grab = pDev->deviceGrab.grab;
95935c4bbdfSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
96035c4bbdfSmrg    CursorPtr pCursor;
96105b261ecSmrg
96205b261ecSmrg    if (syncEvents.playingEvents)
96335c4bbdfSmrg        return;
96435c4bbdfSmrg    if (grab) {
96535c4bbdfSmrg        if (grab->cursor) {
96635c4bbdfSmrg            ChangeToCursor(pDev, grab->cursor);
96735c4bbdfSmrg            return;
96835c4bbdfSmrg        }
96935c4bbdfSmrg        if (IsParent(grab->window, pSprite->win))
97035c4bbdfSmrg            win = pSprite->win;
97135c4bbdfSmrg        else
97235c4bbdfSmrg            win = grab->window;
97305b261ecSmrg    }
97405b261ecSmrg    else
97535c4bbdfSmrg        win = pSprite->win;
97635c4bbdfSmrg    for (; win; win = win->parent) {
97735c4bbdfSmrg        if (win->optional) {
9784642e01fSmrg            pCursor = WindowGetDeviceCursor(win, pDev);
9794642e01fSmrg            if (!pCursor && win->optional->cursor != NullCursor)
9804642e01fSmrg                pCursor = win->optional->cursor;
98135c4bbdfSmrg            if (pCursor) {
9824642e01fSmrg                ChangeToCursor(pDev, pCursor);
9834642e01fSmrg                return;
9844642e01fSmrg            }
98535c4bbdfSmrg        }
9864642e01fSmrg    }
98705b261ecSmrg}
98805b261ecSmrg
98905b261ecSmrg/**
9904642e01fSmrg * @param dev device which you want to know its current root window
9914642e01fSmrg * @return root window where dev's sprite is located
99205b261ecSmrg */
9936747b715SmrgWindowPtr
9944642e01fSmrgGetCurrentRootWindow(DeviceIntPtr dev)
99505b261ecSmrg{
9969ace9065Smrg    return RootWindow(dev->spriteInfo->sprite);
99705b261ecSmrg}
99805b261ecSmrg
99905b261ecSmrg/**
100005b261ecSmrg * @return window underneath the cursor sprite.
100105b261ecSmrg */
10026747b715SmrgWindowPtr
10034642e01fSmrgGetSpriteWindow(DeviceIntPtr pDev)
100405b261ecSmrg{
10054642e01fSmrg    return pDev->spriteInfo->sprite->win;
100605b261ecSmrg}
100705b261ecSmrg
100805b261ecSmrg/**
100905b261ecSmrg * @return current sprite cursor.
101005b261ecSmrg */
10116747b715SmrgCursorPtr
10124642e01fSmrgGetSpriteCursor(DeviceIntPtr pDev)
101305b261ecSmrg{
10144642e01fSmrg    return pDev->spriteInfo->sprite->current;
101505b261ecSmrg}
101605b261ecSmrg
101705b261ecSmrg/**
101805b261ecSmrg * Set x/y current sprite position in screen coordinates.
101905b261ecSmrg */
10206747b715Smrgvoid
10214642e01fSmrgGetSpritePosition(DeviceIntPtr pDev, int *px, int *py)
102205b261ecSmrg{
10234642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
102435c4bbdfSmrg
10254642e01fSmrg    *px = pSprite->hotPhys.x;
10264642e01fSmrg    *py = pSprite->hotPhys.y;
102705b261ecSmrg}
102805b261ecSmrg
102905b261ecSmrg#ifdef PANORAMIX
10306747b715Smrgint
10314642e01fSmrgXineramaGetCursorScreen(DeviceIntPtr pDev)
103205b261ecSmrg{
103335c4bbdfSmrg    if (!noPanoramiXExtension) {
103435c4bbdfSmrg        return pDev->spriteInfo->sprite->screen->myNum;
103535c4bbdfSmrg    }
103635c4bbdfSmrg    else {
103735c4bbdfSmrg        return 0;
103805b261ecSmrg    }
103905b261ecSmrg}
104035c4bbdfSmrg#endif                          /* PANORAMIX */
104105b261ecSmrg
104235c4bbdfSmrg#define TIMESLOP (5 * 60 * 1000)        /* 5 minutes */
104305b261ecSmrg
104405b261ecSmrgstatic void
104535c4bbdfSmrgMonthChangedOrBadTime(CARD32 *ms)
104605b261ecSmrg{
104705b261ecSmrg    /* If the ddx/OS is careless about not processing timestamped events from
104805b261ecSmrg     * different sources in sorted order, then it's possible for time to go
104905b261ecSmrg     * backwards when it should not.  Here we ensure a decent time.
105005b261ecSmrg     */
105135c4bbdfSmrg    if ((currentTime.milliseconds - *ms) > TIMESLOP)
105235c4bbdfSmrg        currentTime.months++;
105305b261ecSmrg    else
105435c4bbdfSmrg        *ms = currentTime.milliseconds;
105535c4bbdfSmrg}
105635c4bbdfSmrg
105735c4bbdfSmrgvoid
105835c4bbdfSmrgNoticeTime(const DeviceIntPtr dev, TimeStamp time)
105935c4bbdfSmrg{
106035c4bbdfSmrg    currentTime = time;
106135c4bbdfSmrg    lastDeviceEventTime[XIAllDevices].time = currentTime;
106235c4bbdfSmrg    lastDeviceEventTime[dev->id].time = currentTime;
106335c4bbdfSmrg
106435c4bbdfSmrg    LastEventTimeToggleResetFlag(dev->id, TRUE);
106535c4bbdfSmrg    LastEventTimeToggleResetFlag(XIAllDevices, TRUE);
106605b261ecSmrg}
106705b261ecSmrg
10686747b715Smrgstatic void
106935c4bbdfSmrgNoticeTimeMillis(const DeviceIntPtr dev, CARD32 *ms)
10706747b715Smrg{
107135c4bbdfSmrg    TimeStamp time;
107235c4bbdfSmrg    if (*ms < currentTime.milliseconds)
107335c4bbdfSmrg        MonthChangedOrBadTime(ms);
107435c4bbdfSmrg    time.months = currentTime.months;
107535c4bbdfSmrg    time.milliseconds = *ms;
107635c4bbdfSmrg    NoticeTime(dev, time);
10776747b715Smrg}
107805b261ecSmrg
107905b261ecSmrgvoid
108035c4bbdfSmrgNoticeEventTime(InternalEvent *ev, DeviceIntPtr dev)
108105b261ecSmrg{
108205b261ecSmrg    if (!syncEvents.playingEvents)
108335c4bbdfSmrg        NoticeTimeMillis(dev, &ev->any.time);
108435c4bbdfSmrg}
108535c4bbdfSmrg
108635c4bbdfSmrgTimeStamp
108735c4bbdfSmrgLastEventTime(int deviceid)
108835c4bbdfSmrg{
108935c4bbdfSmrg    return lastDeviceEventTime[deviceid].time;
109035c4bbdfSmrg}
109135c4bbdfSmrg
109235c4bbdfSmrgBool
109335c4bbdfSmrgLastEventTimeWasReset(int deviceid)
109435c4bbdfSmrg{
109535c4bbdfSmrg    return lastDeviceEventTime[deviceid].reset;
109635c4bbdfSmrg}
109735c4bbdfSmrg
109835c4bbdfSmrgvoid
109935c4bbdfSmrgLastEventTimeToggleResetFlag(int deviceid, Bool state)
110035c4bbdfSmrg{
110135c4bbdfSmrg    lastDeviceEventTime[deviceid].reset = state;
110235c4bbdfSmrg}
110335c4bbdfSmrg
110435c4bbdfSmrgvoid
110535c4bbdfSmrgLastEventTimeToggleResetAll(Bool state)
110635c4bbdfSmrg{
110735c4bbdfSmrg    DeviceIntPtr dev;
110835c4bbdfSmrg    nt_list_for_each_entry(dev, inputInfo.devices, next) {
110935c4bbdfSmrg        LastEventTimeToggleResetFlag(dev->id, FALSE);
111035c4bbdfSmrg    }
111135c4bbdfSmrg    LastEventTimeToggleResetFlag(XIAllDevices, FALSE);
111235c4bbdfSmrg    LastEventTimeToggleResetFlag(XIAllMasterDevices, FALSE);
111305b261ecSmrg}
111405b261ecSmrg
111505b261ecSmrg/**************************************************************************
111605b261ecSmrg *            The following procedures deal with synchronous events       *
111705b261ecSmrg **************************************************************************/
111805b261ecSmrg
11194642e01fSmrg/**
11204642e01fSmrg * EnqueueEvent is a device's processInputProc if a device is frozen.
11214642e01fSmrg * Instead of delivering the events to the client, the event is tacked onto a
11224642e01fSmrg * linked list for later delivery.
11234642e01fSmrg */
112405b261ecSmrgvoid
11256747b715SmrgEnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
112605b261ecSmrg{
112735c4bbdfSmrg    QdEventPtr tail = NULL;
112835c4bbdfSmrg    QdEventPtr qe;
112935c4bbdfSmrg    SpritePtr pSprite = device->spriteInfo->sprite;
113035c4bbdfSmrg    int eventlen;
11316747b715Smrg    DeviceEvent *event = &ev->device_event;
11324642e01fSmrg
113335c4bbdfSmrg    if (!xorg_list_is_empty(&syncEvents.pending))
113435c4bbdfSmrg        tail = xorg_list_last_entry(&syncEvents.pending, QdEventRec, next);
113535c4bbdfSmrg
113635c4bbdfSmrg    NoticeTimeMillis(device, &ev->any.time);
113705b261ecSmrg
113805b261ecSmrg    /* Fix for key repeating bug. */
11394642e01fSmrg    if (device->key != NULL && device->key->xkbInfo != NULL &&
11406747b715Smrg        event->type == ET_KeyRelease)
114135c4bbdfSmrg        AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key);
114235c4bbdfSmrg
114335c4bbdfSmrg    if (DeviceEventCallback) {
114435c4bbdfSmrg        DeviceEventInfoRec eventinfo;
114535c4bbdfSmrg
114635c4bbdfSmrg        /*  The RECORD spec says that the root window field of motion events
114735c4bbdfSmrg         *  must be valid.  At this point, it hasn't been filled in yet, so
114835c4bbdfSmrg         *  we do it here.  The long expression below is necessary to get
114935c4bbdfSmrg         *  the current root window; the apparently reasonable alternative
115035c4bbdfSmrg         *  GetCurrentRootWindow()->drawable.id doesn't give you the right
115135c4bbdfSmrg         *  answer on the first motion event after a screen change because
115235c4bbdfSmrg         *  the data that GetCurrentRootWindow relies on hasn't been
115335c4bbdfSmrg         *  updated yet.
115435c4bbdfSmrg         */
115535c4bbdfSmrg        if (ev->any.type == ET_Motion)
115635c4bbdfSmrg            ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
115705b261ecSmrg
115835c4bbdfSmrg        eventinfo.event = ev;
115935c4bbdfSmrg        eventinfo.device = device;
116035c4bbdfSmrg        CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
116135c4bbdfSmrg    }
116235c4bbdfSmrg
116335c4bbdfSmrg    if (event->type == ET_Motion) {
116405b261ecSmrg#ifdef PANORAMIX
116535c4bbdfSmrg        if (!noPanoramiXExtension) {
116635c4bbdfSmrg            event->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
116735c4bbdfSmrg            event->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
116835c4bbdfSmrg        }
116905b261ecSmrg#endif
117035c4bbdfSmrg        pSprite->hotPhys.x = event->root_x;
117135c4bbdfSmrg        pSprite->hotPhys.y = event->root_y;
117235c4bbdfSmrg        /* do motion compression, but not if from different devices */
117335c4bbdfSmrg        if (tail &&
117435c4bbdfSmrg            (tail->event->any.type == ET_Motion) &&
117505b261ecSmrg            (tail->device == device) &&
117635c4bbdfSmrg            (tail->pScreen == pSprite->hotPhys.pScreen)) {
11776747b715Smrg            DeviceEvent *tailev = &tail->event->device_event;
117835c4bbdfSmrg
117935c4bbdfSmrg            tailev->root_x = pSprite->hotPhys.x;
118035c4bbdfSmrg            tailev->root_y = pSprite->hotPhys.y;
118135c4bbdfSmrg            tailev->time = event->time;
118235c4bbdfSmrg            tail->months = currentTime.months;
118335c4bbdfSmrg            return;
118435c4bbdfSmrg        }
118505b261ecSmrg    }
11864642e01fSmrg
11876747b715Smrg    eventlen = event->length;
11884642e01fSmrg
11896747b715Smrg    qe = malloc(sizeof(QdEventRec) + eventlen);
119005b261ecSmrg    if (!qe)
119135c4bbdfSmrg        return;
119235c4bbdfSmrg    xorg_list_init(&qe->next);
119305b261ecSmrg    qe->device = device;
11944642e01fSmrg    qe->pScreen = pSprite->hotPhys.pScreen;
119505b261ecSmrg    qe->months = currentTime.months;
119635c4bbdfSmrg    qe->event = (InternalEvent *) (qe + 1);
11976747b715Smrg    memcpy(qe->event, event, eventlen);
119835c4bbdfSmrg    xorg_list_append(&qe->next, &syncEvents.pending);
119905b261ecSmrg}
120005b261ecSmrg
12014642e01fSmrg/**
12024642e01fSmrg * Run through the list of events queued up in syncEvents.
12034642e01fSmrg * For each event do:
12044642e01fSmrg * If the device for this event is not frozen anymore, take it and process it
12054642e01fSmrg * as usually.
12064642e01fSmrg * After that, check if there's any devices in the list that are not frozen.
12074642e01fSmrg * If there is none, we're done. If there is at least one device that is not
12084642e01fSmrg * frozen, then re-run from the beginning of the event queue.
12094642e01fSmrg */
121035c4bbdfSmrgvoid
121105b261ecSmrgPlayReleasedEvents(void)
121205b261ecSmrg{
121335c4bbdfSmrg    QdEventPtr tmp;
121435c4bbdfSmrg    QdEventPtr qe;
121505b261ecSmrg    DeviceIntPtr dev;
12164642e01fSmrg    DeviceIntPtr pDev;
121705b261ecSmrg
121835c4bbdfSmrg restart:
121935c4bbdfSmrg    xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) {
122035c4bbdfSmrg        if (!qe->device->deviceGrab.sync.frozen) {
122135c4bbdfSmrg            xorg_list_del(&qe->next);
12224642e01fSmrg            pDev = qe->device;
122335c4bbdfSmrg            if (qe->event->any.type == ET_Motion)
122435c4bbdfSmrg                CheckVirtualMotion(pDev, qe, NullWindow);
122535c4bbdfSmrg            syncEvents.time.months = qe->months;
12266747b715Smrg            syncEvents.time.milliseconds = qe->event->any.time;
122705b261ecSmrg#ifdef PANORAMIX
122835c4bbdfSmrg            /* Translate back to the sprite screen since processInputProc
122935c4bbdfSmrg               will translate from sprite screen to screen 0 upon reentry
123035c4bbdfSmrg               to the DIX layer */
123135c4bbdfSmrg            if (!noPanoramiXExtension) {
12326747b715Smrg                DeviceEvent *ev = &qe->event->device_event;
123335c4bbdfSmrg
123435c4bbdfSmrg                switch (ev->type) {
123535c4bbdfSmrg                case ET_Motion:
123635c4bbdfSmrg                case ET_ButtonPress:
123735c4bbdfSmrg                case ET_ButtonRelease:
123835c4bbdfSmrg                case ET_KeyPress:
123935c4bbdfSmrg                case ET_KeyRelease:
124035c4bbdfSmrg                case ET_ProximityIn:
124135c4bbdfSmrg                case ET_ProximityOut:
124235c4bbdfSmrg                case ET_TouchBegin:
124335c4bbdfSmrg                case ET_TouchUpdate:
124435c4bbdfSmrg                case ET_TouchEnd:
124535c4bbdfSmrg                    ev->root_x += screenInfo.screens[0]->x -
124635c4bbdfSmrg                        pDev->spriteInfo->sprite->screen->x;
124735c4bbdfSmrg                    ev->root_y += screenInfo.screens[0]->y -
124835c4bbdfSmrg                        pDev->spriteInfo->sprite->screen->y;
124935c4bbdfSmrg                    break;
125035c4bbdfSmrg                default:
125135c4bbdfSmrg                    break;
12526747b715Smrg                }
12536747b715Smrg
125435c4bbdfSmrg            }
125505b261ecSmrg#endif
125635c4bbdfSmrg            (*qe->device->public.processInputProc) (qe->event, qe->device);
125735c4bbdfSmrg            free(qe);
125835c4bbdfSmrg            for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen;
125935c4bbdfSmrg                 dev = dev->next);
126035c4bbdfSmrg            if (!dev)
126135c4bbdfSmrg                break;
126235c4bbdfSmrg
126335c4bbdfSmrg            /* Playing the event may have unfrozen another device. */
126435c4bbdfSmrg            /* So to play it safe, restart at the head of the queue */
126535c4bbdfSmrg            goto restart;
126635c4bbdfSmrg        }
12674642e01fSmrg    }
126805b261ecSmrg}
126905b261ecSmrg
12704642e01fSmrg/**
12714642e01fSmrg * Freeze or thaw the given devices. The device's processing proc is
12724642e01fSmrg * switched to either the real processing proc (in case of thawing) or an
12734642e01fSmrg * enqueuing processing proc (usually EnqueueEvent()).
12744642e01fSmrg *
12754642e01fSmrg * @param dev The device to freeze/thaw
12764642e01fSmrg * @param frozen True to freeze or false to thaw.
12774642e01fSmrg */
127805b261ecSmrgstatic void
127905b261ecSmrgFreezeThaw(DeviceIntPtr dev, Bool frozen)
128005b261ecSmrg{
12814642e01fSmrg    dev->deviceGrab.sync.frozen = frozen;
128205b261ecSmrg    if (frozen)
128335c4bbdfSmrg        dev->public.processInputProc = dev->public.enqueueInputProc;
128405b261ecSmrg    else
128535c4bbdfSmrg        dev->public.processInputProc = dev->public.realInputProc;
128605b261ecSmrg}
128705b261ecSmrg
12884642e01fSmrg/**
12894642e01fSmrg * Unfreeze devices and replay all events to the respective clients.
12904642e01fSmrg *
12914642e01fSmrg * ComputeFreezes takes the first event in the device's frozen event queue. It
12924642e01fSmrg * runs up the sprite tree (spriteTrace) and searches for the window to replay
12934642e01fSmrg * the events from. If it is found, it checks for passive grabs one down from
12944642e01fSmrg * the window or delivers the events.
12954642e01fSmrg */
12964642e01fSmrgstatic void
129705b261ecSmrgComputeFreezes(void)
129805b261ecSmrg{
129905b261ecSmrg    DeviceIntPtr replayDev = syncEvents.replayDev;
130005b261ecSmrg    WindowPtr w;
130105b261ecSmrg    GrabPtr grab;
130205b261ecSmrg    DeviceIntPtr dev;
130305b261ecSmrg
130405b261ecSmrg    for (dev = inputInfo.devices; dev; dev = dev->next)
130535c4bbdfSmrg        FreezeThaw(dev, dev->deviceGrab.sync.other ||
130635c4bbdfSmrg                   (dev->deviceGrab.sync.state >= FROZEN));
130735c4bbdfSmrg    if (syncEvents.playingEvents ||
130835c4bbdfSmrg        (!replayDev && xorg_list_is_empty(&syncEvents.pending)))
130935c4bbdfSmrg        return;
131005b261ecSmrg    syncEvents.playingEvents = TRUE;
131135c4bbdfSmrg    if (replayDev) {
131235c4bbdfSmrg        DeviceEvent *event = replayDev->deviceGrab.sync.event;
13136747b715Smrg
131435c4bbdfSmrg        syncEvents.replayDev = (DeviceIntPtr) NULL;
131505b261ecSmrg
13169ace9065Smrg        w = XYToWindow(replayDev->spriteInfo->sprite,
13179ace9065Smrg                       event->root_x, event->root_y);
131835c4bbdfSmrg        if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) {
131935c4bbdfSmrg            if (IsTouchEvent((InternalEvent *) event)) {
132035c4bbdfSmrg                TouchPointInfoPtr ti =
132135c4bbdfSmrg                    TouchFindByClientID(replayDev, event->touchid);
132235c4bbdfSmrg                BUG_WARN(!ti);
132335c4bbdfSmrg
132435c4bbdfSmrg                TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
132535c4bbdfSmrg            }
132635c4bbdfSmrg            else if (replayDev->focus &&
132735c4bbdfSmrg                     !IsPointerEvent((InternalEvent *) event))
132835c4bbdfSmrg                DeliverFocusedEvent(replayDev, (InternalEvent *) event, w);
13299ace9065Smrg            else
133035c4bbdfSmrg                DeliverDeviceEvents(w, (InternalEvent *) event, NullGrab,
13319ace9065Smrg                                    NullWindow, replayDev);
13329ace9065Smrg        }
133305b261ecSmrg    }
133435c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
133535c4bbdfSmrg        if (!dev->deviceGrab.sync.frozen) {
133635c4bbdfSmrg            PlayReleasedEvents();
133735c4bbdfSmrg            break;
133835c4bbdfSmrg        }
133905b261ecSmrg    }
134005b261ecSmrg    syncEvents.playingEvents = FALSE;
134135c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
134235c4bbdfSmrg        if (DevHasCursor(dev)) {
13434642e01fSmrg            /* the following may have been skipped during replay,
134435c4bbdfSmrg               so do it now */
134535c4bbdfSmrg            if ((grab = dev->deviceGrab.grab) && grab->confineTo) {
13464642e01fSmrg                if (grab->confineTo->drawable.pScreen !=
134735c4bbdfSmrg                    dev->spriteInfo->sprite->hotPhys.pScreen)
13484642e01fSmrg                    dev->spriteInfo->sprite->hotPhys.x =
13494642e01fSmrg                        dev->spriteInfo->sprite->hotPhys.y = 0;
13504642e01fSmrg                ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE);
13514642e01fSmrg            }
13524642e01fSmrg            else
13534642e01fSmrg                ConfineCursorToWindow(dev,
135435c4bbdfSmrg                                      dev->spriteInfo->sprite->hotPhys.pScreen->
135535c4bbdfSmrg                                      root, TRUE, FALSE);
13564642e01fSmrg            PostNewCursor(dev);
13574642e01fSmrg        }
135805b261ecSmrg    }
135905b261ecSmrg}
136005b261ecSmrg
136105b261ecSmrg#ifdef RANDR
136205b261ecSmrgvoid
136335c4bbdfSmrgScreenRestructured(ScreenPtr pScreen)
136405b261ecSmrg{
136505b261ecSmrg    GrabPtr grab;
13664642e01fSmrg    DeviceIntPtr pDev;
136705b261ecSmrg
136835c4bbdfSmrg    for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
136935c4bbdfSmrg        if (!IsFloating(pDev) && !DevHasCursor(pDev))
13704642e01fSmrg            continue;
13714642e01fSmrg
13724642e01fSmrg        /* GrabDevice doesn't have a confineTo field, so we don't need to
13734642e01fSmrg         * worry about it. */
137435c4bbdfSmrg        if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
13754642e01fSmrg            if (grab->confineTo->drawable.pScreen
137635c4bbdfSmrg                != pDev->spriteInfo->sprite->hotPhys.pScreen)
137735c4bbdfSmrg                pDev->spriteInfo->sprite->hotPhys.x =
137835c4bbdfSmrg                    pDev->spriteInfo->sprite->hotPhys.y = 0;
13794642e01fSmrg            ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
13804642e01fSmrg        }
13814642e01fSmrg        else
13824642e01fSmrg            ConfineCursorToWindow(pDev,
138335c4bbdfSmrg                                  pDev->spriteInfo->sprite->hotPhys.pScreen->
138435c4bbdfSmrg                                  root, TRUE, FALSE);
138505b261ecSmrg    }
138605b261ecSmrg}
138705b261ecSmrg#endif
138805b261ecSmrg
13894642e01fSmrgstatic void
139005b261ecSmrgCheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
139105b261ecSmrg{
13924642e01fSmrg    GrabPtr grab = thisDev->deviceGrab.grab;
139305b261ecSmrg    DeviceIntPtr dev;
139405b261ecSmrg
139505b261ecSmrg    if (thisMode == GrabModeSync)
139635c4bbdfSmrg        thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT;
139735c4bbdfSmrg    else {                      /* free both if same client owns both */
139835c4bbdfSmrg        thisDev->deviceGrab.sync.state = THAWED;
139935c4bbdfSmrg        if (thisDev->deviceGrab.sync.other &&
140035c4bbdfSmrg            (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) ==
140135c4bbdfSmrg             CLIENT_BITS(grab->resource)))
140235c4bbdfSmrg            thisDev->deviceGrab.sync.other = NullGrab;
140305b261ecSmrg    }
14044642e01fSmrg
140535c4bbdfSmrg    if (IsMaster(thisDev)) {
14064642e01fSmrg        dev = GetPairedDevice(thisDev);
14074642e01fSmrg        if (otherMode == GrabModeSync)
14084642e01fSmrg            dev->deviceGrab.sync.other = grab;
140935c4bbdfSmrg        else {                  /* free both if same client owns both */
14104642e01fSmrg            if (dev->deviceGrab.sync.other &&
141135c4bbdfSmrg                (CLIENT_BITS(dev->deviceGrab.sync.other->resource) ==
141235c4bbdfSmrg                 CLIENT_BITS(grab->resource)))
14134642e01fSmrg                dev->deviceGrab.sync.other = NullGrab;
14144642e01fSmrg        }
141505b261ecSmrg    }
141605b261ecSmrg    ComputeFreezes();
141705b261ecSmrg}
141805b261ecSmrg
14196747b715Smrg/**
14206747b715Smrg * Save the device's master device id. This needs to be done
14216747b715Smrg * if a client directly grabs a slave device that is attached to a master. For
14226747b715Smrg * the duration of the grab, the device is detached, ungrabbing re-attaches it
14236747b715Smrg * though.
14246747b715Smrg *
14256747b715Smrg * We store the ID of the master device only in case the master disappears
14266747b715Smrg * while the device has a grab.
14276747b715Smrg */
14286747b715Smrgstatic void
14296747b715SmrgDetachFromMaster(DeviceIntPtr dev)
14306747b715Smrg{
143135c4bbdfSmrg    if (IsFloating(dev))
14326747b715Smrg        return;
14336747b715Smrg
143435c4bbdfSmrg    dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id;
14356747b715Smrg
14366747b715Smrg    AttachDevice(NULL, dev, NULL);
14376747b715Smrg}
14386747b715Smrg
14396747b715Smrgstatic void
14406747b715SmrgReattachToOldMaster(DeviceIntPtr dev)
14416747b715Smrg{
14426747b715Smrg    DeviceIntPtr master = NULL;
14436747b715Smrg
14446747b715Smrg    if (IsMaster(dev))
14456747b715Smrg        return;
14466747b715Smrg
14476747b715Smrg    dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess);
14486747b715Smrg
144935c4bbdfSmrg    if (master) {
14506747b715Smrg        AttachDevice(serverClient, dev, master);
145135c4bbdfSmrg        dev->saved_master_id = 0;
145235c4bbdfSmrg    }
145335c4bbdfSmrg}
145435c4bbdfSmrg
145535c4bbdfSmrg/**
145635c4bbdfSmrg * Update touch records when an explicit grab is activated. Any touches owned by
145735c4bbdfSmrg * the grabbing client are updated so the listener state reflects the new grab.
145835c4bbdfSmrg */
145935c4bbdfSmrgstatic void
146035c4bbdfSmrgUpdateTouchesForGrab(DeviceIntPtr mouse)
146135c4bbdfSmrg{
146235c4bbdfSmrg    int i;
146335c4bbdfSmrg
146435c4bbdfSmrg    if (!mouse->touch || mouse->deviceGrab.fromPassiveGrab)
146535c4bbdfSmrg        return;
146635c4bbdfSmrg
146735c4bbdfSmrg    for (i = 0; i < mouse->touch->num_touches; i++) {
146835c4bbdfSmrg        TouchPointInfoPtr ti = mouse->touch->touches + i;
146935c4bbdfSmrg        TouchListener *listener = &ti->listeners[0];
147035c4bbdfSmrg        GrabPtr grab = mouse->deviceGrab.grab;
147135c4bbdfSmrg
147235c4bbdfSmrg        if (ti->active &&
147335c4bbdfSmrg            CLIENT_BITS(listener->listener) == grab->resource) {
147435c4bbdfSmrg            listener->listener = grab->resource;
147535c4bbdfSmrg            listener->level = grab->grabtype;
147635c4bbdfSmrg            listener->state = LISTENER_IS_OWNER;
147735c4bbdfSmrg            listener->window = grab->window;
147835c4bbdfSmrg
147935c4bbdfSmrg            if (grab->grabtype == CORE || grab->grabtype == XI ||
148035c4bbdfSmrg                !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
148135c4bbdfSmrg                listener->type = LISTENER_POINTER_GRAB;
148235c4bbdfSmrg            else
148335c4bbdfSmrg                listener->type = LISTENER_GRAB;
148435c4bbdfSmrg            if (listener->grab)
148535c4bbdfSmrg                FreeGrab(listener->grab);
148635c4bbdfSmrg            listener->grab = AllocGrab(grab);
148735c4bbdfSmrg        }
14886747b715Smrg    }
14896747b715Smrg}
14906747b715Smrg
149105b261ecSmrg/**
149205b261ecSmrg * Activate a pointer grab on the given device. A pointer grab will cause all
14934642e01fSmrg * core pointer events of this device to be delivered to the grabbing client only.
14944642e01fSmrg * No other device will send core events to the grab client while the grab is
14954642e01fSmrg * on, but core events will be sent to other clients.
14964642e01fSmrg * Can cause the cursor to change if a grab cursor is set.
14974642e01fSmrg *
14984642e01fSmrg * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab
14994642e01fSmrg * is an implicit grab caused by a ButtonPress event.
15004642e01fSmrg *
150105b261ecSmrg * @param mouse The device to grab.
150205b261ecSmrg * @param grab The grab structure, needs to be setup.
150305b261ecSmrg * @param autoGrab True if the grab was caused by a button down event and not
15044642e01fSmrg * explicitely by a client.
150505b261ecSmrg */
150605b261ecSmrgvoid
15074642e01fSmrgActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
150805b261ecSmrg                    TimeStamp time, Bool autoGrab)
150905b261ecSmrg{
15104642e01fSmrg    GrabInfoPtr grabinfo = &mouse->deviceGrab;
151135c4bbdfSmrg    GrabPtr oldgrab = grabinfo->grab;
15124642e01fSmrg    WindowPtr oldWin = (grabinfo->grab) ?
151335c4bbdfSmrg        grabinfo->grab->window : mouse->spriteInfo->sprite->win;
15144642e01fSmrg    Bool isPassive = autoGrab & ~ImplicitGrabMask;
151505b261ecSmrg
15166747b715Smrg    /* slave devices need to float for the duration of the grab. */
151735c4bbdfSmrg    if (grab->grabtype == XI2 &&
15186747b715Smrg        !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse))
15196747b715Smrg        DetachFromMaster(mouse);
15206747b715Smrg
152135c4bbdfSmrg    if (grab->confineTo) {
152235c4bbdfSmrg        if (grab->confineTo->drawable.pScreen
152335c4bbdfSmrg            != mouse->spriteInfo->sprite->hotPhys.pScreen)
152435c4bbdfSmrg            mouse->spriteInfo->sprite->hotPhys.x =
15254642e01fSmrg                mouse->spriteInfo->sprite->hotPhys.y = 0;
152635c4bbdfSmrg        ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE);
152705b261ecSmrg    }
15286747b715Smrg    DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab);
152905b261ecSmrg    mouse->valuator->motionHintWindow = NullWindow;
153005b261ecSmrg    if (syncEvents.playingEvents)
15314642e01fSmrg        grabinfo->grabTime = syncEvents.time;
153205b261ecSmrg    else
153335c4bbdfSmrg        grabinfo->grabTime = time;
153435c4bbdfSmrg    grabinfo->grab = AllocGrab(grab);
15354642e01fSmrg    grabinfo->fromPassiveGrab = isPassive;
15364642e01fSmrg    grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
15374642e01fSmrg    PostNewCursor(mouse);
153835c4bbdfSmrg    UpdateTouchesForGrab(mouse);
153935c4bbdfSmrg    CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
154035c4bbdfSmrg                      (Bool) grab->keyboardMode);
154135c4bbdfSmrg    if (oldgrab)
154235c4bbdfSmrg        FreeGrab(oldgrab);
154305b261ecSmrg}
154405b261ecSmrg
154505b261ecSmrg/**
154605b261ecSmrg * Delete grab on given device, update the sprite.
154705b261ecSmrg *
15484642e01fSmrg * Extension devices are set up for ActivateKeyboardGrab().
154905b261ecSmrg */
155005b261ecSmrgvoid
155105b261ecSmrgDeactivatePointerGrab(DeviceIntPtr mouse)
155205b261ecSmrg{
15534642e01fSmrg    GrabPtr grab = mouse->deviceGrab.grab;
155405b261ecSmrg    DeviceIntPtr dev;
155535c4bbdfSmrg    Bool wasPassive = mouse->deviceGrab.fromPassiveGrab;
15566747b715Smrg    Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
15576747b715Smrg                        mouse->deviceGrab.implicitGrab);
155835c4bbdfSmrg    XID grab_resource = grab->resource;
155935c4bbdfSmrg    int i;
156035c4bbdfSmrg
156135c4bbdfSmrg    /* If an explicit grab was deactivated, we must remove it from the head of
156235c4bbdfSmrg     * all the touches' listener lists. */
156335c4bbdfSmrg    for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
156435c4bbdfSmrg        TouchPointInfoPtr ti = mouse->touch->touches + i;
156535c4bbdfSmrg        if (ti->active && TouchResourceIsOwner(ti, grab_resource)) {
156635c4bbdfSmrg            int mode = XIRejectTouch;
156735c4bbdfSmrg            /* Rejecting will generate a TouchEnd, but we must not
156835c4bbdfSmrg               emulate a ButtonRelease here. So pretend the listener
156935c4bbdfSmrg               already has the end event */
157035c4bbdfSmrg            if (grab->grabtype == CORE || grab->grabtype == XI ||
157135c4bbdfSmrg                    !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin)) {
157235c4bbdfSmrg                mode = XIAcceptTouch;
157335c4bbdfSmrg                /* NOTE: we set the state here, but
157435c4bbdfSmrg                 * ProcessTouchOwnershipEvent() will still call
157535c4bbdfSmrg                 * TouchEmitTouchEnd for this listener. The other half of
157635c4bbdfSmrg                 * this hack is in DeliverTouchEndEvent */
157735c4bbdfSmrg                ti->listeners[0].state = LISTENER_HAS_END;
157835c4bbdfSmrg            }
157935c4bbdfSmrg            TouchListenerAcceptReject(mouse, ti, 0, mode);
158035c4bbdfSmrg        }
158135c4bbdfSmrg    }
158235c4bbdfSmrg
158335c4bbdfSmrg    TouchRemovePointerGrab(mouse);
158405b261ecSmrg
158505b261ecSmrg    mouse->valuator->motionHintWindow = NullWindow;
15864642e01fSmrg    mouse->deviceGrab.grab = NullGrab;
15874642e01fSmrg    mouse->deviceGrab.sync.state = NOT_GRABBED;
15884642e01fSmrg    mouse->deviceGrab.fromPassiveGrab = FALSE;
15894642e01fSmrg
159035c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
159135c4bbdfSmrg        if (dev->deviceGrab.sync.other == grab)
159235c4bbdfSmrg            dev->deviceGrab.sync.other = NullGrab;
159305b261ecSmrg    }
15946747b715Smrg    DoEnterLeaveEvents(mouse, mouse->id, grab->window,
15954642e01fSmrg                       mouse->spriteInfo->sprite->win, NotifyUngrab);
159605b261ecSmrg    if (grab->confineTo)
159735c4bbdfSmrg        ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE);
15984642e01fSmrg    PostNewCursor(mouse);
15994642e01fSmrg
160035c4bbdfSmrg    if (!wasImplicit && grab->grabtype == XI2)
16016747b715Smrg        ReattachToOldMaster(mouse);
16026747b715Smrg
160305b261ecSmrg    ComputeFreezes();
160435c4bbdfSmrg
160535c4bbdfSmrg    FreeGrab(grab);
160605b261ecSmrg}
160705b261ecSmrg
160805b261ecSmrg/**
16094642e01fSmrg * Activate a keyboard grab on the given device.
161005b261ecSmrg *
161105b261ecSmrg * Extension devices have ActivateKeyboardGrab() set as their grabbing proc.
161205b261ecSmrg */
161305b261ecSmrgvoid
161435c4bbdfSmrgActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
161535c4bbdfSmrg                     Bool passive)
161605b261ecSmrg{
16174642e01fSmrg    GrabInfoPtr grabinfo = &keybd->deviceGrab;
161835c4bbdfSmrg    GrabPtr oldgrab = grabinfo->grab;
161905b261ecSmrg    WindowPtr oldWin;
162005b261ecSmrg
16216747b715Smrg    /* slave devices need to float for the duration of the grab. */
162235c4bbdfSmrg    if (grab->grabtype == XI2 && keybd->enabled &&
162335c4bbdfSmrg        !(passive & ImplicitGrabMask) && !IsMaster(keybd))
16246747b715Smrg        DetachFromMaster(keybd);
16256747b715Smrg
162635c4bbdfSmrg    if (!keybd->enabled)
162735c4bbdfSmrg        oldWin = NULL;
162835c4bbdfSmrg    else if (grabinfo->grab)
162935c4bbdfSmrg        oldWin = grabinfo->grab->window;
163005b261ecSmrg    else if (keybd->focus)
163135c4bbdfSmrg        oldWin = keybd->focus->win;
163205b261ecSmrg    else
163335c4bbdfSmrg        oldWin = keybd->spriteInfo->sprite->win;
163405b261ecSmrg    if (oldWin == FollowKeyboardWin)
163535c4bbdfSmrg        oldWin = keybd->focus->win;
163605b261ecSmrg    if (keybd->valuator)
163735c4bbdfSmrg        keybd->valuator->motionHintWindow = NullWindow;
163835c4bbdfSmrg    if (oldWin)
163935c4bbdfSmrg        DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);
164005b261ecSmrg    if (syncEvents.playingEvents)
164135c4bbdfSmrg        grabinfo->grabTime = syncEvents.time;
164205b261ecSmrg    else
164335c4bbdfSmrg        grabinfo->grabTime = time;
164435c4bbdfSmrg    grabinfo->grab = AllocGrab(grab);
16454642e01fSmrg    grabinfo->fromPassiveGrab = passive;
16466747b715Smrg    grabinfo->implicitGrab = passive & ImplicitGrabMask;
164735c4bbdfSmrg    CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
164835c4bbdfSmrg                      (Bool) grab->pointerMode);
164935c4bbdfSmrg    if (oldgrab)
165035c4bbdfSmrg        FreeGrab(oldgrab);
165105b261ecSmrg}
165205b261ecSmrg
165305b261ecSmrg/**
16544642e01fSmrg * Delete keyboard grab for the given device.
165505b261ecSmrg */
165605b261ecSmrgvoid
165705b261ecSmrgDeactivateKeyboardGrab(DeviceIntPtr keybd)
165805b261ecSmrg{
16594642e01fSmrg    GrabPtr grab = keybd->deviceGrab.grab;
166005b261ecSmrg    DeviceIntPtr dev;
166135c4bbdfSmrg    WindowPtr focusWin;
16626747b715Smrg    Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab &&
16636747b715Smrg                        keybd->deviceGrab.implicitGrab);
166405b261ecSmrg
166505b261ecSmrg    if (keybd->valuator)
166635c4bbdfSmrg        keybd->valuator->motionHintWindow = NullWindow;
16674642e01fSmrg    keybd->deviceGrab.grab = NullGrab;
16684642e01fSmrg    keybd->deviceGrab.sync.state = NOT_GRABBED;
16694642e01fSmrg    keybd->deviceGrab.fromPassiveGrab = FALSE;
16704642e01fSmrg
167135c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
167235c4bbdfSmrg        if (dev->deviceGrab.sync.other == grab)
167335c4bbdfSmrg            dev->deviceGrab.sync.other = NullGrab;
167405b261ecSmrg    }
167535c4bbdfSmrg
167635c4bbdfSmrg    if (keybd->focus)
167735c4bbdfSmrg        focusWin = keybd->focus->win;
167835c4bbdfSmrg    else if (keybd->spriteInfo->sprite)
167935c4bbdfSmrg        focusWin = keybd->spriteInfo->sprite->win;
168035c4bbdfSmrg    else
168135c4bbdfSmrg        focusWin = NullWindow;
168235c4bbdfSmrg
168335c4bbdfSmrg    if (focusWin == FollowKeyboardWin)
168435c4bbdfSmrg        focusWin = inputInfo.keyboard->focus->win;
168535c4bbdfSmrg
168605b261ecSmrg    DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
16874642e01fSmrg
168835c4bbdfSmrg    if (!wasImplicit && grab->grabtype == XI2)
16896747b715Smrg        ReattachToOldMaster(keybd);
16906747b715Smrg
169105b261ecSmrg    ComputeFreezes();
169235c4bbdfSmrg
169335c4bbdfSmrg    FreeGrab(grab);
169405b261ecSmrg}
169505b261ecSmrg
169605b261ecSmrgvoid
169735c4bbdfSmrgAllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState)
169805b261ecSmrg{
169905b261ecSmrg    Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced;
170005b261ecSmrg    TimeStamp grabTime;
170105b261ecSmrg    DeviceIntPtr dev;
170235c4bbdfSmrg    GrabInfoPtr devgrabinfo, grabinfo = &thisDev->deviceGrab;
170305b261ecSmrg
17044642e01fSmrg    thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client);
170505b261ecSmrg    thisSynced = FALSE;
170605b261ecSmrg    otherGrabbed = FALSE;
17076747b715Smrg    othersFrozen = FALSE;
17084642e01fSmrg    grabTime = grabinfo->grabTime;
170935c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
17104642e01fSmrg        devgrabinfo = &dev->deviceGrab;
17114642e01fSmrg
171235c4bbdfSmrg        if (dev == thisDev)
171335c4bbdfSmrg            continue;
171435c4bbdfSmrg        if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) {
171535c4bbdfSmrg            if (!(thisGrabbed || otherGrabbed) ||
171635c4bbdfSmrg                (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER))
171735c4bbdfSmrg                grabTime = devgrabinfo->grabTime;
171835c4bbdfSmrg            otherGrabbed = TRUE;
171935c4bbdfSmrg            if (grabinfo->sync.other == devgrabinfo->grab)
172035c4bbdfSmrg                thisSynced = TRUE;
172135c4bbdfSmrg            if (devgrabinfo->sync.state >= FROZEN)
172235c4bbdfSmrg                othersFrozen = TRUE;
172335c4bbdfSmrg        }
172405b261ecSmrg    }
17254642e01fSmrg    if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced))
172635c4bbdfSmrg        return;
172705b261ecSmrg    if ((CompareTimeStamps(time, currentTime) == LATER) ||
172835c4bbdfSmrg        (CompareTimeStamps(time, grabTime) == EARLIER))
172935c4bbdfSmrg        return;
173035c4bbdfSmrg    switch (newState) {
173135c4bbdfSmrg    case THAWED:               /* Async */
173235c4bbdfSmrg        if (thisGrabbed)
173335c4bbdfSmrg            grabinfo->sync.state = THAWED;
173435c4bbdfSmrg        if (thisSynced)
173535c4bbdfSmrg            grabinfo->sync.other = NullGrab;
173635c4bbdfSmrg        ComputeFreezes();
173735c4bbdfSmrg        break;
173835c4bbdfSmrg    case FREEZE_NEXT_EVENT:    /* Sync */
173935c4bbdfSmrg        if (thisGrabbed) {
174035c4bbdfSmrg            grabinfo->sync.state = FREEZE_NEXT_EVENT;
174135c4bbdfSmrg            if (thisSynced)
174235c4bbdfSmrg                grabinfo->sync.other = NullGrab;
174335c4bbdfSmrg            ComputeFreezes();
174435c4bbdfSmrg        }
174535c4bbdfSmrg        break;
174635c4bbdfSmrg    case THAWED_BOTH:          /* AsyncBoth */
174735c4bbdfSmrg        if (othersFrozen) {
174835c4bbdfSmrg            for (dev = inputInfo.devices; dev; dev = dev->next) {
174935c4bbdfSmrg                devgrabinfo = &dev->deviceGrab;
175035c4bbdfSmrg                if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
175135c4bbdfSmrg                    devgrabinfo->sync.state = THAWED;
175235c4bbdfSmrg                if (devgrabinfo->sync.other &&
175335c4bbdfSmrg                    SameClient(devgrabinfo->sync.other, client))
175435c4bbdfSmrg                    devgrabinfo->sync.other = NullGrab;
175535c4bbdfSmrg            }
175635c4bbdfSmrg            ComputeFreezes();
175735c4bbdfSmrg        }
175835c4bbdfSmrg        break;
175935c4bbdfSmrg    case FREEZE_BOTH_NEXT_EVENT:       /* SyncBoth */
176035c4bbdfSmrg        if (othersFrozen) {
176135c4bbdfSmrg            for (dev = inputInfo.devices; dev; dev = dev->next) {
176235c4bbdfSmrg                devgrabinfo = &dev->deviceGrab;
176335c4bbdfSmrg                if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
176435c4bbdfSmrg                    devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT;
176535c4bbdfSmrg                if (devgrabinfo->sync.other
176635c4bbdfSmrg                    && SameClient(devgrabinfo->sync.other, client))
176735c4bbdfSmrg                    devgrabinfo->sync.other = NullGrab;
176835c4bbdfSmrg            }
176935c4bbdfSmrg            ComputeFreezes();
177035c4bbdfSmrg        }
177135c4bbdfSmrg        break;
177235c4bbdfSmrg    case NOT_GRABBED:          /* Replay */
177335c4bbdfSmrg        if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) {
177435c4bbdfSmrg            if (thisSynced)
177535c4bbdfSmrg                grabinfo->sync.other = NullGrab;
177635c4bbdfSmrg            syncEvents.replayDev = thisDev;
177735c4bbdfSmrg            syncEvents.replayWin = grabinfo->grab->window;
177835c4bbdfSmrg            (*grabinfo->DeactivateGrab) (thisDev);
177935c4bbdfSmrg            syncEvents.replayDev = (DeviceIntPtr) NULL;
178035c4bbdfSmrg        }
178135c4bbdfSmrg        break;
178235c4bbdfSmrg    case THAW_OTHERS:          /* AsyncOthers */
178335c4bbdfSmrg        if (othersFrozen) {
178435c4bbdfSmrg            for (dev = inputInfo.devices; dev; dev = dev->next) {
178535c4bbdfSmrg                if (dev == thisDev)
178635c4bbdfSmrg                    continue;
178735c4bbdfSmrg                devgrabinfo = &dev->deviceGrab;
178835c4bbdfSmrg                if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
178935c4bbdfSmrg                    devgrabinfo->sync.state = THAWED;
179035c4bbdfSmrg                if (devgrabinfo->sync.other
179135c4bbdfSmrg                    && SameClient(devgrabinfo->sync.other, client))
179235c4bbdfSmrg                    devgrabinfo->sync.other = NullGrab;
179335c4bbdfSmrg            }
179435c4bbdfSmrg            ComputeFreezes();
179535c4bbdfSmrg        }
179635c4bbdfSmrg        break;
179735c4bbdfSmrg    }
179835c4bbdfSmrg
179935c4bbdfSmrg    /* We've unfrozen the grab. If the grab was a touch grab, we're now the
180035c4bbdfSmrg     * owner and expected to accept/reject it. Reject == ReplayPointer which
180135c4bbdfSmrg     * we've handled in ComputeFreezes() (during DeactivateGrab) above,
180235c4bbdfSmrg     * anything else is accept.
180335c4bbdfSmrg     */
180435c4bbdfSmrg    if (newState != NOT_GRABBED /* Replay */ &&
180535c4bbdfSmrg        IsTouchEvent((InternalEvent*)grabinfo->sync.event)) {
180635c4bbdfSmrg        TouchAcceptAndEnd(thisDev, grabinfo->sync.event->touchid);
180705b261ecSmrg    }
180805b261ecSmrg}
180905b261ecSmrg
181005b261ecSmrg/**
181105b261ecSmrg * Server-side protocol handling for AllowEvents request.
181205b261ecSmrg *
18134642e01fSmrg * Release some events from a frozen device.
181405b261ecSmrg */
181505b261ecSmrgint
181605b261ecSmrgProcAllowEvents(ClientPtr client)
181705b261ecSmrg{
181835c4bbdfSmrg    TimeStamp time;
181935c4bbdfSmrg    DeviceIntPtr mouse = NULL;
182035c4bbdfSmrg    DeviceIntPtr keybd = NULL;
182135c4bbdfSmrg
182205b261ecSmrg    REQUEST(xAllowEventsReq);
182305b261ecSmrg
182405b261ecSmrg    REQUEST_SIZE_MATCH(xAllowEventsReq);
182505b261ecSmrg    time = ClientTimeToServerTime(stuff->time);
18264642e01fSmrg
18274642e01fSmrg    mouse = PickPointer(client);
18284642e01fSmrg    keybd = PickKeyboard(client);
18294642e01fSmrg
183035c4bbdfSmrg    switch (stuff->mode) {
183135c4bbdfSmrg    case ReplayPointer:
183235c4bbdfSmrg        AllowSome(client, time, mouse, NOT_GRABBED);
183335c4bbdfSmrg        break;
183435c4bbdfSmrg    case SyncPointer:
183535c4bbdfSmrg        AllowSome(client, time, mouse, FREEZE_NEXT_EVENT);
183635c4bbdfSmrg        break;
183735c4bbdfSmrg    case AsyncPointer:
183835c4bbdfSmrg        AllowSome(client, time, mouse, THAWED);
183935c4bbdfSmrg        break;
184035c4bbdfSmrg    case ReplayKeyboard:
184135c4bbdfSmrg        AllowSome(client, time, keybd, NOT_GRABBED);
184235c4bbdfSmrg        break;
184335c4bbdfSmrg    case SyncKeyboard:
184435c4bbdfSmrg        AllowSome(client, time, keybd, FREEZE_NEXT_EVENT);
184535c4bbdfSmrg        break;
184635c4bbdfSmrg    case AsyncKeyboard:
184735c4bbdfSmrg        AllowSome(client, time, keybd, THAWED);
184835c4bbdfSmrg        break;
184935c4bbdfSmrg    case SyncBoth:
185035c4bbdfSmrg        AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT);
185135c4bbdfSmrg        break;
185235c4bbdfSmrg    case AsyncBoth:
185335c4bbdfSmrg        AllowSome(client, time, keybd, THAWED_BOTH);
185435c4bbdfSmrg        break;
185535c4bbdfSmrg    default:
185635c4bbdfSmrg        client->errorValue = stuff->mode;
185735c4bbdfSmrg        return BadValue;
185805b261ecSmrg    }
185905b261ecSmrg    return Success;
186005b261ecSmrg}
186105b261ecSmrg
186205b261ecSmrg/**
186305b261ecSmrg * Deactivate grabs from any device that has been grabbed by the client.
186405b261ecSmrg */
186505b261ecSmrgvoid
186605b261ecSmrgReleaseActiveGrabs(ClientPtr client)
186705b261ecSmrg{
186805b261ecSmrg    DeviceIntPtr dev;
186935c4bbdfSmrg    Bool done;
187005b261ecSmrg
187105b261ecSmrg    /* XXX CloseDownClient should remove passive grabs before
187205b261ecSmrg     * releasing active grabs.
187305b261ecSmrg     */
187405b261ecSmrg    do {
187535c4bbdfSmrg        done = TRUE;
187635c4bbdfSmrg        for (dev = inputInfo.devices; dev; dev = dev->next) {
187735c4bbdfSmrg            if (dev->deviceGrab.grab &&
187835c4bbdfSmrg                SameClient(dev->deviceGrab.grab, client)) {
187935c4bbdfSmrg                (*dev->deviceGrab.DeactivateGrab) (dev);
188035c4bbdfSmrg                done = FALSE;
188135c4bbdfSmrg            }
188235c4bbdfSmrg        }
188305b261ecSmrg    } while (!done);
188405b261ecSmrg}
188505b261ecSmrg
188605b261ecSmrg/**************************************************************************
188705b261ecSmrg *            The following procedures deal with delivering events        *
188805b261ecSmrg **************************************************************************/
188905b261ecSmrg
189005b261ecSmrg/**
189105b261ecSmrg * Deliver the given events to the given client.
189205b261ecSmrg *
189305b261ecSmrg * More than one event may be delivered at a time. This is the case with
189405b261ecSmrg * DeviceMotionNotifies which may be followed by DeviceValuator events.
189505b261ecSmrg *
189605b261ecSmrg * TryClientEvents() is the last station before actually writing the events to
189705b261ecSmrg * the socket. Anything that is not filtered here, will get delivered to the
18984642e01fSmrg * client.
18994642e01fSmrg * An event is only delivered if
190005b261ecSmrg *   - mask and filter match up.
190105b261ecSmrg *   - no other client has a grab on the device that caused the event.
19024642e01fSmrg *
190305b261ecSmrg *
190405b261ecSmrg * @param client The target client to deliver to.
19054642e01fSmrg * @param dev The device the event came from. May be NULL.
190605b261ecSmrg * @param pEvents The events to be delivered.
190705b261ecSmrg * @param count Number of elements in pEvents.
190805b261ecSmrg * @param mask Event mask as set by the window.
190905b261ecSmrg * @param filter Mask based on event type.
19104642e01fSmrg * @param grab Possible grab on the device that caused the event.
191105b261ecSmrg *
191205b261ecSmrg * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the
191305b261ecSmrg * client.
191405b261ecSmrg */
19156747b715Smrgint
191635c4bbdfSmrgTryClientEvents(ClientPtr client, DeviceIntPtr dev, xEvent *pEvents,
191735c4bbdfSmrg                int count, Mask mask, Mask filter, GrabPtr grab)
191805b261ecSmrg{
191905b261ecSmrg    int type;
192005b261ecSmrg
192105b261ecSmrg#ifdef DEBUG_EVENTS
19226747b715Smrg    ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s",
19236747b715Smrg           pEvents->u.u.type, pEvents->u.u.detail, mask,
19246747b715Smrg           client ? client->index : -1,
19256747b715Smrg           (client && client->clientGone) ? " (gone)" : "");
192605b261ecSmrg#endif
19276747b715Smrg
19286747b715Smrg    if (!client || client == serverClient || client->clientGone) {
192905b261ecSmrg#ifdef DEBUG_EVENTS
19306747b715Smrg        ErrorF(" not delivered to fake/dead client\n");
193105b261ecSmrg#endif
19326747b715Smrg        return 0;
19336747b715Smrg    }
193405b261ecSmrg
193535c4bbdfSmrg    if (filter != CantBeFiltered && !(mask & filter)) {
193635c4bbdfSmrg#ifdef DEBUG_EVENTS
19376747b715Smrg        ErrorF(" filtered\n");
193835c4bbdfSmrg#endif
19396747b715Smrg        return 0;
19406747b715Smrg    }
194105b261ecSmrg
194235c4bbdfSmrg    if (grab && !SameClient(grab, client)) {
194305b261ecSmrg#ifdef DEBUG_EVENTS
19446747b715Smrg        ErrorF(" not delivered due to grab\n");
194505b261ecSmrg#endif
194635c4bbdfSmrg        return -1;              /* don't send, but notify caller */
194705b261ecSmrg    }
19486747b715Smrg
19496747b715Smrg    type = pEvents->u.u.type;
195035c4bbdfSmrg    if (type == MotionNotify) {
195135c4bbdfSmrg        if (mask & PointerMotionHintMask) {
19526747b715Smrg            if (WID(dev->valuator->motionHintWindow) ==
195335c4bbdfSmrg                pEvents->u.keyButtonPointer.event) {
195405b261ecSmrg#ifdef DEBUG_EVENTS
19556747b715Smrg                ErrorF("[dix] \n");
19566747b715Smrg                ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n");
195705b261ecSmrg#endif
195835c4bbdfSmrg                return 1;       /* don't send, but pretend we did */
19596747b715Smrg            }
19606747b715Smrg            pEvents->u.u.detail = NotifyHint;
19616747b715Smrg        }
196235c4bbdfSmrg        else {
19636747b715Smrg            pEvents->u.u.detail = NotifyNormal;
19646747b715Smrg        }
19656747b715Smrg    }
196635c4bbdfSmrg    else if (type == DeviceMotionNotify) {
196735c4bbdfSmrg        if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer *) pEvents,
19686747b715Smrg                                            mask) != 0)
19696747b715Smrg            return 1;
197035c4bbdfSmrg    }
197135c4bbdfSmrg    else if (type == KeyPress) {
197235c4bbdfSmrg        if (EventIsKeyRepeat(pEvents)) {
197335c4bbdfSmrg            if (!_XkbWantsDetectableAutoRepeat(client)) {
19746747b715Smrg                xEvent release = *pEvents;
197535c4bbdfSmrg
19766747b715Smrg                release.u.u.type = KeyRelease;
19776747b715Smrg                WriteEventsToClient(client, 1, &release);
19786747b715Smrg#ifdef DEBUG_EVENTS
19796747b715Smrg                ErrorF(" (plus fake core release for repeat)");
19806747b715Smrg#endif
198135c4bbdfSmrg            }
198235c4bbdfSmrg            else {
19836747b715Smrg#ifdef DEBUG_EVENTS
19846747b715Smrg                ErrorF(" (detectable autorepeat for core)");
19856747b715Smrg#endif
19866747b715Smrg            }
19876747b715Smrg        }
19886747b715Smrg
198935c4bbdfSmrg    }
199035c4bbdfSmrg    else if (type == DeviceKeyPress) {
199135c4bbdfSmrg        if (EventIsKeyRepeat(pEvents)) {
199235c4bbdfSmrg            if (!_XkbWantsDetectableAutoRepeat(client)) {
199335c4bbdfSmrg                deviceKeyButtonPointer release =
199435c4bbdfSmrg                    *(deviceKeyButtonPointer *) pEvents;
19956747b715Smrg                release.type = DeviceKeyRelease;
19966747b715Smrg#ifdef DEBUG_EVENTS
19976747b715Smrg                ErrorF(" (plus fake xi1 release for repeat)");
19986747b715Smrg#endif
19996747b715Smrg                WriteEventsToClient(client, 1, (xEvent *) &release);
20006747b715Smrg            }
20016747b715Smrg            else {
20026747b715Smrg#ifdef DEBUG_EVENTS
20036747b715Smrg                ErrorF(" (detectable autorepeat for core)");
20046747b715Smrg#endif
20056747b715Smrg            }
20066747b715Smrg        }
20076747b715Smrg    }
20086747b715Smrg
200935c4bbdfSmrg    if (BitIsOn(criticalEvents, type)) {
20106747b715Smrg        if (client->smart_priority < SMART_MAX_PRIORITY)
20116747b715Smrg            client->smart_priority++;
20126747b715Smrg        SetCriticalOutputPending();
201305b261ecSmrg    }
20146747b715Smrg
20156747b715Smrg    WriteEventsToClient(client, count, pEvents);
20166747b715Smrg#ifdef DEBUG_EVENTS
20176747b715Smrg    ErrorF("[dix]  delivered\n");
20186747b715Smrg#endif
20196747b715Smrg    return 1;
202005b261ecSmrg}
202105b261ecSmrg
202235c4bbdfSmrgstatic BOOL
202335c4bbdfSmrgActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win,
202435c4bbdfSmrg                     xEvent *event, Mask deliveryMask)
202535c4bbdfSmrg{
202635c4bbdfSmrg    GrabPtr tempGrab;
202735c4bbdfSmrg    OtherInputMasks *inputMasks;
202835c4bbdfSmrg    CARD8 type = event->u.u.type;
202935c4bbdfSmrg    enum InputLevel grabtype;
203035c4bbdfSmrg
203135c4bbdfSmrg    if (type == ButtonPress)
203235c4bbdfSmrg        grabtype = CORE;
203335c4bbdfSmrg    else if (type == DeviceButtonPress)
203435c4bbdfSmrg        grabtype = XI;
203535c4bbdfSmrg    else if ((type = xi2_get_type(event)) == XI_ButtonPress)
203635c4bbdfSmrg        grabtype = XI2;
203735c4bbdfSmrg    else
203835c4bbdfSmrg        return FALSE;
203935c4bbdfSmrg
204035c4bbdfSmrg    tempGrab = AllocGrab(NULL);
204135c4bbdfSmrg    if (!tempGrab)
204235c4bbdfSmrg        return FALSE;
204335c4bbdfSmrg    tempGrab->next = NULL;
204435c4bbdfSmrg    tempGrab->device = dev;
204535c4bbdfSmrg    tempGrab->resource = client->clientAsMask;
204635c4bbdfSmrg    tempGrab->window = win;
204735c4bbdfSmrg    tempGrab->ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE;
204835c4bbdfSmrg    tempGrab->eventMask = deliveryMask;
204935c4bbdfSmrg    tempGrab->keyboardMode = GrabModeAsync;
205035c4bbdfSmrg    tempGrab->pointerMode = GrabModeAsync;
205135c4bbdfSmrg    tempGrab->confineTo = NullWindow;
205235c4bbdfSmrg    tempGrab->cursor = NullCursor;
205335c4bbdfSmrg    tempGrab->type = type;
205435c4bbdfSmrg    tempGrab->grabtype = grabtype;
205535c4bbdfSmrg
205635c4bbdfSmrg    /* get the XI and XI2 device mask */
205735c4bbdfSmrg    inputMasks = wOtherInputMasks(win);
205835c4bbdfSmrg    tempGrab->deviceMask = (inputMasks) ? inputMasks->inputEvents[dev->id] : 0;
205935c4bbdfSmrg
206035c4bbdfSmrg    if (inputMasks)
206135c4bbdfSmrg        xi2mask_merge(tempGrab->xi2mask, inputMasks->xi2mask);
206235c4bbdfSmrg
206335c4bbdfSmrg    (*dev->deviceGrab.ActivateGrab) (dev, tempGrab,
206435c4bbdfSmrg                                     currentTime, TRUE | ImplicitGrabMask);
206535c4bbdfSmrg    FreeGrab(tempGrab);
206635c4bbdfSmrg    return TRUE;
206735c4bbdfSmrg}
206835c4bbdfSmrg
206935c4bbdfSmrg/**
207035c4bbdfSmrg * Attempt event delivery to the client owning the window.
207135c4bbdfSmrg */
207235c4bbdfSmrgstatic enum EventDeliveryState
207335c4bbdfSmrgDeliverToWindowOwner(DeviceIntPtr dev, WindowPtr win,
207435c4bbdfSmrg                     xEvent *events, int count, Mask filter, GrabPtr grab)
207535c4bbdfSmrg{
207635c4bbdfSmrg    /* if nobody ever wants to see this event, skip some work */
207735c4bbdfSmrg    if (filter != CantBeFiltered &&
207835c4bbdfSmrg        !((wOtherEventMasks(win) | win->eventMask) & filter))
207935c4bbdfSmrg        return EVENT_SKIP;
208035c4bbdfSmrg
208135c4bbdfSmrg    if (IsInterferingGrab(wClient(win), dev, events))
208235c4bbdfSmrg        return EVENT_SKIP;
208335c4bbdfSmrg
208435c4bbdfSmrg    if (!XaceHook(XACE_RECEIVE_ACCESS, wClient(win), win, events, count)) {
208535c4bbdfSmrg        int attempt = TryClientEvents(wClient(win), dev, events,
208635c4bbdfSmrg                                      count, win->eventMask,
208735c4bbdfSmrg                                      filter, grab);
208835c4bbdfSmrg
208935c4bbdfSmrg        if (attempt > 0)
209035c4bbdfSmrg            return EVENT_DELIVERED;
209135c4bbdfSmrg        if (attempt < 0)
209235c4bbdfSmrg            return EVENT_REJECTED;
209335c4bbdfSmrg    }
209435c4bbdfSmrg
209535c4bbdfSmrg    return EVENT_NOT_DELIVERED;
209635c4bbdfSmrg}
209735c4bbdfSmrg
209835c4bbdfSmrg/**
209935c4bbdfSmrg * Get the list of clients that should be tried for event delivery on the
210035c4bbdfSmrg * given window.
210135c4bbdfSmrg *
210235c4bbdfSmrg * @return 1 if the client list should be traversed, zero if the event
210335c4bbdfSmrg * should be skipped.
210435c4bbdfSmrg */
210535c4bbdfSmrgstatic Bool
210635c4bbdfSmrgGetClientsForDelivery(DeviceIntPtr dev, WindowPtr win,
210735c4bbdfSmrg                      xEvent *events, Mask filter, InputClients ** iclients)
210835c4bbdfSmrg{
210935c4bbdfSmrg    int rc = 0;
211035c4bbdfSmrg
211135c4bbdfSmrg    if (core_get_type(events) != 0)
211235c4bbdfSmrg        *iclients = (InputClients *) wOtherClients(win);
211335c4bbdfSmrg    else if (xi2_get_type(events) != 0) {
211435c4bbdfSmrg        OtherInputMasks *inputMasks = wOtherInputMasks(win);
211535c4bbdfSmrg
211635c4bbdfSmrg        /* Has any client selected for the event? */
211735c4bbdfSmrg        if (!WindowXI2MaskIsset(dev, win, events))
211835c4bbdfSmrg            goto out;
211935c4bbdfSmrg        *iclients = inputMasks->inputClients;
212035c4bbdfSmrg    }
212135c4bbdfSmrg    else {
212235c4bbdfSmrg        OtherInputMasks *inputMasks = wOtherInputMasks(win);
212335c4bbdfSmrg
212435c4bbdfSmrg        /* Has any client selected for the event? */
212535c4bbdfSmrg        if (!inputMasks || !(inputMasks->inputEvents[dev->id] & filter))
212635c4bbdfSmrg            goto out;
212735c4bbdfSmrg
212835c4bbdfSmrg        *iclients = inputMasks->inputClients;
212935c4bbdfSmrg    }
213035c4bbdfSmrg
213135c4bbdfSmrg    rc = 1;
213235c4bbdfSmrg out:
213335c4bbdfSmrg    return rc;
213435c4bbdfSmrg}
213535c4bbdfSmrg
213635c4bbdfSmrg/**
213735c4bbdfSmrg * Try delivery on each client in inputclients, provided the event mask
213835c4bbdfSmrg * accepts it and there is no interfering core grab..
213935c4bbdfSmrg */
214035c4bbdfSmrgstatic enum EventDeliveryState
214135c4bbdfSmrgDeliverEventToInputClients(DeviceIntPtr dev, InputClients * inputclients,
214235c4bbdfSmrg                           WindowPtr win, xEvent *events,
214335c4bbdfSmrg                           int count, Mask filter, GrabPtr grab,
214435c4bbdfSmrg                           ClientPtr *client_return, Mask *mask_return)
214535c4bbdfSmrg{
214635c4bbdfSmrg    int attempt;
214735c4bbdfSmrg    enum EventDeliveryState rc = EVENT_NOT_DELIVERED;
214835c4bbdfSmrg    Bool have_device_button_grab_class_client = FALSE;
214935c4bbdfSmrg
215035c4bbdfSmrg    for (; inputclients; inputclients = inputclients->next) {
215135c4bbdfSmrg        Mask mask;
215235c4bbdfSmrg        ClientPtr client = rClient(inputclients);
215335c4bbdfSmrg
215435c4bbdfSmrg        if (IsInterferingGrab(client, dev, events))
215535c4bbdfSmrg            continue;
215635c4bbdfSmrg
215735c4bbdfSmrg        if (IsWrongPointerBarrierClient(client, dev, events))
215835c4bbdfSmrg            continue;
215935c4bbdfSmrg
216035c4bbdfSmrg        mask = GetEventMask(dev, events, inputclients);
216135c4bbdfSmrg
216235c4bbdfSmrg        if (XaceHook(XACE_RECEIVE_ACCESS, client, win, events, count))
216335c4bbdfSmrg            /* do nothing */ ;
216435c4bbdfSmrg        else if ((attempt = TryClientEvents(client, dev,
216535c4bbdfSmrg                                            events, count,
216635c4bbdfSmrg                                            mask, filter, grab))) {
216735c4bbdfSmrg            if (attempt > 0) {
216835c4bbdfSmrg                /*
216935c4bbdfSmrg                 * The order of clients is arbitrary therefore if one
217035c4bbdfSmrg                 * client belongs to DeviceButtonGrabClass make sure to
217135c4bbdfSmrg                 * catch it.
217235c4bbdfSmrg                 */
217335c4bbdfSmrg                if (!have_device_button_grab_class_client) {
217435c4bbdfSmrg                    rc = EVENT_DELIVERED;
217535c4bbdfSmrg                    *client_return = client;
217635c4bbdfSmrg                    *mask_return = mask;
217735c4bbdfSmrg                    /* Success overrides non-success, so if we've been
217835c4bbdfSmrg                     * successful on one client, return that */
217935c4bbdfSmrg                    if (mask & DeviceButtonGrabMask)
218035c4bbdfSmrg                        have_device_button_grab_class_client = TRUE;
218135c4bbdfSmrg                }
218235c4bbdfSmrg            } else if (rc == EVENT_NOT_DELIVERED)
218335c4bbdfSmrg                rc = EVENT_REJECTED;
218435c4bbdfSmrg        }
218535c4bbdfSmrg    }
218635c4bbdfSmrg
218735c4bbdfSmrg    return rc;
218835c4bbdfSmrg}
218935c4bbdfSmrg
219035c4bbdfSmrg/**
219135c4bbdfSmrg * Deliver events to clients registered on the window.
219235c4bbdfSmrg *
219335c4bbdfSmrg * @param client_return On successful delivery, set to the recipient.
219435c4bbdfSmrg * @param mask_return On successful delivery, set to the recipient's event
219535c4bbdfSmrg * mask for this event.
219635c4bbdfSmrg */
219735c4bbdfSmrgstatic enum EventDeliveryState
219835c4bbdfSmrgDeliverEventToWindowMask(DeviceIntPtr dev, WindowPtr win, xEvent *events,
219935c4bbdfSmrg                         int count, Mask filter, GrabPtr grab,
220035c4bbdfSmrg                         ClientPtr *client_return, Mask *mask_return)
220135c4bbdfSmrg{
220235c4bbdfSmrg    InputClients *iclients;
220335c4bbdfSmrg
220435c4bbdfSmrg    if (!GetClientsForDelivery(dev, win, events, filter, &iclients))
220535c4bbdfSmrg        return EVENT_SKIP;
220635c4bbdfSmrg
220735c4bbdfSmrg    return DeliverEventToInputClients(dev, iclients, win, events, count, filter,
220835c4bbdfSmrg                                      grab, client_return, mask_return);
220935c4bbdfSmrg
221035c4bbdfSmrg}
221135c4bbdfSmrg
221205b261ecSmrg/**
221305b261ecSmrg * Deliver events to a window. At this point, we do not yet know if the event
221405b261ecSmrg * actually needs to be delivered. May activate a grab if the event is a
221505b261ecSmrg * button press.
221605b261ecSmrg *
22174642e01fSmrg * Core events are always delivered to the window owner. If the filter is
22184642e01fSmrg * something other than CantBeFiltered, the event is also delivered to other
22194642e01fSmrg * clients with the matching mask on the window.
22204642e01fSmrg *
222105b261ecSmrg * More than one event may be delivered at a time. This is the case with
222205b261ecSmrg * DeviceMotionNotifies which may be followed by DeviceValuator events.
22234642e01fSmrg *
222405b261ecSmrg * @param pWin The window that would get the event.
222505b261ecSmrg * @param pEvents The events to be delivered.
222605b261ecSmrg * @param count Number of elements in pEvents.
222705b261ecSmrg * @param filter Mask based on event type.
22284642e01fSmrg * @param grab Possible grab on the device that caused the event.
222905b261ecSmrg *
223035c4bbdfSmrg * @return a positive number if at least one successful delivery has been
223135c4bbdfSmrg * made, 0 if no events were delivered, or a negative number if the event
223235c4bbdfSmrg * has not been delivered _and_ rejected by at least one client.
223305b261ecSmrg */
223405b261ecSmrgint
22354642e01fSmrgDeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
223635c4bbdfSmrg                      *pEvents, int count, Mask filter, GrabPtr grab)
223705b261ecSmrg{
223805b261ecSmrg    int deliveries = 0, nondeliveries = 0;
223905b261ecSmrg    ClientPtr client = NullClient;
224035c4bbdfSmrg    Mask deliveryMask = 0;      /* If a grab occurs due to a button press, then
224135c4bbdfSmrg                                   this mask is the mask of the grab. */
224205b261ecSmrg    int type = pEvents->u.u.type;
224305b261ecSmrg
22446747b715Smrg    /* Deliver to window owner */
224535c4bbdfSmrg    if ((filter == CantBeFiltered) || core_get_type(pEvents) != 0) {
224635c4bbdfSmrg        enum EventDeliveryState rc;
22474642e01fSmrg
224835c4bbdfSmrg        rc = DeliverToWindowOwner(pDev, pWin, pEvents, count, filter, grab);
22494642e01fSmrg
225035c4bbdfSmrg        switch (rc) {
225135c4bbdfSmrg        case EVENT_SKIP:
225235c4bbdfSmrg            return 0;
225335c4bbdfSmrg        case EVENT_REJECTED:
225435c4bbdfSmrg            nondeliveries--;
225535c4bbdfSmrg            break;
225635c4bbdfSmrg        case EVENT_DELIVERED:
225735c4bbdfSmrg            /* We delivered to the owner, with our event mask */
225835c4bbdfSmrg            deliveries++;
225935c4bbdfSmrg            client = wClient(pWin);
226035c4bbdfSmrg            deliveryMask = pWin->eventMask;
226135c4bbdfSmrg            break;
226235c4bbdfSmrg        case EVENT_NOT_DELIVERED:
226335c4bbdfSmrg            break;
226435c4bbdfSmrg        }
226505b261ecSmrg    }
22666747b715Smrg
22676747b715Smrg    /* CantBeFiltered means only window owner gets the event */
226835c4bbdfSmrg    if (filter != CantBeFiltered) {
226935c4bbdfSmrg        enum EventDeliveryState rc;
227035c4bbdfSmrg
227135c4bbdfSmrg        rc = DeliverEventToWindowMask(pDev, pWin, pEvents, count, filter,
227235c4bbdfSmrg                                      grab, &client, &deliveryMask);
22734642e01fSmrg
227435c4bbdfSmrg        switch (rc) {
227535c4bbdfSmrg        case EVENT_SKIP:
227635c4bbdfSmrg            return 0;
227735c4bbdfSmrg        case EVENT_REJECTED:
227835c4bbdfSmrg            nondeliveries--;
227935c4bbdfSmrg            break;
228035c4bbdfSmrg        case EVENT_DELIVERED:
228135c4bbdfSmrg            deliveries++;
228235c4bbdfSmrg            break;
228335c4bbdfSmrg        case EVENT_NOT_DELIVERED:
228435c4bbdfSmrg            break;
22854642e01fSmrg        }
228635c4bbdfSmrg    }
22874642e01fSmrg
228835c4bbdfSmrg    if (deliveries) {
228935c4bbdfSmrg        /*
229035c4bbdfSmrg         * Note that since core events are delivered first, an implicit grab may
229135c4bbdfSmrg         * be activated on a core grab, stopping the XI events.
229235c4bbdfSmrg         */
229335c4bbdfSmrg        if (!grab &&
229435c4bbdfSmrg            ActivateImplicitGrab(pDev, client, pWin, pEvents, deliveryMask))
229535c4bbdfSmrg            /* grab activated */ ;
229635c4bbdfSmrg        else if (type == MotionNotify)
229735c4bbdfSmrg            pDev->valuator->motionHintWindow = pWin;
229835c4bbdfSmrg        else if (type == DeviceMotionNotify || type == DeviceButtonPress)
229935c4bbdfSmrg            CheckDeviceGrabAndHintWindow(pWin, type,
230035c4bbdfSmrg                                         (deviceKeyButtonPointer *) pEvents,
230135c4bbdfSmrg                                         grab, client, deliveryMask);
230235c4bbdfSmrg        return deliveries;
230335c4bbdfSmrg    }
230435c4bbdfSmrg    return nondeliveries;
230535c4bbdfSmrg}
230635c4bbdfSmrg
230735c4bbdfSmrg/**
230835c4bbdfSmrg * Filter out raw events for XI 2.0 and XI 2.1 clients.
230935c4bbdfSmrg *
231035c4bbdfSmrg * If there is a grab on the device, 2.0 clients only get raw events if they
231135c4bbdfSmrg * have the grab. 2.1+ clients get raw events in all cases.
231235c4bbdfSmrg *
231335c4bbdfSmrg * @return TRUE if the event should be discarded, FALSE otherwise.
231435c4bbdfSmrg */
231535c4bbdfSmrgstatic BOOL
231635c4bbdfSmrgFilterRawEvents(const ClientPtr client, const GrabPtr grab, WindowPtr root)
231735c4bbdfSmrg{
231835c4bbdfSmrg    XIClientPtr client_xi_version;
231935c4bbdfSmrg    int cmp;
23206747b715Smrg
232135c4bbdfSmrg    /* device not grabbed -> don't filter */
232235c4bbdfSmrg    if (!grab)
232335c4bbdfSmrg        return FALSE;
23246747b715Smrg
232535c4bbdfSmrg    client_xi_version =
232635c4bbdfSmrg        dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
232735c4bbdfSmrg
232835c4bbdfSmrg    cmp = version_compare(client_xi_version->major_version,
232935c4bbdfSmrg                          client_xi_version->minor_version, 2, 0);
233035c4bbdfSmrg    /* XI 2.0: if device is grabbed, skip
233135c4bbdfSmrg       XI 2.1: if device is grabbed by us, skip, we've already delivered */
233235c4bbdfSmrg    if (cmp == 0)
233335c4bbdfSmrg        return TRUE;
233435c4bbdfSmrg
233535c4bbdfSmrg    return (grab->window != root) ? FALSE : SameClient(grab, client);
233635c4bbdfSmrg}
233735c4bbdfSmrg
233835c4bbdfSmrg/**
233935c4bbdfSmrg * Deliver a raw event to the grab owner (if any) and to all root windows.
234035c4bbdfSmrg *
234135c4bbdfSmrg * Raw event delivery differs between XI 2.0 and XI 2.1.
234235c4bbdfSmrg * XI 2.0: events delivered to the grabbing client (if any) OR to all root
234335c4bbdfSmrg * windows
234435c4bbdfSmrg * XI 2.1: events delivered to all root windows, regardless of grabbing
234535c4bbdfSmrg * state.
234635c4bbdfSmrg */
234735c4bbdfSmrgvoid
234835c4bbdfSmrgDeliverRawEvent(RawDeviceEvent *ev, DeviceIntPtr device)
234935c4bbdfSmrg{
235035c4bbdfSmrg    GrabPtr grab = device->deviceGrab.grab;
235135c4bbdfSmrg    xEvent *xi;
235235c4bbdfSmrg    int i, rc;
235335c4bbdfSmrg    int filter;
235435c4bbdfSmrg
235535c4bbdfSmrg    rc = EventToXI2((InternalEvent *) ev, (xEvent **) &xi);
235635c4bbdfSmrg    if (rc != Success) {
235735c4bbdfSmrg        ErrorF("[Xi] %s: XI2 conversion failed in %s (%d)\n",
235835c4bbdfSmrg               __func__, device->name, rc);
235935c4bbdfSmrg        return;
236005b261ecSmrg    }
23614642e01fSmrg
236235c4bbdfSmrg    if (grab)
236335c4bbdfSmrg        DeliverGrabbedEvent((InternalEvent *) ev, device, FALSE);
236435c4bbdfSmrg
236535c4bbdfSmrg    filter = GetEventFilter(device, xi);
236635c4bbdfSmrg
236735c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
236835c4bbdfSmrg        WindowPtr root;
236935c4bbdfSmrg        InputClients *inputclients;
237035c4bbdfSmrg
237135c4bbdfSmrg        root = screenInfo.screens[i]->root;
237235c4bbdfSmrg        if (!GetClientsForDelivery(device, root, xi, filter, &inputclients))
237335c4bbdfSmrg            continue;
237435c4bbdfSmrg
237535c4bbdfSmrg        for (; inputclients; inputclients = inputclients->next) {
237635c4bbdfSmrg            ClientPtr c;        /* unused */
237735c4bbdfSmrg            Mask m;             /* unused */
237835c4bbdfSmrg            InputClients ic = *inputclients;
23794642e01fSmrg
238035c4bbdfSmrg            /* Because we run through the list manually, copy the actual
238135c4bbdfSmrg             * list, shorten the copy to only have one client and then pass
238235c4bbdfSmrg             * that down to DeliverEventToInputClients. This way we avoid
238335c4bbdfSmrg             * double events on XI 2.1 clients that have a grab on the
238435c4bbdfSmrg             * device.
238535c4bbdfSmrg             */
238635c4bbdfSmrg            ic.next = NULL;
23876747b715Smrg
238835c4bbdfSmrg            if (!FilterRawEvents(rClient(&ic), grab, root))
238935c4bbdfSmrg                DeliverEventToInputClients(device, &ic, root, xi, 1,
239035c4bbdfSmrg                                           filter, NULL, &c, &m);
239135c4bbdfSmrg        }
239205b261ecSmrg    }
239335c4bbdfSmrg
239435c4bbdfSmrg    free(xi);
239505b261ecSmrg}
239605b261ecSmrg
239705b261ecSmrg/* If the event goes to dontClient, don't send it and return 0.  if
239805b261ecSmrg   send works,  return 1 or if send didn't work, return 2.
239905b261ecSmrg   Only works for core events.
240005b261ecSmrg*/
240105b261ecSmrg
240205b261ecSmrg#ifdef PANORAMIX
24034642e01fSmrgstatic int
240435c4bbdfSmrgXineramaTryClientEventsResult(ClientPtr client,
240535c4bbdfSmrg                              GrabPtr grab, Mask mask, Mask filter)
240635c4bbdfSmrg{
240705b261ecSmrg    if ((client) && (client != serverClient) && (!client->clientGone) &&
240835c4bbdfSmrg        ((filter == CantBeFiltered) || (mask & filter))) {
240935c4bbdfSmrg        if (grab && !SameClient(grab, client))
241035c4bbdfSmrg            return -1;
241135c4bbdfSmrg        else
241235c4bbdfSmrg            return 1;
241305b261ecSmrg    }
241405b261ecSmrg    return 0;
241505b261ecSmrg}
241605b261ecSmrg#endif
241705b261ecSmrg
241805b261ecSmrg/**
241905b261ecSmrg * Try to deliver events to the interested parties.
242005b261ecSmrg *
242105b261ecSmrg * @param pWin The window that would get the event.
242205b261ecSmrg * @param pEvents The events to be delivered.
242305b261ecSmrg * @param count Number of elements in pEvents.
242405b261ecSmrg * @param filter Mask based on event type.
242505b261ecSmrg * @param dontClient Don't deliver to the dontClient.
242605b261ecSmrg */
242705b261ecSmrgint
24284642e01fSmrgMaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents,
242905b261ecSmrg                           int count, Mask filter, ClientPtr dontClient)
243005b261ecSmrg{
243105b261ecSmrg    OtherClients *other;
243205b261ecSmrg
243335c4bbdfSmrg    if (pWin->eventMask & filter) {
243405b261ecSmrg        if (wClient(pWin) == dontClient)
243535c4bbdfSmrg            return 0;
243605b261ecSmrg#ifdef PANORAMIX
243735c4bbdfSmrg        if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
243835c4bbdfSmrg            return XineramaTryClientEventsResult(wClient(pWin), NullGrab,
243935c4bbdfSmrg                                                 pWin->eventMask, filter);
244005b261ecSmrg#endif
244135c4bbdfSmrg        if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count))
244235c4bbdfSmrg            return 1;           /* don't send, but pretend we did */
244335c4bbdfSmrg        return TryClientEvents(wClient(pWin), NULL, pEvents, count,
244435c4bbdfSmrg                               pWin->eventMask, filter, NullGrab);
244505b261ecSmrg    }
244635c4bbdfSmrg    for (other = wOtherClients(pWin); other; other = other->next) {
244735c4bbdfSmrg        if (other->mask & filter) {
244805b261ecSmrg            if (SameClient(other, dontClient))
244935c4bbdfSmrg                return 0;
245005b261ecSmrg#ifdef PANORAMIX
245135c4bbdfSmrg            if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
245235c4bbdfSmrg                return XineramaTryClientEventsResult(rClient(other), NullGrab,
245335c4bbdfSmrg                                                     other->mask, filter);
245405b261ecSmrg#endif
245535c4bbdfSmrg            if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents,
245635c4bbdfSmrg                         count))
245735c4bbdfSmrg                return 1;       /* don't send, but pretend we did */
245835c4bbdfSmrg            return TryClientEvents(rClient(other), NULL, pEvents, count,
245935c4bbdfSmrg                                   other->mask, filter, NullGrab);
246035c4bbdfSmrg        }
246105b261ecSmrg    }
246205b261ecSmrg    return 2;
246305b261ecSmrg}
246405b261ecSmrg
246535c4bbdfSmrgstatic Window
246635c4bbdfSmrgFindChildForEvent(SpritePtr pSprite, WindowPtr event)
24676747b715Smrg{
246835c4bbdfSmrg    WindowPtr w = DeepestSpriteWin(pSprite);
24696747b715Smrg    Window child = None;
24706747b715Smrg
24716747b715Smrg    /* If the search ends up past the root should the child field be
24726747b715Smrg       set to none or should the value in the argument be passed
24736747b715Smrg       through. It probably doesn't matter since everyone calls
24746747b715Smrg       this function with child == None anyway. */
247535c4bbdfSmrg    while (w) {
24766747b715Smrg        /* If the source window is same as event window, child should be
24776747b715Smrg           none.  Don't bother going all all the way back to the root. */
24786747b715Smrg
247935c4bbdfSmrg        if (w == event) {
24806747b715Smrg            child = None;
24816747b715Smrg            break;
24826747b715Smrg        }
24836747b715Smrg
248435c4bbdfSmrg        if (w->parent == event) {
24856747b715Smrg            child = w->drawable.id;
24866747b715Smrg            break;
24876747b715Smrg        }
24886747b715Smrg        w = w->parent;
24896747b715Smrg    }
24906747b715Smrg    return child;
24916747b715Smrg}
24926747b715Smrg
249305b261ecSmrg/**
249405b261ecSmrg * Adjust event fields to comply with the window properties.
249505b261ecSmrg *
249605b261ecSmrg * @param xE Event to be modified in place
249705b261ecSmrg * @param pWin The window to get the information from.
249805b261ecSmrg * @param child Child window setting for event (if applicable)
249905b261ecSmrg * @param calcChild If True, calculate the child window.
250005b261ecSmrg */
25016747b715Smrgvoid
250235c4bbdfSmrgFixUpEventFromWindow(SpritePtr pSprite,
250335c4bbdfSmrg                     xEvent *xE, WindowPtr pWin, Window child, Bool calcChild)
250405b261ecSmrg{
250535c4bbdfSmrg    int evtype;
250635c4bbdfSmrg
250705b261ecSmrg    if (calcChild)
25089ace9065Smrg        child = FindChildForEvent(pSprite, pWin);
25096747b715Smrg
251035c4bbdfSmrg    if ((evtype = xi2_get_type(xE))) {
251135c4bbdfSmrg        xXIDeviceEvent *event = (xXIDeviceEvent *) xE;
251235c4bbdfSmrg
251335c4bbdfSmrg        switch (evtype) {
251435c4bbdfSmrg        case XI_RawKeyPress:
251535c4bbdfSmrg        case XI_RawKeyRelease:
251635c4bbdfSmrg        case XI_RawButtonPress:
251735c4bbdfSmrg        case XI_RawButtonRelease:
251835c4bbdfSmrg        case XI_RawMotion:
251935c4bbdfSmrg        case XI_RawTouchBegin:
252035c4bbdfSmrg        case XI_RawTouchUpdate:
252135c4bbdfSmrg        case XI_RawTouchEnd:
252235c4bbdfSmrg        case XI_DeviceChanged:
252335c4bbdfSmrg        case XI_HierarchyChanged:
252435c4bbdfSmrg        case XI_PropertyEvent:
252535c4bbdfSmrg        case XI_BarrierHit:
252635c4bbdfSmrg        case XI_BarrierLeave:
25276747b715Smrg            return;
252835c4bbdfSmrg        default:
252935c4bbdfSmrg            break;
253035c4bbdfSmrg        }
253105b261ecSmrg
25329ace9065Smrg        event->root = RootWindow(pSprite)->drawable.id;
25336747b715Smrg        event->event = pWin->drawable.id;
253435c4bbdfSmrg
253535c4bbdfSmrg        if (evtype == XI_TouchOwnership) {
25366747b715Smrg            event->child = child;
253735c4bbdfSmrg            return;
253835c4bbdfSmrg        }
253935c4bbdfSmrg
254035c4bbdfSmrg        if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
254135c4bbdfSmrg            event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
254235c4bbdfSmrg            event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
254335c4bbdfSmrg            event->child = child;
254435c4bbdfSmrg        }
254535c4bbdfSmrg        else {
25466747b715Smrg            event->event_x = 0;
25476747b715Smrg            event->event_y = 0;
25486747b715Smrg            event->child = None;
25496747b715Smrg        }
255005b261ecSmrg
25516747b715Smrg        if (event->evtype == XI_Enter || event->evtype == XI_Leave ||
25526747b715Smrg            event->evtype == XI_FocusIn || event->evtype == XI_FocusOut)
255335c4bbdfSmrg            ((xXIEnterEvent *) event)->same_screen =
25546747b715Smrg                (pSprite->hot.pScreen == pWin->drawable.pScreen);
25554642e01fSmrg
255635c4bbdfSmrg    }
255735c4bbdfSmrg    else {
25589ace9065Smrg        XE_KBPTR.root = RootWindow(pSprite)->drawable.id;
25596747b715Smrg        XE_KBPTR.event = pWin->drawable.id;
256035c4bbdfSmrg        if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
25616747b715Smrg            XE_KBPTR.sameScreen = xTrue;
25626747b715Smrg            XE_KBPTR.child = child;
256335c4bbdfSmrg            XE_KBPTR.eventX = XE_KBPTR.rootX - pWin->drawable.x;
256435c4bbdfSmrg            XE_KBPTR.eventY = XE_KBPTR.rootY - pWin->drawable.y;
25656747b715Smrg        }
256635c4bbdfSmrg        else {
25676747b715Smrg            XE_KBPTR.sameScreen = xFalse;
25686747b715Smrg            XE_KBPTR.child = None;
25696747b715Smrg            XE_KBPTR.eventX = 0;
25706747b715Smrg            XE_KBPTR.eventY = 0;
25716747b715Smrg        }
257205b261ecSmrg    }
257305b261ecSmrg}
257405b261ecSmrg
25756747b715Smrg/**
25766747b715Smrg * Check if a given event is deliverable at all on a given window.
25776747b715Smrg *
25786747b715Smrg * This function only checks if any client wants it, not for a specific
25796747b715Smrg * client.
25806747b715Smrg *
25816747b715Smrg * @param[in] dev The device this event is being sent for.
258235c4bbdfSmrg * @param[in] evtype The event type of the event that is to be sent.
25836747b715Smrg * @param[in] win The current event window.
25846747b715Smrg *
258535c4bbdfSmrg * @return Bitmask of ::EVENT_XI2_MASK, ::EVENT_XI1_MASK, ::EVENT_CORE_MASK, and
258635c4bbdfSmrg *         ::EVENT_DONT_PROPAGATE_MASK.
25876747b715Smrg */
25889ace9065Smrgint
258935c4bbdfSmrgEventIsDeliverable(DeviceIntPtr dev, int evtype, WindowPtr win)
25906747b715Smrg{
25916747b715Smrg    int rc = 0;
25926747b715Smrg    int filter = 0;
25936747b715Smrg    int type;
25946747b715Smrg    OtherInputMasks *inputMasks = wOtherInputMasks(win);
259535c4bbdfSmrg
259635c4bbdfSmrg    if ((type = GetXI2Type(evtype)) != 0) {
259735c4bbdfSmrg        if (inputMasks && xi2mask_isset(inputMasks->xi2mask, dev, type))
259835c4bbdfSmrg            rc |= EVENT_XI2_MASK;
259935c4bbdfSmrg    }
260035c4bbdfSmrg
260135c4bbdfSmrg    if ((type = GetXIType(evtype)) != 0) {
260235c4bbdfSmrg        filter = event_get_filter_from_type(dev, type);
260335c4bbdfSmrg
260435c4bbdfSmrg        /* Check for XI mask */
260535c4bbdfSmrg        if (inputMasks &&
260635c4bbdfSmrg            (inputMasks->deliverableEvents[dev->id] & filter) &&
260735c4bbdfSmrg            (inputMasks->inputEvents[dev->id] & filter))
260835c4bbdfSmrg            rc |= EVENT_XI1_MASK;
260935c4bbdfSmrg
261035c4bbdfSmrg        /* Check for XI DontPropagate mask */
261135c4bbdfSmrg        if (inputMasks && (inputMasks->dontPropagateMask[dev->id] & filter))
261235c4bbdfSmrg            rc |= EVENT_DONT_PROPAGATE_MASK;
261335c4bbdfSmrg
261435c4bbdfSmrg    }
261535c4bbdfSmrg
261635c4bbdfSmrg    if ((type = GetCoreType(evtype)) != 0) {
261735c4bbdfSmrg        filter = event_get_filter_from_type(dev, type);
261835c4bbdfSmrg
261935c4bbdfSmrg        /* Check for core mask */
262035c4bbdfSmrg        if ((win->deliverableEvents & filter) &&
262135c4bbdfSmrg            ((wOtherEventMasks(win) | win->eventMask) & filter))
262235c4bbdfSmrg            rc |= EVENT_CORE_MASK;
262335c4bbdfSmrg
262435c4bbdfSmrg        /* Check for core DontPropagate mask */
262535c4bbdfSmrg        if (filter & wDontPropagateMask(win))
262635c4bbdfSmrg            rc |= EVENT_DONT_PROPAGATE_MASK;
262735c4bbdfSmrg    }
26286747b715Smrg
26296747b715Smrg    return rc;
26306747b715Smrg}
26316747b715Smrg
263235c4bbdfSmrgstatic int
263335c4bbdfSmrgDeliverEvent(DeviceIntPtr dev, xEvent *xE, int count,
263435c4bbdfSmrg             WindowPtr win, Window child, GrabPtr grab)
263535c4bbdfSmrg{
263635c4bbdfSmrg    SpritePtr pSprite = dev->spriteInfo->sprite;
263735c4bbdfSmrg    Mask filter;
263835c4bbdfSmrg    int deliveries = 0;
263935c4bbdfSmrg
264035c4bbdfSmrg    if (XaceHook(XACE_SEND_ACCESS, NULL, dev, win, xE, count) == Success) {
264135c4bbdfSmrg        filter = GetEventFilter(dev, xE);
264235c4bbdfSmrg        FixUpEventFromWindow(pSprite, xE, win, child, FALSE);
264335c4bbdfSmrg        deliveries = DeliverEventsToWindow(dev, win, xE, count, filter, grab);
264435c4bbdfSmrg    }
264535c4bbdfSmrg
264635c4bbdfSmrg    return deliveries;
264735c4bbdfSmrg}
264835c4bbdfSmrg
264935c4bbdfSmrgstatic int
265035c4bbdfSmrgDeliverOneEvent(InternalEvent *event, DeviceIntPtr dev, enum InputLevel level,
265135c4bbdfSmrg                WindowPtr win, Window child, GrabPtr grab)
265235c4bbdfSmrg{
265335c4bbdfSmrg    xEvent *xE = NULL;
265435c4bbdfSmrg    int count = 0;
265535c4bbdfSmrg    int deliveries = 0;
265635c4bbdfSmrg    int rc;
265735c4bbdfSmrg
265835c4bbdfSmrg    switch (level) {
265935c4bbdfSmrg    case XI2:
266035c4bbdfSmrg        rc = EventToXI2(event, &xE);
266135c4bbdfSmrg        count = 1;
266235c4bbdfSmrg        break;
266335c4bbdfSmrg    case XI:
266435c4bbdfSmrg        rc = EventToXI(event, &xE, &count);
266535c4bbdfSmrg        break;
266635c4bbdfSmrg    case CORE:
266735c4bbdfSmrg        rc = EventToCore(event, &xE, &count);
266835c4bbdfSmrg        break;
266935c4bbdfSmrg    default:
267035c4bbdfSmrg        rc = BadImplementation;
267135c4bbdfSmrg        break;
267235c4bbdfSmrg    }
267335c4bbdfSmrg
267435c4bbdfSmrg    if (rc == Success) {
267535c4bbdfSmrg        deliveries = DeliverEvent(dev, xE, count, win, child, grab);
267635c4bbdfSmrg        free(xE);
267735c4bbdfSmrg    }
267835c4bbdfSmrg    else
267935c4bbdfSmrg        BUG_WARN_MSG(rc != BadMatch,
268035c4bbdfSmrg                     "%s: conversion to level %d failed with rc %d\n",
268135c4bbdfSmrg                     dev->name, level, rc);
268235c4bbdfSmrg    return deliveries;
268335c4bbdfSmrg}
268435c4bbdfSmrg
26856747b715Smrg/**
26866747b715Smrg * Deliver events caused by input devices.
26876747b715Smrg *
26884642e01fSmrg * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is
26894642e01fSmrg * called directly from the processInputProc.
26904642e01fSmrg * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call
26914642e01fSmrg * DeliverDeviceEvents.
26924642e01fSmrg * For focused events, DeliverFocusedEvent is called first, and _may_ call
26934642e01fSmrg * DeliverDeviceEvents.
269405b261ecSmrg *
269505b261ecSmrg * @param pWin Window to deliver event to.
26966747b715Smrg * @param event The events to deliver, not yet in wire format.
269705b261ecSmrg * @param grab Possible grab on a device.
269805b261ecSmrg * @param stopAt Don't recurse up to the root window.
269905b261ecSmrg * @param dev The device that is responsible for the event.
270005b261ecSmrg *
27014642e01fSmrg * @see DeliverGrabbedEvent
27024642e01fSmrg * @see DeliverFocusedEvent
270305b261ecSmrg */
270405b261ecSmrgint
27056747b715SmrgDeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab,
27066747b715Smrg                    WindowPtr stopAt, DeviceIntPtr dev)
270705b261ecSmrg{
270805b261ecSmrg    Window child = None;
270905b261ecSmrg    int deliveries = 0;
271035c4bbdfSmrg    int mask;
27114642e01fSmrg
271235c4bbdfSmrg    verify_internal_event(event);
27134642e01fSmrg
271435c4bbdfSmrg    while (pWin) {
271535c4bbdfSmrg        if ((mask = EventIsDeliverable(dev, event->any.type, pWin))) {
27166747b715Smrg            /* XI2 events first */
271735c4bbdfSmrg            if (mask & EVENT_XI2_MASK) {
271835c4bbdfSmrg                deliveries =
271935c4bbdfSmrg                    DeliverOneEvent(event, dev, XI2, pWin, child, grab);
272035c4bbdfSmrg                if (deliveries > 0)
272135c4bbdfSmrg                    break;
27224642e01fSmrg            }
27234642e01fSmrg
27246747b715Smrg            /* XI events */
272535c4bbdfSmrg            if (mask & EVENT_XI1_MASK) {
272635c4bbdfSmrg                deliveries = DeliverOneEvent(event, dev, XI, pWin, child, grab);
272735c4bbdfSmrg                if (deliveries > 0)
272835c4bbdfSmrg                    break;
27296747b715Smrg            }
27304642e01fSmrg
27316747b715Smrg            /* Core event */
273235c4bbdfSmrg            if ((mask & EVENT_CORE_MASK) && IsMaster(dev) && dev->coreEvents) {
273335c4bbdfSmrg                deliveries =
273435c4bbdfSmrg                    DeliverOneEvent(event, dev, CORE, pWin, child, grab);
273535c4bbdfSmrg                if (deliveries > 0)
273635c4bbdfSmrg                    break;
27374642e01fSmrg            }
27384642e01fSmrg
273935c4bbdfSmrg        }
274035c4bbdfSmrg
274135c4bbdfSmrg        if ((deliveries < 0) || (pWin == stopAt) ||
274235c4bbdfSmrg            (mask & EVENT_DONT_PROPAGATE_MASK)) {
274335c4bbdfSmrg            deliveries = 0;
274435c4bbdfSmrg            break;
27454642e01fSmrg        }
27464642e01fSmrg
27474642e01fSmrg        child = pWin->drawable.id;
27484642e01fSmrg        pWin = pWin->parent;
274905b261ecSmrg    }
27504642e01fSmrg
27516747b715Smrg    return deliveries;
275205b261ecSmrg}
275305b261ecSmrg
275405b261ecSmrg/**
275505b261ecSmrg * Deliver event to a window and it's immediate parent. Used for most window
275605b261ecSmrg * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that
27574642e01fSmrg * propagate up the tree or extension events
275805b261ecSmrg *
275905b261ecSmrg * In case of a ReparentNotify event, the event will be delivered to the
276005b261ecSmrg * otherParent as well.
276105b261ecSmrg *
276205b261ecSmrg * @param pWin Window to deliver events to.
276305b261ecSmrg * @param xE Events to deliver.
276405b261ecSmrg * @param count number of events in xE.
276505b261ecSmrg * @param otherParent Used for ReparentNotify events.
276605b261ecSmrg */
27676747b715Smrgint
276835c4bbdfSmrgDeliverEvents(WindowPtr pWin, xEvent *xE, int count, WindowPtr otherParent)
276905b261ecSmrg{
27706747b715Smrg    DeviceIntRec dummy;
277135c4bbdfSmrg    int deliveries;
277205b261ecSmrg
277305b261ecSmrg#ifdef PANORAMIX
277435c4bbdfSmrg    if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
277535c4bbdfSmrg        return count;
277605b261ecSmrg#endif
277705b261ecSmrg
277805b261ecSmrg    if (!count)
277935c4bbdfSmrg        return 0;
27806747b715Smrg
27816747b715Smrg    dummy.id = XIAllDevices;
278235c4bbdfSmrg
278335c4bbdfSmrg    switch (xE->u.u.type) {
278435c4bbdfSmrg    case DestroyNotify:
278535c4bbdfSmrg    case UnmapNotify:
278635c4bbdfSmrg    case MapNotify:
278735c4bbdfSmrg    case MapRequest:
278835c4bbdfSmrg    case ReparentNotify:
278935c4bbdfSmrg    case ConfigureNotify:
279035c4bbdfSmrg    case ConfigureRequest:
279135c4bbdfSmrg    case GravityNotify:
279235c4bbdfSmrg    case CirculateNotify:
279335c4bbdfSmrg    case CirculateRequest:
279435c4bbdfSmrg        xE->u.destroyNotify.event = pWin->drawable.id;
279535c4bbdfSmrg        break;
279635c4bbdfSmrg    }
279735c4bbdfSmrg
279835c4bbdfSmrg    switch (xE->u.u.type) {
279935c4bbdfSmrg    case DestroyNotify:
280035c4bbdfSmrg    case UnmapNotify:
280135c4bbdfSmrg    case MapNotify:
280235c4bbdfSmrg    case ReparentNotify:
280335c4bbdfSmrg    case ConfigureNotify:
280435c4bbdfSmrg    case GravityNotify:
280535c4bbdfSmrg    case CirculateNotify:
280635c4bbdfSmrg        break;
280735c4bbdfSmrg    default:
280835c4bbdfSmrg    {
280935c4bbdfSmrg        Mask filter;
281035c4bbdfSmrg
281135c4bbdfSmrg        filter = GetEventFilter(&dummy, xE);
281235c4bbdfSmrg        return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab);
281335c4bbdfSmrg    }
281435c4bbdfSmrg    }
281535c4bbdfSmrg
28166747b715Smrg    deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count,
28176747b715Smrg                                       StructureNotifyMask, NullGrab);
281835c4bbdfSmrg    if (pWin->parent) {
281935c4bbdfSmrg        xE->u.destroyNotify.event = pWin->parent->drawable.id;
282035c4bbdfSmrg        deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count,
282135c4bbdfSmrg                                            SubstructureNotifyMask, NullGrab);
282235c4bbdfSmrg        if (xE->u.u.type == ReparentNotify) {
282335c4bbdfSmrg            xE->u.destroyNotify.event = otherParent->drawable.id;
28246747b715Smrg            deliveries += DeliverEventsToWindow(&dummy,
282535c4bbdfSmrg                                                otherParent, xE, count,
282635c4bbdfSmrg                                                SubstructureNotifyMask,
282735c4bbdfSmrg                                                NullGrab);
282835c4bbdfSmrg        }
282905b261ecSmrg    }
283005b261ecSmrg    return deliveries;
283105b261ecSmrg}
283205b261ecSmrg
283335c4bbdfSmrgBool
283405b261ecSmrgPointInBorderSize(WindowPtr pWin, int x, int y)
283505b261ecSmrg{
283605b261ecSmrg    BoxRec box;
283705b261ecSmrg
283835c4bbdfSmrg    if (RegionContainsPoint(&pWin->borderSize, x, y, &box))
283935c4bbdfSmrg        return TRUE;
284005b261ecSmrg
284105b261ecSmrg#ifdef PANORAMIX
284235c4bbdfSmrg    if (!noPanoramiXExtension &&
284335c4bbdfSmrg        XineramaSetWindowPntrs(inputInfo.pointer, pWin)) {
284435c4bbdfSmrg        SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite;
284535c4bbdfSmrg        int i;
284635c4bbdfSmrg
284735c4bbdfSmrg        FOR_NSCREENS_FORWARD_SKIP(i) {
284835c4bbdfSmrg            if (RegionContainsPoint(&pSprite->windows[i]->borderSize,
284935c4bbdfSmrg                                    x + screenInfo.screens[0]->x -
285035c4bbdfSmrg                                    screenInfo.screens[i]->x,
285135c4bbdfSmrg                                    y + screenInfo.screens[0]->y -
285235c4bbdfSmrg                                    screenInfo.screens[i]->y, &box))
285335c4bbdfSmrg                return TRUE;
285435c4bbdfSmrg        }
285505b261ecSmrg    }
285605b261ecSmrg#endif
285705b261ecSmrg    return FALSE;
285805b261ecSmrg}
285905b261ecSmrg
286005b261ecSmrg/**
286105b261ecSmrg * Traversed from the root window to the window at the position x/y. While
286205b261ecSmrg * traversing, it sets up the traversal history in the spriteTrace array.
286305b261ecSmrg * After completing, the spriteTrace history is set in the following way:
286405b261ecSmrg *   spriteTrace[0] ... root window
286505b261ecSmrg *   spriteTrace[1] ... top level window that encloses x/y
286605b261ecSmrg *       ...
286705b261ecSmrg *   spriteTrace[spriteTraceGood - 1] ... window at x/y
286805b261ecSmrg *
286905b261ecSmrg * @returns the window at the given coordinates.
287005b261ecSmrg */
28719ace9065SmrgWindowPtr
28729ace9065SmrgXYToWindow(SpritePtr pSprite, int x, int y)
287305b261ecSmrg{
287435c4bbdfSmrg    ScreenPtr pScreen = RootWindow(pSprite)->drawable.pScreen;
287505b261ecSmrg
287635c4bbdfSmrg    return (*pScreen->XYToWindow)(pScreen, pSprite, x, y);
287705b261ecSmrg}
287805b261ecSmrg
28796747b715Smrg/**
28806747b715Smrg * Ungrab a currently FocusIn grabbed device and grab the device on the
28816747b715Smrg * given window. If the win given is the NoneWin, the device is ungrabbed if
28826747b715Smrg * applicable and FALSE is returned.
28836747b715Smrg *
28846747b715Smrg * @returns TRUE if the device has been grabbed, or FALSE otherwise.
28856747b715Smrg */
28866747b715SmrgBOOL
28876747b715SmrgActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
28886747b715Smrg{
28896747b715Smrg    BOOL rc = FALSE;
28906747b715Smrg    DeviceEvent event;
28916747b715Smrg
289235c4bbdfSmrg    if (dev->deviceGrab.grab) {
28939ace9065Smrg        if (!dev->deviceGrab.fromPassiveGrab ||
28949ace9065Smrg            dev->deviceGrab.grab->type != XI_Enter ||
28959ace9065Smrg            dev->deviceGrab.grab->window == win ||
28966747b715Smrg            IsParent(dev->deviceGrab.grab->window, win))
28976747b715Smrg            return FALSE;
28986747b715Smrg        DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
289935c4bbdfSmrg        (*dev->deviceGrab.DeactivateGrab) (dev);
29006747b715Smrg    }
29016747b715Smrg
29026747b715Smrg    if (win == NoneWin || win == PointerRootWin)
29036747b715Smrg        return FALSE;
29046747b715Smrg
290535c4bbdfSmrg    event = (DeviceEvent) {
290635c4bbdfSmrg        .header = ET_Internal,
290735c4bbdfSmrg        .type = ET_FocusIn,
290835c4bbdfSmrg        .length = sizeof(DeviceEvent),
290935c4bbdfSmrg        .time = GetTimeInMillis(),
291035c4bbdfSmrg        .deviceid = dev->id,
291135c4bbdfSmrg        .sourceid = dev->id,
291235c4bbdfSmrg        .detail.button = 0
291335c4bbdfSmrg    };
291435c4bbdfSmrg    rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
291535c4bbdfSmrg                                    TRUE) != NULL);
29166747b715Smrg    if (rc)
29176747b715Smrg        DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
29186747b715Smrg    return rc;
29196747b715Smrg}
29206747b715Smrg
29216747b715Smrg/**
29226747b715Smrg * Ungrab a currently Enter grabbed device and grab the device for the given
29236747b715Smrg * window.
29246747b715Smrg *
29256747b715Smrg * @returns TRUE if the device has been grabbed, or FALSE otherwise.
29266747b715Smrg */
29276747b715Smrgstatic BOOL
29286747b715SmrgActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
29296747b715Smrg{
29306747b715Smrg    BOOL rc = FALSE;
29316747b715Smrg    DeviceEvent event;
29326747b715Smrg
293335c4bbdfSmrg    if (dev->deviceGrab.grab) {
29349ace9065Smrg        if (!dev->deviceGrab.fromPassiveGrab ||
29359ace9065Smrg            dev->deviceGrab.grab->type != XI_Enter ||
29369ace9065Smrg            dev->deviceGrab.grab->window == win ||
29376747b715Smrg            IsParent(dev->deviceGrab.grab->window, win))
29386747b715Smrg            return FALSE;
29396747b715Smrg        DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
294035c4bbdfSmrg        (*dev->deviceGrab.DeactivateGrab) (dev);
294135c4bbdfSmrg    }
294235c4bbdfSmrg
294335c4bbdfSmrg    event = (DeviceEvent) {
294435c4bbdfSmrg        .header = ET_Internal,
294535c4bbdfSmrg        .type = ET_Enter,
294635c4bbdfSmrg        .length = sizeof(DeviceEvent),
294735c4bbdfSmrg        .time = GetTimeInMillis(),
294835c4bbdfSmrg        .deviceid = dev->id,
294935c4bbdfSmrg        .sourceid = dev->id,
295035c4bbdfSmrg        .detail.button = 0
295135c4bbdfSmrg    };
295235c4bbdfSmrg    rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
295335c4bbdfSmrg                                    TRUE) != NULL);
29546747b715Smrg    if (rc)
29556747b715Smrg        DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
29566747b715Smrg    return rc;
29576747b715Smrg}
29586747b715Smrg
295905b261ecSmrg/**
296005b261ecSmrg * Update the sprite coordinates based on the event. Update the cursor
296105b261ecSmrg * position, then update the event with the new coordinates that may have been
296205b261ecSmrg * changed. If the window underneath the sprite has changed, change to new
296305b261ecSmrg * cursor and send enter/leave events.
29644642e01fSmrg *
29654642e01fSmrg * CheckMotion() will not do anything and return FALSE if the event is not a
29664642e01fSmrg * pointer event.
29674642e01fSmrg *
29684642e01fSmrg * @return TRUE if the sprite has moved or FALSE otherwise.
296905b261ecSmrg */
29704642e01fSmrgBool
29716747b715SmrgCheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
297205b261ecSmrg{
29736747b715Smrg    WindowPtr prevSpriteWin, newSpriteWin;
29744642e01fSmrg    SpritePtr pSprite = pDev->spriteInfo->sprite;
29754642e01fSmrg
297635c4bbdfSmrg    verify_internal_event((InternalEvent *) ev);
297705b261ecSmrg
29786747b715Smrg    prevSpriteWin = pSprite->win;
297905b261ecSmrg
298035c4bbdfSmrg    if (ev && !syncEvents.playingEvents) {
29814642e01fSmrg        /* GetPointerEvents() guarantees that pointer events have the correct
29824642e01fSmrg           rootX/Y set already. */
298335c4bbdfSmrg        switch (ev->type) {
298435c4bbdfSmrg        case ET_ButtonPress:
298535c4bbdfSmrg        case ET_ButtonRelease:
298635c4bbdfSmrg        case ET_Motion:
298735c4bbdfSmrg        case ET_TouchBegin:
298835c4bbdfSmrg        case ET_TouchUpdate:
298935c4bbdfSmrg        case ET_TouchEnd:
299035c4bbdfSmrg            break;
299135c4bbdfSmrg        default:
299235c4bbdfSmrg            /* all other events return FALSE */
299335c4bbdfSmrg            return FALSE;
29944642e01fSmrg        }
29954642e01fSmrg
29966747b715Smrg#ifdef PANORAMIX
299735c4bbdfSmrg        if (!noPanoramiXExtension) {
29986747b715Smrg            /* Motion events entering DIX get translated to Screen 0
29996747b715Smrg               coordinates.  Replayed events have already been
30006747b715Smrg               translated since they've entered DIX before */
30016747b715Smrg            ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
30026747b715Smrg            ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
300335c4bbdfSmrg        }
300435c4bbdfSmrg        else
30056747b715Smrg#endif
30066747b715Smrg        {
300735c4bbdfSmrg            if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) {
30086747b715Smrg                pSprite->hot.pScreen = pSprite->hotPhys.pScreen;
30099ace9065Smrg                RootWindow(pDev->spriteInfo->sprite) =
30109ace9065Smrg                    pSprite->hot.pScreen->root;
30116747b715Smrg            }
30124642e01fSmrg        }
30136747b715Smrg
30146747b715Smrg        pSprite->hot.x = ev->root_x;
30156747b715Smrg        pSprite->hot.y = ev->root_y;
30164642e01fSmrg        if (pSprite->hot.x < pSprite->physLimits.x1)
30174642e01fSmrg            pSprite->hot.x = pSprite->physLimits.x1;
30184642e01fSmrg        else if (pSprite->hot.x >= pSprite->physLimits.x2)
30194642e01fSmrg            pSprite->hot.x = pSprite->physLimits.x2 - 1;
30204642e01fSmrg        if (pSprite->hot.y < pSprite->physLimits.y1)
30214642e01fSmrg            pSprite->hot.y = pSprite->physLimits.y1;
30224642e01fSmrg        else if (pSprite->hot.y >= pSprite->physLimits.y2)
30234642e01fSmrg            pSprite->hot.y = pSprite->physLimits.y2 - 1;
302435c4bbdfSmrg        if (pSprite->hotShape)
302535c4bbdfSmrg            ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x,
302635c4bbdfSmrg                           &pSprite->hot.y);
302735c4bbdfSmrg        pSprite->hotPhys = pSprite->hot;
30284642e01fSmrg
302935c4bbdfSmrg        if ((pSprite->hotPhys.x != ev->root_x) ||
303035c4bbdfSmrg            (pSprite->hotPhys.y != ev->root_y)) {
30316747b715Smrg#ifdef PANORAMIX
303235c4bbdfSmrg            if (!noPanoramiXExtension) {
303335c4bbdfSmrg                XineramaSetCursorPosition(pDev, pSprite->hotPhys.x,
303435c4bbdfSmrg                                          pSprite->hotPhys.y, FALSE);
303535c4bbdfSmrg            }
303635c4bbdfSmrg            else
30376747b715Smrg#endif
30386747b715Smrg            {
303935c4bbdfSmrg                (*pSprite->hotPhys.pScreen->SetCursorPosition) (pDev,
304035c4bbdfSmrg                                                                pSprite->
304135c4bbdfSmrg                                                                hotPhys.pScreen,
304235c4bbdfSmrg                                                                pSprite->
304335c4bbdfSmrg                                                                hotPhys.x,
304435c4bbdfSmrg                                                                pSprite->
304535c4bbdfSmrg                                                                hotPhys.y,
304635c4bbdfSmrg                                                                FALSE);
30476747b715Smrg            }
304835c4bbdfSmrg        }
30494642e01fSmrg
305035c4bbdfSmrg        ev->root_x = pSprite->hot.x;
305135c4bbdfSmrg        ev->root_y = pSprite->hot.y;
305205b261ecSmrg    }
305305b261ecSmrg
30549ace9065Smrg    newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y);
30556747b715Smrg
305635c4bbdfSmrg    if (newSpriteWin != prevSpriteWin) {
30576747b715Smrg        int sourceid;
305835c4bbdfSmrg
30596747b715Smrg        if (!ev) {
30606747b715Smrg            UpdateCurrentTimeIf();
306135c4bbdfSmrg            sourceid = pDev->id;        /* when from WindowsRestructured */
306235c4bbdfSmrg        }
306335c4bbdfSmrg        else
30646747b715Smrg            sourceid = ev->sourceid;
30656747b715Smrg
306635c4bbdfSmrg        if (prevSpriteWin != NullWindow) {
30676747b715Smrg            if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin))
30686747b715Smrg                DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin,
30696747b715Smrg                                   newSpriteWin, NotifyNormal);
30704642e01fSmrg        }
30716747b715Smrg        /* set pSprite->win after ActivateEnterGrab, otherwise
30726747b715Smrg           sprite window == grab_window and no enter/leave events are
30736747b715Smrg           sent. */
30746747b715Smrg        pSprite->win = newSpriteWin;
30756747b715Smrg        PostNewCursor(pDev);
307605b261ecSmrg        return FALSE;
307705b261ecSmrg    }
307805b261ecSmrg    return TRUE;
307905b261ecSmrg}
308005b261ecSmrg
308105b261ecSmrg/**
308205b261ecSmrg * Windows have restructured, we need to update the sprite position and the
308305b261ecSmrg * sprite's cursor.
308405b261ecSmrg */
30854642e01fSmrgvoid
308605b261ecSmrgWindowsRestructured(void)
308705b261ecSmrg{
30884642e01fSmrg    DeviceIntPtr pDev = inputInfo.devices;
308935c4bbdfSmrg
309035c4bbdfSmrg    while (pDev) {
309135c4bbdfSmrg        if (IsMaster(pDev) || IsFloating(pDev))
3092b1d344b3Smrg            CheckMotion(NULL, pDev);
30934642e01fSmrg        pDev = pDev->next;
30944642e01fSmrg    }
309505b261ecSmrg}
309605b261ecSmrg
309705b261ecSmrg#ifdef PANORAMIX
309805b261ecSmrg/* This was added to support reconfiguration under Xdmx.  The problem is
30996747b715Smrg * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin
310005b261ecSmrg * other than 0,0, the information in the private sprite structure must
310105b261ecSmrg * be updated accordingly, or XYToWindow (and other routines) will not
310205b261ecSmrg * compute correctly. */
310335c4bbdfSmrgvoid
310435c4bbdfSmrgReinitializeRootWindow(WindowPtr win, int xoff, int yoff)
310505b261ecSmrg{
310635c4bbdfSmrg    GrabPtr grab;
31074642e01fSmrg    DeviceIntPtr pDev;
31084642e01fSmrg    SpritePtr pSprite;
310905b261ecSmrg
311035c4bbdfSmrg    if (noPanoramiXExtension)
311135c4bbdfSmrg        return;
311205b261ecSmrg
31134642e01fSmrg    pDev = inputInfo.devices;
311435c4bbdfSmrg    while (pDev) {
311535c4bbdfSmrg        if (DevHasCursor(pDev)) {
31164642e01fSmrg            pSprite = pDev->spriteInfo->sprite;
311735c4bbdfSmrg            pSprite->hot.x -= xoff;
311835c4bbdfSmrg            pSprite->hot.y -= yoff;
31194642e01fSmrg
312035c4bbdfSmrg            pSprite->hotPhys.x -= xoff;
312135c4bbdfSmrg            pSprite->hotPhys.y -= yoff;
31224642e01fSmrg
31234642e01fSmrg            pSprite->hotLimits.x1 -= xoff;
31244642e01fSmrg            pSprite->hotLimits.y1 -= yoff;
31254642e01fSmrg            pSprite->hotLimits.x2 -= xoff;
31264642e01fSmrg            pSprite->hotLimits.y2 -= yoff;
31274642e01fSmrg
31286747b715Smrg            if (RegionNotEmpty(&pSprite->Reg1))
31296747b715Smrg                RegionTranslate(&pSprite->Reg1, xoff, yoff);
31306747b715Smrg            if (RegionNotEmpty(&pSprite->Reg2))
31316747b715Smrg                RegionTranslate(&pSprite->Reg2, xoff, yoff);
31324642e01fSmrg
31334642e01fSmrg            /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */
31344642e01fSmrg            if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
31354642e01fSmrg                if (grab->confineTo->drawable.pScreen
313635c4bbdfSmrg                    != pSprite->hotPhys.pScreen)
31374642e01fSmrg                    pSprite->hotPhys.x = pSprite->hotPhys.y = 0;
31384642e01fSmrg                ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
313935c4bbdfSmrg            }
314035c4bbdfSmrg            else
314135c4bbdfSmrg                ConfineCursorToWindow(pDev,
314235c4bbdfSmrg                                      pSprite->hotPhys.pScreen->root,
314335c4bbdfSmrg                                      TRUE, FALSE);
31444642e01fSmrg
31454642e01fSmrg        }
31464642e01fSmrg        pDev = pDev->next;
31474642e01fSmrg    }
31484642e01fSmrg}
31494642e01fSmrg#endif
31504642e01fSmrg
31514642e01fSmrg/**
31524642e01fSmrg * Initialize a sprite for the given device and set it to some sane values. If
31534642e01fSmrg * the device already has a sprite alloc'd, don't realloc but just reset to
31544642e01fSmrg * default values.
31554642e01fSmrg * If a window is supplied, the sprite will be initialized with the window's
31564642e01fSmrg * cursor and positioned in the center of the window's screen. The root window
31574642e01fSmrg * is a good choice to pass in here.
31584642e01fSmrg *
31594642e01fSmrg * It's a good idea to call it only for pointer devices, unless you have a
31604642e01fSmrg * really talented keyboard.
31614642e01fSmrg *
31624642e01fSmrg * @param pDev The device to initialize.
31634642e01fSmrg * @param pWin The window where to generate the sprite in.
31644642e01fSmrg *
31654642e01fSmrg */
31664642e01fSmrgvoid
31674642e01fSmrgInitializeSprite(DeviceIntPtr pDev, WindowPtr pWin)
31684642e01fSmrg{
31694642e01fSmrg    SpritePtr pSprite;
31704642e01fSmrg    ScreenPtr pScreen;
31716747b715Smrg    CursorPtr pCursor;
31724642e01fSmrg
317335c4bbdfSmrg    if (!pDev->spriteInfo->sprite) {
31744642e01fSmrg        DeviceIntPtr it;
31754642e01fSmrg
317635c4bbdfSmrg        pDev->spriteInfo->sprite = (SpritePtr) calloc(1, sizeof(SpriteRec));
31774642e01fSmrg        if (!pDev->spriteInfo->sprite)
31784642e01fSmrg            FatalError("InitializeSprite: failed to allocate sprite struct");
31794642e01fSmrg
31804642e01fSmrg        /* We may have paired another device with this device before our
31814642e01fSmrg         * device had a actual sprite. We need to check for this and reset the
31824642e01fSmrg         * sprite field for all paired devices.
31834642e01fSmrg         *
31844642e01fSmrg         * The VCK is always paired with the VCP before the VCP has a sprite.
31854642e01fSmrg         */
318635c4bbdfSmrg        for (it = inputInfo.devices; it; it = it->next) {
31874642e01fSmrg            if (it->spriteInfo->paired == pDev)
31884642e01fSmrg                it->spriteInfo->sprite = pDev->spriteInfo->sprite;
31894642e01fSmrg        }
31904642e01fSmrg        if (inputInfo.keyboard->spriteInfo->paired == pDev)
31914642e01fSmrg            inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite;
31924642e01fSmrg    }
31934642e01fSmrg
31944642e01fSmrg    pSprite = pDev->spriteInfo->sprite;
31954642e01fSmrg    pDev->spriteInfo->spriteOwner = TRUE;
319605b261ecSmrg
319735c4bbdfSmrg    pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr) NULL;
31984642e01fSmrg    pSprite->hot.pScreen = pScreen;
31994642e01fSmrg    pSprite->hotPhys.pScreen = pScreen;
320035c4bbdfSmrg    if (pScreen) {
32014642e01fSmrg        pSprite->hotPhys.x = pScreen->width / 2;
32024642e01fSmrg        pSprite->hotPhys.y = pScreen->height / 2;
32034642e01fSmrg        pSprite->hotLimits.x2 = pScreen->width;
32044642e01fSmrg        pSprite->hotLimits.y2 = pScreen->height;
32054642e01fSmrg    }
32064642e01fSmrg
32074642e01fSmrg    pSprite->hot = pSprite->hotPhys;
32084642e01fSmrg    pSprite->win = pWin;
32094642e01fSmrg
321035c4bbdfSmrg    if (pWin) {
321135c4bbdfSmrg        pCursor = wCursor(pWin);
321235c4bbdfSmrg        pSprite->spriteTrace = (WindowPtr *) calloc(1, 32 * sizeof(WindowPtr));
321335c4bbdfSmrg        if (!pSprite->spriteTrace)
321435c4bbdfSmrg            FatalError("Failed to allocate spriteTrace");
321535c4bbdfSmrg        pSprite->spriteTraceSize = 32;
32164642e01fSmrg
321735c4bbdfSmrg        RootWindow(pDev->spriteInfo->sprite) = pWin;
321835c4bbdfSmrg        pSprite->spriteTraceGood = 1;
32194642e01fSmrg
322035c4bbdfSmrg        pSprite->pEnqueueScreen = pScreen;
322135c4bbdfSmrg        pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
32224642e01fSmrg
322335c4bbdfSmrg    }
322435c4bbdfSmrg    else {
32256747b715Smrg        pCursor = NullCursor;
322635c4bbdfSmrg        pSprite->spriteTrace = NULL;
322735c4bbdfSmrg        pSprite->spriteTraceSize = 0;
322835c4bbdfSmrg        pSprite->spriteTraceGood = 0;
322935c4bbdfSmrg        pSprite->pEnqueueScreen = screenInfo.screens[0];
323035c4bbdfSmrg        pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
323135c4bbdfSmrg    }
323235c4bbdfSmrg    pCursor = RefCursor(pCursor);
32336747b715Smrg    if (pSprite->current)
323435c4bbdfSmrg        FreeCursor(pSprite->current, None);
32356747b715Smrg    pSprite->current = pCursor;
32364642e01fSmrg
323735c4bbdfSmrg    if (pScreen) {
323835c4bbdfSmrg        (*pScreen->RealizeCursor) (pDev, pScreen, pSprite->current);
323935c4bbdfSmrg        (*pScreen->CursorLimits) (pDev, pScreen, pSprite->current,
324035c4bbdfSmrg                                  &pSprite->hotLimits, &pSprite->physLimits);
32414642e01fSmrg        pSprite->confined = FALSE;
32424642e01fSmrg
324335c4bbdfSmrg        (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
32444642e01fSmrg        (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x,
324535c4bbdfSmrg                                       pSprite->hot.y, FALSE);
32464642e01fSmrg        (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
32474642e01fSmrg    }
324805b261ecSmrg#ifdef PANORAMIX
324935c4bbdfSmrg    if (!noPanoramiXExtension) {
32506747b715Smrg        pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
32516747b715Smrg        pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
325235c4bbdfSmrg        pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
32536747b715Smrg        pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
32544642e01fSmrg        pSprite->physLimits = pSprite->hotLimits;
32554642e01fSmrg        pSprite->confineWin = NullWindow;
32564642e01fSmrg        pSprite->hotShape = NullRegion;
32574642e01fSmrg        pSprite->screen = pScreen;
32584642e01fSmrg        /* gotta UNINIT these someplace */
32596747b715Smrg        RegionNull(&pSprite->Reg1);
32606747b715Smrg        RegionNull(&pSprite->Reg2);
32614642e01fSmrg    }
326205b261ecSmrg#endif
32634642e01fSmrg}
32644642e01fSmrg
326535c4bbdfSmrgvoid FreeSprite(DeviceIntPtr dev)
326635c4bbdfSmrg{
326735c4bbdfSmrg    if (DevHasCursor(dev) && dev->spriteInfo->sprite) {
326835c4bbdfSmrg        if (dev->spriteInfo->sprite->current)
326935c4bbdfSmrg            FreeCursor(dev->spriteInfo->sprite->current, None);
327035c4bbdfSmrg        free(dev->spriteInfo->sprite->spriteTrace);
327135c4bbdfSmrg        free(dev->spriteInfo->sprite);
327235c4bbdfSmrg    }
327335c4bbdfSmrg    dev->spriteInfo->sprite = NULL;
327435c4bbdfSmrg}
327535c4bbdfSmrg
327635c4bbdfSmrg
32774642e01fSmrg/**
32784642e01fSmrg * Update the mouse sprite info when the server switches from a pScreen to another.
32794642e01fSmrg * Otherwise, the pScreen of the mouse sprite is never updated when we switch
32804642e01fSmrg * from a pScreen to another. Never updating the pScreen of the mouse sprite
32814642e01fSmrg * implies that windows that are in pScreen whose pScreen->myNum >0 will never
32824642e01fSmrg * get pointer events. This is  because in CheckMotion(), sprite.hotPhys.pScreen
32834642e01fSmrg * always points to the first pScreen it has been set by
32844642e01fSmrg * DefineInitialRootWindow().
32854642e01fSmrg *
32864642e01fSmrg * Calling this function is useful for use cases where the server
32874642e01fSmrg * has more than one pScreen.
32884642e01fSmrg * This function is similar to DefineInitialRootWindow() but it does not
32894642e01fSmrg * reset the mouse pointer position.
32904642e01fSmrg * @param win must be the new pScreen we are switching to.
32914642e01fSmrg */
32924642e01fSmrgvoid
32934642e01fSmrgUpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen)
32944642e01fSmrg{
32954642e01fSmrg    SpritePtr pSprite = NULL;
32964642e01fSmrg    WindowPtr win = NULL;
32976747b715Smrg    CursorPtr pCursor;
329835c4bbdfSmrg
32994642e01fSmrg    if (!pScreen)
330035c4bbdfSmrg        return;
33014642e01fSmrg
33024642e01fSmrg    if (!pDev->spriteInfo->sprite)
33034642e01fSmrg        return;
33044642e01fSmrg
33054642e01fSmrg    pSprite = pDev->spriteInfo->sprite;
33064642e01fSmrg
33076747b715Smrg    win = pScreen->root;
33084642e01fSmrg
33094642e01fSmrg    pSprite->hotPhys.pScreen = pScreen;
33104642e01fSmrg    pSprite->hot = pSprite->hotPhys;
33114642e01fSmrg    pSprite->hotLimits.x2 = pScreen->width;
33124642e01fSmrg    pSprite->hotLimits.y2 = pScreen->height;
33134642e01fSmrg    pSprite->win = win;
331435c4bbdfSmrg    pCursor = RefCursor(wCursor(win));
33156747b715Smrg    if (pSprite->current)
331635c4bbdfSmrg        FreeCursor(pSprite->current, 0);
33176747b715Smrg    pSprite->current = pCursor;
33184642e01fSmrg    pSprite->spriteTraceGood = 1;
33194642e01fSmrg    pSprite->spriteTrace[0] = win;
33204642e01fSmrg    (*pScreen->CursorLimits) (pDev,
33214642e01fSmrg                              pScreen,
33224642e01fSmrg                              pSprite->current,
332335c4bbdfSmrg                              &pSprite->hotLimits, &pSprite->physLimits);
33244642e01fSmrg    pSprite->confined = FALSE;
33254642e01fSmrg    (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
33264642e01fSmrg    (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
33274642e01fSmrg
33284642e01fSmrg#ifdef PANORAMIX
332935c4bbdfSmrg    if (!noPanoramiXExtension) {
33306747b715Smrg        pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
33316747b715Smrg        pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
333235c4bbdfSmrg        pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
33336747b715Smrg        pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
33344642e01fSmrg        pSprite->physLimits = pSprite->hotLimits;
33354642e01fSmrg        pSprite->screen = pScreen;
333605b261ecSmrg    }
333705b261ecSmrg#endif
333805b261ecSmrg}
333905b261ecSmrg
334005b261ecSmrg/*
334105b261ecSmrg * This does not take any shortcuts, and even ignores its argument, since
334205b261ecSmrg * it does not happen very often, and one has to walk up the tree since
334305b261ecSmrg * this might be a newly instantiated cursor for an intermediate window
334405b261ecSmrg * between the one the pointer is in and the one that the last cursor was
334505b261ecSmrg * instantiated from.
334605b261ecSmrg */
334705b261ecSmrgvoid
334805b261ecSmrgWindowHasNewCursor(WindowPtr pWin)
334905b261ecSmrg{
33504642e01fSmrg    DeviceIntPtr pDev;
33514642e01fSmrg
335235c4bbdfSmrg    for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
33534642e01fSmrg        if (DevHasCursor(pDev))
33544642e01fSmrg            PostNewCursor(pDev);
335505b261ecSmrg}
335605b261ecSmrg
33576747b715Smrgvoid
33584642e01fSmrgNewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y)
335905b261ecSmrg{
336035c4bbdfSmrg    DeviceIntPtr ptr;
336135c4bbdfSmrg    SpritePtr pSprite;
336235c4bbdfSmrg
336335c4bbdfSmrg    ptr =
336435c4bbdfSmrg        IsFloating(pDev) ? pDev :
336535c4bbdfSmrg        GetXTestDevice(GetMaster(pDev, MASTER_POINTER));
336635c4bbdfSmrg    pSprite = ptr->spriteInfo->sprite;
33674642e01fSmrg
33684642e01fSmrg    pSprite->hotPhys.x = x;
33694642e01fSmrg    pSprite->hotPhys.y = y;
337005b261ecSmrg#ifdef PANORAMIX
337135c4bbdfSmrg    if (!noPanoramiXExtension) {
337235c4bbdfSmrg        pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x;
337335c4bbdfSmrg        pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y;
337435c4bbdfSmrg        if (newScreen != pSprite->screen) {
337535c4bbdfSmrg            pSprite->screen = newScreen;
337635c4bbdfSmrg            /* Make sure we tell the DDX to update its copy of the screen */
337735c4bbdfSmrg            if (pSprite->confineWin)
337835c4bbdfSmrg                XineramaConfineCursorToWindow(ptr, pSprite->confineWin, TRUE);
337935c4bbdfSmrg            else
338035c4bbdfSmrg                XineramaConfineCursorToWindow(ptr, screenInfo.screens[0]->root,
338135c4bbdfSmrg                                              TRUE);
338235c4bbdfSmrg            /* if the pointer wasn't confined, the DDX won't get
338335c4bbdfSmrg               told of the pointer warp so we reposition it here */
338435c4bbdfSmrg            if (!syncEvents.playingEvents)
338535c4bbdfSmrg                (*pSprite->screen->SetCursorPosition) (ptr,
338635c4bbdfSmrg                                                       pSprite->screen,
338735c4bbdfSmrg                                                       pSprite->hotPhys.x +
338835c4bbdfSmrg                                                       screenInfo.screens[0]->
338935c4bbdfSmrg                                                       x - pSprite->screen->x,
339035c4bbdfSmrg                                                       pSprite->hotPhys.y +
339135c4bbdfSmrg                                                       screenInfo.screens[0]->
339235c4bbdfSmrg                                                       y - pSprite->screen->y,
339335c4bbdfSmrg                                                       FALSE);
339435c4bbdfSmrg        }
339535c4bbdfSmrg    }
339635c4bbdfSmrg    else
339705b261ecSmrg#endif
33984642e01fSmrg    if (newScreen != pSprite->hotPhys.pScreen)
339935c4bbdfSmrg        ConfineCursorToWindow(ptr, newScreen->root, TRUE, FALSE);
340005b261ecSmrg}
340105b261ecSmrg
340205b261ecSmrg#ifdef PANORAMIX
340305b261ecSmrg
340405b261ecSmrgstatic Bool
340535c4bbdfSmrgXineramaPointInWindowIsVisible(WindowPtr pWin, int x, int y)
340605b261ecSmrg{
340705b261ecSmrg    BoxRec box;
340805b261ecSmrg    int i, xoff, yoff;
340905b261ecSmrg
341035c4bbdfSmrg    if (!pWin->realized)
341135c4bbdfSmrg        return FALSE;
341205b261ecSmrg
34136747b715Smrg    if (RegionContainsPoint(&pWin->borderClip, x, y, &box))
341405b261ecSmrg        return TRUE;
341505b261ecSmrg
341635c4bbdfSmrg    if (!XineramaSetWindowPntrs(inputInfo.pointer, pWin))
341735c4bbdfSmrg         return FALSE;
34184642e01fSmrg
34196747b715Smrg    xoff = x + screenInfo.screens[0]->x;
34206747b715Smrg    yoff = y + screenInfo.screens[0]->y;
342105b261ecSmrg
342235c4bbdfSmrg    FOR_NSCREENS_FORWARD_SKIP(i) {
342335c4bbdfSmrg        pWin = inputInfo.pointer->spriteInfo->sprite->windows[i];
342435c4bbdfSmrg
342535c4bbdfSmrg        x = xoff - screenInfo.screens[i]->x;
342635c4bbdfSmrg        y = yoff - screenInfo.screens[i]->y;
342705b261ecSmrg
342835c4bbdfSmrg        if (RegionContainsPoint(&pWin->borderClip, x, y, &box)
342935c4bbdfSmrg            && (!wInputShape(pWin) ||
343035c4bbdfSmrg                RegionContainsPoint(wInputShape(pWin),
343135c4bbdfSmrg                                    x - pWin->drawable.x,
343235c4bbdfSmrg                                    y - pWin->drawable.y, &box)))
343305b261ecSmrg            return TRUE;
343405b261ecSmrg
343505b261ecSmrg    }
343605b261ecSmrg
343705b261ecSmrg    return FALSE;
343805b261ecSmrg}
343905b261ecSmrg
344005b261ecSmrgstatic int
344105b261ecSmrgXineramaWarpPointer(ClientPtr client)
344205b261ecSmrg{
344335c4bbdfSmrg    WindowPtr dest = NULL;
344435c4bbdfSmrg    int x, y, rc;
344535c4bbdfSmrg    SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
344605b261ecSmrg
344705b261ecSmrg    REQUEST(xWarpPointerReq);
344805b261ecSmrg
344905b261ecSmrg    if (stuff->dstWid != None) {
345035c4bbdfSmrg        rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess);
345135c4bbdfSmrg        if (rc != Success)
345235c4bbdfSmrg            return rc;
345305b261ecSmrg    }
34544642e01fSmrg    x = pSprite->hotPhys.x;
34554642e01fSmrg    y = pSprite->hotPhys.y;
345605b261ecSmrg
345735c4bbdfSmrg    if (stuff->srcWid != None) {
345835c4bbdfSmrg        int winX, winY;
345935c4bbdfSmrg        XID winID = stuff->srcWid;
346005b261ecSmrg        WindowPtr source;
34614642e01fSmrg
346235c4bbdfSmrg        rc = dixLookupWindow(&source, winID, client, DixReadAccess);
346335c4bbdfSmrg        if (rc != Success)
346435c4bbdfSmrg            return rc;
346535c4bbdfSmrg
346635c4bbdfSmrg        winX = source->drawable.x;
346735c4bbdfSmrg        winY = source->drawable.y;
346835c4bbdfSmrg        if (source == screenInfo.screens[0]->root) {
346935c4bbdfSmrg            winX -= screenInfo.screens[0]->x;
347035c4bbdfSmrg            winY -= screenInfo.screens[0]->y;
347135c4bbdfSmrg        }
347235c4bbdfSmrg        if (x < winX + stuff->srcX ||
347335c4bbdfSmrg            y < winY + stuff->srcY ||
347435c4bbdfSmrg            (stuff->srcWidth != 0 &&
347535c4bbdfSmrg             winX + stuff->srcX + (int) stuff->srcWidth < x) ||
347635c4bbdfSmrg            (stuff->srcHeight != 0 &&
347735c4bbdfSmrg             winY + stuff->srcY + (int) stuff->srcHeight < y) ||
347835c4bbdfSmrg            !XineramaPointInWindowIsVisible(source, x, y))
347935c4bbdfSmrg            return Success;
348005b261ecSmrg    }
348105b261ecSmrg    if (dest) {
348235c4bbdfSmrg        x = dest->drawable.x;
348335c4bbdfSmrg        y = dest->drawable.y;
348435c4bbdfSmrg        if (dest == screenInfo.screens[0]->root) {
348535c4bbdfSmrg            x -= screenInfo.screens[0]->x;
348635c4bbdfSmrg            y -= screenInfo.screens[0]->y;
348735c4bbdfSmrg        }
34884642e01fSmrg    }
348905b261ecSmrg
349005b261ecSmrg    x += stuff->dstX;
349105b261ecSmrg    y += stuff->dstY;
349205b261ecSmrg
34934642e01fSmrg    if (x < pSprite->physLimits.x1)
349435c4bbdfSmrg        x = pSprite->physLimits.x1;
34954642e01fSmrg    else if (x >= pSprite->physLimits.x2)
349635c4bbdfSmrg        x = pSprite->physLimits.x2 - 1;
34974642e01fSmrg    if (y < pSprite->physLimits.y1)
349835c4bbdfSmrg        y = pSprite->physLimits.y1;
34994642e01fSmrg    else if (y >= pSprite->physLimits.y2)
350035c4bbdfSmrg        y = pSprite->physLimits.y2 - 1;
35014642e01fSmrg    if (pSprite->hotShape)
350235c4bbdfSmrg        ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y);
350305b261ecSmrg
35044642e01fSmrg    XineramaSetCursorPosition(PickPointer(client), x, y, TRUE);
350505b261ecSmrg
350605b261ecSmrg    return Success;
350705b261ecSmrg}
350805b261ecSmrg
350905b261ecSmrg#endif
351005b261ecSmrg
351105b261ecSmrg/**
351205b261ecSmrg * Server-side protocol handling for WarpPointer request.
351305b261ecSmrg * Warps the cursor position to the coordinates given in the request.
351405b261ecSmrg */
351505b261ecSmrgint
351605b261ecSmrgProcWarpPointer(ClientPtr client)
351705b261ecSmrg{
351835c4bbdfSmrg    WindowPtr dest = NULL;
351935c4bbdfSmrg    int x, y, rc;
352035c4bbdfSmrg    ScreenPtr newScreen;
35216747b715Smrg    DeviceIntPtr dev, tmp;
352235c4bbdfSmrg    SpritePtr pSprite;
352305b261ecSmrg
352405b261ecSmrg    REQUEST(xWarpPointerReq);
352505b261ecSmrg    REQUEST_SIZE_MATCH(xWarpPointerReq);
352605b261ecSmrg
35276747b715Smrg    dev = PickPointer(client);
35286747b715Smrg
35296747b715Smrg    for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
353035c4bbdfSmrg        if (GetMaster(tmp, MASTER_ATTACHED) == dev) {
353135c4bbdfSmrg            rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess);
353235c4bbdfSmrg            if (rc != Success)
353335c4bbdfSmrg                return rc;
353435c4bbdfSmrg        }
35354642e01fSmrg    }
35364642e01fSmrg
353735c4bbdfSmrg    if (dev->lastSlave)
353835c4bbdfSmrg        dev = dev->lastSlave;
35394642e01fSmrg    pSprite = dev->spriteInfo->sprite;
35404642e01fSmrg
354105b261ecSmrg#ifdef PANORAMIX
354235c4bbdfSmrg    if (!noPanoramiXExtension)
354335c4bbdfSmrg        return XineramaWarpPointer(client);
354405b261ecSmrg#endif
354505b261ecSmrg
354605b261ecSmrg    if (stuff->dstWid != None) {
354735c4bbdfSmrg        rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess);
354835c4bbdfSmrg        if (rc != Success)
354935c4bbdfSmrg            return rc;
355005b261ecSmrg    }
35514642e01fSmrg    x = pSprite->hotPhys.x;
35524642e01fSmrg    y = pSprite->hotPhys.y;
355305b261ecSmrg
355435c4bbdfSmrg    if (stuff->srcWid != None) {
355535c4bbdfSmrg        int winX, winY;
355635c4bbdfSmrg        XID winID = stuff->srcWid;
355705b261ecSmrg        WindowPtr source;
35584642e01fSmrg
355935c4bbdfSmrg        rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess);
356035c4bbdfSmrg        if (rc != Success)
356135c4bbdfSmrg            return rc;
356235c4bbdfSmrg
356335c4bbdfSmrg        winX = source->drawable.x;
356435c4bbdfSmrg        winY = source->drawable.y;
356535c4bbdfSmrg        if (source->drawable.pScreen != pSprite->hotPhys.pScreen ||
356635c4bbdfSmrg            x < winX + stuff->srcX ||
356735c4bbdfSmrg            y < winY + stuff->srcY ||
356835c4bbdfSmrg            (stuff->srcWidth != 0 &&
356935c4bbdfSmrg             winX + stuff->srcX + (int) stuff->srcWidth < x) ||
357035c4bbdfSmrg            (stuff->srcHeight != 0 &&
357135c4bbdfSmrg             winY + stuff->srcY + (int) stuff->srcHeight < y) ||
357235c4bbdfSmrg            !PointInWindowIsVisible(source, x, y))
357335c4bbdfSmrg            return Success;
357435c4bbdfSmrg    }
357535c4bbdfSmrg    if (dest) {
357635c4bbdfSmrg        x = dest->drawable.x;
357735c4bbdfSmrg        y = dest->drawable.y;
357835c4bbdfSmrg        newScreen = dest->drawable.pScreen;
357935c4bbdfSmrg    }
358035c4bbdfSmrg    else
358135c4bbdfSmrg        newScreen = pSprite->hotPhys.pScreen;
358205b261ecSmrg
358305b261ecSmrg    x += stuff->dstX;
358405b261ecSmrg    y += stuff->dstY;
358505b261ecSmrg
358605b261ecSmrg    if (x < 0)
358735c4bbdfSmrg        x = 0;
358805b261ecSmrg    else if (x >= newScreen->width)
358935c4bbdfSmrg        x = newScreen->width - 1;
359005b261ecSmrg    if (y < 0)
359135c4bbdfSmrg        y = 0;
359205b261ecSmrg    else if (y >= newScreen->height)
359335c4bbdfSmrg        y = newScreen->height - 1;
359435c4bbdfSmrg
359535c4bbdfSmrg    if (newScreen == pSprite->hotPhys.pScreen) {
359635c4bbdfSmrg        if (x < pSprite->physLimits.x1)
359735c4bbdfSmrg            x = pSprite->physLimits.x1;
359835c4bbdfSmrg        else if (x >= pSprite->physLimits.x2)
359935c4bbdfSmrg            x = pSprite->physLimits.x2 - 1;
360035c4bbdfSmrg        if (y < pSprite->physLimits.y1)
360135c4bbdfSmrg            y = pSprite->physLimits.y1;
360235c4bbdfSmrg        else if (y >= pSprite->physLimits.y2)
360335c4bbdfSmrg            y = pSprite->physLimits.y2 - 1;
360435c4bbdfSmrg        if (pSprite->hotShape)
360535c4bbdfSmrg            ConfineToShape(dev, pSprite->hotShape, &x, &y);
360635c4bbdfSmrg        (*newScreen->SetCursorPosition) (dev, newScreen, x, y, TRUE);
360735c4bbdfSmrg    }
360835c4bbdfSmrg    else if (!PointerConfinedToScreen(dev)) {
360935c4bbdfSmrg        NewCurrentScreen(dev, newScreen, x, y);
361005b261ecSmrg    }
361105b261ecSmrg    return Success;
361205b261ecSmrg}
361305b261ecSmrg
36144642e01fSmrgstatic Bool
36154642e01fSmrgBorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin)
361605b261ecSmrg{
361735c4bbdfSmrg    if (RegionNotEmpty(&pWin->borderSize))
361835c4bbdfSmrg        return TRUE;
361905b261ecSmrg
362005b261ecSmrg#ifdef PANORAMIX
362135c4bbdfSmrg    if (!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) {
362235c4bbdfSmrg        int i;
362335c4bbdfSmrg
362435c4bbdfSmrg        FOR_NSCREENS_FORWARD_SKIP(i) {
362535c4bbdfSmrg            if (RegionNotEmpty
362635c4bbdfSmrg                (&pDev->spriteInfo->sprite->windows[i]->borderSize))
362735c4bbdfSmrg                return TRUE;
362835c4bbdfSmrg        }
362935c4bbdfSmrg    }
363005b261ecSmrg#endif
363135c4bbdfSmrg    return FALSE;
363205b261ecSmrg}
363305b261ecSmrg
36344642e01fSmrg/**
363535c4bbdfSmrg * Activate the given passive grab. If the grab is activated successfully, the
363635c4bbdfSmrg * event has been delivered to the client.
36374642e01fSmrg *
363835c4bbdfSmrg * @param device The device of the event to check.
363935c4bbdfSmrg * @param grab The grab to check.
36406747b715Smrg * @param event The current device event.
364135c4bbdfSmrg * @param real_event The original event, in case of touch emulation. The
364235c4bbdfSmrg * real event is the one stored in the sync queue.
364335c4bbdfSmrg *
364435c4bbdfSmrg * @return Whether the grab has been activated.
364505b261ecSmrg */
364635c4bbdfSmrgBool
364735c4bbdfSmrgActivatePassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
364835c4bbdfSmrg                    InternalEvent *real_event)
364905b261ecSmrg{
36509ace9065Smrg    SpritePtr pSprite = device->spriteInfo->sprite;
365135c4bbdfSmrg    GrabInfoPtr grabinfo = &device->deviceGrab;
365235c4bbdfSmrg    xEvent *xE = NULL;
365335c4bbdfSmrg    int count;
365435c4bbdfSmrg    int rc;
36556747b715Smrg
365635c4bbdfSmrg    /* The only consumers of corestate are Xi 1.x and core events, which
365735c4bbdfSmrg     * are guaranteed to come from DeviceEvents. */
365835c4bbdfSmrg    if (grab->grabtype == XI || grab->grabtype == CORE) {
365935c4bbdfSmrg        DeviceIntPtr gdev;
366005b261ecSmrg
366135c4bbdfSmrg        event->device_event.corestate &= 0x1f00;
366235c4bbdfSmrg
366335c4bbdfSmrg        if (grab->grabtype == CORE)
366435c4bbdfSmrg            gdev = GetMaster(device, KEYBOARD_OR_FLOAT);
366535c4bbdfSmrg        else
366635c4bbdfSmrg            gdev = grab->modifierDevice;
366735c4bbdfSmrg
366835c4bbdfSmrg        if (gdev && gdev->key && gdev->key->xkbInfo)
366935c4bbdfSmrg            event->device_event.corestate |=
367035c4bbdfSmrg                gdev->key->xkbInfo->state.grab_mods & (~0x1f00);
367135c4bbdfSmrg    }
367235c4bbdfSmrg
367335c4bbdfSmrg    if (grab->grabtype == CORE) {
367435c4bbdfSmrg        rc = EventToCore(event, &xE, &count);
367535c4bbdfSmrg        if (rc != Success) {
367635c4bbdfSmrg            BUG_WARN_MSG(rc != BadMatch, "[dix] %s: core conversion failed"
367735c4bbdfSmrg                         "(%d, %d).\n", device->name, event->any.type, rc);
367835c4bbdfSmrg            return FALSE;
36794642e01fSmrg        }
368035c4bbdfSmrg    }
368135c4bbdfSmrg    else if (grab->grabtype == XI2) {
368235c4bbdfSmrg        rc = EventToXI2(event, &xE);
368335c4bbdfSmrg        if (rc != Success) {
368435c4bbdfSmrg            if (rc != BadMatch)
368535c4bbdfSmrg                BUG_WARN_MSG(rc != BadMatch, "[dix] %s: XI2 conversion failed"
368635c4bbdfSmrg                             "(%d, %d).\n", device->name, event->any.type, rc);
368735c4bbdfSmrg            return FALSE;
368835c4bbdfSmrg        }
368935c4bbdfSmrg        count = 1;
369035c4bbdfSmrg    }
369135c4bbdfSmrg    else {
369235c4bbdfSmrg        rc = EventToXI(event, &xE, &count);
369335c4bbdfSmrg        if (rc != Success) {
369435c4bbdfSmrg            if (rc != BadMatch)
369535c4bbdfSmrg                BUG_WARN_MSG(rc != BadMatch, "[dix] %s: XI conversion failed"
369635c4bbdfSmrg                             "(%d, %d).\n", device->name, event->any.type, rc);
369735c4bbdfSmrg            return FALSE;
369835c4bbdfSmrg        }
369935c4bbdfSmrg    }
37006747b715Smrg
370135c4bbdfSmrg    (*grabinfo->ActivateGrab) (device, grab,
370235c4bbdfSmrg                               ClientTimeToServerTime(event->any.time), TRUE);
37036747b715Smrg
370435c4bbdfSmrg    if (xE) {
370535c4bbdfSmrg        FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE);
37066747b715Smrg
370735c4bbdfSmrg        /* XXX: XACE? */
370835c4bbdfSmrg        TryClientEvents(rClient(grab), device, xE, count,
370935c4bbdfSmrg                        GetEventFilter(device, xE),
371035c4bbdfSmrg                        GetEventFilter(device, xE), grab);
371135c4bbdfSmrg    }
37126747b715Smrg
371335c4bbdfSmrg    if (grabinfo->sync.state == FROZEN_NO_EVENT)
371435c4bbdfSmrg        grabinfo->sync.state = FROZEN_WITH_EVENT;
371535c4bbdfSmrg    *grabinfo->sync.event = real_event->device_event;
37166747b715Smrg
371735c4bbdfSmrg    free(xE);
371835c4bbdfSmrg    return TRUE;
371935c4bbdfSmrg}
372035c4bbdfSmrg
372135c4bbdfSmrgstatic BOOL
372235c4bbdfSmrgCoreGrabInterferes(DeviceIntPtr device, GrabPtr grab)
372335c4bbdfSmrg{
372435c4bbdfSmrg    DeviceIntPtr other;
372535c4bbdfSmrg    BOOL interfering = FALSE;
372635c4bbdfSmrg
372735c4bbdfSmrg    for (other = inputInfo.devices; other; other = other->next) {
372835c4bbdfSmrg        GrabPtr othergrab = other->deviceGrab.grab;
372935c4bbdfSmrg
373035c4bbdfSmrg        if (othergrab && othergrab->grabtype == CORE &&
373135c4bbdfSmrg            SameClient(grab, rClient(othergrab)) &&
373235c4bbdfSmrg            ((IsPointerDevice(grab->device) &&
373335c4bbdfSmrg              IsPointerDevice(othergrab->device)) ||
373435c4bbdfSmrg             (IsKeyboardDevice(grab->device) &&
373535c4bbdfSmrg              IsKeyboardDevice(othergrab->device)))) {
373635c4bbdfSmrg            interfering = TRUE;
373735c4bbdfSmrg            break;
37386747b715Smrg        }
373935c4bbdfSmrg    }
37406747b715Smrg
374135c4bbdfSmrg    return interfering;
374235c4bbdfSmrg}
37434642e01fSmrg
374435c4bbdfSmrgenum MatchFlags {
374535c4bbdfSmrg    NO_MATCH = 0x0,
374635c4bbdfSmrg    CORE_MATCH = 0x1,
374735c4bbdfSmrg    XI_MATCH = 0x2,
374835c4bbdfSmrg    XI2_MATCH = 0x4,
374935c4bbdfSmrg};
37506747b715Smrg
375135c4bbdfSmrg/**
375235c4bbdfSmrg * Match the grab against the temporary grab on the given input level.
375335c4bbdfSmrg * Modifies the temporary grab pointer.
375435c4bbdfSmrg *
375535c4bbdfSmrg * @param grab The grab to match against
375635c4bbdfSmrg * @param tmp The temporary grab to use for matching
375735c4bbdfSmrg * @param level The input level we want to match on
375835c4bbdfSmrg * @param event_type Wire protocol event type
375935c4bbdfSmrg *
376035c4bbdfSmrg * @return The respective matched flag or 0 for no match
376135c4bbdfSmrg */
376235c4bbdfSmrgstatic enum MatchFlags
376335c4bbdfSmrgMatchForType(const GrabPtr grab, GrabPtr tmp, enum InputLevel level,
376435c4bbdfSmrg             int event_type)
376535c4bbdfSmrg{
376635c4bbdfSmrg    enum MatchFlags match;
376735c4bbdfSmrg    BOOL ignore_device = FALSE;
376835c4bbdfSmrg    int grabtype;
376935c4bbdfSmrg    int evtype;
37704642e01fSmrg
377135c4bbdfSmrg    switch (level) {
377235c4bbdfSmrg    case XI2:
377335c4bbdfSmrg        grabtype = XI2;
377435c4bbdfSmrg        evtype = GetXI2Type(event_type);
377535c4bbdfSmrg        BUG_WARN(!evtype);
377635c4bbdfSmrg        match = XI2_MATCH;
377735c4bbdfSmrg        break;
377835c4bbdfSmrg    case XI:
377935c4bbdfSmrg        grabtype = XI;
378035c4bbdfSmrg        evtype = GetXIType(event_type);
378135c4bbdfSmrg        match = XI_MATCH;
378235c4bbdfSmrg        break;
378335c4bbdfSmrg    case CORE:
378435c4bbdfSmrg        grabtype = CORE;
378535c4bbdfSmrg        evtype = GetCoreType(event_type);
378635c4bbdfSmrg        match = CORE_MATCH;
378735c4bbdfSmrg        ignore_device = TRUE;
378835c4bbdfSmrg        break;
378935c4bbdfSmrg    default:
379035c4bbdfSmrg        return NO_MATCH;
379135c4bbdfSmrg    }
379235c4bbdfSmrg
379335c4bbdfSmrg    tmp->grabtype = grabtype;
379435c4bbdfSmrg    tmp->type = evtype;
379535c4bbdfSmrg
379635c4bbdfSmrg    if (tmp->type && GrabMatchesSecond(tmp, grab, ignore_device))
379735c4bbdfSmrg        return match;
379835c4bbdfSmrg
379935c4bbdfSmrg    return NO_MATCH;
380035c4bbdfSmrg}
38014642e01fSmrg
380235c4bbdfSmrg/**
380335c4bbdfSmrg * Check an individual grab against an event to determine if a passive grab
380435c4bbdfSmrg * should be activated.
380535c4bbdfSmrg *
380635c4bbdfSmrg * @param device The device of the event to check.
380735c4bbdfSmrg * @param grab The grab to check.
380835c4bbdfSmrg * @param event The current device event.
380935c4bbdfSmrg * @param checkCore Check for core grabs too.
381035c4bbdfSmrg * @param tempGrab A pre-allocated temporary grab record for matching. This
381135c4bbdfSmrg *        must have the window and device values filled in.
381235c4bbdfSmrg *
381335c4bbdfSmrg * @return Whether the grab matches the event.
381435c4bbdfSmrg */
381535c4bbdfSmrgstatic Bool
381635c4bbdfSmrgCheckPassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
381735c4bbdfSmrg                 Bool checkCore, GrabPtr tempGrab)
381835c4bbdfSmrg{
381935c4bbdfSmrg    DeviceIntPtr gdev;
382035c4bbdfSmrg    XkbSrvInfoPtr xkbi = NULL;
382135c4bbdfSmrg    enum MatchFlags match = 0;
382235c4bbdfSmrg    int emulated_type = 0;
38236747b715Smrg
382435c4bbdfSmrg    gdev = grab->modifierDevice;
382535c4bbdfSmrg    if (grab->grabtype == CORE) {
382635c4bbdfSmrg        gdev = GetMaster(device, KEYBOARD_OR_FLOAT);
382735c4bbdfSmrg    }
382835c4bbdfSmrg    else if (grab->grabtype == XI2) {
382935c4bbdfSmrg        /* if the device is an attached slave device, gdev must be the
383035c4bbdfSmrg         * attached master keyboard. Since the slave may have been
383135c4bbdfSmrg         * reattached after the grab, the modifier device may not be the
383235c4bbdfSmrg         * same. */
383335c4bbdfSmrg        if (!IsMaster(grab->device) && !IsFloating(device))
383435c4bbdfSmrg            gdev = GetMaster(device, MASTER_KEYBOARD);
383535c4bbdfSmrg    }
38364642e01fSmrg
383735c4bbdfSmrg    if (gdev && gdev->key)
383835c4bbdfSmrg        xkbi = gdev->key->xkbInfo;
383935c4bbdfSmrg    tempGrab->modifierDevice = grab->modifierDevice;
384035c4bbdfSmrg    tempGrab->modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0;
384105b261ecSmrg
384235c4bbdfSmrg    /* Check for XI2 and XI grabs first */
384335c4bbdfSmrg    match = MatchForType(grab, tempGrab, XI2, event->any.type);
384405b261ecSmrg
384535c4bbdfSmrg    if (!match && IsTouchEvent(event) &&
384635c4bbdfSmrg        (event->device_event.flags & TOUCH_POINTER_EMULATED)) {
384735c4bbdfSmrg        emulated_type = TouchGetPointerEventType(event);
384835c4bbdfSmrg        match = MatchForType(grab, tempGrab, XI2, emulated_type);
384935c4bbdfSmrg    }
385035c4bbdfSmrg
385135c4bbdfSmrg    if (!match)
385235c4bbdfSmrg        match = MatchForType(grab, tempGrab, XI, event->any.type);
385335c4bbdfSmrg
385435c4bbdfSmrg    if (!match && emulated_type)
385535c4bbdfSmrg        match = MatchForType(grab, tempGrab, XI, emulated_type);
385635c4bbdfSmrg
385735c4bbdfSmrg    if (!match && checkCore) {
385835c4bbdfSmrg        match = MatchForType(grab, tempGrab, CORE, event->any.type);
385935c4bbdfSmrg        if (!match && emulated_type)
386035c4bbdfSmrg            match = MatchForType(grab, tempGrab, CORE, emulated_type);
386135c4bbdfSmrg    }
386235c4bbdfSmrg
386335c4bbdfSmrg    if (!match || (grab->confineTo &&
386435c4bbdfSmrg                   (!grab->confineTo->realized ||
386535c4bbdfSmrg                    !BorderSizeNotEmpty(device, grab->confineTo))))
386635c4bbdfSmrg        return FALSE;
386735c4bbdfSmrg
386835c4bbdfSmrg    /* In some cases a passive core grab may exist, but the client
386935c4bbdfSmrg     * already has a core grab on some other device. In this case we
387035c4bbdfSmrg     * must not get the grab, otherwise we may never ungrab the
387135c4bbdfSmrg     * device.
387235c4bbdfSmrg     */
387335c4bbdfSmrg
387435c4bbdfSmrg    if (grab->grabtype == CORE) {
387535c4bbdfSmrg        /* A passive grab may have been created for a different device
387635c4bbdfSmrg           than it is assigned to at this point in time.
387735c4bbdfSmrg           Update the grab's device and modifier device to reflect the
387835c4bbdfSmrg           current state.
387935c4bbdfSmrg           Since XGrabDeviceButton requires to specify the
388035c4bbdfSmrg           modifierDevice explicitly, we don't override this choice.
388135c4bbdfSmrg         */
388235c4bbdfSmrg        if (grab->type < GenericEvent) {
388335c4bbdfSmrg            grab->device = device;
388435c4bbdfSmrg            grab->modifierDevice = GetMaster(device, MASTER_KEYBOARD);
388535c4bbdfSmrg        }
388635c4bbdfSmrg
388735c4bbdfSmrg        if (CoreGrabInterferes(device, grab))
388835c4bbdfSmrg            return FALSE;
388935c4bbdfSmrg    }
389035c4bbdfSmrg
389135c4bbdfSmrg    return TRUE;
389235c4bbdfSmrg}
389335c4bbdfSmrg
389435c4bbdfSmrg/**
389535c4bbdfSmrg * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a
389635c4bbdfSmrg * passive grab set on the window to be activated.
389735c4bbdfSmrg * If activate is true and a passive grab is found, it will be activated,
389835c4bbdfSmrg * and the event will be delivered to the client.
389935c4bbdfSmrg *
390035c4bbdfSmrg * @param pWin The window that may be subject to a passive grab.
390135c4bbdfSmrg * @param device Device that caused the event.
390235c4bbdfSmrg * @param event The current device event.
390335c4bbdfSmrg * @param checkCore Check for core grabs too.
390435c4bbdfSmrg * @param activate If a grab is found, activate it and deliver the event.
390535c4bbdfSmrg */
390635c4bbdfSmrg
390735c4bbdfSmrgGrabPtr
390835c4bbdfSmrgCheckPassiveGrabsOnWindow(WindowPtr pWin,
390935c4bbdfSmrg                          DeviceIntPtr device,
391035c4bbdfSmrg                          InternalEvent *event, BOOL checkCore, BOOL activate)
391135c4bbdfSmrg{
391235c4bbdfSmrg    GrabPtr grab = wPassiveGrabs(pWin);
391335c4bbdfSmrg    GrabPtr tempGrab;
391435c4bbdfSmrg
391535c4bbdfSmrg    if (!grab)
391635c4bbdfSmrg        return NULL;
391735c4bbdfSmrg
391835c4bbdfSmrg    tempGrab = AllocGrab(NULL);
391935c4bbdfSmrg    if (tempGrab == NULL)
392035c4bbdfSmrg        return NULL;
392135c4bbdfSmrg
392235c4bbdfSmrg    /* Fill out the grab details, but leave the type for later before
392335c4bbdfSmrg     * comparing */
392435c4bbdfSmrg    switch (event->any.type) {
392535c4bbdfSmrg    case ET_KeyPress:
392635c4bbdfSmrg    case ET_KeyRelease:
392735c4bbdfSmrg        tempGrab->detail.exact = event->device_event.detail.key;
392835c4bbdfSmrg        break;
392935c4bbdfSmrg    case ET_ButtonPress:
393035c4bbdfSmrg    case ET_ButtonRelease:
393135c4bbdfSmrg    case ET_TouchBegin:
393235c4bbdfSmrg    case ET_TouchEnd:
393335c4bbdfSmrg        tempGrab->detail.exact = event->device_event.detail.button;
393435c4bbdfSmrg        break;
393535c4bbdfSmrg    default:
393635c4bbdfSmrg        tempGrab->detail.exact = 0;
393735c4bbdfSmrg        break;
393835c4bbdfSmrg    }
393935c4bbdfSmrg    tempGrab->window = pWin;
394035c4bbdfSmrg    tempGrab->device = device;
394135c4bbdfSmrg    tempGrab->detail.pMask = NULL;
394235c4bbdfSmrg    tempGrab->modifiersDetail.pMask = NULL;
394335c4bbdfSmrg    tempGrab->next = NULL;
394435c4bbdfSmrg
394535c4bbdfSmrg    for (; grab; grab = grab->next) {
394635c4bbdfSmrg        if (!CheckPassiveGrab(device, grab, event, checkCore, tempGrab))
394735c4bbdfSmrg            continue;
394835c4bbdfSmrg
394935c4bbdfSmrg        if (activate && !ActivatePassiveGrab(device, grab, event, event))
395035c4bbdfSmrg            continue;
39516747b715Smrg
395235c4bbdfSmrg        break;
395305b261ecSmrg    }
395435c4bbdfSmrg
395535c4bbdfSmrg    FreeGrab(tempGrab);
395635c4bbdfSmrg    return grab;
395705b261ecSmrg}
395805b261ecSmrg
395905b261ecSmrg/**
396005b261ecSmrg * CheckDeviceGrabs handles both keyboard and pointer events that may cause
39614642e01fSmrg * a passive grab to be activated.
396205b261ecSmrg *
396305b261ecSmrg * If the event is a keyboard event, the ancestors of the focus window are
396405b261ecSmrg * traced down and tried to see if they have any passive grabs to be
396505b261ecSmrg * activated.  If the focus window itself is reached and it's descendants
396605b261ecSmrg * contain the pointer, the ancestors of the window that the pointer is in
396705b261ecSmrg * are then traced down starting at the focus window, otherwise no grabs are
39684642e01fSmrg * activated.
396905b261ecSmrg * If the event is a pointer event, the ancestors of the window that the
397005b261ecSmrg * pointer is in are traced down starting at the root until CheckPassiveGrabs
397105b261ecSmrg * causes a passive grab to activate or all the windows are
397205b261ecSmrg * tried. PRH
397305b261ecSmrg *
397405b261ecSmrg * If a grab is activated, the event has been sent to the client already!
397505b261ecSmrg *
39764642e01fSmrg * The event we pass in must always be an XI event. From this, we then emulate
39774642e01fSmrg * the core event and then check for grabs.
39784642e01fSmrg *
397905b261ecSmrg * @param device The device that caused the event.
39804642e01fSmrg * @param xE The event to handle (Device{Button|Key}Press).
398105b261ecSmrg * @param count Number of events in list.
398205b261ecSmrg * @return TRUE if a grab has been activated or false otherwise.
398305b261ecSmrg*/
398405b261ecSmrg
398505b261ecSmrgBool
39869ace9065SmrgCheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
398705b261ecSmrg{
398805b261ecSmrg    int i;
398905b261ecSmrg    WindowPtr pWin = NULL;
399035c4bbdfSmrg    FocusClassPtr focus =
399135c4bbdfSmrg        IsPointerEvent((InternalEvent *) event) ? NULL : device->focus;
39926747b715Smrg    BOOL sendCore = (IsMaster(device) && device->coreEvents);
399335c4bbdfSmrg    Bool ret = FALSE;
399405b261ecSmrg
399535c4bbdfSmrg    if (event->type != ET_ButtonPress && event->type != ET_KeyPress)
39964642e01fSmrg        return FALSE;
39974642e01fSmrg
399835c4bbdfSmrg    if (event->type == ET_ButtonPress && (device->button->buttonsDown != 1))
399935c4bbdfSmrg        return FALSE;
40004642e01fSmrg
40019ace9065Smrg    if (device->deviceGrab.grab)
40029ace9065Smrg        return FALSE;
40039ace9065Smrg
40049ace9065Smrg    i = 0;
400535c4bbdfSmrg    if (ancestor) {
40069ace9065Smrg        while (i < device->spriteInfo->sprite->spriteTraceGood)
40079ace9065Smrg            if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor)
40089ace9065Smrg                break;
40099ace9065Smrg        if (i == device->spriteInfo->sprite->spriteTraceGood)
401035c4bbdfSmrg            goto out;
40119ace9065Smrg    }
401205b261ecSmrg
401335c4bbdfSmrg    if (focus) {
401435c4bbdfSmrg        for (; i < focus->traceGood; i++) {
401535c4bbdfSmrg            pWin = focus->trace[i];
401635c4bbdfSmrg            if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
401735c4bbdfSmrg                                          sendCore, TRUE)) {
401835c4bbdfSmrg                ret = TRUE;
401935c4bbdfSmrg                goto out;
402035c4bbdfSmrg            }
402135c4bbdfSmrg        }
40224642e01fSmrg
402335c4bbdfSmrg        if ((focus->win == NoneWin) ||
402435c4bbdfSmrg            (i >= device->spriteInfo->sprite->spriteTraceGood) ||
402535c4bbdfSmrg            (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i - 1]))
402635c4bbdfSmrg            goto out;
402705b261ecSmrg    }
402805b261ecSmrg
402935c4bbdfSmrg    for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) {
403035c4bbdfSmrg        pWin = device->spriteInfo->sprite->spriteTrace[i];
403135c4bbdfSmrg        if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
403235c4bbdfSmrg                                      sendCore, TRUE)) {
403335c4bbdfSmrg            ret = TRUE;
403435c4bbdfSmrg            goto out;
403535c4bbdfSmrg        }
403605b261ecSmrg    }
403705b261ecSmrg
403835c4bbdfSmrg out:
403935c4bbdfSmrg    if (ret == TRUE && event->type == ET_KeyPress)
404035c4bbdfSmrg        device->deviceGrab.activatingKey = event->detail.key;
404135c4bbdfSmrg    return ret;
404205b261ecSmrg}
404305b261ecSmrg
404405b261ecSmrg/**
404505b261ecSmrg * Called for keyboard events to deliver event to whatever client owns the
40466747b715Smrg * focus.
40476747b715Smrg *
40486747b715Smrg * The event is delivered to the keyboard's focus window, the root window or
40496747b715Smrg * to the window owning the input focus.
405005b261ecSmrg *
405105b261ecSmrg * @param keybd The keyboard originating the event.
40526747b715Smrg * @param event The event, not yet in wire format.
405305b261ecSmrg * @param window Window underneath the sprite.
405405b261ecSmrg */
405505b261ecSmrgvoid
40566747b715SmrgDeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window)
405705b261ecSmrg{
40586747b715Smrg    DeviceIntPtr ptr;
405905b261ecSmrg    WindowPtr focus = keybd->focus->win;
40606747b715Smrg    BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents);
406135c4bbdfSmrg    xEvent *core = NULL, *xE = NULL, *xi2 = NULL;
40626747b715Smrg    int count, rc;
40634642e01fSmrg    int deliveries = 0;
406405b261ecSmrg
406505b261ecSmrg    if (focus == FollowKeyboardWin)
406635c4bbdfSmrg        focus = inputInfo.keyboard->focus->win;
406705b261ecSmrg    if (!focus)
406835c4bbdfSmrg        return;
406935c4bbdfSmrg    if (focus == PointerRootWin) {
407035c4bbdfSmrg        DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd);
407135c4bbdfSmrg        return;
407205b261ecSmrg    }
407335c4bbdfSmrg    if ((focus == window) || IsParent(focus, window)) {
407435c4bbdfSmrg        if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd))
407535c4bbdfSmrg            return;
407605b261ecSmrg    }
40774642e01fSmrg
407805b261ecSmrg    /* just deliver it to the focus window */
407935c4bbdfSmrg    ptr = GetMaster(keybd, POINTER_OR_FLOAT);
40806747b715Smrg
40816747b715Smrg    rc = EventToXI2(event, &xi2);
408235c4bbdfSmrg    if (rc == Success) {
40836747b715Smrg        /* XXX: XACE */
40846747b715Smrg        int filter = GetEventFilter(keybd, xi2);
408535c4bbdfSmrg
40869ace9065Smrg        FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE);
40876747b715Smrg        deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1,
40886747b715Smrg                                           filter, NullGrab);
40896747b715Smrg        if (deliveries > 0)
40906747b715Smrg            goto unwind;
409135c4bbdfSmrg    }
409235c4bbdfSmrg    else if (rc != BadMatch)
409335c4bbdfSmrg        ErrorF
409435c4bbdfSmrg            ("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n",
409535c4bbdfSmrg             keybd->name, event->any.type, rc);
40966747b715Smrg
40976747b715Smrg    rc = EventToXI(event, &xE, &count);
40986747b715Smrg    if (rc == Success &&
409935c4bbdfSmrg        XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) {
41009ace9065Smrg        FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE);
41016747b715Smrg        deliveries = DeliverEventsToWindow(keybd, focus, xE, count,
410235c4bbdfSmrg                                           GetEventFilter(keybd, xE), NullGrab);
41036747b715Smrg
41046747b715Smrg        if (deliveries > 0)
41056747b715Smrg            goto unwind;
410635c4bbdfSmrg    }
410735c4bbdfSmrg    else if (rc != BadMatch)
410835c4bbdfSmrg        ErrorF
410935c4bbdfSmrg            ("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n",
411035c4bbdfSmrg             keybd->name, event->any.type, rc);
41114642e01fSmrg
411235c4bbdfSmrg    if (sendCore) {
411335c4bbdfSmrg        rc = EventToCore(event, &core, &count);
41146747b715Smrg        if (rc == Success) {
411535c4bbdfSmrg            if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, core, count) ==
411635c4bbdfSmrg                Success) {
411735c4bbdfSmrg                FixUpEventFromWindow(keybd->spriteInfo->sprite, core, focus,
41189ace9065Smrg                                     None, FALSE);
411935c4bbdfSmrg                deliveries =
412035c4bbdfSmrg                    DeliverEventsToWindow(keybd, focus, core, count,
412135c4bbdfSmrg                                          GetEventFilter(keybd, core),
412235c4bbdfSmrg                                          NullGrab);
41236747b715Smrg            }
412435c4bbdfSmrg        }
412535c4bbdfSmrg        else if (rc != BadMatch)
412635c4bbdfSmrg            ErrorF
412735c4bbdfSmrg                ("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n",
412835c4bbdfSmrg                 keybd->name, event->any.type, rc);
41294642e01fSmrg    }
41306747b715Smrg
413135c4bbdfSmrg unwind:
413235c4bbdfSmrg    free(core);
41336747b715Smrg    free(xE);
41346747b715Smrg    free(xi2);
41356747b715Smrg    return;
413605b261ecSmrg}
413705b261ecSmrg
413835c4bbdfSmrgint
413935c4bbdfSmrgDeliverOneGrabbedEvent(InternalEvent *event, DeviceIntPtr dev,
414035c4bbdfSmrg                       enum InputLevel level)
414135c4bbdfSmrg{
414235c4bbdfSmrg    SpritePtr pSprite = dev->spriteInfo->sprite;
414335c4bbdfSmrg    int rc;
414435c4bbdfSmrg    xEvent *xE = NULL;
414535c4bbdfSmrg    int count = 0;
414635c4bbdfSmrg    int deliveries = 0;
414735c4bbdfSmrg    Mask mask;
414835c4bbdfSmrg    GrabInfoPtr grabinfo = &dev->deviceGrab;
414935c4bbdfSmrg    GrabPtr grab = grabinfo->grab;
415035c4bbdfSmrg    Mask filter;
415135c4bbdfSmrg
415235c4bbdfSmrg    if (grab->grabtype != level)
415335c4bbdfSmrg        return 0;
415435c4bbdfSmrg
415535c4bbdfSmrg    switch (level) {
415635c4bbdfSmrg    case XI2:
415735c4bbdfSmrg        rc = EventToXI2(event, &xE);
415835c4bbdfSmrg        count = 1;
415935c4bbdfSmrg        if (rc == Success) {
416035c4bbdfSmrg            int evtype = xi2_get_type(xE);
416135c4bbdfSmrg
416235c4bbdfSmrg            mask = GetXI2MaskByte(grab->xi2mask, dev, evtype);
416335c4bbdfSmrg            filter = GetEventFilter(dev, xE);
416435c4bbdfSmrg        }
416535c4bbdfSmrg        break;
416635c4bbdfSmrg    case XI:
416735c4bbdfSmrg        if (grabinfo->fromPassiveGrab && grabinfo->implicitGrab)
416835c4bbdfSmrg            mask = grab->deviceMask;
416935c4bbdfSmrg        else
417035c4bbdfSmrg            mask = grab->eventMask;
417135c4bbdfSmrg        rc = EventToXI(event, &xE, &count);
417235c4bbdfSmrg        if (rc == Success)
417335c4bbdfSmrg            filter = GetEventFilter(dev, xE);
417435c4bbdfSmrg        break;
417535c4bbdfSmrg    case CORE:
417635c4bbdfSmrg        rc = EventToCore(event, &xE, &count);
417735c4bbdfSmrg        mask = grab->eventMask;
417835c4bbdfSmrg        if (rc == Success)
417935c4bbdfSmrg            filter = GetEventFilter(dev, xE);
418035c4bbdfSmrg        break;
418135c4bbdfSmrg    default:
418235c4bbdfSmrg        BUG_WARN_MSG(1, "Invalid input level %d\n", level);
418335c4bbdfSmrg        return 0;
418435c4bbdfSmrg    }
418535c4bbdfSmrg
418635c4bbdfSmrg    if (rc == Success) {
418735c4bbdfSmrg        FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE);
418835c4bbdfSmrg        if (XaceHook(XACE_SEND_ACCESS, 0, dev,
418935c4bbdfSmrg                     grab->window, xE, count) ||
419035c4bbdfSmrg            XaceHook(XACE_RECEIVE_ACCESS, rClient(grab),
419135c4bbdfSmrg                     grab->window, xE, count))
419235c4bbdfSmrg            deliveries = 1;     /* don't send, but pretend we did */
419335c4bbdfSmrg        else if (level != CORE || !IsInterferingGrab(rClient(grab), dev, xE)) {
419435c4bbdfSmrg            deliveries = TryClientEvents(rClient(grab), dev,
419535c4bbdfSmrg                                         xE, count, mask, filter, grab);
419635c4bbdfSmrg        }
419735c4bbdfSmrg    }
419835c4bbdfSmrg    else
419935c4bbdfSmrg        BUG_WARN_MSG(rc != BadMatch,
420035c4bbdfSmrg                     "%s: conversion to mode %d failed on %d with %d\n",
420135c4bbdfSmrg                     dev->name, level, event->any.type, rc);
420235c4bbdfSmrg
420335c4bbdfSmrg    free(xE);
420435c4bbdfSmrg    return deliveries;
420535c4bbdfSmrg}
420635c4bbdfSmrg
420705b261ecSmrg/**
420805b261ecSmrg * Deliver an event from a device that is currently grabbed. Uses
420905b261ecSmrg * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the
421005b261ecSmrg * grab. If not, TryClientEvents() is used.
421105b261ecSmrg *
421205b261ecSmrg * @param deactivateGrab True if the device's grab should be deactivated.
421335c4bbdfSmrg *
421435c4bbdfSmrg * @return The number of events delivered.
421505b261ecSmrg */
421635c4bbdfSmrgint
42176747b715SmrgDeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev,
42186747b715Smrg                    Bool deactivateGrab)
421905b261ecSmrg{
42204642e01fSmrg    GrabPtr grab;
42214642e01fSmrg    GrabInfoPtr grabinfo;
422205b261ecSmrg    int deliveries = 0;
422305b261ecSmrg    DeviceIntPtr dev;
42244642e01fSmrg    SpritePtr pSprite = thisDev->spriteInfo->sprite;
42254642e01fSmrg    BOOL sendCore = FALSE;
42264642e01fSmrg
42274642e01fSmrg    grabinfo = &thisDev->deviceGrab;
42284642e01fSmrg    grab = grabinfo->grab;
422905b261ecSmrg
423035c4bbdfSmrg    if (grab->ownerEvents) {
423135c4bbdfSmrg        WindowPtr focus;
423205b261ecSmrg
42334642e01fSmrg        /* Hack: Some pointer device have a focus class. So we need to check
42344642e01fSmrg         * for the type of event, to see if we really want to deliver it to
42354642e01fSmrg         * the focus window. For pointer events, the answer is no.
42364642e01fSmrg         */
42376747b715Smrg        if (IsPointerEvent(event))
42384642e01fSmrg            focus = PointerRootWin;
423935c4bbdfSmrg        else if (thisDev->focus) {
424035c4bbdfSmrg            focus = thisDev->focus->win;
424135c4bbdfSmrg            if (focus == FollowKeyboardWin)
424235c4bbdfSmrg                focus = inputInfo.keyboard->focus->win;
424335c4bbdfSmrg        }
424435c4bbdfSmrg        else
424535c4bbdfSmrg            focus = PointerRootWin;
424635c4bbdfSmrg        if (focus == PointerRootWin)
424735c4bbdfSmrg            deliveries = DeliverDeviceEvents(pSprite->win, event, grab,
42486747b715Smrg                                             NullWindow, thisDev);
424935c4bbdfSmrg        else if (focus && (focus == pSprite->win ||
425035c4bbdfSmrg                           IsParent(focus, pSprite->win)))
425135c4bbdfSmrg            deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus,
425235c4bbdfSmrg                                             thisDev);
425335c4bbdfSmrg        else if (focus)
425435c4bbdfSmrg            deliveries = DeliverDeviceEvents(focus, event, grab, focus,
425535c4bbdfSmrg                                             thisDev);
425635c4bbdfSmrg    }
425735c4bbdfSmrg    if (!deliveries) {
42586747b715Smrg        sendCore = (IsMaster(thisDev) && thisDev->coreEvents);
42596747b715Smrg        /* try core event */
426035c4bbdfSmrg        if ((sendCore && grab->grabtype == CORE) || grab->grabtype != CORE)
426135c4bbdfSmrg            deliveries = DeliverOneGrabbedEvent(event, thisDev, grab->grabtype);
42626747b715Smrg
42636747b715Smrg        if (deliveries && (event->any.type == ET_Motion))
42644642e01fSmrg            thisDev->valuator->motionHintWindow = grab->window;
426505b261ecSmrg    }
426635c4bbdfSmrg    if (deliveries && !deactivateGrab &&
426735c4bbdfSmrg        (event->any.type == ET_KeyPress ||
426835c4bbdfSmrg         event->any.type == ET_KeyRelease ||
426935c4bbdfSmrg         event->any.type == ET_ButtonPress ||
427035c4bbdfSmrg         event->any.type == ET_ButtonRelease)) {
427135c4bbdfSmrg        switch (grabinfo->sync.state) {
427235c4bbdfSmrg        case FREEZE_BOTH_NEXT_EVENT:
427335c4bbdfSmrg            dev = GetPairedDevice(thisDev);
427435c4bbdfSmrg            if (dev) {
427535c4bbdfSmrg                FreezeThaw(dev, TRUE);
427635c4bbdfSmrg                if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) &&
427735c4bbdfSmrg                    (CLIENT_BITS(grab->resource) ==
427835c4bbdfSmrg                     CLIENT_BITS(dev->deviceGrab.grab->resource)))
427935c4bbdfSmrg                    dev->deviceGrab.sync.state = FROZEN_NO_EVENT;
428035c4bbdfSmrg                else
42816747b715Smrg                    dev->deviceGrab.sync.other = grab;
428235c4bbdfSmrg            }
428335c4bbdfSmrg            /* fall through */
428435c4bbdfSmrg        case FREEZE_NEXT_EVENT:
428535c4bbdfSmrg            grabinfo->sync.state = FROZEN_WITH_EVENT;
428635c4bbdfSmrg            FreezeThaw(thisDev, TRUE);
428735c4bbdfSmrg            *grabinfo->sync.event = event->device_event;
428835c4bbdfSmrg            break;
428935c4bbdfSmrg        }
429005b261ecSmrg    }
429105b261ecSmrg
429235c4bbdfSmrg    return deliveries;
42936747b715Smrg}
429405b261ecSmrg
42956747b715Smrg/* This function is used to set the key pressed or key released state -
42966747b715Smrg   this is only used when the pressing of keys does not cause
42976747b715Smrg   the device's processInputProc to be called, as in for example Mouse Keys.
42986747b715Smrg*/
42996747b715Smrgvoid
430035c4bbdfSmrgFixKeyState(DeviceEvent *event, DeviceIntPtr keybd)
43016747b715Smrg{
43026747b715Smrg    int key = event->detail.key;
43036747b715Smrg
43046747b715Smrg    if (event->type == ET_KeyPress) {
430535c4bbdfSmrg        DebugF("FixKeyState: Key %d %s\n", key,
43066747b715Smrg               ((event->type == ET_KeyPress) ? "down" : "up"));
430705b261ecSmrg    }
43084642e01fSmrg
43096747b715Smrg    if (event->type == ET_KeyPress)
43106747b715Smrg        set_key_down(keybd, key, KEY_PROCESSED);
43116747b715Smrg    else if (event->type == ET_KeyRelease)
43126747b715Smrg        set_key_up(keybd, key, KEY_PROCESSED);
431305b261ecSmrg    else
43146747b715Smrg        FatalError("Impossible keyboard event");
431505b261ecSmrg}
431605b261ecSmrg
431705b261ecSmrg#define AtMostOneClient \
431805b261ecSmrg	(SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask)
43194642e01fSmrg#define ManagerMask \
43204642e01fSmrg	(SubstructureRedirectMask | ResizeRedirectMask)
432105b261ecSmrg
432205b261ecSmrg/**
432305b261ecSmrg * Recalculate which events may be deliverable for the given window.
432405b261ecSmrg * Recalculated mask is used for quicker determination which events may be
432505b261ecSmrg * delivered to a window.
432605b261ecSmrg *
432705b261ecSmrg * The otherEventMasks on a WindowOptional is the combination of all event
432805b261ecSmrg * masks set by all clients on the window.
432905b261ecSmrg * deliverableEventMask is the combination of the eventMask and the
43306747b715Smrg * otherEventMask plus the events that may be propagated to the parent.
433105b261ecSmrg *
433205b261ecSmrg * Traverses to siblings and parents of the window.
433305b261ecSmrg */
433405b261ecSmrgvoid
43356747b715SmrgRecalculateDeliverableEvents(WindowPtr pWin)
433605b261ecSmrg{
433705b261ecSmrg    OtherClients *others;
433805b261ecSmrg    WindowPtr pChild;
433905b261ecSmrg
434005b261ecSmrg    pChild = pWin;
434135c4bbdfSmrg    while (1) {
434235c4bbdfSmrg        if (pChild->optional) {
434335c4bbdfSmrg            pChild->optional->otherEventMasks = 0;
434435c4bbdfSmrg            for (others = wOtherClients(pChild); others; others = others->next) {
434535c4bbdfSmrg                pChild->optional->otherEventMasks |= others->mask;
434635c4bbdfSmrg            }
434735c4bbdfSmrg        }
434835c4bbdfSmrg        pChild->deliverableEvents = pChild->eventMask |
434935c4bbdfSmrg            wOtherEventMasks(pChild);
435035c4bbdfSmrg        if (pChild->parent)
435135c4bbdfSmrg            pChild->deliverableEvents |=
435235c4bbdfSmrg                (pChild->parent->deliverableEvents &
435335c4bbdfSmrg                 ~wDontPropagateMask(pChild) & PropagateMask);
435435c4bbdfSmrg        if (pChild->firstChild) {
435535c4bbdfSmrg            pChild = pChild->firstChild;
435635c4bbdfSmrg            continue;
435735c4bbdfSmrg        }
435835c4bbdfSmrg        while (!pChild->nextSib && (pChild != pWin))
435935c4bbdfSmrg            pChild = pChild->parent;
436035c4bbdfSmrg        if (pChild == pWin)
436135c4bbdfSmrg            break;
436235c4bbdfSmrg        pChild = pChild->nextSib;
436305b261ecSmrg    }
436405b261ecSmrg}
436505b261ecSmrg
436605b261ecSmrg/**
436705b261ecSmrg *
436805b261ecSmrg *  \param value must conform to DeleteType
436905b261ecSmrg */
437005b261ecSmrgint
437135c4bbdfSmrgOtherClientGone(void *value, XID id)
437205b261ecSmrg{
437305b261ecSmrg    OtherClientsPtr other, prev;
437435c4bbdfSmrg    WindowPtr pWin = (WindowPtr) value;
437505b261ecSmrg
437605b261ecSmrg    prev = 0;
437735c4bbdfSmrg    for (other = wOtherClients(pWin); other; other = other->next) {
437835c4bbdfSmrg        if (other->resource == id) {
437935c4bbdfSmrg            if (prev)
438035c4bbdfSmrg                prev->next = other->next;
438135c4bbdfSmrg            else {
438235c4bbdfSmrg                if (!(pWin->optional->otherClients = other->next))
438335c4bbdfSmrg                    CheckWindowOptionalNeed(pWin);
438435c4bbdfSmrg            }
438535c4bbdfSmrg            free(other);
438635c4bbdfSmrg            RecalculateDeliverableEvents(pWin);
438735c4bbdfSmrg            return Success;
438835c4bbdfSmrg        }
438935c4bbdfSmrg        prev = other;
439005b261ecSmrg    }
439105b261ecSmrg    FatalError("client not on event list");
439205b261ecSmrg}
439305b261ecSmrg
439405b261ecSmrgint
439505b261ecSmrgEventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask)
439605b261ecSmrg{
439705b261ecSmrg    Mask check;
439835c4bbdfSmrg    OtherClients *others;
43994642e01fSmrg    DeviceIntPtr dev;
44004642e01fSmrg    int rc;
440105b261ecSmrg
440235c4bbdfSmrg    if (mask & ~AllEventMasks) {
440335c4bbdfSmrg        client->errorValue = mask;
440435c4bbdfSmrg        return BadValue;
440505b261ecSmrg    }
44064642e01fSmrg    check = (mask & ManagerMask);
44074642e01fSmrg    if (check) {
440835c4bbdfSmrg        rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
440935c4bbdfSmrg                      RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess);
441035c4bbdfSmrg        if (rc != Success)
441135c4bbdfSmrg            return rc;
44124642e01fSmrg    }
441305b261ecSmrg    check = (mask & AtMostOneClient);
441435c4bbdfSmrg    if (check & (pWin->eventMask | wOtherEventMasks(pWin))) {
441535c4bbdfSmrg        /* It is illegal for two different clients to select on any of the
441635c4bbdfSmrg           events for AtMostOneClient. However, it is OK, for some client to
441735c4bbdfSmrg           continue selecting on one of those events.  */
441835c4bbdfSmrg        if ((wClient(pWin) != client) && (check & pWin->eventMask))
441935c4bbdfSmrg            return BadAccess;
442035c4bbdfSmrg        for (others = wOtherClients(pWin); others; others = others->next) {
442135c4bbdfSmrg            if (!SameClient(others, client) && (check & others->mask))
442235c4bbdfSmrg                return BadAccess;
442335c4bbdfSmrg        }
442405b261ecSmrg    }
442535c4bbdfSmrg    if (wClient(pWin) == client) {
442635c4bbdfSmrg        check = pWin->eventMask;
442735c4bbdfSmrg        pWin->eventMask = mask;
442835c4bbdfSmrg    }
442935c4bbdfSmrg    else {
443035c4bbdfSmrg        for (others = wOtherClients(pWin); others; others = others->next) {
443135c4bbdfSmrg            if (SameClient(others, client)) {
443235c4bbdfSmrg                check = others->mask;
443335c4bbdfSmrg                if (mask == 0) {
443435c4bbdfSmrg                    FreeResource(others->resource, RT_NONE);
443535c4bbdfSmrg                    return Success;
443635c4bbdfSmrg                }
443735c4bbdfSmrg                else
443835c4bbdfSmrg                    others->mask = mask;
443935c4bbdfSmrg                goto maskSet;
444035c4bbdfSmrg            }
444135c4bbdfSmrg        }
444235c4bbdfSmrg        check = 0;
444335c4bbdfSmrg        if (!pWin->optional && !MakeWindowOptional(pWin))
444435c4bbdfSmrg            return BadAlloc;
444535c4bbdfSmrg        others = malloc(sizeof(OtherClients));
444635c4bbdfSmrg        if (!others)
444735c4bbdfSmrg            return BadAlloc;
444835c4bbdfSmrg        others->mask = mask;
444935c4bbdfSmrg        others->resource = FakeClientID(client->index);
445035c4bbdfSmrg        others->next = pWin->optional->otherClients;
445135c4bbdfSmrg        pWin->optional->otherClients = others;
445235c4bbdfSmrg        if (!AddResource(others->resource, RT_OTHERCLIENT, (void *) pWin))
445335c4bbdfSmrg            return BadAlloc;
445435c4bbdfSmrg    }
445535c4bbdfSmrg maskSet:
445635c4bbdfSmrg    if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) {
445735c4bbdfSmrg        for (dev = inputInfo.devices; dev; dev = dev->next) {
44584642e01fSmrg            if (dev->valuator && dev->valuator->motionHintWindow == pWin)
44594642e01fSmrg                dev->valuator->motionHintWindow = NullWindow;
44604642e01fSmrg        }
44614642e01fSmrg    }
446205b261ecSmrg    RecalculateDeliverableEvents(pWin);
446305b261ecSmrg    return Success;
446405b261ecSmrg}
446505b261ecSmrg
446605b261ecSmrgint
44674642e01fSmrgEventSuppressForWindow(WindowPtr pWin, ClientPtr client,
446805b261ecSmrg                       Mask mask, Bool *checkOptional)
446905b261ecSmrg{
447035c4bbdfSmrg    int i, freed;
447105b261ecSmrg
447235c4bbdfSmrg    if (mask & ~PropagateMask) {
447335c4bbdfSmrg        client->errorValue = mask;
447435c4bbdfSmrg        return BadValue;
447505b261ecSmrg    }
447605b261ecSmrg    if (pWin->dontPropagate)
447735c4bbdfSmrg        DontPropagateRefCnts[pWin->dontPropagate]--;
447805b261ecSmrg    if (!mask)
447935c4bbdfSmrg        i = 0;
448035c4bbdfSmrg    else {
448135c4bbdfSmrg        for (i = DNPMCOUNT, freed = 0; --i > 0;) {
448235c4bbdfSmrg            if (!DontPropagateRefCnts[i])
448335c4bbdfSmrg                freed = i;
448435c4bbdfSmrg            else if (mask == DontPropagateMasks[i])
448535c4bbdfSmrg                break;
448635c4bbdfSmrg        }
448735c4bbdfSmrg        if (!i && freed) {
448835c4bbdfSmrg            i = freed;
448935c4bbdfSmrg            DontPropagateMasks[i] = mask;
449035c4bbdfSmrg        }
449105b261ecSmrg    }
449235c4bbdfSmrg    if (i || !mask) {
449335c4bbdfSmrg        pWin->dontPropagate = i;
449435c4bbdfSmrg        if (i)
449535c4bbdfSmrg            DontPropagateRefCnts[i]++;
449635c4bbdfSmrg        if (pWin->optional) {
449735c4bbdfSmrg            pWin->optional->dontPropagateMask = mask;
449835c4bbdfSmrg            *checkOptional = TRUE;
449935c4bbdfSmrg        }
450035c4bbdfSmrg    }
450135c4bbdfSmrg    else {
450235c4bbdfSmrg        if (!pWin->optional && !MakeWindowOptional(pWin)) {
450335c4bbdfSmrg            if (pWin->dontPropagate)
450435c4bbdfSmrg                DontPropagateRefCnts[pWin->dontPropagate]++;
450535c4bbdfSmrg            return BadAlloc;
450635c4bbdfSmrg        }
450735c4bbdfSmrg        pWin->dontPropagate = 0;
450805b261ecSmrg        pWin->optional->dontPropagateMask = mask;
450905b261ecSmrg    }
451005b261ecSmrg    RecalculateDeliverableEvents(pWin);
451105b261ecSmrg    return Success;
451205b261ecSmrg}
451305b261ecSmrg
451405b261ecSmrg/**
45154642e01fSmrg * Assembles an EnterNotify or LeaveNotify and sends it event to the client.
45164642e01fSmrg * Uses the paired keyboard to get some additional information.
451705b261ecSmrg */
45184642e01fSmrgvoid
451935c4bbdfSmrgCoreEnterLeaveEvent(DeviceIntPtr mouse,
452035c4bbdfSmrg                    int type,
452135c4bbdfSmrg                    int mode, int detail, WindowPtr pWin, Window child)
452235c4bbdfSmrg{
452335c4bbdfSmrg    xEvent event = {
452435c4bbdfSmrg        .u.u.type = type,
452535c4bbdfSmrg        .u.u.detail = detail
452635c4bbdfSmrg    };
452735c4bbdfSmrg    WindowPtr focus;
452835c4bbdfSmrg    DeviceIntPtr keybd;
452935c4bbdfSmrg    GrabPtr grab = mouse->deviceGrab.grab;
453035c4bbdfSmrg    Mask mask;
453135c4bbdfSmrg
453235c4bbdfSmrg    keybd = GetMaster(mouse, KEYBOARD_OR_FLOAT);
45334642e01fSmrg
453405b261ecSmrg    if ((pWin == mouse->valuator->motionHintWindow) &&
453535c4bbdfSmrg        (detail != NotifyInferior))
453635c4bbdfSmrg        mouse->valuator->motionHintWindow = NullWindow;
453735c4bbdfSmrg    if (grab) {
453835c4bbdfSmrg        mask = (pWin == grab->window) ? grab->eventMask : 0;
453935c4bbdfSmrg        if (grab->ownerEvents)
454035c4bbdfSmrg            mask |= EventMaskForClient(pWin, rClient(grab));
454105b261ecSmrg    }
454235c4bbdfSmrg    else {
454335c4bbdfSmrg        mask = pWin->eventMask | wOtherEventMasks(pWin);
454405b261ecSmrg    }
45454642e01fSmrg
45464642e01fSmrg    event.u.enterLeave.time = currentTime.milliseconds;
45474642e01fSmrg    event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x;
45484642e01fSmrg    event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y;
45494642e01fSmrg    /* Counts on the same initial structure of crossing & button events! */
45509ace9065Smrg    FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE);
45514642e01fSmrg    /* Enter/Leave events always set child */
45524642e01fSmrg    event.u.enterLeave.child = child;
45534642e01fSmrg    event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ?
45544642e01fSmrg        ELFlagSameScreen : 0;
455535c4bbdfSmrg    event.u.enterLeave.state =
455635c4bbdfSmrg        mouse->button ? (mouse->button->state & 0x1f00) : 0;
45576747b715Smrg    if (keybd)
45586747b715Smrg        event.u.enterLeave.state |=
455935c4bbdfSmrg            XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
45604642e01fSmrg    event.u.enterLeave.mode = mode;
45614642e01fSmrg    focus = (keybd) ? keybd->focus->win : None;
45624642e01fSmrg    if ((focus != NoneWin) &&
456335c4bbdfSmrg        ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin)))
45644642e01fSmrg        event.u.enterLeave.flags |= ELFlagFocus;
456505b261ecSmrg
456635c4bbdfSmrg    if ((mask & GetEventFilter(mouse, &event))) {
45674642e01fSmrg        if (grab)
45684642e01fSmrg            TryClientEvents(rClient(grab), mouse, &event, 1, mask,
45696747b715Smrg                            GetEventFilter(mouse, &event), grab);
45704642e01fSmrg        else
45714642e01fSmrg            DeliverEventsToWindow(mouse, pWin, &event, 1,
457235c4bbdfSmrg                                  GetEventFilter(mouse, &event), NullGrab);
457305b261ecSmrg    }
457405b261ecSmrg
457535c4bbdfSmrg    if ((type == EnterNotify) && (mask & KeymapStateMask)) {
457635c4bbdfSmrg        xKeymapEvent ke = {
457735c4bbdfSmrg            .type = KeymapNotify
457835c4bbdfSmrg        };
45796747b715Smrg        ClientPtr client = grab ? rClient(grab) : wClient(pWin);
458035c4bbdfSmrg        int rc;
458135c4bbdfSmrg
458235c4bbdfSmrg        rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess);
458335c4bbdfSmrg        if (rc == Success)
458435c4bbdfSmrg            memcpy((char *) &ke.map[0], (char *) &keybd->key->down[1], 31);
45854642e01fSmrg
45864642e01fSmrg        if (grab)
458735c4bbdfSmrg            TryClientEvents(rClient(grab), keybd, (xEvent *) &ke, 1,
45884642e01fSmrg                            mask, KeymapStateMask, grab);
45894642e01fSmrg        else
459035c4bbdfSmrg            DeliverEventsToWindow(mouse, pWin, (xEvent *) &ke, 1,
45916747b715Smrg                                  KeymapStateMask, NullGrab);
45926747b715Smrg    }
45936747b715Smrg}
45946747b715Smrg
45956747b715Smrgvoid
459635c4bbdfSmrgDeviceEnterLeaveEvent(DeviceIntPtr mouse,
459735c4bbdfSmrg                      int sourceid,
459835c4bbdfSmrg                      int type,
459935c4bbdfSmrg                      int mode, int detail, WindowPtr pWin, Window child)
460035c4bbdfSmrg{
460135c4bbdfSmrg    GrabPtr grab = mouse->deviceGrab.grab;
460235c4bbdfSmrg    xXIEnterEvent *event;
460335c4bbdfSmrg    WindowPtr focus;
460435c4bbdfSmrg    int filter;
460535c4bbdfSmrg    int btlen, len, i;
460635c4bbdfSmrg    DeviceIntPtr kbd;
46076747b715Smrg
46086747b715Smrg    if ((mode == XINotifyPassiveGrab && type == XI_Leave) ||
46096747b715Smrg        (mode == XINotifyPassiveUngrab && type == XI_Enter))
46106747b715Smrg        return;
46116747b715Smrg
46126747b715Smrg    btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0;
46136747b715Smrg    btlen = bytes_to_int32(btlen);
46146747b715Smrg    len = sizeof(xXIEnterEvent) + btlen * 4;
46156747b715Smrg
46166747b715Smrg    event = calloc(1, len);
461735c4bbdfSmrg    event->type = GenericEvent;
461835c4bbdfSmrg    event->extension = IReqCode;
461935c4bbdfSmrg    event->evtype = type;
462035c4bbdfSmrg    event->length = (len - sizeof(xEvent)) / 4;
462135c4bbdfSmrg    event->buttons_len = btlen;
462235c4bbdfSmrg    event->detail = detail;
462335c4bbdfSmrg    event->time = currentTime.milliseconds;
462435c4bbdfSmrg    event->deviceid = mouse->id;
462535c4bbdfSmrg    event->sourceid = sourceid;
462635c4bbdfSmrg    event->mode = mode;
462735c4bbdfSmrg    event->root_x = double_to_fp1616(mouse->spriteInfo->sprite->hot.x);
462835c4bbdfSmrg    event->root_y = double_to_fp1616(mouse->spriteInfo->sprite->hot.y);
46296747b715Smrg
46306747b715Smrg    for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
46316747b715Smrg        if (BitIsOn(mouse->button->down, i))
46326747b715Smrg            SetBit(&event[1], i);
46336747b715Smrg
463435c4bbdfSmrg    kbd = GetMaster(mouse, MASTER_KEYBOARD);
463535c4bbdfSmrg    if (kbd && kbd->key) {
46366747b715Smrg        event->mods.base_mods = kbd->key->xkbInfo->state.base_mods;
46376747b715Smrg        event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods;
46386747b715Smrg        event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods;
46396747b715Smrg
46406747b715Smrg        event->group.base_group = kbd->key->xkbInfo->state.base_group;
46416747b715Smrg        event->group.latched_group = kbd->key->xkbInfo->state.latched_group;
46426747b715Smrg        event->group.locked_group = kbd->key->xkbInfo->state.locked_group;
464305b261ecSmrg    }
46446747b715Smrg
464535c4bbdfSmrg    focus = (kbd) ? kbd->focus->win : None;
464635c4bbdfSmrg    if ((focus != NoneWin) &&
464735c4bbdfSmrg        ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin)))
464835c4bbdfSmrg        event->focus = TRUE;
464935c4bbdfSmrg
465035c4bbdfSmrg    FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent *) event, pWin,
46519ace9065Smrg                         None, FALSE);
46526747b715Smrg
465335c4bbdfSmrg    filter = GetEventFilter(mouse, (xEvent *) event);
46546747b715Smrg
465535c4bbdfSmrg    if (grab && grab->grabtype == XI2) {
46566747b715Smrg        Mask mask;
465735c4bbdfSmrg
465835c4bbdfSmrg        mask = xi2mask_isset(grab->xi2mask, mouse, type);
465935c4bbdfSmrg        TryClientEvents(rClient(grab), mouse, (xEvent *) event, 1, mask, 1,
466035c4bbdfSmrg                        grab);
466135c4bbdfSmrg    }
466235c4bbdfSmrg    else {
466335c4bbdfSmrg        if (!WindowXI2MaskIsset(mouse, pWin, (xEvent *) event))
46646747b715Smrg            goto out;
466535c4bbdfSmrg        DeliverEventsToWindow(mouse, pWin, (xEvent *) event, 1, filter,
46666747b715Smrg                              NullGrab);
46676747b715Smrg    }
46686747b715Smrg
466935c4bbdfSmrg out:
46706747b715Smrg    free(event);
467105b261ecSmrg}
467205b261ecSmrg
46734642e01fSmrgvoid
46744642e01fSmrgCoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
467505b261ecSmrg{
467635c4bbdfSmrg    xEvent event = {
467735c4bbdfSmrg        .u.u.type = type,
467835c4bbdfSmrg        .u.u.detail = detail
467935c4bbdfSmrg    };
468005b261ecSmrg    event.u.focus.mode = mode;
468105b261ecSmrg    event.u.focus.window = pWin->drawable.id;
46826747b715Smrg
46836747b715Smrg    DeliverEventsToWindow(dev, pWin, &event, 1,
46846747b715Smrg                          GetEventFilter(dev, &event), NullGrab);
468505b261ecSmrg    if ((type == FocusIn) &&
468635c4bbdfSmrg        ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) {
468735c4bbdfSmrg        xKeymapEvent ke = {
468835c4bbdfSmrg            .type = KeymapNotify
468935c4bbdfSmrg        };
46906747b715Smrg        ClientPtr client = wClient(pWin);
469135c4bbdfSmrg        int rc;
469205b261ecSmrg
469335c4bbdfSmrg        rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
469435c4bbdfSmrg        if (rc == Success)
469535c4bbdfSmrg            memcpy((char *) &ke.map[0], (char *) &dev->key->down[1], 31);
469635c4bbdfSmrg
469735c4bbdfSmrg        DeliverEventsToWindow(dev, pWin, (xEvent *) &ke, 1,
469835c4bbdfSmrg                              KeymapStateMask, NullGrab);
469905b261ecSmrg    }
470005b261ecSmrg}
470105b261ecSmrg
470205b261ecSmrg/**
470305b261ecSmrg * Set the input focus to the given window. Subsequent keyboard events will be
470405b261ecSmrg * delivered to the given window.
47054642e01fSmrg *
470605b261ecSmrg * Usually called from ProcSetInputFocus as result of a client request. If so,
470705b261ecSmrg * the device is the inputInfo.keyboard.
470805b261ecSmrg * If called from ProcXSetInputFocus as result of a client xinput request, the
470905b261ecSmrg * device is set to the device specified by the client.
471005b261ecSmrg *
471105b261ecSmrg * @param client Client that requested input focus change.
47124642e01fSmrg * @param dev Focus device.
471305b261ecSmrg * @param focusID The window to obtain the focus. Can be PointerRoot or None.
471405b261ecSmrg * @param revertTo Specifies where the focus reverts to when window becomes
471505b261ecSmrg * unviewable.
471605b261ecSmrg * @param ctime Specifies the time.
471705b261ecSmrg * @param followOK True if pointer is allowed to follow the keyboard.
471805b261ecSmrg */
471905b261ecSmrgint
472035c4bbdfSmrgSetInputFocus(ClientPtr client,
472135c4bbdfSmrg              DeviceIntPtr dev,
472235c4bbdfSmrg              Window focusID, CARD8 revertTo, Time ctime, Bool followOK)
472305b261ecSmrg{
472405b261ecSmrg    FocusClassPtr focus;
472505b261ecSmrg    WindowPtr focusWin;
472605b261ecSmrg    int mode, rc;
472705b261ecSmrg    TimeStamp time;
472835c4bbdfSmrg    DeviceIntPtr keybd;         /* used for FollowKeyboard or FollowKeyboardWin */
472905b261ecSmrg
473005b261ecSmrg    UpdateCurrentTime();
473105b261ecSmrg    if ((revertTo != RevertToParent) &&
473235c4bbdfSmrg        (revertTo != RevertToPointerRoot) &&
473335c4bbdfSmrg        (revertTo != RevertToNone) &&
473435c4bbdfSmrg        ((revertTo != RevertToFollowKeyboard) || !followOK)) {
473535c4bbdfSmrg        client->errorValue = revertTo;
473635c4bbdfSmrg        return BadValue;
473705b261ecSmrg    }
473805b261ecSmrg    time = ClientTimeToServerTime(ctime);
47394642e01fSmrg
474035c4bbdfSmrg    keybd = GetMaster(dev, KEYBOARD_OR_FLOAT);
47414642e01fSmrg
474205b261ecSmrg    if ((focusID == None) || (focusID == PointerRoot))
474335c4bbdfSmrg        focusWin = (WindowPtr) (long) focusID;
474435c4bbdfSmrg    else if ((focusID == FollowKeyboard) && followOK) {
474535c4bbdfSmrg        focusWin = keybd->focus->win;
47464642e01fSmrg    }
474705b261ecSmrg    else {
474835c4bbdfSmrg        rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess);
474935c4bbdfSmrg        if (rc != Success)
475035c4bbdfSmrg            return rc;
475135c4bbdfSmrg        /* It is a match error to try to set the input focus to an
475235c4bbdfSmrg           unviewable window. */
475335c4bbdfSmrg        if (!focusWin->realized)
475435c4bbdfSmrg            return BadMatch;
475505b261ecSmrg    }
47564642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess);
47574642e01fSmrg    if (rc != Success)
475835c4bbdfSmrg        return Success;
47594642e01fSmrg
476005b261ecSmrg    focus = dev->focus;
476105b261ecSmrg    if ((CompareTimeStamps(time, currentTime) == LATER) ||
476235c4bbdfSmrg        (CompareTimeStamps(time, focus->time) == EARLIER))
476335c4bbdfSmrg        return Success;
47644642e01fSmrg    mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal;
476535c4bbdfSmrg    if (focus->win == FollowKeyboardWin) {
47666747b715Smrg        if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin))
47676747b715Smrg            DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
476835c4bbdfSmrg    }
476935c4bbdfSmrg    else {
47706747b715Smrg        if (!ActivateFocusInGrab(dev, focus->win, focusWin))
47716747b715Smrg            DoFocusEvents(dev, focus->win, focusWin, mode);
47726747b715Smrg    }
477305b261ecSmrg    focus->time = time;
477405b261ecSmrg    focus->revert = revertTo;
477505b261ecSmrg    if (focusID == FollowKeyboard)
477635c4bbdfSmrg        focus->win = FollowKeyboardWin;
477705b261ecSmrg    else
477835c4bbdfSmrg        focus->win = focusWin;
477905b261ecSmrg    if ((focusWin == NoneWin) || (focusWin == PointerRootWin))
478035c4bbdfSmrg        focus->traceGood = 0;
478135c4bbdfSmrg    else {
478205b261ecSmrg        int depth = 0;
478335c4bbdfSmrg        WindowPtr pWin;
478435c4bbdfSmrg
478535c4bbdfSmrg        for (pWin = focusWin; pWin; pWin = pWin->parent)
478635c4bbdfSmrg            depth++;
478735c4bbdfSmrg        if (depth > focus->traceSize) {
478835c4bbdfSmrg            focus->traceSize = depth + 1;
478935c4bbdfSmrg            focus->trace = reallocarray(focus->trace, focus->traceSize,
479035c4bbdfSmrg                                        sizeof(WindowPtr));
479135c4bbdfSmrg        }
479235c4bbdfSmrg        focus->traceGood = depth;
47934642e01fSmrg        for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--)
479435c4bbdfSmrg            focus->trace[depth] = pWin;
479505b261ecSmrg    }
479605b261ecSmrg    return Success;
479705b261ecSmrg}
479805b261ecSmrg
479905b261ecSmrg/**
480005b261ecSmrg * Server-side protocol handling for SetInputFocus request.
480105b261ecSmrg *
480205b261ecSmrg * Sets the input focus for the virtual core keyboard.
480305b261ecSmrg */
480405b261ecSmrgint
48056747b715SmrgProcSetInputFocus(ClientPtr client)
480605b261ecSmrg{
48074642e01fSmrg    DeviceIntPtr kbd = PickKeyboard(client);
480835c4bbdfSmrg
480905b261ecSmrg    REQUEST(xSetInputFocusReq);
481005b261ecSmrg
481105b261ecSmrg    REQUEST_SIZE_MATCH(xSetInputFocusReq);
481205b261ecSmrg
48134642e01fSmrg    return SetInputFocus(client, kbd, stuff->focus,
481435c4bbdfSmrg                         stuff->revertTo, stuff->time, FALSE);
481505b261ecSmrg}
481605b261ecSmrg
481705b261ecSmrg/**
481805b261ecSmrg * Server-side protocol handling for GetInputFocus request.
48194642e01fSmrg *
48204642e01fSmrg * Sends the current input focus for the client's keyboard back to the
482105b261ecSmrg * client.
482205b261ecSmrg */
482305b261ecSmrgint
482405b261ecSmrgProcGetInputFocus(ClientPtr client)
482505b261ecSmrg{
48264642e01fSmrg    DeviceIntPtr kbd = PickKeyboard(client);
482705b261ecSmrg    xGetInputFocusReply rep;
48284642e01fSmrg    FocusClassPtr focus = kbd->focus;
48294642e01fSmrg    int rc;
483035c4bbdfSmrg
483105b261ecSmrg    /* REQUEST(xReq); */
483205b261ecSmrg    REQUEST_SIZE_MATCH(xReq);
48334642e01fSmrg
48344642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess);
48354642e01fSmrg    if (rc != Success)
483635c4bbdfSmrg        return rc;
483735c4bbdfSmrg
483835c4bbdfSmrg    rep = (xGetInputFocusReply) {
483935c4bbdfSmrg        .type = X_Reply,
484035c4bbdfSmrg        .length = 0,
484135c4bbdfSmrg        .sequenceNumber = client->sequence,
484235c4bbdfSmrg        .revertTo = focus->revert
484335c4bbdfSmrg    };
48444642e01fSmrg
484505b261ecSmrg    if (focus->win == NoneWin)
484635c4bbdfSmrg        rep.focus = None;
484705b261ecSmrg    else if (focus->win == PointerRootWin)
484835c4bbdfSmrg        rep.focus = PointerRoot;
484935c4bbdfSmrg    else
485035c4bbdfSmrg        rep.focus = focus->win->drawable.id;
485135c4bbdfSmrg
485205b261ecSmrg    WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep);
485305b261ecSmrg    return Success;
485405b261ecSmrg}
485505b261ecSmrg
485605b261ecSmrg/**
48574642e01fSmrg * Server-side protocol handling for GrabPointer request.
485805b261ecSmrg *
48594642e01fSmrg * Sets an active grab on the client's ClientPointer and returns success
48604642e01fSmrg * status to client.
486105b261ecSmrg */
486205b261ecSmrgint
486305b261ecSmrgProcGrabPointer(ClientPtr client)
486405b261ecSmrg{
486505b261ecSmrg    xGrabPointerReply rep;
48664642e01fSmrg    DeviceIntPtr device = PickPointer(client);
486705b261ecSmrg    GrabPtr grab;
48686747b715Smrg    GrabMask mask;
48696747b715Smrg    WindowPtr confineTo;
487035c4bbdfSmrg    BYTE status;
487135c4bbdfSmrg
487205b261ecSmrg    REQUEST(xGrabPointerReq);
487305b261ecSmrg    int rc;
487405b261ecSmrg
487505b261ecSmrg    REQUEST_SIZE_MATCH(xGrabPointerReq);
487605b261ecSmrg    UpdateCurrentTime();
48776747b715Smrg
487835c4bbdfSmrg    if (stuff->eventMask & ~PointerGrabMask) {
487935c4bbdfSmrg        client->errorValue = stuff->eventMask;
488005b261ecSmrg        return BadValue;
488105b261ecSmrg    }
48826747b715Smrg
488305b261ecSmrg    if (stuff->confineTo == None)
488435c4bbdfSmrg        confineTo = NullWindow;
488535c4bbdfSmrg    else {
488635c4bbdfSmrg        rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
488735c4bbdfSmrg                             DixSetAttrAccess);
488835c4bbdfSmrg        if (rc != Success)
488935c4bbdfSmrg            return rc;
489005b261ecSmrg    }
48916747b715Smrg
48926747b715Smrg    grab = device->deviceGrab.grab;
48936747b715Smrg
489435c4bbdfSmrg    if (grab && grab->confineTo && !confineTo)
489535c4bbdfSmrg        ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, FALSE);
48966747b715Smrg
48976747b715Smrg    mask.core = stuff->eventMask;
48986747b715Smrg
48996747b715Smrg    rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode,
49006747b715Smrg                    stuff->grabWindow, stuff->ownerEvents, stuff->time,
490135c4bbdfSmrg                    &mask, CORE, stuff->cursor, stuff->confineTo, &status);
49024642e01fSmrg    if (rc != Success)
49036747b715Smrg        return rc;
49046747b715Smrg
490535c4bbdfSmrg    rep = (xGrabPointerReply) {
490635c4bbdfSmrg        .type = X_Reply,
490735c4bbdfSmrg        .status = status,
490835c4bbdfSmrg        .sequenceNumber = client->sequence,
490935c4bbdfSmrg        .length = 0
491035c4bbdfSmrg    };
491105b261ecSmrg    WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep);
491205b261ecSmrg    return Success;
491305b261ecSmrg}
491405b261ecSmrg
491505b261ecSmrg/**
491605b261ecSmrg * Server-side protocol handling for ChangeActivePointerGrab request.
491705b261ecSmrg *
491805b261ecSmrg * Changes properties of the grab hold by the client. If the client does not
49194642e01fSmrg * hold an active grab on the device, nothing happens.
492005b261ecSmrg */
492105b261ecSmrgint
492205b261ecSmrgProcChangeActivePointerGrab(ClientPtr client)
492305b261ecSmrg{
49244642e01fSmrg    DeviceIntPtr device;
492535c4bbdfSmrg    GrabPtr grab;
492605b261ecSmrg    CursorPtr newCursor, oldCursor;
492735c4bbdfSmrg
492805b261ecSmrg    REQUEST(xChangeActivePointerGrabReq);
492905b261ecSmrg    TimeStamp time;
493005b261ecSmrg
493105b261ecSmrg    REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq);
493235c4bbdfSmrg    if (stuff->eventMask & ~PointerGrabMask) {
493335c4bbdfSmrg        client->errorValue = stuff->eventMask;
493405b261ecSmrg        return BadValue;
493505b261ecSmrg    }
493605b261ecSmrg    if (stuff->cursor == None)
493735c4bbdfSmrg        newCursor = NullCursor;
493835c4bbdfSmrg    else {
493935c4bbdfSmrg        int rc = dixLookupResourceByType((void **) &newCursor, stuff->cursor,
494035c4bbdfSmrg                                         RT_CURSOR, client, DixUseAccess);
494135c4bbdfSmrg
494235c4bbdfSmrg        if (rc != Success) {
494335c4bbdfSmrg            client->errorValue = stuff->cursor;
494435c4bbdfSmrg            return rc;
494535c4bbdfSmrg        }
494605b261ecSmrg    }
49474642e01fSmrg
49484642e01fSmrg    device = PickPointer(client);
49494642e01fSmrg    grab = device->deviceGrab.grab;
49504642e01fSmrg
495105b261ecSmrg    if (!grab)
495235c4bbdfSmrg        return Success;
495305b261ecSmrg    if (!SameClient(grab, client))
495435c4bbdfSmrg        return Success;
495505b261ecSmrg    time = ClientTimeToServerTime(stuff->time);
495605b261ecSmrg    if ((CompareTimeStamps(time, currentTime) == LATER) ||
495735c4bbdfSmrg        (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
495835c4bbdfSmrg        return Success;
495905b261ecSmrg    oldCursor = grab->cursor;
496035c4bbdfSmrg    grab->cursor = RefCursor(newCursor);
49614642e01fSmrg    PostNewCursor(device);
496205b261ecSmrg    if (oldCursor)
496335c4bbdfSmrg        FreeCursor(oldCursor, (Cursor) 0);
496405b261ecSmrg    grab->eventMask = stuff->eventMask;
496505b261ecSmrg    return Success;
496605b261ecSmrg}
496705b261ecSmrg
496805b261ecSmrg/**
496905b261ecSmrg * Server-side protocol handling for UngrabPointer request.
497005b261ecSmrg *
49714642e01fSmrg * Deletes a pointer grab on a device the client has grabbed.
497205b261ecSmrg */
497305b261ecSmrgint
497405b261ecSmrgProcUngrabPointer(ClientPtr client)
497505b261ecSmrg{
49764642e01fSmrg    DeviceIntPtr device = PickPointer(client);
497705b261ecSmrg    GrabPtr grab;
497805b261ecSmrg    TimeStamp time;
497935c4bbdfSmrg
498005b261ecSmrg    REQUEST(xResourceReq);
498105b261ecSmrg
498205b261ecSmrg    REQUEST_SIZE_MATCH(xResourceReq);
498305b261ecSmrg    UpdateCurrentTime();
49844642e01fSmrg    grab = device->deviceGrab.grab;
49854642e01fSmrg
498605b261ecSmrg    time = ClientTimeToServerTime(stuff->id);
498705b261ecSmrg    if ((CompareTimeStamps(time, currentTime) != LATER) &&
498835c4bbdfSmrg        (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
498935c4bbdfSmrg        (grab) && SameClient(grab, client))
499035c4bbdfSmrg        (*device->deviceGrab.DeactivateGrab) (device);
499105b261ecSmrg    return Success;
499205b261ecSmrg}
499305b261ecSmrg
499405b261ecSmrg/**
499505b261ecSmrg * Sets a grab on the given device.
49964642e01fSmrg *
49974642e01fSmrg * Called from ProcGrabKeyboard to work on the client's keyboard.
499805b261ecSmrg * Called from ProcXGrabDevice to work on the device specified by the client.
49994642e01fSmrg *
500005b261ecSmrg * The parameters this_mode and other_mode represent the keyboard_mode and
50014642e01fSmrg * pointer_mode parameters of XGrabKeyboard().
500205b261ecSmrg * See man page for details on all the parameters
50034642e01fSmrg *
500405b261ecSmrg * @param client Client that owns the grab.
50054642e01fSmrg * @param dev The device to grab.
500605b261ecSmrg * @param this_mode GrabModeSync or GrabModeAsync
500705b261ecSmrg * @param other_mode GrabModeSync or GrabModeAsync
500805b261ecSmrg * @param status Return code to be returned to the caller.
50094642e01fSmrg *
501035c4bbdfSmrg * @returns Success or BadValue or BadAlloc.
501105b261ecSmrg */
501205b261ecSmrgint
50134642e01fSmrgGrabDevice(ClientPtr client, DeviceIntPtr dev,
50146747b715Smrg           unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow,
50156747b715Smrg           unsigned ownerEvents, Time ctime, GrabMask *mask,
50166747b715Smrg           int grabtype, Cursor curs, Window confineToWin, CARD8 *status)
501705b261ecSmrg{
50186747b715Smrg    WindowPtr pWin, confineTo;
501905b261ecSmrg    GrabPtr grab;
502005b261ecSmrg    TimeStamp time;
50214642e01fSmrg    Mask access_mode = DixGrabAccess;
502205b261ecSmrg    int rc;
50234642e01fSmrg    GrabInfoPtr grabInfo = &dev->deviceGrab;
50246747b715Smrg    CursorPtr cursor;
502505b261ecSmrg
502605b261ecSmrg    UpdateCurrentTime();
502735c4bbdfSmrg    if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) {
502835c4bbdfSmrg        client->errorValue = keyboard_mode;
502905b261ecSmrg        return BadValue;
503005b261ecSmrg    }
503135c4bbdfSmrg    if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) {
503235c4bbdfSmrg        client->errorValue = pointer_mode;
503305b261ecSmrg        return BadValue;
503405b261ecSmrg    }
503535c4bbdfSmrg    if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) {
503635c4bbdfSmrg        client->errorValue = ownerEvents;
503705b261ecSmrg        return BadValue;
503805b261ecSmrg    }
50394642e01fSmrg
50404642e01fSmrg    rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess);
504105b261ecSmrg    if (rc != Success)
504235c4bbdfSmrg        return rc;
50436747b715Smrg
50446747b715Smrg    if (confineToWin == None)
504535c4bbdfSmrg        confineTo = NullWindow;
504635c4bbdfSmrg    else {
504735c4bbdfSmrg        rc = dixLookupWindow(&confineTo, confineToWin, client,
504835c4bbdfSmrg                             DixSetAttrAccess);
504935c4bbdfSmrg        if (rc != Success)
505035c4bbdfSmrg            return rc;
50516747b715Smrg    }
50526747b715Smrg
50536747b715Smrg    if (curs == None)
505435c4bbdfSmrg        cursor = NullCursor;
505535c4bbdfSmrg    else {
505635c4bbdfSmrg        rc = dixLookupResourceByType((void **) &cursor, curs, RT_CURSOR,
505735c4bbdfSmrg                                     client, DixUseAccess);
505835c4bbdfSmrg        if (rc != Success) {
505935c4bbdfSmrg            client->errorValue = curs;
506035c4bbdfSmrg            return rc;
506135c4bbdfSmrg        }
506235c4bbdfSmrg        access_mode |= DixForceAccess;
50636747b715Smrg    }
50646747b715Smrg
50656747b715Smrg    if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync)
506635c4bbdfSmrg        access_mode |= DixFreezeAccess;
50674642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
50684642e01fSmrg    if (rc != Success)
506935c4bbdfSmrg        return rc;
50704642e01fSmrg
507105b261ecSmrg    time = ClientTimeToServerTime(ctime);
50724642e01fSmrg    grab = grabInfo->grab;
50736747b715Smrg    if (grab && grab->grabtype != grabtype)
50746747b715Smrg        *status = AlreadyGrabbed;
507535c4bbdfSmrg    else if (grab && !SameClient(grab, client))
507635c4bbdfSmrg        *status = AlreadyGrabbed;
50776747b715Smrg    else if ((!pWin->realized) ||
50786747b715Smrg             (confineTo &&
507935c4bbdfSmrg              !(confineTo->realized && BorderSizeNotEmpty(dev, confineTo))))
508035c4bbdfSmrg        *status = GrabNotViewable;
508105b261ecSmrg    else if ((CompareTimeStamps(time, currentTime) == LATER) ||
508235c4bbdfSmrg             (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER))
508335c4bbdfSmrg        *status = GrabInvalidTime;
50844642e01fSmrg    else if (grabInfo->sync.frozen &&
508535c4bbdfSmrg             grabInfo->sync.other && !SameClient(grabInfo->sync.other, client))
508635c4bbdfSmrg        *status = GrabFrozen;
508735c4bbdfSmrg    else {
508835c4bbdfSmrg        GrabPtr tempGrab;
508935c4bbdfSmrg
509035c4bbdfSmrg        tempGrab = AllocGrab(NULL);
509135c4bbdfSmrg        if (tempGrab == NULL)
509235c4bbdfSmrg            return BadAlloc;
509335c4bbdfSmrg
509435c4bbdfSmrg        tempGrab->next = NULL;
509535c4bbdfSmrg        tempGrab->window = pWin;
509635c4bbdfSmrg        tempGrab->resource = client->clientAsMask;
509735c4bbdfSmrg        tempGrab->ownerEvents = ownerEvents;
509835c4bbdfSmrg        tempGrab->keyboardMode = keyboard_mode;
509935c4bbdfSmrg        tempGrab->pointerMode = pointer_mode;
510035c4bbdfSmrg        if (grabtype == CORE)
510135c4bbdfSmrg            tempGrab->eventMask = mask->core;
510235c4bbdfSmrg        else if (grabtype == XI)
510335c4bbdfSmrg            tempGrab->eventMask = mask->xi;
510435c4bbdfSmrg        else
510535c4bbdfSmrg            xi2mask_merge(tempGrab->xi2mask, mask->xi2mask);
510635c4bbdfSmrg        tempGrab->device = dev;
510735c4bbdfSmrg        tempGrab->cursor = RefCursor(cursor);
510835c4bbdfSmrg        tempGrab->confineTo = confineTo;
510935c4bbdfSmrg        tempGrab->grabtype = grabtype;
511035c4bbdfSmrg        (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE);
511135c4bbdfSmrg        *status = GrabSuccess;
511235c4bbdfSmrg
511335c4bbdfSmrg        FreeGrab(tempGrab);
511405b261ecSmrg    }
511505b261ecSmrg    return Success;
511605b261ecSmrg}
511705b261ecSmrg
511805b261ecSmrg/**
511905b261ecSmrg * Server-side protocol handling for GrabKeyboard request.
512005b261ecSmrg *
51214642e01fSmrg * Grabs the client's keyboard and returns success status to client.
512205b261ecSmrg */
512305b261ecSmrgint
512405b261ecSmrgProcGrabKeyboard(ClientPtr client)
512505b261ecSmrg{
512605b261ecSmrg    xGrabKeyboardReply rep;
512735c4bbdfSmrg    BYTE status;
512835c4bbdfSmrg
512905b261ecSmrg    REQUEST(xGrabKeyboardReq);
513005b261ecSmrg    int result;
51314642e01fSmrg    DeviceIntPtr keyboard = PickKeyboard(client);
51326747b715Smrg    GrabMask mask;
513305b261ecSmrg
513405b261ecSmrg    REQUEST_SIZE_MATCH(xGrabKeyboardReq);
513505b261ecSmrg
51366747b715Smrg    mask.core = KeyPressMask | KeyReleaseMask;
51376747b715Smrg
51386747b715Smrg    result = GrabDevice(client, keyboard, stuff->pointerMode,
513935c4bbdfSmrg                        stuff->keyboardMode, stuff->grabWindow,
514035c4bbdfSmrg                        stuff->ownerEvents, stuff->time, &mask, CORE, None,
514135c4bbdfSmrg                        None, &status);
514205b261ecSmrg
514305b261ecSmrg    if (result != Success)
514435c4bbdfSmrg        return result;
514535c4bbdfSmrg
514635c4bbdfSmrg    rep = (xGrabKeyboardReply) {
514735c4bbdfSmrg        .type = X_Reply,
514835c4bbdfSmrg        .status = status,
514935c4bbdfSmrg        .sequenceNumber = client->sequence,
515035c4bbdfSmrg        .length = 0
515135c4bbdfSmrg    };
515205b261ecSmrg    WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep);
515305b261ecSmrg    return Success;
515405b261ecSmrg}
515505b261ecSmrg
515605b261ecSmrg/**
515705b261ecSmrg * Server-side protocol handling for UngrabKeyboard request.
515805b261ecSmrg *
51594642e01fSmrg * Deletes a possible grab on the client's keyboard.
516005b261ecSmrg */
516105b261ecSmrgint
516205b261ecSmrgProcUngrabKeyboard(ClientPtr client)
516305b261ecSmrg{
51644642e01fSmrg    DeviceIntPtr device = PickKeyboard(client);
516505b261ecSmrg    GrabPtr grab;
516605b261ecSmrg    TimeStamp time;
516735c4bbdfSmrg
516805b261ecSmrg    REQUEST(xResourceReq);
516905b261ecSmrg
517005b261ecSmrg    REQUEST_SIZE_MATCH(xResourceReq);
517105b261ecSmrg    UpdateCurrentTime();
51724642e01fSmrg
51734642e01fSmrg    grab = device->deviceGrab.grab;
51744642e01fSmrg
517505b261ecSmrg    time = ClientTimeToServerTime(stuff->id);
517605b261ecSmrg    if ((CompareTimeStamps(time, currentTime) != LATER) &&
517735c4bbdfSmrg        (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
517835c4bbdfSmrg        (grab) && SameClient(grab, client) && grab->grabtype == CORE)
517935c4bbdfSmrg        (*device->deviceGrab.DeactivateGrab) (device);
518005b261ecSmrg    return Success;
518105b261ecSmrg}
518205b261ecSmrg
518305b261ecSmrg/**
518405b261ecSmrg * Server-side protocol handling for QueryPointer request.
518505b261ecSmrg *
51864642e01fSmrg * Returns the current state and position of the client's ClientPointer to the
51874642e01fSmrg * client.
518805b261ecSmrg */
518905b261ecSmrgint
519005b261ecSmrgProcQueryPointer(ClientPtr client)
519105b261ecSmrg{
519205b261ecSmrg    xQueryPointerReply rep;
519305b261ecSmrg    WindowPtr pWin, t;
51944642e01fSmrg    DeviceIntPtr mouse = PickPointer(client);
51956747b715Smrg    DeviceIntPtr keyboard;
51964642e01fSmrg    SpritePtr pSprite;
519705b261ecSmrg    int rc;
519835c4bbdfSmrg
51994642e01fSmrg    REQUEST(xResourceReq);
520005b261ecSmrg    REQUEST_SIZE_MATCH(xResourceReq);
52014642e01fSmrg
52024642e01fSmrg    rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
52034642e01fSmrg    if (rc != Success)
520435c4bbdfSmrg        return rc;
52054642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
52066747b715Smrg    if (rc != Success && rc != BadAccess)
520735c4bbdfSmrg        return rc;
52084642e01fSmrg
520935c4bbdfSmrg    keyboard = GetMaster(mouse, MASTER_KEYBOARD);
52106747b715Smrg
52114642e01fSmrg    pSprite = mouse->spriteInfo->sprite;
521205b261ecSmrg    if (mouse->valuator->motionHintWindow)
521335c4bbdfSmrg        MaybeStopHint(mouse, client);
521435c4bbdfSmrg    rep = (xQueryPointerReply) {
521535c4bbdfSmrg        .type = X_Reply,
521635c4bbdfSmrg        .sequenceNumber = client->sequence,
521735c4bbdfSmrg        .length = 0,
521835c4bbdfSmrg        .mask = event_get_corestate(mouse, keyboard),
521935c4bbdfSmrg        .root = (GetCurrentRootWindow(mouse))->drawable.id,
522035c4bbdfSmrg        .rootX = pSprite->hot.x,
522135c4bbdfSmrg        .rootY = pSprite->hot.y,
522235c4bbdfSmrg        .child = None
522335c4bbdfSmrg    };
522435c4bbdfSmrg    if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
522535c4bbdfSmrg        rep.sameScreen = xTrue;
522635c4bbdfSmrg        rep.winX = pSprite->hot.x - pWin->drawable.x;
522735c4bbdfSmrg        rep.winY = pSprite->hot.y - pWin->drawable.y;
522835c4bbdfSmrg        for (t = pSprite->win; t; t = t->parent)
522935c4bbdfSmrg            if (t->parent == pWin) {
523035c4bbdfSmrg                rep.child = t->drawable.id;
523135c4bbdfSmrg                break;
523235c4bbdfSmrg            }
523305b261ecSmrg    }
523435c4bbdfSmrg    else {
523535c4bbdfSmrg        rep.sameScreen = xFalse;
523635c4bbdfSmrg        rep.winX = 0;
523735c4bbdfSmrg        rep.winY = 0;
523805b261ecSmrg    }
523905b261ecSmrg
524005b261ecSmrg#ifdef PANORAMIX
524135c4bbdfSmrg    if (!noPanoramiXExtension) {
524235c4bbdfSmrg        rep.rootX += screenInfo.screens[0]->x;
524335c4bbdfSmrg        rep.rootY += screenInfo.screens[0]->y;
524435c4bbdfSmrg        if (stuff->id == rep.root) {
524535c4bbdfSmrg            rep.winX += screenInfo.screens[0]->x;
524635c4bbdfSmrg            rep.winY += screenInfo.screens[0]->y;
524735c4bbdfSmrg        }
524805b261ecSmrg    }
524905b261ecSmrg#endif
525005b261ecSmrg
52516747b715Smrg    if (rc == BadAccess) {
525235c4bbdfSmrg        rep.mask = 0;
525335c4bbdfSmrg        rep.child = None;
525435c4bbdfSmrg        rep.rootX = 0;
525535c4bbdfSmrg        rep.rootY = 0;
525635c4bbdfSmrg        rep.winX = 0;
525735c4bbdfSmrg        rep.winY = 0;
52586747b715Smrg    }
52596747b715Smrg
526005b261ecSmrg    WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep);
526105b261ecSmrg
52626747b715Smrg    return Success;
526305b261ecSmrg}
526405b261ecSmrg
526505b261ecSmrg/**
526605b261ecSmrg * Initializes the device list and the DIX sprite to sane values. Allocates
526705b261ecSmrg * trace memory used for quick window traversal.
526805b261ecSmrg */
526905b261ecSmrgvoid
527005b261ecSmrgInitEvents(void)
527105b261ecSmrg{
527205b261ecSmrg    int i;
527335c4bbdfSmrg    QdEventPtr qe, tmp;
527405b261ecSmrg
527505b261ecSmrg    inputInfo.numDevices = 0;
527635c4bbdfSmrg    inputInfo.devices = (DeviceIntPtr) NULL;
527735c4bbdfSmrg    inputInfo.off_devices = (DeviceIntPtr) NULL;
527835c4bbdfSmrg    inputInfo.keyboard = (DeviceIntPtr) NULL;
527935c4bbdfSmrg    inputInfo.pointer = (DeviceIntPtr) NULL;
528035c4bbdfSmrg
528135c4bbdfSmrg    for (i = 0; i < MAXDEVICES; i++) {
528235c4bbdfSmrg        DeviceIntRec dummy;
528335c4bbdfSmrg        memcpy(&event_filters[i], default_filter, sizeof(default_filter));
528435c4bbdfSmrg
528535c4bbdfSmrg        dummy.id = i;
528635c4bbdfSmrg        NoticeTime(&dummy, currentTime);
528735c4bbdfSmrg        LastEventTimeToggleResetFlag(i, FALSE);
528805b261ecSmrg    }
52894642e01fSmrg
529035c4bbdfSmrg    syncEvents.replayDev = (DeviceIntPtr) NULL;
529105b261ecSmrg    syncEvents.replayWin = NullWindow;
529235c4bbdfSmrg    if (syncEvents.pending.next)
529335c4bbdfSmrg        xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next)
529435c4bbdfSmrg            free(qe);
529535c4bbdfSmrg    xorg_list_init(&syncEvents.pending);
529605b261ecSmrg    syncEvents.playingEvents = FALSE;
529705b261ecSmrg    syncEvents.time.months = 0;
529835c4bbdfSmrg    syncEvents.time.milliseconds = 0;   /* hardly matters */
529905b261ecSmrg    currentTime.months = 0;
530005b261ecSmrg    currentTime.milliseconds = GetTimeInMillis();
530135c4bbdfSmrg    for (i = 0; i < DNPMCOUNT; i++) {
530235c4bbdfSmrg        DontPropagateMasks[i] = 0;
530335c4bbdfSmrg        DontPropagateRefCnts[i] = 0;
530405b261ecSmrg    }
53054642e01fSmrg
530635c4bbdfSmrg    InputEventList = InitEventList(GetMaximumEventsNum());
53074642e01fSmrg    if (!InputEventList)
53084642e01fSmrg        FatalError("[dix] Failed to allocate input event list.\n");
530905b261ecSmrg}
531005b261ecSmrg
531105b261ecSmrgvoid
531205b261ecSmrgCloseDownEvents(void)
531305b261ecSmrg{
531435c4bbdfSmrg    FreeEventList(InputEventList, GetMaximumEventsNum());
53156747b715Smrg    InputEventList = NULL;
531605b261ecSmrg}
531705b261ecSmrg
5318475c125cSmrg#define SEND_EVENT_BIT 0x80
5319475c125cSmrg
532005b261ecSmrg/**
532105b261ecSmrg * Server-side protocol handling for SendEvent request.
532205b261ecSmrg *
53234642e01fSmrg * Locates the window to send the event to and forwards the event.
532405b261ecSmrg */
532505b261ecSmrgint
532605b261ecSmrgProcSendEvent(ClientPtr client)
532705b261ecSmrg{
532805b261ecSmrg    WindowPtr pWin;
532935c4bbdfSmrg    WindowPtr effectiveFocus = NullWindow;      /* only set if dest==InputFocus */
53306747b715Smrg    DeviceIntPtr dev = PickPointer(client);
533135c4bbdfSmrg    DeviceIntPtr keybd = GetMaster(dev, MASTER_KEYBOARD);
53326747b715Smrg    SpritePtr pSprite = dev->spriteInfo->sprite;
533335c4bbdfSmrg
533405b261ecSmrg    REQUEST(xSendEventReq);
533505b261ecSmrg
533605b261ecSmrg    REQUEST_SIZE_MATCH(xSendEventReq);
533705b261ecSmrg
5338475c125cSmrg    /* libXext and other extension libraries may set the bit indicating
5339475c125cSmrg     * that this event came from a SendEvent request so remove it
5340475c125cSmrg     * since otherwise the event type may fail the range checks
5341475c125cSmrg     * and cause an invalid BadValue error to be returned.
5342475c125cSmrg     *
5343475c125cSmrg     * This is safe to do since we later add the SendEvent bit (0x80)
5344475c125cSmrg     * back in once we send the event to the client */
5345475c125cSmrg
5346475c125cSmrg    stuff->event.u.u.type &= ~(SEND_EVENT_BIT);
5347475c125cSmrg
534805b261ecSmrg    /* The client's event type must be a core event type or one defined by an
534935c4bbdfSmrg       extension. */
535005b261ecSmrg
535135c4bbdfSmrg    if (!((stuff->event.u.u.type > X_Reply &&
535235c4bbdfSmrg           stuff->event.u.u.type < LASTEvent) ||
535335c4bbdfSmrg          (stuff->event.u.u.type >= EXTENSION_EVENT_BASE &&
535435c4bbdfSmrg           stuff->event.u.u.type < (unsigned) lastEvent))) {
535535c4bbdfSmrg        client->errorValue = stuff->event.u.u.type;
535635c4bbdfSmrg        return BadValue;
535705b261ecSmrg    }
535805b261ecSmrg    if (stuff->event.u.u.type == ClientMessage &&
535935c4bbdfSmrg        stuff->event.u.u.detail != 8 &&
536035c4bbdfSmrg        stuff->event.u.u.detail != 16 && stuff->event.u.u.detail != 32) {
536135c4bbdfSmrg        client->errorValue = stuff->event.u.u.detail;
536235c4bbdfSmrg        return BadValue;
536305b261ecSmrg    }
536435c4bbdfSmrg    if (stuff->eventMask & ~AllEventMasks) {
536535c4bbdfSmrg        client->errorValue = stuff->eventMask;
536635c4bbdfSmrg        return BadValue;
536705b261ecSmrg    }
536805b261ecSmrg
536905b261ecSmrg    if (stuff->destination == PointerWindow)
537035c4bbdfSmrg        pWin = pSprite->win;
537135c4bbdfSmrg    else if (stuff->destination == InputFocus) {
537235c4bbdfSmrg        WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin;
537305b261ecSmrg
537435c4bbdfSmrg        if (inputFocus == NoneWin)
537535c4bbdfSmrg            return Success;
537605b261ecSmrg
537735c4bbdfSmrg        /* If the input focus is PointerRootWin, send the event to where
537835c4bbdfSmrg           the pointer is if possible, then perhaps propogate up to root. */
537935c4bbdfSmrg        if (inputFocus == PointerRootWin)
538035c4bbdfSmrg            inputFocus = GetCurrentRootWindow(dev);
538105b261ecSmrg
538235c4bbdfSmrg        if (IsParent(inputFocus, pSprite->win)) {
538335c4bbdfSmrg            effectiveFocus = inputFocus;
538435c4bbdfSmrg            pWin = pSprite->win;
538535c4bbdfSmrg        }
538635c4bbdfSmrg        else
538735c4bbdfSmrg            effectiveFocus = pWin = inputFocus;
538805b261ecSmrg    }
538905b261ecSmrg    else
539035c4bbdfSmrg        dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess);
539105b261ecSmrg
539205b261ecSmrg    if (!pWin)
539335c4bbdfSmrg        return BadWindow;
539435c4bbdfSmrg    if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) {
539535c4bbdfSmrg        client->errorValue = stuff->propagate;
539635c4bbdfSmrg        return BadValue;
539705b261ecSmrg    }
5398475c125cSmrg    stuff->event.u.u.type |= SEND_EVENT_BIT;
539935c4bbdfSmrg    if (stuff->propagate) {
540035c4bbdfSmrg        for (; pWin; pWin = pWin->parent) {
540135c4bbdfSmrg            if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin,
540235c4bbdfSmrg                         &stuff->event, 1))
540335c4bbdfSmrg                return Success;
54046747b715Smrg            if (DeliverEventsToWindow(dev, pWin,
540535c4bbdfSmrg                                      &stuff->event, 1, stuff->eventMask,
540635c4bbdfSmrg                                      NullGrab))
540735c4bbdfSmrg                return Success;
540835c4bbdfSmrg            if (pWin == effectiveFocus)
540935c4bbdfSmrg                return Success;
541035c4bbdfSmrg            stuff->eventMask &= ~wDontPropagateMask(pWin);
541135c4bbdfSmrg            if (!stuff->eventMask)
541235c4bbdfSmrg                break;
541335c4bbdfSmrg        }
541405b261ecSmrg    }
54154642e01fSmrg    else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1))
54166747b715Smrg        DeliverEventsToWindow(dev, pWin, &stuff->event,
541735c4bbdfSmrg                              1, stuff->eventMask, NullGrab);
541805b261ecSmrg    return Success;
541905b261ecSmrg}
542005b261ecSmrg
542105b261ecSmrg/**
542205b261ecSmrg * Server-side protocol handling for UngrabKey request.
542305b261ecSmrg *
54244642e01fSmrg * Deletes a passive grab for the given key. Works on the
54254642e01fSmrg * client's keyboard.
542605b261ecSmrg */
542705b261ecSmrgint
542805b261ecSmrgProcUngrabKey(ClientPtr client)
542905b261ecSmrg{
543005b261ecSmrg    REQUEST(xUngrabKeyReq);
543105b261ecSmrg    WindowPtr pWin;
543235c4bbdfSmrg    GrabPtr tempGrab;
54334642e01fSmrg    DeviceIntPtr keybd = PickKeyboard(client);
543405b261ecSmrg    int rc;
543505b261ecSmrg
543605b261ecSmrg    REQUEST_SIZE_MATCH(xUngrabKeyReq);
54376747b715Smrg    rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess);
543805b261ecSmrg    if (rc != Success)
543935c4bbdfSmrg        return rc;
544005b261ecSmrg
54416747b715Smrg    if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
544235c4bbdfSmrg         (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
544335c4bbdfSmrg        && (stuff->key != AnyKey)) {
544435c4bbdfSmrg        client->errorValue = stuff->key;
544505b261ecSmrg        return BadValue;
544605b261ecSmrg    }
544705b261ecSmrg    if ((stuff->modifiers != AnyModifier) &&
544835c4bbdfSmrg        (stuff->modifiers & ~AllModifiersMask)) {
544935c4bbdfSmrg        client->errorValue = stuff->modifiers;
545035c4bbdfSmrg        return BadValue;
545135c4bbdfSmrg    }
545235c4bbdfSmrg    tempGrab = AllocGrab(NULL);
545335c4bbdfSmrg    if (!tempGrab)
545435c4bbdfSmrg        return BadAlloc;
545535c4bbdfSmrg    tempGrab->resource = client->clientAsMask;
545635c4bbdfSmrg    tempGrab->device = keybd;
545735c4bbdfSmrg    tempGrab->window = pWin;
545835c4bbdfSmrg    tempGrab->modifiersDetail.exact = stuff->modifiers;
545935c4bbdfSmrg    tempGrab->modifiersDetail.pMask = NULL;
546035c4bbdfSmrg    tempGrab->modifierDevice = keybd;
546135c4bbdfSmrg    tempGrab->type = KeyPress;
546235c4bbdfSmrg    tempGrab->grabtype = CORE;
546335c4bbdfSmrg    tempGrab->detail.exact = stuff->key;
546435c4bbdfSmrg    tempGrab->detail.pMask = NULL;
546535c4bbdfSmrg    tempGrab->next = NULL;
546635c4bbdfSmrg
546735c4bbdfSmrg    if (!DeletePassiveGrabFromList(tempGrab))
546835c4bbdfSmrg        rc = BadAlloc;
546935c4bbdfSmrg
547035c4bbdfSmrg    FreeGrab(tempGrab);
547135c4bbdfSmrg
547235c4bbdfSmrg    return rc;
547305b261ecSmrg}
547405b261ecSmrg
547505b261ecSmrg/**
547605b261ecSmrg * Server-side protocol handling for GrabKey request.
547705b261ecSmrg *
54784642e01fSmrg * Creates a grab for the client's keyboard and adds it to the list of passive
54794642e01fSmrg * grabs.
548005b261ecSmrg */
548105b261ecSmrgint
548205b261ecSmrgProcGrabKey(ClientPtr client)
548305b261ecSmrg{
548405b261ecSmrg    WindowPtr pWin;
548535c4bbdfSmrg
548605b261ecSmrg    REQUEST(xGrabKeyReq);
548705b261ecSmrg    GrabPtr grab;
54884642e01fSmrg    DeviceIntPtr keybd = PickKeyboard(client);
548905b261ecSmrg    int rc;
54906747b715Smrg    GrabParameters param;
54916747b715Smrg    GrabMask mask;
549205b261ecSmrg
549305b261ecSmrg    REQUEST_SIZE_MATCH(xGrabKeyReq);
54946747b715Smrg
549535c4bbdfSmrg    param = (GrabParameters) {
549635c4bbdfSmrg        .grabtype = CORE,
549735c4bbdfSmrg        .ownerEvents = stuff->ownerEvents,
549835c4bbdfSmrg        .this_device_mode = stuff->keyboardMode,
549935c4bbdfSmrg        .other_devices_mode = stuff->pointerMode,
550035c4bbdfSmrg        .modifiers = stuff->modifiers
550135c4bbdfSmrg    };
55026747b715Smrg
55036747b715Smrg    rc = CheckGrabValues(client, &param);
55046747b715Smrg    if (rc != Success)
55056747b715Smrg        return rc;
55066747b715Smrg
55076747b715Smrg    if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
550835c4bbdfSmrg         (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
550935c4bbdfSmrg        && (stuff->key != AnyKey)) {
551035c4bbdfSmrg        client->errorValue = stuff->key;
551105b261ecSmrg        return BadValue;
551205b261ecSmrg    }
55134642e01fSmrg    rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
551405b261ecSmrg    if (rc != Success)
551535c4bbdfSmrg        return rc;
55166747b715Smrg
55176747b715Smrg    mask.core = (KeyPressMask | KeyReleaseMask);
55186747b715Smrg
551935c4bbdfSmrg    grab = CreateGrab(client->index, keybd, keybd, pWin, CORE, &mask,
55206747b715Smrg                      &param, KeyPress, stuff->key, NullWindow, NullCursor);
552105b261ecSmrg    if (!grab)
552235c4bbdfSmrg        return BadAlloc;
55234642e01fSmrg    return AddPassiveGrabToList(client, grab);
552405b261ecSmrg}
552505b261ecSmrg
552605b261ecSmrg/**
552705b261ecSmrg * Server-side protocol handling for GrabButton request.
552805b261ecSmrg *
55294642e01fSmrg * Creates a grab for the client's ClientPointer and adds it as a passive grab
55304642e01fSmrg * to the list.
553105b261ecSmrg */
553205b261ecSmrgint
553305b261ecSmrgProcGrabButton(ClientPtr client)
553405b261ecSmrg{
553505b261ecSmrg    WindowPtr pWin, confineTo;
553635c4bbdfSmrg
553705b261ecSmrg    REQUEST(xGrabButtonReq);
553805b261ecSmrg    CursorPtr cursor;
553905b261ecSmrg    GrabPtr grab;
55404642e01fSmrg    DeviceIntPtr ptr, modifierDevice;
55414642e01fSmrg    Mask access_mode = DixGrabAccess;
55426747b715Smrg    GrabMask mask;
55436747b715Smrg    GrabParameters param;
554405b261ecSmrg    int rc;
554505b261ecSmrg
554605b261ecSmrg    REQUEST_SIZE_MATCH(xGrabButtonReq);
554705b261ecSmrg    if ((stuff->pointerMode != GrabModeSync) &&
554835c4bbdfSmrg        (stuff->pointerMode != GrabModeAsync)) {
554935c4bbdfSmrg        client->errorValue = stuff->pointerMode;
555005b261ecSmrg        return BadValue;
555105b261ecSmrg    }
555205b261ecSmrg    if ((stuff->keyboardMode != GrabModeSync) &&
555335c4bbdfSmrg        (stuff->keyboardMode != GrabModeAsync)) {
555435c4bbdfSmrg        client->errorValue = stuff->keyboardMode;
555505b261ecSmrg        return BadValue;
555605b261ecSmrg    }
555705b261ecSmrg    if ((stuff->modifiers != AnyModifier) &&
555835c4bbdfSmrg        (stuff->modifiers & ~AllModifiersMask)) {
555935c4bbdfSmrg        client->errorValue = stuff->modifiers;
556035c4bbdfSmrg        return BadValue;
556105b261ecSmrg    }
556235c4bbdfSmrg    if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) {
556335c4bbdfSmrg        client->errorValue = stuff->ownerEvents;
556435c4bbdfSmrg        return BadValue;
556505b261ecSmrg    }
556635c4bbdfSmrg    if (stuff->eventMask & ~PointerGrabMask) {
556735c4bbdfSmrg        client->errorValue = stuff->eventMask;
556805b261ecSmrg        return BadValue;
556905b261ecSmrg    }
55704642e01fSmrg    rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
557105b261ecSmrg    if (rc != Success)
557235c4bbdfSmrg        return rc;
557305b261ecSmrg    if (stuff->confineTo == None)
557435c4bbdfSmrg        confineTo = NullWindow;
557505b261ecSmrg    else {
557635c4bbdfSmrg        rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
557735c4bbdfSmrg                             DixSetAttrAccess);
557835c4bbdfSmrg        if (rc != Success)
557935c4bbdfSmrg            return rc;
558005b261ecSmrg    }
558105b261ecSmrg    if (stuff->cursor == None)
558235c4bbdfSmrg        cursor = NullCursor;
558335c4bbdfSmrg    else {
558435c4bbdfSmrg        rc = dixLookupResourceByType((void **) &cursor, stuff->cursor,
558535c4bbdfSmrg                                     RT_CURSOR, client, DixUseAccess);
558635c4bbdfSmrg        if (rc != Success) {
558735c4bbdfSmrg            client->errorValue = stuff->cursor;
558835c4bbdfSmrg            return rc;
558935c4bbdfSmrg        }
559035c4bbdfSmrg        access_mode |= DixForceAccess;
559105b261ecSmrg    }
559205b261ecSmrg
55934642e01fSmrg    ptr = PickPointer(client);
559435c4bbdfSmrg    modifierDevice = GetMaster(ptr, MASTER_KEYBOARD);
55954642e01fSmrg    if (stuff->pointerMode == GrabModeSync ||
559635c4bbdfSmrg        stuff->keyboardMode == GrabModeSync)
559735c4bbdfSmrg        access_mode |= DixFreezeAccess;
55984642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode);
55994642e01fSmrg    if (rc != Success)
560035c4bbdfSmrg        return rc;
560105b261ecSmrg
560235c4bbdfSmrg    param = (GrabParameters) {
560335c4bbdfSmrg        .grabtype = CORE,
560435c4bbdfSmrg        .ownerEvents = stuff->ownerEvents,
560535c4bbdfSmrg        .this_device_mode = stuff->keyboardMode,
560635c4bbdfSmrg        .other_devices_mode = stuff->pointerMode,
560735c4bbdfSmrg        .modifiers = stuff->modifiers
560835c4bbdfSmrg    };
56096747b715Smrg
56106747b715Smrg    mask.core = stuff->eventMask;
56116747b715Smrg
56126747b715Smrg    grab = CreateGrab(client->index, ptr, modifierDevice, pWin,
561335c4bbdfSmrg                      CORE, &mask, &param, ButtonPress,
56146747b715Smrg                      stuff->button, confineTo, cursor);
561505b261ecSmrg    if (!grab)
561635c4bbdfSmrg        return BadAlloc;
56174642e01fSmrg    return AddPassiveGrabToList(client, grab);
561805b261ecSmrg}
561905b261ecSmrg
562005b261ecSmrg/**
562105b261ecSmrg * Server-side protocol handling for UngrabButton request.
562205b261ecSmrg *
56234642e01fSmrg * Deletes a passive grab on the client's ClientPointer from the list.
562405b261ecSmrg */
562505b261ecSmrgint
562605b261ecSmrgProcUngrabButton(ClientPtr client)
562705b261ecSmrg{
562805b261ecSmrg    REQUEST(xUngrabButtonReq);
562905b261ecSmrg    WindowPtr pWin;
563035c4bbdfSmrg    GrabPtr tempGrab;
563105b261ecSmrg    int rc;
56326747b715Smrg    DeviceIntPtr ptr;
563305b261ecSmrg
563405b261ecSmrg    REQUEST_SIZE_MATCH(xUngrabButtonReq);
563505b261ecSmrg    if ((stuff->modifiers != AnyModifier) &&
563635c4bbdfSmrg        (stuff->modifiers & ~AllModifiersMask)) {
563735c4bbdfSmrg        client->errorValue = stuff->modifiers;
563835c4bbdfSmrg        return BadValue;
563905b261ecSmrg    }
564005b261ecSmrg    rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
564105b261ecSmrg    if (rc != Success)
564235c4bbdfSmrg        return rc;
56436747b715Smrg
56446747b715Smrg    ptr = PickPointer(client);
56456747b715Smrg
564635c4bbdfSmrg    tempGrab = AllocGrab(NULL);
564735c4bbdfSmrg    if (!tempGrab)
564835c4bbdfSmrg        return BadAlloc;
564935c4bbdfSmrg    tempGrab->resource = client->clientAsMask;
565035c4bbdfSmrg    tempGrab->device = ptr;
565135c4bbdfSmrg    tempGrab->window = pWin;
565235c4bbdfSmrg    tempGrab->modifiersDetail.exact = stuff->modifiers;
565335c4bbdfSmrg    tempGrab->modifiersDetail.pMask = NULL;
565435c4bbdfSmrg    tempGrab->modifierDevice = GetMaster(ptr, MASTER_KEYBOARD);
565535c4bbdfSmrg    tempGrab->type = ButtonPress;
565635c4bbdfSmrg    tempGrab->detail.exact = stuff->button;
565735c4bbdfSmrg    tempGrab->grabtype = CORE;
565835c4bbdfSmrg    tempGrab->detail.pMask = NULL;
565935c4bbdfSmrg    tempGrab->next = NULL;
566035c4bbdfSmrg
566135c4bbdfSmrg    if (!DeletePassiveGrabFromList(tempGrab))
566235c4bbdfSmrg        rc = BadAlloc;
566335c4bbdfSmrg
566435c4bbdfSmrg    FreeGrab(tempGrab);
566535c4bbdfSmrg    return rc;
566605b261ecSmrg}
566705b261ecSmrg
566805b261ecSmrg/**
566905b261ecSmrg * Deactivate any grab that may be on the window, remove the focus.
567005b261ecSmrg * Delete any XInput extension events from the window too. Does not change the
567105b261ecSmrg * window mask. Use just before the window is deleted.
567205b261ecSmrg *
567305b261ecSmrg * If freeResources is set, passive grabs on the window are deleted.
567405b261ecSmrg *
567505b261ecSmrg * @param pWin The window to delete events from.
567605b261ecSmrg * @param freeResources True if resources associated with the window should be
567705b261ecSmrg * deleted.
567805b261ecSmrg */
567905b261ecSmrgvoid
568005b261ecSmrgDeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources)
568105b261ecSmrg{
568235c4bbdfSmrg    WindowPtr parent;
568335c4bbdfSmrg    DeviceIntPtr mouse = inputInfo.pointer;
568435c4bbdfSmrg    DeviceIntPtr keybd = inputInfo.keyboard;
568535c4bbdfSmrg    FocusClassPtr focus;
568635c4bbdfSmrg    OtherClientsPtr oc;
568735c4bbdfSmrg    GrabPtr passive;
568835c4bbdfSmrg    GrabPtr grab;
568905b261ecSmrg
569005b261ecSmrg    /* Deactivate any grabs performed on this window, before making any
569135c4bbdfSmrg       input focus changes. */
56924642e01fSmrg    grab = mouse->deviceGrab.grab;
569335c4bbdfSmrg    if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
569435c4bbdfSmrg        (*mouse->deviceGrab.DeactivateGrab) (mouse);
569505b261ecSmrg
569605b261ecSmrg    /* Deactivating a keyboard grab should cause focus events. */
56974642e01fSmrg    grab = keybd->deviceGrab.grab;
56984642e01fSmrg    if (grab && (grab->window == pWin))
569935c4bbdfSmrg        (*keybd->deviceGrab.DeactivateGrab) (keybd);
570005b261ecSmrg
57014642e01fSmrg    /* And now the real devices */
570235c4bbdfSmrg    for (mouse = inputInfo.devices; mouse; mouse = mouse->next) {
57034642e01fSmrg        grab = mouse->deviceGrab.grab;
57044642e01fSmrg        if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
570535c4bbdfSmrg            (*mouse->deviceGrab.DeactivateGrab) (mouse);
57064642e01fSmrg    }
570705b261ecSmrg
570835c4bbdfSmrg    for (keybd = inputInfo.devices; keybd; keybd = keybd->next) {
570935c4bbdfSmrg        if (IsKeyboardDevice(keybd)) {
57104642e01fSmrg            focus = keybd->focus;
57114642e01fSmrg
571235c4bbdfSmrg            /* If the focus window is a root window (ie. has no parent)
571335c4bbdfSmrg               then don't delete the focus from it. */
57144642e01fSmrg
571535c4bbdfSmrg            if ((pWin == focus->win) && (pWin->parent != NullWindow)) {
57164642e01fSmrg                int focusEventMode = NotifyNormal;
57174642e01fSmrg
57184642e01fSmrg                /* If a grab is in progress, then alter the mode of focus events. */
57194642e01fSmrg
57204642e01fSmrg                if (keybd->deviceGrab.grab)
57214642e01fSmrg                    focusEventMode = NotifyWhileGrabbed;
57224642e01fSmrg
572335c4bbdfSmrg                switch (focus->revert) {
572435c4bbdfSmrg                case RevertToNone:
572535c4bbdfSmrg                    DoFocusEvents(keybd, pWin, NoneWin, focusEventMode);
572635c4bbdfSmrg                    focus->win = NoneWin;
572735c4bbdfSmrg                    focus->traceGood = 0;
572835c4bbdfSmrg                    break;
572935c4bbdfSmrg                case RevertToParent:
573035c4bbdfSmrg                    parent = pWin;
573135c4bbdfSmrg                    do {
573235c4bbdfSmrg                        parent = parent->parent;
573335c4bbdfSmrg                        focus->traceGood--;
573435c4bbdfSmrg                    } while (!parent->realized
573535c4bbdfSmrg                    /* This would be a good protocol change -- windows being
573635c4bbdfSmrg                       reparented during SaveSet processing would cause the
573735c4bbdfSmrg                       focus to revert to the nearest enclosing window which
573835c4bbdfSmrg                       will survive the death of the exiting client, instead
573935c4bbdfSmrg                       of ending up reverting to a dying window and thence
574035c4bbdfSmrg                       to None */
574105b261ecSmrg#ifdef NOTDEF
574235c4bbdfSmrg                             || wClient(parent)->clientGone
574305b261ecSmrg#endif
574435c4bbdfSmrg                        );
574535c4bbdfSmrg                    if (!ActivateFocusInGrab(keybd, pWin, parent))
574635c4bbdfSmrg                        DoFocusEvents(keybd, pWin, parent, focusEventMode);
574735c4bbdfSmrg                    focus->win = parent;
574835c4bbdfSmrg                    focus->revert = RevertToNone;
574935c4bbdfSmrg                    break;
575035c4bbdfSmrg                case RevertToPointerRoot:
575135c4bbdfSmrg                    if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin))
575235c4bbdfSmrg                        DoFocusEvents(keybd, pWin, PointerRootWin,
575335c4bbdfSmrg                                      focusEventMode);
575435c4bbdfSmrg                    focus->win = PointerRootWin;
575535c4bbdfSmrg                    focus->traceGood = 0;
575635c4bbdfSmrg                    break;
57574642e01fSmrg                }
57584642e01fSmrg            }
57594642e01fSmrg        }
576005b261ecSmrg
576135c4bbdfSmrg        if (IsPointerDevice(keybd)) {
57624642e01fSmrg            if (keybd->valuator->motionHintWindow == pWin)
57634642e01fSmrg                keybd->valuator->motionHintWindow = NullWindow;
57644642e01fSmrg        }
57654642e01fSmrg    }
576605b261ecSmrg
576735c4bbdfSmrg    if (freeResources) {
576835c4bbdfSmrg        if (pWin->dontPropagate)
576935c4bbdfSmrg            DontPropagateRefCnts[pWin->dontPropagate]--;
577035c4bbdfSmrg        while ((oc = wOtherClients(pWin)))
577135c4bbdfSmrg            FreeResource(oc->resource, RT_NONE);
577235c4bbdfSmrg        while ((passive = wPassiveGrabs(pWin)))
577335c4bbdfSmrg            FreeResource(passive->resource, RT_NONE);
577435c4bbdfSmrg    }
57754642e01fSmrg
577605b261ecSmrg    DeleteWindowFromAnyExtEvents(pWin, freeResources);
577705b261ecSmrg}
577805b261ecSmrg
577905b261ecSmrg/**
578005b261ecSmrg * Call this whenever some window at or below pWin has changed geometry. If
578105b261ecSmrg * there is a grab on the window, the cursor will be re-confined into the
578205b261ecSmrg * window.
578305b261ecSmrg */
57846747b715Smrgvoid
578505b261ecSmrgCheckCursorConfinement(WindowPtr pWin)
578605b261ecSmrg{
57874642e01fSmrg    GrabPtr grab;
578805b261ecSmrg    WindowPtr confineTo;
57894642e01fSmrg    DeviceIntPtr pDev;
579005b261ecSmrg
579105b261ecSmrg#ifdef PANORAMIX
579235c4bbdfSmrg    if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
579335c4bbdfSmrg        return;
579405b261ecSmrg#endif
579505b261ecSmrg
579635c4bbdfSmrg    for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
579735c4bbdfSmrg        if (DevHasCursor(pDev)) {
57984642e01fSmrg            grab = pDev->deviceGrab.grab;
579935c4bbdfSmrg            if (grab && (confineTo = grab->confineTo)) {
58004642e01fSmrg                if (!BorderSizeNotEmpty(pDev, confineTo))
580135c4bbdfSmrg                    (*pDev->deviceGrab.DeactivateGrab) (pDev);
58024642e01fSmrg                else if ((pWin == confineTo) || IsParent(pWin, confineTo))
58034642e01fSmrg                    ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE);
58044642e01fSmrg            }
58054642e01fSmrg        }
580605b261ecSmrg    }
580705b261ecSmrg}
580805b261ecSmrg
580905b261ecSmrgMask
581005b261ecSmrgEventMaskForClient(WindowPtr pWin, ClientPtr client)
581105b261ecSmrg{
581235c4bbdfSmrg    OtherClientsPtr other;
581305b261ecSmrg
581435c4bbdfSmrg    if (wClient(pWin) == client)
581535c4bbdfSmrg        return pWin->eventMask;
581635c4bbdfSmrg    for (other = wOtherClients(pWin); other; other = other->next) {
581735c4bbdfSmrg        if (SameClient(other, client))
581835c4bbdfSmrg            return other->mask;
581905b261ecSmrg    }
582005b261ecSmrg    return 0;
582105b261ecSmrg}
582205b261ecSmrg
582305b261ecSmrg/**
582405b261ecSmrg * Server-side protocol handling for RecolorCursor request.
582505b261ecSmrg */
582605b261ecSmrgint
582705b261ecSmrgProcRecolorCursor(ClientPtr client)
582805b261ecSmrg{
582905b261ecSmrg    CursorPtr pCursor;
583035c4bbdfSmrg    int rc, nscr;
583135c4bbdfSmrg    ScreenPtr pscr;
583235c4bbdfSmrg    Bool displayed;
583335c4bbdfSmrg    SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
583435c4bbdfSmrg
583505b261ecSmrg    REQUEST(xRecolorCursorReq);
583605b261ecSmrg
583705b261ecSmrg    REQUEST_SIZE_MATCH(xRecolorCursorReq);
583835c4bbdfSmrg    rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor, RT_CURSOR,
583935c4bbdfSmrg                                 client, DixWriteAccess);
584035c4bbdfSmrg    if (rc != Success) {
584135c4bbdfSmrg        client->errorValue = stuff->cursor;
584235c4bbdfSmrg        return rc;
584305b261ecSmrg    }
584405b261ecSmrg
584505b261ecSmrg    pCursor->foreRed = stuff->foreRed;
584605b261ecSmrg    pCursor->foreGreen = stuff->foreGreen;
584705b261ecSmrg    pCursor->foreBlue = stuff->foreBlue;
584805b261ecSmrg
584905b261ecSmrg    pCursor->backRed = stuff->backRed;
585005b261ecSmrg    pCursor->backGreen = stuff->backGreen;
585105b261ecSmrg    pCursor->backBlue = stuff->backBlue;
585205b261ecSmrg
585335c4bbdfSmrg    for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
585435c4bbdfSmrg        pscr = screenInfo.screens[nscr];
585505b261ecSmrg#ifdef PANORAMIX
585635c4bbdfSmrg        if (!noPanoramiXExtension)
585735c4bbdfSmrg            displayed = (pscr == pSprite->screen);
585835c4bbdfSmrg        else
585905b261ecSmrg#endif
586035c4bbdfSmrg            displayed = (pscr == pSprite->hotPhys.pScreen);
586135c4bbdfSmrg        (*pscr->RecolorCursor) (PickPointer(client), pscr, pCursor,
586235c4bbdfSmrg                                (pCursor == pSprite->current) && displayed);
586305b261ecSmrg    }
58646747b715Smrg    return Success;
586505b261ecSmrg}
586605b261ecSmrg
586705b261ecSmrg/**
586805b261ecSmrg * Write the given events to a client, swapping the byte order if necessary.
586905b261ecSmrg * To swap the byte ordering, a callback is called that has to be set up for
587005b261ecSmrg * the given event type.
587105b261ecSmrg *
587205b261ecSmrg * In the case of DeviceMotionNotify trailed by DeviceValuators, the events
58734642e01fSmrg * can be more than one. Usually it's just one event.
587405b261ecSmrg *
587505b261ecSmrg * Do not modify the event structure passed in. See comment below.
58764642e01fSmrg *
587705b261ecSmrg * @param pClient Client to send events to.
587805b261ecSmrg * @param count Number of events.
587905b261ecSmrg * @param events The event list.
588005b261ecSmrg */
58816747b715Smrgvoid
588205b261ecSmrgWriteEventsToClient(ClientPtr pClient, int count, xEvent *events)
588305b261ecSmrg{
588405b261ecSmrg#ifdef PANORAMIX
588535c4bbdfSmrg    xEvent eventCopy;
588605b261ecSmrg#endif
588735c4bbdfSmrg    xEvent *eventTo, *eventFrom;
588835c4bbdfSmrg    int i, eventlength = sizeof(xEvent);
588905b261ecSmrg
58906747b715Smrg    if (!pClient || pClient == serverClient || pClient->clientGone)
589135c4bbdfSmrg        return;
58926747b715Smrg
58936747b715Smrg    for (i = 0; i < count; i++)
589435c4bbdfSmrg        if ((events[i].u.u.type & 0x7f) != KeymapNotify)
589535c4bbdfSmrg            events[i].u.u.sequenceNumber = pClient->sequence;
58966747b715Smrg
58976747b715Smrg    /* Let XKB rewrite the state, as it depends on client preferences. */
58986747b715Smrg    XkbFilterEvents(pClient, count, events);
589905b261ecSmrg
590005b261ecSmrg#ifdef PANORAMIX
590135c4bbdfSmrg    if (!noPanoramiXExtension &&
590235c4bbdfSmrg        (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) {
590335c4bbdfSmrg        switch (events->u.u.type) {
590435c4bbdfSmrg        case MotionNotify:
590535c4bbdfSmrg        case ButtonPress:
590635c4bbdfSmrg        case ButtonRelease:
590735c4bbdfSmrg        case KeyPress:
590835c4bbdfSmrg        case KeyRelease:
590935c4bbdfSmrg        case EnterNotify:
591035c4bbdfSmrg        case LeaveNotify:
591135c4bbdfSmrg            /*
591235c4bbdfSmrg               When multiple clients want the same event DeliverEventsToWindow
591335c4bbdfSmrg               passes the same event structure multiple times so we can't
591435c4bbdfSmrg               modify the one passed to us
591535c4bbdfSmrg             */
591635c4bbdfSmrg            count = 1;          /* should always be 1 */
591735c4bbdfSmrg            memcpy(&eventCopy, events, sizeof(xEvent));
591835c4bbdfSmrg            eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x;
591935c4bbdfSmrg            eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y;
592035c4bbdfSmrg            if (eventCopy.u.keyButtonPointer.event ==
592135c4bbdfSmrg                eventCopy.u.keyButtonPointer.root) {
592235c4bbdfSmrg                eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x;
592335c4bbdfSmrg                eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y;
592435c4bbdfSmrg            }
592535c4bbdfSmrg            events = &eventCopy;
592635c4bbdfSmrg            break;
592735c4bbdfSmrg        default:
592835c4bbdfSmrg            break;
592935c4bbdfSmrg        }
593005b261ecSmrg    }
593105b261ecSmrg#endif
593205b261ecSmrg
593335c4bbdfSmrg    if (EventCallback) {
593435c4bbdfSmrg        EventInfoRec eventinfo;
593535c4bbdfSmrg
593635c4bbdfSmrg        eventinfo.client = pClient;
593735c4bbdfSmrg        eventinfo.events = events;
593835c4bbdfSmrg        eventinfo.count = count;
593935c4bbdfSmrg        CallCallbacks(&EventCallback, (void *) &eventinfo);
594005b261ecSmrg    }
594105b261ecSmrg#ifdef XSERVER_DTRACE
594205b261ecSmrg    if (XSERVER_SEND_EVENT_ENABLED()) {
594335c4bbdfSmrg        for (i = 0; i < count; i++) {
594435c4bbdfSmrg            XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]);
594535c4bbdfSmrg        }
594605b261ecSmrg    }
59474642e01fSmrg#endif
59484642e01fSmrg    /* Just a safety check to make sure we only have one GenericEvent, it just
59494642e01fSmrg     * makes things easier for me right now. (whot) */
595035c4bbdfSmrg    for (i = 1; i < count; i++) {
595135c4bbdfSmrg        if (events[i].u.u.type == GenericEvent) {
59524642e01fSmrg            ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n");
59534642e01fSmrg            return;
59544642e01fSmrg        }
59554642e01fSmrg    }
59564642e01fSmrg
595735c4bbdfSmrg    if (events->u.u.type == GenericEvent) {
595835c4bbdfSmrg        eventlength += ((xGenericEvent *) events)->length * 4;
59594642e01fSmrg    }
59604642e01fSmrg
596135c4bbdfSmrg    if (pClient->swapped) {
596235c4bbdfSmrg        if (eventlength > swapEventLen) {
59634642e01fSmrg            swapEventLen = eventlength;
59646747b715Smrg            swapEvent = realloc(swapEvent, swapEventLen);
596535c4bbdfSmrg            if (!swapEvent) {
59664642e01fSmrg                FatalError("WriteEventsToClient: Out of memory.\n");
59674642e01fSmrg                return;
59684642e01fSmrg            }
59694642e01fSmrg        }
59704642e01fSmrg
597135c4bbdfSmrg        for (i = 0; i < count; i++) {
597235c4bbdfSmrg            eventFrom = &events[i];
59734642e01fSmrg            eventTo = swapEvent;
59744642e01fSmrg
597535c4bbdfSmrg            /* Remember to strip off the leading bit of type in case
597635c4bbdfSmrg               this event was sent with "SendEvent." */
597735c4bbdfSmrg            (*EventSwapVector[eventFrom->u.u.type & 0177])
597835c4bbdfSmrg                (eventFrom, eventTo);
59794642e01fSmrg
598035c4bbdfSmrg            WriteToClient(pClient, eventlength, eventTo);
598135c4bbdfSmrg        }
598205b261ecSmrg    }
598335c4bbdfSmrg    else {
59844642e01fSmrg        /* only one GenericEvent, remember? that means either count is 1 and
59854642e01fSmrg         * eventlength is arbitrary or eventlength is 32 and count doesn't
59864642e01fSmrg         * matter. And we're all set. Woohoo. */
598735c4bbdfSmrg        WriteToClient(pClient, count * eventlength, events);
598805b261ecSmrg    }
598905b261ecSmrg}
59904642e01fSmrg
59914642e01fSmrg/*
59926747b715Smrg * Set the client pointer for the given client.
59934642e01fSmrg *
59944642e01fSmrg * A client can have exactly one ClientPointer. Each time a
59954642e01fSmrg * request/reply/event is processed and the choice of devices is ambiguous
59964642e01fSmrg * (e.g. QueryPointer request), the server will pick the ClientPointer (see
59974642e01fSmrg * PickPointer()).
59984642e01fSmrg * If a keyboard is needed, the first keyboard paired with the CP is used.
59994642e01fSmrg */
60006747b715Smrgint
60016747b715SmrgSetClientPointer(ClientPtr client, DeviceIntPtr device)
60024642e01fSmrg{
60036747b715Smrg    int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess);
600435c4bbdfSmrg
60056747b715Smrg    if (rc != Success)
600635c4bbdfSmrg        return rc;
60076747b715Smrg
600835c4bbdfSmrg    if (!IsMaster(device)) {
60094642e01fSmrg        ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n");
60106747b715Smrg        return BadDevice;
601135c4bbdfSmrg    }
601235c4bbdfSmrg    else if (!device->spriteInfo->spriteOwner) {
60134642e01fSmrg        ErrorF("[dix] Device %d does not have a sprite. "
601435c4bbdfSmrg               "Cannot be ClientPointer\n", device->id);
60156747b715Smrg        return BadDevice;
60164642e01fSmrg    }
60174642e01fSmrg    client->clientPtr = device;
60186747b715Smrg    return Success;
60194642e01fSmrg}
60204642e01fSmrg
60214642e01fSmrg/* PickPointer will pick an appropriate pointer for the given client.
60224642e01fSmrg *
60234642e01fSmrg * An "appropriate device" is (in order of priority):
60244642e01fSmrg *  1) A device the given client has a core grab on.
60254642e01fSmrg *  2) A device set as ClientPointer for the given client.
60264642e01fSmrg *  3) The first master device.
60274642e01fSmrg */
60286747b715SmrgDeviceIntPtr
60294642e01fSmrgPickPointer(ClientPtr client)
60304642e01fSmrg{
60314642e01fSmrg    DeviceIntPtr it = inputInfo.devices;
60324642e01fSmrg
60334642e01fSmrg    /* First, check if the client currently has a grab on a device. Even
60344642e01fSmrg     * keyboards count. */
603535c4bbdfSmrg    for (it = inputInfo.devices; it; it = it->next) {
60364642e01fSmrg        GrabPtr grab = it->deviceGrab.grab;
603735c4bbdfSmrg
603835c4bbdfSmrg        if (grab && grab->grabtype == CORE && SameClient(grab, client)) {
60396747b715Smrg            it = GetMaster(it, MASTER_POINTER);
604035c4bbdfSmrg            return it;          /* Always return a core grabbed device */
60414642e01fSmrg        }
60424642e01fSmrg    }
60434642e01fSmrg
604435c4bbdfSmrg    if (!client->clientPtr) {
604535c4bbdfSmrg        it = inputInfo.devices;
604635c4bbdfSmrg        while (it) {
604735c4bbdfSmrg            if (IsMaster(it) && it->spriteInfo->spriteOwner) {
60484642e01fSmrg                client->clientPtr = it;
60494642e01fSmrg                break;
60504642e01fSmrg            }
60514642e01fSmrg            it = it->next;
60524642e01fSmrg        }
60534642e01fSmrg    }
60544642e01fSmrg    return client->clientPtr;
60554642e01fSmrg}
60564642e01fSmrg
60574642e01fSmrg/* PickKeyboard will pick an appropriate keyboard for the given client by
60584642e01fSmrg * searching the list of devices for the keyboard device that is paired with
60594642e01fSmrg * the client's pointer.
60604642e01fSmrg */
60616747b715SmrgDeviceIntPtr
60624642e01fSmrgPickKeyboard(ClientPtr client)
60634642e01fSmrg{
60644642e01fSmrg    DeviceIntPtr ptr = PickPointer(client);
60656747b715Smrg    DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD);
60664642e01fSmrg
606735c4bbdfSmrg    if (!kbd) {
60684642e01fSmrg        ErrorF("[dix] ClientPointer not paired with a keyboard. This "
606935c4bbdfSmrg               "is a bug.\n");
60704642e01fSmrg    }
60714642e01fSmrg
60724642e01fSmrg    return kbd;
60734642e01fSmrg}
60744642e01fSmrg
60754642e01fSmrg/* A client that has one or more core grabs does not get core events from
60764642e01fSmrg * devices it does not have a grab on. Legacy applications behave bad
60774642e01fSmrg * otherwise because they are not used to it and the events interfere.
60784642e01fSmrg * Only applies for core events.
60794642e01fSmrg *
60804642e01fSmrg * Return true if a core event from the device would interfere and should not
60814642e01fSmrg * be delivered.
60824642e01fSmrg */
60834642e01fSmrgBool
608435c4bbdfSmrgIsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent *event)
60854642e01fSmrg{
60864642e01fSmrg    DeviceIntPtr it = inputInfo.devices;
60874642e01fSmrg
608835c4bbdfSmrg    switch (event->u.u.type) {
608935c4bbdfSmrg    case KeyPress:
609035c4bbdfSmrg    case KeyRelease:
609135c4bbdfSmrg    case ButtonPress:
609235c4bbdfSmrg    case ButtonRelease:
609335c4bbdfSmrg    case MotionNotify:
609435c4bbdfSmrg    case EnterNotify:
609535c4bbdfSmrg    case LeaveNotify:
609635c4bbdfSmrg        break;
609735c4bbdfSmrg    default:
609835c4bbdfSmrg        return FALSE;
60994642e01fSmrg    }
61004642e01fSmrg
61016747b715Smrg    if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
61026747b715Smrg        return FALSE;
61036747b715Smrg
610435c4bbdfSmrg    while (it) {
610535c4bbdfSmrg        if (it != dev) {
61064642e01fSmrg            if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client)
610735c4bbdfSmrg                && !it->deviceGrab.fromPassiveGrab) {
61084642e01fSmrg                if ((IsPointerDevice(it) && IsPointerDevice(dev)) ||
610935c4bbdfSmrg                    (IsKeyboardDevice(it) && IsKeyboardDevice(dev)))
61104642e01fSmrg                    return TRUE;
61114642e01fSmrg            }
61124642e01fSmrg        }
61134642e01fSmrg        it = it->next;
61144642e01fSmrg    }
61154642e01fSmrg
61164642e01fSmrg    return FALSE;
61174642e01fSmrg}
61184642e01fSmrg
611935c4bbdfSmrg/* PointerBarrier events are only delivered to the client that created that
612035c4bbdfSmrg * barrier */
612135c4bbdfSmrgstatic Bool
612235c4bbdfSmrgIsWrongPointerBarrierClient(ClientPtr client, DeviceIntPtr dev, xEvent *event)
612335c4bbdfSmrg{
612435c4bbdfSmrg    xXIBarrierEvent *ev = (xXIBarrierEvent*)event;
612535c4bbdfSmrg
612635c4bbdfSmrg    if (ev->type != GenericEvent || ev->extension != IReqCode)
612735c4bbdfSmrg        return FALSE;
612835c4bbdfSmrg
612935c4bbdfSmrg    if (ev->evtype != XI_BarrierHit && ev->evtype != XI_BarrierLeave)
613035c4bbdfSmrg        return FALSE;
613135c4bbdfSmrg
613235c4bbdfSmrg    return client->index != CLIENT_ID(ev->barrier);
613335c4bbdfSmrg}
6134