xipassivegrab.c revision e383896c
1/* 2 * Copyright © 2009 Red Hat, Inc. 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 24 */ 25 26/*********************************************************************** 27 * 28 * Request to grab or ungrab input device. 29 * 30 */ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include "inputstr.h" /* DeviceIntPtr */ 37#include "windowstr.h" /* window structure */ 38#include <X11/extensions/XI2.h> 39#include <X11/extensions/XI2proto.h> 40#include "swaprep.h" 41 42#include "exglobals.h" /* BadDevice */ 43#include "exevents.h" 44#include "xipassivegrab.h" 45#include "dixgrabs.h" 46#include "misc.h" 47#include "inpututils.h" 48 49int _X_COLD 50SProcXIPassiveGrabDevice(ClientPtr client) 51{ 52 int i; 53 uint32_t *mods; 54 55 REQUEST(xXIPassiveGrabDeviceReq); 56 REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq); 57 58 swaps(&stuff->length); 59 swaps(&stuff->deviceid); 60 swapl(&stuff->grab_window); 61 swapl(&stuff->cursor); 62 swapl(&stuff->time); 63 swapl(&stuff->detail); 64 swaps(&stuff->mask_len); 65 swaps(&stuff->num_modifiers); 66 67 REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq, 68 ((uint32_t) stuff->mask_len + stuff->num_modifiers) *4); 69 mods = (uint32_t *) &stuff[1] + stuff->mask_len; 70 71 for (i = 0; i < stuff->num_modifiers; i++, mods++) { 72 swapl(mods); 73 } 74 75 return ProcXIPassiveGrabDevice(client); 76} 77 78int 79ProcXIPassiveGrabDevice(ClientPtr client) 80{ 81 DeviceIntPtr dev, mod_dev; 82 xXIPassiveGrabDeviceReply rep = { 83 .repType = X_Reply, 84 .RepType = X_XIPassiveGrabDevice, 85 .sequenceNumber = client->sequence, 86 .length = 0, 87 .num_modifiers = 0 88 }; 89 int i, ret = Success; 90 uint32_t *modifiers; 91 xXIGrabModifierInfo *modifiers_failed = NULL; 92 GrabMask mask = { 0 }; 93 GrabParameters param; 94 void *tmp; 95 int mask_len; 96 97 REQUEST(xXIPassiveGrabDeviceReq); 98 REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq, 99 ((uint32_t) stuff->mask_len + stuff->num_modifiers) * 4); 100 101 if (stuff->deviceid == XIAllDevices) 102 dev = inputInfo.all_devices; 103 else if (stuff->deviceid == XIAllMasterDevices) 104 dev = inputInfo.all_master_devices; 105 else { 106 ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); 107 if (ret != Success) { 108 client->errorValue = stuff->deviceid; 109 return ret; 110 } 111 } 112 113 if (stuff->grab_type != XIGrabtypeButton && 114 stuff->grab_type != XIGrabtypeKeycode && 115 stuff->grab_type != XIGrabtypeEnter && 116 stuff->grab_type != XIGrabtypeFocusIn && 117 stuff->grab_type != XIGrabtypeTouchBegin && 118 stuff->grab_type != XIGrabtypeGesturePinchBegin && 119 stuff->grab_type != XIGrabtypeGestureSwipeBegin) { 120 client->errorValue = stuff->grab_type; 121 return BadValue; 122 } 123 124 if ((stuff->grab_type == XIGrabtypeEnter || 125 stuff->grab_type == XIGrabtypeFocusIn || 126 stuff->grab_type == XIGrabtypeTouchBegin || 127 stuff->grab_type == XIGrabtypeGesturePinchBegin || 128 stuff->grab_type == XIGrabtypeGestureSwipeBegin) && stuff->detail != 0) { 129 client->errorValue = stuff->detail; 130 return BadValue; 131 } 132 133 if (stuff->grab_type == XIGrabtypeTouchBegin && 134 (stuff->grab_mode != XIGrabModeTouch || 135 stuff->paired_device_mode != GrabModeAsync)) { 136 client->errorValue = stuff->grab_mode; 137 return BadValue; 138 } 139 140 /* XI2 allows 32-bit keycodes but thanks to XKB we can never 141 * implement this. Just return an error for all keycodes that 142 * cannot work anyway, same for buttons > 255. */ 143 if (stuff->detail > 255) 144 return XIAlreadyGrabbed; 145 146 if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1], 147 stuff->mask_len * 4) != Success) 148 return BadValue; 149 150 mask.xi2mask = xi2mask_new(); 151 if (!mask.xi2mask) 152 return BadAlloc; 153 154 mask_len = min(xi2mask_mask_size(mask.xi2mask), stuff->mask_len * 4); 155 xi2mask_set_one_mask(mask.xi2mask, stuff->deviceid, 156 (unsigned char *) &stuff[1], mask_len * 4); 157 158 memset(¶m, 0, sizeof(param)); 159 param.grabtype = XI2; 160 param.ownerEvents = stuff->owner_events; 161 param.grabWindow = stuff->grab_window; 162 param.cursor = stuff->cursor; 163 164 if (IsKeyboardDevice(dev)) { 165 param.this_device_mode = stuff->grab_mode; 166 param.other_devices_mode = stuff->paired_device_mode; 167 } 168 else { 169 param.this_device_mode = stuff->paired_device_mode; 170 param.other_devices_mode = stuff->grab_mode; 171 } 172 173 if (stuff->cursor != None) { 174 ret = dixLookupResourceByType(&tmp, stuff->cursor, 175 RT_CURSOR, client, DixUseAccess); 176 if (ret != Success) { 177 client->errorValue = stuff->cursor; 178 goto out; 179 } 180 } 181 182 ret = 183 dixLookupWindow((WindowPtr *) &tmp, stuff->grab_window, client, 184 DixSetAttrAccess); 185 if (ret != Success) 186 goto out; 187 188 ret = CheckGrabValues(client, ¶m); 189 if (ret != Success) 190 goto out; 191 192 modifiers = (uint32_t *) &stuff[1] + stuff->mask_len; 193 modifiers_failed = 194 calloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo)); 195 if (!modifiers_failed) { 196 ret = BadAlloc; 197 goto out; 198 } 199 200 mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD); 201 202 for (i = 0; i < stuff->num_modifiers; i++, modifiers++) { 203 uint8_t status = Success; 204 205 param.modifiers = *modifiers; 206 ret = CheckGrabValues(client, ¶m); 207 if (ret != Success) 208 goto out; 209 210 switch (stuff->grab_type) { 211 case XIGrabtypeButton: 212 status = GrabButton(client, dev, mod_dev, stuff->detail, 213 ¶m, XI2, &mask); 214 break; 215 case XIGrabtypeKeycode: 216 status = GrabKey(client, dev, mod_dev, stuff->detail, 217 ¶m, XI2, &mask); 218 break; 219 case XIGrabtypeEnter: 220 case XIGrabtypeFocusIn: 221 status = GrabWindow(client, dev, stuff->grab_type, ¶m, &mask); 222 break; 223 case XIGrabtypeTouchBegin: 224 status = GrabTouchOrGesture(client, dev, mod_dev, XI_TouchBegin, 225 ¶m, &mask); 226 break; 227 case XIGrabtypeGesturePinchBegin: 228 status = GrabTouchOrGesture(client, dev, mod_dev, 229 XI_GesturePinchBegin, ¶m, &mask); 230 break; 231 case XIGrabtypeGestureSwipeBegin: 232 status = GrabTouchOrGesture(client, dev, mod_dev, 233 XI_GestureSwipeBegin, ¶m, &mask); 234 break; 235 } 236 237 if (status != GrabSuccess) { 238 xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers; 239 240 info->status = status; 241 info->modifiers = *modifiers; 242 if (client->swapped) 243 swapl(&info->modifiers); 244 245 rep.num_modifiers++; 246 rep.length += bytes_to_int32(sizeof(xXIGrabModifierInfo)); 247 } 248 } 249 250 WriteReplyToClient(client, sizeof(rep), &rep); 251 if (rep.num_modifiers) 252 WriteToClient(client, rep.length * 4, modifiers_failed); 253 254 out: 255 free(modifiers_failed); 256 xi2mask_free(&mask.xi2mask); 257 return ret; 258} 259 260void _X_COLD 261SRepXIPassiveGrabDevice(ClientPtr client, int size, 262 xXIPassiveGrabDeviceReply * rep) 263{ 264 swaps(&rep->sequenceNumber); 265 swapl(&rep->length); 266 swaps(&rep->num_modifiers); 267 268 WriteToClient(client, size, rep); 269} 270 271int _X_COLD 272SProcXIPassiveUngrabDevice(ClientPtr client) 273{ 274 int i; 275 uint32_t *modifiers; 276 277 REQUEST(xXIPassiveUngrabDeviceReq); 278 REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq); 279 280 swaps(&stuff->length); 281 swapl(&stuff->grab_window); 282 swaps(&stuff->deviceid); 283 swapl(&stuff->detail); 284 swaps(&stuff->num_modifiers); 285 286 REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq, 287 ((uint32_t) stuff->num_modifiers) << 2); 288 modifiers = (uint32_t *) &stuff[1]; 289 290 for (i = 0; i < stuff->num_modifiers; i++, modifiers++) 291 swapl(modifiers); 292 293 return ProcXIPassiveUngrabDevice(client); 294} 295 296int 297ProcXIPassiveUngrabDevice(ClientPtr client) 298{ 299 DeviceIntPtr dev, mod_dev; 300 WindowPtr win; 301 GrabPtr tempGrab; 302 uint32_t *modifiers; 303 int i, rc; 304 305 REQUEST(xXIPassiveUngrabDeviceReq); 306 REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq, 307 ((uint32_t) stuff->num_modifiers) << 2); 308 309 if (stuff->deviceid == XIAllDevices) 310 dev = inputInfo.all_devices; 311 else if (stuff->deviceid == XIAllMasterDevices) 312 dev = inputInfo.all_master_devices; 313 else { 314 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess); 315 if (rc != Success) 316 return rc; 317 } 318 319 if (stuff->grab_type != XIGrabtypeButton && 320 stuff->grab_type != XIGrabtypeKeycode && 321 stuff->grab_type != XIGrabtypeEnter && 322 stuff->grab_type != XIGrabtypeFocusIn && 323 stuff->grab_type != XIGrabtypeTouchBegin && 324 stuff->grab_type != XIGrabtypeGesturePinchBegin && 325 stuff->grab_type != XIGrabtypeGestureSwipeBegin) { 326 client->errorValue = stuff->grab_type; 327 return BadValue; 328 } 329 330 if ((stuff->grab_type == XIGrabtypeEnter || 331 stuff->grab_type == XIGrabtypeFocusIn || 332 stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) { 333 client->errorValue = stuff->detail; 334 return BadValue; 335 } 336 337 /* We don't allow passive grabs for details > 255 anyway */ 338 if (stuff->detail > 255) { 339 client->errorValue = stuff->detail; 340 return BadValue; 341 } 342 343 rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess); 344 if (rc != Success) 345 return rc; 346 347 mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD); 348 349 tempGrab = AllocGrab(NULL); 350 if (!tempGrab) 351 return BadAlloc; 352 353 tempGrab->resource = client->clientAsMask; 354 tempGrab->device = dev; 355 tempGrab->window = win; 356 switch (stuff->grab_type) { 357 case XIGrabtypeButton: 358 tempGrab->type = XI_ButtonPress; 359 break; 360 case XIGrabtypeKeycode: 361 tempGrab->type = XI_KeyPress; 362 break; 363 case XIGrabtypeEnter: 364 tempGrab->type = XI_Enter; 365 break; 366 case XIGrabtypeFocusIn: 367 tempGrab->type = XI_FocusIn; 368 break; 369 case XIGrabtypeTouchBegin: 370 tempGrab->type = XI_TouchBegin; 371 break; 372 case XIGrabtypeGesturePinchBegin: 373 tempGrab->type = XI_GesturePinchBegin; 374 break; 375 case XIGrabtypeGestureSwipeBegin: 376 tempGrab->type = XI_GestureSwipeBegin; 377 break; 378 } 379 tempGrab->grabtype = XI2; 380 tempGrab->modifierDevice = mod_dev; 381 tempGrab->modifiersDetail.pMask = NULL; 382 tempGrab->detail.exact = stuff->detail; 383 tempGrab->detail.pMask = NULL; 384 385 modifiers = (uint32_t *) &stuff[1]; 386 387 for (i = 0; i < stuff->num_modifiers; i++, modifiers++) { 388 tempGrab->modifiersDetail.exact = *modifiers; 389 DeletePassiveGrabFromList(tempGrab); 390 } 391 392 FreeGrab(tempGrab); 393 394 return Success; 395} 396