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