synclient.c revision b85037db
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/shm.h> 36b85037dbSmrg#include <sys/time.h> 37b85037dbSmrg#include <unistd.h> 38b85037dbSmrg#include <string.h> 39b85037dbSmrg#include <stddef.h> 40b85037dbSmrg#include <math.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.h" 47b85037dbSmrg#include "synaptics-properties.h" 48b85037dbSmrg#include <xserver-properties.h> 49b85037dbSmrg 50b85037dbSmrg#ifndef XATOM_FLOAT 51b85037dbSmrg#define XATOM_FLOAT "FLOAT" 52b85037dbSmrg#endif 53b85037dbSmrg 54b85037dbSmrgunion flong { /* Xlibs 64-bit property handling madness */ 55b85037dbSmrg long l; 56b85037dbSmrg float f; 57b85037dbSmrg}; 58b85037dbSmrg 59b85037dbSmrg 60b85037dbSmrgenum ParaType { 61b85037dbSmrg PT_INT, 62b85037dbSmrg PT_BOOL, 63b85037dbSmrg PT_DOUBLE 64b85037dbSmrg}; 65b85037dbSmrg 66b85037dbSmrgstruct Parameter { 67b85037dbSmrg char *name; /* Name of parameter */ 68b85037dbSmrg enum ParaType type; /* Type of parameter */ 69b85037dbSmrg double min_val; /* Minimum allowed value */ 70b85037dbSmrg double max_val; /* Maximum allowed value */ 71b85037dbSmrg char *prop_name; /* Property name */ 72b85037dbSmrg int prop_format; /* Property format (0 for floats) */ 73b85037dbSmrg int prop_offset; /* Offset inside property */ 74b85037dbSmrg}; 75b85037dbSmrg 76b85037dbSmrgstatic struct Parameter params[] = { 77b85037dbSmrg {"LeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 0}, 78b85037dbSmrg {"RightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 1}, 79b85037dbSmrg {"TopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 2}, 80b85037dbSmrg {"BottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_EDGES, 32, 3}, 81b85037dbSmrg {"FingerLow", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 0}, 82b85037dbSmrg {"FingerHigh", PT_INT, 0, 255, SYNAPTICS_PROP_FINGER, 32, 1}, 83b85037dbSmrg {"FingerPress", PT_INT, 0, 256, SYNAPTICS_PROP_FINGER, 32, 2}, 84b85037dbSmrg {"MaxTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_TIME, 32, 0}, 85b85037dbSmrg {"MaxTapMove", PT_INT, 0, 2000, SYNAPTICS_PROP_TAP_MOVE, 32, 0}, 86b85037dbSmrg {"MaxDoubleTapTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS,32, 1}, 87b85037dbSmrg {"SingleTapTimeout", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS,32, 0}, 88b85037dbSmrg {"ClickTime", PT_INT, 0, 1000, SYNAPTICS_PROP_TAP_DURATIONS,32, 2}, 89b85037dbSmrg {"FastTaps", PT_BOOL, 0, 1, SYNAPTICS_PROP_TAP_FAST, 8, 0}, 90b85037dbSmrg {"EmulateMidButtonTime", PT_INT, 0, 1000, SYNAPTICS_PROP_MIDDLE_TIMEOUT,32, 0}, 91b85037dbSmrg {"EmulateTwoFingerMinZ", PT_INT, 0, 1000, SYNAPTICS_PROP_TWOFINGER_PRESSURE, 32, 0}, 92b85037dbSmrg {"EmulateTwoFingerMinW", PT_INT, 0, 15, SYNAPTICS_PROP_TWOFINGER_WIDTH, 32, 0}, 93b85037dbSmrg {"VertScrollDelta", PT_INT, 0, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 0}, 94b85037dbSmrg {"HorizScrollDelta", PT_INT, 0, 1000, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 1}, 95b85037dbSmrg {"VertEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 0}, 96b85037dbSmrg {"HorizEdgeScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 1}, 97b85037dbSmrg {"CornerCoasting", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_EDGE, 8, 2}, 98b85037dbSmrg {"VertTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 0}, 99b85037dbSmrg {"HorizTwoFingerScroll", PT_BOOL, 0, 1, SYNAPTICS_PROP_SCROLL_TWOFINGER, 8, 1}, 100b85037dbSmrg {"MinSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 0}, 101b85037dbSmrg {"MaxSpeed", PT_DOUBLE, 0, 255.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 1}, 102b85037dbSmrg {"AccelFactor", PT_DOUBLE, 0, 1.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 2}, 103b85037dbSmrg {"TrackstickSpeed", PT_DOUBLE, 0, 200.0, SYNAPTICS_PROP_SPEED, 0, /*float */ 3}, 104b85037dbSmrg {"EdgeMotionMinZ", PT_INT, 1, 255, SYNAPTICS_PROP_EDGEMOTION_PRESSURE, 32, 0}, 105b85037dbSmrg {"EdgeMotionMaxZ", PT_INT, 1, 255, SYNAPTICS_PROP_EDGEMOTION_PRESSURE, 32, 1}, 106b85037dbSmrg {"EdgeMotionMinSpeed", PT_INT, 0, 1000, SYNAPTICS_PROP_EDGEMOTION_SPEED, 32, 0}, 107b85037dbSmrg {"EdgeMotionMaxSpeed", PT_INT, 0, 1000, SYNAPTICS_PROP_EDGEMOTION_SPEED, 32, 1}, 108b85037dbSmrg {"EdgeMotionUseAlways", PT_BOOL, 0, 1, SYNAPTICS_PROP_EDGEMOTION, 8, 0}, 109b85037dbSmrg {"UpDownScrolling", PT_BOOL, 0, 1, SYNAPTICS_PROP_BUTTONSCROLLING, 8, 0}, 110b85037dbSmrg {"LeftRightScrolling", PT_BOOL, 0, 1, SYNAPTICS_PROP_BUTTONSCROLLING, 8, 1}, 111b85037dbSmrg {"UpDownScrollRepeat", PT_BOOL, 0, 1, SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT, 8, 0}, 112b85037dbSmrg {"LeftRightScrollRepeat", PT_BOOL, 0, 1, SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT, 8, 1}, 113b85037dbSmrg {"ScrollButtonRepeat", PT_INT, SBR_MIN , SBR_MAX, SYNAPTICS_PROP_BUTTONSCROLLING_TIME, 32, 0}, 114b85037dbSmrg {"TouchpadOff", PT_INT, 0, 2, SYNAPTICS_PROP_OFF, 8, 0}, 115b85037dbSmrg {"LockedDrags", PT_BOOL, 0, 1, SYNAPTICS_PROP_LOCKED_DRAGS, 8, 0}, 116b85037dbSmrg {"LockedDragTimeout", PT_INT, 0, 30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT, 32, 0}, 117b85037dbSmrg {"RTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 0}, 118b85037dbSmrg {"RBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 1}, 119b85037dbSmrg {"LTCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 2}, 120b85037dbSmrg {"LBCornerButton", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 3}, 121b85037dbSmrg {"TapButton1", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 4}, 122b85037dbSmrg {"TapButton2", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 5}, 123b85037dbSmrg {"TapButton3", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8, 6}, 124b85037dbSmrg {"ClickFinger1", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 0}, 125b85037dbSmrg {"ClickFinger2", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 1}, 126b85037dbSmrg {"ClickFinger3", PT_INT, 0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, 8, 2}, 127b85037dbSmrg {"CircularScrolling", PT_BOOL, 0, 1, SYNAPTICS_PROP_CIRCULAR_SCROLLING, 8, 0}, 128b85037dbSmrg {"CircScrollDelta", PT_DOUBLE, .01, 3, SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST, 0 /* float */, 0}, 129b85037dbSmrg {"CircScrollTrigger", PT_INT, 0, 8, SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER, 8, 0}, 130b85037dbSmrg {"CircularPad", PT_BOOL, 0, 1, SYNAPTICS_PROP_CIRCULAR_PAD, 8, 0}, 131b85037dbSmrg {"PalmDetect", PT_BOOL, 0, 1, SYNAPTICS_PROP_PALM_DETECT, 8, 0}, 132b85037dbSmrg {"PalmMinWidth", PT_INT, 0, 15, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 0}, 133b85037dbSmrg {"PalmMinZ", PT_INT, 0, 255, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 1}, 134b85037dbSmrg {"CoastingSpeed", PT_DOUBLE, 0, 20, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 0}, 135b85037dbSmrg {"CoastingFriction", PT_DOUBLE, 0, 255, SYNAPTICS_PROP_COASTING_SPEED, 0 /* float*/, 1}, 136b85037dbSmrg {"PressureMotionMinZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 0}, 137b85037dbSmrg {"PressureMotionMaxZ", PT_INT, 1, 255, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 1}, 138b85037dbSmrg {"PressureMotionMinFactor", PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 0}, 139b85037dbSmrg {"PressureMotionMaxFactor", PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 0 /*float*/, 1}, 140b85037dbSmrg {"GrabEventDevice", PT_BOOL, 0, 1, SYNAPTICS_PROP_GRAB, 8, 0}, 141b85037dbSmrg {"TapAndDragGesture", PT_BOOL, 0, 1, SYNAPTICS_PROP_GESTURES, 8, 0}, 142b85037dbSmrg {"AreaLeftEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 0}, 143b85037dbSmrg {"AreaRightEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 1}, 144b85037dbSmrg {"AreaTopEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 2}, 145b85037dbSmrg {"AreaBottomEdge", PT_INT, 0, 10000, SYNAPTICS_PROP_AREA, 32, 3}, 146b85037dbSmrg { NULL, 0, 0, 0, 0 } 147b85037dbSmrg}; 148b85037dbSmrg 149b85037dbSmrgstatic double 150b85037dbSmrgparse_cmd(char* cmd, struct Parameter** par) 151b85037dbSmrg{ 152b85037dbSmrg char *eqp = index(cmd, '='); 153b85037dbSmrg *par = NULL; 154b85037dbSmrg 155b85037dbSmrg if (eqp) { 156b85037dbSmrg int j; 157b85037dbSmrg int found = 0; 158b85037dbSmrg *eqp = 0; 159b85037dbSmrg for (j = 0; params[j].name; j++) { 160b85037dbSmrg if (strcasecmp(cmd, params[j].name) == 0) { 161b85037dbSmrg found = 1; 162b85037dbSmrg break; 163b85037dbSmrg } 164b85037dbSmrg } 165b85037dbSmrg if (found) { 166b85037dbSmrg double val = atof(&eqp[1]); 167b85037dbSmrg *par = ¶ms[j]; 168b85037dbSmrg 169b85037dbSmrg if (val < (*par)->min_val) 170b85037dbSmrg val = (*par)->min_val; 171b85037dbSmrg if (val > (*par)->max_val) 172b85037dbSmrg val = (*par)->max_val; 173b85037dbSmrg 174b85037dbSmrg return val; 175b85037dbSmrg } else { 176b85037dbSmrg printf("Unknown parameter %s\n", cmd); 177b85037dbSmrg } 178b85037dbSmrg } else { 179b85037dbSmrg printf("Invalid command: %s\n", cmd); 180b85037dbSmrg } 181b85037dbSmrg 182b85037dbSmrg return 0; 183b85037dbSmrg} 184b85037dbSmrg 185b85037dbSmrgstatic int 186b85037dbSmrgis_equal(SynapticsSHM *s1, SynapticsSHM *s2) 187b85037dbSmrg{ 188b85037dbSmrg int i; 189b85037dbSmrg 190b85037dbSmrg if ((s1->x != s2->x) || 191b85037dbSmrg (s1->y != s2->y) || 192b85037dbSmrg (s1->z != s2->z) || 193b85037dbSmrg (s1->numFingers != s2->numFingers) || 194b85037dbSmrg (s1->fingerWidth != s2->fingerWidth) || 195b85037dbSmrg (s1->left != s2->left) || 196b85037dbSmrg (s1->right != s2->right) || 197b85037dbSmrg (s1->up != s2->up) || 198b85037dbSmrg (s1->down != s2->down) || 199b85037dbSmrg (s1->middle != s2->middle)) 200b85037dbSmrg return 0; 201b85037dbSmrg 202b85037dbSmrg for (i = 0; i < 8; i++) 203b85037dbSmrg if (s1->multi[i] != s2->multi[i]) 204b85037dbSmrg return 0; 205b85037dbSmrg 206b85037dbSmrg return 1; 207b85037dbSmrg} 208b85037dbSmrg 209b85037dbSmrgstatic double 210b85037dbSmrgget_time(void) 211b85037dbSmrg{ 212b85037dbSmrg struct timeval tv; 213b85037dbSmrg gettimeofday(&tv, NULL); 214b85037dbSmrg return tv.tv_sec + tv.tv_usec / 1000000.0; 215b85037dbSmrg} 216b85037dbSmrg 217b85037dbSmrgstatic void 218b85037dbSmrgshm_monitor(SynapticsSHM *synshm, int delay) 219b85037dbSmrg{ 220b85037dbSmrg int header = 0; 221b85037dbSmrg SynapticsSHM old; 222b85037dbSmrg double t0 = get_time(); 223b85037dbSmrg 224b85037dbSmrg memset(&old, 0, sizeof(SynapticsSHM)); 225b85037dbSmrg old.x = -1; /* Force first equality test to fail */ 226b85037dbSmrg 227b85037dbSmrg while (1) { 228b85037dbSmrg SynapticsSHM cur = *synshm; 229b85037dbSmrg if (!is_equal(&old, &cur)) { 230b85037dbSmrg if (!header) { 231b85037dbSmrg printf("%8s %4s %4s %3s %s %2s %2s %s %s %s %s %8s " 232b85037dbSmrg "%2s %2s %2s %3s %3s\n", 233b85037dbSmrg "time", "x", "y", "z", "f", "w", "l", "r", "u", "d", "m", 234b85037dbSmrg "multi", "gl", "gm", "gr", "gdx", "gdy"); 235b85037dbSmrg header = 20; 236b85037dbSmrg } 237b85037dbSmrg header--; 238b85037dbSmrg printf("%8.3f %4d %4d %3d %d %2d %2d %d %d %d %d %d%d%d%d%d%d%d%d\n", 239b85037dbSmrg get_time() - t0, 240b85037dbSmrg cur.x, cur.y, cur.z, cur.numFingers, cur.fingerWidth, 241b85037dbSmrg cur.left, cur.right, cur.up, cur.down, cur.middle, 242b85037dbSmrg cur.multi[0], cur.multi[1], cur.multi[2], cur.multi[3], 243b85037dbSmrg cur.multi[4], cur.multi[5], cur.multi[6], cur.multi[7]); 244b85037dbSmrg fflush(stdout); 245b85037dbSmrg old = cur; 246b85037dbSmrg } 247b85037dbSmrg usleep(delay * 1000); 248b85037dbSmrg } 249b85037dbSmrg} 250b85037dbSmrg 251b85037dbSmrg/** Init and return SHM area or NULL on error */ 252b85037dbSmrgstatic SynapticsSHM* 253b85037dbSmrgshm_init() 254b85037dbSmrg{ 255b85037dbSmrg SynapticsSHM *synshm = NULL; 256b85037dbSmrg int shmid = 0; 257b85037dbSmrg 258b85037dbSmrg if ((shmid = shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM), 0)) == -1) { 259b85037dbSmrg if ((shmid = shmget(SHM_SYNAPTICS, 0, 0)) == -1) 260b85037dbSmrg fprintf(stderr, "Can't access shared memory area. SHMConfig disabled?\n"); 261b85037dbSmrg else 262b85037dbSmrg fprintf(stderr, "Incorrect size of shared memory area. Incompatible driver version?\n"); 263b85037dbSmrg } else if ((synshm = (SynapticsSHM*) shmat(shmid, NULL, SHM_RDONLY)) == NULL) 264b85037dbSmrg perror("shmat"); 265b85037dbSmrg 266b85037dbSmrg return synshm; 267b85037dbSmrg} 268b85037dbSmrg 269b85037dbSmrgstatic void 270b85037dbSmrgshm_process_commands(int do_monitor, int delay) 271b85037dbSmrg{ 272b85037dbSmrg SynapticsSHM *synshm = NULL; 273b85037dbSmrg 274b85037dbSmrg synshm = shm_init(); 275b85037dbSmrg if (!synshm) 276b85037dbSmrg return; 277b85037dbSmrg 278b85037dbSmrg if (do_monitor) 279b85037dbSmrg shm_monitor(synshm, delay); 280b85037dbSmrg} 281b85037dbSmrg 282b85037dbSmrg/** Init display connection or NULL on error */ 283b85037dbSmrgstatic Display* 284b85037dbSmrgdp_init() 285b85037dbSmrg{ 286b85037dbSmrg Display *dpy = NULL; 287b85037dbSmrg XExtensionVersion *v = NULL; 288b85037dbSmrg Atom touchpad_type = 0; 289b85037dbSmrg Atom synaptics_property = 0; 290b85037dbSmrg int error = 0; 291b85037dbSmrg 292b85037dbSmrg dpy = XOpenDisplay(NULL); 293b85037dbSmrg if (!dpy) { 294b85037dbSmrg fprintf(stderr, "Failed to connect to X Server.\n"); 295b85037dbSmrg error = 1; 296b85037dbSmrg goto unwind; 297b85037dbSmrg } 298b85037dbSmrg 299b85037dbSmrg v = XGetExtensionVersion(dpy, INAME); 300b85037dbSmrg if (!v->present || 301b85037dbSmrg (v->major_version * 1000 + v->minor_version) < (XI_Add_DeviceProperties_Major * 1000 302b85037dbSmrg + XI_Add_DeviceProperties_Minor)) { 303b85037dbSmrg fprintf(stderr, "X server supports X Input %d.%d. I need %d.%d.\n", 304b85037dbSmrg v->major_version, v->minor_version, 305b85037dbSmrg XI_Add_DeviceProperties_Major, 306b85037dbSmrg XI_Add_DeviceProperties_Minor); 307b85037dbSmrg error = 1; 308b85037dbSmrg goto unwind; 309b85037dbSmrg } 310b85037dbSmrg 311b85037dbSmrg /* We know synaptics sets XI_TOUCHPAD for all the devices. */ 312b85037dbSmrg touchpad_type = XInternAtom(dpy, XI_TOUCHPAD, True); 313b85037dbSmrg if (!touchpad_type) { 314b85037dbSmrg fprintf(stderr, "XI_TOUCHPAD not initialised.\n"); 315b85037dbSmrg error = 1; 316b85037dbSmrg goto unwind; 317b85037dbSmrg } 318b85037dbSmrg 319b85037dbSmrg synaptics_property = XInternAtom(dpy, SYNAPTICS_PROP_EDGES, True); 320b85037dbSmrg if (!synaptics_property) { 321b85037dbSmrg fprintf(stderr, "Couldn't find synaptics properties. No synaptics " 322b85037dbSmrg "driver loaded?\n"); 323b85037dbSmrg error = 1; 324b85037dbSmrg goto unwind; 325b85037dbSmrg } 326b85037dbSmrg 327b85037dbSmrgunwind: 328b85037dbSmrg XFree(v); 329b85037dbSmrg if (error && dpy) 330b85037dbSmrg { 331b85037dbSmrg XCloseDisplay(dpy); 332b85037dbSmrg dpy = NULL; 333b85037dbSmrg } 334b85037dbSmrg return dpy; 335b85037dbSmrg} 336b85037dbSmrg 337b85037dbSmrgstatic XDevice * 338b85037dbSmrgdp_get_device(Display *dpy) 339b85037dbSmrg{ 340b85037dbSmrg XDevice* dev = NULL; 341b85037dbSmrg XDeviceInfo *info = NULL; 342b85037dbSmrg int ndevices = 0; 343b85037dbSmrg Atom touchpad_type = 0; 344b85037dbSmrg Atom synaptics_property = 0; 345b85037dbSmrg Atom *properties = NULL; 346b85037dbSmrg int nprops = 0; 347b85037dbSmrg int error = 0; 348b85037dbSmrg 349b85037dbSmrg touchpad_type = XInternAtom(dpy, XI_TOUCHPAD, True); 350b85037dbSmrg synaptics_property = XInternAtom(dpy, SYNAPTICS_PROP_EDGES, True); 351b85037dbSmrg info = XListInputDevices(dpy, &ndevices); 352b85037dbSmrg 353b85037dbSmrg while(ndevices--) { 354b85037dbSmrg if (info[ndevices].type == touchpad_type) { 355b85037dbSmrg dev = XOpenDevice(dpy, info[ndevices].id); 356b85037dbSmrg if (!dev) { 357b85037dbSmrg fprintf(stderr, "Failed to open device '%s'.\n", 358b85037dbSmrg info[ndevices].name); 359b85037dbSmrg error = 1; 360b85037dbSmrg goto unwind; 361b85037dbSmrg } 362b85037dbSmrg 363b85037dbSmrg properties = XListDeviceProperties(dpy, dev, &nprops); 364b85037dbSmrg if (!properties || !nprops) 365b85037dbSmrg { 366b85037dbSmrg fprintf(stderr, "No properties on device '%s'.\n", 367b85037dbSmrg info[ndevices].name); 368b85037dbSmrg error = 1; 369b85037dbSmrg goto unwind; 370b85037dbSmrg } 371b85037dbSmrg 372b85037dbSmrg while(nprops--) 373b85037dbSmrg { 374b85037dbSmrg if (properties[nprops] == synaptics_property) 375b85037dbSmrg break; 376b85037dbSmrg } 377b85037dbSmrg if (!nprops) 378b85037dbSmrg { 379b85037dbSmrg fprintf(stderr, "No synaptics properties on device '%s'.\n", 380b85037dbSmrg info[ndevices].name); 381b85037dbSmrg error = 1; 382b85037dbSmrg goto unwind; 383b85037dbSmrg } 384b85037dbSmrg 385b85037dbSmrg break; /* Yay, device is suitable */ 386b85037dbSmrg } 387b85037dbSmrg } 388b85037dbSmrg 389b85037dbSmrgunwind: 390b85037dbSmrg XFree(properties); 391b85037dbSmrg XFreeDeviceList(info); 392b85037dbSmrg if (!dev) 393b85037dbSmrg fprintf(stderr, "Unable to find a synaptics device.\n"); 394b85037dbSmrg else if (error && dev) 395b85037dbSmrg { 396b85037dbSmrg XCloseDevice(dpy, dev); 397b85037dbSmrg dev = NULL; 398b85037dbSmrg } 399b85037dbSmrg return dev; 400b85037dbSmrg} 401b85037dbSmrg 402b85037dbSmrgstatic void 403b85037dbSmrgdp_set_variables(Display *dpy, XDevice* dev, int argc, char *argv[], int first_cmd) 404b85037dbSmrg{ 405b85037dbSmrg int i; 406b85037dbSmrg double val; 407b85037dbSmrg struct Parameter *par; 408b85037dbSmrg Atom prop, type, float_type; 409b85037dbSmrg int format; 410b85037dbSmrg unsigned char* data; 411b85037dbSmrg unsigned long nitems, bytes_after; 412b85037dbSmrg 413b85037dbSmrg union flong *f; 414b85037dbSmrg long *n; 415b85037dbSmrg char *b; 416b85037dbSmrg 417b85037dbSmrg float_type = XInternAtom(dpy, XATOM_FLOAT, True); 418b85037dbSmrg if (!float_type) 419b85037dbSmrg fprintf(stderr, "Float properties not available.\n"); 420b85037dbSmrg 421b85037dbSmrg for (i = first_cmd; i < argc; i++) { 422b85037dbSmrg val = parse_cmd(argv[i], &par); 423b85037dbSmrg if (!par) 424b85037dbSmrg continue; 425b85037dbSmrg 426b85037dbSmrg prop = XInternAtom(dpy, par->prop_name, True); 427b85037dbSmrg if (!prop) 428b85037dbSmrg { 429b85037dbSmrg fprintf(stderr, "Property for '%s' not available. Skipping.\n", 430b85037dbSmrg par->name); 431b85037dbSmrg continue; 432b85037dbSmrg 433b85037dbSmrg } 434b85037dbSmrg 435b85037dbSmrg XGetDeviceProperty(dpy, dev, prop, 0, 1000, False, AnyPropertyType, 436b85037dbSmrg &type, &format, &nitems, &bytes_after, &data); 437b85037dbSmrg 438b85037dbSmrg switch(par->prop_format) 439b85037dbSmrg { 440b85037dbSmrg case 8: 441b85037dbSmrg if (format != par->prop_format || type != XA_INTEGER) { 442b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 443b85037dbSmrg par->name, format); 444b85037dbSmrg break; 445b85037dbSmrg } 446b85037dbSmrg b = (char*)data; 447b85037dbSmrg b[par->prop_offset] = rint(val); 448b85037dbSmrg break; 449b85037dbSmrg case 32: 450b85037dbSmrg if (format != par->prop_format || type != XA_INTEGER) { 451b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 452b85037dbSmrg par->name, format); 453b85037dbSmrg break; 454b85037dbSmrg } 455b85037dbSmrg n = (long*)data; 456b85037dbSmrg n[par->prop_offset] = rint(val); 457b85037dbSmrg break; 458b85037dbSmrg case 0: /* float */ 459b85037dbSmrg if (!float_type) 460b85037dbSmrg continue; 461b85037dbSmrg if (format != 32 || type != float_type) { 462b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 463b85037dbSmrg par->name, format); 464b85037dbSmrg break; 465b85037dbSmrg } 466b85037dbSmrg f = (union flong*)data; 467b85037dbSmrg f[par->prop_offset].f = val; 468b85037dbSmrg break; 469b85037dbSmrg } 470b85037dbSmrg 471b85037dbSmrg XChangeDeviceProperty(dpy, dev, prop, type, format, 472b85037dbSmrg PropModeReplace, data, nitems); 473b85037dbSmrg XFlush(dpy); 474b85037dbSmrg } 475b85037dbSmrg} 476b85037dbSmrg 477b85037dbSmrg/* FIXME: horribly inefficient. */ 478b85037dbSmrgstatic void 479b85037dbSmrgdp_show_settings(Display *dpy, XDevice *dev) 480b85037dbSmrg{ 481b85037dbSmrg int j; 482b85037dbSmrg Atom a, type, float_type; 483b85037dbSmrg int format; 484b85037dbSmrg unsigned long nitems, bytes_after; 485b85037dbSmrg unsigned char* data; 486b85037dbSmrg int len; 487b85037dbSmrg 488b85037dbSmrg union flong *f; 489b85037dbSmrg long *i; 490b85037dbSmrg char *b; 491b85037dbSmrg 492b85037dbSmrg float_type = XInternAtom(dpy, XATOM_FLOAT, True); 493b85037dbSmrg if (!float_type) 494b85037dbSmrg fprintf(stderr, "Float properties not available.\n"); 495b85037dbSmrg 496b85037dbSmrg printf("Parameter settings:\n"); 497b85037dbSmrg for (j = 0; params[j].name; j++) { 498b85037dbSmrg struct Parameter *par = ¶ms[j]; 499b85037dbSmrg a = XInternAtom(dpy, par->prop_name, True); 500b85037dbSmrg if (!a) 501b85037dbSmrg continue; 502b85037dbSmrg 503b85037dbSmrg len = 1 + ((par->prop_offset * (par->prop_format ? par->prop_format : 32)/8))/4; 504b85037dbSmrg 505b85037dbSmrg XGetDeviceProperty(dpy, dev, a, 0, len, False, 506b85037dbSmrg AnyPropertyType, &type, &format, 507b85037dbSmrg &nitems, &bytes_after, &data); 508b85037dbSmrg 509b85037dbSmrg switch(par->prop_format) { 510b85037dbSmrg case 8: 511b85037dbSmrg if (format != par->prop_format || type != XA_INTEGER) { 512b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 513b85037dbSmrg par->name, format); 514b85037dbSmrg break; 515b85037dbSmrg } 516b85037dbSmrg 517b85037dbSmrg b = (char*)data; 518b85037dbSmrg printf(" %-23s = %d\n", par->name, b[par->prop_offset]); 519b85037dbSmrg break; 520b85037dbSmrg case 32: 521b85037dbSmrg if (format != par->prop_format || type != XA_INTEGER) { 522b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 523b85037dbSmrg par->name, format); 524b85037dbSmrg break; 525b85037dbSmrg } 526b85037dbSmrg 527b85037dbSmrg i = (long*)data; 528b85037dbSmrg printf(" %-23s = %ld\n", par->name, i[par->prop_offset]); 529b85037dbSmrg break; 530b85037dbSmrg case 0: /* Float */ 531b85037dbSmrg if (!float_type) 532b85037dbSmrg continue; 533b85037dbSmrg if (format != 32 || type != float_type) { 534b85037dbSmrg fprintf(stderr, " %-23s = format mismatch (%d)\n", 535b85037dbSmrg par->name, format); 536b85037dbSmrg break; 537b85037dbSmrg } 538b85037dbSmrg 539b85037dbSmrg f = (union flong*)data; 540b85037dbSmrg printf(" %-23s = %g\n", par->name, f[par->prop_offset].f); 541b85037dbSmrg break; 542b85037dbSmrg } 543b85037dbSmrg 544b85037dbSmrg XFree(data); 545b85037dbSmrg } 546b85037dbSmrg} 547b85037dbSmrg 548b85037dbSmrgstatic void 549b85037dbSmrgusage(void) 550b85037dbSmrg{ 551b85037dbSmrg fprintf(stderr, "Usage: synclient [-s] [-m interval] [-h] [-l] [-V] [-?] [var1=value1 [var2=value2] ...]\n"); 552b85037dbSmrg fprintf(stderr, " -m monitor changes to the touchpad state (implies -s)\n" 553b85037dbSmrg " interval specifies how often (in ms) to poll the touchpad state\n"); 554b85037dbSmrg fprintf(stderr, " -l List current user settings\n"); 555b85037dbSmrg fprintf(stderr, " -V Print synclient version string and exit\n"); 556b85037dbSmrg fprintf(stderr, " -? Show this help message\n"); 557b85037dbSmrg fprintf(stderr, " var=value Set user parameter 'var' to 'value'.\n"); 558b85037dbSmrg exit(1); 559b85037dbSmrg} 560b85037dbSmrg 561b85037dbSmrgint 562b85037dbSmrgmain(int argc, char *argv[]) 563b85037dbSmrg{ 564b85037dbSmrg int c; 565b85037dbSmrg int delay = -1; 566b85037dbSmrg int do_monitor = 0; 567b85037dbSmrg int dump_settings = 0; 568b85037dbSmrg int first_cmd; 569b85037dbSmrg 570b85037dbSmrg Display *dpy; 571b85037dbSmrg XDevice *dev; 572b85037dbSmrg 573b85037dbSmrg if (argc == 1) 574b85037dbSmrg dump_settings = 1; 575b85037dbSmrg 576b85037dbSmrg /* Parse command line parameters */ 577b85037dbSmrg while ((c = getopt(argc, argv, "sm:hlV")) != -1) { 578b85037dbSmrg switch (c) { 579b85037dbSmrg case 'm': 580b85037dbSmrg do_monitor = 1; 581b85037dbSmrg if ((delay = atoi(optarg)) < 0) 582b85037dbSmrg usage(); 583b85037dbSmrg break; 584b85037dbSmrg case 'l': 585b85037dbSmrg dump_settings = 1; 586b85037dbSmrg break; 587b85037dbSmrg case 'V': 588b85037dbSmrg printf("%s\n", VERSION); 589b85037dbSmrg exit(0); 590b85037dbSmrg default: 591b85037dbSmrg usage(); 592b85037dbSmrg } 593b85037dbSmrg } 594b85037dbSmrg 595b85037dbSmrg first_cmd = optind; 596b85037dbSmrg if (!do_monitor && !dump_settings && first_cmd == argc) 597b85037dbSmrg usage(); 598b85037dbSmrg 599b85037dbSmrg /* Connect to the shared memory area */ 600b85037dbSmrg if (do_monitor) 601b85037dbSmrg shm_process_commands(do_monitor, delay); 602b85037dbSmrg 603b85037dbSmrg dpy = dp_init(); 604b85037dbSmrg if (!dpy || !(dev = dp_get_device(dpy))) 605b85037dbSmrg return 1; 606b85037dbSmrg 607b85037dbSmrg dp_set_variables(dpy, dev, argc, argv, first_cmd); 608b85037dbSmrg if (dump_settings) 609b85037dbSmrg dp_show_settings(dpy, dev); 610b85037dbSmrg 611b85037dbSmrg XCloseDevice(dpy, dev); 612b85037dbSmrg XCloseDisplay(dpy); 613b85037dbSmrg 614b85037dbSmrg return 0; 615b85037dbSmrg} 616