2 * Copyright © 2009 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 * Authors: Peter Hutterer
28 * @file Protocol handling for the XIQueryDevice request/reply.
31 #include <dix-config.h>
34 #include <X11/Xatom.h>
35 #include <X11/extensions/XI2proto.h>
37 #include "dix/exevents_priv.h"
38 #include "dix/input_priv.h"
43 #include "xserver-properties.h"
45 #include "inpututils.h"
46 #include "exglobals.h"
48 #include "xiquerydevice.h"
50 static Bool
ShouldSkipDevice(ClientPtr client
, int deviceid
, DeviceIntPtr d
);
52 ListDeviceInfo(ClientPtr client
, DeviceIntPtr dev
, xXIDeviceInfo
* info
);
53 static int SizeDeviceInfo(DeviceIntPtr dev
);
54 static void SwapDeviceInfo(DeviceIntPtr dev
, xXIDeviceInfo
* info
);
56 SProcXIQueryDevice(ClientPtr client
)
58 REQUEST(xXIQueryDeviceReq
);
59 REQUEST_SIZE_MATCH(xXIQueryDeviceReq
);
61 swaps(&stuff
->length
);
62 swaps(&stuff
->deviceid
);
64 return ProcXIQueryDevice(client
);
68 ProcXIQueryDevice(ClientPtr client
)
70 xXIQueryDeviceReply rep
;
71 DeviceIntPtr dev
= NULL
;
77 REQUEST(xXIQueryDeviceReq
);
78 REQUEST_SIZE_MATCH(xXIQueryDeviceReq
);
80 if (stuff
->deviceid
!= XIAllDevices
&&
81 stuff
->deviceid
!= XIAllMasterDevices
) {
82 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixGetAttrAccess
);
84 client
->errorValue
= stuff
->deviceid
;
87 len
+= SizeDeviceInfo(dev
);
90 skip
= calloc(inputInfo
.numDevices
, sizeof(Bool
));
94 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
, i
++) {
95 skip
[i
] = ShouldSkipDevice(client
, stuff
->deviceid
, dev
);
97 len
+= SizeDeviceInfo(dev
);
100 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
, i
++) {
101 skip
[i
] = ShouldSkipDevice(client
, stuff
->deviceid
, dev
);
103 len
+= SizeDeviceInfo(dev
);
107 info
= calloc(1, len
);
113 rep
= (xXIQueryDeviceReply
) {
115 .RepType
= X_XIQueryDevice
,
116 .sequenceNumber
= client
->sequence
,
123 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
125 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
131 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
, i
++) {
133 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
135 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
141 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
, i
++) {
143 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
145 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
152 len
= rep
.length
* 4;
153 WriteReplyToClient(client
, sizeof(xXIQueryDeviceReply
), &rep
);
154 WriteToClient(client
, len
, ptr
);
161 SRepXIQueryDevice(ClientPtr client
, int size
, xXIQueryDeviceReply
* rep
)
163 swaps(&rep
->sequenceNumber
);
165 swaps(&rep
->num_devices
);
167 /* Device info is already swapped, see ProcXIQueryDevice */
169 WriteToClient(client
, size
, rep
);
173 * @return Whether the device should be included in the returned list.
176 ShouldSkipDevice(ClientPtr client
, int deviceid
, DeviceIntPtr dev
)
178 /* if all devices are not being queried, only master devices are */
179 if (deviceid
== XIAllDevices
|| IsMaster(dev
)) {
180 int rc
= XaceHookDeviceAccess(client
, dev
, DixGetAttrAccess
);
189 * @return The number of bytes needed to store this device's xXIDeviceInfo
193 SizeDeviceInfo(DeviceIntPtr dev
)
195 int len
= sizeof(xXIDeviceInfo
);
198 len
+= pad_to_int32(strlen(dev
->name
));
200 return len
+ SizeDeviceClasses(dev
);
205 * @return The number of bytes needed to store this device's classes.
208 SizeDeviceClasses(DeviceIntPtr dev
)
213 len
+= sizeof(xXIButtonInfo
);
214 len
+= dev
->button
->numButtons
* sizeof(Atom
);
215 len
+= pad_to_int32(bits_to_bytes(dev
->button
->numButtons
));
219 XkbDescPtr xkb
= dev
->key
->xkbInfo
->desc
;
221 len
+= sizeof(xXIKeyInfo
);
222 len
+= (xkb
->max_key_code
- xkb
->min_key_code
+ 1) * sizeof(uint32_t);
228 len
+= (sizeof(xXIValuatorInfo
)) * dev
->valuator
->numAxes
;
230 for (i
= 0; i
< dev
->valuator
->numAxes
; i
++) {
231 if (dev
->valuator
->axes
[i
].scroll
.type
!= SCROLL_TYPE_NONE
)
232 len
+= sizeof(xXIScrollInfo
);
237 len
+= sizeof(xXITouchInfo
);
240 len
+= sizeof(xXIGestureInfo
);
246 * Get pointers to button information areas holding button mask and labels.
249 ButtonInfoData(xXIButtonInfo
*info
, int *mask_words
, unsigned char **mask
,
252 *mask_words
= bytes_to_int32(bits_to_bytes(info
->num_buttons
));
253 *mask
= (unsigned char*) &info
[1];
254 *atoms
= (Atom
*) ((*mask
) + (*mask_words
) * 4);
258 * Write button information into info.
259 * @return Number of bytes written into info.
262 ListButtonInfo(DeviceIntPtr dev
, xXIButtonInfo
* info
, Bool reportState
)
269 if (!dev
|| !dev
->button
)
272 info
->type
= ButtonClass
;
273 info
->num_buttons
= dev
->button
->numButtons
;
274 ButtonInfoData(info
, &mask_len
, &bits
, &labels
);
275 info
->length
= bytes_to_int32(sizeof(xXIButtonInfo
)) +
276 info
->num_buttons
+ mask_len
;
277 info
->sourceid
= dev
->button
->sourceid
;
279 memset(bits
, 0, mask_len
* 4);
282 for (i
= 0; i
< dev
->button
->numButtons
; i
++)
283 if (BitIsOn(dev
->button
->down
, i
))
286 memcpy(labels
, dev
->button
->labels
, dev
->button
->numButtons
* sizeof(Atom
));
288 return info
->length
* 4;
292 SwapButtonInfo(DeviceIntPtr dev
, xXIButtonInfo
* info
)
299 ButtonInfoData(info
, &mask_len
, &mask
, &btn
);
302 swaps(&info
->length
);
303 swaps(&info
->sourceid
);
305 for (i
= 0 ; i
< info
->num_buttons
; i
++, btn
++)
308 swaps(&info
->num_buttons
);
312 * Write key information into info.
313 * @return Number of bytes written into info.
316 ListKeyInfo(DeviceIntPtr dev
, xXIKeyInfo
* info
)
319 XkbDescPtr xkb
= dev
->key
->xkbInfo
->desc
;
322 info
->type
= KeyClass
;
323 info
->num_keycodes
= xkb
->max_key_code
- xkb
->min_key_code
+ 1;
324 info
->length
= sizeof(xXIKeyInfo
) / 4 + info
->num_keycodes
;
325 info
->sourceid
= dev
->key
->sourceid
;
327 kc
= (uint32_t *) &info
[1];
328 for (i
= xkb
->min_key_code
; i
<= xkb
->max_key_code
; i
++, kc
++)
331 return info
->length
* 4;
335 SwapKeyInfo(DeviceIntPtr dev
, xXIKeyInfo
* info
)
341 swaps(&info
->length
);
342 swaps(&info
->sourceid
);
344 for (i
= 0, key
= (uint32_t *) &info
[1]; i
< info
->num_keycodes
;
348 swaps(&info
->num_keycodes
);
352 * List axis information for the given axis.
354 * @return The number of bytes written into info.
357 ListValuatorInfo(DeviceIntPtr dev
, xXIValuatorInfo
* info
, int axisnumber
,
360 ValuatorClassPtr v
= dev
->valuator
;
362 info
->type
= ValuatorClass
;
363 info
->length
= sizeof(xXIValuatorInfo
) / 4;
364 info
->label
= v
->axes
[axisnumber
].label
;
365 info
->min
.integral
= v
->axes
[axisnumber
].min_value
;
367 info
->max
.integral
= v
->axes
[axisnumber
].max_value
;
369 info
->value
= double_to_fp3232(v
->axisVal
[axisnumber
]);
370 info
->resolution
= v
->axes
[axisnumber
].resolution
;
371 info
->number
= axisnumber
;
372 info
->mode
= valuator_get_mode(dev
, axisnumber
);
373 info
->sourceid
= v
->sourceid
;
376 info
->value
= info
->min
;
378 return info
->length
* 4;
382 SwapValuatorInfo(DeviceIntPtr dev
, xXIValuatorInfo
* info
)
385 swaps(&info
->length
);
387 swapl(&info
->min
.integral
);
388 swapl(&info
->min
.frac
);
389 swapl(&info
->max
.integral
);
390 swapl(&info
->max
.frac
);
391 swapl(&info
->value
.integral
);
392 swapl(&info
->value
.frac
);
393 swapl(&info
->resolution
);
394 swaps(&info
->number
);
395 swaps(&info
->sourceid
);
399 ListScrollInfo(DeviceIntPtr dev
, xXIScrollInfo
* info
, int axisnumber
)
401 ValuatorClassPtr v
= dev
->valuator
;
402 AxisInfoPtr axis
= &v
->axes
[axisnumber
];
404 if (axis
->scroll
.type
== SCROLL_TYPE_NONE
)
407 info
->type
= XIScrollClass
;
408 info
->length
= sizeof(xXIScrollInfo
) / 4;
409 info
->number
= axisnumber
;
410 switch (axis
->scroll
.type
) {
411 case SCROLL_TYPE_VERTICAL
:
412 info
->scroll_type
= XIScrollTypeVertical
;
414 case SCROLL_TYPE_HORIZONTAL
:
415 info
->scroll_type
= XIScrollTypeHorizontal
;
418 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
422 info
->increment
= double_to_fp3232(axis
->scroll
.increment
);
423 info
->sourceid
= v
->sourceid
;
427 if (axis
->scroll
.flags
& SCROLL_FLAG_DONT_EMULATE
)
428 info
->flags
|= XIScrollFlagNoEmulation
;
429 if (axis
->scroll
.flags
& SCROLL_FLAG_PREFERRED
)
430 info
->flags
|= XIScrollFlagPreferred
;
432 return info
->length
* 4;
436 SwapScrollInfo(DeviceIntPtr dev
, xXIScrollInfo
* info
)
439 swaps(&info
->length
);
440 swaps(&info
->number
);
441 swaps(&info
->sourceid
);
442 swaps(&info
->scroll_type
);
443 swapl(&info
->increment
.integral
);
444 swapl(&info
->increment
.frac
);
448 * List multitouch information
450 * @return The number of bytes written into info.
453 ListTouchInfo(DeviceIntPtr dev
, xXITouchInfo
* touch
)
455 touch
->type
= XITouchClass
;
456 touch
->length
= sizeof(xXITouchInfo
) >> 2;
457 touch
->sourceid
= dev
->touch
->sourceid
;
458 touch
->mode
= dev
->touch
->mode
;
459 touch
->num_touches
= dev
->touch
->num_touches
;
461 return touch
->length
<< 2;
465 SwapTouchInfo(DeviceIntPtr dev
, xXITouchInfo
* touch
)
468 swaps(&touch
->length
);
469 swaps(&touch
->sourceid
);
472 static Bool
ShouldListGestureInfo(ClientPtr client
)
474 /* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
475 * properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
476 * applications, we instead report Gesture device class only if the client advertised support
477 * for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
478 * and then a completely separate module within the client uses broken libxcb to call
481 XIClientPtr pXIClient
= dixLookupPrivate(&client
->devPrivates
, XIClientPrivateKey
);
482 if (pXIClient
->major_version
) {
483 return version_compare(pXIClient
->major_version
, pXIClient
->minor_version
, 2, 4) >= 0;
489 * List gesture information
491 * @return The number of bytes written into info.
494 ListGestureInfo(DeviceIntPtr dev
, xXIGestureInfo
* gesture
)
496 gesture
->type
= XIGestureClass
;
497 gesture
->length
= sizeof(xXIGestureInfo
) >> 2;
498 gesture
->sourceid
= dev
->gesture
->sourceid
;
499 gesture
->num_touches
= dev
->gesture
->max_touches
;
501 return gesture
->length
<< 2;
505 SwapGestureInfo(DeviceIntPtr dev
, xXIGestureInfo
* gesture
)
507 swaps(&gesture
->type
);
508 swaps(&gesture
->length
);
509 swaps(&gesture
->sourceid
);
513 GetDeviceUse(DeviceIntPtr dev
, uint16_t * attachment
)
515 DeviceIntPtr master
= GetMaster(dev
, MASTER_ATTACHED
);
519 DeviceIntPtr paired
= GetPairedDevice(dev
);
521 use
= IsPointerDevice(dev
) ? XIMasterPointer
: XIMasterKeyboard
;
522 *attachment
= (paired
? paired
->id
: 0);
524 else if (!IsFloating(dev
)) {
525 use
= IsPointerDevice(master
) ? XISlavePointer
: XISlaveKeyboard
;
526 *attachment
= master
->id
;
529 use
= XIFloatingSlave
;
535 * Write the info for device dev into the buffer pointed to by info.
537 * @return The number of bytes used.
540 ListDeviceInfo(ClientPtr client
, DeviceIntPtr dev
, xXIDeviceInfo
* info
)
542 char *any
= (char *) &info
[1];
543 int len
= 0, total_len
= 0;
545 info
->deviceid
= dev
->id
;
546 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
547 info
->num_classes
= 0;
548 info
->name_len
= strlen(dev
->name
);
549 info
->enabled
= dev
->enabled
;
550 total_len
= sizeof(xXIDeviceInfo
);
552 len
= pad_to_int32(info
->name_len
);
554 strncpy(any
, dev
->name
, info
->name_len
);
558 total_len
+= ListDeviceClasses(client
, dev
, any
, &info
->num_classes
);
563 * Write the class info of the device into the memory pointed to by any, set
564 * nclasses to the number of classes in total and return the number of bytes
568 ListDeviceClasses(ClientPtr client
, DeviceIntPtr dev
,
569 char *any
, uint16_t * nclasses
)
576 /* Check if the current device state should be suppressed */
577 rc
= XaceHookDeviceAccess(client
, dev
, DixReadAccess
);
581 len
= ListButtonInfo(dev
, (xXIButtonInfo
*) any
, rc
== Success
);
588 len
= ListKeyInfo(dev
, (xXIKeyInfo
*) any
);
593 for (i
= 0; dev
->valuator
&& i
< dev
->valuator
->numAxes
; i
++) {
595 len
= ListValuatorInfo(dev
, (xXIValuatorInfo
*) any
, i
, rc
== Success
);
600 for (i
= 0; dev
->valuator
&& i
< dev
->valuator
->numAxes
; i
++) {
601 len
= ListScrollInfo(dev
, (xXIScrollInfo
*) any
, i
);
610 len
= ListTouchInfo(dev
, (xXITouchInfo
*) any
);
615 if (dev
->gesture
&& ShouldListGestureInfo(client
)) {
617 len
= ListGestureInfo(dev
, (xXIGestureInfo
*) any
);
626 SwapDeviceInfo(DeviceIntPtr dev
, xXIDeviceInfo
* info
)
628 char *any
= (char *) &info
[1];
632 any
+= pad_to_int32(info
->name_len
);
634 for (i
= 0; i
< info
->num_classes
; i
++) {
635 int len
= ((xXIAnyInfo
*) any
)->length
;
637 switch (((xXIAnyInfo
*) any
)->type
) {
639 SwapButtonInfo(dev
, (xXIButtonInfo
*) any
);
642 SwapKeyInfo(dev
, (xXIKeyInfo
*) any
);
644 case XIValuatorClass
:
645 SwapValuatorInfo(dev
, (xXIValuatorInfo
*) any
);
648 SwapScrollInfo(dev
, (xXIScrollInfo
*) any
);
651 SwapTouchInfo(dev
, (xXITouchInfo
*) any
);
654 SwapGestureInfo(dev
, (xXIGestureInfo
*) any
);
661 swaps(&info
->deviceid
);
663 swaps(&info
->attachment
);
664 swaps(&info
->num_classes
);
665 swaps(&info
->name_len
);