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 #ifdef HAVE_DIX_CONFIG_H
32 #include <dix-config.h>
37 #include <X11/Xatom.h>
38 #include <X11/extensions/XI2proto.h>
41 #include "xserver-properties.h"
44 #include "inpututils.h"
46 #include "xiquerydevice.h"
48 static Bool
ShouldSkipDevice(ClientPtr client
, int deviceid
, DeviceIntPtr d
);
50 ListDeviceInfo(ClientPtr client
, DeviceIntPtr dev
, xXIDeviceInfo
* info
);
51 static int SizeDeviceInfo(DeviceIntPtr dev
);
52 static void SwapDeviceInfo(DeviceIntPtr dev
, xXIDeviceInfo
* info
);
54 SProcXIQueryDevice(ClientPtr client
)
56 REQUEST(xXIQueryDeviceReq
);
58 swaps(&stuff
->length
);
59 swaps(&stuff
->deviceid
);
61 return ProcXIQueryDevice(client
);
65 ProcXIQueryDevice(ClientPtr client
)
67 xXIQueryDeviceReply rep
;
68 DeviceIntPtr dev
= NULL
;
74 REQUEST(xXIQueryDeviceReq
);
75 REQUEST_SIZE_MATCH(xXIQueryDeviceReq
);
77 if (stuff
->deviceid
!= XIAllDevices
&&
78 stuff
->deviceid
!= XIAllMasterDevices
) {
79 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixGetAttrAccess
);
81 client
->errorValue
= stuff
->deviceid
;
84 len
+= SizeDeviceInfo(dev
);
87 skip
= calloc(sizeof(Bool
), inputInfo
.numDevices
);
91 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
, i
++) {
92 skip
[i
] = ShouldSkipDevice(client
, stuff
->deviceid
, dev
);
94 len
+= SizeDeviceInfo(dev
);
97 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
, i
++) {
98 skip
[i
] = ShouldSkipDevice(client
, stuff
->deviceid
, dev
);
100 len
+= SizeDeviceInfo(dev
);
104 info
= calloc(1, len
);
110 rep
= (xXIQueryDeviceReply
) {
112 .RepType
= X_XIQueryDevice
,
113 .sequenceNumber
= client
->sequence
,
120 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
122 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
128 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
, i
++) {
130 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
132 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
138 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
, i
++) {
140 len
= ListDeviceInfo(client
, dev
, (xXIDeviceInfo
*) info
);
142 SwapDeviceInfo(dev
, (xXIDeviceInfo
*) info
);
149 len
= rep
.length
* 4;
150 WriteReplyToClient(client
, sizeof(xXIQueryDeviceReply
), &rep
);
151 WriteToClient(client
, len
, ptr
);
158 SRepXIQueryDevice(ClientPtr client
, int size
, xXIQueryDeviceReply
* rep
)
160 swaps(&rep
->sequenceNumber
);
162 swaps(&rep
->num_devices
);
164 /* Device info is already swapped, see ProcXIQueryDevice */
166 WriteToClient(client
, size
, rep
);
170 * @return Whether the device should be included in the returned list.
173 ShouldSkipDevice(ClientPtr client
, int deviceid
, DeviceIntPtr dev
)
175 /* if all devices are not being queried, only master devices are */
176 if (deviceid
== XIAllDevices
|| IsMaster(dev
)) {
177 int rc
= XaceHook(XACE_DEVICE_ACCESS
, client
, dev
, DixGetAttrAccess
);
186 * @return The number of bytes needed to store this device's xXIDeviceInfo
190 SizeDeviceInfo(DeviceIntPtr dev
)
192 int len
= sizeof(xXIDeviceInfo
);
195 len
+= pad_to_int32(strlen(dev
->name
));
197 return len
+ SizeDeviceClasses(dev
);
202 * @return The number of bytes needed to store this device's classes.
205 SizeDeviceClasses(DeviceIntPtr dev
)
210 len
+= sizeof(xXIButtonInfo
);
211 len
+= dev
->button
->numButtons
* sizeof(Atom
);
212 len
+= pad_to_int32(bits_to_bytes(dev
->button
->numButtons
));
216 XkbDescPtr xkb
= dev
->key
->xkbInfo
->desc
;
218 len
+= sizeof(xXIKeyInfo
);
219 len
+= (xkb
->max_key_code
- xkb
->min_key_code
+ 1) * sizeof(uint32_t);
225 len
+= (sizeof(xXIValuatorInfo
)) * dev
->valuator
->numAxes
;
227 for (i
= 0; i
< dev
->valuator
->numAxes
; i
++) {
228 if (dev
->valuator
->axes
[i
].scroll
.type
!= SCROLL_TYPE_NONE
)
229 len
+= sizeof(xXIScrollInfo
);
234 len
+= sizeof(xXITouchInfo
);
240 * Write button information into info.
241 * @return Number of bytes written into info.
244 ListButtonInfo(DeviceIntPtr dev
, xXIButtonInfo
* info
, Bool reportState
)
250 if (!dev
|| !dev
->button
)
253 mask_len
= bytes_to_int32(bits_to_bytes(dev
->button
->numButtons
));
255 info
->type
= ButtonClass
;
256 info
->num_buttons
= dev
->button
->numButtons
;
257 info
->length
= bytes_to_int32(sizeof(xXIButtonInfo
)) +
258 info
->num_buttons
+ mask_len
;
259 info
->sourceid
= dev
->button
->sourceid
;
261 bits
= (unsigned char *) &info
[1];
262 memset(bits
, 0, mask_len
* 4);
265 for (i
= 0; i
< dev
->button
->numButtons
; i
++)
266 if (BitIsOn(dev
->button
->down
, i
))
269 bits
+= mask_len
* 4;
270 memcpy(bits
, dev
->button
->labels
, dev
->button
->numButtons
* sizeof(Atom
));
272 return info
->length
* 4;
276 SwapButtonInfo(DeviceIntPtr dev
, xXIButtonInfo
* info
)
282 swaps(&info
->length
);
283 swaps(&info
->sourceid
);
285 for (i
= 0, btn
= (Atom
*) &info
[1]; i
< info
->num_buttons
; i
++, btn
++)
288 swaps(&info
->num_buttons
);
292 * Write key information into info.
293 * @return Number of bytes written into info.
296 ListKeyInfo(DeviceIntPtr dev
, xXIKeyInfo
* info
)
299 XkbDescPtr xkb
= dev
->key
->xkbInfo
->desc
;
302 info
->type
= KeyClass
;
303 info
->num_keycodes
= xkb
->max_key_code
- xkb
->min_key_code
+ 1;
304 info
->length
= sizeof(xXIKeyInfo
) / 4 + info
->num_keycodes
;
305 info
->sourceid
= dev
->key
->sourceid
;
307 kc
= (uint32_t *) &info
[1];
308 for (i
= xkb
->min_key_code
; i
<= xkb
->max_key_code
; i
++, kc
++)
311 return info
->length
* 4;
315 SwapKeyInfo(DeviceIntPtr dev
, xXIKeyInfo
* info
)
321 swaps(&info
->length
);
322 swaps(&info
->sourceid
);
324 for (i
= 0, key
= (uint32_t *) &info
[1]; i
< info
->num_keycodes
;
328 swaps(&info
->num_keycodes
);
332 * List axis information for the given axis.
334 * @return The number of bytes written into info.
337 ListValuatorInfo(DeviceIntPtr dev
, xXIValuatorInfo
* info
, int axisnumber
,
340 ValuatorClassPtr v
= dev
->valuator
;
342 info
->type
= ValuatorClass
;
343 info
->length
= sizeof(xXIValuatorInfo
) / 4;
344 info
->label
= v
->axes
[axisnumber
].label
;
345 info
->min
.integral
= v
->axes
[axisnumber
].min_value
;
347 info
->max
.integral
= v
->axes
[axisnumber
].max_value
;
349 info
->value
= double_to_fp3232(v
->axisVal
[axisnumber
]);
350 info
->resolution
= v
->axes
[axisnumber
].resolution
;
351 info
->number
= axisnumber
;
352 info
->mode
= valuator_get_mode(dev
, axisnumber
);
353 info
->sourceid
= v
->sourceid
;
356 info
->value
= info
->min
;
358 return info
->length
* 4;
362 SwapValuatorInfo(DeviceIntPtr dev
, xXIValuatorInfo
* info
)
365 swaps(&info
->length
);
367 swapl(&info
->min
.integral
);
368 swapl(&info
->min
.frac
);
369 swapl(&info
->max
.integral
);
370 swapl(&info
->max
.frac
);
371 swaps(&info
->number
);
372 swaps(&info
->sourceid
);
376 ListScrollInfo(DeviceIntPtr dev
, xXIScrollInfo
* info
, int axisnumber
)
378 ValuatorClassPtr v
= dev
->valuator
;
379 AxisInfoPtr axis
= &v
->axes
[axisnumber
];
381 if (axis
->scroll
.type
== SCROLL_TYPE_NONE
)
384 info
->type
= XIScrollClass
;
385 info
->length
= sizeof(xXIScrollInfo
) / 4;
386 info
->number
= axisnumber
;
387 switch (axis
->scroll
.type
) {
388 case SCROLL_TYPE_VERTICAL
:
389 info
->scroll_type
= XIScrollTypeVertical
;
391 case SCROLL_TYPE_HORIZONTAL
:
392 info
->scroll_type
= XIScrollTypeHorizontal
;
395 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
399 info
->increment
= double_to_fp3232(axis
->scroll
.increment
);
400 info
->sourceid
= v
->sourceid
;
404 if (axis
->scroll
.flags
& SCROLL_FLAG_DONT_EMULATE
)
405 info
->flags
|= XIScrollFlagNoEmulation
;
406 if (axis
->scroll
.flags
& SCROLL_FLAG_PREFERRED
)
407 info
->flags
|= XIScrollFlagPreferred
;
409 return info
->length
* 4;
413 SwapScrollInfo(DeviceIntPtr dev
, xXIScrollInfo
* info
)
416 swaps(&info
->length
);
417 swaps(&info
->number
);
418 swaps(&info
->sourceid
);
419 swaps(&info
->scroll_type
);
420 swapl(&info
->increment
.integral
);
421 swapl(&info
->increment
.frac
);
425 * List multitouch information
427 * @return The number of bytes written into info.
430 ListTouchInfo(DeviceIntPtr dev
, xXITouchInfo
* touch
)
432 touch
->type
= XITouchClass
;
433 touch
->length
= sizeof(xXITouchInfo
) >> 2;
434 touch
->sourceid
= dev
->touch
->sourceid
;
435 touch
->mode
= dev
->touch
->mode
;
436 touch
->num_touches
= dev
->touch
->num_touches
;
438 return touch
->length
<< 2;
442 SwapTouchInfo(DeviceIntPtr dev
, xXITouchInfo
* touch
)
445 swaps(&touch
->length
);
446 swaps(&touch
->sourceid
);
450 GetDeviceUse(DeviceIntPtr dev
, uint16_t * attachment
)
452 DeviceIntPtr master
= GetMaster(dev
, MASTER_ATTACHED
);
456 DeviceIntPtr paired
= GetPairedDevice(dev
);
458 use
= IsPointerDevice(dev
) ? XIMasterPointer
: XIMasterKeyboard
;
459 *attachment
= (paired
? paired
->id
: 0);
461 else if (!IsFloating(dev
)) {
462 use
= IsPointerDevice(master
) ? XISlavePointer
: XISlaveKeyboard
;
463 *attachment
= master
->id
;
466 use
= XIFloatingSlave
;
472 * Write the info for device dev into the buffer pointed to by info.
474 * @return The number of bytes used.
477 ListDeviceInfo(ClientPtr client
, DeviceIntPtr dev
, xXIDeviceInfo
* info
)
479 char *any
= (char *) &info
[1];
480 int len
= 0, total_len
= 0;
482 info
->deviceid
= dev
->id
;
483 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
484 info
->num_classes
= 0;
485 info
->name_len
= strlen(dev
->name
);
486 info
->enabled
= dev
->enabled
;
487 total_len
= sizeof(xXIDeviceInfo
);
489 len
= pad_to_int32(info
->name_len
);
491 strncpy(any
, dev
->name
, info
->name_len
);
495 total_len
+= ListDeviceClasses(client
, dev
, any
, &info
->num_classes
);
500 * Write the class info of the device into the memory pointed to by any, set
501 * nclasses to the number of classes in total and return the number of bytes
505 ListDeviceClasses(ClientPtr client
, DeviceIntPtr dev
,
506 char *any
, uint16_t * nclasses
)
513 /* Check if the current device state should be suppressed */
514 rc
= XaceHook(XACE_DEVICE_ACCESS
, client
, dev
, DixReadAccess
);
518 len
= ListButtonInfo(dev
, (xXIButtonInfo
*) any
, rc
== Success
);
525 len
= ListKeyInfo(dev
, (xXIKeyInfo
*) any
);
530 for (i
= 0; dev
->valuator
&& i
< dev
->valuator
->numAxes
; i
++) {
532 len
= ListValuatorInfo(dev
, (xXIValuatorInfo
*) any
, i
, rc
== Success
);
537 for (i
= 0; dev
->valuator
&& i
< dev
->valuator
->numAxes
; i
++) {
538 len
= ListScrollInfo(dev
, (xXIScrollInfo
*) any
, i
);
547 len
= ListTouchInfo(dev
, (xXITouchInfo
*) any
);
556 SwapDeviceInfo(DeviceIntPtr dev
, xXIDeviceInfo
* info
)
558 char *any
= (char *) &info
[1];
562 any
+= pad_to_int32(info
->name_len
);
564 for (i
= 0; i
< info
->num_classes
; i
++) {
565 int len
= ((xXIAnyInfo
*) any
)->length
;
567 switch (((xXIAnyInfo
*) any
)->type
) {
569 SwapButtonInfo(dev
, (xXIButtonInfo
*) any
);
572 SwapKeyInfo(dev
, (xXIKeyInfo
*) any
);
574 case XIValuatorClass
:
575 SwapValuatorInfo(dev
, (xXIValuatorInfo
*) any
);
578 SwapScrollInfo(dev
, (xXIScrollInfo
*) any
);
581 SwapTouchInfo(dev
, (xXITouchInfo
*) any
);
589 swaps(&info
->deviceid
);
591 swaps(&info
->attachment
);
592 swaps(&info
->num_classes
);
593 swaps(&info
->name_len
);