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