os: if inet_ntop() is available, use it for IPv4 addresses as well
[xserver.git] / Xi / xiquerydevice.c
blobcbc3c037e4cc125491210d4cdccbc19ead7a3193
1 /*
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
13 * Software.
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
27 /**
28 * @file Protocol handling for the XIQueryDevice request/reply.
31 #include <dix-config.h>
33 #include <X11/X.h>
34 #include <X11/Xatom.h>
35 #include <X11/extensions/XI2proto.h>
37 #include "dix/exevents_priv.h"
38 #include "dix/input_priv.h"
40 #include "inputstr.h"
41 #include "xkbstr.h"
42 #include "xkbsrv.h"
43 #include "xserver-properties.h"
44 #include "xace.h"
45 #include "inpututils.h"
46 #include "exglobals.h"
47 #include "privates.h"
48 #include "xiquerydevice.h"
50 static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
51 static int
52 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info);
53 static int SizeDeviceInfo(DeviceIntPtr dev);
54 static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info);
55 int _X_COLD
56 SProcXIQueryDevice(ClientPtr client)
58 REQUEST(xXIQueryDeviceReq);
59 REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
61 swaps(&stuff->length);
62 swaps(&stuff->deviceid);
64 return ProcXIQueryDevice(client);
67 int
68 ProcXIQueryDevice(ClientPtr client)
70 xXIQueryDeviceReply rep;
71 DeviceIntPtr dev = NULL;
72 int rc = Success;
73 int i = 0, len = 0;
74 char *info, *ptr;
75 Bool *skip = 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);
83 if (rc != Success) {
84 client->errorValue = stuff->deviceid;
85 return rc;
87 len += SizeDeviceInfo(dev);
89 else {
90 skip = calloc(inputInfo.numDevices, sizeof(Bool));
91 if (!skip)
92 return BadAlloc;
94 for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
95 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
96 if (!skip[i])
97 len += SizeDeviceInfo(dev);
100 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
101 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
102 if (!skip[i])
103 len += SizeDeviceInfo(dev);
107 info = calloc(1, len);
108 if (!info) {
109 free(skip);
110 return BadAlloc;
113 rep = (xXIQueryDeviceReply) {
114 .repType = X_Reply,
115 .RepType = X_XIQueryDevice,
116 .sequenceNumber = client->sequence,
117 .length = len / 4,
118 .num_devices = 0
121 ptr = info;
122 if (dev) {
123 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
124 if (client->swapped)
125 SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
126 info += len;
127 rep.num_devices = 1;
129 else {
130 i = 0;
131 for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
132 if (!skip[i]) {
133 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
134 if (client->swapped)
135 SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
136 info += len;
137 rep.num_devices++;
141 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
142 if (!skip[i]) {
143 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
144 if (client->swapped)
145 SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
146 info += len;
147 rep.num_devices++;
152 len = rep.length * 4;
153 WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep);
154 WriteToClient(client, len, ptr);
155 free(ptr);
156 free(skip);
157 return rc;
160 void
161 SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply * rep)
163 swaps(&rep->sequenceNumber);
164 swapl(&rep->length);
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.
175 static Bool
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);
182 if (rc == Success)
183 return FALSE;
185 return TRUE;
189 * @return The number of bytes needed to store this device's xXIDeviceInfo
190 * (and its classes).
192 static int
193 SizeDeviceInfo(DeviceIntPtr dev)
195 int len = sizeof(xXIDeviceInfo);
197 /* 4-padded name */
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)
210 int len = 0;
212 if (dev->button) {
213 len += sizeof(xXIButtonInfo);
214 len += dev->button->numButtons * sizeof(Atom);
215 len += pad_to_int32(bits_to_bytes(dev->button->numButtons));
218 if (dev->key) {
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);
225 if (dev->valuator) {
226 int i;
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);
236 if (dev->touch)
237 len += sizeof(xXITouchInfo);
239 if (dev->gesture)
240 len += sizeof(xXIGestureInfo);
242 return len;
246 * Get pointers to button information areas holding button mask and labels.
248 static void
249 ButtonInfoData(xXIButtonInfo *info, int *mask_words, unsigned char **mask,
250 Atom **atoms)
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)
264 unsigned char *bits;
265 Atom *labels;
266 int mask_len;
267 int i;
269 if (!dev || !dev->button)
270 return 0;
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);
281 if (reportState)
282 for (i = 0; i < dev->button->numButtons; i++)
283 if (BitIsOn(dev->button->down, i))
284 SetBit(bits, i);
286 memcpy(labels, dev->button->labels, dev->button->numButtons * sizeof(Atom));
288 return info->length * 4;
291 static void
292 SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info)
294 Atom *btn;
295 int mask_len;
296 unsigned char *mask;
298 int i;
299 ButtonInfoData(info, &mask_len, &mask, &btn);
301 swaps(&info->type);
302 swaps(&info->length);
303 swaps(&info->sourceid);
305 for (i = 0 ; i < info->num_buttons; i++, btn++)
306 swapl(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)
318 int i;
319 XkbDescPtr xkb = dev->key->xkbInfo->desc;
320 uint32_t *kc;
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++)
329 *kc = i;
331 return info->length * 4;
334 static void
335 SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
337 uint32_t *key;
338 int i;
340 swaps(&info->type);
341 swaps(&info->length);
342 swaps(&info->sourceid);
344 for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes;
345 i++, key++)
346 swapl(key);
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,
358 Bool reportState)
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;
366 info->min.frac = 0;
367 info->max.integral = v->axes[axisnumber].max_value;
368 info->max.frac = 0;
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;
375 if (!reportState)
376 info->value = info->min;
378 return info->length * 4;
381 static void
382 SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info)
384 swaps(&info->type);
385 swaps(&info->length);
386 swapl(&info->label);
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)
405 return 0;
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;
413 break;
414 case SCROLL_TYPE_HORIZONTAL:
415 info->scroll_type = XIScrollTypeHorizontal;
416 break;
417 default:
418 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
419 axis->scroll.type);
420 break;
422 info->increment = double_to_fp3232(axis->scroll.increment);
423 info->sourceid = v->sourceid;
425 info->flags = 0;
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;
435 static void
436 SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info)
438 swaps(&info->type);
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;
464 static void
465 SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
467 swaps(&touch->type);
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
479 * XIQueryDevice.
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;
485 return FALSE;
489 * List gesture information
491 * @return The number of bytes written into info.
493 static int
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;
504 static void
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);
516 int use;
518 if (IsMaster(dev)) {
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;
528 else
529 use = XIFloatingSlave;
531 return use;
535 * Write the info for device dev into the buffer pointed to by info.
537 * @return The number of bytes used.
539 static int
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);
553 memset(any, 0, len);
554 strncpy(any, dev->name, info->name_len);
555 any += len;
556 total_len += len;
558 total_len += ListDeviceClasses(client, dev, any, &info->num_classes);
559 return total_len;
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
565 * written.
568 ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
569 char *any, uint16_t * nclasses)
571 int total_len = 0;
572 int len;
573 int i;
574 int rc;
576 /* Check if the current device state should be suppressed */
577 rc = XaceHookDeviceAccess(client, dev, DixReadAccess);
579 if (dev->button) {
580 (*nclasses)++;
581 len = ListButtonInfo(dev, (xXIButtonInfo *) any, rc == Success);
582 any += len;
583 total_len += len;
586 if (dev->key) {
587 (*nclasses)++;
588 len = ListKeyInfo(dev, (xXIKeyInfo *) any);
589 any += len;
590 total_len += len;
593 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
594 (*nclasses)++;
595 len = ListValuatorInfo(dev, (xXIValuatorInfo *) any, i, rc == Success);
596 any += len;
597 total_len += len;
600 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
601 len = ListScrollInfo(dev, (xXIScrollInfo *) any, i);
602 if (len)
603 (*nclasses)++;
604 any += len;
605 total_len += len;
608 if (dev->touch) {
609 (*nclasses)++;
610 len = ListTouchInfo(dev, (xXITouchInfo *) any);
611 any += len;
612 total_len += len;
615 if (dev->gesture && ShouldListGestureInfo(client)) {
616 (*nclasses)++;
617 len = ListGestureInfo(dev, (xXIGestureInfo *) any);
618 any += len;
619 total_len += len;
622 return total_len;
625 static void
626 SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
628 char *any = (char *) &info[1];
629 int i;
631 /* Skip over name */
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) {
638 case XIButtonClass:
639 SwapButtonInfo(dev, (xXIButtonInfo *) any);
640 break;
641 case XIKeyClass:
642 SwapKeyInfo(dev, (xXIKeyInfo *) any);
643 break;
644 case XIValuatorClass:
645 SwapValuatorInfo(dev, (xXIValuatorInfo *) any);
646 break;
647 case XIScrollClass:
648 SwapScrollInfo(dev, (xXIScrollInfo *) any);
649 break;
650 case XITouchClass:
651 SwapTouchInfo(dev, (xXITouchInfo *) any);
652 break;
653 case XIGestureClass:
654 SwapGestureInfo(dev, (xXIGestureInfo *) any);
655 break;
658 any += len * 4;
661 swaps(&info->deviceid);
662 swaps(&info->use);
663 swaps(&info->attachment);
664 swaps(&info->num_classes);
665 swaps(&info->name_len);