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 #include "dixstruct.h"
31 #include "windowstr.h"
32 #include "exglobals.h"
33 #include "exevents.h"
34 #include <X11/extensions/XI2proto.h>
35 #include "inpututils.h"
36
37 #include "xiselectev.h"
38
39 /**
40 * Ruleset:
41 * - if A has XIAllDevices, B may select on device X
42 * - If A has XIAllDevices, B may select on XIAllMasterDevices
43 * - If A has XIAllMasterDevices, B may select on device X
44 * - If A has XIAllMasterDevices, B may select on XIAllDevices
45 * - if A has device X, B may select on XIAllDevices/XIAllMasterDevices
46 */
check_for_touch_selection_conflicts(ClientPtr B,WindowPtr win,int deviceid)47 static int check_for_touch_selection_conflicts(ClientPtr B, WindowPtr win, int deviceid)
48 {
49 OtherInputMasks *inputMasks = wOtherInputMasks(win);
50 InputClients *A = NULL;
51
52 if (inputMasks)
53 A = inputMasks->inputClients;
54 for (; A; A = A->next) {
55 DeviceIntPtr tmp;
56
57 if (CLIENT_ID(A->resource) == B->index)
58 continue;
59
60 if (deviceid == XIAllDevices)
61 tmp = inputInfo.all_devices;
62 else if (deviceid == XIAllMasterDevices)
63 tmp = inputInfo.all_master_devices;
64 else
65 dixLookupDevice(&tmp, deviceid, serverClient, DixReadAccess);
66 if (!tmp)
67 return BadImplementation; /* this shouldn't happen */
68
69 /* A has XIAllDevices */
70 if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_devices, XI_TouchBegin)) {
71 if (deviceid == XIAllDevices)
72 return BadAccess;
73 }
74
75 /* A has XIAllMasterDevices */
76 if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_master_devices, XI_TouchBegin)) {
77 if (deviceid == XIAllMasterDevices)
78 return BadAccess;
79 }
80
81 /* A has this device */
82 if (xi2mask_isset_for_device(A->xi2mask, tmp, XI_TouchBegin))
83 return BadAccess;
84 }
85
86 return Success;
87 }
88
89
90 /**
91 * Check the given mask (in len bytes) for invalid mask bits.
92 * Invalid mask bits are any bits above XI2LastEvent.
93 *
94 * @return BadValue if at least one invalid bit is set or Success otherwise.
95 */
96 int
XICheckInvalidMaskBits(ClientPtr client,unsigned char * mask,int len)97 XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len)
98 {
99 if (len >= XIMaskLen(XI2LASTEVENT)) {
100 int i;
101
102 for (i = XI2LASTEVENT + 1; i < len * 8; i++) {
103 if (BitIsOn(mask, i)) {
104 client->errorValue = i;
105 return BadValue;
106 }
107 }
108 }
109
110 return Success;
111 }
112
113 int _X_COLD
SProcXISelectEvents(ClientPtr client)114 SProcXISelectEvents(ClientPtr client)
115 {
116 int i;
117 int len;
118 xXIEventMask *evmask;
119
120 REQUEST(xXISelectEventsReq);
121 swaps(&stuff->length);
122 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
123 swapl(&stuff->win);
124 swaps(&stuff->num_masks);
125
126 len = stuff->length - bytes_to_int32(sizeof(xXISelectEventsReq));
127 evmask = (xXIEventMask *) &stuff[1];
128 for (i = 0; i < stuff->num_masks; i++) {
129 if (len < bytes_to_int32(sizeof(xXIEventMask)))
130 return BadLength;
131 len -= bytes_to_int32(sizeof(xXIEventMask));
132 swaps(&evmask->deviceid);
133 swaps(&evmask->mask_len);
134 if (len < evmask->mask_len)
135 return BadLength;
136 len -= evmask->mask_len;
137 evmask =
138 (xXIEventMask *) (((char *) &evmask[1]) + evmask->mask_len * 4);
139 }
140
141 return (ProcXISelectEvents(client));
142 }
143
144 int
ProcXISelectEvents(ClientPtr client)145 ProcXISelectEvents(ClientPtr client)
146 {
147 int rc, num_masks;
148 WindowPtr win;
149 DeviceIntPtr dev;
150 DeviceIntRec dummy;
151 xXIEventMask *evmask;
152 int *types = NULL;
153 int len;
154
155 REQUEST(xXISelectEventsReq);
156 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
157
158 if (stuff->num_masks == 0)
159 return BadValue;
160
161 rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess);
162 if (rc != Success)
163 return rc;
164
165 len = sz_xXISelectEventsReq;
166
167 /* check request validity */
168 evmask = (xXIEventMask *) &stuff[1];
169 num_masks = stuff->num_masks;
170 while (num_masks--) {
171 len += sizeof(xXIEventMask) + evmask->mask_len * 4;
172
173 if (bytes_to_int32(len) > stuff->length)
174 return BadLength;
175
176 if (evmask->deviceid != XIAllDevices &&
177 evmask->deviceid != XIAllMasterDevices)
178 rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
179 else {
180 /* XXX: XACE here? */
181 }
182 if (rc != Success)
183 return rc;
184
185 /* hierarchy event mask is not allowed on devices */
186 if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) {
187 unsigned char *bits = (unsigned char *) &evmask[1];
188
189 if (BitIsOn(bits, XI_HierarchyChanged)) {
190 client->errorValue = XI_HierarchyChanged;
191 return BadValue;
192 }
193 }
194
195 /* Raw events may only be selected on root windows */
196 if (win->parent && evmask->mask_len >= 1) {
197 unsigned char *bits = (unsigned char *) &evmask[1];
198
199 if (BitIsOn(bits, XI_RawKeyPress) ||
200 BitIsOn(bits, XI_RawKeyRelease) ||
201 BitIsOn(bits, XI_RawButtonPress) ||
202 BitIsOn(bits, XI_RawButtonRelease) ||
203 BitIsOn(bits, XI_RawMotion) ||
204 BitIsOn(bits, XI_RawTouchBegin) ||
205 BitIsOn(bits, XI_RawTouchUpdate) ||
206 BitIsOn(bits, XI_RawTouchEnd)) {
207 client->errorValue = XI_RawKeyPress;
208 return BadValue;
209 }
210 }
211
212 if (evmask->mask_len >= 1) {
213 unsigned char *bits = (unsigned char *) &evmask[1];
214
215 /* All three touch events must be selected at once */
216 if ((BitIsOn(bits, XI_TouchBegin) ||
217 BitIsOn(bits, XI_TouchUpdate) ||
218 BitIsOn(bits, XI_TouchOwnership) ||
219 BitIsOn(bits, XI_TouchEnd)) &&
220 (!BitIsOn(bits, XI_TouchBegin) ||
221 !BitIsOn(bits, XI_TouchUpdate) ||
222 !BitIsOn(bits, XI_TouchEnd))) {
223 client->errorValue = XI_TouchBegin;
224 return BadValue;
225 }
226
227 /* Only one client per window may select for touch events on the
228 * same devices, including master devices.
229 * XXX: This breaks if a device goes from floating to attached. */
230 if (BitIsOn(bits, XI_TouchBegin)) {
231 rc = check_for_touch_selection_conflicts(client,
232 win,
233 evmask->deviceid);
234 if (rc != Success)
235 return rc;
236 }
237 }
238
239 if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],
240 evmask->mask_len * 4) != Success)
241 return BadValue;
242
243 evmask =
244 (xXIEventMask *) (((unsigned char *) evmask) +
245 evmask->mask_len * 4);
246 evmask++;
247 }
248
249 if (bytes_to_int32(len) != stuff->length)
250 return BadLength;
251
252 /* Set masks on window */
253 evmask = (xXIEventMask *) &stuff[1];
254 num_masks = stuff->num_masks;
255 while (num_masks--) {
256 if (evmask->deviceid == XIAllDevices ||
257 evmask->deviceid == XIAllMasterDevices) {
258 dummy.id = evmask->deviceid;
259 dev = &dummy;
260 }
261 else
262 dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
263 if (XISetEventMask(dev, win, client, evmask->mask_len * 4,
264 (unsigned char *) &evmask[1]) != Success)
265 return BadAlloc;
266 evmask =
267 (xXIEventMask *) (((unsigned char *) evmask) +
268 evmask->mask_len * 4);
269 evmask++;
270 }
271
272 RecalculateDeliverableEvents(win);
273
274 free(types);
275 return Success;
276 }
277
278 int _X_COLD
SProcXIGetSelectedEvents(ClientPtr client)279 SProcXIGetSelectedEvents(ClientPtr client)
280 {
281 REQUEST(xXIGetSelectedEventsReq);
282 swaps(&stuff->length);
283 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
284 swapl(&stuff->win);
285
286 return (ProcXIGetSelectedEvents(client));
287 }
288
289 int
ProcXIGetSelectedEvents(ClientPtr client)290 ProcXIGetSelectedEvents(ClientPtr client)
291 {
292 int rc, i;
293 WindowPtr win;
294 char *buffer = NULL;
295 xXIGetSelectedEventsReply reply;
296 OtherInputMasks *masks;
297 InputClientsPtr others = NULL;
298 xXIEventMask *evmask = NULL;
299 DeviceIntPtr dev;
300
301 REQUEST(xXIGetSelectedEventsReq);
302 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
303
304 rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess);
305 if (rc != Success)
306 return rc;
307
308 reply = (xXIGetSelectedEventsReply) {
309 .repType = X_Reply,
310 .RepType = X_XIGetSelectedEvents,
311 .sequenceNumber = client->sequence,
312 .length = 0,
313 .num_masks = 0
314 };
315
316 masks = wOtherInputMasks(win);
317 if (masks) {
318 for (others = wOtherInputMasks(win)->inputClients; others;
319 others = others->next) {
320 if (SameClient(others, client)) {
321 break;
322 }
323 }
324 }
325
326 if (!others) {
327 WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
328 return Success;
329 }
330
331 buffer =
332 calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE));
333 if (!buffer)
334 return BadAlloc;
335
336 evmask = (xXIEventMask *) buffer;
337 for (i = 0; i < MAXDEVICES; i++) {
338 int j;
339 const unsigned char *devmask = xi2mask_get_one_mask(others->xi2mask, i);
340
341 if (i > 2) {
342 rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess);
343 if (rc != Success)
344 continue;
345 }
346
347 for (j = xi2mask_mask_size(others->xi2mask) - 1; j >= 0; j--) {
348 if (devmask[j] != 0) {
349 int mask_len = (j + 4) / 4; /* j is an index, hence + 4, not + 3 */
350
351 evmask->deviceid = i;
352 evmask->mask_len = mask_len;
353 reply.num_masks++;
354 reply.length += sizeof(xXIEventMask) / 4 + evmask->mask_len;
355
356 if (client->swapped) {
357 swaps(&evmask->deviceid);
358 swaps(&evmask->mask_len);
359 }
360
361 memcpy(&evmask[1], devmask, j + 1);
362 evmask = (xXIEventMask *) ((char *) evmask +
363 sizeof(xXIEventMask) + mask_len * 4);
364 break;
365 }
366 }
367 }
368
369 WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
370
371 if (reply.num_masks)
372 WriteToClient(client, reply.length * 4, buffer);
373
374 free(buffer);
375 return Success;
376 }
377
378 void
SRepXIGetSelectedEvents(ClientPtr client,int len,xXIGetSelectedEventsReply * rep)379 SRepXIGetSelectedEvents(ClientPtr client,
380 int len, xXIGetSelectedEventsReply * rep)
381 {
382 swaps(&rep->sequenceNumber);
383 swapl(&rep->length);
384 swaps(&rep->num_masks);
385 WriteToClient(client, len, rep);
386 }
387