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