xiselectev.c revision 9ace9065
1/* 2 * Copyright 2008 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#ifdef HAVE_DIX_CONFIG_H 27#include <dix-config.h> 28#endif 29 30 31#include "dixstruct.h" 32#include "windowstr.h" 33#include "exglobals.h" 34#include "exevents.h" 35#include <X11/extensions/XI2proto.h> 36 37#include "xiselectev.h" 38 39/** 40 * Check the given mask (in len bytes) for invalid mask bits. 41 * Invalid mask bits are any bits above XI2LastEvent. 42 * 43 * @return BadValue if at least one invalid bit is set or Success otherwise. 44 */ 45int XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len) 46{ 47 if (len >= XIMaskLen(XI2LASTEVENT)) 48 { 49 int i; 50 for (i = XI2LASTEVENT + 1; i < len * 8; i++) 51 { 52 if (BitIsOn(mask, i)) 53 { 54 client->errorValue = i; 55 return BadValue; 56 } 57 } 58 } 59 60 return Success; 61} 62 63int 64SProcXISelectEvents(ClientPtr client) 65{ 66 char n; 67 int i; 68 xXIEventMask* evmask; 69 70 REQUEST(xXISelectEventsReq); 71 swaps(&stuff->length, n); 72 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); 73 swapl(&stuff->win, n); 74 swaps(&stuff->num_masks, n); 75 76 evmask = (xXIEventMask*)&stuff[1]; 77 for (i = 0; i < stuff->num_masks; i++) 78 { 79 swaps(&evmask->deviceid, n); 80 swaps(&evmask->mask_len, n); 81 evmask = (xXIEventMask*)(((char*)&evmask[1]) + evmask->mask_len * 4); 82 } 83 84 return (ProcXISelectEvents(client)); 85} 86 87int 88ProcXISelectEvents(ClientPtr client) 89{ 90 int rc, num_masks; 91 WindowPtr win; 92 DeviceIntPtr dev; 93 DeviceIntRec dummy; 94 xXIEventMask *evmask; 95 int *types = NULL; 96 int len; 97 98 REQUEST(xXISelectEventsReq); 99 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq); 100 101 if (stuff->num_masks == 0) 102 return BadValue; 103 104 rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess); 105 if (rc != Success) 106 return rc; 107 108 len = sz_xXISelectEventsReq; 109 110 /* check request validity */ 111 evmask = (xXIEventMask*)&stuff[1]; 112 num_masks = stuff->num_masks; 113 while(num_masks--) 114 { 115 len += sizeof(xXIEventMask) + evmask->mask_len * 4; 116 117 if (bytes_to_int32(len) > stuff->length) 118 return BadLength; 119 120 if (evmask->deviceid != XIAllDevices && 121 evmask->deviceid != XIAllMasterDevices) 122 rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); 123 else { 124 /* XXX: XACE here? */ 125 } 126 if (rc != Success) 127 return rc; 128 129 /* hierarchy event mask is not allowed on devices */ 130 if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) 131 { 132 unsigned char *bits = (unsigned char*)&evmask[1]; 133 if (BitIsOn(bits, XI_HierarchyChanged)) 134 { 135 client->errorValue = XI_HierarchyChanged; 136 return BadValue; 137 } 138 } 139 140 /* Raw events may only be selected on root windows */ 141 if (win->parent && evmask->mask_len >= 1) 142 { 143 unsigned char *bits = (unsigned char*)&evmask[1]; 144 if (BitIsOn(bits, XI_RawKeyPress) || 145 BitIsOn(bits, XI_RawKeyRelease) || 146 BitIsOn(bits, XI_RawButtonPress) || 147 BitIsOn(bits, XI_RawButtonRelease) || 148 BitIsOn(bits, XI_RawMotion)) 149 { 150 client->errorValue = XI_RawKeyPress; 151 return BadValue; 152 } 153 } 154 155 if (XICheckInvalidMaskBits(client, (unsigned char*)&evmask[1], 156 evmask->mask_len * 4) != Success) 157 return BadValue; 158 159 evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); 160 evmask++; 161 } 162 163 if (bytes_to_int32(len) != stuff->length) 164 return BadLength; 165 166 /* Set masks on window */ 167 evmask = (xXIEventMask*)&stuff[1]; 168 num_masks = stuff->num_masks; 169 while(num_masks--) 170 { 171 if (evmask->deviceid == XIAllDevices || 172 evmask->deviceid == XIAllMasterDevices) 173 { 174 dummy.id = evmask->deviceid; 175 dev = &dummy; 176 } else 177 dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess); 178 if (XISetEventMask(dev, win, client, evmask->mask_len * 4, 179 (unsigned char*)&evmask[1]) != Success) 180 return BadAlloc; 181 evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4); 182 evmask++; 183 } 184 185 RecalculateDeliverableEvents(win); 186 187 free(types); 188 return Success; 189} 190 191 192int 193SProcXIGetSelectedEvents(ClientPtr client) 194{ 195 char n; 196 197 REQUEST(xXIGetSelectedEventsReq); 198 swaps(&stuff->length, n); 199 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); 200 swapl(&stuff->win, n); 201 202 return (ProcXIGetSelectedEvents(client)); 203} 204 205int 206ProcXIGetSelectedEvents(ClientPtr client) 207{ 208 int rc, i; 209 WindowPtr win; 210 char n; 211 char *buffer = NULL; 212 xXIGetSelectedEventsReply reply; 213 OtherInputMasks *masks; 214 InputClientsPtr others = NULL; 215 xXIEventMask *evmask = NULL; 216 DeviceIntPtr dev; 217 218 REQUEST(xXIGetSelectedEventsReq); 219 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq); 220 221 rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess); 222 if (rc != Success) 223 return rc; 224 225 reply.repType = X_Reply; 226 reply.RepType = X_XIGetSelectedEvents; 227 reply.length = 0; 228 reply.sequenceNumber = client->sequence; 229 reply.num_masks = 0; 230 231 masks = wOtherInputMasks(win); 232 if (masks) 233 { 234 for (others = wOtherInputMasks(win)->inputClients; others; 235 others = others->next) { 236 if (SameClient(others, client)) { 237 break; 238 } 239 } 240 } 241 242 if (!others) 243 { 244 WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); 245 return Success; 246 } 247 248 buffer = calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE)); 249 if (!buffer) 250 return BadAlloc; 251 252 evmask = (xXIEventMask*)buffer; 253 for (i = 0; i < MAXDEVICES; i++) 254 { 255 int j; 256 unsigned char *devmask = others->xi2mask[i]; 257 258 if (i > 2) 259 { 260 rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess); 261 if (rc != Success) 262 continue; 263 } 264 265 266 for (j = XI2MASKSIZE - 1; j >= 0; j--) 267 { 268 if (devmask[j] != 0) 269 { 270 int mask_len = (j + 4)/4; /* j is an index, hence + 4, not + 3 */ 271 evmask->deviceid = i; 272 evmask->mask_len = mask_len; 273 reply.num_masks++; 274 reply.length += sizeof(xXIEventMask)/4 + evmask->mask_len; 275 276 if (client->swapped) 277 { 278 swaps(&evmask->deviceid, n); 279 swaps(&evmask->mask_len, n); 280 } 281 282 memcpy(&evmask[1], devmask, j + 1); 283 evmask = (xXIEventMask*)((char*)evmask + 284 sizeof(xXIEventMask) + mask_len * 4); 285 break; 286 } 287 } 288 } 289 290 WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply); 291 292 if (reply.num_masks) 293 WriteToClient(client, reply.length * 4, buffer); 294 295 free(buffer); 296 return Success; 297} 298 299void SRepXIGetSelectedEvents(ClientPtr client, 300 int len, xXIGetSelectedEventsReply *rep) 301{ 302 char n; 303 304 swaps(&rep->sequenceNumber, n); 305 swapl(&rep->length, n); 306 swaps(&rep->num_masks, n); 307 WriteToClient(client, len, (char *)rep); 308} 309 310 311