property.c revision 5b944e2a
1/*
2 * Copyright 2007 Peter Hutterer
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Except as contained in this notice, the name of the author shall
22 * not be used in advertising or otherwise to promote the sale, use or
23 * other dealings in this Software without prior written authorization
24 * from the author.
25 *
26 */
27
28#include <ctype.h>
29#include <string.h>
30#include <stdlib.h>
31#include <stdint.h>
32#include <X11/Xatom.h>
33#include <X11/extensions/XIproto.h>
34
35#include "xinput.h"
36
37static void
38print_property(Display *dpy, XDevice* dev, Atom property)
39{
40    Atom                act_type;
41    char                *name;
42    int                 act_format;
43    unsigned long       nitems, bytes_after;
44    unsigned char       *data, *ptr;
45    int                 j;
46
47    name = XGetAtomName(dpy, property);
48    printf("\t%s (%ld):\t", name, property);
49
50    if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
51                           AnyPropertyType, &act_type, &act_format,
52                           &nitems, &bytes_after, &data) == Success)
53    {
54        int float_atom = XInternAtom(dpy, "FLOAT", False);
55
56        ptr = data;
57        printf("\t");
58
59        for (j = 0; j < nitems; j++)
60        {
61            switch(act_type)
62            {
63                case XA_INTEGER:
64                    switch(act_format)
65                    {
66                        case 8:
67                            printf("%d", *((int8_t*)ptr));
68                            break;
69                        case 16:
70                            printf("%d", *((int16_t*)ptr));
71                            break;
72                        case 32:
73                            printf("%d", *((int32_t*)ptr));
74                            break;
75                    }
76                    break;
77                case XA_STRING:
78                    printf("\t%s", ptr);
79                    break;
80                case XA_ATOM:
81                    printf("\t%s", XGetAtomName(dpy, *(Atom*)ptr));
82                    break;
83                default:
84                    if (float_atom != None && act_type == float_atom)
85                    {
86                        printf("\t%f\n", *((float*)ptr));
87                        break;
88                    }
89
90                    printf("\t\t... of unknown type %s\n",
91                            XGetAtomName(dpy, act_type));
92                    break;
93            }
94
95            ptr += act_format/8;
96
97            if (j < nitems - 1)
98                printf(", ");
99            if (act_type == XA_STRING)
100                break;
101        }
102        printf("\n");
103        XFree(data);
104    } else
105        printf("\tFetch failure\n");
106
107}
108
109int list_props(Display *dpy, int argc, char** argv, char* name, char *desc)
110{
111    XDeviceInfo *info;
112    XDevice     *dev;
113    int          i;
114    int         nprops;
115    Atom        *props;
116
117    if (argc == 0)
118    {
119        fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
120        return EXIT_FAILURE;
121    }
122
123    for (i = 0; i < argc; i++)
124    {
125        info = find_device_info(dpy, argv[i], False);
126        if (!info)
127        {
128            fprintf(stderr, "unable to find device %s\n", argv[i]);
129            continue;
130        }
131
132        dev = XOpenDevice(dpy, info->id);
133        if (!dev)
134        {
135            fprintf(stderr, "unable to open device '%s'\n", info->name);
136            continue;
137        }
138
139        props = XListDeviceProperties(dpy, dev, &nprops);
140        if (!nprops)
141        {
142            printf("Device '%s' does not report any properties.\n", info->name);
143            continue;
144        }
145
146        printf("Device '%s':\n", info->name);
147        while(nprops--)
148        {
149            print_property(dpy, dev, props[nprops]);
150        }
151
152        XFree(props);
153        XCloseDevice(dpy, dev);
154    }
155    return EXIT_SUCCESS;
156}
157
158int
159set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
160{
161    XDeviceInfo *info;
162    XDevice     *dev;
163    Atom         prop;
164    char        *name;
165    int          i;
166    Bool         is_atom = True;
167    char        *data;
168    int          format, nelements =  0;
169
170    if (argc < 3)
171    {
172        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
173        return EXIT_FAILURE;
174    }
175
176    info = find_device_info(dpy, argv[0], False);
177    if (!info)
178    {
179        fprintf(stderr, "unable to find device %s\n", argv[0]);
180        return EXIT_FAILURE;
181    }
182
183    dev = XOpenDevice(dpy, info->id);
184    if (!dev)
185    {
186        fprintf(stderr, "unable to open device %s\n", argv[0]);
187        return EXIT_FAILURE;
188    }
189
190    name = argv[1];
191
192    for(i = 0; i < strlen(name); i++) {
193	if (!isdigit(name[i])) {
194            is_atom = False;
195	    break;
196	}
197    }
198
199    if (!is_atom)
200        prop = XInternAtom(dpy, name, False);
201    else
202        prop = atoi(name);
203
204    nelements = argc - 3;
205    format    = atoi(argv[2]);
206    if (format != 8 && format != 16 && format != 32)
207    {
208        fprintf(stderr, "Invalid format %d\n", format);
209        return EXIT_FAILURE;
210    }
211
212    data = calloc(nelements, format/8);
213    for (i = 0; i < nelements; i++)
214    {
215        switch(format)
216        {
217            case 8:
218                *(((int8_t*)data) + i) = atoi(argv[3 + i]);
219                break;
220            case 16:
221                *(((int16_t*)data) + i) = atoi(argv[3 + i]);
222                break;
223            case 32:
224                *(((int32_t*)data) + i) = atoi(argv[3 + i]);
225                break;
226        }
227    }
228
229    XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, format, PropModeReplace,
230                          (unsigned char*)data, nelements);
231
232    free(data);
233    XCloseDevice(dpy, dev);
234    return EXIT_SUCCESS;
235}
236
237int
238set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
239{
240    XDeviceInfo *info;
241    XDevice     *dev;
242    Atom         prop, float_atom;
243    char        *name;
244    int          i;
245    Bool         is_atom = True;
246    float       *data;
247    int          nelements =  0;
248    char*        endptr;
249
250    if (argc < 2)
251    {
252        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
253        return EXIT_FAILURE;
254    }
255
256    info = find_device_info(dpy, argv[0], False);
257    if (!info)
258    {
259        fprintf(stderr, "unable to find device %s\n", argv[0]);
260        return EXIT_FAILURE;
261    }
262
263    dev = XOpenDevice(dpy, info->id);
264    if (!dev)
265    {
266        fprintf(stderr, "unable to open device %s\n", argv[0]);
267        return EXIT_FAILURE;
268    }
269
270    name = argv[1];
271
272    for(i = 0; i < strlen(name); i++) {
273	if (!isdigit(name[i])) {
274            is_atom = False;
275	    break;
276	}
277    }
278
279    if (!is_atom)
280        prop = XInternAtom(dpy, name, False);
281    else
282        prop = atoi(name);
283
284    nelements = argc - 2;
285
286    float_atom = XInternAtom(dpy, "FLOAT", False);
287
288    if (float_atom == (Atom)0)
289    {
290	fprintf(stderr, "no FLOAT atom present in server\n");
291	return EXIT_FAILURE;
292    }
293
294    if (sizeof(float) != 4)
295    {
296	fprintf(stderr, "sane FP required\n");
297	return EXIT_FAILURE;
298    }
299
300    data = calloc(nelements, 4);
301    for (i = 0; i < nelements; i++)
302    {
303        *(data + i) = strtod(argv[2 + i], &endptr);
304	if(endptr == argv[2 + i]){
305	    fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
306	    return EXIT_FAILURE;
307	}
308    }
309
310    XChangeDeviceProperty(dpy, dev, prop, float_atom, 32, PropModeReplace,
311                          (unsigned char*)data, nelements);
312
313    free(data);
314    XCloseDevice(dpy, dev);
315    return EXIT_SUCCESS;
316}
317
318
319int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
320{
321    XDevice     *dev;
322    XDeviceInfo *info;
323    XEvent      ev;
324    XDevicePropertyNotifyEvent *dpev;
325    char        *name;
326    int         type_prop;
327    XEventClass cls_prop;
328
329    if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
330        return EXIT_FAILURE;
331
332    info = find_device_info(dpy, argv[0], False);
333    if (!info)
334    {
335        fprintf(stderr, "unable to find device %s\n", argv[0]);
336        return EXIT_FAILURE;
337    }
338
339    dev = XOpenDevice(dpy, info->id);
340    if (!dev)
341    {
342        fprintf(stderr, "unable to open device '%s'\n", info->name);
343        return EXIT_FAILURE;
344    }
345
346    DevicePropertyNotify(dev, type_prop, cls_prop);
347    XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
348
349    while(1)
350    {
351        XNextEvent(dpy, &ev);
352
353        dpev = (XDevicePropertyNotifyEvent*)&ev;
354        if (dpev->type != type_prop)
355            continue;
356
357        name = XGetAtomName(dpy, dpev->atom);
358        printf("Property '%s' changed.\n", name);
359        print_property(dpy, dev, dpev->atom);
360    }
361
362    XCloseDevice(dpy, dev);
363}
364
365int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
366{
367    XDevice     *dev;
368    XDeviceInfo *info;
369    char        *name;
370    int         i;
371    Bool        is_atom = True;
372    Atom        prop;
373
374    info = find_device_info(dpy, argv[0], False);
375    if (!info)
376    {
377        fprintf(stderr, "unable to find device %s\n", argv[0]);
378        return EXIT_FAILURE;
379    }
380
381    dev = XOpenDevice(dpy, info->id);
382    if (!dev)
383    {
384        fprintf(stderr, "unable to open device '%s'\n", info->name);
385        return EXIT_FAILURE;
386    }
387
388    name = argv[1];
389
390    for(i = 0; i < strlen(name); i++) {
391	if (!isdigit(name[i])) {
392            is_atom = False;
393	    break;
394	}
395    }
396
397    if (!is_atom)
398        prop = XInternAtom(dpy, name, False);
399    else
400        prop = atoi(name);
401
402    XDeleteDeviceProperty(dpy, dev, prop);
403
404    XCloseDevice(dpy, dev);
405    return EXIT_SUCCESS;
406}
407
408int
409set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
410{
411    XDeviceInfo *info;
412    XDevice     *dev;
413    Atom         prop;
414    char        *name;
415    int          i, j;
416    Bool         is_atom = True;
417    Atom        *data;
418    int          nelements =  0;
419
420    if (argc < 3)
421    {
422        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
423        return EXIT_FAILURE;
424    }
425
426    info = find_device_info(dpy, argv[0], False);
427    if (!info)
428    {
429        fprintf(stderr, "unable to find device %s\n", argv[0]);
430        return EXIT_FAILURE;
431    }
432
433    dev = XOpenDevice(dpy, info->id);
434    if (!dev)
435    {
436        fprintf(stderr, "unable to open device %s\n", argv[0]);
437        return EXIT_FAILURE;
438    }
439
440    name = argv[1];
441
442    for(i = 0; i < strlen(name); i++) {
443	if (!isdigit(name[i])) {
444            is_atom = False;
445	    break;
446	}
447    }
448
449    if (!is_atom)
450        prop = XInternAtom(dpy, name, False);
451    else
452        prop = atoi(name);
453
454    nelements = argc - 2;
455    data = calloc(nelements, sizeof(Atom));
456    for (i = 0; i < nelements; i++)
457    {
458        is_atom = True;
459        name = argv[2 + i];
460        for(j = 0; j < strlen(name); j++) {
461            if (!isdigit(name[j])) {
462                is_atom = False;
463                break;
464            }
465        }
466
467        if (!is_atom)
468            data[i] = XInternAtom(dpy, name, False);
469        else
470        {
471            data[i] = atoi(name);
472            XFree(XGetAtomName(dpy, data[i]));
473        }
474    }
475
476    XChangeDeviceProperty(dpy, dev, prop, XA_ATOM, 32, PropModeReplace,
477                          (unsigned char*)data, nelements);
478
479    free(data);
480    XCloseDevice(dpy, dev);
481    return EXIT_SUCCESS;
482}
483
484
485