16747b715Smrg/*
26747b715Smrg * Copyright © 2009 Red Hat, Inc.
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
226747b715Smrg *
236747b715Smrg * Authors: Peter Hutterer
246747b715Smrg *
256747b715Smrg */
266747b715Smrg
276747b715Smrg/**
286747b715Smrg * @file Protocol handling for the XIQueryDevice request/reply.
296747b715Smrg */
306747b715Smrg
316747b715Smrg#ifdef HAVE_DIX_CONFIG_H
326747b715Smrg#include <dix-config.h>
336747b715Smrg#endif
346747b715Smrg
356747b715Smrg#include "inputstr.h"
366747b715Smrg#include <X11/X.h>
376747b715Smrg#include <X11/Xatom.h>
386747b715Smrg#include <X11/extensions/XI2proto.h>
396747b715Smrg#include "xkbstr.h"
406747b715Smrg#include "xkbsrv.h"
416747b715Smrg#include "xserver-properties.h"
426747b715Smrg#include "exevents.h"
436747b715Smrg#include "xace.h"
44f7df2e56Smrg#include "inpututils.h"
456747b715Smrg
465a112b11Smrg#include "exglobals.h"
475a112b11Smrg#include "privates.h"
485a112b11Smrg
496747b715Smrg#include "xiquerydevice.h"
506747b715Smrg
516747b715Smrgstatic Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
526747b715Smrgstatic int
53f7df2e56Smrg ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info);
546747b715Smrgstatic int SizeDeviceInfo(DeviceIntPtr dev);
55f7df2e56Smrgstatic void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info);
567e31ba66Smrgint _X_COLD
576747b715SmrgSProcXIQueryDevice(ClientPtr client)
586747b715Smrg{
596747b715Smrg    REQUEST(xXIQueryDeviceReq);
600b0d8713Smrg    REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
616747b715Smrg
62f7df2e56Smrg    swaps(&stuff->length);
63f7df2e56Smrg    swaps(&stuff->deviceid);
646747b715Smrg
656747b715Smrg    return ProcXIQueryDevice(client);
666747b715Smrg}
676747b715Smrg
686747b715Smrgint
696747b715SmrgProcXIQueryDevice(ClientPtr client)
706747b715Smrg{
716747b715Smrg    xXIQueryDeviceReply rep;
726747b715Smrg    DeviceIntPtr dev = NULL;
736747b715Smrg    int rc = Success;
746747b715Smrg    int i = 0, len = 0;
756747b715Smrg    char *info, *ptr;
766747b715Smrg    Bool *skip = NULL;
776747b715Smrg
786747b715Smrg    REQUEST(xXIQueryDeviceReq);
796747b715Smrg    REQUEST_SIZE_MATCH(xXIQueryDeviceReq);
806747b715Smrg
81f7df2e56Smrg    if (stuff->deviceid != XIAllDevices &&
82f7df2e56Smrg        stuff->deviceid != XIAllMasterDevices) {
836747b715Smrg        rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
84f7df2e56Smrg        if (rc != Success) {
856747b715Smrg            client->errorValue = stuff->deviceid;
866747b715Smrg            return rc;
876747b715Smrg        }
886747b715Smrg        len += SizeDeviceInfo(dev);
896747b715Smrg    }
90f7df2e56Smrg    else {
916747b715Smrg        skip = calloc(sizeof(Bool), inputInfo.numDevices);
926747b715Smrg        if (!skip)
936747b715Smrg            return BadAlloc;
946747b715Smrg
95f7df2e56Smrg        for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
966747b715Smrg            skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
976747b715Smrg            if (!skip[i])
986747b715Smrg                len += SizeDeviceInfo(dev);
996747b715Smrg        }
1006747b715Smrg
101f7df2e56Smrg        for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
1026747b715Smrg            skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
1036747b715Smrg            if (!skip[i])
1046747b715Smrg                len += SizeDeviceInfo(dev);
1056747b715Smrg        }
1066747b715Smrg    }
1076747b715Smrg
1086747b715Smrg    info = calloc(1, len);
1099ace9065Smrg    if (!info) {
1109ace9065Smrg        free(skip);
1116747b715Smrg        return BadAlloc;
1129ace9065Smrg    }
1136747b715Smrg
114f7df2e56Smrg    rep = (xXIQueryDeviceReply) {
115f7df2e56Smrg        .repType = X_Reply,
116f7df2e56Smrg        .RepType = X_XIQueryDevice,
117f7df2e56Smrg        .sequenceNumber = client->sequence,
118f7df2e56Smrg        .length = len / 4,
119f7df2e56Smrg        .num_devices = 0
120f7df2e56Smrg    };
1216747b715Smrg
1226747b715Smrg    ptr = info;
123f7df2e56Smrg    if (dev) {
124f7df2e56Smrg        len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
1256747b715Smrg        if (client->swapped)
126f7df2e56Smrg            SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
1276747b715Smrg        info += len;
1286747b715Smrg        rep.num_devices = 1;
129f7df2e56Smrg    }
130f7df2e56Smrg    else {
1316747b715Smrg        i = 0;
132f7df2e56Smrg        for (dev = inputInfo.devices; dev; dev = dev->next, i++) {
133f7df2e56Smrg            if (!skip[i]) {
134f7df2e56Smrg                len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
1356747b715Smrg                if (client->swapped)
136f7df2e56Smrg                    SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
1376747b715Smrg                info += len;
1386747b715Smrg                rep.num_devices++;
1396747b715Smrg            }
1406747b715Smrg        }
1416747b715Smrg
142f7df2e56Smrg        for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) {
143f7df2e56Smrg            if (!skip[i]) {
144f7df2e56Smrg                len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info);
1456747b715Smrg                if (client->swapped)
146f7df2e56Smrg                    SwapDeviceInfo(dev, (xXIDeviceInfo *) info);
1476747b715Smrg                info += len;
1486747b715Smrg                rep.num_devices++;
1496747b715Smrg            }
1506747b715Smrg        }
1516747b715Smrg    }
1526747b715Smrg
1539ace9065Smrg    len = rep.length * 4;
1546747b715Smrg    WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep);
1559ace9065Smrg    WriteToClient(client, len, ptr);
1566747b715Smrg    free(ptr);
1576747b715Smrg    free(skip);
1586747b715Smrg    return rc;
1596747b715Smrg}
1606747b715Smrg
1616747b715Smrgvoid
162f7df2e56SmrgSRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply * rep)
1636747b715Smrg{
164f7df2e56Smrg    swaps(&rep->sequenceNumber);
165f7df2e56Smrg    swapl(&rep->length);
166f7df2e56Smrg    swaps(&rep->num_devices);
1676747b715Smrg
1686747b715Smrg    /* Device info is already swapped, see ProcXIQueryDevice */
1696747b715Smrg
170f7df2e56Smrg    WriteToClient(client, size, rep);
1716747b715Smrg}
1726747b715Smrg
1736747b715Smrg/**
1746747b715Smrg * @return Whether the device should be included in the returned list.
1756747b715Smrg */
1766747b715Smrgstatic Bool
1776747b715SmrgShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev)
1786747b715Smrg{
1796747b715Smrg    /* if all devices are not being queried, only master devices are */
180f7df2e56Smrg    if (deviceid == XIAllDevices || IsMaster(dev)) {
1816747b715Smrg        int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
182f7df2e56Smrg
1836747b715Smrg        if (rc == Success)
1846747b715Smrg            return FALSE;
1856747b715Smrg    }
1866747b715Smrg    return TRUE;
1876747b715Smrg}
1886747b715Smrg
1896747b715Smrg/**
1906747b715Smrg * @return The number of bytes needed to store this device's xXIDeviceInfo
1916747b715Smrg * (and its classes).
1926747b715Smrg */
1936747b715Smrgstatic int
1946747b715SmrgSizeDeviceInfo(DeviceIntPtr dev)
1956747b715Smrg{
1966747b715Smrg    int len = sizeof(xXIDeviceInfo);
1976747b715Smrg
1986747b715Smrg    /* 4-padded name */
1996747b715Smrg    len += pad_to_int32(strlen(dev->name));
2006747b715Smrg
2016747b715Smrg    return len + SizeDeviceClasses(dev);
2026747b715Smrg
2036747b715Smrg}
2046747b715Smrg
2056747b715Smrg/*
2066747b715Smrg * @return The number of bytes needed to store this device's classes.
2076747b715Smrg */
2086747b715Smrgint
2096747b715SmrgSizeDeviceClasses(DeviceIntPtr dev)
2106747b715Smrg{
2116747b715Smrg    int len = 0;
2126747b715Smrg
213f7df2e56Smrg    if (dev->button) {
2146747b715Smrg        len += sizeof(xXIButtonInfo);
2156747b715Smrg        len += dev->button->numButtons * sizeof(Atom);
2166747b715Smrg        len += pad_to_int32(bits_to_bytes(dev->button->numButtons));
2176747b715Smrg    }
2186747b715Smrg
219f7df2e56Smrg    if (dev->key) {
2206747b715Smrg        XkbDescPtr xkb = dev->key->xkbInfo->desc;
221f7df2e56Smrg
2226747b715Smrg        len += sizeof(xXIKeyInfo);
2236747b715Smrg        len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t);
2246747b715Smrg    }
2256747b715Smrg
226f7df2e56Smrg    if (dev->valuator) {
227f7df2e56Smrg        int i;
228f7df2e56Smrg
229f7df2e56Smrg        len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes;
230f7df2e56Smrg
231f7df2e56Smrg        for (i = 0; i < dev->valuator->numAxes; i++) {
232f7df2e56Smrg            if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE)
233f7df2e56Smrg                len += sizeof(xXIScrollInfo);
234f7df2e56Smrg        }
235f7df2e56Smrg    }
236f7df2e56Smrg
237f7df2e56Smrg    if (dev->touch)
238f7df2e56Smrg        len += sizeof(xXITouchInfo);
2396747b715Smrg
2405a112b11Smrg    if (dev->gesture)
2415a112b11Smrg        len += sizeof(xXIGestureInfo);
2425a112b11Smrg
2436747b715Smrg    return len;
2446747b715Smrg}
2456747b715Smrg
2467e31ba66Smrg/**
2477e31ba66Smrg * Get pointers to button information areas holding button mask and labels.
2487e31ba66Smrg */
2497e31ba66Smrgstatic void
2507e31ba66SmrgButtonInfoData(xXIButtonInfo *info, int *mask_words, unsigned char **mask,
2517e31ba66Smrg               Atom **atoms)
2527e31ba66Smrg{
2537e31ba66Smrg    *mask_words = bytes_to_int32(bits_to_bytes(info->num_buttons));
2547e31ba66Smrg    *mask = (unsigned char*) &info[1];
2557e31ba66Smrg    *atoms = (Atom*) ((*mask) + (*mask_words) * 4);
2567e31ba66Smrg}
2577e31ba66Smrg
2586747b715Smrg/**
2596747b715Smrg * Write button information into info.
2606747b715Smrg * @return Number of bytes written into info.
2616747b715Smrg */
2626747b715Smrgint
263f7df2e56SmrgListButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info, Bool reportState)
2646747b715Smrg{
2656747b715Smrg    unsigned char *bits;
2667e31ba66Smrg    Atom *labels;
2676747b715Smrg    int mask_len;
2686747b715Smrg    int i;
2696747b715Smrg
2706747b715Smrg    if (!dev || !dev->button)
271f7df2e56Smrg        return 0;
2726747b715Smrg
2736747b715Smrg    info->type = ButtonClass;
2746747b715Smrg    info->num_buttons = dev->button->numButtons;
2757e31ba66Smrg    ButtonInfoData(info, &mask_len, &bits, &labels);
2766747b715Smrg    info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
277f7df2e56Smrg        info->num_buttons + mask_len;
2786747b715Smrg    info->sourceid = dev->button->sourceid;
2796747b715Smrg
2806747b715Smrg    memset(bits, 0, mask_len * 4);
2816747b715Smrg
2826747b715Smrg    if (reportState)
283f7df2e56Smrg        for (i = 0; i < dev->button->numButtons; i++)
284f7df2e56Smrg            if (BitIsOn(dev->button->down, i))
285f7df2e56Smrg                SetBit(bits, i);
2866747b715Smrg
2877e31ba66Smrg    memcpy(labels, dev->button->labels, dev->button->numButtons * sizeof(Atom));
2886747b715Smrg
2896747b715Smrg    return info->length * 4;
2906747b715Smrg}
2916747b715Smrg
2926747b715Smrgstatic void
293f7df2e56SmrgSwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info)
2946747b715Smrg{
2956747b715Smrg    Atom *btn;
2967e31ba66Smrg    int mask_len;
2977e31ba66Smrg    unsigned char *mask;
2987e31ba66Smrg
2996747b715Smrg    int i;
3007e31ba66Smrg    ButtonInfoData(info, &mask_len, &mask, &btn);
3016747b715Smrg
302f7df2e56Smrg    swaps(&info->type);
303f7df2e56Smrg    swaps(&info->length);
304f7df2e56Smrg    swaps(&info->sourceid);
305f7df2e56Smrg
3067e31ba66Smrg    for (i = 0 ; i < info->num_buttons; i++, btn++)
307f7df2e56Smrg        swapl(btn);
3086747b715Smrg
309f7df2e56Smrg    swaps(&info->num_buttons);
3106747b715Smrg}
3116747b715Smrg
3126747b715Smrg/**
3136747b715Smrg * Write key information into info.
3146747b715Smrg * @return Number of bytes written into info.
3156747b715Smrg */
3166747b715Smrgint
317f7df2e56SmrgListKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
3186747b715Smrg{
3196747b715Smrg    int i;
3206747b715Smrg    XkbDescPtr xkb = dev->key->xkbInfo->desc;
3216747b715Smrg    uint32_t *kc;
3226747b715Smrg
3236747b715Smrg    info->type = KeyClass;
3246747b715Smrg    info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1;
325f7df2e56Smrg    info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes;
3266747b715Smrg    info->sourceid = dev->key->sourceid;
3276747b715Smrg
328f7df2e56Smrg    kc = (uint32_t *) &info[1];
3296747b715Smrg    for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++)
3306747b715Smrg        *kc = i;
3316747b715Smrg
3326747b715Smrg    return info->length * 4;
3336747b715Smrg}
3346747b715Smrg
3356747b715Smrgstatic void
336f7df2e56SmrgSwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
3376747b715Smrg{
3386747b715Smrg    uint32_t *key;
3396747b715Smrg    int i;
3406747b715Smrg
341f7df2e56Smrg    swaps(&info->type);
342f7df2e56Smrg    swaps(&info->length);
343f7df2e56Smrg    swaps(&info->sourceid);
3446747b715Smrg
345f7df2e56Smrg    for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes;
346f7df2e56Smrg         i++, key++)
347f7df2e56Smrg        swapl(key);
348f7df2e56Smrg
349f7df2e56Smrg    swaps(&info->num_keycodes);
3506747b715Smrg}
3516747b715Smrg
3526747b715Smrg/**
3536747b715Smrg * List axis information for the given axis.
3546747b715Smrg *
3556747b715Smrg * @return The number of bytes written into info.
3566747b715Smrg */
3576747b715Smrgint
358f7df2e56SmrgListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info, int axisnumber,
359f7df2e56Smrg                 Bool reportState)
3606747b715Smrg{
3616747b715Smrg    ValuatorClassPtr v = dev->valuator;
3626747b715Smrg
3636747b715Smrg    info->type = ValuatorClass;
364f7df2e56Smrg    info->length = sizeof(xXIValuatorInfo) / 4;
3656747b715Smrg    info->label = v->axes[axisnumber].label;
3666747b715Smrg    info->min.integral = v->axes[axisnumber].min_value;
3676747b715Smrg    info->min.frac = 0;
3686747b715Smrg    info->max.integral = v->axes[axisnumber].max_value;
3696747b715Smrg    info->max.frac = 0;
370f7df2e56Smrg    info->value = double_to_fp3232(v->axisVal[axisnumber]);
3716747b715Smrg    info->resolution = v->axes[axisnumber].resolution;
3726747b715Smrg    info->number = axisnumber;
3739ace9065Smrg    info->mode = valuator_get_mode(dev, axisnumber);
3746747b715Smrg    info->sourceid = v->sourceid;
3756747b715Smrg
3766747b715Smrg    if (!reportState)
377f7df2e56Smrg        info->value = info->min;
3786747b715Smrg
3796747b715Smrg    return info->length * 4;
3806747b715Smrg}
3816747b715Smrg
3826747b715Smrgstatic void
383f7df2e56SmrgSwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info)
384f7df2e56Smrg{
385f7df2e56Smrg    swaps(&info->type);
386f7df2e56Smrg    swaps(&info->length);
387f7df2e56Smrg    swapl(&info->label);
388f7df2e56Smrg    swapl(&info->min.integral);
389f7df2e56Smrg    swapl(&info->min.frac);
390f7df2e56Smrg    swapl(&info->max.integral);
391f7df2e56Smrg    swapl(&info->max.frac);
3927e31ba66Smrg    swapl(&info->value.integral);
3937e31ba66Smrg    swapl(&info->value.frac);
3947e31ba66Smrg    swapl(&info->resolution);
395f7df2e56Smrg    swaps(&info->number);
396f7df2e56Smrg    swaps(&info->sourceid);
397f7df2e56Smrg}
398f7df2e56Smrg
399f7df2e56Smrgint
400f7df2e56SmrgListScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info, int axisnumber)
4016747b715Smrg{
402f7df2e56Smrg    ValuatorClassPtr v = dev->valuator;
403f7df2e56Smrg    AxisInfoPtr axis = &v->axes[axisnumber];
404f7df2e56Smrg
405f7df2e56Smrg    if (axis->scroll.type == SCROLL_TYPE_NONE)
406f7df2e56Smrg        return 0;
407f7df2e56Smrg
408f7df2e56Smrg    info->type = XIScrollClass;
409f7df2e56Smrg    info->length = sizeof(xXIScrollInfo) / 4;
410f7df2e56Smrg    info->number = axisnumber;
411f7df2e56Smrg    switch (axis->scroll.type) {
412f7df2e56Smrg    case SCROLL_TYPE_VERTICAL:
413f7df2e56Smrg        info->scroll_type = XIScrollTypeVertical;
414f7df2e56Smrg        break;
415f7df2e56Smrg    case SCROLL_TYPE_HORIZONTAL:
416f7df2e56Smrg        info->scroll_type = XIScrollTypeHorizontal;
417f7df2e56Smrg        break;
418f7df2e56Smrg    default:
419f7df2e56Smrg        ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
420f7df2e56Smrg               axis->scroll.type);
421f7df2e56Smrg        break;
422f7df2e56Smrg    }
423f7df2e56Smrg    info->increment = double_to_fp3232(axis->scroll.increment);
424f7df2e56Smrg    info->sourceid = v->sourceid;
425f7df2e56Smrg
426f7df2e56Smrg    info->flags = 0;
427f7df2e56Smrg
428f7df2e56Smrg    if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE)
429f7df2e56Smrg        info->flags |= XIScrollFlagNoEmulation;
430f7df2e56Smrg    if (axis->scroll.flags & SCROLL_FLAG_PREFERRED)
431f7df2e56Smrg        info->flags |= XIScrollFlagPreferred;
432f7df2e56Smrg
433f7df2e56Smrg    return info->length * 4;
4346747b715Smrg}
4356747b715Smrg
436f7df2e56Smrgstatic void
437f7df2e56SmrgSwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info)
4386747b715Smrg{
439f7df2e56Smrg    swaps(&info->type);
440f7df2e56Smrg    swaps(&info->length);
441f7df2e56Smrg    swaps(&info->number);
442f7df2e56Smrg    swaps(&info->sourceid);
443f7df2e56Smrg    swaps(&info->scroll_type);
444f7df2e56Smrg    swapl(&info->increment.integral);
445f7df2e56Smrg    swapl(&info->increment.frac);
446f7df2e56Smrg}
447f7df2e56Smrg
448f7df2e56Smrg/**
449f7df2e56Smrg * List multitouch information
450f7df2e56Smrg *
451f7df2e56Smrg * @return The number of bytes written into info.
452f7df2e56Smrg */
453f7df2e56Smrgint
454f7df2e56SmrgListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
455f7df2e56Smrg{
456f7df2e56Smrg    touch->type = XITouchClass;
457f7df2e56Smrg    touch->length = sizeof(xXITouchInfo) >> 2;
458f7df2e56Smrg    touch->sourceid = dev->touch->sourceid;
459f7df2e56Smrg    touch->mode = dev->touch->mode;
460f7df2e56Smrg    touch->num_touches = dev->touch->num_touches;
461f7df2e56Smrg
462f7df2e56Smrg    return touch->length << 2;
463f7df2e56Smrg}
464f7df2e56Smrg
465f7df2e56Smrgstatic void
466f7df2e56SmrgSwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
467f7df2e56Smrg{
468f7df2e56Smrg    swaps(&touch->type);
469f7df2e56Smrg    swaps(&touch->length);
470f7df2e56Smrg    swaps(&touch->sourceid);
471f7df2e56Smrg}
472f7df2e56Smrg
4735a112b11Smrgstatic Bool ShouldListGestureInfo(ClientPtr client)
4745a112b11Smrg{
4755a112b11Smrg    /* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
4765a112b11Smrg     * properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
4775a112b11Smrg     * applications, we instead report Gesture device class only if the client advertised support
4785a112b11Smrg     * for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
4795a112b11Smrg     * and then a completely separate module within the client uses broken libxcb to call
4805a112b11Smrg     * XIQueryDevice.
4815a112b11Smrg     */
4825a112b11Smrg    XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
4835a112b11Smrg    if (pXIClient->major_version) {
4845a112b11Smrg        return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
4855a112b11Smrg    }
4865a112b11Smrg    return FALSE;
4875a112b11Smrg}
4885a112b11Smrg
4895a112b11Smrg/**
4905a112b11Smrg * List gesture information
4915a112b11Smrg *
4925a112b11Smrg * @return The number of bytes written into info.
4935a112b11Smrg */
4945a112b11Smrgstatic int
4955a112b11SmrgListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
4965a112b11Smrg{
4975a112b11Smrg    gesture->type = XIGestureClass;
4985a112b11Smrg    gesture->length = sizeof(xXIGestureInfo) >> 2;
4995a112b11Smrg    gesture->sourceid = dev->gesture->sourceid;
5005a112b11Smrg    gesture->num_touches = dev->gesture->max_touches;
5015a112b11Smrg
5025a112b11Smrg    return gesture->length << 2;
5035a112b11Smrg}
5045a112b11Smrg
5055a112b11Smrgstatic void
5065a112b11SmrgSwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
5075a112b11Smrg{
5085a112b11Smrg    swaps(&gesture->type);
5095a112b11Smrg    swaps(&gesture->length);
5105a112b11Smrg    swaps(&gesture->sourceid);
5115a112b11Smrg}
5125a112b11Smrg
513f7df2e56Smrgint
514f7df2e56SmrgGetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
515f7df2e56Smrg{
516f7df2e56Smrg    DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
5176747b715Smrg    int use;
5186747b715Smrg
519f7df2e56Smrg    if (IsMaster(dev)) {
5206747b715Smrg        DeviceIntPtr paired = GetPairedDevice(dev);
521f7df2e56Smrg
5226747b715Smrg        use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard;
5236747b715Smrg        *attachment = (paired ? paired->id : 0);
524f7df2e56Smrg    }
525f7df2e56Smrg    else if (!IsFloating(dev)) {
5266747b715Smrg        use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard;
5276747b715Smrg        *attachment = master->id;
528f7df2e56Smrg    }
529f7df2e56Smrg    else
5306747b715Smrg        use = XIFloatingSlave;
5316747b715Smrg
5326747b715Smrg    return use;
5336747b715Smrg}
5346747b715Smrg
5356747b715Smrg/**
5366747b715Smrg * Write the info for device dev into the buffer pointed to by info.
5376747b715Smrg *
5386747b715Smrg * @return The number of bytes used.
5396747b715Smrg */
5406747b715Smrgstatic int
541f7df2e56SmrgListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info)
5426747b715Smrg{
543f7df2e56Smrg    char *any = (char *) &info[1];
5446747b715Smrg    int len = 0, total_len = 0;
5456747b715Smrg
5466747b715Smrg    info->deviceid = dev->id;
5476747b715Smrg    info->use = GetDeviceUse(dev, &info->attachment);
5486747b715Smrg    info->num_classes = 0;
5496747b715Smrg    info->name_len = strlen(dev->name);
5506747b715Smrg    info->enabled = dev->enabled;
5516747b715Smrg    total_len = sizeof(xXIDeviceInfo);
5526747b715Smrg
5536747b715Smrg    len = pad_to_int32(info->name_len);
5546747b715Smrg    memset(any, 0, len);
5556747b715Smrg    strncpy(any, dev->name, info->name_len);
5566747b715Smrg    any += len;
5576747b715Smrg    total_len += len;
5586747b715Smrg
5596747b715Smrg    total_len += ListDeviceClasses(client, dev, any, &info->num_classes);
5606747b715Smrg    return total_len;
5616747b715Smrg}
5626747b715Smrg
5636747b715Smrg/**
5646747b715Smrg * Write the class info of the device into the memory pointed to by any, set
5656747b715Smrg * nclasses to the number of classes in total and return the number of bytes
5666747b715Smrg * written.
5676747b715Smrg */
5686747b715Smrgint
5696747b715SmrgListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
570f7df2e56Smrg                  char *any, uint16_t * nclasses)
5716747b715Smrg{
5726747b715Smrg    int total_len = 0;
5736747b715Smrg    int len;
5746747b715Smrg    int i;
5756747b715Smrg    int rc;
5766747b715Smrg
5776747b715Smrg    /* Check if the current device state should be suppressed */
5786747b715Smrg    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
5796747b715Smrg
580f7df2e56Smrg    if (dev->button) {
5816747b715Smrg        (*nclasses)++;
582f7df2e56Smrg        len = ListButtonInfo(dev, (xXIButtonInfo *) any, rc == Success);
5836747b715Smrg        any += len;
5846747b715Smrg        total_len += len;
5856747b715Smrg    }
5866747b715Smrg
587f7df2e56Smrg    if (dev->key) {
5886747b715Smrg        (*nclasses)++;
589f7df2e56Smrg        len = ListKeyInfo(dev, (xXIKeyInfo *) any);
5906747b715Smrg        any += len;
5916747b715Smrg        total_len += len;
5926747b715Smrg    }
5936747b715Smrg
594f7df2e56Smrg    for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
5956747b715Smrg        (*nclasses)++;
596f7df2e56Smrg        len = ListValuatorInfo(dev, (xXIValuatorInfo *) any, i, rc == Success);
597f7df2e56Smrg        any += len;
598f7df2e56Smrg        total_len += len;
599f7df2e56Smrg    }
600f7df2e56Smrg
601f7df2e56Smrg    for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) {
602f7df2e56Smrg        len = ListScrollInfo(dev, (xXIScrollInfo *) any, i);
603f7df2e56Smrg        if (len)
604f7df2e56Smrg            (*nclasses)++;
605f7df2e56Smrg        any += len;
606f7df2e56Smrg        total_len += len;
607f7df2e56Smrg    }
608f7df2e56Smrg
609f7df2e56Smrg    if (dev->touch) {
610f7df2e56Smrg        (*nclasses)++;
611f7df2e56Smrg        len = ListTouchInfo(dev, (xXITouchInfo *) any);
6126747b715Smrg        any += len;
6136747b715Smrg        total_len += len;
6146747b715Smrg    }
6156747b715Smrg
6165a112b11Smrg    if (dev->gesture && ShouldListGestureInfo(client)) {
6175a112b11Smrg        (*nclasses)++;
6185a112b11Smrg        len = ListGestureInfo(dev, (xXIGestureInfo *) any);
6195a112b11Smrg        any += len;
6205a112b11Smrg        total_len += len;
6215a112b11Smrg    }
6225a112b11Smrg
6236747b715Smrg    return total_len;
6246747b715Smrg}
6256747b715Smrg
6266747b715Smrgstatic void
627f7df2e56SmrgSwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
6286747b715Smrg{
629f7df2e56Smrg    char *any = (char *) &info[1];
6306747b715Smrg    int i;
6316747b715Smrg
6326747b715Smrg    /* Skip over name */
6336747b715Smrg    any += pad_to_int32(info->name_len);
6346747b715Smrg
635f7df2e56Smrg    for (i = 0; i < info->num_classes; i++) {
636f7df2e56Smrg        int len = ((xXIAnyInfo *) any)->length;
637f7df2e56Smrg
638f7df2e56Smrg        switch (((xXIAnyInfo *) any)->type) {
639f7df2e56Smrg        case XIButtonClass:
640f7df2e56Smrg            SwapButtonInfo(dev, (xXIButtonInfo *) any);
641f7df2e56Smrg            break;
642f7df2e56Smrg        case XIKeyClass:
643f7df2e56Smrg            SwapKeyInfo(dev, (xXIKeyInfo *) any);
644f7df2e56Smrg            break;
645f7df2e56Smrg        case XIValuatorClass:
646f7df2e56Smrg            SwapValuatorInfo(dev, (xXIValuatorInfo *) any);
647f7df2e56Smrg            break;
648f7df2e56Smrg        case XIScrollClass:
649f7df2e56Smrg            SwapScrollInfo(dev, (xXIScrollInfo *) any);
650f7df2e56Smrg            break;
651f7df2e56Smrg        case XITouchClass:
652f7df2e56Smrg            SwapTouchInfo(dev, (xXITouchInfo *) any);
653f7df2e56Smrg            break;
6545a112b11Smrg        case XIGestureClass:
6555a112b11Smrg            SwapGestureInfo(dev, (xXIGestureInfo *) any);
6565a112b11Smrg            break;
6576747b715Smrg        }
6586747b715Smrg
6596747b715Smrg        any += len * 4;
6606747b715Smrg    }
6616747b715Smrg
662f7df2e56Smrg    swaps(&info->deviceid);
663f7df2e56Smrg    swaps(&info->use);
664f7df2e56Smrg    swaps(&info->attachment);
665f7df2e56Smrg    swaps(&info->num_classes);
666f7df2e56Smrg    swaps(&info->name_len);
6676747b715Smrg
6686747b715Smrg}
669