1b85037dbSmrg/*
2b85037dbSmrg * Copyright © 2002-2005,2007 Peter Osterlund
3b85037dbSmrg *
4b85037dbSmrg * Permission to use, copy, modify, distribute, and sell this software
5b85037dbSmrg * and its documentation for any purpose is hereby granted without
6b85037dbSmrg * fee, provided that the above copyright notice appear in all copies
7b85037dbSmrg * and that both that copyright notice and this permission notice
8b85037dbSmrg * appear in supporting documentation, and that the name of Red Hat
9b85037dbSmrg * not be used in advertising or publicity pertaining to distribution
10b85037dbSmrg * of the software without specific, written prior permission.  Red
11b85037dbSmrg * Hat makes no representations about the suitability of this software
12b85037dbSmrg * for any purpose.  It is provided "as is" without express or implied
13b85037dbSmrg * warranty.
14b85037dbSmrg *
15b85037dbSmrg * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16b85037dbSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17b85037dbSmrg * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18b85037dbSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19b85037dbSmrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20b85037dbSmrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21b85037dbSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22b85037dbSmrg *
23b85037dbSmrg * Authors:
24b85037dbSmrg *      Peter Osterlund (petero2@telia.com)
25b85037dbSmrg */
26b85037dbSmrg
27b85037dbSmrg#ifdef HAVE_CONFIG_H
28b85037dbSmrg#include "config.h"
29b85037dbSmrg#endif
30b85037dbSmrg
31b85037dbSmrg#include <stdio.h>
32b85037dbSmrg#include <stdlib.h>
33b85037dbSmrg#include <sys/types.h>
34b85037dbSmrg#include <sys/ipc.h>
35b85037dbSmrg#include <sys/time.h>
36b85037dbSmrg#include <unistd.h>
37b85037dbSmrg#include <string.h>
38b85037dbSmrg#include <stddef.h>
39b85037dbSmrg#include <math.h>
4028515619Smrg#include <limits.h>
41b85037dbSmrg
42b85037dbSmrg#include <X11/Xdefs.h>
43b85037dbSmrg#include <X11/Xatom.h>
44b85037dbSmrg#include <X11/extensions/XI.h>
45b85037dbSmrg#include <X11/extensions/XInput.h>
46b85037dbSmrg#include "synaptics-properties.h"
47b85037dbSmrg
48b85037dbSmrg#ifndef XATOM_FLOAT
49b85037dbSmrg#define XATOM_FLOAT "FLOAT"
50b85037dbSmrg#endif
51b85037dbSmrg
5228515619Smrg#define SYN_MAX_BUTTONS 12
5328515619Smrg
5428515619Smrgunion flong {                   /* Xlibs 64-bit property handling madness */
55b85037dbSmrg    long l;
56b85037dbSmrg    float f;
57b85037dbSmrg};
58b85037dbSmrg
59b85037dbSmrgenum ParaType {
60b85037dbSmrg    PT_INT,
61b85037dbSmrg    PT_BOOL,
62b85037dbSmrg    PT_DOUBLE
63b85037dbSmrg};
64b85037dbSmrg
65b85037dbSmrgstruct Parameter {
6628515619Smrg    char *name;                 /* Name of parameter */
6728515619Smrg    enum ParaType type;         /* Type of parameter */
6828515619Smrg    double min_val;             /* Minimum allowed value */
6928515619Smrg    double max_val;             /* Maximum allowed value */
7028515619Smrg    char *prop_name;            /* Property name */
7128515619Smrg    int prop_format;            /* Property format (0 for floats) */
7228515619Smrg    int prop_offset;            /* Offset inside property */
73b85037dbSmrg};
74b85037dbSmrg
75b85037dbSmrgstatic struct Parameter params[] = {
76b85037dbSmrg    {"LeftEdge",              PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	0},
77b85037dbSmrg    {"RightEdge",             PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	1},
78b85037dbSmrg    {"TopEdge",               PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	2},
79b85037dbSmrg    {"BottomEdge",            PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	3},
80b85037dbSmrg    {"FingerLow",             PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,	32,	0},
81b85037dbSmrg    {"FingerHigh",            PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,	32,	1},
82b85037dbSmrg    {"MaxTapTime",            PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_TIME,	32,	0},
83b85037dbSmrg    {"MaxTapMove",            PT_INT,    0, 2000,  SYNAPTICS_PROP_TAP_MOVE,	32,	0},
84b85037dbSmrg    {"MaxDoubleTapTime",      PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_DURATIONS,32,	1},
85b85037dbSmrg    {"SingleTapTimeout",      PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_DURATIONS,32,	0},
86b85037dbSmrg    {"ClickTime",             PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_DURATIONS,32,	2},
87b85037dbSmrg    {"FastTaps",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_TAP_FAST,	8,	0},
88b85037dbSmrg    {"EmulateMidButtonTime",  PT_INT,    0, 1000,  SYNAPTICS_PROP_MIDDLE_TIMEOUT,32,	0},
89b85037dbSmrg    {"EmulateTwoFingerMinZ",  PT_INT,    0, 1000,  SYNAPTICS_PROP_TWOFINGER_PRESSURE,	32,	0},
90b85037dbSmrg    {"EmulateTwoFingerMinW",  PT_INT,    0, 15,    SYNAPTICS_PROP_TWOFINGER_WIDTH,	32,	0},
9128515619Smrg    {"VertScrollDelta",       PT_INT,    -1000, 1000,  SYNAPTICS_PROP_SCROLL_DISTANCE,	32,	0},
9228515619Smrg    {"HorizScrollDelta",      PT_INT,    -1000, 1000,  SYNAPTICS_PROP_SCROLL_DISTANCE,	32,	1},
93b85037dbSmrg    {"VertEdgeScroll",        PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,	8,	0},
94b85037dbSmrg    {"HorizEdgeScroll",       PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,	8,	1},
95b85037dbSmrg    {"CornerCoasting",        PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,	8,	2},
96b85037dbSmrg    {"VertTwoFingerScroll",   PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_TWOFINGER,	8,	0},
97b85037dbSmrg    {"HorizTwoFingerScroll",  PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_TWOFINGER,	8,	1},
98b85037dbSmrg    {"MinSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	0},
99b85037dbSmrg    {"MaxSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	1},
100b85037dbSmrg    {"AccelFactor",           PT_DOUBLE, 0, 1.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	2},
101b85037dbSmrg    {"TouchpadOff",           PT_INT,    0, 2,     SYNAPTICS_PROP_OFF,		8,	0},
102b85037dbSmrg    {"LockedDrags",           PT_BOOL,   0, 1,     SYNAPTICS_PROP_LOCKED_DRAGS,	8,	0},
103b85037dbSmrg    {"LockedDragTimeout",     PT_INT,    0, 30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT,	32,	0},
104b85037dbSmrg    {"RTCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	0},
105b85037dbSmrg    {"RBCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	1},
106b85037dbSmrg    {"LTCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	2},
107b85037dbSmrg    {"LBCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	3},
108b85037dbSmrg    {"TapButton1",            PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	4},
109b85037dbSmrg    {"TapButton2",            PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	5},
110b85037dbSmrg    {"TapButton3",            PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION,	8,	6},
111b85037dbSmrg    {"ClickFinger1",          PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION,	8,	0},
112b85037dbSmrg    {"ClickFinger2",          PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION,	8,	1},
113b85037dbSmrg    {"ClickFinger3",          PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION,	8,	2},
114b85037dbSmrg    {"CircularScrolling",     PT_BOOL,   0, 1,     SYNAPTICS_PROP_CIRCULAR_SCROLLING,	8,	0},
115b85037dbSmrg    {"CircScrollDelta",       PT_DOUBLE, .01, 3,   SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST,	0 /* float */,	0},
116b85037dbSmrg    {"CircScrollTrigger",     PT_INT,    0, 8,     SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER,	8,	0},
117b85037dbSmrg    {"PalmDetect",            PT_BOOL,   0, 1,     SYNAPTICS_PROP_PALM_DETECT,	8,	0},
118b85037dbSmrg    {"PalmMinWidth",          PT_INT,    0, 15,    SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	0},
119b85037dbSmrg    {"PalmMinZ",              PT_INT,    0, 255,   SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	1},
12028515619Smrg    {"CoastingSpeed",         PT_DOUBLE, 0, 255,    SYNAPTICS_PROP_COASTING_SPEED,	0 /* float*/,	0},
121b85037dbSmrg    {"CoastingFriction",      PT_DOUBLE, 0, 255,   SYNAPTICS_PROP_COASTING_SPEED,	0 /* float*/,	1},
122b85037dbSmrg    {"PressureMotionMinZ",    PT_INT,    1, 255,   SYNAPTICS_PROP_PRESSURE_MOTION,	32,	0},
123b85037dbSmrg    {"PressureMotionMaxZ",    PT_INT,    1, 255,   SYNAPTICS_PROP_PRESSURE_MOTION,	32,	1},
124b85037dbSmrg    {"PressureMotionMinFactor", PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR,	0 /*float*/,	0},
125b85037dbSmrg    {"PressureMotionMaxFactor", PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR,	0 /*float*/,	1},
126b85037dbSmrg    {"GrabEventDevice",       PT_BOOL,   0, 1,     SYNAPTICS_PROP_GRAB,	8,	0},
127b85037dbSmrg    {"TapAndDragGesture",     PT_BOOL,   0, 1,     SYNAPTICS_PROP_GESTURES,	8,	0},
128b85037dbSmrg    {"AreaLeftEdge",          PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	0},
129b85037dbSmrg    {"AreaRightEdge",         PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	1},
130b85037dbSmrg    {"AreaTopEdge",           PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	2},
131b85037dbSmrg    {"AreaBottomEdge",        PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	3},
13228515619Smrg    {"HorizHysteresis",       PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	0},
13328515619Smrg    {"VertHysteresis",        PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	1},
13428515619Smrg    {"ClickPad",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_CLICKPAD,	8,	0},
13528515619Smrg    {"RightButtonAreaLeft",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	0},
13628515619Smrg    {"RightButtonAreaRight",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	1},
13728515619Smrg    {"RightButtonAreaTop",    PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	2},
13828515619Smrg    {"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	3},
13928515619Smrg    {"MiddleButtonAreaLeft",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	4},
14028515619Smrg    {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	5},
14128515619Smrg    {"MiddleButtonAreaTop",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	6},
14228515619Smrg    {"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	7},
143b85037dbSmrg    { NULL, 0, 0, 0, 0 }
144b85037dbSmrg};
145b85037dbSmrg
146b85037dbSmrgstatic double
14728515619Smrgparse_cmd(char *cmd, struct Parameter **par)
148b85037dbSmrg{
149302b15bdSmrg    char *eqp = strchr(cmd, '=');
15028515619Smrg
151b85037dbSmrg    *par = NULL;
152b85037dbSmrg
153b85037dbSmrg    if (eqp) {
15428515619Smrg        int j;
15528515619Smrg        int found = 0;
15628515619Smrg
15728515619Smrg        *eqp = 0;
15828515619Smrg        for (j = 0; params[j].name; j++) {
15928515619Smrg            if (strcasecmp(cmd, params[j].name) == 0) {
16028515619Smrg                found = 1;
16128515619Smrg                break;
16228515619Smrg            }
16328515619Smrg        }
16428515619Smrg        if (found) {
16528515619Smrg            double val = atof(&eqp[1]);
16628515619Smrg
16728515619Smrg            *par = &params[j];
16828515619Smrg
16928515619Smrg            if (val < (*par)->min_val)
17028515619Smrg                val = (*par)->min_val;
17128515619Smrg            if (val > (*par)->max_val)
17228515619Smrg                val = (*par)->max_val;
17328515619Smrg
17428515619Smrg            return val;
17528515619Smrg        }
17628515619Smrg        else {
17728515619Smrg            printf("Unknown parameter %s\n", cmd);
17828515619Smrg        }
179b85037dbSmrg    }
18028515619Smrg    else {
18128515619Smrg        printf("Invalid command: %s\n", cmd);
182b85037dbSmrg    }
183b85037dbSmrg
18428515619Smrg    return 0;
185b85037dbSmrg}
186b85037dbSmrg
187b85037dbSmrg/** Init display connection or NULL on error */
18828515619Smrgstatic Display *
189b85037dbSmrgdp_init()
190b85037dbSmrg{
19128515619Smrg    Display *dpy = NULL;
19228515619Smrg    XExtensionVersion *v = NULL;
19328515619Smrg    Atom touchpad_type = 0;
19428515619Smrg    Atom synaptics_property = 0;
19528515619Smrg    int error = 0;
196b85037dbSmrg
197b85037dbSmrg    dpy = XOpenDisplay(NULL);
198b85037dbSmrg    if (!dpy) {
19928515619Smrg        fprintf(stderr, "Failed to connect to X Server.\n");
20028515619Smrg        error = 1;
20128515619Smrg        goto unwind;
202b85037dbSmrg    }
203b85037dbSmrg
204b85037dbSmrg    v = XGetExtensionVersion(dpy, INAME);
205b85037dbSmrg    if (!v->present ||
20628515619Smrg        (v->major_version * 1000 + v->minor_version) <
20728515619Smrg        (XI_Add_DeviceProperties_Major * 1000 +
20828515619Smrg         XI_Add_DeviceProperties_Minor)) {
20928515619Smrg        fprintf(stderr, "X server supports X Input %d.%d. I need %d.%d.\n",
21028515619Smrg                v->major_version, v->minor_version,
21128515619Smrg                XI_Add_DeviceProperties_Major, XI_Add_DeviceProperties_Minor);
21228515619Smrg        error = 1;
21328515619Smrg        goto unwind;
214b85037dbSmrg    }
215b85037dbSmrg
216b85037dbSmrg    /* We know synaptics sets XI_TOUCHPAD for all the devices. */
217b85037dbSmrg    touchpad_type = XInternAtom(dpy, XI_TOUCHPAD, True);
218b85037dbSmrg    if (!touchpad_type) {
21928515619Smrg        fprintf(stderr, "XI_TOUCHPAD not initialised.\n");
22028515619Smrg        error = 1;
22128515619Smrg        goto unwind;
222b85037dbSmrg    }
223b85037dbSmrg
224b85037dbSmrg    synaptics_property = XInternAtom(dpy, SYNAPTICS_PROP_EDGES, True);
225b85037dbSmrg    if (!synaptics_property) {
22628515619Smrg        fprintf(stderr, "Couldn't find synaptics properties. No synaptics "
22728515619Smrg                "driver loaded?\n");
22828515619Smrg        error = 1;
22928515619Smrg        goto unwind;
230b85037dbSmrg    }
231b85037dbSmrg
23228515619Smrg unwind:
233b85037dbSmrg    XFree(v);
23428515619Smrg    if (error && dpy) {
23528515619Smrg        XCloseDisplay(dpy);
23628515619Smrg        dpy = NULL;
237b85037dbSmrg    }
238b85037dbSmrg    return dpy;
239b85037dbSmrg}
240b85037dbSmrg
241b85037dbSmrgstatic XDevice *
24228515619Smrgdp_get_device(Display * dpy)
243b85037dbSmrg{
24428515619Smrg    XDevice *dev = NULL;
24528515619Smrg    XDeviceInfo *info = NULL;
24628515619Smrg    int ndevices = 0;
24728515619Smrg    Atom touchpad_type = 0;
24828515619Smrg    Atom synaptics_property = 0;
24928515619Smrg    Atom *properties = NULL;
25028515619Smrg    int nprops = 0;
25128515619Smrg    int error = 0;
252b85037dbSmrg
253b85037dbSmrg    touchpad_type = XInternAtom(dpy, XI_TOUCHPAD, True);
254b85037dbSmrg    synaptics_property = XInternAtom(dpy, SYNAPTICS_PROP_EDGES, True);
255b85037dbSmrg    info = XListInputDevices(dpy, &ndevices);
256b85037dbSmrg
25728515619Smrg    while (ndevices--) {
25828515619Smrg        if (info[ndevices].type == touchpad_type) {
25928515619Smrg            dev = XOpenDevice(dpy, info[ndevices].id);
26028515619Smrg            if (!dev) {
26128515619Smrg                fprintf(stderr, "Failed to open device '%s'.\n",
26228515619Smrg                        info[ndevices].name);
26328515619Smrg                error = 1;
26428515619Smrg                goto unwind;
26528515619Smrg            }
26628515619Smrg
26728515619Smrg            properties = XListDeviceProperties(dpy, dev, &nprops);
26828515619Smrg            if (!properties || !nprops) {
26928515619Smrg                fprintf(stderr, "No properties on device '%s'.\n",
27028515619Smrg                        info[ndevices].name);
27128515619Smrg                error = 1;
27228515619Smrg                goto unwind;
27328515619Smrg            }
27428515619Smrg
27528515619Smrg            while (nprops--) {
27628515619Smrg                if (properties[nprops] == synaptics_property)
27728515619Smrg                    break;
27828515619Smrg            }
27928515619Smrg            if (!nprops) {
28028515619Smrg                fprintf(stderr, "No synaptics properties on device '%s'.\n",
28128515619Smrg                        info[ndevices].name);
28228515619Smrg                error = 1;
28328515619Smrg                goto unwind;
28428515619Smrg            }
28528515619Smrg
28628515619Smrg            break;              /* Yay, device is suitable */
28728515619Smrg        }
288b85037dbSmrg    }
289b85037dbSmrg
29028515619Smrg unwind:
291b85037dbSmrg    XFree(properties);
292b85037dbSmrg    XFreeDeviceList(info);
293b85037dbSmrg    if (!dev)
294b85037dbSmrg        fprintf(stderr, "Unable to find a synaptics device.\n");
29528515619Smrg    else if (error && dev) {
29628515619Smrg        XCloseDevice(dpy, dev);
29728515619Smrg        dev = NULL;
298b85037dbSmrg    }
299b85037dbSmrg    return dev;
300b85037dbSmrg}
301b85037dbSmrg
302b85037dbSmrgstatic void
30328515619Smrgdp_set_variables(Display * dpy, XDevice * dev, int argc, char *argv[],
30428515619Smrg                 int first_cmd)
305b85037dbSmrg{
306b85037dbSmrg    int i;
307b85037dbSmrg    double val;
308b85037dbSmrg    struct Parameter *par;
309b85037dbSmrg    Atom prop, type, float_type;
310b85037dbSmrg    int format;
31128515619Smrg    unsigned char *data;
312b85037dbSmrg    unsigned long nitems, bytes_after;
313b85037dbSmrg
314b85037dbSmrg    union flong *f;
315b85037dbSmrg    long *n;
316b85037dbSmrg    char *b;
317b85037dbSmrg
318b85037dbSmrg    float_type = XInternAtom(dpy, XATOM_FLOAT, True);
319b85037dbSmrg    if (!float_type)
32028515619Smrg        fprintf(stderr, "Float properties not available.\n");
321b85037dbSmrg
322b85037dbSmrg    for (i = first_cmd; i < argc; i++) {
32328515619Smrg        val = parse_cmd(argv[i], &par);
32428515619Smrg        if (!par)
32528515619Smrg            continue;
32628515619Smrg
32728515619Smrg        prop = XInternAtom(dpy, par->prop_name, True);
32828515619Smrg        if (!prop) {
32928515619Smrg            fprintf(stderr, "Property for '%s' not available. Skipping.\n",
33028515619Smrg                    par->name);
33128515619Smrg            continue;
33228515619Smrg
33328515619Smrg        }
33428515619Smrg
33528515619Smrg        XGetDeviceProperty(dpy, dev, prop, 0, 1000, False, AnyPropertyType,
33628515619Smrg                           &type, &format, &nitems, &bytes_after, &data);
33728515619Smrg
33828515619Smrg        if (type == None) {
33928515619Smrg            fprintf(stderr, "Property for '%s' not available. Skipping.\n",
34028515619Smrg                    par->name);
34128515619Smrg            continue;
34228515619Smrg        }
34328515619Smrg
34428515619Smrg        switch (par->prop_format) {
34528515619Smrg        case 8:
34628515619Smrg            if (format != par->prop_format || type != XA_INTEGER) {
34728515619Smrg                fprintf(stderr, "   %-23s = format mismatch (%d)\n",
34828515619Smrg                        par->name, format);
34928515619Smrg                break;
35028515619Smrg            }
35128515619Smrg            b = (char *) data;
35228515619Smrg            b[par->prop_offset] = rint(val);
35328515619Smrg            break;
35428515619Smrg        case 32:
35528515619Smrg            if (format != par->prop_format ||
35628515619Smrg                (type != XA_INTEGER && type != XA_CARDINAL)) {
35728515619Smrg                fprintf(stderr, "   %-23s = format mismatch (%d)\n",
35828515619Smrg                        par->name, format);
35928515619Smrg                break;
36028515619Smrg            }
36128515619Smrg            n = (long *) data;
36228515619Smrg            n[par->prop_offset] = rint(val);
36328515619Smrg            break;
36428515619Smrg        case 0:                /* float */
36528515619Smrg            if (!float_type)
36628515619Smrg                continue;
36728515619Smrg            if (format != 32 || type != float_type) {
36828515619Smrg                fprintf(stderr, "   %-23s = format mismatch (%d)\n",
36928515619Smrg                        par->name, format);
37028515619Smrg                break;
37128515619Smrg            }
37228515619Smrg            f = (union flong *) data;
37328515619Smrg            f[par->prop_offset].f = val;
37428515619Smrg            break;
37528515619Smrg        }
37628515619Smrg
37728515619Smrg        XChangeDeviceProperty(dpy, dev, prop, type, format,
37828515619Smrg                              PropModeReplace, data, nitems);
37928515619Smrg        XFlush(dpy);
380b85037dbSmrg    }
381b85037dbSmrg}
382b85037dbSmrg
383b85037dbSmrg/* FIXME: horribly inefficient. */
384b85037dbSmrgstatic void
38528515619Smrgdp_show_settings(Display * dpy, XDevice * dev)
386b85037dbSmrg{
387b85037dbSmrg    int j;
388b85037dbSmrg    Atom a, type, float_type;
389b85037dbSmrg    int format;
390b85037dbSmrg    unsigned long nitems, bytes_after;
39128515619Smrg    unsigned char *data;
392b85037dbSmrg    int len;
393b85037dbSmrg
394b85037dbSmrg    union flong *f;
395b85037dbSmrg    long *i;
396b85037dbSmrg    char *b;
397b85037dbSmrg
398b85037dbSmrg    float_type = XInternAtom(dpy, XATOM_FLOAT, True);
399b85037dbSmrg    if (!float_type)
40028515619Smrg        fprintf(stderr, "Float properties not available.\n");
401b85037dbSmrg
402b85037dbSmrg    printf("Parameter settings:\n");
403b85037dbSmrg    for (j = 0; params[j].name; j++) {
40428515619Smrg        struct Parameter *par = &params[j];
40528515619Smrg
40628515619Smrg        a = XInternAtom(dpy, par->prop_name, True);
40728515619Smrg        if (!a)
40828515619Smrg            continue;
40928515619Smrg
41028515619Smrg        len =
41128515619Smrg            1 +
41228515619Smrg            ((par->prop_offset * (par->prop_format ? par->prop_format : 32) /
41328515619Smrg              8)) / 4;
41428515619Smrg
41528515619Smrg        XGetDeviceProperty(dpy, dev, a, 0, len, False,
41628515619Smrg                           AnyPropertyType, &type, &format,
41728515619Smrg                           &nitems, &bytes_after, &data);
41828515619Smrg        if (type == None)
41928515619Smrg            continue;
42028515619Smrg
42128515619Smrg        switch (par->prop_format) {
42228515619Smrg        case 8:
42328515619Smrg            if (format != par->prop_format || type != XA_INTEGER) {
42428515619Smrg                fprintf(stderr, "    %-23s = format mismatch (%d)\n",
42528515619Smrg                        par->name, format);
42628515619Smrg                break;
42728515619Smrg            }
42828515619Smrg
42928515619Smrg            b = (char *) data;
43028515619Smrg            printf("    %-23s = %d\n", par->name, b[par->prop_offset]);
43128515619Smrg            break;
43228515619Smrg        case 32:
43328515619Smrg            if (format != par->prop_format ||
43428515619Smrg                (type != XA_INTEGER && type != XA_CARDINAL)) {
43528515619Smrg                fprintf(stderr, "    %-23s = format mismatch (%d)\n",
43628515619Smrg                        par->name, format);
43728515619Smrg                break;
43828515619Smrg            }
43928515619Smrg
44028515619Smrg            i = (long *) data;
44128515619Smrg            printf("    %-23s = %ld\n", par->name, i[par->prop_offset]);
44228515619Smrg            break;
44328515619Smrg        case 0:                /* Float */
44428515619Smrg            if (!float_type)
44528515619Smrg                continue;
44628515619Smrg            if (format != 32 || type != float_type) {
44728515619Smrg                fprintf(stderr, "    %-23s = format mismatch (%d)\n",
44828515619Smrg                        par->name, format);
44928515619Smrg                break;
45028515619Smrg            }
45128515619Smrg
45228515619Smrg            f = (union flong *) data;
45328515619Smrg            printf("    %-23s = %g\n", par->name, f[par->prop_offset].f);
45428515619Smrg            break;
45528515619Smrg        }
45628515619Smrg
45728515619Smrg        XFree(data);
458b85037dbSmrg    }
459b85037dbSmrg}
460b85037dbSmrg
461b85037dbSmrgstatic void
462b85037dbSmrgusage(void)
463b85037dbSmrg{
46428515619Smrg    fprintf(stderr, "Usage: synclient [-h] [-l] [-V] [-?] [var1=value1 [var2=value2] ...]\n");
465b85037dbSmrg    fprintf(stderr, "  -l List current user settings\n");
466b85037dbSmrg    fprintf(stderr, "  -V Print synclient version string and exit\n");
467b85037dbSmrg    fprintf(stderr, "  -? Show this help message\n");
468b85037dbSmrg    fprintf(stderr, "  var=value  Set user parameter 'var' to 'value'.\n");
469b85037dbSmrg    exit(1);
470b85037dbSmrg}
471b85037dbSmrg
472b85037dbSmrgint
473b85037dbSmrgmain(int argc, char *argv[])
474b85037dbSmrg{
475b85037dbSmrg    int c;
476b85037dbSmrg    int dump_settings = 0;
477b85037dbSmrg    int first_cmd;
478b85037dbSmrg
479b85037dbSmrg    Display *dpy;
480b85037dbSmrg    XDevice *dev;
481b85037dbSmrg
482b85037dbSmrg    if (argc == 1)
483b85037dbSmrg        dump_settings = 1;
484b85037dbSmrg
485b85037dbSmrg    /* Parse command line parameters */
48628515619Smrg    while ((c = getopt(argc, argv, "lV?")) != -1) {
48728515619Smrg        switch (c) {
48828515619Smrg        case 'l':
48928515619Smrg            dump_settings = 1;
49028515619Smrg            break;
49128515619Smrg        case 'V':
49228515619Smrg            printf("%s\n", VERSION);
49328515619Smrg            exit(0);
49428515619Smrg        case '?':
49528515619Smrg        default:
49628515619Smrg            usage();
49728515619Smrg        }
498b85037dbSmrg    }
499b85037dbSmrg
500b85037dbSmrg    first_cmd = optind;
50128515619Smrg    if (!dump_settings && first_cmd == argc)
50228515619Smrg        usage();
503b85037dbSmrg
504b85037dbSmrg    dpy = dp_init();
505b85037dbSmrg    if (!dpy || !(dev = dp_get_device(dpy)))
506b85037dbSmrg        return 1;
507b85037dbSmrg
508b85037dbSmrg    dp_set_variables(dpy, dev, argc, argv, first_cmd);
509b85037dbSmrg    if (dump_settings)
510b85037dbSmrg        dp_show_settings(dpy, dev);
511b85037dbSmrg
512b85037dbSmrg    XCloseDevice(dpy, dev);
513b85037dbSmrg    XCloseDisplay(dpy);
514b85037dbSmrg
515b85037dbSmrg    return 0;
516b85037dbSmrg}
517