xref: /OK3568_Linux_fs/external/xserver/Xi/xiselectev.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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