1/* 2 * Copyright 2007-2008 Peter Hutterer 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Author: Peter Hutterer, University of South Australia, NICTA 24 */ 25 26/*********************************************************************** 27 * 28 * Request to query the pointer location of an extension input device. 29 * 30 */ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <X11/X.h> /* for inputstr.h */ 37#include <X11/Xproto.h> /* Request macro */ 38#include "inputstr.h" /* DeviceIntPtr */ 39#include "windowstr.h" /* window structure */ 40#include <X11/extensions/XI.h> 41#include <X11/extensions/XI2proto.h> 42#include "extnsionst.h" 43#include "exevents.h" 44#include "exglobals.h" 45#include "eventconvert.h" 46#include "scrnintstr.h" 47#include "xkbsrv.h" 48 49#ifdef PANORAMIX 50#include "panoramiXsrv.h" 51#endif 52 53#include "inpututils.h" 54#include "xiquerypointer.h" 55 56/*********************************************************************** 57 * 58 * This procedure allows a client to query the pointer of a device. 59 * 60 */ 61 62int _X_COLD 63SProcXIQueryPointer(ClientPtr client) 64{ 65 REQUEST(xXIQueryPointerReq); 66 REQUEST_SIZE_MATCH(xXIQueryPointerReq); 67 68 swaps(&stuff->length); 69 swaps(&stuff->deviceid); 70 swapl(&stuff->win); 71 return (ProcXIQueryPointer(client)); 72} 73 74int 75ProcXIQueryPointer(ClientPtr client) 76{ 77 int rc; 78 xXIQueryPointerReply rep; 79 DeviceIntPtr pDev, kbd; 80 WindowPtr pWin, t; 81 SpritePtr pSprite; 82 XkbStatePtr state; 83 char *buttons = NULL; 84 int buttons_size = 0; /* size of buttons array */ 85 XIClientPtr xi_client; 86 Bool have_xi22 = FALSE; 87 88 REQUEST(xXIQueryPointerReq); 89 REQUEST_SIZE_MATCH(xXIQueryPointerReq); 90 91 /* Check if client is compliant with XInput 2.2 or later. Earlier clients 92 * do not know about touches, so we must report emulated button presses. 2.2 93 * and later clients are aware of touches, so we don't include emulated 94 * button presses in the reply. */ 95 xi_client = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey); 96 if (version_compare(xi_client->major_version, 97 xi_client->minor_version, 2, 2) >= 0) 98 have_xi22 = TRUE; 99 100 rc = dixLookupDevice(&pDev, stuff->deviceid, client, DixReadAccess); 101 if (rc != Success) { 102 client->errorValue = stuff->deviceid; 103 return rc; 104 } 105 106 if (pDev->valuator == NULL || IsKeyboardDevice(pDev) || (!IsMaster(pDev) && !IsFloating(pDev))) { /* no attached devices */ 107 client->errorValue = stuff->deviceid; 108 return BadDevice; 109 } 110 111 rc = dixLookupWindow(&pWin, stuff->win, client, DixGetAttrAccess); 112 if (rc != Success) { 113 client->errorValue = stuff->win; 114 return rc; 115 } 116 117 if (pDev->valuator->motionHintWindow) 118 MaybeStopHint(pDev, client); 119 120 if (IsMaster(pDev)) 121 kbd = GetMaster(pDev, MASTER_KEYBOARD); 122 else 123 kbd = (pDev->key) ? pDev : NULL; 124 125 pSprite = pDev->spriteInfo->sprite; 126 127 rep = (xXIQueryPointerReply) { 128 .repType = X_Reply, 129 .RepType = X_XIQueryPointer, 130 .sequenceNumber = client->sequence, 131 .length = 6, 132 .root = (GetCurrentRootWindow(pDev))->drawable.id, 133 .root_x = double_to_fp1616(pSprite->hot.x), 134 .root_y = double_to_fp1616(pSprite->hot.y), 135 .child = None 136 }; 137 138 if (kbd) { 139 state = &kbd->key->xkbInfo->state; 140 rep.mods.base_mods = state->base_mods; 141 rep.mods.latched_mods = state->latched_mods; 142 rep.mods.locked_mods = state->locked_mods; 143 144 rep.group.base_group = state->base_group; 145 rep.group.latched_group = state->latched_group; 146 rep.group.locked_group = state->locked_group; 147 } 148 149 if (pDev->button) { 150 int i; 151 152 rep.buttons_len = bytes_to_int32(bits_to_bytes(256)); /* button map up to 255 */ 153 rep.length += rep.buttons_len; 154 buttons = calloc(rep.buttons_len, 4); 155 if (!buttons) 156 return BadAlloc; 157 buttons_size = rep.buttons_len * 4; 158 159 for (i = 1; i < pDev->button->numButtons; i++) 160 if (BitIsOn(pDev->button->down, i)) 161 SetBit(buttons, pDev->button->map[i]); 162 163 if (!have_xi22 && pDev->touch && pDev->touch->buttonsDown > 0) 164 SetBit(buttons, pDev->button->map[1]); 165 } 166 else 167 rep.buttons_len = 0; 168 169 if (pSprite->hot.pScreen == pWin->drawable.pScreen) { 170 rep.same_screen = xTrue; 171 rep.win_x = double_to_fp1616(pSprite->hot.x - pWin->drawable.x); 172 rep.win_y = double_to_fp1616(pSprite->hot.y - pWin->drawable.y); 173 for (t = pSprite->win; t; t = t->parent) 174 if (t->parent == pWin) { 175 rep.child = t->drawable.id; 176 break; 177 } 178 } 179 else { 180 rep.same_screen = xFalse; 181 rep.win_x = 0; 182 rep.win_y = 0; 183 } 184 185#ifdef PANORAMIX 186 if (!noPanoramiXExtension) { 187 rep.root_x += double_to_fp1616(screenInfo.screens[0]->x); 188 rep.root_y += double_to_fp1616(screenInfo.screens[0]->y); 189 if (stuff->win == rep.root) { 190 rep.win_x += double_to_fp1616(screenInfo.screens[0]->x); 191 rep.win_y += double_to_fp1616(screenInfo.screens[0]->y); 192 } 193 } 194#endif 195 196 WriteReplyToClient(client, sizeof(xXIQueryPointerReply), &rep); 197 if (buttons) 198 WriteToClient(client, buttons_size, buttons); 199 200 free(buttons); 201 202 return Success; 203} 204 205/*********************************************************************** 206 * 207 * This procedure writes the reply for the XIQueryPointer function, 208 * if the client and server have a different byte ordering. 209 * 210 */ 211 212void 213SRepXIQueryPointer(ClientPtr client, int size, xXIQueryPointerReply * rep) 214{ 215 swaps(&rep->sequenceNumber); 216 swapl(&rep->length); 217 swapl(&rep->root); 218 swapl(&rep->child); 219 swapl(&rep->root_x); 220 swapl(&rep->root_y); 221 swapl(&rep->win_x); 222 swapl(&rep->win_y); 223 swaps(&rep->buttons_len); 224 225 WriteToClient(client, size, rep); 226} 227