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