From d67954c0dd5352022ea24eccb1a96f7c01d7f68c Mon Sep 17 00:00:00 2001 From: Stephen Chandler Paul Date: Thu, 13 Feb 2014 16:03:56 -0500 Subject: [PATCH] Add support for monitoring pointing sticks Using XSync syndaemon can watch for activity from a laptop's pointing stick and change the settings accordingly. Useful for machines with a pointing stick that relies on it's clickpad's software buttons. By default, enabling point stick monitoring will also disable keyboard monitoring so that the user doesn't have to have keyboard monitoring enabled. However, keyboard monitoring can be enabled simultaneously by specifying -M on the command line. --- configure.ac | 2 +- man/syndaemon.man | 56 ++++-- tools/Makefile.am | 2 +- tools/syndaemon.c | 533 ++++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 483 insertions(+), 110 deletions(-) diff --git a/configure.ac b/configure.ac index 77edbb2..c6cf29b 100644 --- a/configure.ac +++ b/configure.ac @@ -135,7 +135,7 @@ AM_CONDITIONAL([BUILD_PS2COMM], [test "x${BUILD_PS2COMM}" = "xyes"]) # Dependencies for synclient and syndaemon # ----------------------------------------------------------------------------- # Obtain compiler/linker options for the Synaptics apps dependencies -PKG_CHECK_MODULES(XI, x11 inputproto [xi >= 1.2]) +PKG_CHECK_MODULES(XI, x11 inputproto xext [xi >= 1.2]) # The syndaemon program uses an optional XRecord extension implementation # If libxtst >= 1.0.99 is installed, Cflags contains the path to record.h diff --git a/man/syndaemon.man b/man/syndaemon.man index 30ea20b..f08ee09 100644 --- a/man/syndaemon.man +++ b/man/syndaemon.man @@ -3,12 +3,11 @@ .TH syndaemon __appmansuffix__ __vendorversion__ .SH NAME .LP -syndaemon \- a program that monitors keyboard activity and disables -the touchpad when the keyboard is being used. +syndaemon \- a program that monitors keyboard and/or pointing stick activity and +disables the touchpad when either of them are being used. .SH "SYNOPSIS" .LP -syndaemon [\fI\-i idle\-time\fP] [\fI\-m poll-inverval\fP] [\fI\-d\fP] [\fI\-p pid\-file\fP] -[\fI\-t\fP] [\fI\-k\fP] [\fI\-K\fP] [\fI\-R\fP] +syndaemon [\fI\-i idle\-time\fP] [\fI\-m poll-inverval\fP] [\fI\-d\fP] [\fI\-p pid\-file\fP] [\fI\-t\fP] [\fI\-P\fP [\fIpointing-stick\fP]] [\fI\-M\fP] [\fI\-k\fP] [\fI\-K\fP] [\fI\-R\fP] .SH "DESCRIPTION" .LP Disabling the touchpad while typing avoids unwanted movements of the @@ -18,18 +17,17 @@ pointer that could lead to giving focus to the wrong window. .LP .TP \fB\-i\fR <\fIidle\-time\fP> -How many seconds to wait after the last key press before enabling the -touchpad. +How many seconds to wait after the last key press or pointing stick activity +before enabling the touchpad. . (default is 2.0s). .LP .TP \fB\-m\fR <\fIpoll\-interval\fP> How many milliseconds to wait between two polling intervals. If this value is -too low, it will cause unnecessary wake-ups. If this value is too high, -some key presses (press and release happen between two intervals) may not -be noticed. This switch has no effect when running with -\fB-R\fP. +too low, it will cause unnecessary wake-ups. If this value is too high, some key +presses (press and release happen between two intervals) may not be noticed. +This switch has no effect when running with \fB\-R\fP and/or \fB\-P\fP. . Default is 200ms. .LP @@ -46,10 +44,30 @@ mode. .LP .TP \fB\-t\fP [off|tapping|click-only] - Disable state. "off" for disabling the touchpad entirely, "tapping" for - disabling tapping and scrolling only, "click-only" for disabling - everything but physical clicks. The default if this option is missing is - "off". If this option is given without a mode it defaults to "tapping". +Disable state. "off" for disabling the touchpad entirely, "tapping" for +disabling tapping and scrolling only, "click-only" for disabling everything but +physical clicks. The default if this option is missing is "off". If this option +is given without a mode it defaults to "tapping". +.LP +.TP +\fB\-T\fP [off|tapping|click-only] +Same as \fB\-t\fP, but sets the disable state for pointing stick monitoring. +.LP +.TP +\fB\-P\fP [pointing-stick] +Monitors the pointing stick for activity instead of keyboard activity. XSync +support is required on the server for this to work. Useful on laptops that have +a pointing stick but lack a set of physical buttons for their pointing stick. +If this option is given without the name of a pointing stick, it defaults to +"TPPS/2 IBM TrackPoint". +. +When using this option, keyboard monitoring is disabled unless explicitly +enabled by specifying \fB\-R\fP or \fB\-M\fP. +.LP +.TP +\fB\-M\fP +Explicitly enables keyboard monitoring. This is the default behavior, unless +\fB\-P\fP has been enabled. .LP .TP \fB\-k\fP @@ -92,6 +110,16 @@ The fork into daemon mode failed or the pid file could not be created. .TP \fBExit code 4 XRECORD requested but not available or usable on the server. +.LP +.TP +\fBExit code 5 +Pointing stick monitoring requested, but XSync was not available or usable on +the server. +.LP +.TP +\fBExit code 6 +Pointing stick monitoring requested, but a pointing stick could not be found +(try specifying the name manually when using \fB\-P\fP). .SH "CAVEATS" .LP It doesn't make much sense to connect to a remote X server, because diff --git a/tools/Makefile.am b/tools/Makefile.am index e790905..02ea7ba 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -28,4 +28,4 @@ synclient_SOURCES = synclient.c syndaemon_SOURCES = syndaemon.c syndaemon_CFLAGS = $(AM_CFLAGS) $(XTST_CFLAGS) -syndaemon_LDFLAGS = $(AM_LDFLAGS) $(XTST_LIBS) +syndaemon_LDFLAGS = $(AM_LDFLAGS) $(XTST_LIBS) $(XEXT_LIBS) diff --git a/tools/syndaemon.c b/tools/syndaemon.c index b181d16..d686af7 100644 --- a/tools/syndaemon.c +++ b/tools/syndaemon.c @@ -1,5 +1,6 @@ /* * Copyright © 2003-2004 Peter Osterlund + * Copyright © 2014 Stephen Chandler Paul * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without @@ -22,6 +23,7 @@ * * Authors: * Peter Osterlund (petero2@telia.com) + * Stephen Chandler Paul (thatslyude@gmail.com) */ #ifdef HAVE_CONFIG_H @@ -36,6 +38,9 @@ #include #endif /* HAVE_X11_EXTENSIONS_RECORD_H */ +#include +#define DEFAULT_POINTING_STICK "TPPS/2 IBM TrackPoint" + #include #include #include @@ -44,6 +49,8 @@ #include #include #include +#include +#include #include "synaptics-properties.h" @@ -51,11 +58,21 @@ enum TouchpadState { TouchpadOn = 0, TouchpadOff = 1, TappingOff = 2, - ClickOnly = 3 + ClickOnly = 3, + InvalidState = -1 +}; + +enum TouchpadIdleMode { + KeyboardIdle = 0, + PStickIdle = 1, }; -static Bool pad_disabled - /* internal flag, this does not correspond to device state */ ; +typedef struct { + int x; + int y; +} CursorPosition; + +static Bool tp_state[2]; static int ignore_modifier_combos; static int ignore_modifier_keys; static int background; @@ -64,9 +81,19 @@ static Display *display; static XDevice *dev; static Atom touchpad_off_prop; static enum TouchpadState previous_state; -static enum TouchpadState disable_state = TouchpadOff; +static enum TouchpadState idle_state[2]; +static double idle_time; +static Bool use_xrecord; +static Bool monitor_keyboard; static int verbose; +Bool monitor_pstick = False; +static int sync_event; +static int pstick_id; /* trackpoint device */ +static const char * pstick_name; +static XSyncAlarm pstick_leave_idle_alarm; +static XSyncAlarm pstick_enter_idle_alarm; + #define KEYMAP_SIZE 32 static unsigned char keyboard_mask[KEYMAP_SIZE]; @@ -74,7 +101,7 @@ static void usage(void) { fprintf(stderr, - "Usage: syndaemon [-i idle-time] [-m poll-delay] [-d] [-t [off|tapping|click-only]] [-k]\n"); + "Usage: syndaemon [-i idle-time] [-m poll-delay] [-d] [-t [off|tapping|click-only]] [-T [off|tapping|click-only]] [-k] [-K] [-M] [-R] [-P [pointing-stick]]\n"); fprintf(stderr, " -i How many seconds to wait after the last key press before\n"); fprintf(stderr, " enabling the touchpad. (default is 2.0s)\n"); @@ -88,6 +115,15 @@ usage(void) " 'tapping' for disabling tapping and scrolling only,\n" " 'click-only' for disabling everything but physical clicks.\n"); fprintf(stderr, + " -T Disable state.\n" + " Same as -t, applies to pointing stick monitoring.\n"); + fprintf(stderr, + " -M Enables monitoring of the keyboard (default).\n"); + fprintf(stderr, + " -P Pointing Stick.\n" + " Enables monitoring of the pointing stick (disables keyboard \n" + " monitoring unless -R or -M is also specified)\n"); + fprintf(stderr, " -k Ignore modifier keys when monitoring keyboard activity.\n"); fprintf(stderr, " -K Like -k but also ignore Modifier+Key combos.\n"); fprintf(stderr, " -R Use the XRecord extension.\n"); @@ -112,41 +148,61 @@ store_current_touchpad_state(void) } } -/** - * Toggle touchpad enabled/disabled state, decided by value. - */ static void -toggle_touchpad(Bool enable) -{ - unsigned char data; +set_touchpad_state(enum TouchpadState new_state) { + unsigned char data = new_state; + + XChangeDeviceProperty(display, dev, touchpad_off_prop, XA_INTEGER, 8, + PropModeReplace, &data, 1); + XFlush(display); +} + +static void +update_touchpad_state() { + static Bool last_tp_state[2]; + enum TouchpadState new_state; + + if (memcmp(&last_tp_state, &tp_state, sizeof(tp_state)) == 0) + return; + + /* Decide on the idle state to use */ + if (tp_state[PStickIdle]) { + if (last_tp_state[PStickIdle]) + goto nothing_to_update; + + if (!last_tp_state[KeyboardIdle]) + store_current_touchpad_state(); - if (pad_disabled && enable) { - data = previous_state; - pad_disabled = False; if (verbose) - printf("Enable\n"); + printf("Switching to pointing stick mode.\n"); + + new_state = idle_state[PStickIdle]; } - else if (!pad_disabled && !enable && - previous_state != disable_state && previous_state != TouchpadOff) { - store_current_touchpad_state(); - pad_disabled = True; - data = disable_state; + else if (tp_state[KeyboardIdle]) { + if (!last_tp_state[PStickIdle]) + store_current_touchpad_state(); + if (verbose) - printf("Disable\n"); + printf("Switching to keyboard mode.\n"); + + new_state = idle_state[KeyboardIdle]; } - else - return; + else { + if (verbose) + printf("Enabling touchpad.\n"); - /* This potentially overwrites a different client's setting, but ... */ - XChangeDeviceProperty(display, dev, touchpad_off_prop, XA_INTEGER, 8, - PropModeReplace, &data, 1); - XFlush(display); + new_state = previous_state; + } + + set_touchpad_state(new_state); +nothing_to_update: + memcpy(&last_tp_state, &tp_state, sizeof(tp_state)); } static void signal_handler(int signum) { - toggle_touchpad(True); + set_touchpad_state(previous_state); if (pid_file) unlink(pid_file); @@ -185,6 +241,24 @@ install_signal_handler(void) } } + +static int +setup_xsync(Display * display) +{ + int sync_error; + int sync_major, sync_minor; + + if (!XSyncQueryExtension(display, &sync_event, &sync_error)) + return 1; + + if (!XSyncInitialize(display, &sync_major, &sync_minor)) + return 1; + if (verbose) + printf("X Sync extension version %d.%d\n", sync_major, sync_minor); + + return 0; +} + /** * Return non-zero if the keyboard state has changed since the last call. */ @@ -217,6 +291,28 @@ keyboard_activity(Display * display) return ret; } +/** + * Handles XSync events from the pointing stick + */ +static void +handle_pstick_events(Display * display) { + while (XPending(display)) { + XEvent event; + XSyncAlarmNotifyEvent * alarm_event; + + XNextEvent(display, &event); + alarm_event = (XSyncAlarmNotifyEvent*)&event; + + if (alarm_event->alarm == pstick_leave_idle_alarm) + tp_state[PStickIdle] = True; + else if (alarm_event->alarm == pstick_enter_idle_alarm) + tp_state[PStickIdle] = False; + else + fprintf(stderr, "Got event from unknown alarm %ld\n", + alarm_event->alarm); + } +} + static double get_time(void) { @@ -227,31 +323,54 @@ get_time(void) } static void -main_loop(Display * display, double idle_time, int poll_delay) +main_loop(Display * display, int poll_delay) { - double last_activity = 0.0; + double last_activity_time = 0.0; double current_time; + struct pollfd pstick_pollfd; + int poll_res = 0; - keyboard_activity(display); + if (monitor_keyboard) + keyboard_activity(display); - for (;;) { - current_time = get_time(); - if (keyboard_activity(display)) - last_activity = current_time; + if (monitor_pstick) { + pstick_pollfd.fd = XConnectionNumber(display); + pstick_pollfd.events = POLLIN; + } - /* If system times goes backwards, touchpad can get locked. Make - * sure our last activity wasn't in the future and reset if it was. */ - if (last_activity > current_time) - last_activity = current_time - idle_time - 1; + for (;;) { + if (monitor_keyboard) { + current_time = get_time(); - if (current_time > last_activity + idle_time) { /* Enable touchpad */ - toggle_touchpad(True); + if (keyboard_activity(display)) { + tp_state[KeyboardIdle] = True; + last_activity_time = current_time; + } + else if (tp_state[KeyboardIdle] == True) { + /* If system time goes backwards, touchpad can get locked. Make + * sure out last activity wasn't in the future and reset it if + * it was. */ + if (last_activity_time > current_time) + last_activity_time = 0.0; + + if (current_time > last_activity_time + idle_time) + tp_state[KeyboardIdle] = False; + } } - else { /* Disable touchpad */ - toggle_touchpad(False); + + if (monitor_pstick) { + if (poll_res != 0) + handle_pstick_events(display); + + /* Only have a timeout if we're doing plain monitoring for the + * keyboard too */ + poll_res = poll(&pstick_pollfd, 1, + monitor_keyboard ? poll_delay : -1); } + else + sleep(poll_delay); - usleep(poll_delay); + update_touchpad_state(); } } @@ -285,6 +404,77 @@ setup_keyboard_mask(Display * display, int ignore_modifier_keys) } } +static XSyncAlarm +setup_device_alarm(Display * display, int device_id, XSyncTestType test_type, + int wait_time) { + XSyncAlarm alarm; + int alarm_flags; + XSyncAlarmAttributes attr; + XSyncValue delta, interval; + + int ncounters; + char idle_counter_name[20]; + XSyncCounter counter = 0; + XSyncSystemCounter * counters; + + snprintf(&idle_counter_name[0], sizeof(idle_counter_name), + "DEVICEIDLETIME %d", device_id); + counters = XSyncListSystemCounters(display, &ncounters); + + /* Find the idle counter for the trackpoint */ + for (int i = 0; i < ncounters; i++) { + if (strcmp(counters[i].name, &idle_counter_name[0]) == 0) { + counter = counters[i].counter; + break; + } + } + + if (counter == 0) + return 0; + + XSyncFreeSystemCounterList(counters); + + XSyncIntToValue(&delta, 0); + XSyncIntToValue(&interval, wait_time); + + attr.trigger.counter = counter; + attr.trigger.test_type = test_type; + attr.trigger.value_type = XSyncAbsolute; + attr.trigger.wait_value = interval; + attr.delta = delta; + attr.events = True; + + alarm_flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | + XSyncCAValue | XSyncCADelta; + + alarm = XSyncCreateAlarm(display, alarm_flags, &attr); + return alarm; +} + +static int +get_device_id(Display * display, const char * dev_name, + char * dev_type) { + XDeviceInfo * info = NULL; + int ndevices = 0; + int dev_id = 0; + Atom dev_type_atom; + + dev_type_atom = + (dev_type != NULL) ? XInternAtom(display, dev_type, True) : 0; + info = XListInputDevices(display, &ndevices); + + while (ndevices--) { + if (info[ndevices].type == dev_type_atom && + strcmp(info[ndevices].name, dev_name) == 0) { + dev_id = info[ndevices].id; + break; + } + } + + XFreeDeviceList(info); + return dev_id; +} + /* ---- the following code is for using the xrecord extension ----- */ #ifdef HAVE_X11_EXTENSIONS_RECORD_H @@ -395,7 +585,7 @@ is_modifier_pressed(const struct xrecord_callback_results *cbres) } void -record_main_loop(Display * display, double idle_time) +record_main_loop(Display * display) { struct xrecord_callback_results cbres; @@ -403,9 +593,15 @@ record_main_loop(Display * display, double idle_time) XRecordClientSpec cspec = XRecordAllClients; Display *dpy_data; XRecordRange *range; - int i; - - dpy_data = XOpenDisplay(NULL); /* we need an additional data connection. */ + int keyboard_fd = 0; + int pstick_fd = 0; + int max_fd; + struct timeval timeout; + struct timespec kbd_activity_end; + fd_set read_fds; + + /* we need an additional data connection. */ + dpy_data = XOpenDisplay(NULL); range = XRecordAllocRange(); range->device_events.first = KeyPress; @@ -418,27 +614,60 @@ record_main_loop(Display * display, double idle_time) cbres.modifiers = XGetModifierMapping(display); /* clear list of modifiers */ - for (i = 0; i < MAX_MODIFIERS; ++i) + for (int i = 0; i < MAX_MODIFIERS; ++i) cbres.pressed_modifiers[i] = 0; - while (1) { + keyboard_fd = ConnectionNumber(dpy_data); + + if (monitor_pstick) + pstick_fd = ConnectionNumber(display); + + if (keyboard_fd > pstick_fd) + max_fd = keyboard_fd; + else + max_fd = pstick_fd; - int fd = ConnectionNumber(dpy_data); - fd_set read_fds; + while (1) { int ret; - int disable_event = 0; - struct timeval timeout; + int keyboard_event = 0; FD_ZERO(&read_fds); - FD_SET(fd, &read_fds); - ret = select(fd + 1 /* =(max descriptor in read_fds) + 1 */ , - &read_fds, NULL, NULL, - pad_disabled ? &timeout : NULL - /* timeout only required for enabling */ ); + FD_SET(keyboard_fd, &read_fds); + + if (monitor_pstick) + FD_SET(pstick_fd, &read_fds); + + ret = select(max_fd + 1, &read_fds, NULL, NULL, + tp_state[KeyboardIdle] ? &timeout : NULL + /* timeout only required for enabling keyboard */); + + if (FD_ISSET(pstick_fd, &read_fds)) { + handle_pstick_events(display); - if (FD_ISSET(fd, &read_fds)) { + if (tp_state[KeyboardIdle]) { + struct timespec current_time; + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + /* Check to make sure the keyboard activity didn't stop while we + * were worrying about pointing stick events */ + if (current_time.tv_sec >= kbd_activity_end.tv_sec && + current_time.tv_nsec >= kbd_activity_end.tv_nsec) { + tp_state[KeyboardIdle] = False; + } + /* Update the keyboard timeout so we still get notified when + * keyboard activity ceases */ + else { + timeout.tv_sec = + kbd_activity_end.tv_sec - current_time.tv_sec; + timeout.tv_usec = + (kbd_activity_end.tv_nsec - current_time.tv_nsec) / + 1000; + } + } + } + + if (FD_ISSET(keyboard_fd, &read_fds)) { cbres.key_event = 0; cbres.non_modifier_event = 0; @@ -455,28 +684,46 @@ record_main_loop(Display * display, double idle_time) } if (!ignore_modifier_keys && cbres.key_event) { - disable_event = 1; + keyboard_event = 1; } if (cbres.non_modifier_event && !(ignore_modifier_combos && is_modifier_pressed(&cbres))) { - disable_event = 1; + keyboard_event = 1; } } - if (disable_event) { + if (keyboard_event) { /* adjust the enable_time */ timeout.tv_sec = (int) idle_time; - timeout.tv_usec = (idle_time - (double) timeout.tv_sec) * 1.e6; + timeout.tv_usec = + (idle_time - (double) timeout.tv_sec) * 1.e6; + + /* Knowing when the end of the activity period for the keyboard + * only matters if we could get interrupted before a select() + * timeout by pstick events + */ + if (monitor_pstick) { + clock_gettime(CLOCK_MONOTONIC, &kbd_activity_end); + + kbd_activity_end.tv_sec += timeout.tv_sec; + kbd_activity_end.tv_nsec += timeout.tv_usec * 1000; + + // Normalize the tv_usec value + if (kbd_activity_end.tv_nsec >= 1.e9) { + kbd_activity_end.tv_sec++; + kbd_activity_end.tv_nsec -= 1.e9; + } + } - toggle_touchpad(False); + tp_state[KeyboardIdle] = True; } - if (ret == 0 && pad_disabled) { /* timeout => enable event */ - toggle_touchpad(True); - } + if (ret == 0) /* timeout => enable event */ + tp_state[KeyboardIdle] = False; - } /* end while(1) */ + update_touchpad_state(); + } XFreeModifiermap(cbres.modifiers); } @@ -542,22 +789,39 @@ dp_get_device(Display * dpy) return dev; } +static enum TouchpadState +parse_idle_mode(const char * state) { + if (state[0] == '-') + return 0; + else if (strcmp(state, "off") == 0) + return TouchpadOff; + else if (strcmp(state, "tapping") == 0) + return TappingOff; + else if (strcmp(state, "click-only") == 0) + return ClickOnly; + else + return InvalidState; +} + int main(int argc, char *argv[]) { - double idle_time = 2.0; - int poll_delay = 200000; /* 200 ms */ + int poll_delay = 200; int c; - int use_xrecord = 0; + + idle_time = 2.0; + + idle_state[KeyboardIdle] = TouchpadOff; + idle_state[PStickIdle] = ClickOnly; /* Parse command line parameters */ - while ((c = getopt(argc, argv, ":i:m:dp:kKR?v")) != EOF) { + while ((c = getopt(argc, argv, ":i:m:dp:MkKR?v")) != EOF) { switch (c) { case 'i': idle_time = atof(optarg); break; case 'm': - poll_delay = atoi(optarg) * 1000; + poll_delay = atoi(optarg); break; case 'd': background = 1; @@ -573,28 +837,39 @@ main(int argc, char *argv[]) ignore_modifier_keys = 1; break; case 'R': - use_xrecord = 1; + use_xrecord = True; + break; + case 'M': + monitor_keyboard = True; break; case 'v': verbose = 1; break; case '?': - if (optopt != 't') - usage(); - else { + if (optopt == 'P') { + monitor_pstick = True; if (optind < argc) { if (argv[optind][0] == '-') - disable_state = TappingOff; - else if (strcmp(argv[optind], "off") == 0) - disable_state = TouchpadOff; - else if (strcmp(argv[optind], "tapping") == 0) - disable_state = TappingOff; - else if (strcmp(argv[optind], "click-only") == 0) - disable_state = ClickOnly; + pstick_name = DEFAULT_POINTING_STICK; else - usage(); - } else - disable_state = TappingOff; + pstick_name = &argv[optind][0]; + } + else + pstick_name = DEFAULT_POINTING_STICK; + } + else if (optopt == 'T') { + idle_state[PStickIdle] = parse_idle_mode(argv[optind]); + if (idle_state[PStickIdle] == InvalidState) + usage(); + } + else if (optopt == 't') { + idle_state[KeyboardIdle] = parse_idle_mode(argv[optind]); + if (idle_state[KeyboardIdle] == InvalidState) + usage(); + } + else { + usage(); + break; } break; default: @@ -605,6 +880,54 @@ main(int argc, char *argv[]) if (idle_time <= 0.0) usage(); + /* If the keyboard was not selected and no alternate devices to monitor were + * selected, default to the keyboard */ + if (!monitor_pstick) + monitor_keyboard = True; + + /* Open a connection to the X server */ + display = XOpenDisplay(NULL); + if (!display) { + fprintf(stderr, "Can't open display.\n"); + exit(2); + } + + if (!(dev = dp_get_device(display))) + exit(2); + + /* Install a signal handler to restore synaptics parameters on exit */ + install_signal_handler(); + + if (background) { + pid_t pid; + + if ((pid = fork()) < 0) { + perror("fork"); + exit(3); + } + else if (pid != 0) + exit(0); + + /* Child (daemon) is running here */ + setsid(); /* Become session leader */ + chdir("/"); /* In case the file system gets unmounted */ + umask(0); /* We don't want any surprises */ + if (pid_file) { + FILE *fd = fopen(pid_file, "w"); + + if (!fd) { + perror("Can't create pid file"); + } + } + } + if (idle_time <= 0.0) + usage(); + + /* If the keyboard was not selected and no alternate devices to monitor were + * selected, default to the keyboard */ + if (!monitor_pstick) + monitor_keyboard = True; + /* Open a connection to the X server */ display = XOpenDisplay(NULL); if (!display) { @@ -644,26 +967,48 @@ main(int argc, char *argv[]) } } - pad_disabled = False; store_current_touchpad_state(); + memset(&tp_state, 0, sizeof(tp_state)); + + if (monitor_pstick) { + pstick_id = get_device_id(display, pstick_name, XI_MOUSE); + if (pstick_id == 0) { + fprintf(stderr, "Couldn't find pointing stick %s\n", pstick_name); + exit(6); + } + + pstick_leave_idle_alarm = + setup_device_alarm(display, pstick_id, XSyncNegativeTransition, + idle_time * 1000); + pstick_enter_idle_alarm = + setup_device_alarm(display, pstick_id, XSyncPositiveTransition, + idle_time * 1000); + + if (setup_xsync(display) != 0) { + fprintf(stderr, "Monitoring of pointing stick requested, but " + "XSync could not be initialized.\n"); + exit(5); + } + } + #ifdef HAVE_X11_EXTENSIONS_RECORD_H if (use_xrecord) { - if (check_xrecord(display)) - record_main_loop(display, idle_time); - else { + if (!check_xrecord(display)) { fprintf(stderr, "Use of XRecord requested, but failed to " " initialize.\n"); exit(4); } + record_main_loop(display); } else #endif /* HAVE_X11_EXTENSIONS_RECORD_H */ { - setup_keyboard_mask(display, ignore_modifier_keys); + if (monitor_keyboard) + setup_keyboard_mask(display, ignore_modifier_keys); /* Run the main loop */ - main_loop(display, idle_time, poll_delay); + main_loop(display, poll_delay); } return 0; } -- 1.8.3.2