xiquerydevice.c revision 9ace9065
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
45#include "xiquerydevice.h"
46
47static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
48static int
49ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info);
50static int SizeDeviceInfo(DeviceIntPtr dev);
51static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info);
52int
53SProcXIQueryDevice(ClientPtr client)
54{
55    char n;
56
57    REQUEST(xXIQueryDeviceReq);
58
59    swaps(&stuff->length, n);
60    swaps(&stuff->deviceid, n);
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 && stuff->deviceid != XIAllMasterDevices)
79    {
80        rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
81        if (rc != Success)
82        {
83            client->errorValue = stuff->deviceid;
84            return rc;
85        }
86        len += SizeDeviceInfo(dev);
87    }
88    else
89    {
90        skip = calloc(sizeof(Bool), inputInfo.numDevices);
91        if (!skip)
92            return BadAlloc;
93
94        for (dev = inputInfo.devices; dev; dev = dev->next, i++)
95        {
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        {
103            skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev);
104            if (!skip[i])
105                len += SizeDeviceInfo(dev);
106        }
107    }
108
109    info = calloc(1, len);
110    if (!info) {
111        free(skip);
112        return BadAlloc;
113    }
114
115    memset(&rep, 0, sizeof(xXIQueryDeviceReply));
116    rep.repType = X_Reply;
117    rep.RepType = X_XIQueryDevice;
118    rep.sequenceNumber = client->sequence;
119    rep.length = len/4;
120    rep.num_devices = 0;
121
122    ptr = info;
123    if (dev)
124    {
125        len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
126        if (client->swapped)
127            SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
128        info += len;
129        rep.num_devices = 1;
130    } else
131    {
132        i = 0;
133        for (dev = inputInfo.devices; dev; dev = dev->next, i++)
134        {
135            if (!skip[i])
136            {
137                len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
138                if (client->swapped)
139                    SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
140                info += len;
141                rep.num_devices++;
142            }
143        }
144
145        for (dev = inputInfo.off_devices; dev; dev = dev->next, i++)
146        {
147            if (!skip[i])
148            {
149                len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info);
150                if (client->swapped)
151                    SwapDeviceInfo(dev, (xXIDeviceInfo*)info);
152                info += len;
153                rep.num_devices++;
154            }
155        }
156    }
157
158    len = rep.length * 4;
159    WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep);
160    WriteToClient(client, len, ptr);
161    free(ptr);
162    free(skip);
163    return rc;
164}
165
166void
167SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep)
168{
169    char n;
170
171    swaps(&rep->sequenceNumber, n);
172    swapl(&rep->length, n);
173    swaps(&rep->num_devices, n);
174
175    /* Device info is already swapped, see ProcXIQueryDevice */
176
177    WriteToClient(client, size, (char *)rep);
178}
179
180
181/**
182 * @return Whether the device should be included in the returned list.
183 */
184static Bool
185ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev)
186{
187    /* if all devices are not being queried, only master devices are */
188    if (deviceid == XIAllDevices || IsMaster(dev))
189    {
190        int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess);
191        if (rc == Success)
192            return FALSE;
193    }
194    return TRUE;
195}
196
197/**
198 * @return The number of bytes needed to store this device's xXIDeviceInfo
199 * (and its classes).
200 */
201static int
202SizeDeviceInfo(DeviceIntPtr dev)
203{
204    int len = sizeof(xXIDeviceInfo);
205
206    /* 4-padded name */
207    len += pad_to_int32(strlen(dev->name));
208
209    return len + SizeDeviceClasses(dev);
210
211}
212
213/*
214 * @return The number of bytes needed to store this device's classes.
215 */
216int
217SizeDeviceClasses(DeviceIntPtr dev)
218{
219    int len = 0;
220
221    if (dev->button)
222    {
223        len += sizeof(xXIButtonInfo);
224        len += dev->button->numButtons * sizeof(Atom);
225        len += pad_to_int32(bits_to_bytes(dev->button->numButtons));
226    }
227
228    if (dev->key)
229    {
230        XkbDescPtr xkb = dev->key->xkbInfo->desc;
231        len += sizeof(xXIKeyInfo);
232        len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t);
233    }
234
235    if (dev->valuator)
236        len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes;
237
238    return len;
239}
240
241
242/**
243 * Write button information into info.
244 * @return Number of bytes written into info.
245 */
246int
247ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState)
248{
249    unsigned char *bits;
250    int mask_len;
251    int i;
252
253    if (!dev || !dev->button)
254	return 0;
255
256    mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons));
257
258    info->type = ButtonClass;
259    info->num_buttons = dev->button->numButtons;
260    info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
261                   info->num_buttons + mask_len;
262    info->sourceid = dev->button->sourceid;
263
264    bits = (unsigned char*)&info[1];
265    memset(bits, 0, mask_len * 4);
266
267    if (reportState)
268	for (i = 0; i < dev->button->numButtons; i++)
269	    if (BitIsOn(dev->button->down, i))
270		SetBit(bits, i);
271
272    bits += mask_len * 4;
273    memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom));
274
275    return info->length * 4;
276}
277
278static void
279SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info)
280{
281    char n;
282    Atom *btn;
283    int i;
284    swaps(&info->type, n);
285    swaps(&info->length, n);
286    swaps(&info->sourceid, n);
287
288    for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++)
289        swaps(btn, n);
290
291    swaps(&info->num_buttons, n);
292}
293
294/**
295 * Write key information into info.
296 * @return Number of bytes written into info.
297 */
298int
299ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info)
300{
301    int i;
302    XkbDescPtr xkb = dev->key->xkbInfo->desc;
303    uint32_t *kc;
304
305    info->type = KeyClass;
306    info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1;
307    info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
308    info->sourceid = dev->key->sourceid;
309
310    kc = (uint32_t*)&info[1];
311    for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++)
312        *kc = i;
313
314    return info->length * 4;
315}
316
317static void
318SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info)
319{
320    char n;
321    uint32_t *key;
322    int i;
323    swaps(&info->type, n);
324    swaps(&info->length, n);
325    swaps(&info->sourceid, n);
326
327    for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++)
328        swapl(key, n);
329
330    swaps(&info->num_keycodes, n);
331}
332
333/**
334 * List axis information for the given axis.
335 *
336 * @return The number of bytes written into info.
337 */
338int
339ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber,
340		 Bool reportState)
341{
342    ValuatorClassPtr v = dev->valuator;
343
344    info->type = ValuatorClass;
345    info->length = sizeof(xXIValuatorInfo)/4;
346    info->label = v->axes[axisnumber].label;
347    info->min.integral = v->axes[axisnumber].min_value;
348    info->min.frac = 0;
349    info->max.integral = v->axes[axisnumber].max_value;
350    info->max.frac = 0;
351    info->value.integral = (int)v->axisVal[axisnumber];
352    info->value.frac = (int)(v->axisVal[axisnumber] * (1 << 16) * (1 << 16));
353    info->resolution = v->axes[axisnumber].resolution;
354    info->number = axisnumber;
355    info->mode = valuator_get_mode(dev, axisnumber);
356    info->sourceid = v->sourceid;
357
358    if (!reportState)
359	info->value = info->min;
360
361    return info->length * 4;
362}
363
364static void
365SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info)
366{
367    char n;
368    swaps(&info->type, n);
369    swaps(&info->length, n);
370    swapl(&info->label, n);
371    swapl(&info->min.integral, n);
372    swapl(&info->min.frac, n);
373    swapl(&info->max.integral, n);
374    swapl(&info->max.frac, n);
375    swaps(&info->number, n);
376    swaps(&info->sourceid, n);
377}
378
379int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
380{
381    DeviceIntPtr master = dev->u.master;
382    int use;
383
384    if (IsMaster(dev))
385    {
386        DeviceIntPtr paired = GetPairedDevice(dev);
387        use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard;
388        *attachment = (paired ? paired->id : 0);
389    } else if (master)
390    {
391        use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard;
392        *attachment = master->id;
393    } else
394        use = XIFloatingSlave;
395
396    return use;
397}
398
399/**
400 * Write the info for device dev into the buffer pointed to by info.
401 *
402 * @return The number of bytes used.
403 */
404static int
405ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info)
406{
407    char *any = (char*)&info[1];
408    int len = 0, total_len = 0;
409
410    info->deviceid = dev->id;
411    info->use = GetDeviceUse(dev, &info->attachment);
412    info->num_classes = 0;
413    info->name_len = strlen(dev->name);
414    info->enabled = dev->enabled;
415    total_len = sizeof(xXIDeviceInfo);
416
417    len = pad_to_int32(info->name_len);
418    memset(any, 0, len);
419    strncpy(any, dev->name, info->name_len);
420    any += len;
421    total_len += len;
422
423    total_len += ListDeviceClasses(client, dev, any, &info->num_classes);
424    return total_len;
425}
426
427/**
428 * Write the class info of the device into the memory pointed to by any, set
429 * nclasses to the number of classes in total and return the number of bytes
430 * written.
431 */
432int
433ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
434		  char *any, uint16_t *nclasses)
435{
436    int total_len = 0;
437    int len;
438    int i;
439    int rc;
440
441    /* Check if the current device state should be suppressed */
442    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
443
444    if (dev->button)
445    {
446        (*nclasses)++;
447        len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success);
448        any += len;
449        total_len += len;
450    }
451
452    if (dev->key)
453    {
454        (*nclasses)++;
455        len = ListKeyInfo(dev, (xXIKeyInfo*)any);
456        any += len;
457        total_len += len;
458    }
459
460    for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++)
461    {
462        (*nclasses)++;
463        len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success);
464        any += len;
465        total_len += len;
466    }
467
468    return total_len;
469}
470
471static void
472SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
473{
474    char n;
475    char *any = (char*)&info[1];
476    int i;
477
478    /* Skip over name */
479    any += pad_to_int32(info->name_len);
480
481    for (i = 0; i < info->num_classes; i++)
482    {
483        int len = ((xXIAnyInfo*)any)->length;
484        switch(((xXIAnyInfo*)any)->type)
485        {
486            case XIButtonClass:
487                SwapButtonInfo(dev, (xXIButtonInfo*)any);
488                break;
489            case XIKeyClass:
490                SwapKeyInfo(dev, (xXIKeyInfo*)any);
491                break;
492            case XIValuatorClass:
493                SwapValuatorInfo(dev, (xXIValuatorInfo*)any);
494                break;
495        }
496
497        any += len * 4;
498    }
499
500    swaps(&info->deviceid, n);
501    swaps(&info->use, n);
502    swaps(&info->attachment, n);
503    swaps(&info->num_classes, n);
504    swaps(&info->name_len, n);
505
506}
507