1 /*
2 * Copyright © 2009 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 * Authors: Peter Hutterer
24 *
25 */
27 /**
28 * @file Protocol handling for the XIQueryDevice request/reply.
29 */
31 #ifdef HAVE_DIX_CONFIG_H
32 #include <dix-config.h>
33 #endif
35 #include "inputstr.h"
36 #include <X11/X.h>
37 #include <X11/Xatom.h>
38 #include <X11/extensions/XI2proto.h>
39 #include "xkbstr.h"
40 #include "xkbsrv.h"
41 #include "xserver-properties.h"
42 #include "exevents.h"
43 #include "xace.h"
44 #include "inpututils.h"
46 #include "xiquerydevice.h"
48 static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
49 static int
50 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info);
51 static int SizeDeviceInfo(DeviceIntPtr dev);
52 static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info);
53 int
54 SProcXIQueryDevice(ClientPtr client)
55 {
56 char n;
58 REQUEST(xXIQueryDeviceReq);
60 swaps(&stuff->length, n);
61 swaps(&stuff->deviceid, n);
63 return ProcXIQueryDevice(client);
64 }
66 int
67 ProcXIQueryDevice(ClientPtr client)
68 {
69 xXIQueryDeviceReply rep;
70 DeviceIntPtr dev = NULL;
71 int rc = Success;
72 int i = 0, len = 0;
73 char *info, *ptr;
74 Bool *skip = NULL;
76 REQUEST(xXIQueryDeviceReq);
77 REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
79 if (stuff->deviceid != XIAllDevices && stuff->deviceid != XIAllMasterDevices)
80 {
81 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
82 if (rc != Success)
83 {
84 client->errorValue = stuff->deviceid;
85 return rc;
86 }
87 len += SizeDeviceInfo(dev);
88 }
89 else
90 {
91 skip = calloc(sizeof(Bool), inputInfo.numDevices);
92 if (!skip)
93 return BadAlloc;
95 for (dev = inputInfo.devices; dev; dev = dev->next, i++)
96 {
97 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
98 if (!skip[i])
99 len += SizeDeviceInfo(dev);
100 }
102 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++)
103 {
104 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
105 if (!skip[i])
106 len += SizeDeviceInfo(dev);
107 }
108 }
110 info = calloc(1, len);
111 if (!info) {
112 free(skip);
113 return BadAlloc;
114 }
116 memset(&rep, 0, sizeof(xXIQueryDeviceReply));
117 rep.repType = X_Reply;
118 rep.RepType = X_XIQueryDevice;
119 rep.sequenceNumber = client->sequence;
120 rep.length = len/4;
121 rep.num_devices = 0;
123 ptr = info;
124 if (dev)
125 {
126 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
127 if (client->swapped)
128 SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
129 info += len;
130 rep.num_devices = 1;
131 } else
132 {
133 i = 0;
134 for (dev = inputInfo.devices; dev; dev = dev->next, i++)
135 {
136 if (!skip[i])
137 {
138 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
139 if (client->swapped)
140 SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
141 info += len;
142 rep.num_devices++;
143 }
144 }
146 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++)
147 {
148 if (!skip[i])
149 {
150 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
151 if (client->swapped)
152 SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
153 info += len;
154 rep.num_devices++;
155 }
156 }
157 }
159 len = rep.length * 4;
160 WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep);
161 WriteToClient(client, len, ptr);
162 free(ptr);
163 free(skip);
164 return rc;
165 }
167 void
168 SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep)
169 {
170 char n;
172 swaps(&rep->sequenceNumber, n);
173 swapl(&rep->length, n);
174 swaps(&rep->num_devices, n);
176 /* Device info is already swapped, see ProcXIQueryDevice */
178 WriteToClient(client, size, (char *)rep);
179 }
182 /**
183 * @return Whether the device should be included in the returned list.
184 */
185 static Bool
186 ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev)
187 {
188 /* if all devices are not being queried, only master devices are */
189 if (deviceid == XIAllDevices || IsMaster(dev))
190 {
191 int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
192 if (rc == Success)
193 return FALSE;
194 }
195 return TRUE;
196 }
198 /**
199 * @return The number of bytes needed to store this device's xXIDeviceInfo
200 * (and its classes).
201 */
202 static int
203 SizeDeviceInfo(DeviceIntPtr dev)
204 {
205 int len = sizeof(xXIDeviceInfo);
207 /* 4-padded name */
208 len += pad_to_int32(strlen(dev->name));
210 return len + SizeDeviceClasses(dev);
212 }
214 /*
215 * @return The number of bytes needed to store this device's classes.
216 */
217 int
218 SizeDeviceClasses(DeviceIntPtr dev)
219 {
220 int len = 0;
222 if (dev->button)
223 {
224 len += sizeof(xXIButtonInfo);
225 len += dev->button->numButtons * sizeof(Atom);
226 len += pad_to_int32(bits_to_bytes(dev->button->numButtons));
227 }
229 if (dev->key)
230 {
231 XkbDescPtr xkb = dev->key->xkbInfo->desc;
232 len += sizeof(xXIKeyInfo);
233 len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t);
234 }
236 if (dev->valuator)
237 {
238 int i;
239 len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes;
241 for (i = 0; i < dev->valuator->numAxes; i++) {
242 if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE)
243 len += sizeof(xXIScrollInfo);
244 }
245 }
247 if (dev->touch)
248 len += sizeof(xXITouchInfo);
250 return len;
251 }
254 /**
255 * Write button information into info.
256 * @return Number of bytes written into info.
257 */
258 int
259 ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState)
260 {
261 unsigned char *bits;
262 int mask_len;
263 int i;
265 if (!dev || !dev->button)
266 return 0;
268 mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons));
270 info->type = ButtonClass;
271 info->num_buttons = dev->button->numButtons;
272 info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
273 info->num_buttons + mask_len;
274 info->sourceid = dev->button->sourceid;
276 bits = (unsigned char*)&info[1];
277 memset(bits, 0, mask_len * 4);
279 if (reportState)
280 for (i = 0; i < dev->button->numButtons; i++)
281 if (BitIsOn(dev->button->down, i))
282 SetBit(bits, i);
284 bits += mask_len * 4;
285 memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom));
287 return info->length * 4;
288 }
290 static void
291 SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info)
292 {
293 char n;
294 Atom *btn;
295 int i;
296 swaps(&info->type, n);
297 swaps(&info->length, n);
298 swaps(&info->sourceid, n);
300 for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++)
301 swaps(btn, n);
303 swaps(&info->num_buttons, n);
304 }
306 /**
307 * Write key information into info.
308 * @return Number of bytes written into info.
309 */
310 int
311 ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info)
312 {
313 int i;
314 XkbDescPtr xkb = dev->key->xkbInfo->desc;
315 uint32_t *kc;
317 info->type = KeyClass;
318 info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1;
319 info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
320 info->sourceid = dev->key->sourceid;
322 kc = (uint32_t*)&info[1];
323 for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++)
324 *kc = i;
326 return info->length * 4;
327 }
329 static void
330 SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info)
331 {
332 char n;
333 uint32_t *key;
334 int i;
335 swaps(&info->type, n);
336 swaps(&info->length, n);
337 swaps(&info->sourceid, n);
339 for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++)
340 swapl(key, n);
342 swaps(&info->num_keycodes, n);
343 }
345 /**
346 * List axis information for the given axis.
347 *
348 * @return The number of bytes written into info.
349 */
350 int
351 ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber,
352 Bool reportState)
353 {
354 ValuatorClassPtr v = dev->valuator;
356 info->type = ValuatorClass;
357 info->length = sizeof(xXIValuatorInfo)/4;
358 info->label = v->axes[axisnumber].label;
359 info->min.integral = v->axes[axisnumber].min_value;
360 info->min.frac = 0;
361 info->max.integral = v->axes[axisnumber].max_value;
362 info->max.frac = 0;
363 info->value = double_to_fp3232(v->axisVal[axisnumber]);
364 info->resolution = v->axes[axisnumber].resolution;
365 info->number = axisnumber;
366 info->mode = valuator_get_mode(dev, axisnumber);
367 info->sourceid = v->sourceid;
369 if (!reportState)
370 info->value = info->min;
372 return info->length * 4;
373 }
375 static void
376 SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info)
377 {
378 char n;
379 swaps(&info->type, n);
380 swaps(&info->length, n);
381 swapl(&info->label, n);
382 swapl(&info->min.integral, n);
383 swapl(&info->min.frac, n);
384 swapl(&info->max.integral, n);
385 swapl(&info->max.frac, n);
386 swaps(&info->number, n);
387 swaps(&info->sourceid, n);
388 }
390 int
391 ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo *info, int axisnumber)
392 {
393 ValuatorClassPtr v = dev->valuator;
394 AxisInfoPtr axis = &v->axes[axisnumber];
396 if (axis->scroll.type == SCROLL_TYPE_NONE)
397 return 0;
399 info->type = XIScrollClass;
400 info->length = sizeof(xXIScrollInfo)/4;
401 info->number = axisnumber;
402 switch(axis->scroll.type)
403 {
404 case SCROLL_TYPE_VERTICAL:
405 info->scroll_type = XIScrollTypeVertical;
406 break;
407 case SCROLL_TYPE_HORIZONTAL:
408 info->scroll_type = XIScrollTypeHorizontal;
409 break;
410 default:
411 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n", axis->scroll.type);
412 break;
413 }
414 info->increment = double_to_fp3232(axis->scroll.increment);
415 info->sourceid = v->sourceid;
417 info->flags = 0;
419 if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE)
420 info->flags |= XIScrollFlagNoEmulation;
421 if (axis->scroll.flags & SCROLL_FLAG_PREFERRED)
422 info->flags |= XIScrollFlagPreferred;
424 return info->length * 4;
425 }
427 static void
428 SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info)
429 {
430 char n;
432 swaps(&info->type, n);
433 swaps(&info->length, n);
434 swaps(&info->number, n);
435 swaps(&info->sourceid, n);
436 swaps(&info->scroll_type, n);
437 swapl(&info->increment.integral, n);
438 swapl(&info->increment.frac, n);
439 }
441 /**
442 * List multitouch information
443 *
444 * @return The number of bytes written into info.
445 */
446 int
447 ListTouchInfo(DeviceIntPtr dev, xXITouchInfo *touch)
448 {
449 touch->type = XITouchClass;
450 touch->length = sizeof(xXITouchInfo) >> 2;
451 touch->sourceid = touch->sourceid;
452 touch->mode = dev->touch->mode;
453 touch->num_touches = dev->touch->num_touches;
455 return touch->length << 2;
456 }
458 static void
459 SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo* touch)
460 {
461 char n;
463 swaps(&touch->type, n);
464 swaps(&touch->length, n);
465 swaps(&touch->sourceid, n);
466 }
468 int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
469 {
470 DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
471 int use;
473 if (IsMaster(dev))
474 {
475 DeviceIntPtr paired = GetPairedDevice(dev);
476 use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard;
477 *attachment = (paired ? paired->id : 0);
478 } else if (!IsFloating(dev))
479 {
480 use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard;
481 *attachment = master->id;
482 } else
483 use = XIFloatingSlave;
485 return use;
486 }
488 /**
489 * Write the info for device dev into the buffer pointed to by info.
490 *
491 * @return The number of bytes used.
492 */
493 static int
494 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info)
495 {
496 char *any = (char*)&info[1];
497 int len = 0, total_len = 0;
499 info->deviceid = dev->id;
500 info->use = GetDeviceUse(dev, &info->attachment);
501 info->num_classes = 0;
502 info->name_len = strlen(dev->name);
503 info->enabled = dev->enabled;
504 total_len = sizeof(xXIDeviceInfo);
506 len = pad_to_int32(info->name_len);
507 memset(any, 0, len);
508 strncpy(any, dev->name, info->name_len);
509 any += len;
510 total_len += len;
512 total_len += ListDeviceClasses(client, dev, any, &info->num_classes);
513 return total_len;
514 }
516 /**
517 * Write the class info of the device into the memory pointed to by any, set
518 * nclasses to the number of classes in total and return the number of bytes
519 * written.
520 */
521 int
522 ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
523 char *any, uint16_t *nclasses)
524 {
525 int total_len = 0;
526 int len;
527 int i;
528 int rc;
530 /* Check if the current device state should be suppressed */
531 rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
533 if (dev->button)
534 {
535 (*nclasses)++;
536 len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success);
537 any += len;
538 total_len += len;
539 }
541 if (dev->key)
542 {
543 (*nclasses)++;
544 len = ListKeyInfo(dev, (xXIKeyInfo*)any);
545 any += len;
546 total_len += len;
547 }
549 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++)
550 {
551 (*nclasses)++;
552 len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success);
553 any += len;
554 total_len += len;
555 }
557 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++)
558 {
559 len = ListScrollInfo(dev, (xXIScrollInfo*)any, i);
560 if (len)
561 (*nclasses)++;
562 any += len;
563 total_len += len;
564 }
566 if (dev->touch)
567 {
568 (*nclasses)++;
569 len = ListTouchInfo(dev, (xXITouchInfo*)any);
570 any += len;
571 total_len += len;
572 }
574 return total_len;
575 }
577 static void
578 SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
579 {
580 char n;
581 char *any = (char*)&info[1];
582 int i;
584 /* Skip over name */
585 any += pad_to_int32(info->name_len);
587 for (i = 0; i < info->num_classes; i++)
588 {
589 int len = ((xXIAnyInfo*)any)->length;
590 switch(((xXIAnyInfo*)any)->type)
591 {
592 case XIButtonClass:
593 SwapButtonInfo(dev, (xXIButtonInfo*)any);
594 break;
595 case XIKeyClass:
596 SwapKeyInfo(dev, (xXIKeyInfo*)any);
597 break;
598 case XIValuatorClass:
599 SwapValuatorInfo(dev, (xXIValuatorInfo*)any);
600 break;
601 case XIScrollClass:
602 SwapScrollInfo(dev, (xXIScrollInfo*)any);
603 break;
604 case XITouchClass:
605 SwapTouchInfo(dev, (xXITouchInfo*)any);
606 break;
608 }
610 any += len * 4;
611 }
613 swaps(&info->deviceid, n);
614 swaps(&info->use, n);
615 swaps(&info->attachment, n);
616 swaps(&info->num_classes, n);
617 swaps(&info->name_len, n);
619 }