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