2 * Copyright 2008 Red Hat, Inc.
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:
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
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.
23 * Author: Peter Hutterer
26 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
30 #include "dixstruct.h"
31 #include "windowstr.h"
32 #include "exglobals.h"
34 #include <X11/extensions/XI2proto.h>
35 #include "inpututils.h"
37 #include "xiselectev.h"
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
47 static int check_for_touch_selection_conflicts(ClientPtr B
, WindowPtr win
, int deviceid
)
49 OtherInputMasks
*inputMasks
= wOtherInputMasks(win
);
50 InputClients
*A
= NULL
;
53 A
= inputMasks
->inputClients
;
54 for (; A
; A
= A
->next
) {
57 if (CLIENT_ID(A
->resource
) == B
->index
)
60 if (deviceid
== XIAllDevices
)
61 tmp
= inputInfo
.all_devices
;
62 else if (deviceid
== XIAllMasterDevices
)
63 tmp
= inputInfo
.all_master_devices
;
65 dixLookupDevice(&tmp
, deviceid
, serverClient
, DixReadAccess
);
67 return BadImplementation
; /* this shouldn't happen */
69 /* A has XIAllDevices */
70 if (xi2mask_isset_for_device(A
->xi2mask
, inputInfo
.all_devices
, XI_TouchBegin
)) {
71 if (deviceid
== XIAllDevices
)
75 /* A has XIAllMasterDevices */
76 if (xi2mask_isset_for_device(A
->xi2mask
, inputInfo
.all_master_devices
, XI_TouchBegin
)) {
77 if (deviceid
== XIAllMasterDevices
)
81 /* A has this device */
82 if (xi2mask_isset_for_device(A
->xi2mask
, tmp
, XI_TouchBegin
))
91 * Check the given mask (in len bytes) for invalid mask bits.
92 * Invalid mask bits are any bits above XI2LastEvent.
94 * @return BadValue if at least one invalid bit is set or Success otherwise.
97 XICheckInvalidMaskBits(ClientPtr client
, unsigned char *mask
, int len
)
99 if (len
>= XIMaskLen(XI2LASTEVENT
)) {
102 for (i
= XI2LASTEVENT
+ 1; i
< len
* 8; i
++) {
103 if (BitIsOn(mask
, i
)) {
104 client
->errorValue
= i
;
114 SProcXISelectEvents(ClientPtr client
)
117 xXIEventMask
*evmask
;
119 REQUEST(xXISelectEventsReq
);
120 swaps(&stuff
->length
);
121 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq
);
123 swaps(&stuff
->num_masks
);
125 evmask
= (xXIEventMask
*) &stuff
[1];
126 for (i
= 0; i
< stuff
->num_masks
; i
++) {
127 swaps(&evmask
->deviceid
);
128 swaps(&evmask
->mask_len
);
130 (xXIEventMask
*) (((char *) &evmask
[1]) + evmask
->mask_len
* 4);
133 return (ProcXISelectEvents(client
));
137 ProcXISelectEvents(ClientPtr client
)
143 xXIEventMask
*evmask
;
147 REQUEST(xXISelectEventsReq
);
148 REQUEST_AT_LEAST_SIZE(xXISelectEventsReq
);
150 if (stuff
->num_masks
== 0)
153 rc
= dixLookupWindow(&win
, stuff
->win
, client
, DixReceiveAccess
);
157 len
= sz_xXISelectEventsReq
;
159 /* check request validity */
160 evmask
= (xXIEventMask
*) &stuff
[1];
161 num_masks
= stuff
->num_masks
;
162 while (num_masks
--) {
163 len
+= sizeof(xXIEventMask
) + evmask
->mask_len
* 4;
165 if (bytes_to_int32(len
) > stuff
->length
)
168 if (evmask
->deviceid
!= XIAllDevices
&&
169 evmask
->deviceid
!= XIAllMasterDevices
)
170 rc
= dixLookupDevice(&dev
, evmask
->deviceid
, client
, DixUseAccess
);
172 /* XXX: XACE here? */
177 /* hierarchy event mask is not allowed on devices */
178 if (evmask
->deviceid
!= XIAllDevices
&& evmask
->mask_len
>= 1) {
179 unsigned char *bits
= (unsigned char *) &evmask
[1];
181 if (BitIsOn(bits
, XI_HierarchyChanged
)) {
182 client
->errorValue
= XI_HierarchyChanged
;
187 /* Raw events may only be selected on root windows */
188 if (win
->parent
&& evmask
->mask_len
>= 1) {
189 unsigned char *bits
= (unsigned char *) &evmask
[1];
191 if (BitIsOn(bits
, XI_RawKeyPress
) ||
192 BitIsOn(bits
, XI_RawKeyRelease
) ||
193 BitIsOn(bits
, XI_RawButtonPress
) ||
194 BitIsOn(bits
, XI_RawButtonRelease
) ||
195 BitIsOn(bits
, XI_RawMotion
) ||
196 BitIsOn(bits
, XI_RawTouchBegin
) ||
197 BitIsOn(bits
, XI_RawTouchUpdate
) ||
198 BitIsOn(bits
, XI_RawTouchEnd
)) {
199 client
->errorValue
= XI_RawKeyPress
;
204 if (evmask
->mask_len
>= 1) {
205 unsigned char *bits
= (unsigned char *) &evmask
[1];
207 /* All three touch events must be selected at once */
208 if ((BitIsOn(bits
, XI_TouchBegin
) ||
209 BitIsOn(bits
, XI_TouchUpdate
) ||
210 BitIsOn(bits
, XI_TouchOwnership
) ||
211 BitIsOn(bits
, XI_TouchEnd
)) &&
212 (!BitIsOn(bits
, XI_TouchBegin
) ||
213 !BitIsOn(bits
, XI_TouchUpdate
) ||
214 !BitIsOn(bits
, XI_TouchEnd
))) {
215 client
->errorValue
= XI_TouchBegin
;
219 /* Only one client per window may select for touch events on the
220 * same devices, including master devices.
221 * XXX: This breaks if a device goes from floating to attached. */
222 if (BitIsOn(bits
, XI_TouchBegin
)) {
223 rc
= check_for_touch_selection_conflicts(client
,
231 if (XICheckInvalidMaskBits(client
, (unsigned char *) &evmask
[1],
232 evmask
->mask_len
* 4) != Success
)
236 (xXIEventMask
*) (((unsigned char *) evmask
) +
237 evmask
->mask_len
* 4);
241 if (bytes_to_int32(len
) != stuff
->length
)
244 /* Set masks on window */
245 evmask
= (xXIEventMask
*) &stuff
[1];
246 num_masks
= stuff
->num_masks
;
247 while (num_masks
--) {
248 if (evmask
->deviceid
== XIAllDevices
||
249 evmask
->deviceid
== XIAllMasterDevices
) {
250 dummy
.id
= evmask
->deviceid
;
254 dixLookupDevice(&dev
, evmask
->deviceid
, client
, DixUseAccess
);
255 if (XISetEventMask(dev
, win
, client
, evmask
->mask_len
* 4,
256 (unsigned char *) &evmask
[1]) != Success
)
259 (xXIEventMask
*) (((unsigned char *) evmask
) +
260 evmask
->mask_len
* 4);
264 RecalculateDeliverableEvents(win
);
271 SProcXIGetSelectedEvents(ClientPtr client
)
273 REQUEST(xXIGetSelectedEventsReq
);
274 swaps(&stuff
->length
);
275 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq
);
278 return (ProcXIGetSelectedEvents(client
));
282 ProcXIGetSelectedEvents(ClientPtr client
)
287 xXIGetSelectedEventsReply reply
;
288 OtherInputMasks
*masks
;
289 InputClientsPtr others
= NULL
;
290 xXIEventMask
*evmask
= NULL
;
293 REQUEST(xXIGetSelectedEventsReq
);
294 REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq
);
296 rc
= dixLookupWindow(&win
, stuff
->win
, client
, DixGetAttrAccess
);
300 reply
= (xXIGetSelectedEventsReply
) {
302 .RepType
= X_XIGetSelectedEvents
,
303 .sequenceNumber
= client
->sequence
,
308 masks
= wOtherInputMasks(win
);
310 for (others
= wOtherInputMasks(win
)->inputClients
; others
;
311 others
= others
->next
) {
312 if (SameClient(others
, client
)) {
319 WriteReplyToClient(client
, sizeof(xXIGetSelectedEventsReply
), &reply
);
324 calloc(MAXDEVICES
, sizeof(xXIEventMask
) + pad_to_int32(XI2MASKSIZE
));
328 evmask
= (xXIEventMask
*) buffer
;
329 for (i
= 0; i
< MAXDEVICES
; i
++) {
331 const unsigned char *devmask
= xi2mask_get_one_mask(others
->xi2mask
, i
);
334 rc
= dixLookupDevice(&dev
, i
, client
, DixGetAttrAccess
);
339 for (j
= xi2mask_mask_size(others
->xi2mask
) - 1; j
>= 0; j
--) {
340 if (devmask
[j
] != 0) {
341 int mask_len
= (j
+ 4) / 4; /* j is an index, hence + 4, not + 3 */
343 evmask
->deviceid
= i
;
344 evmask
->mask_len
= mask_len
;
346 reply
.length
+= sizeof(xXIEventMask
) / 4 + evmask
->mask_len
;
348 if (client
->swapped
) {
349 swaps(&evmask
->deviceid
);
350 swaps(&evmask
->mask_len
);
353 memcpy(&evmask
[1], devmask
, j
+ 1);
354 evmask
= (xXIEventMask
*) ((char *) evmask
+
355 sizeof(xXIEventMask
) + mask_len
* 4);
361 WriteReplyToClient(client
, sizeof(xXIGetSelectedEventsReply
), &reply
);
364 WriteToClient(client
, reply
.length
* 4, buffer
);
371 SRepXIGetSelectedEvents(ClientPtr client
,
372 int len
, xXIGetSelectedEventsReply
* rep
)
374 swaps(&rep
->sequenceNumber
);
376 swaps(&rep
->num_masks
);
377 WriteToClient(client
, len
, rep
);