exevents.c revision 35c4bbdf
105b261ecSmrg/************************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1989, 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 1989 by Hewlett-Packard Company, Palo Alto, California.
2605b261ecSmrg
2705b261ecSmrg			All Rights Reserved
2805b261ecSmrg
2905b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3005b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
3205b261ecSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Hewlett-Packard not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
3505b261ecSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgHEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgHEWLETT-PACKARD 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
4735c4bbdfSmrg/*
4835c4bbdfSmrg * Copyright © 2010 Collabora Ltd.
4935c4bbdfSmrg * Copyright © 2011 Red Hat, Inc.
5035c4bbdfSmrg *
5135c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5235c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
5335c4bbdfSmrg * to deal in the Software without restriction, including without limitation
5435c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5535c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
5635c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
5735c4bbdfSmrg *
5835c4bbdfSmrg * The above copyright notice and this permission notice (including the next
5935c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
6035c4bbdfSmrg * Software.
6135c4bbdfSmrg *
6235c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6335c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6435c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6535c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6635c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
6735c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
6835c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
6935c4bbdfSmrg *
7035c4bbdfSmrg * Author: Daniel Stone <daniel@fooishbar.org>
7135c4bbdfSmrg */
7235c4bbdfSmrg
7305b261ecSmrg/********************************************************************
7405b261ecSmrg *
7505b261ecSmrg *  Routines to register and initialize extension input devices.
7605b261ecSmrg *  This also contains ProcessOtherEvent, the routine called from DDX
7705b261ecSmrg *  to route extension events.
7805b261ecSmrg *
7905b261ecSmrg */
8005b261ecSmrg
8105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
8205b261ecSmrg#include <dix-config.h>
8305b261ecSmrg#endif
8405b261ecSmrg
856747b715Smrg#include "inputstr.h"
8605b261ecSmrg#include <X11/X.h>
8705b261ecSmrg#include <X11/Xproto.h>
8805b261ecSmrg#include <X11/extensions/XI.h>
8905b261ecSmrg#include <X11/extensions/XIproto.h>
906747b715Smrg#include <X11/extensions/XI2proto.h>
914642e01fSmrg#include <X11/extensions/geproto.h>
9205b261ecSmrg#include "windowstr.h"
9305b261ecSmrg#include "miscstruct.h"
9405b261ecSmrg#include "region.h"
9505b261ecSmrg#include "exevents.h"
9605b261ecSmrg#include "extnsionst.h"
9705b261ecSmrg#include "exglobals.h"
9835c4bbdfSmrg#include "dixevents.h"          /* DeliverFocusedEvent */
9935c4bbdfSmrg#include "dixgrabs.h"           /* CreateGrab() */
10005b261ecSmrg#include "scrnintstr.h"
10135c4bbdfSmrg#include "listdev.h"            /* for CopySwapXXXClass */
1024642e01fSmrg#include "xace.h"
10335c4bbdfSmrg#include "xiquerydevice.h"      /* For List*Info */
1046747b715Smrg#include "eventconvert.h"
1056747b715Smrg#include "eventstr.h"
10635c4bbdfSmrg#include "inpututils.h"
10735c4bbdfSmrg#include "mi.h"
10805b261ecSmrg
1094642e01fSmrg#include <X11/extensions/XKBproto.h>
11005b261ecSmrg#include "xkbsrv.h"
11105b261ecSmrg
11205b261ecSmrg#define WID(w) ((w) ? ((w)->drawable.id) : 0)
11305b261ecSmrg#define AllModifiersMask ( \
11405b261ecSmrg	ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
11505b261ecSmrg	Mod3Mask | Mod4Mask | Mod5Mask )
11605b261ecSmrg#define AllButtonsMask ( \
11705b261ecSmrg	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
11805b261ecSmrg
1194642e01fSmrgBool ShouldFreeInputMasks(WindowPtr /* pWin */ ,
12035c4bbdfSmrg                          Bool  /* ignoreSelectedEvents */
12105b261ecSmrg    );
12235c4bbdfSmrgstatic Bool MakeInputMasks(WindowPtr    /* pWin */
12305b261ecSmrg    );
12405b261ecSmrg
1256747b715Smrg/*
1266747b715Smrg * Only let the given client know of core events which will affect its
1276747b715Smrg * interpretation of input events, if the client's ClientPointer (or the
1286747b715Smrg * paired keyboard) is the current device.
1296747b715Smrg */
1306747b715Smrgint
1316747b715SmrgXIShouldNotify(ClientPtr client, DeviceIntPtr dev)
1326747b715Smrg{
1336747b715Smrg    DeviceIntPtr current_ptr = PickPointer(client);
13435c4bbdfSmrg    DeviceIntPtr current_kbd = GetMaster(current_ptr, KEYBOARD_OR_FLOAT);
1356747b715Smrg
1366747b715Smrg    if (dev == current_kbd || dev == current_ptr)
1376747b715Smrg        return 1;
1384642e01fSmrg
1396747b715Smrg    return 0;
1406747b715Smrg}
14105b261ecSmrg
1424642e01fSmrgBool
14335c4bbdfSmrgIsPointerEvent(InternalEvent *event)
1444642e01fSmrg{
14535c4bbdfSmrg    switch (event->any.type) {
14635c4bbdfSmrg    case ET_ButtonPress:
14735c4bbdfSmrg    case ET_ButtonRelease:
14835c4bbdfSmrg    case ET_Motion:
14935c4bbdfSmrg        /* XXX: enter/leave ?? */
15035c4bbdfSmrg        return TRUE;
15135c4bbdfSmrg    default:
15235c4bbdfSmrg        break;
15335c4bbdfSmrg    }
15435c4bbdfSmrg    return FALSE;
15535c4bbdfSmrg}
15635c4bbdfSmrg
15735c4bbdfSmrgBool
15835c4bbdfSmrgIsTouchEvent(InternalEvent *event)
15935c4bbdfSmrg{
16035c4bbdfSmrg    switch (event->any.type) {
16135c4bbdfSmrg    case ET_TouchBegin:
16235c4bbdfSmrg    case ET_TouchUpdate:
16335c4bbdfSmrg    case ET_TouchEnd:
16435c4bbdfSmrg        return TRUE;
16535c4bbdfSmrg    default:
16635c4bbdfSmrg        break;
1674642e01fSmrg    }
1684642e01fSmrg    return FALSE;
1694642e01fSmrg}
1704642e01fSmrg
1714642e01fSmrg/**
1724642e01fSmrg * @return the device matching the deviceid of the device set in the event, or
1734642e01fSmrg * NULL if the event is not an XInput event.
1744642e01fSmrg */
1754642e01fSmrgDeviceIntPtr
17635c4bbdfSmrgXIGetDevice(xEvent *xE)
17705b261ecSmrg{
1784642e01fSmrg    DeviceIntPtr pDev = NULL;
1794642e01fSmrg
1804642e01fSmrg    if (xE->u.u.type == DeviceButtonPress ||
1814642e01fSmrg        xE->u.u.type == DeviceButtonRelease ||
1824642e01fSmrg        xE->u.u.type == DeviceMotionNotify ||
1834642e01fSmrg        xE->u.u.type == ProximityIn ||
18435c4bbdfSmrg        xE->u.u.type == ProximityOut || xE->u.u.type == DevicePropertyNotify) {
1854642e01fSmrg        int rc;
1864642e01fSmrg        int id;
1874642e01fSmrg
18835c4bbdfSmrg        id = ((deviceKeyButtonPointer *) xE)->deviceid & ~MORE_EVENTS;
1894642e01fSmrg
1904642e01fSmrg        rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess);
1914642e01fSmrg        if (rc != Success)
1924642e01fSmrg            ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc);
1934642e01fSmrg    }
1944642e01fSmrg    return pDev;
1954642e01fSmrg}
1964642e01fSmrg
1974642e01fSmrg/**
1984642e01fSmrg * Copy the device->key into master->key and send a mapping notify to the
1994642e01fSmrg * clients if appropriate.
2004642e01fSmrg * master->key needs to be allocated by the caller.
2014642e01fSmrg *
2024642e01fSmrg * Device is the slave device. If it is attached to a master device, we may
2034642e01fSmrg * need to send a mapping notify to the client because it causes the MD
2044642e01fSmrg * to change state.
2054642e01fSmrg *
2064642e01fSmrg * Mapping notify needs to be sent in the following cases:
2074642e01fSmrg *      - different slave device on same master
2084642e01fSmrg *      - different master
2094642e01fSmrg *
2104642e01fSmrg * XXX: They way how the code is we also send a map notify if the slave device
2114642e01fSmrg * stays the same, but the master changes. This isn't really necessary though.
2124642e01fSmrg *
2134642e01fSmrg * XXX: this gives you funny behaviour with the ClientPointer. When a
2144642e01fSmrg * MappingNotify is sent to the client, the client usually responds with a
2154642e01fSmrg * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
2164642e01fSmrg * mapping, regardless of which keyboard sent the last mapping notify request.
2174642e01fSmrg * So depending on the CP setting, your keyboard may change layout in each
2184642e01fSmrg * app...
2194642e01fSmrg *
2204642e01fSmrg * This code is basically the old SwitchCoreKeyboard.
2214642e01fSmrg */
2224642e01fSmrg
2234642e01fSmrgvoid
2244642e01fSmrgCopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
2254642e01fSmrg{
2266747b715Smrg    KeyClassPtr mk = master->key;
2274642e01fSmrg
2284642e01fSmrg    if (device == master)
2294642e01fSmrg        return;
2304642e01fSmrg
2316747b715Smrg    mk->sourceid = device->id;
2324642e01fSmrg
23335c4bbdfSmrg    if (!XkbDeviceApplyKeymap(master, device->key->xkbInfo->desc))
2346747b715Smrg        FatalError("Couldn't pivot keymap from device to core!\n");
2354642e01fSmrg}
23605b261ecSmrg
2374642e01fSmrg/**
2384642e01fSmrg * Copies the feedback classes from device "from" into device "to". Classes
2394642e01fSmrg * are duplicated (not just flipping the pointers). All feedback classes are
2404642e01fSmrg * linked lists, the full list is duplicated.
2414642e01fSmrg */
2424642e01fSmrgstatic void
2434642e01fSmrgDeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
2444642e01fSmrg{
2454642e01fSmrg    ClassesPtr classes;
2464642e01fSmrg
24735c4bbdfSmrg    if (from->intfeed) {
2484642e01fSmrg        IntegerFeedbackPtr *i, it;
2494642e01fSmrg
25035c4bbdfSmrg        if (!to->intfeed) {
2516747b715Smrg            classes = to->unused_classes;
2524642e01fSmrg            to->intfeed = classes->intfeed;
2536747b715Smrg            classes->intfeed = NULL;
2544642e01fSmrg        }
2554642e01fSmrg
2564642e01fSmrg        i = &to->intfeed;
25735c4bbdfSmrg        for (it = from->intfeed; it; it = it->next) {
25835c4bbdfSmrg            if (!(*i)) {
2596747b715Smrg                *i = calloc(1, sizeof(IntegerFeedbackClassRec));
26035c4bbdfSmrg                if (!(*i)) {
2614642e01fSmrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
2624642e01fSmrg                    return;
2634642e01fSmrg                }
2644642e01fSmrg            }
2654642e01fSmrg            (*i)->CtrlProc = it->CtrlProc;
26635c4bbdfSmrg            (*i)->ctrl = it->ctrl;
2674642e01fSmrg
2684642e01fSmrg            i = &(*i)->next;
2694642e01fSmrg        }
27035c4bbdfSmrg    }
27135c4bbdfSmrg    else if (to->intfeed && !from->intfeed) {
2726747b715Smrg        classes = to->unused_classes;
2734642e01fSmrg        classes->intfeed = to->intfeed;
27435c4bbdfSmrg        to->intfeed = NULL;
2754642e01fSmrg    }
2764642e01fSmrg
27735c4bbdfSmrg    if (from->stringfeed) {
2784642e01fSmrg        StringFeedbackPtr *s, it;
2794642e01fSmrg
28035c4bbdfSmrg        if (!to->stringfeed) {
2816747b715Smrg            classes = to->unused_classes;
2824642e01fSmrg            to->stringfeed = classes->stringfeed;
2836747b715Smrg            classes->stringfeed = NULL;
2844642e01fSmrg        }
2854642e01fSmrg
2864642e01fSmrg        s = &to->stringfeed;
28735c4bbdfSmrg        for (it = from->stringfeed; it; it = it->next) {
28835c4bbdfSmrg            if (!(*s)) {
2896747b715Smrg                *s = calloc(1, sizeof(StringFeedbackClassRec));
29035c4bbdfSmrg                if (!(*s)) {
2914642e01fSmrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
2924642e01fSmrg                    return;
2934642e01fSmrg                }
2944642e01fSmrg            }
2954642e01fSmrg            (*s)->CtrlProc = it->CtrlProc;
29635c4bbdfSmrg            (*s)->ctrl = it->ctrl;
2974642e01fSmrg
2984642e01fSmrg            s = &(*s)->next;
2994642e01fSmrg        }
30035c4bbdfSmrg    }
30135c4bbdfSmrg    else if (to->stringfeed && !from->stringfeed) {
3026747b715Smrg        classes = to->unused_classes;
3034642e01fSmrg        classes->stringfeed = to->stringfeed;
30435c4bbdfSmrg        to->stringfeed = NULL;
3054642e01fSmrg    }
3064642e01fSmrg
30735c4bbdfSmrg    if (from->bell) {
3084642e01fSmrg        BellFeedbackPtr *b, it;
3094642e01fSmrg
31035c4bbdfSmrg        if (!to->bell) {
3116747b715Smrg            classes = to->unused_classes;
3124642e01fSmrg            to->bell = classes->bell;
3136747b715Smrg            classes->bell = NULL;
3144642e01fSmrg        }
3154642e01fSmrg
3164642e01fSmrg        b = &to->bell;
31735c4bbdfSmrg        for (it = from->bell; it; it = it->next) {
31835c4bbdfSmrg            if (!(*b)) {
3196747b715Smrg                *b = calloc(1, sizeof(BellFeedbackClassRec));
32035c4bbdfSmrg                if (!(*b)) {
3214642e01fSmrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
3224642e01fSmrg                    return;
3234642e01fSmrg                }
3244642e01fSmrg            }
3254642e01fSmrg            (*b)->BellProc = it->BellProc;
3264642e01fSmrg            (*b)->CtrlProc = it->CtrlProc;
32735c4bbdfSmrg            (*b)->ctrl = it->ctrl;
3284642e01fSmrg
3294642e01fSmrg            b = &(*b)->next;
3304642e01fSmrg        }
33135c4bbdfSmrg    }
33235c4bbdfSmrg    else if (to->bell && !from->bell) {
3336747b715Smrg        classes = to->unused_classes;
3344642e01fSmrg        classes->bell = to->bell;
33535c4bbdfSmrg        to->bell = NULL;
3364642e01fSmrg    }
3374642e01fSmrg
33835c4bbdfSmrg    if (from->leds) {
3394642e01fSmrg        LedFeedbackPtr *l, it;
3404642e01fSmrg
34135c4bbdfSmrg        if (!to->leds) {
3426747b715Smrg            classes = to->unused_classes;
3434642e01fSmrg            to->leds = classes->leds;
3446747b715Smrg            classes->leds = NULL;
3454642e01fSmrg        }
3464642e01fSmrg
3474642e01fSmrg        l = &to->leds;
34835c4bbdfSmrg        for (it = from->leds; it; it = it->next) {
34935c4bbdfSmrg            if (!(*l)) {
3506747b715Smrg                *l = calloc(1, sizeof(LedFeedbackClassRec));
35135c4bbdfSmrg                if (!(*l)) {
3524642e01fSmrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
3534642e01fSmrg                    return;
3544642e01fSmrg                }
3554642e01fSmrg            }
3564642e01fSmrg            (*l)->CtrlProc = it->CtrlProc;
35735c4bbdfSmrg            (*l)->ctrl = it->ctrl;
3584642e01fSmrg            if ((*l)->xkb_sli)
3594642e01fSmrg                XkbFreeSrvLedInfo((*l)->xkb_sli);
3604642e01fSmrg            (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l);
3614642e01fSmrg
3624642e01fSmrg            l = &(*l)->next;
3634642e01fSmrg        }
36435c4bbdfSmrg    }
36535c4bbdfSmrg    else if (to->leds && !from->leds) {
3666747b715Smrg        classes = to->unused_classes;
3674642e01fSmrg        classes->leds = to->leds;
36835c4bbdfSmrg        to->leds = NULL;
3694642e01fSmrg    }
3704642e01fSmrg}
3714642e01fSmrg
3726747b715Smrgstatic void
3736747b715SmrgDeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to)
3744642e01fSmrg{
3754642e01fSmrg    ClassesPtr classes;
3764642e01fSmrg
3774642e01fSmrg    /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the
3784642e01fSmrg     * kbdfeed to be set up properly, so let's do the feedback classes first.
3794642e01fSmrg     */
38035c4bbdfSmrg    if (from->kbdfeed) {
3816747b715Smrg        KbdFeedbackPtr *k, it;
3826747b715Smrg
38335c4bbdfSmrg        if (!to->kbdfeed) {
3846747b715Smrg            classes = to->unused_classes;
3856747b715Smrg
3866747b715Smrg            to->kbdfeed = classes->kbdfeed;
3876747b715Smrg            if (!to->kbdfeed)
3886747b715Smrg                InitKeyboardDeviceStruct(to, NULL, NULL, NULL);
3896747b715Smrg            classes->kbdfeed = NULL;
3906747b715Smrg        }
3916747b715Smrg
3926747b715Smrg        k = &to->kbdfeed;
39335c4bbdfSmrg        for (it = from->kbdfeed; it; it = it->next) {
39435c4bbdfSmrg            if (!(*k)) {
3956747b715Smrg                *k = calloc(1, sizeof(KbdFeedbackClassRec));
39635c4bbdfSmrg                if (!*k) {
3976747b715Smrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
3986747b715Smrg                    return;
3996747b715Smrg                }
4006747b715Smrg            }
4016747b715Smrg            (*k)->BellProc = it->BellProc;
4026747b715Smrg            (*k)->CtrlProc = it->CtrlProc;
40335c4bbdfSmrg            (*k)->ctrl = it->ctrl;
4046747b715Smrg            if ((*k)->xkb_sli)
4056747b715Smrg                XkbFreeSrvLedInfo((*k)->xkb_sli);
4066747b715Smrg            (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL);
4076747b715Smrg
4086747b715Smrg            k = &(*k)->next;
4096747b715Smrg        }
41035c4bbdfSmrg    }
41135c4bbdfSmrg    else if (to->kbdfeed && !from->kbdfeed) {
4126747b715Smrg        classes = to->unused_classes;
4136747b715Smrg        classes->kbdfeed = to->kbdfeed;
41435c4bbdfSmrg        to->kbdfeed = NULL;
4156747b715Smrg    }
4164642e01fSmrg
41735c4bbdfSmrg    if (from->key) {
41835c4bbdfSmrg        if (!to->key) {
4196747b715Smrg            classes = to->unused_classes;
4204642e01fSmrg            to->key = classes->key;
4214642e01fSmrg            if (!to->key)
4226747b715Smrg                InitKeyboardDeviceStruct(to, NULL, NULL, NULL);
4236747b715Smrg            else
4246747b715Smrg                classes->key = NULL;
4256747b715Smrg        }
4266747b715Smrg
4276747b715Smrg        CopyKeyClass(from, to);
42835c4bbdfSmrg    }
42935c4bbdfSmrg    else if (to->key && !from->key) {
4306747b715Smrg        classes = to->unused_classes;
4316747b715Smrg        classes->key = to->key;
43235c4bbdfSmrg        to->key = NULL;
4336747b715Smrg    }
4346747b715Smrg
4356747b715Smrg    /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps
4366747b715Smrg     * pointer point into the xkbInfo->desc struct.  XkbCopySrvLedInfo
4376747b715Smrg     * didn't update the pointers so we need to do it manually here.
4386747b715Smrg     */
43935c4bbdfSmrg    if (to->kbdfeed) {
4406747b715Smrg        KbdFeedbackPtr k;
4416747b715Smrg
44235c4bbdfSmrg        for (k = to->kbdfeed; k; k = k->next) {
4436747b715Smrg            if (!k->xkb_sli)
4446747b715Smrg                continue;
44535c4bbdfSmrg            if (k->xkb_sli->flags & XkbSLI_IsDefault) {
4466747b715Smrg                k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators;
4476747b715Smrg                k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps;
4486747b715Smrg            }
4496747b715Smrg        }
4506747b715Smrg    }
4516747b715Smrg
4526747b715Smrg    /* We can't just copy over the focus class. When an app sets the focus,
4536747b715Smrg     * it'll do so on the master device. Copying the SDs focus means losing
4546747b715Smrg     * the focus.
4556747b715Smrg     * So we only copy the focus class if the device didn't have one,
4566747b715Smrg     * otherwise we leave it as it is.
4576747b715Smrg     */
45835c4bbdfSmrg    if (from->focus) {
45935c4bbdfSmrg        if (!to->focus) {
4606747b715Smrg            WindowPtr *oldTrace;
4616747b715Smrg
4626747b715Smrg            classes = to->unused_classes;
4636747b715Smrg            to->focus = classes->focus;
46435c4bbdfSmrg            if (!to->focus) {
4656747b715Smrg                to->focus = calloc(1, sizeof(FocusClassRec));
4666747b715Smrg                if (!to->focus)
4674642e01fSmrg                    FatalError("[Xi] no memory for class shift.\n");
46835c4bbdfSmrg            }
46935c4bbdfSmrg            else
4706747b715Smrg                classes->focus = NULL;
4716747b715Smrg
4726747b715Smrg            oldTrace = to->focus->trace;
4736747b715Smrg            memcpy(to->focus, from->focus, sizeof(FocusClassRec));
47435c4bbdfSmrg            to->focus->trace = reallocarray(oldTrace,
47535c4bbdfSmrg                                            to->focus->traceSize,
47635c4bbdfSmrg                                            sizeof(WindowPtr));
4776747b715Smrg            if (!to->focus->trace && to->focus->traceSize)
4786747b715Smrg                FatalError("[Xi] no memory for trace.\n");
4796747b715Smrg            memcpy(to->focus->trace, from->focus->trace,
48035c4bbdfSmrg                   from->focus->traceSize * sizeof(WindowPtr));
4816747b715Smrg            to->focus->sourceid = from->id;
4824642e01fSmrg        }
48335c4bbdfSmrg    }
48435c4bbdfSmrg    else if (to->focus) {
4856747b715Smrg        classes = to->unused_classes;
4866747b715Smrg        classes->focus = to->focus;
48735c4bbdfSmrg        to->focus = NULL;
4886747b715Smrg    }
4894642e01fSmrg
4906747b715Smrg}
4914642e01fSmrg
49235c4bbdfSmrg/* FIXME: this should really be shared with the InitValuatorAxisClassRec and
49335c4bbdfSmrg * similar */
4946747b715Smrgstatic void
4956747b715SmrgDeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
4966747b715Smrg{
4976747b715Smrg    ClassesPtr classes;
4986747b715Smrg
4996747b715Smrg    /* Feedback classes must be copied first */
50035c4bbdfSmrg    if (from->ptrfeed) {
5016747b715Smrg        PtrFeedbackPtr *p, it;
50235c4bbdfSmrg
50335c4bbdfSmrg        if (!to->ptrfeed) {
5046747b715Smrg            classes = to->unused_classes;
5056747b715Smrg            to->ptrfeed = classes->ptrfeed;
5066747b715Smrg            classes->ptrfeed = NULL;
5074642e01fSmrg        }
5084642e01fSmrg
5096747b715Smrg        p = &to->ptrfeed;
51035c4bbdfSmrg        for (it = from->ptrfeed; it; it = it->next) {
51135c4bbdfSmrg            if (!(*p)) {
5126747b715Smrg                *p = calloc(1, sizeof(PtrFeedbackClassRec));
51335c4bbdfSmrg                if (!*p) {
5146747b715Smrg                    ErrorF("[Xi] Cannot alloc memory for class copy.");
5156747b715Smrg                    return;
5166747b715Smrg                }
5176747b715Smrg            }
5186747b715Smrg            (*p)->CtrlProc = it->CtrlProc;
51935c4bbdfSmrg            (*p)->ctrl = it->ctrl;
5204642e01fSmrg
5216747b715Smrg            p = &(*p)->next;
5226747b715Smrg        }
52335c4bbdfSmrg    }
52435c4bbdfSmrg    else if (to->ptrfeed && !from->ptrfeed) {
5256747b715Smrg        classes = to->unused_classes;
5266747b715Smrg        classes->ptrfeed = to->ptrfeed;
52735c4bbdfSmrg        to->ptrfeed = NULL;
5284642e01fSmrg    }
5294642e01fSmrg
53035c4bbdfSmrg    if (from->valuator) {
5314642e01fSmrg        ValuatorClassPtr v;
5329ace9065Smrg
53335c4bbdfSmrg        if (!to->valuator) {
5346747b715Smrg            classes = to->unused_classes;
5354642e01fSmrg            to->valuator = classes->valuator;
5364642e01fSmrg            if (to->valuator)
5374642e01fSmrg                classes->valuator = NULL;
5384642e01fSmrg        }
5394642e01fSmrg
5409ace9065Smrg        v = AllocValuatorClass(to->valuator, from->valuator->numAxes);
5419ace9065Smrg
5424642e01fSmrg        if (!v)
5434642e01fSmrg            FatalError("[Xi] no memory for class shift.\n");
5444642e01fSmrg
5459ace9065Smrg        to->valuator = v;
5464642e01fSmrg        memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo));
5474642e01fSmrg
5486747b715Smrg        v->sourceid = from->id;
54935c4bbdfSmrg    }
55035c4bbdfSmrg    else if (to->valuator && !from->valuator) {
5516747b715Smrg        classes = to->unused_classes;
5524642e01fSmrg        classes->valuator = to->valuator;
55335c4bbdfSmrg        to->valuator = NULL;
5544642e01fSmrg    }
5554642e01fSmrg
55635c4bbdfSmrg    if (from->button) {
55735c4bbdfSmrg        if (!to->button) {
5586747b715Smrg            classes = to->unused_classes;
5594642e01fSmrg            to->button = classes->button;
56035c4bbdfSmrg            if (!to->button) {
5616747b715Smrg                to->button = calloc(1, sizeof(ButtonClassRec));
5624642e01fSmrg                if (!to->button)
5634642e01fSmrg                    FatalError("[Xi] no memory for class shift.\n");
56435c4bbdfSmrg            }
56535c4bbdfSmrg            else
5664642e01fSmrg                classes->button = NULL;
5674642e01fSmrg        }
5684642e01fSmrg
56935c4bbdfSmrg        if (from->button->xkb_acts) {
57035c4bbdfSmrg            if (!to->button->xkb_acts) {
5716747b715Smrg                to->button->xkb_acts = calloc(1, sizeof(XkbAction));
5724642e01fSmrg                if (!to->button->xkb_acts)
5734642e01fSmrg                    FatalError("[Xi] not enough memory for xkb_acts.\n");
5744642e01fSmrg            }
5754642e01fSmrg            memcpy(to->button->xkb_acts, from->button->xkb_acts,
57635c4bbdfSmrg                   sizeof(XkbAction));
57735c4bbdfSmrg        }
57835c4bbdfSmrg        else
5796747b715Smrg            free(to->button->xkb_acts);
5806747b715Smrg
58135c4bbdfSmrg        memcpy(to->button->labels, from->button->labels,
58235c4bbdfSmrg               from->button->numButtons * sizeof(Atom));
5836747b715Smrg        to->button->sourceid = from->id;
58435c4bbdfSmrg    }
58535c4bbdfSmrg    else if (to->button && !from->button) {
5866747b715Smrg        classes = to->unused_classes;
5874642e01fSmrg        classes->button = to->button;
58835c4bbdfSmrg        to->button = NULL;
5894642e01fSmrg    }
5904642e01fSmrg
59135c4bbdfSmrg    if (from->proximity) {
59235c4bbdfSmrg        if (!to->proximity) {
5936747b715Smrg            classes = to->unused_classes;
5944642e01fSmrg            to->proximity = classes->proximity;
59535c4bbdfSmrg            if (!to->proximity) {
5966747b715Smrg                to->proximity = calloc(1, sizeof(ProximityClassRec));
5974642e01fSmrg                if (!to->proximity)
5984642e01fSmrg                    FatalError("[Xi] no memory for class shift.\n");
59935c4bbdfSmrg            }
60035c4bbdfSmrg            else
6014642e01fSmrg                classes->proximity = NULL;
6024642e01fSmrg        }
6034642e01fSmrg        memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec));
6046747b715Smrg        to->proximity->sourceid = from->id;
60535c4bbdfSmrg    }
60635c4bbdfSmrg    else if (to->proximity) {
6076747b715Smrg        classes = to->unused_classes;
6084642e01fSmrg        classes->proximity = to->proximity;
60935c4bbdfSmrg        to->proximity = NULL;
6104642e01fSmrg    }
6114642e01fSmrg
61235c4bbdfSmrg    if (from->touch) {
61335c4bbdfSmrg        TouchClassPtr t, f;
61435c4bbdfSmrg
61535c4bbdfSmrg        if (!to->touch) {
6166747b715Smrg            classes = to->unused_classes;
61735c4bbdfSmrg            to->touch = classes->touch;
61835c4bbdfSmrg            if (!to->touch) {
61935c4bbdfSmrg                int i;
62035c4bbdfSmrg
62135c4bbdfSmrg                to->touch = calloc(1, sizeof(TouchClassRec));
62235c4bbdfSmrg                if (!to->touch)
62335c4bbdfSmrg                    FatalError("[Xi] no memory for class shift.\n");
62435c4bbdfSmrg                to->touch->num_touches = from->touch->num_touches;
62535c4bbdfSmrg                to->touch->touches = calloc(to->touch->num_touches,
62635c4bbdfSmrg                                            sizeof(TouchPointInfoRec));
62735c4bbdfSmrg                for (i = 0; i < to->touch->num_touches; i++)
62835c4bbdfSmrg                    TouchInitTouchPoint(to->touch, to->valuator, i);
62935c4bbdfSmrg                if (!to->touch)
6304642e01fSmrg                    FatalError("[Xi] no memory for class shift.\n");
63135c4bbdfSmrg            }
63235c4bbdfSmrg            else
63335c4bbdfSmrg                classes->touch = NULL;
6344642e01fSmrg        }
63535c4bbdfSmrg
63635c4bbdfSmrg        t = to->touch;
63735c4bbdfSmrg        f = from->touch;
63835c4bbdfSmrg        t->sourceid = f->sourceid;
63935c4bbdfSmrg        t->max_touches = f->max_touches;
64035c4bbdfSmrg        t->mode = f->mode;
64135c4bbdfSmrg        t->buttonsDown = f->buttonsDown;
64235c4bbdfSmrg        t->state = f->state;
64335c4bbdfSmrg        t->motionMask = f->motionMask;
64435c4bbdfSmrg        /* to->touches and to->num_touches are separate on the master,
64535c4bbdfSmrg         * don't copy */
6466747b715Smrg    }
64735c4bbdfSmrg    /* Don't remove touch class if from->touch is non-existent. The to device
64835c4bbdfSmrg     * may have an active touch grab, so we need to keep the touch class record
64935c4bbdfSmrg     * around. */
6506747b715Smrg}
6516747b715Smrg
6526747b715Smrg/**
6536747b715Smrg * Copies the CONTENT of the classes of device from into the classes in device
6546747b715Smrg * to. From and to are identical after finishing.
6556747b715Smrg *
6566747b715Smrg * If to does not have classes from currenly has, the classes are stored in
6576747b715Smrg * to's devPrivates system. Later, we recover it again from there if needed.
6586747b715Smrg * Saves a few memory allocations.
6596747b715Smrg */
6606747b715Smrgvoid
66135c4bbdfSmrgDeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to,
66235c4bbdfSmrg                      DeviceChangedEvent *dce)
6636747b715Smrg{
66435c4bbdfSmrg    OsBlockSIGIO();
66535c4bbdfSmrg
6666747b715Smrg    /* generic feedback classes, not tied to pointer and/or keyboard */
6676747b715Smrg    DeepCopyFeedbackClasses(from, to);
6686747b715Smrg
6696747b715Smrg    if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT))
6706747b715Smrg        DeepCopyKeyboardClasses(from, to);
6716747b715Smrg    if ((dce->flags & DEVCHANGE_POINTER_EVENT))
6726747b715Smrg        DeepCopyPointerClasses(from, to);
6736747b715Smrg
67435c4bbdfSmrg    OsReleaseSIGIO();
67535c4bbdfSmrg}
6766747b715Smrg
6776747b715Smrg/**
6786747b715Smrg * Send an XI2 DeviceChangedEvent to all interested clients.
6796747b715Smrg */
6806747b715Smrgvoid
68135c4bbdfSmrgXISendDeviceChangedEvent(DeviceIntPtr device, DeviceChangedEvent *dce)
6826747b715Smrg{
6836747b715Smrg    xXIDeviceChangedEvent *dcce;
6846747b715Smrg    int rc;
6856747b715Smrg
68635c4bbdfSmrg    rc = EventToXI2((InternalEvent *) dce, (xEvent **) &dcce);
68735c4bbdfSmrg    if (rc != Success) {
6886747b715Smrg        ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc);
6896747b715Smrg        return;
6904642e01fSmrg    }
6916747b715Smrg
6926747b715Smrg    /* we don't actually swap if there's a NullClient, swapping is done
6936747b715Smrg     * later when event is delivered. */
69435c4bbdfSmrg    SendEventToAllWindows(device, XI_DeviceChangedMask, (xEvent *) dcce, 1);
6956747b715Smrg    free(dcce);
6964642e01fSmrg}
6974642e01fSmrg
6986747b715Smrgstatic void
6996747b715SmrgChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce)
7006747b715Smrg{
7016747b715Smrg    DeviceIntPtr slave;
7026747b715Smrg    int rc;
7036747b715Smrg
7046747b715Smrg    /* For now, we don't have devices that change physically. */
7056747b715Smrg    if (!IsMaster(device))
7066747b715Smrg        return;
7076747b715Smrg
7086747b715Smrg    rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess);
7096747b715Smrg
7106747b715Smrg    if (rc != Success)
71135c4bbdfSmrg        return;                 /* Device has disappeared */
7126747b715Smrg
71335c4bbdfSmrg    if (IsMaster(slave))
71435c4bbdfSmrg        return;
71535c4bbdfSmrg
71635c4bbdfSmrg    if (IsFloating(slave))
71735c4bbdfSmrg        return;                 /* set floating since the event */
7186747b715Smrg
71935c4bbdfSmrg    if (GetMaster(slave, MASTER_ATTACHED)->id != dce->masterid)
72035c4bbdfSmrg        return;                 /* not our slave anymore, don't care */
7216747b715Smrg
7226747b715Smrg    /* FIXME: we probably need to send a DCE for the new slave now */
7236747b715Smrg
7246747b715Smrg    device->public.devicePrivate = slave->public.devicePrivate;
7256747b715Smrg
7266747b715Smrg    /* FIXME: the classes may have changed since we generated the event. */
7276747b715Smrg    DeepCopyDeviceClasses(slave, device, dce);
72835c4bbdfSmrg    dce->deviceid = device->id;
72935c4bbdfSmrg    XISendDeviceChangedEvent(device, dce);
73035c4bbdfSmrg}
73135c4bbdfSmrg
73235c4bbdfSmrg/**
73335c4bbdfSmrg * Add state and motionMask to the filter for this event. The protocol
73435c4bbdfSmrg * supports some extra masks for motion when a button is down:
73535c4bbdfSmrg * ButtonXMotionMask and the DeviceButtonMotionMask to trigger only when at
73635c4bbdfSmrg * least one button (or that specific button is down). These masks need to
73735c4bbdfSmrg * be added to the filters for core/XI motion events.
73835c4bbdfSmrg *
73935c4bbdfSmrg * @param device The device to update the mask for
74035c4bbdfSmrg * @param state The current button state mask
74135c4bbdfSmrg * @param motion_mask The motion mask (DeviceButtonMotionMask or 0)
74235c4bbdfSmrg */
74335c4bbdfSmrgstatic void
74435c4bbdfSmrgUpdateDeviceMotionMask(DeviceIntPtr device, unsigned short state,
74535c4bbdfSmrg                       Mask motion_mask)
74635c4bbdfSmrg{
74735c4bbdfSmrg    Mask mask;
74835c4bbdfSmrg
74935c4bbdfSmrg    mask = DevicePointerMotionMask | state | motion_mask;
75035c4bbdfSmrg    SetMaskForEvent(device->id, mask, DeviceMotionNotify);
75135c4bbdfSmrg    mask = PointerMotionMask | state | motion_mask;
75235c4bbdfSmrg    SetMaskForEvent(device->id, mask, MotionNotify);
75335c4bbdfSmrg}
75435c4bbdfSmrg
75535c4bbdfSmrgstatic void
75635c4bbdfSmrgIncreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
75735c4bbdfSmrg                    Mask *motion_mask, unsigned short *state)
75835c4bbdfSmrg{
75935c4bbdfSmrg    if (dev->valuator)
76035c4bbdfSmrg        dev->valuator->motionHintWindow = NullWindow;
76135c4bbdfSmrg
76235c4bbdfSmrg    (*buttons_down)++;
76335c4bbdfSmrg    *motion_mask = DeviceButtonMotionMask;
76435c4bbdfSmrg    if (dev->button->map[key] <= 5)
76535c4bbdfSmrg        *state |= (Button1Mask >> 1) << dev->button->map[key];
76635c4bbdfSmrg}
76735c4bbdfSmrg
76835c4bbdfSmrgstatic void
76935c4bbdfSmrgDecreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
77035c4bbdfSmrg                    Mask *motion_mask, unsigned short *state)
77135c4bbdfSmrg{
77235c4bbdfSmrg    if (dev->valuator)
77335c4bbdfSmrg        dev->valuator->motionHintWindow = NullWindow;
77435c4bbdfSmrg
77535c4bbdfSmrg    if (*buttons_down >= 1 && !--(*buttons_down))
77635c4bbdfSmrg        *motion_mask = 0;
77735c4bbdfSmrg    if (dev->button->map[key] <= 5)
77835c4bbdfSmrg        *state &= ~((Button1Mask >> 1) << dev->button->map[key]);
7796747b715Smrg}
7804642e01fSmrg
7814642e01fSmrg/**
7824642e01fSmrg * Update the device state according to the data in the event.
7834642e01fSmrg *
7844642e01fSmrg * return values are
7854642e01fSmrg *   DEFAULT ... process as normal
7864642e01fSmrg *   DONT_PROCESS ... return immediately from caller
7874642e01fSmrg */
7884642e01fSmrg#define DEFAULT 0
7894642e01fSmrg#define DONT_PROCESS 1
7904642e01fSmrgint
79135c4bbdfSmrgUpdateDeviceState(DeviceIntPtr device, DeviceEvent *event)
7924642e01fSmrg{
7934642e01fSmrg    int i;
79435c4bbdfSmrg    int key = 0, last_valuator;
7954642e01fSmrg
79635c4bbdfSmrg    KeyClassPtr k = NULL;
79735c4bbdfSmrg    ButtonClassPtr b = NULL;
79835c4bbdfSmrg    ValuatorClassPtr v = NULL;
79935c4bbdfSmrg    TouchClassPtr t = NULL;
8004642e01fSmrg
8016747b715Smrg    /* This event is always the first we get, before the actual events with
8026747b715Smrg     * the data. However, the way how the DDX is set up, "device" will
8036747b715Smrg     * actually be the slave device that caused the event.
8046747b715Smrg     */
80535c4bbdfSmrg    switch (event->type) {
80635c4bbdfSmrg    case ET_DeviceChanged:
80735c4bbdfSmrg        ChangeMasterDeviceClasses(device, (DeviceChangedEvent *) event);
80835c4bbdfSmrg        return DONT_PROCESS;    /* event has been sent already */
80935c4bbdfSmrg    case ET_Motion:
81035c4bbdfSmrg    case ET_ButtonPress:
81135c4bbdfSmrg    case ET_ButtonRelease:
81235c4bbdfSmrg    case ET_KeyPress:
81335c4bbdfSmrg    case ET_KeyRelease:
81435c4bbdfSmrg    case ET_ProximityIn:
81535c4bbdfSmrg    case ET_ProximityOut:
81635c4bbdfSmrg    case ET_TouchBegin:
81735c4bbdfSmrg    case ET_TouchUpdate:
81835c4bbdfSmrg    case ET_TouchEnd:
81935c4bbdfSmrg        break;
82035c4bbdfSmrg    default:
82135c4bbdfSmrg        /* other events don't update the device */
82235c4bbdfSmrg        return DEFAULT;
8236747b715Smrg    }
8244642e01fSmrg
8254642e01fSmrg    k = device->key;
8264642e01fSmrg    v = device->valuator;
8274642e01fSmrg    b = device->button;
82835c4bbdfSmrg    t = device->touch;
8294642e01fSmrg
8306747b715Smrg    key = event->detail.key;
8314642e01fSmrg
8326747b715Smrg    /* Update device axis */
8336747b715Smrg    /* Check valuators first */
8346747b715Smrg    last_valuator = -1;
83535c4bbdfSmrg    for (i = 0; i < MAX_VALUATORS; i++) {
83635c4bbdfSmrg        if (BitIsOn(&event->valuators.mask, i)) {
83735c4bbdfSmrg            if (!v) {
8386747b715Smrg                ErrorF("[Xi] Valuators reported for non-valuator device '%s'. "
83935c4bbdfSmrg                       "Ignoring event.\n", device->name);
8406747b715Smrg                return DONT_PROCESS;
84135c4bbdfSmrg            }
84235c4bbdfSmrg            else if (v->numAxes < i) {
8436747b715Smrg                ErrorF("[Xi] Too many valuators reported for device '%s'. "
84435c4bbdfSmrg                       "Ignoring event.\n", device->name);
8456747b715Smrg                return DONT_PROCESS;
8466747b715Smrg            }
8476747b715Smrg            last_valuator = i;
8486747b715Smrg        }
8494642e01fSmrg    }
8504642e01fSmrg
85135c4bbdfSmrg    for (i = 0; i <= last_valuator && i < v->numAxes; i++) {
85235c4bbdfSmrg        /* XXX: Relative/Absolute mode */
8536747b715Smrg        if (BitIsOn(&event->valuators.mask, i))
8546747b715Smrg            v->axisVal[i] = event->valuators.data[i];
8554642e01fSmrg    }
85605b261ecSmrg
8576747b715Smrg    if (event->type == ET_KeyPress) {
85805b261ecSmrg        if (!k)
8594642e01fSmrg            return DONT_PROCESS;
86005b261ecSmrg
86135c4bbdfSmrg        /* don't allow ddx to generate multiple downs, but repeats are okay */
86235c4bbdfSmrg        if (key_is_down(device, key, KEY_PROCESSED) && !event->key_repeat)
86335c4bbdfSmrg            return DONT_PROCESS;
8646747b715Smrg
86535c4bbdfSmrg        if (device->valuator)
86635c4bbdfSmrg            device->valuator->motionHintWindow = NullWindow;
86735c4bbdfSmrg        set_key_down(device, key, KEY_PROCESSED);
86835c4bbdfSmrg    }
86935c4bbdfSmrg    else if (event->type == ET_KeyRelease) {
87005b261ecSmrg        if (!k)
8714642e01fSmrg            return DONT_PROCESS;
87205b261ecSmrg
87335c4bbdfSmrg        if (!key_is_down(device, key, KEY_PROCESSED))   /* guard against duplicates */
87435c4bbdfSmrg            return DONT_PROCESS;
87535c4bbdfSmrg        if (device->valuator)
87635c4bbdfSmrg            device->valuator->motionHintWindow = NullWindow;
87735c4bbdfSmrg        set_key_up(device, key, KEY_PROCESSED);
87835c4bbdfSmrg    }
87935c4bbdfSmrg    else if (event->type == ET_ButtonPress) {
88005b261ecSmrg        if (!b)
8814642e01fSmrg            return DONT_PROCESS;
8824642e01fSmrg
8836747b715Smrg        if (button_is_down(device, key, BUTTON_PROCESSED))
8844642e01fSmrg            return DONT_PROCESS;
8856747b715Smrg
8866747b715Smrg        set_button_down(device, key, BUTTON_PROCESSED);
88735c4bbdfSmrg
8884642e01fSmrg        if (!b->map[key])
8894642e01fSmrg            return DONT_PROCESS;
89035c4bbdfSmrg
89135c4bbdfSmrg        IncreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
89235c4bbdfSmrg                            &b->state);
89335c4bbdfSmrg        UpdateDeviceMotionMask(device, b->state, b->motionMask);
89435c4bbdfSmrg    }
89535c4bbdfSmrg    else if (event->type == ET_ButtonRelease) {
89605b261ecSmrg        if (!b)
8974642e01fSmrg            return DONT_PROCESS;
8984642e01fSmrg
8996747b715Smrg        if (!button_is_down(device, key, BUTTON_PROCESSED))
9004642e01fSmrg            return DONT_PROCESS;
9016747b715Smrg        if (IsMaster(device)) {
9024642e01fSmrg            DeviceIntPtr sd;
9034642e01fSmrg
9044642e01fSmrg            /*
9054642e01fSmrg             * Leave the button down if any slave has the
9064642e01fSmrg             * button still down. Note that this depends on the
9074642e01fSmrg             * event being delivered through the slave first
9084642e01fSmrg             */
9094642e01fSmrg            for (sd = inputInfo.devices; sd; sd = sd->next) {
91035c4bbdfSmrg                if (IsMaster(sd) || GetMaster(sd, MASTER_POINTER) != device)
9114642e01fSmrg                    continue;
9126747b715Smrg                if (!sd->button)
9136747b715Smrg                    continue;
9148223e2f2Smrg                for (i = 1; i <= sd->button->numButtons; i++)
9158223e2f2Smrg                    if (sd->button->map[i] == key &&
9168223e2f2Smrg                        button_is_down(sd, i, BUTTON_PROCESSED))
9178223e2f2Smrg                        return DONT_PROCESS;
9184642e01fSmrg            }
9194642e01fSmrg        }
9206747b715Smrg        set_button_up(device, key, BUTTON_PROCESSED);
9214642e01fSmrg        if (!b->map[key])
9224642e01fSmrg            return DONT_PROCESS;
92335c4bbdfSmrg
92435c4bbdfSmrg        DecreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
92535c4bbdfSmrg                            &b->state);
92635c4bbdfSmrg        UpdateDeviceMotionMask(device, b->state, b->motionMask);
92735c4bbdfSmrg    }
92835c4bbdfSmrg    else if (event->type == ET_ProximityIn)
92935c4bbdfSmrg        device->proximity->in_proximity = TRUE;
9306747b715Smrg    else if (event->type == ET_ProximityOut)
93135c4bbdfSmrg        device->proximity->in_proximity = FALSE;
93235c4bbdfSmrg    else if (event->type == ET_TouchBegin) {
93335c4bbdfSmrg        BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
93435c4bbdfSmrg        BUG_RETURN_VAL(!t, DONT_PROCESS);
9354642e01fSmrg
93635c4bbdfSmrg        if (!b->map[key])
93735c4bbdfSmrg            return DONT_PROCESS;
9384642e01fSmrg
93935c4bbdfSmrg        if (!(event->flags & TOUCH_POINTER_EMULATED) ||
94035c4bbdfSmrg            (event->flags & TOUCH_REPLAYING))
94135c4bbdfSmrg            return DONT_PROCESS;
9426747b715Smrg
94335c4bbdfSmrg        IncreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
94435c4bbdfSmrg                            &t->state);
94535c4bbdfSmrg        UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
94635c4bbdfSmrg    }
94735c4bbdfSmrg    else if (event->type == ET_TouchEnd) {
94835c4bbdfSmrg        BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
94935c4bbdfSmrg        BUG_RETURN_VAL(!t, DONT_PROCESS);
9506747b715Smrg
95135c4bbdfSmrg        if (t->buttonsDown <= 0 || !b->map[key])
95235c4bbdfSmrg            return DONT_PROCESS;
95335c4bbdfSmrg
95435c4bbdfSmrg        if (!(event->flags & TOUCH_POINTER_EMULATED))
95535c4bbdfSmrg            return DONT_PROCESS;
9566747b715Smrg
95735c4bbdfSmrg        DecreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
95835c4bbdfSmrg                            &t->state);
95935c4bbdfSmrg        UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
9606747b715Smrg    }
96135c4bbdfSmrg
96235c4bbdfSmrg    return DEFAULT;
9636747b715Smrg}
9646747b715Smrg
9654642e01fSmrg/**
96635c4bbdfSmrg * A client that does not have the TouchOwnership mask set may not receive a
96735c4bbdfSmrg * TouchBegin event if there is at least one grab active.
9684642e01fSmrg *
96935c4bbdfSmrg * @return TRUE if the client selected for ownership events on the given
97035c4bbdfSmrg * window for this device, FALSE otherwise
9714642e01fSmrg */
97235c4bbdfSmrgstatic inline Bool
97335c4bbdfSmrgTouchClientWantsOwnershipEvents(ClientPtr client, DeviceIntPtr dev,
97435c4bbdfSmrg                                WindowPtr win)
9754642e01fSmrg{
97635c4bbdfSmrg    InputClients *iclient;
9776747b715Smrg
97835c4bbdfSmrg    nt_list_for_each_entry(iclient, wOtherInputMasks(win)->inputClients, next) {
97935c4bbdfSmrg        if (rClient(iclient) != client)
98035c4bbdfSmrg            continue;
9816747b715Smrg
98235c4bbdfSmrg        return xi2mask_isset(iclient->xi2mask, dev, XI_TouchOwnership);
9836747b715Smrg    }
9844642e01fSmrg
98535c4bbdfSmrg    return FALSE;
98635c4bbdfSmrg}
9874642e01fSmrg
98835c4bbdfSmrgstatic void
98935c4bbdfSmrgTouchSendOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, int reason,
99035c4bbdfSmrg                        XID resource)
99135c4bbdfSmrg{
99235c4bbdfSmrg    int nev, i;
99335c4bbdfSmrg    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
9946747b715Smrg
99535c4bbdfSmrg    nev = GetTouchOwnershipEvents(tel, dev, ti, reason, resource, 0);
99635c4bbdfSmrg    for (i = 0; i < nev; i++)
99735c4bbdfSmrg        mieqProcessDeviceEvent(dev, tel + i, NULL);
9986747b715Smrg
99935c4bbdfSmrg    FreeEventList(tel, GetMaximumEventsNum());
100035c4bbdfSmrg}
10016747b715Smrg
100235c4bbdfSmrg/**
100335c4bbdfSmrg * Attempts to deliver a touch event to the given client.
100435c4bbdfSmrg */
100535c4bbdfSmrgstatic Bool
100635c4bbdfSmrgDeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
100735c4bbdfSmrg                     GrabPtr grab, WindowPtr win, InternalEvent *ev)
100835c4bbdfSmrg{
100935c4bbdfSmrg    int err;
101035c4bbdfSmrg    xEvent *xi2;
101135c4bbdfSmrg    Mask filter;
101235c4bbdfSmrg    Window child = DeepestSpriteWin(&ti->sprite)->drawable.id;
101335c4bbdfSmrg
101435c4bbdfSmrg    /* FIXME: owner event handling */
101535c4bbdfSmrg
101635c4bbdfSmrg    /* If the client does not have the ownership mask set and is not
101735c4bbdfSmrg     * the current owner of the touch, only pretend we delivered */
101835c4bbdfSmrg    if (!grab && ti->num_grabs != 0 &&
101935c4bbdfSmrg        !TouchClientWantsOwnershipEvents(client, dev, win))
102035c4bbdfSmrg        return TRUE;
102135c4bbdfSmrg
102235c4bbdfSmrg    /* If we fail here, we're going to leave a client hanging. */
102335c4bbdfSmrg    err = EventToXI2(ev, &xi2);
102435c4bbdfSmrg    if (err != Success)
102535c4bbdfSmrg        FatalError("[Xi] %s: XI2 conversion failed in %s"
102635c4bbdfSmrg                   " (%d)\n", dev->name, __func__, err);
102735c4bbdfSmrg
102835c4bbdfSmrg    FixUpEventFromWindow(&ti->sprite, xi2, win, child, FALSE);
102935c4bbdfSmrg    filter = GetEventFilter(dev, xi2);
103035c4bbdfSmrg    if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
103135c4bbdfSmrg        return FALSE;
103235c4bbdfSmrg    err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
103335c4bbdfSmrg    free(xi2);
103435c4bbdfSmrg
103535c4bbdfSmrg    /* Returning the value from TryClientEvents isn't useful, since all our
103635c4bbdfSmrg     * resource-gone cleanups will update the delivery list anyway. */
103735c4bbdfSmrg    return TRUE;
103835c4bbdfSmrg}
10396747b715Smrg
104035c4bbdfSmrgstatic void
104135c4bbdfSmrgActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
104235c4bbdfSmrg{
104335c4bbdfSmrg    ClientPtr client;
104435c4bbdfSmrg    XID error;
104535c4bbdfSmrg    GrabPtr grab = ti->listeners[0].grab;
10464642e01fSmrg
104735c4bbdfSmrg    BUG_RETURN(ti->listeners[0].type != LISTENER_GRAB &&
104835c4bbdfSmrg               ti->listeners[0].type != LISTENER_POINTER_GRAB);
104935c4bbdfSmrg    BUG_RETURN(!grab);
10504642e01fSmrg
105135c4bbdfSmrg    client = rClient(grab);
10524642e01fSmrg
105335c4bbdfSmrg    if (TouchAcceptReject(client, dev, XIAcceptTouch, ti->client_id,
105435c4bbdfSmrg                          ti->listeners[0].window->drawable.id, &error) != Success)
105535c4bbdfSmrg        ErrorF("[Xi] Failed to accept touch grab after early acceptance.\n");
105635c4bbdfSmrg}
10574642e01fSmrg
105835c4bbdfSmrg/**
105935c4bbdfSmrg * Find the oldest touch that still has a pointer emulation client.
106035c4bbdfSmrg *
106135c4bbdfSmrg * Pointer emulation can only be performed for the oldest touch. Otherwise, the
106235c4bbdfSmrg * order of events seen by the client will be wrong. This function helps us find
106335c4bbdfSmrg * the next touch to be emulated.
106435c4bbdfSmrg *
106535c4bbdfSmrg * @param dev The device to find touches for.
106635c4bbdfSmrg */
106735c4bbdfSmrgstatic TouchPointInfoPtr
106835c4bbdfSmrgFindOldestPointerEmulatedTouch(DeviceIntPtr dev)
106935c4bbdfSmrg{
107035c4bbdfSmrg    TouchPointInfoPtr oldest = NULL;
107135c4bbdfSmrg    int i;
10726747b715Smrg
107335c4bbdfSmrg    for (i = 0; i < dev->touch->num_touches; i++) {
107435c4bbdfSmrg        TouchPointInfoPtr ti = dev->touch->touches + i;
107535c4bbdfSmrg        int j;
10764642e01fSmrg
107735c4bbdfSmrg        if (!ti->active || !ti->emulate_pointer)
107835c4bbdfSmrg            continue;
10794642e01fSmrg
108035c4bbdfSmrg        for (j = 0; j < ti->num_listeners; j++) {
108135c4bbdfSmrg            if (ti->listeners[j].type == LISTENER_POINTER_GRAB ||
108235c4bbdfSmrg                ti->listeners[j].type == LISTENER_POINTER_REGULAR)
108335c4bbdfSmrg                break;
108435c4bbdfSmrg        }
108535c4bbdfSmrg        if (j == ti->num_listeners)
108635c4bbdfSmrg            continue;
10874642e01fSmrg
108835c4bbdfSmrg        if (!oldest) {
108935c4bbdfSmrg            oldest = ti;
109035c4bbdfSmrg            continue;
109135c4bbdfSmrg        }
10924642e01fSmrg
109335c4bbdfSmrg        if (oldest->client_id - ti->client_id < UINT_MAX / 2)
109435c4bbdfSmrg            oldest = ti;
10954642e01fSmrg    }
109605b261ecSmrg
109735c4bbdfSmrg    return oldest;
109805b261ecSmrg}
109905b261ecSmrg
110035c4bbdfSmrg/**
110135c4bbdfSmrg * If the current owner has rejected the event, deliver the
110235c4bbdfSmrg * TouchOwnership/TouchBegin to the next item in the sprite stack.
110335c4bbdfSmrg */
110435c4bbdfSmrgstatic void
110535c4bbdfSmrgTouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
110635c4bbdfSmrg                     TouchOwnershipEvent *ev)
110705b261ecSmrg{
110835c4bbdfSmrg    TouchListener *listener = &ti->listeners[0]; /* new owner */
110935c4bbdfSmrg    int accepted_early = listener->state == LISTENER_EARLY_ACCEPT;
111035c4bbdfSmrg
111135c4bbdfSmrg    /* Deliver the ownership */
111235c4bbdfSmrg    if (listener->state == LISTENER_AWAITING_OWNER || accepted_early)
111335c4bbdfSmrg        DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
111435c4bbdfSmrg                           listener->listener);
111535c4bbdfSmrg    else if (listener->state == LISTENER_AWAITING_BEGIN) {
111635c4bbdfSmrg        /* We can't punt to a pointer listener unless all older pointer
111735c4bbdfSmrg         * emulated touches have been seen already. */
111835c4bbdfSmrg        if ((listener->type == LISTENER_POINTER_GRAB ||
111935c4bbdfSmrg             listener->type == LISTENER_POINTER_REGULAR) &&
112035c4bbdfSmrg            ti != FindOldestPointerEmulatedTouch(dev))
112135c4bbdfSmrg            return;
112205b261ecSmrg
112335c4bbdfSmrg        TouchEventHistoryReplay(ti, dev, listener->listener);
112435c4bbdfSmrg    }
112505b261ecSmrg
112635c4bbdfSmrg    /* New owner has Begin/Update but not end. If touch is pending_finish,
112735c4bbdfSmrg     * emulate the TouchEnd now */
112835c4bbdfSmrg    if (ti->pending_finish) {
112935c4bbdfSmrg        TouchEmitTouchEnd(dev, ti, 0, 0);
113035c4bbdfSmrg
113135c4bbdfSmrg        /* If the last owner is not a touch grab, finalise the touch, we
113235c4bbdfSmrg           won't get more correspondence on this.
113335c4bbdfSmrg         */
113435c4bbdfSmrg        if (ti->num_listeners == 1 &&
113535c4bbdfSmrg            (ti->num_grabs == 0 ||
113635c4bbdfSmrg             listener->grab->grabtype != XI2 ||
113735c4bbdfSmrg             !xi2mask_isset(listener->grab->xi2mask, dev, XI_TouchBegin))) {
113835c4bbdfSmrg            TouchEndTouch(dev, ti);
113935c4bbdfSmrg            return;
114035c4bbdfSmrg        }
114135c4bbdfSmrg    }
114235c4bbdfSmrg
114335c4bbdfSmrg    if (accepted_early)
114435c4bbdfSmrg        ActivateEarlyAccept(dev, ti);
114535c4bbdfSmrg}
114635c4bbdfSmrg
114735c4bbdfSmrg/**
114835c4bbdfSmrg * Check the oldest touch to see if it needs to be replayed to its pointer
114935c4bbdfSmrg * owner.
115035c4bbdfSmrg *
115135c4bbdfSmrg * Touch event propagation is paused if it hits a pointer listener while an
115235c4bbdfSmrg * older touch with a pointer listener is waiting on accept or reject. This
115335c4bbdfSmrg * function will restart propagation of a paused touch if needed.
115435c4bbdfSmrg *
115535c4bbdfSmrg * @param dev The device to check touches for.
115635c4bbdfSmrg */
115735c4bbdfSmrgstatic void
115835c4bbdfSmrgCheckOldestTouch(DeviceIntPtr dev)
115935c4bbdfSmrg{
116035c4bbdfSmrg    TouchPointInfoPtr oldest = FindOldestPointerEmulatedTouch(dev);
116135c4bbdfSmrg
116235c4bbdfSmrg    if (oldest && oldest->listeners[0].state == LISTENER_AWAITING_BEGIN)
116335c4bbdfSmrg        TouchPuntToNextOwner(dev, oldest, NULL);
116435c4bbdfSmrg}
116535c4bbdfSmrg
116635c4bbdfSmrg/**
116735c4bbdfSmrg * Process a touch rejection.
116835c4bbdfSmrg *
116935c4bbdfSmrg * @param sourcedev The source device of the touch sequence.
117035c4bbdfSmrg * @param ti The touchpoint info record.
117135c4bbdfSmrg * @param resource The resource of the client rejecting the touch.
117235c4bbdfSmrg * @param ev TouchOwnership event to send. Set to NULL if no event should be
117335c4bbdfSmrg *        sent.
117435c4bbdfSmrg */
117535c4bbdfSmrgvoid
117635c4bbdfSmrgTouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
117735c4bbdfSmrg              TouchOwnershipEvent *ev)
117835c4bbdfSmrg{
117935c4bbdfSmrg    Bool was_owner = (resource == ti->listeners[0].listener);
118035c4bbdfSmrg    int i;
118135c4bbdfSmrg
118235c4bbdfSmrg    /* Send a TouchEnd event to the resource being removed, but only if they
118335c4bbdfSmrg     * haven't received one yet already */
118435c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++) {
118535c4bbdfSmrg        if (ti->listeners[i].listener == resource) {
118635c4bbdfSmrg            if (ti->listeners[i].state != LISTENER_HAS_END)
118735c4bbdfSmrg                TouchEmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource);
118835c4bbdfSmrg            break;
118935c4bbdfSmrg        }
119035c4bbdfSmrg    }
119135c4bbdfSmrg
119235c4bbdfSmrg    /* Remove the resource from the listener list, updating
119335c4bbdfSmrg     * ti->num_listeners, as well as ti->num_grabs if it was a grab. */
119435c4bbdfSmrg    TouchRemoveListener(ti, resource);
119535c4bbdfSmrg
119635c4bbdfSmrg    /* If the current owner was removed and there are further listeners, deliver
119735c4bbdfSmrg     * the TouchOwnership or TouchBegin event to the new owner. */
119835c4bbdfSmrg    if (ev && ti->num_listeners > 0 && was_owner)
119935c4bbdfSmrg        TouchPuntToNextOwner(sourcedev, ti, ev);
120035c4bbdfSmrg    else if (ti->num_listeners == 0)
120135c4bbdfSmrg        TouchEndTouch(sourcedev, ti);
120235c4bbdfSmrg
120335c4bbdfSmrg    CheckOldestTouch(sourcedev);
120435c4bbdfSmrg}
120535c4bbdfSmrg
120635c4bbdfSmrg/**
120735c4bbdfSmrg * Processes a TouchOwnership event, indicating a grab has accepted the touch
120835c4bbdfSmrg * it currently owns, or a grab or selection has been removed.  Will generate
120935c4bbdfSmrg * and send TouchEnd events to all clients removed from the delivery list, as
121035c4bbdfSmrg * well as possibly sending the new TouchOwnership event.  May end the
121135c4bbdfSmrg * touchpoint if it is pending finish.
121235c4bbdfSmrg */
121335c4bbdfSmrgstatic void
121435c4bbdfSmrgProcessTouchOwnershipEvent(TouchOwnershipEvent *ev,
121535c4bbdfSmrg                           DeviceIntPtr dev)
121635c4bbdfSmrg{
121735c4bbdfSmrg    TouchPointInfoPtr ti = TouchFindByClientID(dev, ev->touchid);
121835c4bbdfSmrg
121935c4bbdfSmrg    if (!ti) {
122035c4bbdfSmrg        DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
122135c4bbdfSmrg               dev->name, ev->type, ev->touchid);
122235c4bbdfSmrg        return;
122335c4bbdfSmrg    }
122435c4bbdfSmrg
122535c4bbdfSmrg    if (ev->reason == XIRejectTouch)
122635c4bbdfSmrg        TouchRejected(dev, ti, ev->resource, ev);
122735c4bbdfSmrg    else if (ev->reason == XIAcceptTouch) {
122835c4bbdfSmrg        int i;
122935c4bbdfSmrg
123035c4bbdfSmrg
123135c4bbdfSmrg        /* For pointer-emulated listeners that ungrabbed the active grab,
123235c4bbdfSmrg         * the state was forced to LISTENER_HAS_END. Still go
123335c4bbdfSmrg         * through the motions of ending the touch if the listener has
123435c4bbdfSmrg         * already seen the end. This ensures that the touch record is ended in
123535c4bbdfSmrg         * the server.
123635c4bbdfSmrg         */
123735c4bbdfSmrg        if (ti->listeners[0].state == LISTENER_HAS_END)
123835c4bbdfSmrg            TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
123935c4bbdfSmrg
124035c4bbdfSmrg        /* The touch owner has accepted the touch.  Send TouchEnd events to
124135c4bbdfSmrg         * everyone else, and truncate the list of listeners. */
124235c4bbdfSmrg        for (i = 1; i < ti->num_listeners; i++)
124335c4bbdfSmrg            TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
124435c4bbdfSmrg
124535c4bbdfSmrg        while (ti->num_listeners > 1)
124635c4bbdfSmrg            TouchRemoveListener(ti, ti->listeners[1].listener);
124735c4bbdfSmrg        /* Owner accepted after receiving end */
124835c4bbdfSmrg        if (ti->listeners[0].state == LISTENER_HAS_END)
124935c4bbdfSmrg            TouchEndTouch(dev, ti);
125035c4bbdfSmrg        else
125135c4bbdfSmrg            ti->listeners[0].state = LISTENER_HAS_ACCEPTED;
125235c4bbdfSmrg    }
125335c4bbdfSmrg    else {  /* this is the very first ownership event for a grab */
125435c4bbdfSmrg        DeliverTouchEvents(dev, ti, (InternalEvent *) ev, ev->resource);
125535c4bbdfSmrg    }
125635c4bbdfSmrg}
125735c4bbdfSmrg
125835c4bbdfSmrg/**
125935c4bbdfSmrg * Copy the event's valuator information into the touchpoint, we may need
126035c4bbdfSmrg * this for emulated TouchEnd events.
126135c4bbdfSmrg */
126235c4bbdfSmrgstatic void
126335c4bbdfSmrgTouchCopyValuatorData(DeviceEvent *ev, TouchPointInfoPtr ti)
126435c4bbdfSmrg{
126535c4bbdfSmrg    int i;
126635c4bbdfSmrg
126735c4bbdfSmrg    for (i = 0; i < ARRAY_SIZE(ev->valuators.data); i++)
126835c4bbdfSmrg        if (BitIsOn(ev->valuators.mask, i))
126935c4bbdfSmrg            valuator_mask_set_double(ti->valuators, i, ev->valuators.data[i]);
127035c4bbdfSmrg}
127135c4bbdfSmrg
127235c4bbdfSmrg/**
127335c4bbdfSmrg * Given a touch event and a potential listener, retrieve info needed for
127435c4bbdfSmrg * processing the event.
127535c4bbdfSmrg *
127635c4bbdfSmrg * @param dev The device generating the touch event.
127735c4bbdfSmrg * @param ti The touch point info record for the touch event.
127835c4bbdfSmrg * @param ev The touch event to process.
127935c4bbdfSmrg * @param listener The touch event listener that may receive the touch event.
128035c4bbdfSmrg * @param[out] client The client that should receive the touch event.
128135c4bbdfSmrg * @param[out] win The window to deliver the event on.
128235c4bbdfSmrg * @param[out] grab The grab to deliver the event through, if any.
128335c4bbdfSmrg * @param[out] mask The XI 2.x event mask of the grab or selection, if any.
128435c4bbdfSmrg * @return TRUE if an event should be delivered to the listener, FALSE
128535c4bbdfSmrg *         otherwise.
128635c4bbdfSmrg */
128735c4bbdfSmrgstatic Bool
128835c4bbdfSmrgRetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
128935c4bbdfSmrg                          InternalEvent *ev, TouchListener * listener,
129035c4bbdfSmrg                          ClientPtr *client, WindowPtr *win, GrabPtr *grab,
129135c4bbdfSmrg                          XI2Mask **mask)
129235c4bbdfSmrg{
129335c4bbdfSmrg    int rc;
129435c4bbdfSmrg    InputClients *iclients = NULL;
129535c4bbdfSmrg    *mask = NULL;
129635c4bbdfSmrg
129735c4bbdfSmrg    if (listener->type == LISTENER_GRAB ||
129835c4bbdfSmrg        listener->type == LISTENER_POINTER_GRAB) {
129935c4bbdfSmrg
130035c4bbdfSmrg        *grab = listener->grab;
130135c4bbdfSmrg
130235c4bbdfSmrg        BUG_RETURN_VAL(!*grab, FALSE);
130335c4bbdfSmrg
130435c4bbdfSmrg        *client = rClient(*grab);
130535c4bbdfSmrg        *win = (*grab)->window;
130635c4bbdfSmrg        *mask = (*grab)->xi2mask;
130735c4bbdfSmrg    }
130835c4bbdfSmrg    else {
130935c4bbdfSmrg        rc = dixLookupResourceByType((void **) win, listener->listener,
131035c4bbdfSmrg                                     listener->resource_type,
131135c4bbdfSmrg                                     serverClient, DixSendAccess);
131235c4bbdfSmrg        if (rc != Success)
131335c4bbdfSmrg            return FALSE;
131435c4bbdfSmrg
131535c4bbdfSmrg        if (listener->level == XI2) {
131635c4bbdfSmrg            int evtype;
131735c4bbdfSmrg
131835c4bbdfSmrg            if (ti->emulate_pointer &&
131935c4bbdfSmrg                listener->type == LISTENER_POINTER_REGULAR)
132035c4bbdfSmrg                evtype = GetXI2Type(TouchGetPointerEventType(ev));
132135c4bbdfSmrg            else
132235c4bbdfSmrg                evtype = GetXI2Type(ev->any.type);
132335c4bbdfSmrg
132435c4bbdfSmrg            nt_list_for_each_entry(iclients,
132535c4bbdfSmrg                                   wOtherInputMasks(*win)->inputClients, next)
132635c4bbdfSmrg                if (xi2mask_isset(iclients->xi2mask, dev, evtype))
132735c4bbdfSmrg                break;
132835c4bbdfSmrg
132935c4bbdfSmrg            BUG_RETURN_VAL(!iclients, FALSE);
133035c4bbdfSmrg
133135c4bbdfSmrg            *mask = iclients->xi2mask;
133235c4bbdfSmrg            *client = rClient(iclients);
133335c4bbdfSmrg        }
133435c4bbdfSmrg        else if (listener->level == XI) {
133535c4bbdfSmrg            int xi_type = GetXIType(TouchGetPointerEventType(ev));
133635c4bbdfSmrg            Mask xi_filter = event_get_filter_from_type(dev, xi_type);
133735c4bbdfSmrg
133835c4bbdfSmrg            nt_list_for_each_entry(iclients,
133935c4bbdfSmrg                                   wOtherInputMasks(*win)->inputClients, next)
134035c4bbdfSmrg                if (iclients->mask[dev->id] & xi_filter)
134135c4bbdfSmrg                break;
134235c4bbdfSmrg            BUG_RETURN_VAL(!iclients, FALSE);
134335c4bbdfSmrg
134435c4bbdfSmrg            *client = rClient(iclients);
134535c4bbdfSmrg        }
134635c4bbdfSmrg        else {
134735c4bbdfSmrg            int coretype = GetCoreType(TouchGetPointerEventType(ev));
134835c4bbdfSmrg            Mask core_filter = event_get_filter_from_type(dev, coretype);
134935c4bbdfSmrg            OtherClients *oclients;
135035c4bbdfSmrg
135135c4bbdfSmrg            /* all others */
135235c4bbdfSmrg            nt_list_for_each_entry(oclients,
135335c4bbdfSmrg                                   (OtherClients *) wOtherClients(*win), next)
135435c4bbdfSmrg                if (oclients->mask & core_filter)
135535c4bbdfSmrg                    break;
135635c4bbdfSmrg
135735c4bbdfSmrg            /* if owner selected, oclients is NULL */
135835c4bbdfSmrg            *client = oclients ? rClient(oclients) : wClient(*win);
135935c4bbdfSmrg        }
136035c4bbdfSmrg
136135c4bbdfSmrg        *grab = NULL;
136235c4bbdfSmrg    }
136335c4bbdfSmrg
136435c4bbdfSmrg    return TRUE;
136535c4bbdfSmrg}
136635c4bbdfSmrg
136735c4bbdfSmrgstatic int
136835c4bbdfSmrgDeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
136935c4bbdfSmrg                          InternalEvent *ev, TouchListener * listener,
137035c4bbdfSmrg                          ClientPtr client, WindowPtr win, GrabPtr grab,
137135c4bbdfSmrg                          XI2Mask *xi2mask)
137235c4bbdfSmrg{
137335c4bbdfSmrg    InternalEvent motion, button;
137435c4bbdfSmrg    InternalEvent *ptrev = &motion;
137535c4bbdfSmrg    int nevents;
137635c4bbdfSmrg    DeviceIntPtr kbd;
137735c4bbdfSmrg
137835c4bbdfSmrg    /* We don't deliver pointer events to non-owners */
137935c4bbdfSmrg    if (!TouchResourceIsOwner(ti, listener->listener))
138035c4bbdfSmrg        return !Success;
138135c4bbdfSmrg
138235c4bbdfSmrg    if (!ti->emulate_pointer)
138335c4bbdfSmrg        return !Success;
138435c4bbdfSmrg
138535c4bbdfSmrg    nevents = TouchConvertToPointerEvent(ev, &motion, &button);
138635c4bbdfSmrg    BUG_RETURN_VAL(nevents == 0, BadValue);
138735c4bbdfSmrg
138835c4bbdfSmrg    if (nevents > 1)
138935c4bbdfSmrg        ptrev = &button;
139035c4bbdfSmrg
139135c4bbdfSmrg    kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
139235c4bbdfSmrg    event_set_state(dev, kbd, &ptrev->device_event);
139335c4bbdfSmrg    ptrev->device_event.corestate = event_get_corestate(dev, kbd);
139435c4bbdfSmrg
139535c4bbdfSmrg    if (grab) {
139635c4bbdfSmrg        /* this side-steps the usual activation mechanisms, but... */
139735c4bbdfSmrg        if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
139835c4bbdfSmrg            ActivatePassiveGrab(dev, grab, ptrev, ev);  /* also delivers the event */
139935c4bbdfSmrg        else {
140035c4bbdfSmrg            int deliveries = 0;
140135c4bbdfSmrg
140235c4bbdfSmrg            /* 'grab' is the passive grab, but if the grab isn't active,
140335c4bbdfSmrg             * don't deliver */
140435c4bbdfSmrg            if (!dev->deviceGrab.grab)
140535c4bbdfSmrg                return !Success;
140635c4bbdfSmrg
140735c4bbdfSmrg            if (grab->ownerEvents) {
140835c4bbdfSmrg                WindowPtr focus = NullWindow;
140935c4bbdfSmrg                WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
141035c4bbdfSmrg
141135c4bbdfSmrg                deliveries = DeliverDeviceEvents(sprite_win, ptrev, grab, focus, dev);
141235c4bbdfSmrg            }
141335c4bbdfSmrg
141435c4bbdfSmrg            if (!deliveries)
141535c4bbdfSmrg                deliveries = DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
141635c4bbdfSmrg
141735c4bbdfSmrg            /* We must accept the touch sequence once a pointer listener has
141835c4bbdfSmrg             * received one event past ButtonPress. */
141935c4bbdfSmrg            if (deliveries && ev->any.type != ET_TouchBegin &&
142035c4bbdfSmrg                !(ev->device_event.flags & TOUCH_CLIENT_ID))
142135c4bbdfSmrg                TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
142235c4bbdfSmrg
142335c4bbdfSmrg            if (ev->any.type == ET_TouchEnd &&
142435c4bbdfSmrg                ti->num_listeners == 1 &&
142535c4bbdfSmrg                !dev->button->buttonsDown &&
142635c4bbdfSmrg                dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
142735c4bbdfSmrg                (*dev->deviceGrab.DeactivateGrab) (dev);
142835c4bbdfSmrg                CheckOldestTouch(dev);
142935c4bbdfSmrg                return Success;
143035c4bbdfSmrg            }
143135c4bbdfSmrg        }
143235c4bbdfSmrg    }
143335c4bbdfSmrg    else {
143435c4bbdfSmrg        GrabPtr devgrab = dev->deviceGrab.grab;
143535c4bbdfSmrg        WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
143635c4bbdfSmrg
143735c4bbdfSmrg        DeliverDeviceEvents(sprite_win, ptrev, grab, win, dev);
143835c4bbdfSmrg        /* FIXME: bad hack
143935c4bbdfSmrg         * Implicit passive grab activated in response to this event. Store
144035c4bbdfSmrg         * the event.
144135c4bbdfSmrg         */
144235c4bbdfSmrg        if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) {
144335c4bbdfSmrg            TouchListener *l;
144435c4bbdfSmrg            GrabPtr g;
144535c4bbdfSmrg
144635c4bbdfSmrg            devgrab = dev->deviceGrab.grab;
144735c4bbdfSmrg            g = AllocGrab(devgrab);
144835c4bbdfSmrg            BUG_WARN(!g);
144935c4bbdfSmrg
145035c4bbdfSmrg            *dev->deviceGrab.sync.event = ev->device_event;
145135c4bbdfSmrg
145235c4bbdfSmrg            /* The listener array has a sequence of grabs and then one event
145335c4bbdfSmrg             * selection. Implicit grab activation occurs through delivering an
145435c4bbdfSmrg             * event selection. Thus, we update the last listener in the array.
145535c4bbdfSmrg             */
145635c4bbdfSmrg            l = &ti->listeners[ti->num_listeners - 1];
145735c4bbdfSmrg            l->listener = g->resource;
145835c4bbdfSmrg            l->grab = g;
145935c4bbdfSmrg            //l->resource_type = RT_NONE;
146035c4bbdfSmrg
146135c4bbdfSmrg            if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin)
146235c4bbdfSmrg                l->type = LISTENER_POINTER_GRAB;
146335c4bbdfSmrg            else
146435c4bbdfSmrg                l->type = LISTENER_GRAB;
146535c4bbdfSmrg        }
146635c4bbdfSmrg
146735c4bbdfSmrg    }
146835c4bbdfSmrg    if (ev->any.type == ET_TouchBegin)
146935c4bbdfSmrg        listener->state = LISTENER_IS_OWNER;
147035c4bbdfSmrg    else if (ev->any.type == ET_TouchEnd)
147135c4bbdfSmrg        listener->state = LISTENER_HAS_END;
147235c4bbdfSmrg
147335c4bbdfSmrg    return Success;
147435c4bbdfSmrg}
147535c4bbdfSmrg
147635c4bbdfSmrgstatic void
147735c4bbdfSmrgDeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
147835c4bbdfSmrg                           InternalEvent *ev)
147935c4bbdfSmrg{
148035c4bbdfSmrg    DeviceEvent motion;
148135c4bbdfSmrg
148235c4bbdfSmrg    if (ti->num_listeners) {
148335c4bbdfSmrg        ClientPtr client;
148435c4bbdfSmrg        WindowPtr win;
148535c4bbdfSmrg        GrabPtr grab;
148635c4bbdfSmrg        XI2Mask *mask;
148735c4bbdfSmrg
148835c4bbdfSmrg        if (ti->listeners[0].type != LISTENER_POINTER_REGULAR &&
148935c4bbdfSmrg            ti->listeners[0].type != LISTENER_POINTER_GRAB)
149035c4bbdfSmrg            return;
149135c4bbdfSmrg
149235c4bbdfSmrg        motion = ev->device_event;
149335c4bbdfSmrg        motion.type = ET_TouchUpdate;
149435c4bbdfSmrg        motion.detail.button = 0;
149535c4bbdfSmrg
149635c4bbdfSmrg        if (!RetrieveTouchDeliveryData(dev, ti, (InternalEvent*)&motion,
149735c4bbdfSmrg                                       &ti->listeners[0], &client, &win, &grab,
149835c4bbdfSmrg                                       &mask))
149935c4bbdfSmrg            return;
150035c4bbdfSmrg
150135c4bbdfSmrg        /* There may be a pointer grab on the device */
150235c4bbdfSmrg        if (!grab) {
150335c4bbdfSmrg            grab = dev->deviceGrab.grab;
150435c4bbdfSmrg            if (grab) {
150535c4bbdfSmrg                win = grab->window;
150635c4bbdfSmrg                mask = grab->xi2mask;
150735c4bbdfSmrg                client = rClient(grab);
150835c4bbdfSmrg            }
150935c4bbdfSmrg        }
151035c4bbdfSmrg
151135c4bbdfSmrg        DeliverTouchEmulatedEvent(dev, ti, (InternalEvent*)&motion, &ti->listeners[0], client,
151235c4bbdfSmrg                                  win, grab, mask);
151335c4bbdfSmrg    }
151435c4bbdfSmrg    else {
151535c4bbdfSmrg        InternalEvent button;
151635c4bbdfSmrg        int converted;
151735c4bbdfSmrg
151835c4bbdfSmrg        converted = TouchConvertToPointerEvent(ev, (InternalEvent*)&motion, &button);
151935c4bbdfSmrg
152035c4bbdfSmrg        BUG_WARN(converted == 0);
152135c4bbdfSmrg        if (converted)
152235c4bbdfSmrg            ProcessOtherEvent((InternalEvent*)&motion, dev);
152335c4bbdfSmrg    }
152435c4bbdfSmrg}
152535c4bbdfSmrg
152635c4bbdfSmrg/**
152735c4bbdfSmrg * Processes and delivers a TouchBegin, TouchUpdate, or a
152835c4bbdfSmrg * TouchEnd event.
152935c4bbdfSmrg *
153035c4bbdfSmrg * Due to having rather different delivery semantics (see the Xi 2.2 protocol
153135c4bbdfSmrg * spec for more information), this implements its own grab and event-selection
153235c4bbdfSmrg * delivery logic.
153335c4bbdfSmrg */
153435c4bbdfSmrgstatic void
153535c4bbdfSmrgProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
153635c4bbdfSmrg{
153735c4bbdfSmrg    TouchClassPtr t = dev->touch;
153835c4bbdfSmrg    TouchPointInfoPtr ti;
153935c4bbdfSmrg    uint32_t touchid;
154035c4bbdfSmrg    int type = ev->any.type;
154135c4bbdfSmrg    int emulate_pointer = ! !(ev->device_event.flags & TOUCH_POINTER_EMULATED);
154235c4bbdfSmrg    DeviceIntPtr kbd;
154335c4bbdfSmrg
154435c4bbdfSmrg    if (!t)
154535c4bbdfSmrg        return;
154635c4bbdfSmrg
154735c4bbdfSmrg    touchid = ev->device_event.touchid;
154835c4bbdfSmrg
154935c4bbdfSmrg    if (type == ET_TouchBegin && !(ev->device_event.flags & TOUCH_REPLAYING)) {
155035c4bbdfSmrg        ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
155135c4bbdfSmrg                             emulate_pointer);
155235c4bbdfSmrg    }
155335c4bbdfSmrg    else
155435c4bbdfSmrg        ti = TouchFindByClientID(dev, touchid);
155535c4bbdfSmrg
155635c4bbdfSmrg    /* Active pointer grab */
155735c4bbdfSmrg    if (emulate_pointer && dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
155835c4bbdfSmrg        (dev->deviceGrab.grab->grabtype == CORE ||
155935c4bbdfSmrg         dev->deviceGrab.grab->grabtype == XI ||
156035c4bbdfSmrg         !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin)))
156135c4bbdfSmrg    {
156235c4bbdfSmrg        /* Active pointer grab on touch point and we get a TouchEnd - claim this
156335c4bbdfSmrg         * touchpoint accepted, otherwise clients waiting for ownership will
156435c4bbdfSmrg         * wait on this touchpoint until this client ungrabs, or the cows come
156535c4bbdfSmrg         * home, whichever is earlier */
156635c4bbdfSmrg        if (ti && type == ET_TouchEnd)
156735c4bbdfSmrg            TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
156835c4bbdfSmrg        else if (!ti && type != ET_TouchBegin) {
156935c4bbdfSmrg            /* Under the following circumstances we create a new touch record for an
157035c4bbdfSmrg             * existing touch:
157135c4bbdfSmrg             *
157235c4bbdfSmrg             * - The touch may be pointer emulated
157335c4bbdfSmrg             * - An explicit grab is active on the device
157435c4bbdfSmrg             * - The grab is a pointer grab
157535c4bbdfSmrg             *
157635c4bbdfSmrg             * This allows for an explicit grab to receive pointer events for an already
157735c4bbdfSmrg             * active touch.
157835c4bbdfSmrg             */
157935c4bbdfSmrg            ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
158035c4bbdfSmrg                                 emulate_pointer);
158135c4bbdfSmrg            if (!ti) {
158235c4bbdfSmrg                DebugF("[Xi] %s: Failed to create new dix record for explicitly "
158335c4bbdfSmrg                       "grabbed touchpoint %d\n",
158435c4bbdfSmrg                       dev->name, touchid);
158535c4bbdfSmrg                return;
158635c4bbdfSmrg            }
158735c4bbdfSmrg
158835c4bbdfSmrg            TouchBuildSprite(dev, ti, ev);
158935c4bbdfSmrg            TouchSetupListeners(dev, ti, ev);
159035c4bbdfSmrg        }
159135c4bbdfSmrg    }
159235c4bbdfSmrg
159335c4bbdfSmrg    if (!ti) {
159435c4bbdfSmrg        DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
159535c4bbdfSmrg               dev->name, type, touchid);
159635c4bbdfSmrg        goto out;
159735c4bbdfSmrg    }
159835c4bbdfSmrg
159935c4bbdfSmrg    /* if emulate_pointer is set, emulate the motion event right
160035c4bbdfSmrg     * here, so we can ignore it for button event emulation. TouchUpdate
160135c4bbdfSmrg     * events which _only_ emulate motion just work normally */
160235c4bbdfSmrg    if (emulate_pointer && ev->any.type != ET_TouchUpdate)
160335c4bbdfSmrg        DeliverEmulatedMotionEvent(dev, ti, ev);
160435c4bbdfSmrg
160535c4bbdfSmrg    if (emulate_pointer && IsMaster(dev))
160635c4bbdfSmrg        CheckMotion(&ev->device_event, dev);
160735c4bbdfSmrg
160835c4bbdfSmrg    kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
160935c4bbdfSmrg    event_set_state(NULL, kbd, &ev->device_event);
161035c4bbdfSmrg    ev->device_event.corestate = event_get_corestate(NULL, kbd);
161135c4bbdfSmrg
161235c4bbdfSmrg    /* Make sure we have a valid window trace for event delivery; must be
161335c4bbdfSmrg     * called after event type mutation. Touch end events are always processed
161435c4bbdfSmrg     * in order to end touch records. */
161535c4bbdfSmrg    /* FIXME: check this */
161635c4bbdfSmrg    if ((type == ET_TouchBegin &&
161735c4bbdfSmrg         !(ev->device_event.flags & TOUCH_REPLAYING) &&
161835c4bbdfSmrg         !TouchBuildSprite(dev, ti, ev)) ||
161935c4bbdfSmrg        (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
162035c4bbdfSmrg        return;
162135c4bbdfSmrg
162235c4bbdfSmrg    TouchCopyValuatorData(&ev->device_event, ti);
162335c4bbdfSmrg    /* WARNING: the event type may change to TouchUpdate in
162435c4bbdfSmrg     * DeliverTouchEvents if a TouchEnd was delivered to a grabbing
162535c4bbdfSmrg     * owner */
162635c4bbdfSmrg    DeliverTouchEvents(dev, ti, ev, ev->device_event.resource);
162735c4bbdfSmrg    if (ev->any.type == ET_TouchEnd)
162835c4bbdfSmrg        TouchEndTouch(dev, ti);
162935c4bbdfSmrg
163035c4bbdfSmrg out:
163135c4bbdfSmrg    if (emulate_pointer)
163235c4bbdfSmrg        UpdateDeviceState(dev, &ev->device_event);
163335c4bbdfSmrg}
163435c4bbdfSmrg
163535c4bbdfSmrgstatic void
163635c4bbdfSmrgProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
163735c4bbdfSmrg{
163835c4bbdfSmrg    Mask filter;
163935c4bbdfSmrg    WindowPtr pWin;
164035c4bbdfSmrg    BarrierEvent *be = &e->barrier_event;
164135c4bbdfSmrg    xEvent *ev;
164235c4bbdfSmrg    int rc;
164335c4bbdfSmrg    GrabPtr grab = dev->deviceGrab.grab;
164435c4bbdfSmrg
164535c4bbdfSmrg    if (!IsMaster(dev))
164635c4bbdfSmrg        return;
164735c4bbdfSmrg
164835c4bbdfSmrg    if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
164935c4bbdfSmrg        return;
165035c4bbdfSmrg
165135c4bbdfSmrg    if (grab)
165235c4bbdfSmrg        be->flags |= XIBarrierDeviceIsGrabbed;
165335c4bbdfSmrg
165435c4bbdfSmrg    rc = EventToXI2(e, &ev);
165535c4bbdfSmrg    if (rc != Success) {
165635c4bbdfSmrg        ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc);
165735c4bbdfSmrg        return;
165835c4bbdfSmrg    }
165935c4bbdfSmrg
166035c4bbdfSmrg    /* A client has a grab, deliver to this client if the grab_window is the
166135c4bbdfSmrg       barrier window.
166235c4bbdfSmrg
166335c4bbdfSmrg       Otherwise, deliver normally to the client.
166435c4bbdfSmrg     */
166535c4bbdfSmrg    if (grab &&
166635c4bbdfSmrg        CLIENT_ID(be->barrierid) == CLIENT_ID(grab->resource) &&
166735c4bbdfSmrg        grab->window->drawable.id == be->window) {
166835c4bbdfSmrg        DeliverGrabbedEvent(e, dev, FALSE);
166935c4bbdfSmrg    } else {
167035c4bbdfSmrg        filter = GetEventFilter(dev, ev);
167135c4bbdfSmrg
167235c4bbdfSmrg        DeliverEventsToWindow(dev, pWin, ev, 1,
167335c4bbdfSmrg                              filter, NullGrab);
167435c4bbdfSmrg    }
167535c4bbdfSmrg    free(ev);
167635c4bbdfSmrg}
167735c4bbdfSmrg
167835c4bbdfSmrg/**
167935c4bbdfSmrg * Process DeviceEvents and DeviceChangedEvents.
168035c4bbdfSmrg */
168135c4bbdfSmrgstatic void
168235c4bbdfSmrgProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
168335c4bbdfSmrg{
168435c4bbdfSmrg    GrabPtr grab;
168535c4bbdfSmrg    Bool deactivateDeviceGrab = FALSE;
168635c4bbdfSmrg    int key = 0, rootX, rootY;
168735c4bbdfSmrg    ButtonClassPtr b;
168835c4bbdfSmrg    int ret = 0;
168935c4bbdfSmrg    int corestate;
169035c4bbdfSmrg    DeviceIntPtr mouse = NULL, kbd = NULL;
169135c4bbdfSmrg    DeviceEvent *event = &ev->device_event;
169235c4bbdfSmrg
169335c4bbdfSmrg    if (IsPointerDevice(device)) {
169435c4bbdfSmrg        kbd = GetMaster(device, KEYBOARD_OR_FLOAT);
169535c4bbdfSmrg        mouse = device;
169635c4bbdfSmrg        if (!kbd->key)          /* can happen with floating SDs */
169735c4bbdfSmrg            kbd = NULL;
169835c4bbdfSmrg    }
169935c4bbdfSmrg    else {
170035c4bbdfSmrg        mouse = GetMaster(device, POINTER_OR_FLOAT);
170135c4bbdfSmrg        kbd = device;
170235c4bbdfSmrg        if (!mouse->valuator || !mouse->button) /* may be float. SDs */
170335c4bbdfSmrg            mouse = NULL;
170435c4bbdfSmrg    }
170535c4bbdfSmrg
170635c4bbdfSmrg    corestate = event_get_corestate(mouse, kbd);
170735c4bbdfSmrg    event_set_state(mouse, kbd, event);
170835c4bbdfSmrg
170935c4bbdfSmrg    ret = UpdateDeviceState(device, event);
171035c4bbdfSmrg    if (ret == DONT_PROCESS)
171135c4bbdfSmrg        return;
171235c4bbdfSmrg
171335c4bbdfSmrg    b = device->button;
171435c4bbdfSmrg
171535c4bbdfSmrg    if (IsMaster(device) || IsFloating(device))
171635c4bbdfSmrg        CheckMotion(event, device);
171735c4bbdfSmrg
171835c4bbdfSmrg    switch (event->type) {
171935c4bbdfSmrg    case ET_Motion:
172035c4bbdfSmrg    case ET_ButtonPress:
172135c4bbdfSmrg    case ET_ButtonRelease:
172235c4bbdfSmrg    case ET_KeyPress:
172335c4bbdfSmrg    case ET_KeyRelease:
172435c4bbdfSmrg    case ET_ProximityIn:
172535c4bbdfSmrg    case ET_ProximityOut:
172635c4bbdfSmrg        GetSpritePosition(device, &rootX, &rootY);
172735c4bbdfSmrg        event->root_x = rootX;
172835c4bbdfSmrg        event->root_y = rootY;
172935c4bbdfSmrg        NoticeEventTime((InternalEvent *) event, device);
173035c4bbdfSmrg        event->corestate = corestate;
173135c4bbdfSmrg        key = event->detail.key;
173235c4bbdfSmrg        break;
173335c4bbdfSmrg    default:
173435c4bbdfSmrg        break;
173535c4bbdfSmrg    }
173635c4bbdfSmrg
173735c4bbdfSmrg    /* send KeyPress and KeyRelease events to XACE plugins */
173835c4bbdfSmrg    if (XaceHookIsSet(XACE_KEY_AVAIL) &&
173935c4bbdfSmrg            (event->type == ET_KeyPress || event->type == ET_KeyRelease)) {
174035c4bbdfSmrg        xEvent *core;
174135c4bbdfSmrg        int count;
174235c4bbdfSmrg
174335c4bbdfSmrg        if (EventToCore(ev, &core, &count) == Success && count > 0) {
174435c4bbdfSmrg            XaceHook(XACE_KEY_AVAIL, core, device, 0);
174535c4bbdfSmrg            free(core);
174635c4bbdfSmrg        }
174735c4bbdfSmrg    }
174835c4bbdfSmrg
174935c4bbdfSmrg    if (DeviceEventCallback && !syncEvents.playingEvents) {
175035c4bbdfSmrg        DeviceEventInfoRec eventinfo;
175135c4bbdfSmrg        SpritePtr pSprite = device->spriteInfo->sprite;
175235c4bbdfSmrg
175335c4bbdfSmrg        /* see comment in EnqueueEvents regarding the next three lines */
175435c4bbdfSmrg        if (ev->any.type == ET_Motion)
175535c4bbdfSmrg            ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
175635c4bbdfSmrg
175735c4bbdfSmrg        eventinfo.device = device;
175835c4bbdfSmrg        eventinfo.event = ev;
175935c4bbdfSmrg        CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
176035c4bbdfSmrg    }
176135c4bbdfSmrg
176235c4bbdfSmrg    grab = device->deviceGrab.grab;
176335c4bbdfSmrg
176435c4bbdfSmrg    switch (event->type) {
176535c4bbdfSmrg    case ET_KeyPress:
176635c4bbdfSmrg        if (!grab && CheckDeviceGrabs(device, event, 0))
176735c4bbdfSmrg            return;
176835c4bbdfSmrg        break;
176935c4bbdfSmrg    case ET_KeyRelease:
177035c4bbdfSmrg        if (grab && device->deviceGrab.fromPassiveGrab &&
177135c4bbdfSmrg            (key == device->deviceGrab.activatingKey) &&
177235c4bbdfSmrg            GrabIsKeyboardGrab(device->deviceGrab.grab))
177335c4bbdfSmrg            deactivateDeviceGrab = TRUE;
177435c4bbdfSmrg        break;
177535c4bbdfSmrg    case ET_ButtonPress:
177635c4bbdfSmrg        if (b->map[key] == 0)   /* there's no button 0 */
177735c4bbdfSmrg            return;
177835c4bbdfSmrg        event->detail.button = b->map[key];
177935c4bbdfSmrg        if (!grab && CheckDeviceGrabs(device, event, 0)) {
178035c4bbdfSmrg            /* if a passive grab was activated, the event has been sent
178135c4bbdfSmrg             * already */
178235c4bbdfSmrg            return;
178335c4bbdfSmrg        }
178435c4bbdfSmrg        break;
178535c4bbdfSmrg    case ET_ButtonRelease:
178635c4bbdfSmrg        if (b->map[key] == 0)   /* there's no button 0 */
178735c4bbdfSmrg            return;
178835c4bbdfSmrg        event->detail.button = b->map[key];
178935c4bbdfSmrg        if (grab && !b->buttonsDown &&
179035c4bbdfSmrg            device->deviceGrab.fromPassiveGrab &&
179135c4bbdfSmrg            GrabIsPointerGrab(device->deviceGrab.grab))
179235c4bbdfSmrg            deactivateDeviceGrab = TRUE;
179335c4bbdfSmrg    default:
179435c4bbdfSmrg        break;
179535c4bbdfSmrg    }
179635c4bbdfSmrg
179735c4bbdfSmrg    if (grab)
179835c4bbdfSmrg        DeliverGrabbedEvent((InternalEvent *) event, device,
179935c4bbdfSmrg                            deactivateDeviceGrab);
180035c4bbdfSmrg    else if (device->focus && !IsPointerEvent(ev))
180135c4bbdfSmrg        DeliverFocusedEvent(device, (InternalEvent *) event,
180235c4bbdfSmrg                            GetSpriteWindow(device));
180335c4bbdfSmrg    else
180435c4bbdfSmrg        DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent *) event,
180535c4bbdfSmrg                            NullGrab, NullWindow, device);
180635c4bbdfSmrg
180735c4bbdfSmrg    if (deactivateDeviceGrab == TRUE) {
180835c4bbdfSmrg        (*device->deviceGrab.DeactivateGrab) (device);
180935c4bbdfSmrg
181035c4bbdfSmrg        if (!IsMaster (device) && !IsFloating (device)) {
181135c4bbdfSmrg            int flags, num_events = 0;
181235c4bbdfSmrg            InternalEvent dce;
181335c4bbdfSmrg
181435c4bbdfSmrg            flags = (IsPointerDevice (device)) ?
181535c4bbdfSmrg                DEVCHANGE_POINTER_EVENT : DEVCHANGE_KEYBOARD_EVENT;
181635c4bbdfSmrg            UpdateFromMaster (&dce, device, flags, &num_events);
181735c4bbdfSmrg            BUG_WARN(num_events > 1);
181835c4bbdfSmrg
181935c4bbdfSmrg            if (num_events == 1)
182035c4bbdfSmrg                ChangeMasterDeviceClasses(GetMaster (device, MASTER_ATTACHED),
182135c4bbdfSmrg                                          &dce.changed_event);
182235c4bbdfSmrg        }
182335c4bbdfSmrg
182435c4bbdfSmrg    }
182535c4bbdfSmrg
182635c4bbdfSmrg    event->detail.key = key;
182735c4bbdfSmrg}
182835c4bbdfSmrg
182935c4bbdfSmrg/**
183035c4bbdfSmrg * Main device event processing function.
183135c4bbdfSmrg * Called from when processing the events from the event queue.
183235c4bbdfSmrg *
183335c4bbdfSmrg */
183435c4bbdfSmrgvoid
183535c4bbdfSmrgProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
183635c4bbdfSmrg{
183735c4bbdfSmrg    verify_internal_event(ev);
183835c4bbdfSmrg
183935c4bbdfSmrg    switch (ev->any.type) {
184035c4bbdfSmrg    case ET_RawKeyPress:
184135c4bbdfSmrg    case ET_RawKeyRelease:
184235c4bbdfSmrg    case ET_RawButtonPress:
184335c4bbdfSmrg    case ET_RawButtonRelease:
184435c4bbdfSmrg    case ET_RawMotion:
184535c4bbdfSmrg    case ET_RawTouchBegin:
184635c4bbdfSmrg    case ET_RawTouchUpdate:
184735c4bbdfSmrg    case ET_RawTouchEnd:
184835c4bbdfSmrg        DeliverRawEvent(&ev->raw_event, device);
184935c4bbdfSmrg        break;
185035c4bbdfSmrg    case ET_TouchBegin:
185135c4bbdfSmrg    case ET_TouchUpdate:
185235c4bbdfSmrg    case ET_TouchEnd:
185335c4bbdfSmrg        ProcessTouchEvent(ev, device);
185435c4bbdfSmrg        break;
185535c4bbdfSmrg    case ET_TouchOwnership:
185635c4bbdfSmrg        /* TouchOwnership events are handled separately from the rest, as they
185735c4bbdfSmrg         * have more complex semantics. */
185835c4bbdfSmrg        ProcessTouchOwnershipEvent(&ev->touch_ownership_event, device);
185935c4bbdfSmrg        break;
186035c4bbdfSmrg    case ET_BarrierHit:
186135c4bbdfSmrg    case ET_BarrierLeave:
186235c4bbdfSmrg        ProcessBarrierEvent(ev, device);
186335c4bbdfSmrg        break;
186435c4bbdfSmrg    default:
186535c4bbdfSmrg        ProcessDeviceEvent(ev, device);
186635c4bbdfSmrg        break;
186735c4bbdfSmrg    }
186835c4bbdfSmrg}
186935c4bbdfSmrg
187035c4bbdfSmrgstatic int
187135c4bbdfSmrgDeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
187235c4bbdfSmrg                       InternalEvent *ev, TouchListener * listener,
187335c4bbdfSmrg                       ClientPtr client, WindowPtr win, GrabPtr grab,
187435c4bbdfSmrg                       XI2Mask *xi2mask)
187535c4bbdfSmrg{
187635c4bbdfSmrg    enum TouchListenerState state;
187735c4bbdfSmrg    int rc = Success;
187835c4bbdfSmrg    Bool has_ownershipmask;
187935c4bbdfSmrg
188035c4bbdfSmrg    if (listener->type == LISTENER_POINTER_REGULAR ||
188135c4bbdfSmrg        listener->type == LISTENER_POINTER_GRAB) {
188235c4bbdfSmrg        rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
188335c4bbdfSmrg                                       grab, xi2mask);
188435c4bbdfSmrg        if (rc == Success) {
188535c4bbdfSmrg            listener->state = LISTENER_IS_OWNER;
188635c4bbdfSmrg            /* async grabs cannot replay, so automatically accept this touch */
188735c4bbdfSmrg            if (listener->type == LISTENER_POINTER_GRAB &&
188835c4bbdfSmrg                dev->deviceGrab.grab &&
188935c4bbdfSmrg                dev->deviceGrab.fromPassiveGrab &&
189035c4bbdfSmrg                dev->deviceGrab.grab->pointerMode == GrabModeAsync)
189135c4bbdfSmrg                ActivateEarlyAccept(dev, ti);
189235c4bbdfSmrg        }
189335c4bbdfSmrg        goto out;
189435c4bbdfSmrg    }
189535c4bbdfSmrg
189635c4bbdfSmrg    has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
189735c4bbdfSmrg
189835c4bbdfSmrg    if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
189935c4bbdfSmrg        rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
190035c4bbdfSmrg    if (!TouchResourceIsOwner(ti, listener->listener)) {
190135c4bbdfSmrg        if (has_ownershipmask)
190235c4bbdfSmrg            state = LISTENER_AWAITING_OWNER;
190335c4bbdfSmrg        else
190435c4bbdfSmrg            state = LISTENER_AWAITING_BEGIN;
190535c4bbdfSmrg    }
190635c4bbdfSmrg    else {
190735c4bbdfSmrg        if (has_ownershipmask)
190835c4bbdfSmrg            TouchSendOwnershipEvent(dev, ti, 0, listener->listener);
190935c4bbdfSmrg
191035c4bbdfSmrg        if (listener->type == LISTENER_REGULAR)
191135c4bbdfSmrg            state = LISTENER_HAS_ACCEPTED;
191235c4bbdfSmrg        else
191335c4bbdfSmrg            state = LISTENER_IS_OWNER;
191435c4bbdfSmrg    }
191535c4bbdfSmrg    listener->state = state;
191635c4bbdfSmrg
191735c4bbdfSmrg out:
191835c4bbdfSmrg    return rc;
191935c4bbdfSmrg}
192035c4bbdfSmrg
192135c4bbdfSmrgstatic int
192235c4bbdfSmrgDeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
192335c4bbdfSmrg                     TouchListener * listener, ClientPtr client,
192435c4bbdfSmrg                     WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
192535c4bbdfSmrg{
192635c4bbdfSmrg    int rc = Success;
192735c4bbdfSmrg
192835c4bbdfSmrg    if (listener->type == LISTENER_POINTER_REGULAR ||
192935c4bbdfSmrg        listener->type == LISTENER_POINTER_GRAB) {
193035c4bbdfSmrg        /* Note: If the active grab was ungrabbed, we already changed the
193135c4bbdfSmrg         * state to LISTENER_HAS_END but still get here. So we mustn't
193235c4bbdfSmrg         * actually send the event.
193335c4bbdfSmrg         * This is part two of the hack in DeactivatePointerGrab
193435c4bbdfSmrg         */
193535c4bbdfSmrg        if (listener->state != LISTENER_HAS_END) {
193635c4bbdfSmrg            rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
193735c4bbdfSmrg                                           grab, xi2mask);
193835c4bbdfSmrg
193935c4bbdfSmrg             /* Once we send a TouchEnd to a legacy listener, we're already well
194035c4bbdfSmrg              * past the accepting/rejecting stage (can only happen on
194135c4bbdfSmrg              * GrabModeSync + replay. This listener now gets the end event,
194235c4bbdfSmrg              * and we can continue.
194335c4bbdfSmrg              */
194435c4bbdfSmrg            if (rc == Success)
194535c4bbdfSmrg                listener->state = LISTENER_HAS_END;
194635c4bbdfSmrg        }
194735c4bbdfSmrg        goto out;
194835c4bbdfSmrg    }
194935c4bbdfSmrg
195035c4bbdfSmrg    /* A client is waiting for the begin, don't give it a TouchEnd */
195135c4bbdfSmrg    if (listener->state == LISTENER_AWAITING_BEGIN) {
195235c4bbdfSmrg        listener->state = LISTENER_HAS_END;
195335c4bbdfSmrg        goto out;
195435c4bbdfSmrg    }
195535c4bbdfSmrg
195635c4bbdfSmrg    /* Event in response to reject */
195735c4bbdfSmrg    if (ev->device_event.flags & TOUCH_REJECT ||
195835c4bbdfSmrg        (ev->device_event.flags & TOUCH_ACCEPT && !TouchResourceIsOwner(ti, listener->listener))) {
195935c4bbdfSmrg        /* Touch has been rejected, or accepted by its owner which is not this listener */
196035c4bbdfSmrg        if (listener->state != LISTENER_HAS_END)
196135c4bbdfSmrg            rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
196235c4bbdfSmrg        listener->state = LISTENER_HAS_END;
196335c4bbdfSmrg    }
196435c4bbdfSmrg    else if (TouchResourceIsOwner(ti, listener->listener)) {
196535c4bbdfSmrg        Bool normal_end = !(ev->device_event.flags & TOUCH_ACCEPT);
196635c4bbdfSmrg
196735c4bbdfSmrg        /* FIXME: what about early acceptance */
196835c4bbdfSmrg        if (normal_end && listener->state != LISTENER_HAS_END)
196935c4bbdfSmrg            rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
197035c4bbdfSmrg
197135c4bbdfSmrg        if ((ti->num_listeners > 1 ||
197235c4bbdfSmrg             (ti->num_grabs > 0 && listener->state != LISTENER_HAS_ACCEPTED)) &&
197335c4bbdfSmrg            (ev->device_event.flags & (TOUCH_ACCEPT | TOUCH_REJECT)) == 0) {
197435c4bbdfSmrg            ev->any.type = ET_TouchUpdate;
197535c4bbdfSmrg            ev->device_event.flags |= TOUCH_PENDING_END;
197635c4bbdfSmrg            ti->pending_finish = TRUE;
197735c4bbdfSmrg        }
197835c4bbdfSmrg
197935c4bbdfSmrg        if (normal_end)
198035c4bbdfSmrg            listener->state = LISTENER_HAS_END;
198135c4bbdfSmrg    }
198235c4bbdfSmrg
198335c4bbdfSmrg out:
198435c4bbdfSmrg    return rc;
198535c4bbdfSmrg}
198635c4bbdfSmrg
198735c4bbdfSmrgstatic int
198835c4bbdfSmrgDeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
198935c4bbdfSmrg                  TouchListener * listener, ClientPtr client,
199035c4bbdfSmrg                  WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
199135c4bbdfSmrg{
199235c4bbdfSmrg    Bool has_ownershipmask = FALSE;
199335c4bbdfSmrg    int rc = Success;
199435c4bbdfSmrg
199535c4bbdfSmrg    if (xi2mask)
199635c4bbdfSmrg        has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
199735c4bbdfSmrg
199835c4bbdfSmrg    if (ev->any.type == ET_TouchOwnership) {
199935c4bbdfSmrg        ev->touch_ownership_event.deviceid = dev->id;
200035c4bbdfSmrg        if (!TouchResourceIsOwner(ti, listener->listener))
200135c4bbdfSmrg            goto out;
200235c4bbdfSmrg        rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
200335c4bbdfSmrg        listener->state = LISTENER_IS_OWNER;
200435c4bbdfSmrg    }
200535c4bbdfSmrg    else
200635c4bbdfSmrg        ev->device_event.deviceid = dev->id;
200735c4bbdfSmrg
200835c4bbdfSmrg    if (ev->any.type == ET_TouchBegin) {
200935c4bbdfSmrg        rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab,
201035c4bbdfSmrg                                    xi2mask);
201135c4bbdfSmrg    }
201235c4bbdfSmrg    else if (ev->any.type == ET_TouchUpdate) {
201335c4bbdfSmrg        if (listener->type == LISTENER_POINTER_REGULAR ||
201435c4bbdfSmrg            listener->type == LISTENER_POINTER_GRAB)
201535c4bbdfSmrg            DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab,
201635c4bbdfSmrg                                      xi2mask);
201735c4bbdfSmrg        else if (TouchResourceIsOwner(ti, listener->listener) ||
201835c4bbdfSmrg                 has_ownershipmask)
201935c4bbdfSmrg            rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
202035c4bbdfSmrg    }
202135c4bbdfSmrg    else if (ev->any.type == ET_TouchEnd)
202235c4bbdfSmrg        rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab,
202335c4bbdfSmrg                                  xi2mask);
202435c4bbdfSmrg
202535c4bbdfSmrg out:
202635c4bbdfSmrg    return rc;
202735c4bbdfSmrg}
202835c4bbdfSmrg
202935c4bbdfSmrg/**
203035c4bbdfSmrg * Delivers a touch events to all interested clients.  For TouchBegin events,
203135c4bbdfSmrg * will update ti->listeners, ti->num_listeners, and ti->num_grabs.
203235c4bbdfSmrg * May also mutate ev (type and flags) upon successful delivery.  If
203335c4bbdfSmrg * @resource is non-zero, will only attempt delivery to the owner of that
203435c4bbdfSmrg * resource.
203535c4bbdfSmrg *
203635c4bbdfSmrg * @return TRUE if the event was delivered at least once, FALSE otherwise
203735c4bbdfSmrg */
203835c4bbdfSmrgvoid
203935c4bbdfSmrgDeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
204035c4bbdfSmrg                   InternalEvent *ev, XID resource)
204135c4bbdfSmrg{
204235c4bbdfSmrg    int i;
204335c4bbdfSmrg
204435c4bbdfSmrg    if (ev->any.type == ET_TouchBegin &&
204535c4bbdfSmrg        !(ev->device_event.flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING)))
204635c4bbdfSmrg        TouchSetupListeners(dev, ti, ev);
204735c4bbdfSmrg
204835c4bbdfSmrg    TouchEventHistoryPush(ti, &ev->device_event);
204935c4bbdfSmrg
205035c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++) {
205135c4bbdfSmrg        GrabPtr grab = NULL;
205235c4bbdfSmrg        ClientPtr client;
205335c4bbdfSmrg        WindowPtr win;
205435c4bbdfSmrg        XI2Mask *mask;
205535c4bbdfSmrg        TouchListener *listener = &ti->listeners[i];
205635c4bbdfSmrg
205735c4bbdfSmrg        if (resource && listener->listener != resource)
205835c4bbdfSmrg            continue;
205935c4bbdfSmrg
206035c4bbdfSmrg        if (!RetrieveTouchDeliveryData(dev, ti, ev, listener, &client, &win,
206135c4bbdfSmrg                                       &grab, &mask))
206235c4bbdfSmrg            continue;
206335c4bbdfSmrg
206435c4bbdfSmrg        DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
206535c4bbdfSmrg    }
206635c4bbdfSmrg}
206735c4bbdfSmrg
206835c4bbdfSmrgint
206935c4bbdfSmrgInitProximityClassDeviceStruct(DeviceIntPtr dev)
207035c4bbdfSmrg{
207135c4bbdfSmrg    ProximityClassPtr proxc;
207235c4bbdfSmrg
207335c4bbdfSmrg    BUG_RETURN_VAL(dev == NULL, FALSE);
207435c4bbdfSmrg    BUG_RETURN_VAL(dev->proximity != NULL, FALSE);
207535c4bbdfSmrg
207635c4bbdfSmrg    proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec));
207735c4bbdfSmrg    if (!proxc)
207835c4bbdfSmrg        return FALSE;
207935c4bbdfSmrg    proxc->sourceid = dev->id;
208035c4bbdfSmrg    proxc->in_proximity = TRUE;
208135c4bbdfSmrg    dev->proximity = proxc;
208235c4bbdfSmrg    return TRUE;
208335c4bbdfSmrg}
208435c4bbdfSmrg
208535c4bbdfSmrg/**
208635c4bbdfSmrg * Initialise the device's valuators. The memory must already be allocated,
20874642e01fSmrg * this function merely inits the matching axis (specified through axnum) to
20884642e01fSmrg * sane values.
20894642e01fSmrg *
20904642e01fSmrg * It is a condition that (minval < maxval).
20914642e01fSmrg *
20924642e01fSmrg * @see InitValuatorClassDeviceStruct
20934642e01fSmrg */
209435c4bbdfSmrgBool
209535c4bbdfSmrgInitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval,
209635c4bbdfSmrg                       int maxval, int resolution, int min_res, int max_res,
209735c4bbdfSmrg                       int mode)
209805b261ecSmrg{
209905b261ecSmrg    AxisInfoPtr ax;
21004642e01fSmrg
210135c4bbdfSmrg    BUG_RETURN_VAL(dev == NULL, FALSE);
210235c4bbdfSmrg    BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
210335c4bbdfSmrg    BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
210435c4bbdfSmrg    BUG_RETURN_VAL(minval > maxval && mode == Absolute, FALSE);
210505b261ecSmrg
210605b261ecSmrg    ax = dev->valuator->axes + axnum;
210705b261ecSmrg
210805b261ecSmrg    ax->min_value = minval;
210905b261ecSmrg    ax->max_value = maxval;
211005b261ecSmrg    ax->resolution = resolution;
211105b261ecSmrg    ax->min_resolution = min_res;
211205b261ecSmrg    ax->max_resolution = max_res;
21136747b715Smrg    ax->label = label;
21149ace9065Smrg    ax->mode = mode;
21159ace9065Smrg
21169ace9065Smrg    if (mode & OutOfProximity)
21179ace9065Smrg        dev->proximity->in_proximity = FALSE;
211805b261ecSmrg
211935c4bbdfSmrg    return SetScrollValuator(dev, axnum, SCROLL_TYPE_NONE, 0, SCROLL_FLAG_NONE);
212005b261ecSmrg}
212105b261ecSmrg
212235c4bbdfSmrg/**
212335c4bbdfSmrg * Set the given axis number as a scrolling valuator.
212435c4bbdfSmrg */
212535c4bbdfSmrgBool
212635c4bbdfSmrgSetScrollValuator(DeviceIntPtr dev, int axnum, enum ScrollType type,
212735c4bbdfSmrg                  double increment, int flags)
212805b261ecSmrg{
212935c4bbdfSmrg    AxisInfoPtr ax;
213035c4bbdfSmrg    int *current_ax;
213135c4bbdfSmrg    InternalEvent dce;
213235c4bbdfSmrg    DeviceIntPtr master;
213335c4bbdfSmrg
213435c4bbdfSmrg    BUG_RETURN_VAL(dev == NULL, FALSE);
213535c4bbdfSmrg    BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
213635c4bbdfSmrg    BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
213735c4bbdfSmrg
213835c4bbdfSmrg    switch (type) {
213935c4bbdfSmrg    case SCROLL_TYPE_VERTICAL:
214035c4bbdfSmrg        current_ax = &dev->valuator->v_scroll_axis;
214135c4bbdfSmrg        break;
214235c4bbdfSmrg    case SCROLL_TYPE_HORIZONTAL:
214335c4bbdfSmrg        current_ax = &dev->valuator->h_scroll_axis;
214435c4bbdfSmrg        break;
214535c4bbdfSmrg    case SCROLL_TYPE_NONE:
214635c4bbdfSmrg        ax = &dev->valuator->axes[axnum];
214735c4bbdfSmrg        ax->scroll.type = type;
214835c4bbdfSmrg        return TRUE;
214935c4bbdfSmrg    default:
215035c4bbdfSmrg        return FALSE;
215105b261ecSmrg    }
215205b261ecSmrg
215335c4bbdfSmrg    if (increment == 0.0)
215435c4bbdfSmrg        return FALSE;
21556747b715Smrg
215635c4bbdfSmrg    if (*current_ax != -1 && axnum != *current_ax) {
215735c4bbdfSmrg        ax = &dev->valuator->axes[*current_ax];
215835c4bbdfSmrg        if (ax->scroll.type == type &&
215935c4bbdfSmrg            (flags & SCROLL_FLAG_PREFERRED) &&
216035c4bbdfSmrg            (ax->scroll.flags & SCROLL_FLAG_PREFERRED))
216135c4bbdfSmrg            return FALSE;
21626747b715Smrg    }
216335c4bbdfSmrg    *current_ax = axnum;
216405b261ecSmrg
216535c4bbdfSmrg    ax = &dev->valuator->axes[axnum];
216635c4bbdfSmrg    ax->scroll.type = type;
216735c4bbdfSmrg    ax->scroll.increment = increment;
216835c4bbdfSmrg    ax->scroll.flags = flags;
21696747b715Smrg
217035c4bbdfSmrg    master = GetMaster(dev, MASTER_ATTACHED);
217135c4bbdfSmrg    CreateClassesChangedEvent(&dce, master, dev,
217235c4bbdfSmrg                              DEVCHANGE_POINTER_EVENT |
217335c4bbdfSmrg                              DEVCHANGE_DEVICE_CHANGE);
217435c4bbdfSmrg    XISendDeviceChangedEvent(dev, &dce.changed_event);
21756747b715Smrg
217635c4bbdfSmrg    /* if the current slave is us, update the master. If not, we'll update
217735c4bbdfSmrg     * whenever the next slave switch happens anyway. CMDC sends the event
217835c4bbdfSmrg     * for us */
217935c4bbdfSmrg    if (master && master->lastSlave == dev)
218035c4bbdfSmrg        ChangeMasterDeviceClasses(master, &dce.changed_event);
218105b261ecSmrg
218235c4bbdfSmrg    return TRUE;
218305b261ecSmrg}
218405b261ecSmrg
218505b261ecSmrgint
218635c4bbdfSmrgCheckGrabValues(ClientPtr client, GrabParameters *param)
218705b261ecSmrg{
218835c4bbdfSmrg    if (param->grabtype != CORE &&
218935c4bbdfSmrg        param->grabtype != XI && param->grabtype != XI2) {
21906747b715Smrg        ErrorF("[Xi] grabtype is invalid. This is a bug.\n");
21916747b715Smrg        return BadImplementation;
21926747b715Smrg    }
219305b261ecSmrg
21946747b715Smrg    if ((param->this_device_mode != GrabModeSync) &&
219535c4bbdfSmrg        (param->this_device_mode != GrabModeAsync) &&
219635c4bbdfSmrg        (param->this_device_mode != XIGrabModeTouch)) {
219735c4bbdfSmrg        client->errorValue = param->this_device_mode;
219835c4bbdfSmrg        return BadValue;
219905b261ecSmrg    }
22006747b715Smrg    if ((param->other_devices_mode != GrabModeSync) &&
220135c4bbdfSmrg        (param->other_devices_mode != GrabModeAsync) &&
220235c4bbdfSmrg        (param->other_devices_mode != XIGrabModeTouch)) {
220335c4bbdfSmrg        client->errorValue = param->other_devices_mode;
220435c4bbdfSmrg        return BadValue;
220505b261ecSmrg    }
22066747b715Smrg
220735c4bbdfSmrg    if (param->modifiers != AnyModifier &&
220835c4bbdfSmrg        param->modifiers != XIAnyModifier &&
22096747b715Smrg        (param->modifiers & ~AllModifiersMask)) {
221035c4bbdfSmrg        client->errorValue = param->modifiers;
221135c4bbdfSmrg        return BadValue;
221205b261ecSmrg    }
22136747b715Smrg
22146747b715Smrg    if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) {
221535c4bbdfSmrg        client->errorValue = param->ownerEvents;
221635c4bbdfSmrg        return BadValue;
221705b261ecSmrg    }
22186747b715Smrg    return Success;
22196747b715Smrg}
22206747b715Smrg
22216747b715Smrgint
22226747b715SmrgGrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
222335c4bbdfSmrg           int button, GrabParameters *param, enum InputLevel grabtype,
222435c4bbdfSmrg           GrabMask *mask)
22256747b715Smrg{
22266747b715Smrg    WindowPtr pWin, confineTo;
22276747b715Smrg    CursorPtr cursor;
22286747b715Smrg    GrabPtr grab;
22296747b715Smrg    int rc, type = -1;
22306747b715Smrg    Mask access_mode = DixGrabAccess;
22316747b715Smrg
22326747b715Smrg    rc = CheckGrabValues(client, param);
223305b261ecSmrg    if (rc != Success)
223435c4bbdfSmrg        return rc;
22356747b715Smrg    if (param->confineTo == None)
223635c4bbdfSmrg        confineTo = NullWindow;
223705b261ecSmrg    else {
223835c4bbdfSmrg        rc = dixLookupWindow(&confineTo, param->confineTo, client,
223935c4bbdfSmrg                             DixSetAttrAccess);
224035c4bbdfSmrg        if (rc != Success)
224135c4bbdfSmrg            return rc;
224205b261ecSmrg    }
22436747b715Smrg    if (param->cursor == None)
224435c4bbdfSmrg        cursor = NullCursor;
224505b261ecSmrg    else {
224635c4bbdfSmrg        rc = dixLookupResourceByType((void **) &cursor, param->cursor,
224735c4bbdfSmrg                                     RT_CURSOR, client, DixUseAccess);
224835c4bbdfSmrg        if (rc != Success) {
224935c4bbdfSmrg            client->errorValue = param->cursor;
225035c4bbdfSmrg            return rc;
225135c4bbdfSmrg        }
225235c4bbdfSmrg        access_mode |= DixForceAccess;
225335c4bbdfSmrg    }
225435c4bbdfSmrg    if (param->this_device_mode == GrabModeSync ||
225535c4bbdfSmrg        param->other_devices_mode == GrabModeSync)
225635c4bbdfSmrg        access_mode |= DixFreezeAccess;
22574642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
22586747b715Smrg    if (rc != Success)
225935c4bbdfSmrg        return rc;
22606747b715Smrg    rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
22614642e01fSmrg    if (rc != Success)
226235c4bbdfSmrg        return rc;
226305b261ecSmrg
226435c4bbdfSmrg    if (grabtype == XI)
22656747b715Smrg        type = DeviceButtonPress;
226635c4bbdfSmrg    else if (grabtype == XI2)
22676747b715Smrg        type = XI_ButtonPress;
22686747b715Smrg
22696747b715Smrg    grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
22706747b715Smrg                      mask, param, type, button, confineTo, cursor);
227105b261ecSmrg    if (!grab)
227235c4bbdfSmrg        return BadAlloc;
22734642e01fSmrg    return AddPassiveGrabToList(client, grab);
227405b261ecSmrg}
227505b261ecSmrg
22766747b715Smrg/**
227735c4bbdfSmrg * Grab the given key.
22786747b715Smrg */
227905b261ecSmrgint
22806747b715SmrgGrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
228135c4bbdfSmrg        int key, GrabParameters *param, enum InputLevel grabtype,
228235c4bbdfSmrg        GrabMask *mask)
228305b261ecSmrg{
228405b261ecSmrg    WindowPtr pWin;
228505b261ecSmrg    GrabPtr grab;
228605b261ecSmrg    KeyClassPtr k = dev->key;
22874642e01fSmrg    Mask access_mode = DixGrabAccess;
22886747b715Smrg    int rc, type = -1;
228905b261ecSmrg
22906747b715Smrg    rc = CheckGrabValues(client, param);
22916747b715Smrg    if (rc != Success)
22926747b715Smrg        return rc;
2293475c125cSmrg    if ((dev->id != XIAllDevices && dev->id != XIAllMasterDevices) && k == NULL)
229435c4bbdfSmrg        return BadMatch;
229535c4bbdfSmrg    if (grabtype == XI) {
22966747b715Smrg        if ((key > k->xkbInfo->desc->max_key_code ||
229735c4bbdfSmrg             key < k->xkbInfo->desc->min_key_code)
229835c4bbdfSmrg            && (key != AnyKey)) {
22996747b715Smrg            client->errorValue = key;
23006747b715Smrg            return BadValue;
23016747b715Smrg        }
23026747b715Smrg        type = DeviceKeyPress;
230335c4bbdfSmrg    }
230435c4bbdfSmrg    else if (grabtype == XI2)
23056747b715Smrg        type = XI_KeyPress;
23066747b715Smrg
23076747b715Smrg    rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
23084642e01fSmrg    if (rc != Success)
230935c4bbdfSmrg        return rc;
231035c4bbdfSmrg    if (param->this_device_mode == GrabModeSync ||
231135c4bbdfSmrg        param->other_devices_mode == GrabModeSync)
231235c4bbdfSmrg        access_mode |= DixFreezeAccess;
23134642e01fSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
231405b261ecSmrg    if (rc != Success)
231535c4bbdfSmrg        return rc;
231605b261ecSmrg
23176747b715Smrg    grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
23186747b715Smrg                      mask, param, type, key, NULL, NULL);
231905b261ecSmrg    if (!grab)
232035c4bbdfSmrg        return BadAlloc;
23214642e01fSmrg    return AddPassiveGrabToList(client, grab);
232205b261ecSmrg}
232305b261ecSmrg
23246747b715Smrg/* Enter/FocusIn grab */
23256747b715Smrgint
23266747b715SmrgGrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
23276747b715Smrg           GrabParameters *param, GrabMask *mask)
23286747b715Smrg{
23296747b715Smrg    WindowPtr pWin;
23306747b715Smrg    CursorPtr cursor;
23316747b715Smrg    GrabPtr grab;
23326747b715Smrg    Mask access_mode = DixGrabAccess;
23336747b715Smrg    int rc;
23346747b715Smrg
23356747b715Smrg    rc = CheckGrabValues(client, param);
23366747b715Smrg    if (rc != Success)
23376747b715Smrg        return rc;
23386747b715Smrg
23396747b715Smrg    rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
23406747b715Smrg    if (rc != Success)
234135c4bbdfSmrg        return rc;
23426747b715Smrg    if (param->cursor == None)
234335c4bbdfSmrg        cursor = NullCursor;
23446747b715Smrg    else {
234535c4bbdfSmrg        rc = dixLookupResourceByType((void **) &cursor, param->cursor,
234635c4bbdfSmrg                                     RT_CURSOR, client, DixUseAccess);
234735c4bbdfSmrg        if (rc != Success) {
234835c4bbdfSmrg            client->errorValue = param->cursor;
234935c4bbdfSmrg            return rc;
235035c4bbdfSmrg        }
235135c4bbdfSmrg        access_mode |= DixForceAccess;
235235c4bbdfSmrg    }
235335c4bbdfSmrg    if (param->this_device_mode == GrabModeSync ||
235435c4bbdfSmrg        param->other_devices_mode == GrabModeSync)
235535c4bbdfSmrg        access_mode |= DixFreezeAccess;
23566747b715Smrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
23576747b715Smrg    if (rc != Success)
235835c4bbdfSmrg        return rc;
235935c4bbdfSmrg
236035c4bbdfSmrg    grab = CreateGrab(client->index, dev, dev, pWin, XI2,
236135c4bbdfSmrg                      mask, param,
236235c4bbdfSmrg                      (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, 0,
236335c4bbdfSmrg                      NULL, cursor);
236435c4bbdfSmrg
236535c4bbdfSmrg    if (!grab)
236635c4bbdfSmrg        return BadAlloc;
236735c4bbdfSmrg
236835c4bbdfSmrg    return AddPassiveGrabToList(client, grab);
236935c4bbdfSmrg}
237035c4bbdfSmrg
237135c4bbdfSmrg/* Touch grab */
237235c4bbdfSmrgint
237335c4bbdfSmrgGrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
237435c4bbdfSmrg          GrabParameters *param, GrabMask *mask)
237535c4bbdfSmrg{
237635c4bbdfSmrg    WindowPtr pWin;
237735c4bbdfSmrg    GrabPtr grab;
237835c4bbdfSmrg    int rc;
237935c4bbdfSmrg
238035c4bbdfSmrg    rc = CheckGrabValues(client, param);
238135c4bbdfSmrg    if (rc != Success)
238235c4bbdfSmrg        return rc;
23836747b715Smrg
238435c4bbdfSmrg    rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
238535c4bbdfSmrg    if (rc != Success)
238635c4bbdfSmrg        return rc;
238735c4bbdfSmrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGrabAccess);
238835c4bbdfSmrg    if (rc != Success)
238935c4bbdfSmrg        return rc;
23906747b715Smrg
239135c4bbdfSmrg    grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
239235c4bbdfSmrg                      mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
23936747b715Smrg    if (!grab)
23946747b715Smrg        return BadAlloc;
23956747b715Smrg
23966747b715Smrg    return AddPassiveGrabToList(client, grab);
23976747b715Smrg}
23986747b715Smrg
239905b261ecSmrgint
240005b261ecSmrgSelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
240135c4bbdfSmrg                Mask mask, Mask exclusivemasks)
240205b261ecSmrg{
240305b261ecSmrg    int mskidx = dev->id;
240405b261ecSmrg    int i, ret;
240505b261ecSmrg    Mask check;
240605b261ecSmrg    InputClientsPtr others;
240705b261ecSmrg
240805b261ecSmrg    check = (mask & exclusivemasks);
240905b261ecSmrg    if (wOtherInputMasks(pWin)) {
241035c4bbdfSmrg        if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) {
241135c4bbdfSmrg            /* It is illegal for two different clients to select on any of
241235c4bbdfSmrg             * the events for maskcheck. However, it is OK, for some client
241335c4bbdfSmrg             * to continue selecting on one of those events.
241435c4bbdfSmrg             */
241535c4bbdfSmrg            for (others = wOtherInputMasks(pWin)->inputClients; others;
241635c4bbdfSmrg                 others = others->next) {
241735c4bbdfSmrg                if (!SameClient(others, client) && (check &
241835c4bbdfSmrg                                                    others->mask[mskidx]))
241935c4bbdfSmrg                    return BadAccess;
242035c4bbdfSmrg            }
242135c4bbdfSmrg        }
242235c4bbdfSmrg        for (others = wOtherInputMasks(pWin)->inputClients; others;
242335c4bbdfSmrg             others = others->next) {
242435c4bbdfSmrg            if (SameClient(others, client)) {
242535c4bbdfSmrg                check = others->mask[mskidx];
242635c4bbdfSmrg                others->mask[mskidx] = mask;
242735c4bbdfSmrg                if (mask == 0) {
242835c4bbdfSmrg                    for (i = 0; i < EMASKSIZE; i++)
242935c4bbdfSmrg                        if (i != mskidx && others->mask[i] != 0)
243035c4bbdfSmrg                            break;
243135c4bbdfSmrg                    if (i == EMASKSIZE) {
243235c4bbdfSmrg                        RecalculateDeviceDeliverableEvents(pWin);
243335c4bbdfSmrg                        if (ShouldFreeInputMasks(pWin, FALSE))
243435c4bbdfSmrg                            FreeResource(others->resource, RT_NONE);
243535c4bbdfSmrg                        return Success;
243635c4bbdfSmrg                    }
243735c4bbdfSmrg                }
243835c4bbdfSmrg                goto maskSet;
243935c4bbdfSmrg            }
244035c4bbdfSmrg        }
244105b261ecSmrg    }
244205b261ecSmrg    check = 0;
244305b261ecSmrg    if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success)
244435c4bbdfSmrg        return ret;
244535c4bbdfSmrg maskSet:
244605b261ecSmrg    if (dev->valuator)
244735c4bbdfSmrg        if ((dev->valuator->motionHintWindow == pWin) &&
244835c4bbdfSmrg            (mask & DevicePointerMotionHintMask) &&
244935c4bbdfSmrg            !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab)
245035c4bbdfSmrg            dev->valuator->motionHintWindow = NullWindow;
245105b261ecSmrg    RecalculateDeviceDeliverableEvents(pWin);
245205b261ecSmrg    return Success;
245305b261ecSmrg}
245405b261ecSmrg
245535c4bbdfSmrgstatic void
245635c4bbdfSmrgFreeInputClient(InputClientsPtr * other)
245735c4bbdfSmrg{
245835c4bbdfSmrg    xi2mask_free(&(*other)->xi2mask);
245935c4bbdfSmrg    free(*other);
246035c4bbdfSmrg    *other = NULL;
246135c4bbdfSmrg}
246235c4bbdfSmrg
246335c4bbdfSmrgstatic InputClientsPtr
246435c4bbdfSmrgAllocInputClient(void)
246535c4bbdfSmrg{
246635c4bbdfSmrg    return calloc(1, sizeof(InputClients));
246735c4bbdfSmrg}
246835c4bbdfSmrg
246905b261ecSmrgint
247005b261ecSmrgAddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx)
247105b261ecSmrg{
247205b261ecSmrg    InputClientsPtr others;
247305b261ecSmrg
247405b261ecSmrg    if (!pWin->optional && !MakeWindowOptional(pWin))
247535c4bbdfSmrg        return BadAlloc;
247635c4bbdfSmrg    others = AllocInputClient();
247705b261ecSmrg    if (!others)
247835c4bbdfSmrg        return BadAlloc;
247905b261ecSmrg    if (!pWin->optional->inputMasks && !MakeInputMasks(pWin))
248035c4bbdfSmrg        goto bail;
248135c4bbdfSmrg    others->xi2mask = xi2mask_new();
248235c4bbdfSmrg    if (!others->xi2mask)
248335c4bbdfSmrg        goto bail;
248405b261ecSmrg    others->mask[mskidx] = mask;
248505b261ecSmrg    others->resource = FakeClientID(client->index);
248605b261ecSmrg    others->next = pWin->optional->inputMasks->inputClients;
248705b261ecSmrg    pWin->optional->inputMasks->inputClients = others;
248835c4bbdfSmrg    if (!AddResource(others->resource, RT_INPUTCLIENT, (void *) pWin))
248935c4bbdfSmrg        goto bail;
249005b261ecSmrg    return Success;
24919ace9065Smrg
249235c4bbdfSmrg bail:
249335c4bbdfSmrg    FreeInputClient(&others);
24949ace9065Smrg    return BadAlloc;
249505b261ecSmrg}
249605b261ecSmrg
249705b261ecSmrgstatic Bool
249805b261ecSmrgMakeInputMasks(WindowPtr pWin)
249905b261ecSmrg{
250005b261ecSmrg    struct _OtherInputMasks *imasks;
250105b261ecSmrg
25026747b715Smrg    imasks = calloc(1, sizeof(struct _OtherInputMasks));
250305b261ecSmrg    if (!imasks)
250435c4bbdfSmrg        return FALSE;
250535c4bbdfSmrg    imasks->xi2mask = xi2mask_new();
250635c4bbdfSmrg    if (!imasks->xi2mask) {
250735c4bbdfSmrg        free(imasks);
250835c4bbdfSmrg        return FALSE;
250935c4bbdfSmrg    }
251005b261ecSmrg    pWin->optional->inputMasks = imasks;
251105b261ecSmrg    return TRUE;
251205b261ecSmrg}
251305b261ecSmrg
251435c4bbdfSmrgstatic void
251535c4bbdfSmrgFreeInputMask(OtherInputMasks ** imask)
251635c4bbdfSmrg{
251735c4bbdfSmrg    xi2mask_free(&(*imask)->xi2mask);
251835c4bbdfSmrg    free(*imask);
251935c4bbdfSmrg    *imask = NULL;
252035c4bbdfSmrg}
252135c4bbdfSmrg
252205b261ecSmrgvoid
252305b261ecSmrgRecalculateDeviceDeliverableEvents(WindowPtr pWin)
252405b261ecSmrg{
252505b261ecSmrg    InputClientsPtr others;
252635c4bbdfSmrg    struct _OtherInputMasks *inputMasks;        /* default: NULL */
252705b261ecSmrg    WindowPtr pChild, tmp;
252835c4bbdfSmrg    int i;
252905b261ecSmrg
253005b261ecSmrg    pChild = pWin;
253105b261ecSmrg    while (1) {
253235c4bbdfSmrg        if ((inputMasks = wOtherInputMasks(pChild)) != 0) {
253335c4bbdfSmrg            xi2mask_zero(inputMasks->xi2mask, -1);
253435c4bbdfSmrg            for (others = inputMasks->inputClients; others;
253535c4bbdfSmrg                 others = others->next) {
25366747b715Smrg                for (i = 0; i < EMASKSIZE; i++)
253735c4bbdfSmrg                    inputMasks->inputEvents[i] |= others->mask[i];
253835c4bbdfSmrg                xi2mask_merge(inputMasks->xi2mask, others->xi2mask);
253935c4bbdfSmrg            }
254035c4bbdfSmrg            for (i = 0; i < EMASKSIZE; i++)
254135c4bbdfSmrg                inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i];
254235c4bbdfSmrg            for (tmp = pChild->parent; tmp; tmp = tmp->parent)
254335c4bbdfSmrg                if (wOtherInputMasks(tmp))
254435c4bbdfSmrg                    for (i = 0; i < EMASKSIZE; i++)
254535c4bbdfSmrg                        inputMasks->deliverableEvents[i] |=
254635c4bbdfSmrg                            (wOtherInputMasks(tmp)->deliverableEvents[i]
254735c4bbdfSmrg                             & ~inputMasks->dontPropagateMask[i] &
254835c4bbdfSmrg                             PropagateMask[i]);
254935c4bbdfSmrg        }
255035c4bbdfSmrg        if (pChild->firstChild) {
255135c4bbdfSmrg            pChild = pChild->firstChild;
255235c4bbdfSmrg            continue;
255335c4bbdfSmrg        }
255435c4bbdfSmrg        while (!pChild->nextSib && (pChild != pWin))
255535c4bbdfSmrg            pChild = pChild->parent;
255635c4bbdfSmrg        if (pChild == pWin)
255735c4bbdfSmrg            break;
255835c4bbdfSmrg        pChild = pChild->nextSib;
255905b261ecSmrg    }
256005b261ecSmrg}
256105b261ecSmrg
256205b261ecSmrgint
256305b261ecSmrgInputClientGone(WindowPtr pWin, XID id)
256405b261ecSmrg{
256505b261ecSmrg    InputClientsPtr other, prev;
256605b261ecSmrg
256705b261ecSmrg    if (!wOtherInputMasks(pWin))
256835c4bbdfSmrg        return Success;
256905b261ecSmrg    prev = 0;
257005b261ecSmrg    for (other = wOtherInputMasks(pWin)->inputClients; other;
257135c4bbdfSmrg         other = other->next) {
257235c4bbdfSmrg        if (other->resource == id) {
257335c4bbdfSmrg            if (prev) {
257435c4bbdfSmrg                prev->next = other->next;
257535c4bbdfSmrg                FreeInputClient(&other);
257635c4bbdfSmrg            }
257735c4bbdfSmrg            else if (!(other->next)) {
257835c4bbdfSmrg                if (ShouldFreeInputMasks(pWin, TRUE)) {
257935c4bbdfSmrg                    OtherInputMasks *mask = wOtherInputMasks(pWin);
258035c4bbdfSmrg
258135c4bbdfSmrg                    mask->inputClients = other->next;
258235c4bbdfSmrg                    FreeInputMask(&mask);
258335c4bbdfSmrg                    pWin->optional->inputMasks = (OtherInputMasks *) NULL;
258435c4bbdfSmrg                    CheckWindowOptionalNeed(pWin);
258535c4bbdfSmrg                    FreeInputClient(&other);
258635c4bbdfSmrg                }
258735c4bbdfSmrg                else {
258835c4bbdfSmrg                    other->resource = FakeClientID(0);
258935c4bbdfSmrg                    if (!AddResource(other->resource, RT_INPUTCLIENT,
259035c4bbdfSmrg                                     (void *) pWin))
259135c4bbdfSmrg                        return BadAlloc;
259235c4bbdfSmrg                }
259335c4bbdfSmrg            }
259435c4bbdfSmrg            else {
259535c4bbdfSmrg                wOtherInputMasks(pWin)->inputClients = other->next;
259635c4bbdfSmrg                FreeInputClient(&other);
259735c4bbdfSmrg            }
259835c4bbdfSmrg            RecalculateDeviceDeliverableEvents(pWin);
259935c4bbdfSmrg            return Success;
260035c4bbdfSmrg        }
260135c4bbdfSmrg        prev = other;
260205b261ecSmrg    }
260305b261ecSmrg    FatalError("client not on device event list");
260405b261ecSmrg}
260505b261ecSmrg
260635c4bbdfSmrg/**
260735c4bbdfSmrg * Search for window in each touch trace for each device. Remove the window
260835c4bbdfSmrg * and all its subwindows from the trace when found. The initial window
260935c4bbdfSmrg * order is preserved.
261035c4bbdfSmrg */
261135c4bbdfSmrgvoid
261235c4bbdfSmrgWindowGone(WindowPtr win)
261335c4bbdfSmrg{
261435c4bbdfSmrg    DeviceIntPtr dev;
261535c4bbdfSmrg
261635c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
261735c4bbdfSmrg        TouchClassPtr t = dev->touch;
261835c4bbdfSmrg        int i;
261935c4bbdfSmrg
262035c4bbdfSmrg        if (!t)
262135c4bbdfSmrg            continue;
262235c4bbdfSmrg
262335c4bbdfSmrg        for (i = 0; i < t->num_touches; i++) {
262435c4bbdfSmrg            SpritePtr sprite = &t->touches[i].sprite;
262535c4bbdfSmrg            int j;
262635c4bbdfSmrg
262735c4bbdfSmrg            for (j = 0; j < sprite->spriteTraceGood; j++) {
262835c4bbdfSmrg                if (sprite->spriteTrace[j] == win) {
262935c4bbdfSmrg                    sprite->spriteTraceGood = j;
263035c4bbdfSmrg                    break;
263135c4bbdfSmrg                }
263235c4bbdfSmrg            }
263335c4bbdfSmrg        }
263435c4bbdfSmrg    }
263535c4bbdfSmrg}
263635c4bbdfSmrg
263705b261ecSmrgint
263805b261ecSmrgSendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate,
263935c4bbdfSmrg          xEvent *ev, Mask mask, int count)
264005b261ecSmrg{
264105b261ecSmrg    WindowPtr pWin;
264235c4bbdfSmrg    WindowPtr effectiveFocus = NullWindow;      /* only set if dest==InputFocus */
26434642e01fSmrg    WindowPtr spriteWin = GetSpriteWindow(d);
264405b261ecSmrg
264505b261ecSmrg    if (dest == PointerWindow)
264635c4bbdfSmrg        pWin = spriteWin;
264705b261ecSmrg    else if (dest == InputFocus) {
264835c4bbdfSmrg        WindowPtr inputFocus;
264935c4bbdfSmrg
265035c4bbdfSmrg        if (!d->focus)
265135c4bbdfSmrg            inputFocus = spriteWin;
265235c4bbdfSmrg        else
265335c4bbdfSmrg            inputFocus = d->focus->win;
265435c4bbdfSmrg
265535c4bbdfSmrg        if (inputFocus == FollowKeyboardWin)
265635c4bbdfSmrg            inputFocus = inputInfo.keyboard->focus->win;
265735c4bbdfSmrg
265835c4bbdfSmrg        if (inputFocus == NoneWin)
265935c4bbdfSmrg            return Success;
266035c4bbdfSmrg
266135c4bbdfSmrg        /* If the input focus is PointerRootWin, send the event to where
266235c4bbdfSmrg         * the pointer is if possible, then perhaps propogate up to root. */
266335c4bbdfSmrg        if (inputFocus == PointerRootWin)
266435c4bbdfSmrg            inputFocus = GetCurrentRootWindow(d);
266535c4bbdfSmrg
266635c4bbdfSmrg        if (IsParent(inputFocus, spriteWin)) {
266735c4bbdfSmrg            effectiveFocus = inputFocus;
266835c4bbdfSmrg            pWin = spriteWin;
266935c4bbdfSmrg        }
267035c4bbdfSmrg        else
267135c4bbdfSmrg            effectiveFocus = pWin = inputFocus;
267235c4bbdfSmrg    }
267335c4bbdfSmrg    else
267435c4bbdfSmrg        dixLookupWindow(&pWin, dest, client, DixSendAccess);
267505b261ecSmrg    if (!pWin)
267635c4bbdfSmrg        return BadWindow;
267705b261ecSmrg    if ((propagate != xFalse) && (propagate != xTrue)) {
267835c4bbdfSmrg        client->errorValue = propagate;
267935c4bbdfSmrg        return BadValue;
268005b261ecSmrg    }
268105b261ecSmrg    ev->u.u.type |= 0x80;
268205b261ecSmrg    if (propagate) {
268335c4bbdfSmrg        for (; pWin; pWin = pWin->parent) {
268435c4bbdfSmrg            if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab))
268535c4bbdfSmrg                return Success;
268635c4bbdfSmrg            if (pWin == effectiveFocus)
268735c4bbdfSmrg                return Success;
268835c4bbdfSmrg            if (wOtherInputMasks(pWin))
268935c4bbdfSmrg                mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id];
269035c4bbdfSmrg            if (!mask)
269135c4bbdfSmrg                break;
269235c4bbdfSmrg        }
269335c4bbdfSmrg    }
269435c4bbdfSmrg    else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count))
269535c4bbdfSmrg        DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab);
269605b261ecSmrg    return Success;
269705b261ecSmrg}
269805b261ecSmrg
269905b261ecSmrgint
270005b261ecSmrgSetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map)
270105b261ecSmrg{
270205b261ecSmrg    int i;
270305b261ecSmrg    ButtonClassPtr b = dev->button;
270405b261ecSmrg
270505b261ecSmrg    if (b == NULL)
270635c4bbdfSmrg        return BadMatch;
270705b261ecSmrg
270805b261ecSmrg    if (nElts != b->numButtons) {
270935c4bbdfSmrg        client->errorValue = nElts;
271035c4bbdfSmrg        return BadValue;
271105b261ecSmrg    }
271205b261ecSmrg    if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue))
271335c4bbdfSmrg        return BadValue;
271405b261ecSmrg    for (i = 0; i < nElts; i++)
271535c4bbdfSmrg        if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1))
271635c4bbdfSmrg            return MappingBusy;
271705b261ecSmrg    for (i = 0; i < nElts; i++)
271835c4bbdfSmrg        b->map[i + 1] = map[i];
271905b261ecSmrg    return Success;
272005b261ecSmrg}
272105b261ecSmrg
272205b261ecSmrgint
272305b261ecSmrgChangeKeyMapping(ClientPtr client,
272435c4bbdfSmrg                 DeviceIntPtr dev,
272535c4bbdfSmrg                 unsigned len,
272635c4bbdfSmrg                 int type,
272735c4bbdfSmrg                 KeyCode firstKeyCode,
272835c4bbdfSmrg                 CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map)
272905b261ecSmrg{
273005b261ecSmrg    KeySymsRec keysyms;
273105b261ecSmrg    KeyClassPtr k = dev->key;
273205b261ecSmrg
273305b261ecSmrg    if (k == NULL)
273435c4bbdfSmrg        return BadMatch;
273505b261ecSmrg
273605b261ecSmrg    if (len != (keyCodes * keySymsPerKeyCode))
273735c4bbdfSmrg        return BadLength;
273805b261ecSmrg
27396747b715Smrg    if ((firstKeyCode < k->xkbInfo->desc->min_key_code) ||
274035c4bbdfSmrg        (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) {
274135c4bbdfSmrg        client->errorValue = firstKeyCode;
274235c4bbdfSmrg        return BadValue;
274305b261ecSmrg    }
274405b261ecSmrg    if (keySymsPerKeyCode == 0) {
274535c4bbdfSmrg        client->errorValue = 0;
274635c4bbdfSmrg        return BadValue;
274705b261ecSmrg    }
274805b261ecSmrg    keysyms.minKeyCode = firstKeyCode;
274905b261ecSmrg    keysyms.maxKeyCode = firstKeyCode + keyCodes - 1;
275005b261ecSmrg    keysyms.mapWidth = keySymsPerKeyCode;
275105b261ecSmrg    keysyms.map = map;
27526747b715Smrg
27536747b715Smrg    XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL,
27546747b715Smrg                          serverClient);
27556747b715Smrg
27566747b715Smrg    return Success;
275705b261ecSmrg}
275805b261ecSmrg
275905b261ecSmrgstatic void
276005b261ecSmrgDeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
276105b261ecSmrg{
276205b261ecSmrg    WindowPtr parent;
276305b261ecSmrg
276405b261ecSmrg    /* Deactivate any grabs performed on this window, before making
276505b261ecSmrg     * any input focus changes.
276605b261ecSmrg     * Deactivating a device grab should cause focus events. */
276705b261ecSmrg
27684642e01fSmrg    if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin))
276935c4bbdfSmrg        (*dev->deviceGrab.DeactivateGrab) (dev);
277005b261ecSmrg
27714642e01fSmrg    /* If the focus window is a root window (ie. has no parent)
277205b261ecSmrg     * then don't delete the focus from it. */
277305b261ecSmrg
277405b261ecSmrg    if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) {
277535c4bbdfSmrg        int focusEventMode = NotifyNormal;
277635c4bbdfSmrg
277735c4bbdfSmrg        /* If a grab is in progress, then alter the mode of focus events. */
277835c4bbdfSmrg
277935c4bbdfSmrg        if (dev->deviceGrab.grab)
278035c4bbdfSmrg            focusEventMode = NotifyWhileGrabbed;
278135c4bbdfSmrg
278235c4bbdfSmrg        switch (dev->focus->revert) {
278335c4bbdfSmrg        case RevertToNone:
278435c4bbdfSmrg            if (!ActivateFocusInGrab(dev, pWin, NoneWin))
278535c4bbdfSmrg                DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
278635c4bbdfSmrg            dev->focus->win = NoneWin;
278735c4bbdfSmrg            dev->focus->traceGood = 0;
278835c4bbdfSmrg            break;
278935c4bbdfSmrg        case RevertToParent:
279035c4bbdfSmrg            parent = pWin;
279135c4bbdfSmrg            do {
279235c4bbdfSmrg                parent = parent->parent;
279335c4bbdfSmrg                dev->focus->traceGood--;
279435c4bbdfSmrg            }
279535c4bbdfSmrg            while (!parent->realized);
279635c4bbdfSmrg            if (!ActivateFocusInGrab(dev, pWin, parent))
279735c4bbdfSmrg                DoFocusEvents(dev, pWin, parent, focusEventMode);
279835c4bbdfSmrg            dev->focus->win = parent;
279935c4bbdfSmrg            dev->focus->revert = RevertToNone;
280035c4bbdfSmrg            break;
280135c4bbdfSmrg        case RevertToPointerRoot:
280235c4bbdfSmrg            if (!ActivateFocusInGrab(dev, pWin, PointerRootWin))
280335c4bbdfSmrg                DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode);
280435c4bbdfSmrg            dev->focus->win = PointerRootWin;
280535c4bbdfSmrg            dev->focus->traceGood = 0;
280635c4bbdfSmrg            break;
280735c4bbdfSmrg        case RevertToFollowKeyboard:
280835c4bbdfSmrg        {
280935c4bbdfSmrg            DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD);
281035c4bbdfSmrg
281135c4bbdfSmrg            if (!kbd || (kbd == dev && kbd != inputInfo.keyboard))
281235c4bbdfSmrg                kbd = inputInfo.keyboard;
281335c4bbdfSmrg            if (kbd->focus->win) {
281435c4bbdfSmrg                if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win))
281535c4bbdfSmrg                    DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode);
281635c4bbdfSmrg                dev->focus->win = FollowKeyboardWin;
281735c4bbdfSmrg                dev->focus->traceGood = 0;
281835c4bbdfSmrg            }
281935c4bbdfSmrg            else {
28206747b715Smrg                if (!ActivateFocusInGrab(dev, pWin, NoneWin))
28216747b715Smrg                    DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
282235c4bbdfSmrg                dev->focus->win = NoneWin;
282335c4bbdfSmrg                dev->focus->traceGood = 0;
28246747b715Smrg            }
282535c4bbdfSmrg        }
282635c4bbdfSmrg            break;
282735c4bbdfSmrg        }
282805b261ecSmrg    }
282905b261ecSmrg
283005b261ecSmrg    if (dev->valuator)
283135c4bbdfSmrg        if (dev->valuator->motionHintWindow == pWin)
283235c4bbdfSmrg            dev->valuator->motionHintWindow = NullWindow;
283305b261ecSmrg}
283405b261ecSmrg
283505b261ecSmrgvoid
283605b261ecSmrgDeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources)
283705b261ecSmrg{
283805b261ecSmrg    int i;
283905b261ecSmrg    DeviceIntPtr dev;
284005b261ecSmrg    InputClientsPtr ic;
284105b261ecSmrg    struct _OtherInputMasks *inputMasks;
284205b261ecSmrg
284305b261ecSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
284435c4bbdfSmrg        DeleteDeviceFromAnyExtEvents(pWin, dev);
284505b261ecSmrg    }
284605b261ecSmrg
284705b261ecSmrg    for (dev = inputInfo.off_devices; dev; dev = dev->next)
284835c4bbdfSmrg        DeleteDeviceFromAnyExtEvents(pWin, dev);
284905b261ecSmrg
285005b261ecSmrg    if (freeResources)
285135c4bbdfSmrg        while ((inputMasks = wOtherInputMasks(pWin)) != 0) {
285235c4bbdfSmrg            ic = inputMasks->inputClients;
285335c4bbdfSmrg            for (i = 0; i < EMASKSIZE; i++)
285435c4bbdfSmrg                inputMasks->dontPropagateMask[i] = 0;
285535c4bbdfSmrg            FreeResource(ic->resource, RT_NONE);
285635c4bbdfSmrg        }
285705b261ecSmrg}
285805b261ecSmrg
285905b261ecSmrgint
286035c4bbdfSmrgMaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer *pEvents, Mask mask)
286105b261ecSmrg{
286205b261ecSmrg    DeviceIntPtr dev;
286305b261ecSmrg
28644642e01fSmrg    dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient,
286535c4bbdfSmrg                    DixReadAccess);
286605b261ecSmrg    if (!dev)
286705b261ecSmrg        return 0;
286805b261ecSmrg
286905b261ecSmrg    if (pEvents->type == DeviceMotionNotify) {
287035c4bbdfSmrg        if (mask & DevicePointerMotionHintMask) {
287135c4bbdfSmrg            if (WID(dev->valuator->motionHintWindow) == pEvents->event) {
287235c4bbdfSmrg                return 1;       /* don't send, but pretend we did */
287335c4bbdfSmrg            }
287435c4bbdfSmrg            pEvents->detail = NotifyHint;
287535c4bbdfSmrg        }
287635c4bbdfSmrg        else {
287735c4bbdfSmrg            pEvents->detail = NotifyNormal;
287835c4bbdfSmrg        }
287905b261ecSmrg    }
28806747b715Smrg    return 0;
288105b261ecSmrg}
288205b261ecSmrg
288305b261ecSmrgvoid
288405b261ecSmrgCheckDeviceGrabAndHintWindow(WindowPtr pWin, int type,
288535c4bbdfSmrg                             deviceKeyButtonPointer *xE, GrabPtr grab,
288635c4bbdfSmrg                             ClientPtr client, Mask deliveryMask)
288705b261ecSmrg{
288805b261ecSmrg    DeviceIntPtr dev;
288905b261ecSmrg
28904642e01fSmrg    dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient,
289135c4bbdfSmrg                    DixGrabAccess);
289205b261ecSmrg    if (!dev)
289305b261ecSmrg        return;
289405b261ecSmrg
289505b261ecSmrg    if (type == DeviceMotionNotify)
289635c4bbdfSmrg        dev->valuator->motionHintWindow = pWin;
289705b261ecSmrg    else if ((type == DeviceButtonPress) && (!grab) &&
289835c4bbdfSmrg             (deliveryMask & DeviceButtonGrabMask)) {
289935c4bbdfSmrg        GrabPtr tempGrab;
290005b261ecSmrg
290135c4bbdfSmrg        tempGrab = AllocGrab(NULL);
290235c4bbdfSmrg        if (!tempGrab)
290335c4bbdfSmrg            return;
290435c4bbdfSmrg
290535c4bbdfSmrg        tempGrab->device = dev;
290635c4bbdfSmrg        tempGrab->resource = client->clientAsMask;
290735c4bbdfSmrg        tempGrab->window = pWin;
290835c4bbdfSmrg        tempGrab->ownerEvents =
290935c4bbdfSmrg            (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE;
291035c4bbdfSmrg        tempGrab->eventMask = deliveryMask;
291135c4bbdfSmrg        tempGrab->keyboardMode = GrabModeAsync;
291235c4bbdfSmrg        tempGrab->pointerMode = GrabModeAsync;
291335c4bbdfSmrg        tempGrab->confineTo = NullWindow;
291435c4bbdfSmrg        tempGrab->cursor = NullCursor;
291535c4bbdfSmrg        tempGrab->next = NULL;
291635c4bbdfSmrg        (*dev->deviceGrab.ActivateGrab) (dev, tempGrab, currentTime, TRUE);
291735c4bbdfSmrg        FreeGrab(tempGrab);
291805b261ecSmrg    }
291905b261ecSmrg}
292005b261ecSmrg
292105b261ecSmrgstatic Mask
292205b261ecSmrgDeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client)
292305b261ecSmrg{
292405b261ecSmrg    InputClientsPtr other;
292505b261ecSmrg
292605b261ecSmrg    if (!wOtherInputMasks(pWin))
292735c4bbdfSmrg        return 0;
292805b261ecSmrg    for (other = wOtherInputMasks(pWin)->inputClients; other;
292935c4bbdfSmrg         other = other->next) {
293035c4bbdfSmrg        if (SameClient(other, client))
293135c4bbdfSmrg            return other->mask[dev->id];
293205b261ecSmrg    }
293305b261ecSmrg    return 0;
293405b261ecSmrg}
293505b261ecSmrg
293605b261ecSmrgvoid
293705b261ecSmrgMaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client)
293805b261ecSmrg{
293905b261ecSmrg    WindowPtr pWin;
29404642e01fSmrg    GrabPtr grab = dev->deviceGrab.grab;
294105b261ecSmrg
294205b261ecSmrg    pWin = dev->valuator->motionHintWindow;
294305b261ecSmrg
294405b261ecSmrg    if ((grab && SameClient(grab, client) &&
294535c4bbdfSmrg         ((grab->eventMask & DevicePointerMotionHintMask) ||
294635c4bbdfSmrg          (grab->ownerEvents &&
294735c4bbdfSmrg           (DeviceEventMaskForClient(dev, pWin, client) &
294835c4bbdfSmrg            DevicePointerMotionHintMask)))) ||
294935c4bbdfSmrg        (!grab &&
295035c4bbdfSmrg         (DeviceEventMaskForClient(dev, pWin, client) &
295135c4bbdfSmrg          DevicePointerMotionHintMask)))
295235c4bbdfSmrg        dev->valuator->motionHintWindow = NullWindow;
295305b261ecSmrg}
295405b261ecSmrg
295505b261ecSmrgint
295605b261ecSmrgDeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask,
295735c4bbdfSmrg                             int maskndx)
295805b261ecSmrg{
295905b261ecSmrg    struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
296005b261ecSmrg
296105b261ecSmrg    if (mask & ~PropagateMask[maskndx]) {
296235c4bbdfSmrg        client->errorValue = mask;
296335c4bbdfSmrg        return BadValue;
296405b261ecSmrg    }
296505b261ecSmrg
296605b261ecSmrg    if (mask == 0) {
296735c4bbdfSmrg        if (inputMasks)
296835c4bbdfSmrg            inputMasks->dontPropagateMask[maskndx] = mask;
296935c4bbdfSmrg    }
297035c4bbdfSmrg    else {
297135c4bbdfSmrg        if (!inputMasks)
297235c4bbdfSmrg            AddExtensionClient(pWin, client, 0, 0);
297335c4bbdfSmrg        inputMasks = wOtherInputMasks(pWin);
297435c4bbdfSmrg        inputMasks->dontPropagateMask[maskndx] = mask;
297505b261ecSmrg    }
297605b261ecSmrg    RecalculateDeviceDeliverableEvents(pWin);
297705b261ecSmrg    if (ShouldFreeInputMasks(pWin, FALSE))
297835c4bbdfSmrg        FreeResource(inputMasks->inputClients->resource, RT_NONE);
297905b261ecSmrg    return Success;
298005b261ecSmrg}
298105b261ecSmrg
29824642e01fSmrgBool
298305b261ecSmrgShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents)
298405b261ecSmrg{
298505b261ecSmrg    int i;
298605b261ecSmrg    Mask allInputEventMasks = 0;
298705b261ecSmrg    struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
298805b261ecSmrg
298905b261ecSmrg    for (i = 0; i < EMASKSIZE; i++)
299035c4bbdfSmrg        allInputEventMasks |= inputMasks->dontPropagateMask[i];
299105b261ecSmrg    if (!ignoreSelectedEvents)
299235c4bbdfSmrg        for (i = 0; i < EMASKSIZE; i++)
299335c4bbdfSmrg            allInputEventMasks |= inputMasks->inputEvents[i];
299405b261ecSmrg    if (allInputEventMasks == 0)
299535c4bbdfSmrg        return TRUE;
299605b261ecSmrg    else
299735c4bbdfSmrg        return FALSE;
299805b261ecSmrg}
299905b261ecSmrg
300005b261ecSmrg/***********************************************************************
300105b261ecSmrg *
300205b261ecSmrg * Walk through the window tree, finding all clients that want to know
300305b261ecSmrg * about the Event.
300405b261ecSmrg *
300505b261ecSmrg */
300605b261ecSmrg
300705b261ecSmrgstatic void
300805b261ecSmrgFindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask,
300935c4bbdfSmrg                       xEvent *ev, int count)
301005b261ecSmrg{
301105b261ecSmrg    WindowPtr p2;
301205b261ecSmrg
301305b261ecSmrg    while (p1) {
301405b261ecSmrg        p2 = p1->firstChild;
30156747b715Smrg        DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab);
301605b261ecSmrg        FindInterestedChildren(dev, p2, mask, ev, count);
301705b261ecSmrg        p1 = p1->nextSib;
301805b261ecSmrg    }
301905b261ecSmrg}
302005b261ecSmrg
302105b261ecSmrg/***********************************************************************
302205b261ecSmrg *
302305b261ecSmrg * Send an event to interested clients in all windows on all screens.
302405b261ecSmrg *
302505b261ecSmrg */
302605b261ecSmrg
302705b261ecSmrgvoid
302835c4bbdfSmrgSendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent *ev, int count)
302905b261ecSmrg{
303005b261ecSmrg    int i;
303105b261ecSmrg    WindowPtr pWin, p1;
303205b261ecSmrg
303305b261ecSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
30346747b715Smrg        pWin = screenInfo.screens[i]->root;
30354642e01fSmrg        if (!pWin)
30364642e01fSmrg            continue;
30376747b715Smrg        DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab);
303805b261ecSmrg        p1 = pWin->firstChild;
303905b261ecSmrg        FindInterestedChildren(dev, p1, mask, ev, count);
304005b261ecSmrg    }
304105b261ecSmrg}
30424642e01fSmrg
30436747b715Smrg/**
30446747b715Smrg * Set the XI2 mask for the given client on the given window.
30456747b715Smrg * @param dev The device to set the mask for.
30466747b715Smrg * @param win The window to set the mask on.
30476747b715Smrg * @param client The client setting the mask.
30486747b715Smrg * @param len Number of bytes in mask.
30496747b715Smrg * @param mask Event mask in the form of (1 << eventtype)
30506747b715Smrg */
30516747b715Smrgint
30526747b715SmrgXISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
305335c4bbdfSmrg               unsigned int len, unsigned char *mask)
30546747b715Smrg{
30556747b715Smrg    OtherInputMasks *masks;
30566747b715Smrg    InputClientsPtr others = NULL;
30576747b715Smrg
30586747b715Smrg    masks = wOtherInputMasks(win);
305935c4bbdfSmrg    if (masks) {
306035c4bbdfSmrg        for (others = wOtherInputMasks(win)->inputClients; others;
306135c4bbdfSmrg             others = others->next) {
306235c4bbdfSmrg            if (SameClient(others, client)) {
306335c4bbdfSmrg                xi2mask_zero(others->xi2mask, dev->id);
30646747b715Smrg                break;
30656747b715Smrg            }
30666747b715Smrg        }
30676747b715Smrg    }
30686747b715Smrg
306935c4bbdfSmrg    if (len && !others) {
30706747b715Smrg        if (AddExtensionClient(win, client, 0, 0) != Success)
30716747b715Smrg            return BadAlloc;
307235c4bbdfSmrg        others = wOtherInputMasks(win)->inputClients;
30736747b715Smrg    }
30746747b715Smrg
307535c4bbdfSmrg    if (others) {
307635c4bbdfSmrg        xi2mask_zero(others->xi2mask, dev->id);
307735c4bbdfSmrg        len = min(len, xi2mask_mask_size(others->xi2mask));
307835c4bbdfSmrg    }
30796747b715Smrg
308035c4bbdfSmrg    if (len) {
308135c4bbdfSmrg        xi2mask_set_one_mask(others->xi2mask, dev->id, mask, len);
308235c4bbdfSmrg    }
30836747b715Smrg
30846747b715Smrg    RecalculateDeviceDeliverableEvents(win);
30856747b715Smrg
30866747b715Smrg    return Success;
30876747b715Smrg}
3088