xiquerydevice.c revision 7e31ba66
1/*
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Peter Hutterer
24 *
25 */
26
27/**
28 * @file Protocol handling for the XIQueryDevice request/reply.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include "inputstr.h"
36#include <X11/X.h>
37#include <X11/Xatom.h>
38#include <X11/extensions/XI2proto.h>
39#include "xkbstr.h"
40#include "xkbsrv.h"
41#include "xserver-properties.h"
42#include "exevents.h"
43#include "xace.h"
44#include "inpututils.h"
45
46#include "xiquerydevice.h"
47
48static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
49static int
50 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info);
51static int SizeDeviceInfo(DeviceIntPtr dev);
52static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info);
53int _X_COLD
54SProcXIQueryDevice(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
65int
66ProcXIQueryDevice(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
158void
159SRepXIQueryDevice(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 */
173static Bool
174ShouldSkipDevice(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 */
190static int
191SizeDeviceInfo(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 */
205int
206SizeDeviceClasses(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 */
243static void
244ButtonInfoData(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 */
256int
257ListButtonInfo(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
286static void
287SwapButtonInfo(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 */
310int
311ListKeyInfo(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
329static void
330SwapKeyInfo(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 */
351int
352ListValuatorInfo(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
376static void
377SwapValuatorInfo(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
393int
394ListScrollInfo(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
430static void
431SwapScrollInfo(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 */
447int
448ListTouchInfo(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
459static void
460SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
461{
462    swaps(&touch->type);
463    swaps(&touch->length);
464    swaps(&touch->sourceid);
465}
466
467int
468GetDeviceUse(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 */
494static int
495ListDeviceInfo(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 */
522int
523ListDeviceClasses(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
573static void
574SwapDeviceInfo(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