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