diff options
Diffstat (limited to 'source/a/gpm')
-rw-r--r-- | source/a/gpm/gpm-1.20.1-consolename.patch | 18 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-gpmopen.patch | 22 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-idie.patch | 12 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-input-defines.diff | 26 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-input.patch | 16 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-lib-silent.patch | 19 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-math.patch | 11 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-multilib.patch | 52 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-no-console-error.patch | 15 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-nodebug.patch | 12 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-subscript.patch | 11 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1-weak-wgetch.patch | 38 | ||||
-rw-r--r-- | source/a/gpm/gpm-1.20.1.send-noise-to-syslogs.diff | 86 | ||||
-rw-r--r-- | source/a/gpm/gpm-evdev-cumulative.patch | 7023 | ||||
-rwxr-xr-x | source/a/gpm/gpm.SlackBuild | 149 | ||||
-rw-r--r-- | source/a/gpm/gpm.evdevmakefile.patch | 11 | ||||
-rw-r--r-- | source/a/gpm/inputattach.c | 472 | ||||
-rw-r--r-- | source/a/gpm/mouseconfig | 7 | ||||
-rw-r--r-- | source/a/gpm/setup.mouse | 154 | ||||
-rw-r--r-- | source/a/gpm/slack-desc | 19 |
20 files changed, 8173 insertions, 0 deletions
diff --git a/source/a/gpm/gpm-1.20.1-consolename.patch b/source/a/gpm/gpm-1.20.1-consolename.patch new file mode 100644 index 00000000..c5879fb4 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-consolename.patch @@ -0,0 +1,18 @@ +--- gpm-1.20.1/src/lib/liblow.c.orig 2004-10-13 16:34:15.181502369 -0400 ++++ gpm-1.20.1/src/lib/liblow.c 2004-10-13 16:34:20.491778415 -0400 +@@ -262,13 +262,14 @@ + gpm_report(GPM_PR_ERR,"consolename not set"); + goto err; + } ++#if 0 + /* do we really need this check ? */ + if(strncmp(tty,consolename,strlen(consolename)-1) + || !isdigit(tty[strlen(consolename)-1])) { + gpm_report(GPM_PR_ERR,"strncmp/isdigit/consolename failed"); + goto err; + } +- ++#endif + conn->vc=atoi(&tty[strlen(consolename)-1]); + } + diff --git a/source/a/gpm/gpm-1.20.1-gpmopen.patch b/source/a/gpm/gpm-1.20.1-gpmopen.patch new file mode 100644 index 00000000..f36ad939 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-gpmopen.patch @@ -0,0 +1,22 @@ +--- gpm-1.20.1/src/lib/liblow.c.gpmopen 2004-05-04 17:36:09.000000000 -0400 ++++ gpm-1.20.1/src/lib/liblow.c 2004-05-04 17:42:51.000000000 -0400 +@@ -200,8 +200,6 @@ + Gpm_Stst *new = NULL; + char* sock_name = 0; + +- consolename = NULL; +- + #if 0 + gpm_report(GPM_PR_DEBUG,"VC: %d",flag); + #endif +@@ -260,6 +258,10 @@ + gpm_report(GPM_PR_ERR,"checking tty name failed"); + goto err; + } ++ if (consolename == NULL) { ++ gpm_report(GPM_PR_ERR,"consolename not set"); ++ goto err; ++ } + /* do we really need this check ? */ + if(strncmp(tty,consolename,strlen(consolename)-1) + || !isdigit(tty[strlen(consolename)-1])) { diff --git a/source/a/gpm/gpm-1.20.1-idie.patch b/source/a/gpm/gpm-1.20.1-idie.patch new file mode 100644 index 00000000..4594f078 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-idie.patch @@ -0,0 +1,12 @@ +--- gpm-1.20.1/src/lib/liblow.c.orig 2004-05-06 14:14:03.000000000 -0400 ++++ gpm-1.20.1/src/lib/liblow.c 2004-05-06 14:18:05.000000000 -0400 +@@ -376,7 +376,9 @@ + + /*....................................... Error: free all memory */ + err: ++#if 0 + gpm_report(GPM_PR_ERR,"Oh, oh, it's an error! possibly I die! "); ++#endif + do { + new=gpm_stack->next; + free(gpm_stack); diff --git a/source/a/gpm/gpm-1.20.1-input-defines.diff b/source/a/gpm/gpm-1.20.1-input-defines.diff new file mode 100644 index 00000000..4a925a6a --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-input-defines.diff @@ -0,0 +1,26 @@ +--- ./src/headers/input-defines.h.orig 2006-12-11 19:56:14.000000000 -0600 ++++ ./src/headers/input-defines.h 2006-12-11 19:59:30.000000000 -0600 +@@ -59,23 +59,4 @@ + #define PSMOUSE_SYNAPTICS 7 + #endif + +-#ifndef HAVE_INPUT_ID +-struct input_id { +- unsigned short bustype; +- unsigned short vendor; +- unsigned short product; +- unsigned short version; +-}; +-#endif +- +-#ifndef HAVE_INPUT_ABSINFO +-struct input_absinfo { +- int value; +- int minimum; +- int maximum; +- int fuzz; +- int flat; +-}; +-#endif +- + #endif diff --git a/source/a/gpm/gpm-1.20.1-input.patch b/source/a/gpm/gpm-1.20.1-input.patch new file mode 100644 index 00000000..152e6038 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-input.patch @@ -0,0 +1,16 @@ +diff -ur gpm-1.20.1.orig/src/headers/config.h.in gpm-1.20.1/src/headers/config.h.in +--- gpm-1.20.1.orig/src/headers/config.h.in 2004-09-04 10:24:11.000000000 -0400 ++++ gpm-1.20.1/src/headers/config.h.in 2004-09-04 10:26:02.000000000 -0400 +@@ -46,6 +46,12 @@ + /* Define if you have the <linux/input.h> header file. */ + #undef HAVE_LINUX_INPUT_H + ++/* Definedif you have the input_id structure */ ++#undef HAVE_INPUT_ID ++ ++/* Definedif you have the input_absinfo structure */ ++#undef HAVE_INPUT_ABSINFO ++ + /* Define if you have the <linux/joystick.h> header file. */ + #undef HAVE_LINUX_JOYSTICK_H + diff --git a/source/a/gpm/gpm-1.20.1-lib-silent.patch b/source/a/gpm/gpm-1.20.1-lib-silent.patch new file mode 100644 index 00000000..099075b5 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-lib-silent.patch @@ -0,0 +1,19 @@ +--- gpm-1.20.1/src/lib/report-lib.c.lib-silent 2002-12-24 23:57:16.000000000 +0100 ++++ gpm-1.20.1/src/lib/report-lib.c 2006-01-18 17:55:38.000000000 +0100 +@@ -24,8 +24,16 @@ + + #include "headers/message.h" + ++static int gpm_silent() { ++ if ( getenv( "GPM_VERBOSE" ) == NULL ) return 1; ++ return 0; ++} ++ + void gpm_report(int line, char *file, int stat, char *text, ... ) + { ++ if ( gpm_silent() && stat != GPM_STAT_OOPS ) ++ return; ++ + char *string = NULL; + va_list ap; + va_start(ap,text); diff --git a/source/a/gpm/gpm-1.20.1-math.patch b/source/a/gpm/gpm-1.20.1-math.patch new file mode 100644 index 00000000..634a5fd8 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-math.patch @@ -0,0 +1,11 @@ +--- gpm-1.20.1/configure.in.math Tue Jun 24 10:52:44 2003 ++++ gpm-1.20.1/configure.in Tue Jun 24 10:53:54 2003 +@@ -128,7 +128,7 @@ + AC_SUBST(lispdir) + + CPPFLAGS='-I$(srcdir) $(DEFS) -include headers/config.h -Wall -DSYSCONFDIR="\"$(sysconfdir)\"" -DSBINDIR="\"$(sbindir)\""' +-LDFLAGS='-L$(srcdir)' ++LDFLAGS='-lm -L$(srcdir)' + + dnl AC_DEFINE_UNQUOTED(SYSCONFDIR,"$sysconfdir") + dnl AC_DEFINE_UNQUOTED(SBINDIR,"$sbindir") diff --git a/source/a/gpm/gpm-1.20.1-multilib.patch b/source/a/gpm/gpm-1.20.1-multilib.patch new file mode 100644 index 00000000..723ee2b5 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-multilib.patch @@ -0,0 +1,52 @@ +--- gpm-1.20.1/doc/Makefile.in.multilib 2002-12-24 17:57:16.000000000 -0500 ++++ gpm-1.20.1/doc/Makefile.in 2004-10-20 17:25:11.000000000 -0400 +@@ -97,7 +97,7 @@ + + # Main portion + +-all: $(srcdir)/gpm.info $(MANPAGES) ++all: gpm.info $(MANPAGES) + + # why gpmdoc.ps and gpm.ps?? + # there is no gpm.ps in my tree and no rule to generate gpm.ps. +@@ -131,8 +131,8 @@ + #i keep all my infopages compressed and i'm tired to do it by + #hand, so check if there are any compressed pages and do this + #one too +- -ls $(infodir)/*[-.]info.gz >/dev/null 2>&1 \ +- && gzip -f $(infodir)/gpm.info ++ #-ls $(infodir)/*[-.]info.gz >/dev/null 2>&1 \ ++ # && gzip -f $(infodir)/gpm.info + # Hmm.... shouldn't man pages be compressed too? + # maybe they should, but at least at my system they are not. + +--- gpm-1.20.1/contrib/Makefile.in.multilib 2002-12-24 17:57:16.000000000 -0500 ++++ gpm-1.20.1/contrib/Makefile.in 2004-10-20 17:11:38.000000000 -0400 +@@ -9,10 +9,10 @@ + + include $(top_builddir)/Makefile.include + +-all: $(srcdir)/$(ELISP) ++all: $(filter-out %.elc,$(srcdir)/$(ELISP)) + + install: all +- if [ -n "$(ELISP)" ]; then for i in `echo $(ELISP)`; do \ ++ if [ -n "$(filter-out %.elc,$(ELISP))" ]; then for i in `echo $(filter-out %.elc,$(ELISP))`; do \ + $(INSTALL_DATA) $(srcdir)/$$i $(lispdir)/`basename $$i` ;\ + done; fi + +@@ -20,7 +20,7 @@ + $(EMACS) -batch -l $(srcdir)/emacs/exec.el -exec '(byte-compile-file "$<")' + + uninstall: +- if [ -n "$(ELISP)" ]; then for i in `echo $(ELISP)`; do \ ++ if [ -n "$(filter-out %.elc,$(ELISP))" ]; then for i in `echo $(filter-out %.elc,$(ELISP))`; do \ + rm -f $(lispdir)/$$i ;\ + done; fi + +@@ -28,4 +28,4 @@ + $(CP) -r $(srcdir) $(top_builddir)/gpm-$(release)/ + + clean distclean: +- $(RM) -f $(srcdir)/emacs/*.elc ++ $(RM) $(srcdir)/emacs/*.elc diff --git a/source/a/gpm/gpm-1.20.1-no-console-error.patch b/source/a/gpm/gpm-1.20.1-no-console-error.patch new file mode 100644 index 00000000..20c177b4 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-no-console-error.patch @@ -0,0 +1,15 @@ +--- gpm-1.20.1/src/console.c.no-console-error 2006-01-18 17:06:15.000000000 +0100 ++++ gpm-1.20.1/src/console.c 2006-01-18 17:08:19.000000000 +0100 +@@ -249,8 +249,10 @@ + /* Failed, try OLD console */ + else if (stat(GPM_OLD_CONSOLE, &buf) == 0) + console.device = GPM_OLD_CONSOLE; +- else +- gpm_report(GPM_PR_OOPS, "Can't determine console device"); ++ else { // XXX handle this gracefully? ++ fprintf( stderr, "no console device found" ); ++ exit( 1 ); ++ } + + return console.device; + } diff --git a/source/a/gpm/gpm-1.20.1-nodebug.patch b/source/a/gpm/gpm-1.20.1-nodebug.patch new file mode 100644 index 00000000..945b576c --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-nodebug.patch @@ -0,0 +1,12 @@ +--- gpm-1.20.1/src/lib/liblow.c.orig 2004-03-31 15:06:45.000000000 -0500 ++++ gpm-1.20.1/src/lib/liblow.c 2004-03-31 15:09:32.000000000 -0500 +@@ -202,7 +202,9 @@ + + consolename = NULL; + ++#if 0 + gpm_report(GPM_PR_DEBUG,"VC: %d",flag); ++#endif + + /*....................................... First of all, check xterm */ + diff --git a/source/a/gpm/gpm-1.20.1-subscript.patch b/source/a/gpm/gpm-1.20.1-subscript.patch new file mode 100644 index 00000000..bf4ca75b --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-subscript.patch @@ -0,0 +1,11 @@ +--- gpm-1.20.1/src/mice.c.lr 2004-02-15 09:19:48.000000000 +0100 ++++ gpm-1.20.1/src/mice.c 2004-02-15 09:22:18.000000000 +0100 +@@ -2112,7 +2112,7 @@ + for (i=0; i<4; i++) + if (gunze_calib[i] & ~1023) calibok = 0; + if (gunze_calib[0] == gunze_calib[2]) calibok = 0; +- if (gunze_calib[1] == gunze_calib[4]) calibok = 0; ++ if (gunze_calib[1] == gunze_calib[3]) calibok = 0; + fclose(f); + } + if (!calibok) { diff --git a/source/a/gpm/gpm-1.20.1-weak-wgetch.patch b/source/a/gpm/gpm-1.20.1-weak-wgetch.patch new file mode 100644 index 00000000..81e6a2b5 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1-weak-wgetch.patch @@ -0,0 +1,38 @@ +--- gpm-1.20.1/src/lib/libcurses.c.weak-wgetch 2002-12-24 17:57:16.000000000 -0500 ++++ gpm-1.20.1/src/lib/libcurses.c 2004-03-22 15:51:24.000000000 -0500 +@@ -41,7 +41,12 @@ + #endif /* HAVE_NCURSES_CURSES_H */ + #endif /* HAVE_NCURSES_H */ + +-#define GET(win) ((win) ? wgetch(win) : getch()) ++/* If win != NULL, it must have been created by ncurses anyway. ++ Avoid circular library dependencies. */ ++#pragma weak wgetch ++#pragma weak stdscr ++ ++#define GET(win) ((win && wgetch) ? wgetch(win) : getch()) + + int Gpm_Wgetch(WINDOW *win) + { +--- gpm-1.20.1/configure.in.weak-wgetch 2004-03-22 15:49:51.000000000 -0500 ++++ gpm-1.20.1/configure.in 2004-03-22 15:51:24.000000000 -0500 +@@ -115,7 +115,7 @@ + AC_CHECK_LIB($i, wgetch,,,$TERMLIBS) + else :; fi + done +- SHARED_LIBS="$LIBS $TERMLIBS -lc" ++ SHARED_LIBS="-lc" + LIBS=$SAVELIBS ;; + esac + +--- gpm-1.20.1/configure.weak-wgetch 2004-03-22 15:49:55.000000000 -0500 ++++ gpm-1.20.1/configure 2004-03-22 15:51:24.000000000 -0500 +@@ -4295,7 +4295,7 @@ + + else :; fi + done +- SHARED_LIBS="$LIBS $TERMLIBS -lc" ++ SHARED_LIBS="-lc" + LIBS=$SAVELIBS ;; + esac + diff --git a/source/a/gpm/gpm-1.20.1.send-noise-to-syslogs.diff b/source/a/gpm/gpm-1.20.1.send-noise-to-syslogs.diff new file mode 100644 index 00000000..111e7843 --- /dev/null +++ b/source/a/gpm/gpm-1.20.1.send-noise-to-syslogs.diff @@ -0,0 +1,86 @@ +diff -u -r gpm-1.20.1.orig/src/report.c gpm-1.20.1/src/report.c +--- gpm-1.20.1.orig/src/report.c 2006-08-20 14:34:30.000000000 -0500 ++++ gpm-1.20.1/src/report.c 2006-08-20 14:44:54.000000000 -0500 +@@ -48,15 +48,15 @@ + * + * Startup Mode: + * debug : - (ignore) +- * info : syslog/stdout +- * warn/err : syslog/stderr ++ * info : syslog ++ * warn/err : syslog + * oops : syslog/stderr [exit] + * + * Running Mode: (daemon) + * debug : - (ignore) + * info : syslog +- * warn : syslog+system console +- * err : syslog+system console+current console ++ * warn : syslog ++ * err : syslog + * oops : syslog/stderr [_exit] + * + * Debug Mode : +@@ -85,9 +85,6 @@ + syslog(LOG_INFO | LOG_USER, GPM_STRING_INFO); + vsyslog(LOG_INFO | LOG_USER, text, ap); + #endif +- fprintf(stderr,GPM_STRING_INFO); +- vfprintf(stderr,text,ap); +- fprintf(stderr,"\n"); + break; + + case GPM_STAT_WARN: +@@ -95,9 +92,6 @@ + syslog(LOG_DAEMON | LOG_WARNING, GPM_STRING_WARN); + vsyslog(LOG_DAEMON | LOG_WARNING, text, ap); + #endif +- fprintf(stderr,GPM_STRING_WARN); +- vfprintf(stderr,text,ap); +- fprintf(stderr,"\n"); + break; + + case GPM_STAT_ERR: +@@ -105,9 +99,6 @@ + syslog(LOG_DAEMON | LOG_ERR, GPM_STRING_ERR); + vsyslog(LOG_DAEMON | LOG_ERR, text, ap); + #endif +- fprintf(stderr,GPM_STRING_ERR); +- vfprintf(stderr,text,ap); +- fprintf(stderr,"\n"); + break; + + case GPM_STAT_OOPS: +@@ -139,12 +130,6 @@ + syslog(LOG_DAEMON | LOG_WARNING, GPM_STRING_WARN); + vsyslog(LOG_DAEMON | LOG_WARNING, text, ap); + #endif +- if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) { +- fprintf(f, GPM_STRING_WARN); +- vfprintf(f, text, ap); +- fprintf(f, "\n"); +- fclose(f); +- } + break; + + case GPM_STAT_ERR: +@@ -152,19 +137,6 @@ + syslog(LOG_DAEMON | LOG_ERR, GPM_STRING_ERR); + vsyslog(LOG_DAEMON | LOG_ERR, text, ap); + #endif +- if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) { +- fprintf(f, GPM_STRING_ERR); +- vfprintf(f, text, ap); +- fprintf(f, "\n"); +- fclose(f); +- } +- +- if ((f = fopen(console.device, "a")) != NULL) { +- fprintf(f, GPM_STRING_ERR); +- vfprintf(f, text, ap); +- fprintf(f, "\n"); +- fclose(f); +- } + break; + + case GPM_STAT_OOPS: diff --git a/source/a/gpm/gpm-evdev-cumulative.patch b/source/a/gpm/gpm-evdev-cumulative.patch new file mode 100644 index 00000000..2fd86d10 --- /dev/null +++ b/source/a/gpm/gpm-evdev-cumulative.patch @@ -0,0 +1,7023 @@ +diff -urN gpm-1.20.1/configure.in gpm/configure.in +--- gpm-1.20.1/configure.in 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/configure.in 2003-10-02 01:22:42.000000000 -0500 +@@ -61,6 +61,13 @@ + + AC_CHECK_HEADERS(syslog.h linux/input.h linux/joystick.h ncurses.h ncurses/curses.h curses.h) + ++EVDEV_SRCS= ++if test ${ac_cv_header_linux_input_h} = yes ; then ++ EVDEV_SRCS=evdev.c ; ++ AC_CHECK_TYPE(struct input_absinfo,AC_DEFINE_UNQUOTED(HAVE_INPUT_ABSINFO, 1, [define if struct input_absinfo defined in linux/input.h]),,[#include <linux/input.h>]) ++ AC_CHECK_TYPE(struct input_id,AC_DEFINE_UNQUOTED(HAVE_INPUT_ID, 1, [define if struct input_id defined in linux/input.h]),,[#include <linux/input.h>]) ++fi ++ + AC_ARG_WITH(curses, + [ --without-curses disable curses support even if curses found]) + +@@ -124,6 +131,7 @@ + AC_SUBST(PICFLAGS) + AC_SUBST(SOLDFLAGS) + AC_SUBST(CURSES_OBJS) ++AC_SUBST(EVDEV_SRCS) + AC_SUBST(SHARED_LIBS) + AC_SUBST(lispdir) + +diff -urN gpm-1.20.1/src/client.c gpm/src/client.c +--- gpm-1.20.1/src/client.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/client.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,319 @@ ++/* ++ * client.c - GPM client handling (server side) ++ * ++ * Copyright (C) 1993 Andreq Haylett <ajh@gec-mrc.co.uk> ++ * Copyright (C) 1994-1999 Alessandro Rubini <rubini@linux.it> ++ * Copyright (C) 1998 Ian Zimmerman <itz@rahul.net> ++ * Copyright (c) 2001,2002 Nico Schottelius <nico@schottelius.org> ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> /* strerror(); ?!? */ ++#include <errno.h> ++#include <unistd.h> /* select(); */ ++#include <signal.h> /* SIGPIPE */ ++#include <time.h> /* time() */ ++#include <sys/fcntl.h> /* O_RDONLY */ ++#include <sys/stat.h> /* mkdir() */ ++#include <sys/time.h> /* timeval */ ++#include <sys/types.h> /* socket() */ ++#include <sys/socket.h> /* socket() */ ++#include <sys/un.h> /* struct sockaddr_un */ ++ ++#include "headers/gpmInt.h" ++#include "headers/message.h" ++#include "headers/console.h" ++#include "headers/selection.h" ++#include "headers/client.h" ++ ++/* who the f*** runs gpm without glibc? doesn't have dietlibc __socklent_t? */ ++#if !defined(__GLIBC__) ++ typedef unsigned int __socklen_t; ++#endif /* __GLIBC__ */ ++ ++#ifndef max ++#define max(a,b) ((a)>(b) ? (a) : (b)) ++#endif ++ ++extern int errno; ++ ++struct client_info *cinfo[MAX_VC + 1]; ++ ++/*-------------------------------------------------------------------* ++ * This was inline, and incurred in a compiler bug (2.7.0) ++ *-------------------------------------------------------------------*/ ++static int get_data(int fd, Gpm_Connect *data) ++{ ++ static int len; ++ ++#ifdef GPM_USE_MAGIC ++ while ((len = read(whence, &check, sizeof(int))) == 4 && ++ check != GPM_MAGIC) ++ gpm_report(GPM_PR_INFO, GPM_MESS_NO_MAGIC); ++ ++ if (len == 0) return 0; ++ ++ if (check != GPM_MAGIC) { ++ gpm_report(GPM_PR_INFO, GPM_MESS_NOTHING_MORE); ++ return -1; ++ } ++#endif ++ ++ len = read(fd, data, sizeof(Gpm_Connect)); ++ ++ return len ? (len == sizeof(Gpm_Connect) ? 1 : -1) : 0; ++} ++ ++/*-------------------------------------------------------------------*/ ++int listen_for_clients(void) ++{ ++ struct sockaddr_un ctladdr; ++ int fd, len; ++ ++ unlink(GPM_NODE_CTL); ++ ++ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_SOCKET_PROB); ++ ++ memset(&ctladdr, 0, sizeof(ctladdr)); ++ ctladdr.sun_family = AF_UNIX; ++ strcpy(ctladdr.sun_path, GPM_NODE_CTL); ++ len = sizeof(ctladdr.sun_family) + strlen(GPM_NODE_CTL); ++ ++ if (bind(fd, (struct sockaddr *)&ctladdr, len) == -1) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_BIND_PROB, ctladdr.sun_path); ++ ++ /* needs to be 0777, so all users can _try_ to access gpm */ ++ chmod(GPM_NODE_CTL, 0777); ++ listen(fd, 5); /* Queue up calls */ ++ ++ return fd; ++} ++ ++/*-------------------------------------------------------------------*/ ++struct client_info *accept_client_connection(int fd) ++{ ++ struct client_info *info; ++ Gpm_Connect *request; ++ int newfd; ++#if !defined(__GLIBC__) ++ int len; ++#else /* __GLIBC__ */ ++ size_t len; /* isn't that generally defined in C ??? -- nico */ ++#endif /* __GLIBC__ */ ++ struct sockaddr_un addr; /* reuse this each time */ ++#ifndef SO_PEERCRED ++ struct stat statbuf; ++ time_t staletime; ++#endif ++ uid_t uid; ++ ++ /*....................................... Accept */ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sun_family = AF_UNIX; ++ ++ len = sizeof(addr); ++ if ((newfd = accept(fd, (struct sockaddr *)&addr, &len)) < 0) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_ACCEPT_FAILED, strerror(errno)); ++ return NULL; ++ } ++ ++ gpm_report(GPM_PR_INFO, GPM_MESS_CONECT_AT, newfd); ++ ++ if (!(info = malloc(sizeof(struct client_info)))) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_NO_MEM); ++ ++ request = &info->data; ++ if (get_data(newfd, request) == -1) ++ goto err; ++ ++ if (request->vc > MAX_VC) { ++ gpm_report(GPM_PR_WARN,GPM_MESS_REQUEST_ON, request->vc, MAX_VC); ++ goto err; ++ } ++ ++#ifndef SO_PEERCRED ++ if (stat(addr.sun_path, &statbuf) == -1 || !S_ISSOCK(statbuf.st_mode)) { ++ gpm_report(GPM_PR_ERR,GPM_MESS_ADDRES_NSOCKET,addr.sun_path); ++ goto err; ++ } ++ ++ unlink(addr.sun_path); /* delete socket */ ++ ++ staletime = time(0) - 30; ++ if (statbuf.st_atime < staletime || ++ statbuf.st_ctime < staletime || ++ statbuf.st_mtime < staletime) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_SOCKET_OLD); ++ goto err; ++ } ++ ++ uid = statbuf.st_uid; /* owner of socket */ ++#else ++ { ++ struct ucred sucred; ++ socklen_t credlen = sizeof(struct ucred); ++ ++ if (getsockopt(newfd, SOL_SOCKET, SO_PEERCRED, &sucred, &credlen) == -1) { ++ gpm_report(GPM_PR_ERR,GPM_MESS_GETSOCKOPT, strerror(errno)); ++ goto err; ++ } ++ uid = sucred.uid; ++ gpm_report(GPM_PR_DEBUG,GPM_MESS_PEER_SCK_UID, uid); ++ } ++#endif ++ ++ if (uid != 0 && !is_console_owner(request->vc, uid)) { ++ gpm_report(GPM_PR_WARN, GPM_MESS_FAILED_CONNECT, uid, request->vc); ++ goto err; ++ } ++ ++ /* register the connection information in the right place */ ++ info->next = cinfo[request->vc]; ++ info->fd = newfd; ++ cinfo[request->vc] = info; ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_LONG_STATUS, ++ request->pid, request->vc, request->eventMask, request->defaultMask, ++ request->minMod, request->maxMod); ++ ++ return info; ++ ++err: ++ free(info); ++ close(newfd); ++ ++ return NULL; ++} ++ ++/*-------------------------------------------------------------------*/ ++void remove_client(struct client_info *ci, int vc) ++{ ++ struct client_info *p, *prev = NULL; ++ ++ for (p = cinfo[vc]; p; prev = p, p = p->next) { ++ if (p == ci) { ++ if (!prev) /* it is on top of the stack */ ++ cinfo[vc] = p->next; ++ else ++ prev->next = p->next; ++ break; ++ } ++ } ++ if (p) free(p); ++} ++ ++/*-------------------------------------------------------------------*/ ++void notify_clients_resize(void) ++{ ++ struct client_info *ci; ++ int i; ++ ++ for (i = 0; i < MAX_VC + 1; i++) ++ for (ci = cinfo[i]; ci; ci = ci->next) ++ kill(ci->data.pid, SIGWINCH); ++} ++ ++/*-------------------------------------------------------------------*/ ++/* returns 0 if the event has not been processed, and 1 if it has */ ++int do_client(struct client_info *cinfo, Gpm_Event *event) ++{ ++ Gpm_Connect *info = &cinfo->data; ++ /* value to return if event is not used */ ++ int res = !(info->defaultMask & event->type); ++ ++ /* instead of returning 0, scan the stack of clients */ ++ if ((info->minMod & event->modifiers) < info->minMod) ++ goto try_next; ++ if ((info->maxMod & event->modifiers) < event->modifiers) ++ goto try_next; ++ ++ /* if not managed, use default mask */ ++ if (!(info->eventMask & GPM_BARE_EVENTS(event->type))) { ++ if (res) return res; ++ else goto try_next; ++ } ++ ++ /* WARNING */ /* This can generate a SIGPIPE... I'd better catch it */ ++ MAGIC_P((write(cinfo->fd, &magic, sizeof(int)))); ++ write(cinfo->fd, event, sizeof(Gpm_Event)); ++ ++ return info->defaultMask & GPM_HARD ? res : 1; /* HARD forces pass-on */ ++ ++ try_next: ++ if (cinfo->next != 0) ++ return do_client(cinfo->next, event); /* try the next */ ++ ++ return 0; /* no next, not used */ ++} ++ ++/*-------------------------------------------------------------------*/ ++/* returns 0 if client disconnects, -1 - error, 1 -successs */ ++int process_client_request(struct client_info *ci, int vc, ++ int x, int y, int buttons, int clicks, ++ int three_button_mouse) ++{ ++ int rc; ++ Gpm_Connect conn; ++ static Gpm_Event event; ++ ++ gpm_report(GPM_PR_INFO, GPM_MESS_CON_REQUEST, ci->fd, vc); ++ if (vc > MAX_VC) return -1; ++ ++ /* itz 10-22-96 this shouldn't happen now */ ++ if (vc == -1) gpm_report(GPM_PR_OOPS, GPM_MESS_UNKNOWN_FD); ++ ++ rc = get_data(ci->fd, &conn); ++ ++ if (rc == 0) { /* no data */ ++ gpm_report(GPM_PR_INFO, GPM_MESS_CLOSE); ++ close(ci->fd); ++ return 0; ++ } ++ ++ if (rc == -1) return -1; /* too few bytes */ ++ ++ if (conn.pid != 0) { ++ ci->data = conn; ++ return 1; ++ } ++ ++ /* Aha, request for information (so-called snapshot) */ ++ switch (conn.vc) { ++ case GPM_REQ_SNAPSHOT: ++ event.vc = get_console_state(&event.modifiers); ++ event.x = x; event.y = y; ++ event.buttons = buttons; ++ event.clicks = clicks; ++ event.dx = console.max_x; event.dy = console.max_y; ++ /* fall through */ ++ ++ case GPM_REQ_BUTTONS: ++ event.type = (three_button_mouse == 1 ? 3 : 2); /* buttons */ ++ write(ci->fd, &event, sizeof(Gpm_Event)); ++ break; ++ ++ case GPM_REQ_NOPASTE: ++ selection_disable_paste(); ++ gpm_report(GPM_PR_INFO, GPM_MESS_DISABLE_PASTE, vc); ++ break; ++ } ++ ++ return 1; ++} ++ +diff -urN gpm-1.20.1/src/console.c gpm/src/console.c +--- gpm-1.20.1/src/console.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/console.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,257 @@ ++/* ++ * console.c - GPM console and selection/paste handling ++ * ++ * Copyright (C) 1993 Andreq Haylett <ajh@gec-mrc.co.uk> ++ * Copyright (C) 1994-1999 Alessandro Rubini <rubini@linux.it> ++ * Copyright (C) 1998 Ian Zimmerman <itz@rahul.net> ++ * Copyright (c) 2001,2002 Nico Schottelius <nico@schottelius.org> ++ * Copyright (c) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> /* strerror(); ?!? */ ++#include <errno.h> ++#include <unistd.h> /* select(); */ ++#include <time.h> /* time() */ ++#include <sys/fcntl.h> /* O_RDONLY */ ++#include <sys/stat.h> /* mkdir() */ ++#include <asm/types.h> /* __u32 */ ++ ++#include <linux/vt.h> /* VT_GETSTATE */ ++#include <sys/kd.h> /* KDGETMODE */ ++#include <termios.h> /* winsize */ ++ ++#include "headers/gpmInt.h" ++#include "headers/console.h" ++#include "headers/message.h" ++ ++#ifndef HAVE___U32 ++# ifndef _I386_TYPES_H /* /usr/include/asm/types.h */ ++typedef unsigned int __u32; ++# endif ++#endif ++ ++struct gpm_console console = { 0, DEF_LUT, 0, 0 }; ++ ++/*-------------------------------------------------------------------*/ ++static int count_digits(int num) ++{ ++ int digits = 1; ++ ++ while ((num /= 10)) ++ digits++; ++ ++ return digits; ++} ++ ++/*-------------------------------------------------------------------*/ ++char *compose_vc_name(int vc) ++{ ++ char *tty; ++ ++ tty = malloc(strlen(console.device) + count_digits(vc) + sizeof(char)); ++ if (tty) { ++ /* console is /dev/vc/0 or /dev/tty0 and we trimming the ending 0 */ ++ strncpy(tty, console.device, strlen(console.device) - 1); ++ sprintf(&tty[strlen(console.device) - 1], "%d", vc); ++ } ++ ++ return tty; ++} ++ ++/*-------------------------------------------------------------------*/ ++int open_console(int mode) ++{ ++ int fd; ++ ++ if ((fd = open(console.device, mode)) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN_CON); ++ ++ return fd; ++} ++ ++/*-------------------------------------------------------------------*/ ++int is_text_console(void) ++{ ++ int fd; ++ int kd_mode; ++ ++ fd = open_console(O_RDONLY); ++ if (ioctl(fd, KDGETMODE, &kd_mode)<0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_IOCTL_KDGETMODE); ++ close(fd); ++ ++ return kd_mode == KD_TEXT; ++} ++ ++/*-------------------------------------------------------------------*/ ++void wait_text_console(void) ++{ ++ do { ++ sleep(2); ++ } while (!is_text_console()); ++} ++ ++/*-------------------------------------------------------------------*/ ++void refresh_console_size(void) ++{ ++ struct winsize win; ++ int fd = open_console(O_RDONLY); ++ ++ ioctl(fd, TIOCGWINSZ, &win); ++ close(fd); ++ ++ if (!win.ws_col || !win.ws_row) { ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_ZERO_SCREEN_DIM); ++ console.max_x = 80; console.max_y = 25; ++ } else { ++ console.max_x = win.ws_col; console.max_y = win.ws_row; ++ } ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_SCREEN_SIZE, console.max_x, console.max_y); ++} ++ ++/*-------------------------------------------------------------------*/ ++int get_console_state(unsigned char *shift_state) ++{ ++ struct vt_stat stat; ++ int fd; ++ ++ fd = open_console(O_RDONLY); ++ ++ *shift_state = 6; /* code for the ioctl */ ++ if (ioctl(fd, TIOCLINUX, shift_state) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_GET_SHIFT_STATE); ++ ++ if (ioctl(fd, VT_GETSTATE, &stat) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_GET_CONSOLE_STAT); ++ ++ close(fd); ++ ++ return stat.v_active; ++} ++ ++/*-------------------------------------------------------------------*/ ++int is_console_owner(int vc, uid_t uid) ++{ ++ struct stat statbuf; ++ char *tty; ++ int rc; ++ ++ if ((tty = compose_vc_name(vc)) == NULL) ++ gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); ++ ++ if ((rc = stat(tty, &statbuf)) == -1) ++ gpm_report(GPM_PR_ERR, GPM_MESS_STAT_FAILS, tty); ++ ++ free(tty); ++ ++ return rc != -1 && uid == statbuf.st_uid; ++} ++ ++/*-------------------------------------------------------------------*/ ++/* octal digit */ ++static int isodigit(const unsigned char c) ++{ ++ return ((c & ~7) == '0'); ++} ++ ++/*-------------------------------------------------------------------*/ ++/* routine to convert digits from octal notation (Andries Brouwer) */ ++static int getsym(const unsigned char *p0, unsigned char *res) ++{ ++ const unsigned char *p = p0; ++ char c; ++ ++ c = *p++; ++ if (c == '\\' && *p) { ++ c = *p++; ++ if (isodigit(c)) { ++ c -= '0'; ++ if (isodigit(*p)) c = 8*c + (*p++ - '0'); ++ if (isodigit(*p)) c = 8*c + (*p++ - '0'); ++ } ++ } ++ *res = c; ++ return (p - p0); ++} ++ ++/*-------------------------------------------------------------------*/ ++/* description missing! FIXME */ ++void console_load_lut(void) ++{ ++ extern int errno; ++ int i, c, fd; ++ unsigned char this, next; ++ static __u32 long_array[9] = { ++ 0x05050505, /* ugly, but preserves alignment */ ++ 0x00000000, /* control chars */ ++ 0x00000000, /* digits */ ++ 0x00000000, /* uppercase and '_' */ ++ 0x00000000, /* lowercase */ ++ 0x00000000, /* Latin-1 control */ ++ 0x00000000, /* Latin-1 misc */ ++ 0x00000000, /* Latin-1 uppercase */ ++ 0x00000000 /* Latin-1 lowercase */ ++ }; ++ ++#define inwordLut (long_array+1) ++ ++ for (i = 0; console.charset[i]; ) { ++ i += getsym(console.charset + i, &this); ++ if (console.charset[i] == '-' && console.charset[i + 1] != '\0') ++ i += getsym(console.charset + i + 1, &next) + 1; ++ else ++ next = this; ++ for (c = this; c <= next; c++) ++ inwordLut[c >> 5] |= 1 << (c & 0x1F); ++ } ++ ++ fd = open_console(O_WRONLY); ++ ++ if (ioctl(fd, TIOCLINUX, &long_array) < 0) { /* fd <0 is checked */ ++ if (errno == EPERM && getuid()) ++ gpm_report(GPM_PR_WARN, GPM_MESS_ROOT); /* why do we still continue?*/ ++ else if (errno == EINVAL) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_CSELECT); ++ } ++ close(fd); ++} ++ ++/*-------------------------------------------------------------------*/ ++/* Returns the name of the console (/dev/tty0 or /dev/vc/0) */ ++/* Also fills console.device */ ++char *get_console_name() ++{ ++ struct stat buf; ++ ++ /* first try the devfs device, because in the next time this will be ++ * the preferred one. If that fails, take the old console */ ++ ++ /* Check for open new console */ ++ if (stat(GPM_DEVFS_CONSOLE, &buf) == 0) ++ console.device = GPM_DEVFS_CONSOLE; ++ ++ /* Failed, try OLD console */ ++ else if (stat(GPM_OLD_CONSOLE, &buf) == 0) ++ console.device = GPM_OLD_CONSOLE; ++ else ++ gpm_report(GPM_PR_OOPS, "Can't determine console device"); ++ ++ return console.device; ++} ++ +diff -urN gpm-1.20.1/src/evdev.c gpm/src/evdev.c +--- gpm-1.20.1/src/evdev.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/evdev.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,851 @@ ++/* ++ * evdev.c - support for event input devices in linux 2.4 & 2.6 ++ * ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * Based on XFree86 driver by Stefan Gmeiner & Peter Osterlund ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <string.h> ++#include <time.h> ++#include <sys/select.h> ++#include <sys/time.h> ++ ++#include <linux/input.h> ++#include "headers/input-defines.h" /* misisng bits in case <linux/input.h> is old */ ++ ++#include "headers/gpm.h" ++#include "headers/gpmInt.h" ++#include "headers/console.h" ++#include "headers/message.h" ++#include "headers/optparser.h" ++ ++enum evdev_type { ++ EVDEV_UNKNOWN, ++ EVDEV_RELATIVE, ++ EVDEV_ABSOLUTE, ++ EVDEV_TOUCHPAD, ++ EVDEV_SYNAPTICS ++}; ++ ++enum touch_type { ++ TOUCH_NONE, ++ TOUCH_FINGERS, ++ TOUCH_PALM ++}; ++ ++enum gesture_type { ++ GESTURE_NONE, ++ GESTURE_TAP_PENDING, ++ GESTURE_TAP, ++ GESTURE_DRAG_PENDING, ++ GESTURE_DRAG, ++ GESTURE_DOUBLE_TAP ++}; ++ ++enum edge_type { ++ BOTTOM_EDGE = 1, ++ TOP_EDGE = 2, ++ LEFT_EDGE = 4, ++ RIGHT_EDGE = 8, ++ LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE, ++ RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE, ++ RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE, ++ LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE ++}; ++ ++struct event_data { ++ int dx, dy; ++ int wdx, wdy; ++ int abs_x, abs_y; ++ int buttons; ++ int touch; /* dumb touchpad report touch events, smart ones - pressure */ ++ int pressure; ++ int w; ++ int finger_count; ++ int synced; ++}; ++ ++struct touch_data { ++ int touching; ++ int x, y; ++ int finger_count; ++ int buttons; ++ int clicks; ++ struct timeval start; ++ enum gesture_type gesture; ++}; ++ ++struct event_device { ++ enum evdev_type type; ++ int dont_sync; ++ ++ struct event_data pkt; ++ int pkt_count; ++ ++ int prev_x[4], prev_y[4]; ++ int prev_pressure, avg_w; ++ struct touch_data touch; ++ ++ int left_edge, right_edge; ++ int top_edge, bottom_edge; ++ int touch_high, touch_low; ++ int tap_time, tap_move; ++ int y_inverted; ++ ++ enum touch_type (*detect_touch)(struct event_device *evdev); ++ void (*update_finger_count)(struct event_device *evdev); ++}; ++ ++struct evdev_capabilities { ++ unsigned char evbits[EV_MAX/8 + 1]; ++ unsigned char keybits[KEY_MAX/8 + 1]; ++ unsigned char absbits[ABS_MAX/8 + 1]; ++ unsigned char mscbits[MSC_MAX/8 + 1]; ++}; ++ ++#ifndef max ++#define max(a,b) ((a)>(b) ? (a) : (b)) ++#endif ++ ++#define fx(i) (evdev->prev_x[(evdev->pkt_count - (i)) & 03]) ++#define fy(i) (evdev->prev_y[(evdev->pkt_count - (i)) & 03]) ++ ++#define toggle_btn(btn, val) do { if (val) data->buttons |= (btn);\ ++ else data->buttons &= ~(btn);\ ++ } while (0) ++#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL)) ++#define DIF_TIME(t1,t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec) / 1000) ++ ++#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) ++ ++/* ------------- evdev protocol handling routines ---------------------*/ ++ ++static void parse_input_event(struct input_event *event, struct event_data *data) ++{ ++ switch (event->type) { ++ case EV_REL: ++ switch (event->code) { ++ case REL_X: ++ data->dx = (signed char)event->value; ++ break; ++ case REL_Y: ++ data->dy = (signed char)event->value; ++ break; ++ case REL_WHEEL: ++ data->wdy += event->value; ++ break; ++ case REL_HWHEEL: ++ data->wdx += event->value; ++ break; ++ } ++ break; ++ ++ case EV_ABS: ++ switch (event->code) { ++ case ABS_X: ++ data->abs_x = event->value; ++ break; ++ ++ case ABS_Y: ++ data->abs_y = event->value; ++ break; ++ ++ case ABS_PRESSURE: ++ data->pressure = event->value; ++ break; ++ ++ case ABS_TOOL_WIDTH: ++ data->w = event->value; ++ break; ++ } ++ break; ++ ++ case EV_MSC: ++ switch (event->code) { ++ case MSC_GESTURE: ++ data->w = event->value; ++ break; ++ } ++ break; ++ ++ ++ case EV_KEY: ++ switch(event->code) { ++ case BTN_0: ++ case BTN_LEFT: ++ toggle_btn(GPM_B_LEFT, event->value); ++ break; ++ ++ case BTN_2: ++ case BTN_STYLUS2: ++ case BTN_SIDE: ++ case BTN_MIDDLE: ++ toggle_btn(GPM_B_MIDDLE, event->value); ++ break; ++ ++ case BTN_STYLUS: ++ case BTN_1: ++ case BTN_RIGHT: ++ toggle_btn(GPM_B_RIGHT, event->value); ++ break; ++ ++ case BTN_TOUCH: ++ data->touch = event->value ? 1 : 0; ++ break; ++ ++ case BTN_TOOL_FINGER: ++ if (event->value) data->finger_count = 1; ++ break; ++ ++ case BTN_TOOL_DOUBLETAP: ++ if (event->value) data->finger_count = 2; ++ break; ++ ++ case BTN_TOOL_TRIPLETAP: ++ if (event->value) data->finger_count = 3; ++ break; ++ ++ } ++ break; ++ ++ case EV_SYNC: ++ switch(event->code) { ++ case SYN_REPORT: ++ data->synced = 1; ++ break; ++ } ++ break; ++ } ++} ++ ++static void tp_figure_deltas(struct event_device *evdev, struct Gpm_Event *state) ++{ ++ struct event_data *pkt = &evdev->pkt; ++ ++ state->dx = state->dy = 0; ++ if (evdev->touch.touching) { ++ fx(0) = pkt->abs_x; ++ fy(0) = pkt->abs_y; ++ if (evdev->pkt_count >= 2 && ++ evdev->touch.gesture != GESTURE_DRAG_PENDING) { ++ state->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; //SYN_REL_DECEL_FACTOR; ++ state->dy = ((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; //SYN_REL_DECEL_FACTOR; ++ } ++ evdev->pkt_count++; ++ } else { ++ evdev->pkt_count = 0; ++ } ++} ++ ++static enum touch_type dumb_tp_detect_touch(struct event_device *evdev) ++{ ++ return evdev->pkt.touch ? TOUCH_FINGERS : TOUCH_NONE; ++} ++ ++static enum touch_type smart_tp_detect_touch(struct event_device *evdev) ++{ ++ if (evdev->touch.touching) ++ return evdev->pkt.pressure > evdev->touch_low ? TOUCH_FINGERS : TOUCH_NONE; ++ else ++ return evdev->pkt.pressure > evdev->touch_high ? TOUCH_FINGERS : TOUCH_NONE; ++} ++ ++static enum touch_type syn_detect_touch(struct event_device *evdev) ++{ ++ struct event_data *pkt = &evdev->pkt; ++ enum touch_type type = TOUCH_NONE; ++ ++ if (pkt->pressure > 200 || pkt->w > 10) ++ return TOUCH_PALM; ++ ++ if (pkt->abs_x == 0) ++ evdev->avg_w = 0; ++ else ++ evdev->avg_w = (pkt->w - evdev->avg_w + 1) / 2; ++ ++ if (evdev->touch.touching) { ++ type = pkt->pressure > evdev->touch_low ? TOUCH_FINGERS : TOUCH_NONE; ++ } else if (pkt->pressure > evdev->touch_high) { ++ int safe_w = max(pkt->w, evdev->avg_w); ++ ++ if (pkt->finger_count > 1) ++ type = TOUCH_FINGERS; ++ else if (pkt->w < 2) ++ type = TOUCH_FINGERS; /* more than one finger -> not a palm */ ++ else if (safe_w < 6 && evdev->prev_pressure < evdev->touch_high) ++ type = TOUCH_FINGERS; /* thin finger, distinct touch -> not a palm */ ++ else if (safe_w < 7 && evdev->prev_pressure < evdev->touch_high / 2) ++ type = TOUCH_FINGERS; /* thin finger, distinct touch -> not a palm */ ++ else if (pkt->pressure > evdev->prev_pressure + 1) ++ type = TOUCH_NONE; /* pressure not stable, may be a palm */ ++ else if (pkt->pressure < evdev->prev_pressure - 5) ++ type = TOUCH_NONE; /* pressure not stable, may be a palm */ ++ else ++ type = TOUCH_FINGERS; ++ } ++ ++ evdev->prev_pressure = pkt->pressure; ++ return type; ++} ++ ++static enum edge_type tp_detect_edges(struct event_device *evdev, int x, int y) ++{ ++ enum edge_type edge = 0; ++ ++ if (x > evdev->right_edge) ++ edge |= RIGHT_EDGE; ++ else if (x < evdev->left_edge) ++ edge |= LEFT_EDGE; ++ ++ if (y < evdev->top_edge) ++ edge |= TOP_EDGE; ++ else if (y > evdev->bottom_edge) ++ edge |= BOTTOM_EDGE; ++ ++ return edge; ++} ++ ++static int tp_touch_expired(struct event_device *evdev) ++{ ++ struct timeval now; ++ ++ GET_TIME(now); ++ return DIF_TIME(evdev->touch.start, now) > evdev->tap_time; ++} ++ ++static int tp_detect_tap(struct event_device *evdev) ++{ ++ return !tp_touch_expired(evdev) && ++ (evdev->touch.finger_count > 1 || ++ (abs(evdev->pkt.abs_x - evdev->touch.x) < evdev->tap_move && ++ abs(evdev->pkt.abs_y - evdev->touch.y) < evdev->tap_move)); ++} ++ ++static int tp_tap_to_buttons(struct event_device *evdev) ++{ ++ enum edge_type edge; ++ if (evdev->touch.finger_count < 2) { ++ edge = tp_detect_edges(evdev, evdev->pkt.abs_x, evdev->pkt.abs_y); ++ switch (edge) { ++ case RIGHT_TOP_EDGE: ++ return GPM_B_MIDDLE; ++ break; ++ case RIGHT_BOTTOM_EDGE: ++ return GPM_B_RIGHT; ++ break; ++ default: ++ return GPM_B_LEFT; ++ break; ++ } ++ } else { ++ switch (evdev->touch.finger_count) { ++ case 2: ++ return GPM_B_MIDDLE; ++ case 3: ++ return GPM_B_RIGHT; ++ default: ++ return GPM_B_LEFT; ++ } ++ } ++} ++ ++static void tp_detect_gesture(struct event_device *evdev, int timed_out, enum touch_type touch_type) ++{ ++ struct touch_data *touch = &evdev->touch; ++ int was_touching = touch->touching; ++ ++ touch->touching = touch_type == TOUCH_FINGERS; ++ ++ if (touch->touching) { ++ if (!was_touching) { ++ GET_TIME(touch->start); ++ touch->finger_count = 0; ++ if (touch->gesture == GESTURE_TAP_PENDING) { ++ touch->gesture = GESTURE_DRAG_PENDING; ++ } else { ++ touch->x = evdev->pkt.abs_x; ++ touch->y = evdev->pkt.abs_y; ++ touch->buttons = 0; ++ } ++ } else if (touch->gesture == GESTURE_DRAG_PENDING && tp_touch_expired(evdev)) { ++ touch->gesture = GESTURE_DRAG; ++ } ++ } else { ++ if (was_touching) { ++ if (tp_detect_tap(evdev)) { ++ if (touch->gesture == GESTURE_DRAG_PENDING) { ++ touch->gesture = GESTURE_DOUBLE_TAP; ++ touch->clicks = 4; ++ } else { ++ if ((touch->buttons = tp_tap_to_buttons(evdev)) == GPM_B_LEFT) { ++ touch->gesture = GESTURE_TAP_PENDING; ++ } else { ++ touch->gesture = GESTURE_TAP; ++ touch->clicks = 2; ++ } ++ } ++ } else { ++ touch->gesture = GESTURE_NONE; ++ } ++ } else { ++ if (touch->gesture == GESTURE_TAP_PENDING && tp_touch_expired(evdev)) { ++ touch->gesture = GESTURE_TAP; ++ touch->clicks = 2; ++ } ++ } ++ } ++} ++ ++static int tp_process_gesture(struct event_device *evdev, struct Gpm_Event *state) ++{ ++ int next_timeout = -1; ++ ++ switch(evdev->touch.gesture) { ++ case GESTURE_DOUBLE_TAP: ++ case GESTURE_TAP: ++ if (--evdev->touch.clicks == 0) ++ evdev->touch.gesture = GESTURE_NONE; ++ else ++ next_timeout = 0; ++ ++ if (evdev->touch.clicks % 2) ++ state->buttons |= evdev->touch.buttons; ++ else ++ state->buttons &= ~evdev->touch.buttons; ++ break; ++ ++ case GESTURE_DRAG: ++ state->buttons |= evdev->touch.buttons; ++ break; ++ ++ case GESTURE_DRAG_PENDING: ++ case GESTURE_TAP_PENDING: ++ next_timeout = evdev->tap_time; ++ break; ++ ++ default: ++ break; ++ } ++ return next_timeout; ++} ++ ++static void tp_update_finger_count(struct event_device *evdev) ++{ ++ evdev->touch.finger_count = max(evdev->pkt.finger_count, evdev->touch.finger_count); ++} ++ ++static void syn_update_finger_count(struct event_device *evdev) ++{ ++ if (evdev->pkt.w == 1) ++ evdev->touch.finger_count = 3; ++ else if (evdev->pkt.w == 0 && evdev->touch.finger_count != 3) ++ evdev->touch.finger_count = 2; ++ else ++ evdev->touch.finger_count = 1; ++} ++ ++static int compose_gpm_event(struct event_device *evdev, int timed_out, Gpm_Event *state) ++{ ++ struct event_data *pkt = &evdev->pkt; ++ enum touch_type touch_type; ++ int next_timeout = -1; ++ ++ if (!timed_out) { ++ state->buttons = pkt->buttons; ++ state->wdx = pkt->wdx; state->wdy = pkt->wdy; ++ } ++ ++ switch (evdev->type) { ++ case EVDEV_RELATIVE: ++ if (!timed_out) { ++ state->dx = pkt->dx; state->dy = pkt->dy; ++ if (evdev->pkt.touch) ++ state->buttons |= GPM_B_LEFT; ++ else ++ state->buttons &= ~GPM_B_LEFT; ++ } ++ break; ++ ++ case EVDEV_ABSOLUTE: ++ if (!timed_out) { ++ if (pkt->abs_x < evdev->left_edge) ++ pkt->abs_x = evdev->left_edge; ++ else if (pkt->abs_x > evdev->right_edge) ++ pkt->abs_x = evdev->right_edge; ++ ++ if (pkt->abs_y > evdev->bottom_edge) ++ pkt->abs_y = evdev->bottom_edge; ++ else if (pkt->abs_y < evdev->top_edge) ++ pkt->abs_y = evdev->top_edge; ++ ++ state->x = (pkt->abs_x - evdev->left_edge) * ++ console.max_x / (evdev->right_edge - evdev->left_edge); ++ state->y = (pkt->abs_y - evdev->top_edge) * ++ console.max_y / (evdev->bottom_edge - evdev->top_edge); ++ ++ if (evdev->y_inverted) state->y = console.max_y - state->y; ++ ++ if (evdev->pkt.touch) ++ state->buttons |= GPM_B_LEFT; ++ else ++ state->buttons &= ~GPM_B_LEFT; ++ } ++ break; ++ ++ case EVDEV_TOUCHPAD: ++ case EVDEV_SYNAPTICS: ++ touch_type = timed_out ? TOUCH_NONE : evdev->detect_touch(evdev); ++ ++ if (touch_type != TOUCH_PALM) { ++ tp_detect_gesture(evdev, timed_out, touch_type); ++ ++ if (evdev->touch.touching && !tp_touch_expired(evdev)) ++ evdev->update_finger_count(evdev); ++ ++ if (evdev->touch.finger_count < 2) ++ tp_figure_deltas(evdev, state); ++ ++ next_timeout = tp_process_gesture(evdev, state); ++ } ++ break; ++ ++ default: ++ /* should not happen */ ++ gpm_report(GPM_PR_OOPS, "Bad evdev type %d", evdev->type); ++ break; ++ } ++ ++ if (evdev->y_inverted) state->dy = -state->dy; ++ ++ return next_timeout; ++} ++ ++int M_evdev(struct micedev *dev, struct miceopt *opts, ++ unsigned char *data, struct Gpm_Event *state) ++{ ++ struct event_device *evdev = dev->private; ++ struct input_event *event = (struct input_event *)data; ++ int timed_out = data == NULL; ++ ++ if (!timed_out) ++ parse_input_event(event, &evdev->pkt); ++ ++ if (timed_out || evdev->pkt.synced || evdev->dont_sync) { ++ dev->timeout = compose_gpm_event(evdev, timed_out, state); ++ evdev->pkt.dx = evdev->pkt.dy = 0; ++ evdev->pkt.wdx = evdev->pkt.wdy = 0; ++ evdev->pkt.finger_count = 0; ++ evdev->pkt.synced = 0; ++ return 0; ++ } ++ ++ dev->timeout = -1; ++ return -1; ++} ++ ++/* ------------- evdev initialization routines ---------------------*/ ++ ++static int evdev_get_id(int fd, struct input_id *id) ++{ ++ if (ioctl(fd, EVIOCGID, id) < 0) { ++ gpm_report(GPM_PR_ERR, "evdev: cannot query device identification"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int evdev_get_capabilities(int fd, struct evdev_capabilities *caps) ++{ ++ memset(caps, 0, sizeof(*caps)); ++ ++ if (ioctl(fd, EVIOCGBIT(0, EV_MAX), caps->evbits) < 0) { ++ gpm_report(GPM_PR_ERR, "evdev: cannot query device capabilities"); ++ return -1; ++ } ++ ++ if (test_bit(EV_ABS, caps->evbits) && ++ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(caps->absbits)), caps->absbits) < 0) { ++ gpm_report(GPM_PR_ERR, "evdev: cannot query ABS device capabilities"); ++ return -1; ++ } ++ ++ if (test_bit(EV_KEY, caps->evbits) && ++ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(caps->keybits)), caps->keybits) < 0) { ++ gpm_report(GPM_PR_ERR, "evdev: cannot query KEY device capabilities"); ++ return -1; ++ } ++ ++ if (test_bit(EV_MSC, caps->evbits) && ++ ioctl(fd, EVIOCGBIT(EV_MSC, sizeof(caps->mscbits)), caps->mscbits) < 0) { ++ /* don't complain as 2.4 kernels didnt have it ++ gpm_report(GPM_PR_ERR, "evdev: cannot query MSC device capabilities"); ++ return -1; ++ */ ++ } ++ return 0; ++} ++ ++static int evdev_query_axis(int fd, int axis, int *axis_min, int *axis_max) ++{ ++ struct input_absinfo axis_info; ++ ++ if (ioctl(fd, EVIOCGABS(axis), &axis_info) == -1) { ++ gpm_report(GPM_PR_ERR, "evdev: could not query axis data"); ++ return -1; ++ } ++ ++ *axis_min = axis_info.minimum; ++ *axis_max = axis_info.maximum; ++ return 0; ++} ++ ++static int evdev_get_limits(int fd, struct event_device *evdev, ++ struct evdev_capabilities *caps) ++{ ++ if (test_bit(ABS_X, caps->absbits) && ++ evdev_query_axis(fd, ABS_X, &evdev->left_edge, &evdev->right_edge) < 0) ++ return -1; ++ ++ if (test_bit(ABS_Y, caps->absbits) && ++ evdev_query_axis(fd, ABS_Y, &evdev->top_edge, &evdev->bottom_edge) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int is_synaptics(struct input_id *id) ++{ ++ return id->bustype == BUS_I8042 && id->vendor == 0x0002 && id->product == PSMOUSE_SYNAPTICS; ++} ++ ++static enum evdev_type evdev_guess_type(struct input_id *id, struct evdev_capabilities *caps) ++{ ++ if (test_bit(EV_ABS, caps->evbits)) { ++ if (is_synaptics(id)) ++ return EVDEV_SYNAPTICS; ++ ++ if (test_bit(BTN_TOUCH, caps->keybits) && caps->keybits[BTN_MOUSE / 8]) ++ return EVDEV_TOUCHPAD; ++ ++ return EVDEV_ABSOLUTE; ++ } ++ ++ if (!test_bit(EV_REL, caps->evbits)) { ++ gpm_report(GPM_PR_ERR, ++ "evdev: device does not report neither absolute nor relative coordinates"); ++ return EVDEV_UNKNOWN; ++ } ++ ++ return EVDEV_RELATIVE; ++} ++ ++static enum evdev_type evdev_str_to_type(const char *type) ++{ ++ if (!strcmp(type, "relative")) { ++ return EVDEV_RELATIVE; ++ } else if (!strcmp(type, "absolute")) { ++ return EVDEV_ABSOLUTE; ++ } else if (!strcmp(type, "touchpad")) { ++ return EVDEV_TOUCHPAD; ++ } else if (!strcmp(type, "synaptics")) { ++ return EVDEV_SYNAPTICS; ++ } else { ++ gpm_report(GPM_PR_ERR, "evdev: unknown type '%s'", type); ++ return EVDEV_UNKNOWN; ++ } ++} ++ ++static void warn_if_present(struct option_helper *optinfo, const char *name, const char *type) ++{ ++ if (is_option_present(optinfo, name)) ++ gpm_report(GPM_PR_WARN, ++ "evdev: option '%s' is not valud for type '%s', ignored", ++ name, type); ++} ++ ++// -o type=(auto|synaptics|touchpad|relative|absolute),y_inverse, ++// left=1234,right=1234,top=1234,bottom=1234, ++// touch_high=30,touch_low=25,tap_time=30,tap_move=100 ++static int evdev_apply_options(struct event_device *evdev, char *optstring) ++{ ++ char *type = "auto"; ++ struct option_helper optinfo[] = { ++ { "type", OPT_STRING, u: { sptr: &type } }, ++ { "y_inverted", OPT_BOOL, u: { iptr: &evdev->y_inverted }, value: 1 }, ++ { "left", OPT_INT, u: { iptr: &evdev->left_edge } }, ++ { "right", OPT_INT, u: { iptr: &evdev->right_edge } }, ++ { "top", OPT_INT, u: { iptr: &evdev->top_edge } }, ++ { "bottom", OPT_INT, u: { iptr: &evdev->bottom_edge } }, ++ { "touch_high", OPT_INT, u: { iptr: &evdev->touch_high } }, ++ { "touch_low", OPT_INT, u: { iptr: &evdev->touch_low } }, ++ { "tap_time", OPT_INT, u: { iptr: &evdev->tap_time } }, ++ { "tap_move", OPT_INT, u: { iptr: &evdev->tap_move } }, ++ { "", OPT_END } ++ }; ++ ++ if (parse_options("evdev", optstring, ',', optinfo) < 0) ++ return -1; ++ ++ if (strcmp(type, "auto")) ++ evdev->type = evdev_str_to_type(type); ++ ++ switch (evdev->type) { ++ case EVDEV_RELATIVE: ++ warn_if_present(optinfo, "left", type); ++ warn_if_present(optinfo, "right", type); ++ warn_if_present(optinfo, "top", type); ++ warn_if_present(optinfo, "bottom", type); ++ warn_if_present(optinfo, "tap_move", type); ++ warn_if_present(optinfo, "tap_time", type); ++ warn_if_present(optinfo, "touch_high", type); ++ warn_if_present(optinfo, "touch_low", type); ++ break; ++ ++ case EVDEV_ABSOLUTE: ++ warn_if_present(optinfo, "tap_move", type); ++ warn_if_present(optinfo, "tap_time", type); ++ warn_if_present(optinfo, "touch_high", type); ++ warn_if_present(optinfo, "touch_low", type); ++ break; ++ ++ case EVDEV_TOUCHPAD: ++ break; ++ ++ case EVDEV_SYNAPTICS: ++ warn_if_present(optinfo, "y_inverted", type); ++ break; ++ ++ default: ++ return -1; ++ } ++ return 0; ++} ++ ++int I_evdev(struct micedev *dev, struct miceopt *opts, Gpm_Type *type) ++{ ++ struct input_id id; ++ struct evdev_capabilities caps; ++ struct event_device *evdev; ++ ++ if (!dev->private) { /* called first time, not re-init */ ++ if (!(dev->private = evdev = malloc(sizeof(*evdev)))) ++ gpm_report(GPM_PR_OOPS, "Can't allocate memory for event device"); ++ ++ memset(evdev, 0, sizeof(*evdev)); ++ ++ if (evdev_get_id(dev->fd, &id)) ++ goto init_fail; ++ ++ if (evdev_get_capabilities(dev->fd, &caps)) ++ goto init_fail; ++ ++ evdev->type = evdev_guess_type(&id, &caps); ++ ++ /* load default values - suitable for my synaptics ;P */ ++ evdev->left_edge = 1900; ++ evdev->right_edge = 5300; ++ evdev->top_edge = 2000; ++ evdev->bottom_edge = 3900; ++ evdev->tap_time = 180; ++ evdev->tap_move = 220; ++ evdev->touch_high = 30; ++ evdev->touch_low = 25; ++ ++ if (evdev->type == EVDEV_ABSOLUTE && evdev_get_limits(dev->fd, evdev, &caps) < 0) ++ goto init_fail; ++ ++ if (evdev_apply_options(evdev, opts->text) < 0) ++ goto init_fail; ++ ++ if (!test_bit(EV_SYNC, caps.evbits)) { ++ evdev->dont_sync = 1; ++ if (evdev->type == EVDEV_TOUCHPAD || evdev->type == EVDEV_SYNAPTICS) { ++ gpm_report(GPM_PR_ERR, ++ "evdev: The running kernel lacks EV_SYNC support which is required for touchpad/synaptics mode"); ++ goto init_fail; ++ } ++ } ++ ++ switch (evdev->type) { ++ case EVDEV_RELATIVE: ++ gpm_report(GPM_PR_INFO, "evdev: selected Relative mode"); ++ if (!test_bit(EV_REL, caps.evbits)) ++ gpm_report(GPM_PR_WARN, "evdev: selected relative mode but device does not report any relative events"); ++ break; ++ ++ case EVDEV_ABSOLUTE: ++ gpm_report(GPM_PR_INFO, "evdev: selected Absolute mode"); ++ if (evdev->right_edge <= evdev->left_edge) { ++ gpm_report(GPM_PR_ERR, "evdev: right edge value should be gerater than left"); ++ goto init_fail; ++ } ++ if (evdev->bottom_edge <= evdev->top_edge) { ++ gpm_report(GPM_PR_ERR, "evdev: bottom edge value should be gerater than top"); ++ goto init_fail; ++ } ++ if (!test_bit(EV_ABS, caps.evbits)) ++ gpm_report(GPM_PR_WARN, "evdev: selected absolute mode but device does not report any absolute events"); ++ opts->absolute = 1; ++ break; ++ ++ case EVDEV_TOUCHPAD: ++ gpm_report(GPM_PR_INFO, "evdev: selected Touchpad mode"); ++ if (!test_bit(EV_ABS, caps.evbits)) ++ gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report any absolute events"); ++ if (test_bit(ABS_PRESSURE, caps.absbits)) ++ evdev->detect_touch = smart_tp_detect_touch; ++ else if (test_bit(BTN_TOUCH, caps.keybits)) ++ evdev->detect_touch = dumb_tp_detect_touch; ++ else ++ gpm_report(GPM_PR_WARN, "evdev: selected touchpad mode but device does not report pressure not touch events"); ++ evdev->update_finger_count = tp_update_finger_count; ++ break; ++ ++ case EVDEV_SYNAPTICS: ++ gpm_report(GPM_PR_INFO, "evdev: selected Synaptics mode"); ++ if (!is_synaptics(&id)) ++ gpm_report(GPM_PR_WARN, "evdev: idevice isn't identified as Synaptics"); ++ if (!test_bit(EV_ABS, caps.evbits)) ++ gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report any absolute events"); ++ if (!test_bit(ABS_PRESSURE, caps.absbits)) ++ gpm_report(GPM_PR_WARN, "evdev: selected synaptics mode but device does not report pressure"); ++ if (test_bit(EV_MSC, caps.evbits) && test_bit(MSC_GESTURE, caps.mscbits)) { ++ /* this is compatibility mode with pre 2.6-test6 kernels */ ++ evdev->update_finger_count = syn_update_finger_count; ++ evdev->y_inverted = 1; ++ } else { ++ evdev->update_finger_count = tp_update_finger_count; ++ } ++ evdev->detect_touch = syn_detect_touch; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++ ++init_fail: ++ free(dev->private); ++ return -1; ++} ++ +diff -urN gpm-1.20.1/src/gpm.c gpm/src/gpm.c +--- gpm-1.20.1/src/gpm.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/gpm.c 2003-10-02 01:22:42.000000000 -0500 +@@ -24,1108 +24,607 @@ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> /* strerror(); ?!? */ ++#include <limits.h> + #include <errno.h> + #include <unistd.h> /* select(); */ + #include <signal.h> /* SIGPIPE */ + #include <time.h> /* time() */ +-#include <sys/param.h> + #include <sys/fcntl.h> /* O_RDONLY */ + #include <sys/wait.h> /* wait() */ +-#include <sys/stat.h> /* mkdir() */ + #include <sys/time.h> /* timeval */ +-#include <sys/types.h> /* socket() */ +-#include <sys/socket.h> /* socket() */ +-#include <sys/un.h> /* struct sockaddr_un */ +- +-#include <linux/vt.h> /* VT_GETSTATE */ +-#include <sys/kd.h> /* KDGETMODE */ +-#include <termios.h> /* winsize */ + + #include "headers/gpmInt.h" + #include "headers/message.h" +- +-/* who the f*** runs gpm without glibc? doesn't have dietlibc __socklent_t? */ +-#if !defined(__GLIBC__) +- typedef unsigned int __socklen_t; +-#endif /* __GLIBC__ */ ++#include "headers/console.h" ++#include "headers/selection.h" ++#include "headers/client.h" + + #ifndef max + #define max(a,b) ((a)>(b) ? (a) : (b)) + #endif + +-extern int errno; +- +-static void gpm_killed(int); +- +-/* +- * all the values duplicated for dual-mouse operation are +- * now in this structure (see gpmInt.h) +- * mouse_table[0] is single mouse, mouse_table[1] and mouse_table[2] +- * are copied data from mouse_table[0] for dual mouse operation. +- */ +- +-struct mouse_features mouse_table[3] = { +- { +- DEF_TYPE, DEF_DEV, DEF_SEQUENCE, +- DEF_BAUD, DEF_SAMPLE, DEF_DELTA, DEF_ACCEL, DEF_SCALE, 0 /* scaley */, +- DEF_TIME, DEF_CLUSTER, DEF_THREE, DEF_GLIDEPOINT_TAP, +- (char *)NULL /* extra */, +- (Gpm_Type *)NULL, +- -1 +- } +-}; +-struct mouse_features *which_mouse; +- +-/* These are only the 'global' options */ +- +-char *opt_lut=DEF_LUT; +-int opt_test=DEF_TEST; +-int opt_ptrdrag=DEF_PTRDRAG; +-int opt_double=0; +-int opt_aged = 0; +-char *opt_special=NULL; /* special commands, like reboot or such */ +-int opt_rawrep=0; +-Gpm_Type *repeated_type=0; +- +-static int opt_resize=0; /* not really an option */ +-struct winsize win; +-int maxx, maxy; +-int fifofd=-1; +- +-int eventFlag=0; +-Gpm_Cinfo *cinfo[MAX_VC+1]; +-fd_set selSet, readySet, connSet; +- +-time_t last_selection_time; +-time_t opt_age_limit = 0; +- +-/* BRAINDEAD..ok not really, but got to leave anyway... FIXME */ +-/* argc and argv for mice initialization */ +-static int mouse_argc[3]; /* 0 for default (unused) and two mice */ +-static char **mouse_argv[3]; /* 0 for default (unused) and two mice */ +- +-/*===================================================================*/ +-/* +- * first, all the stuff that used to be in gpn.c (i.e., not main-loop) +- */ +-/*-------------------------------------------------------------------*/ ++#ifndef min ++#define min(a,b) ((a)<(b) ? (a) : (b)) ++#endif + +-/* build_argv is used for mouse initialization routines */ +-static char **build_argv(char *argv0, char *str, int *argcptr, char sep) +-{ +- int argc = 1; +- char **argv; +- char *s; +- +- /* argv0 is never NULL, but the extra string may well be */ +- if (str) +- for (s=str; sep && (s = strchr(s, sep)); argc++) s++; +- +- argv = calloc(argc+2, sizeof(char **)); +- if (!argv) gpm_report(GPM_PR_OOPS,GPM_MESS_ALLOC_FAILED); +- argv[0] = argv0; +- +- if (!str) { +- *argcptr = argc; /* 1 */ +- return argv; +- } +- /* else, add arguments */ +- s = argv[1] = strdup(str); +- argc = 2; /* first to fill */ +- +- /* ok, now split: the first one is in place, and s is the whole string */ +- for ( ; sep && (s = strchr(s, sep)) ; argc++) { +- *s = '\0'; +- s++; +- argv[argc] = s; +- } +- *argcptr = argc; +- return argv; +-} ++#define NULL_SET ((fd_set *)NULL) ++#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL)) ++#define DIF_TIME(t1,t2) ((t2.tv_sec - t1.tv_sec)*1000 + (t2.tv_usec - t1.tv_usec)/1000) + +-/*-------------------------------------------------------------------*/ +-/* The old console option is removed. We are taking stderr now +- * In the next update there should also be support for syslog +- ********************************************************************/ + +-static inline int open_console(const int mode) +-{ +- int fd; ++enum mouse_rslt { MOUSE_NO_DATA, MOUSE_DATA_OK, MOUSE_MORE_DATA }; + +- if ((fd=open(option.consolename, mode)) < 0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON); +- return fd; +-} ++extern int errno; + +-/*-------------------------------------------------------------------*/ +-static inline int wait_text(int *fdptr) +-{ +- int fd; +- int kd_mode; ++char *opt_special=NULL; /* special commands, like reboot or such */ ++struct repeater repeater; + +- close(*fdptr); +- do +- { +- sleep(2); +- fd = open_console(O_RDONLY); +- if (ioctl(fd, KDGETMODE, &kd_mode)<0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_KDGETMODE); +- close(fd); +- } +- while (kd_mode != KD_TEXT) ; +- +- /* reopen, reinit (the function is only used if we have one mouse device) */ +- if ((*fdptr=open(opt_dev,O_RDWR))<0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,opt_dev); +- if (m_type->init) +- m_type=(m_type->init)(*fdptr, m_type->flags, m_type, mouse_argc[1], +- mouse_argv[1]); +- return (1); +-} ++static int console_resized; /* not really an option */ + + /*-------------------------------------------------------------------*/ +-static inline void selection_copy(int x1, int y1, int x2, int y2, int mode) ++static void gpm_killed(int signo) + { +-/* +- * The approach in "selection" causes a bus error when run under SunOS 4.1 +- * due to alignment problems... +- */ +- unsigned char buf[6*sizeof(short)]; +- unsigned short *arg = (unsigned short *)buf + 1; +- int fd; +- +- buf[sizeof(short)-1] = 2; /* set selection */ +- +- arg[0]=(unsigned short)x1; +- arg[1]=(unsigned short)y1; +- arg[2]=(unsigned short)x2; +- arg[3]=(unsigned short)y2; +- arg[4]=(unsigned short)mode; +- +- if ((fd=open_console(O_WRONLY))<0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON); +- /* FIXME: should be replaced with string constant (headers/message.h) */ +- gpm_report(GPM_PR_DEBUG,"ctl %i, mode %i",(int)*buf, arg[4]); +- if (ioctl(fd, TIOCLINUX, buf+sizeof(short)-1) < 0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX); +- close(fd); +- +- if (mode < 3) { +- opt_aged = 0; +- last_selection_time = time(0); ++ if (signo == SIGWINCH) { ++ gpm_report(GPM_PR_WARN, GPM_MESS_RESIZING, option.progname, getpid()); ++ console_resized = 1; ++ } else { ++ if (signo == SIGUSR1) ++ gpm_report(GPM_PR_WARN, GPM_MESS_KILLED_BY, option.progname, getpid(), option.progname); ++ exit(0); + } + } + +- +-/*-------------------------------------------------------------------*/ +-/* comment missing; FIXME */ +-/*-------------------------------------------------------------------*/ +-static inline void selection_paste(void) +-{ +- char c=3; +- int fd; +- +- if (!opt_aged && (0 != opt_age_limit) && +- (last_selection_time + opt_age_limit < time(0))) { +- opt_aged = 1; +- } +- +- if (opt_aged) { +- gpm_report(GPM_PR_DEBUG,GPM_MESS_SKIP_PASTE); +- return; +- } +- +- fd=open_console(O_WRONLY); +- if(ioctl(fd, TIOCLINUX, &c) < 0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX); +- close(fd); +-} +- +-/*-------------------------------------------------------------------*/ +-static inline int do_selection(Gpm_Event *event) /* returns 0, always */ +-{ +- static int x1=1, y1=1, x2, y2; +-#define UNPOINTER() 0 +- +- x2=event->x; y2=event->y; +- switch(GPM_BARE_EVENTS(event->type)) { +- case GPM_MOVE: +- if (x2<1) x2++; else if (x2>maxx) x2--; +- if (y2<1) y2++; else if (y2>maxy) y2--; +- selection_copy(x2,y2,x2,y2,3); /* just highlight pointer */ +- return 0; +- +- case GPM_DRAG: +- if (event->buttons==GPM_B_LEFT) { +- if (event->margin) /* fix margins */ +- switch(event->margin) { +- case GPM_TOP: x2=1; y2++; break; +- case GPM_BOT: x2=maxx; y2--; break; +- case GPM_RGT: x2--; break; +- case GPM_LFT: y2<=y1 ? x2++ : (x2=maxx, y2--); break; +- } +- selection_copy(x1,y1,x2,y2,event->clicks); +- if (event->clicks>=opt_ptrdrag && !event->margin) /* pointer */ +- selection_copy(x2,y2,x2,y2,3); +- } /* if */ +- return 0; +- +- case GPM_DOWN: +- switch (event->buttons) { +- case GPM_B_LEFT: +- x1=x2; y1=y2; +- selection_copy(x1,y1,x2,y2,event->clicks); /* start selection */ +- return 0; +- +- case GPM_B_MIDDLE: +- selection_paste(); +- return 0; +- +- case GPM_B_RIGHT: +- if (opt_three==1) +- selection_copy(x1,y1,x2,y2,event->clicks); +- else +- selection_paste(); +- return 0; +- } +- } /* switch above */ +- return 0; +-} +- +-/*-------------------------------------------------------------------*/ +-/* returns 0 if the event has not been processed, and 1 if it has */ +-static inline int do_client(Gpm_Cinfo *cinfo, Gpm_Event *event) +-{ +- Gpm_Connect info=cinfo->data; +- int fd=cinfo->fd; +- /* value to return if event is not used */ +- int res = !(info.defaultMask & event->type); +- +- /* instead of returning 0, scan the stack of clients */ +- if ((info.minMod & event->modifiers) < info.minMod) +- goto scan; +- if ((info.maxMod & event->modifiers) < event->modifiers) +- goto scan; +- +- /* if not managed, use default mask */ +- if (!(info.eventMask & GPM_BARE_EVENTS(event->type))) { +- if (res) return res; +- else goto scan; +- } +- +- /* WARNING */ /* This can generate a SIGPIPE... I'd better catch it */ +- MAGIC_P((write(fd,&magic, sizeof(int)))); +- write(fd,event, sizeof(Gpm_Event)); +- +- return info.defaultMask & GPM_HARD ? res : 1; /* HARD forces pass-on */ +- +- scan: +- if (cinfo->next != 0) +- return do_client (cinfo->next, event); /* try the next */ +- return 0; /* no next, not used */ +-} +- + /*------------------------------------------------------------------- + * fetch the actual device data from the mouse device, dependent on + * what Gpm_Type is being passed. + *-------------------------------------------------------------------*/ +-static inline char *getMouseData(int fd, Gpm_Type *type, int kd_mode) ++static char *getMouseData(int fd, Gpm_Type *type, int text_mode) + { + static unsigned char data[32]; /* quite a big margin :) */ +- char *edata=data+type->packetlen; +- int howmany=type->howmany; +- int i,j; ++ unsigned char *pdata; ++ int len, togo; + +-/*....................................... read and identify one byte */ +- +- if (read(fd, data, howmany)!=howmany) { +- if (opt_test) exit(0); ++ /*....................................... read and identify one byte */ ++ if (read(fd, data, type->howmany) != type->howmany) { + gpm_report(GPM_PR_ERR,GPM_MESS_READ_FIRST, strerror(errno)); + return NULL; + } + +- if (kd_mode!=KD_TEXT && fifofd != -1 && opt_rawrep) +- write(fifofd, data, howmany); ++ if (!text_mode && repeater.fd != -1 && repeater.raw) ++ write(repeater.fd, data, type->howmany); + +- if ((data[0]&(m_type->proto)[0]) != (m_type->proto)[1]) { +- if (m_type->getextra == 1) { +- data[1]=GPM_EXTRA_MAGIC_1; data[2]=GPM_EXTRA_MAGIC_2; +- gpm_report(GPM_PR_DEBUG,GPM_EXTRA_DATA,data[0]); ++ if ((data[0] & type->proto[0]) != type->proto[1]) { ++ if (type->getextra == 1) { ++ data[1] = GPM_EXTRA_MAGIC_1; data[2] = GPM_EXTRA_MAGIC_2; ++ gpm_report(GPM_PR_DEBUG, GPM_EXTRA_DATA, data[0]); + return data; + } +- gpm_report(GPM_PR_DEBUG,GPM_MESS_PROT_ERR); ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_PROT_ERR); + return NULL; + } + +-/*....................................... read the rest */ ++ /*....................................... read the rest */ + + /* + * well, this seems to work almost right with ps2 mice. However, I've never + * tried ps2 with the original selection package, which called usleep() + */ +- +- if((i=m_type->packetlen-howmany)) /* still to get */ ++ if ((togo = type->packetlen - type->howmany)) { /* still to get */ ++ pdata = &data[type->howmany]; + do { +- j = read(fd,edata-i,i); /* edata is pointer just after data */ +- if (kd_mode!=KD_TEXT && fifofd != -1 && opt_rawrep && j > 0) +- write(fifofd, edata-i, j); +- i -= j; +- } while (i && j); +- +- if (i) { +- gpm_report(GPM_PR_ERR,GPM_MESS_READ_REST, strerror(errno)); ++ if ((len = read(fd, pdata, togo)) == 0) ++ break; ++ if (!text_mode && repeater.fd != -1 && repeater.raw && len > 0) ++ write(repeater.fd, pdata, len); ++ pdata += len; ++ togo -= len; ++ } while (togo); ++ } ++ ++ if (togo) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_READ_REST, strerror(errno)); + return NULL; + } + +- if ((data[1]&(m_type->proto)[2]) != (m_type->proto)[3]) { +- gpm_report(GPM_PR_INFO,GPM_MESS_SKIP_DATA); ++ if ((data[1] & type->proto[2]) != type->proto[3]) { ++ gpm_report(GPM_PR_INFO, GPM_MESS_SKIP_DATA); + return NULL; + } +- gpm_report(GPM_PR_DEBUG,GPM_MESS_DATA_4,data[0],data[1],data[2],data[3]); ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_DATA_4, data[0], data[1], data[2], data[3]); + return data; + } + +- +-static int statusX,statusY,statusB; /* to return info */ +-static int statusC=0; /* clicks */ +-void get_console_size(Gpm_Event *ePtr); +- +-/*------------------------------------------------------------------- +- * call getMouseData to get hardware device data, call mouse device's fun() +- * to retrieve the hardware independent event data, then optionally repeat +- * the data via repeat_fun() to the repeater device +- *-------------------------------------------------------------------*/ +-static inline int processMouse(int fd, Gpm_Event *event, Gpm_Type *type, +- int kd_mode) ++/*-------------------------------------------------------------------*/ ++void handle_console_resize(Gpm_Event *event) + { +- char *data; +- static int fine_dx, fine_dy; +- static int i, j, m; +- static Gpm_Event nEvent; +- static struct vt_stat stat; +- static struct timeval tv1={0,0}, tv2; /* tv1==0: first click is single */ +- static struct timeval timeout={0,0}; +- fd_set fdSet; +- static int newB=0, oldB=0, oldT=0; /* old buttons and Type to chain events */ +- /* static int buttonlock, buttonlockflag; */ +- +-#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL)) +-#define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \ +- (t2.tv_usec-t1.tv_usec)/1000) +- +- +- oldT=event->type; +- +- if (eventFlag) { +- eventFlag=0; +- +- if (m_type->absolute) { /* a pen or other absolute device */ +- event->x=nEvent.x; +- event->y=nEvent.y; +- } +- event->dx=nEvent.dx; +- event->dy=nEvent.dy; +- event->buttons=nEvent.buttons; +- } else { +- event->dx=event->dy=0; +- event->wdx=event->wdy=0; +- nEvent.modifiers = 0; /* some mice set them */ +- FD_ZERO(&fdSet); FD_SET(fd,&fdSet); i=0; +- +- do { /* cluster loop */ +- if(((data=getMouseData(fd,m_type,kd_mode))==NULL) +- || ((*(m_type->fun))(&nEvent,data)==-1) ) { +- if (!i) return 0; +- else break; +- } +- +- event->modifiers = nEvent.modifiers; /* propagate modifiers */ +- +- /* propagate buttons */ +- nEvent.buttons = (opt_sequence[nEvent.buttons&7]&7) | +- (nEvent.buttons & ~7); /* change the order */ +- oldB=newB; newB=nEvent.buttons; +- if (!i) event->buttons=nEvent.buttons; +- +- if (oldB!=newB) { +- eventFlag = (i!=0)*(which_mouse-mouse_table); /* 1 or 2 */ +- break; +- } +- +- /* propagate movement */ +- if (!(m_type->absolute)) { /* mouse */ +- if (abs(nEvent.dx)+abs(nEvent.dy) > opt_delta) +- nEvent.dx*=opt_accel, nEvent.dy*=opt_accel; +- +- /* increment the reported dx,dy */ +- event->dx+=nEvent.dx; +- event->dy+=nEvent.dy; +- } else { /* a pen */ +- /* get dx,dy to check if there has been movement */ +- event->dx = (nEvent.x) - (event->x); +- event->dy = (nEvent.y) - (event->y); +- } +- +- /* propagate wheel */ +- event->wdx += nEvent.wdx; +- event->wdy += nEvent.wdy; +- +- select(fd+1,&fdSet,(fd_set *)NULL,(fd_set *)NULL,&timeout/* zero */); +- +- } while (i++ <opt_cluster && nEvent.buttons==oldB && FD_ISSET(fd,&fdSet)); +- +- } /* if(eventFlag) */ +- +-/*....................................... update the button number */ ++ int old_x, old_y; ++ struct micetab *mouse; + +- if ((event->buttons&GPM_B_MIDDLE) && !opt_three) opt_three++; ++ old_x = console.max_x; old_y = console.max_y; ++ refresh_console_size(); ++ if (!old_x) { /* first invocation, place the pointer in the middle */ ++ event->x = console.max_x / 2; ++ event->y = console.max_y / 2; ++ } else { /* keep the pointer in the same position where it was */ ++ event->x = event->x * console.max_x / old_x; ++ event->y = event->y * console.max_y / old_y; ++ } + +-/*....................................... we're a repeater, aren't we? */ ++ for (mouse = micelist; mouse; mouse = mouse->next) { ++ /* ++ * the following operation is based on the observation that 80x50 ++ * has square cells. (An author-centric observation ;-) ++ */ ++ mouse->options.scaley = mouse->options.scalex * 50 * console.max_x / 80 / console.max_y; ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_X_Y_VAL, ++ mouse->options.scalex, mouse->options.scaley); ++ } ++} + +- if (kd_mode!=KD_TEXT) { +- if (fifofd != -1 && ! opt_rawrep) { +- if (m_type->absolute) { /* hof Wed Feb 3 21:43:28 MET 1999 */ +- /* prepare the values from a absolute device for repeater mode */ +- static struct timeval rept1,rept2; +- gettimeofday(&rept2, (struct timezone *)NULL); +- if (((rept2.tv_sec -rept1.tv_sec) +- *1000+(rept2.tv_usec-rept1.tv_usec)/1000)>250) { +- event->dx=0; +- event->dy=0; +- } +- rept1=rept2; +- +- event->dy=event->dy*((win.ws_col/win.ws_row)+1); +- event->x=nEvent.x; +- event->y=nEvent.y; +- } +- repeated_type->repeat_fun(event, fifofd); /* itz Jan 11 1999 */ ++static void handle_repeater(int absolute_dev, Gpm_Event *new_event, Gpm_Event *event) ++{ ++ static struct timeval last; ++ struct timeval now; ++ ++ if (absolute_dev) { ++ /* prepare the values from a absolute device for repeater mode */ ++ GET_TIME(now); ++ if (((now.tv_sec - last.tv_sec) * 1000 + ++ (now.tv_usec - last.tv_usec) / 1000) > 250) { ++ event->dx = 0; ++ event->dy = 0; + } +- return 0; /* no events nor information for clients */ +- } /* first if of these three */ +- +-/*....................................... no, we arent a repeater, go on */ ++ last = now; + +- /* use fine delta values now, if delta is the information */ +- if (!(m_type)->absolute) { +- fine_dx+=event->dx; fine_dy+=event->dy; +- event->dx=fine_dx/opt_scale; event->dy=fine_dy/opt_scaley; +- fine_dx %= opt_scale; fine_dy %= opt_scaley; ++ event->dy = event->dy * ((console.max_x / console.max_y) + 1); ++ event->x = new_event->x; ++ event->y = new_event->y; + } ++ repeater.type->repeat_fun(event, repeater.fd); ++} + +- /* up and down, up and down, ... who does a do..while(0) loop ??? +- and then makes a break into it... argh ! */ +- +- if (!event->dx && !event->dy && (event->buttons==oldB)) +- do { /* so to break */ +- static long awaketime; +- /* +- * Ret information also if never happens, but enough time has elapsed. +- * Note: return 1 will segfault due to missing event->vc; FIXME! +- */ +- if (time(NULL)<=awaketime) return 0; +- awaketime=time(NULL)+1; +- break; +- } while (0); +- +-/*....................................... fill missing fields */ +- +- event->x+=event->dx, event->y+=event->dy; +- statusB=event->buttons; +- +- i=open_console(O_RDONLY); +- /* modifiers */ +- j = event->modifiers; /* save them */ +- event->modifiers=6; /* code for the ioctl */ +- if (ioctl(i,TIOCLINUX,&(event->modifiers))<0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_GET_SHIFT_STATE); +- event->modifiers |= j; /* add mouse-specific bits */ +- +- /* status */ +- j = stat.v_active; +- if (ioctl(i,VT_GETSTATE,&stat)<0) gpm_report(GPM_PR_OOPS,GPM_MESS_GET_CONSOLE_STAT); +- +- /* +- * if we changed console, request the current console size, +- * as different consoles can be of different size +- */ +- if (stat.v_active != j) +- get_console_size(event); +- close(i); +- +- event->vc = stat.v_active; +- +- if (oldB==event->buttons) +- event->type = (event->buttons ? GPM_DRAG : GPM_MOVE); +- else +- event->type = (event->buttons > oldB ? GPM_DOWN : GPM_UP); +- ++static void calculate_clicks(Gpm_Event *event, int click_tmo) ++{ ++ static struct timeval release; ++ struct timeval now; ++ + switch(event->type) { /* now provide the cooked bits */ + case GPM_DOWN: +- GET_TIME(tv2); +- if (tv1.tv_sec && (DIF_TIME(tv1,tv2)<opt_time)) /* check first click */ +- statusC++, statusC%=3; /* 0, 1 or 2 */ ++ GET_TIME(now); ++ if (release.tv_sec && (DIF_TIME(release, now) < click_tmo)) /* check first click */ ++ event->clicks++, event->clicks %= 3; /* 0, 1 or 2 */ + else +- statusC=0; +- event->type|=(GPM_SINGLE<<statusC); ++ event->clicks = 0; ++ event->type |= GPM_SINGLE << event->clicks; + break; + + case GPM_UP: +- GET_TIME(tv1); +- event->buttons^=oldB; /* for button-up, tell which one */ +- event->type|= (oldT&GPM_MFLAG); +- event->type|=(GPM_SINGLE<<statusC); ++ GET_TIME(release); ++ event->type |= GPM_SINGLE << event->clicks; + break; + + case GPM_DRAG: +- event->type |= GPM_MFLAG; +- event->type|=(GPM_SINGLE<<statusC); ++ event->type |= GPM_SINGLE << event->clicks; + break; + + case GPM_MOVE: +- statusC=0; ++ event->clicks = 0; ++ + default: + break; + } +- event->clicks=statusC; ++} ++ ++static void snap_to_screen_limits(Gpm_Event *event) ++{ ++ int extent; + +-/* UGLY - FIXME! */ +-/* The current policy is to force the following behaviour: +- * - At buttons up, must fit inside the screen, though flags are set. +- * - At button down, allow going outside by one single step +- */ ++ /* The current policy is to force the following behaviour: ++ * - At buttons up, must fit inside the screen, though flags are set. ++ * - At button down, allow going outside by one single step ++ * DTOR: Midnight Commander seems to want the opposite... ++ */ + ++ extent = (event->type & (GPM_DRAG|GPM_UP)) ? 1 : 0; + + /* selection used 1-based coordinates, so do I */ +- + /* + * 1.05: only one margin is current. Y takes priority over X. +- * The i variable is how much margin is allowed. "m" is which one is there. + */ + +- m = 0; +- i = ((event->type&(GPM_DRAG|GPM_UP))!=0); /* i is boolean */ +- +- if (event->y>win.ws_row) {event->y=win.ws_row+1-!i; i=0; m = GPM_BOT;} +- else if (event->y<=0) {event->y=1-i; i=0; m = GPM_TOP;} +- +- if (event->x>win.ws_col) {event->x=win.ws_col+1-!i; if (!m) m = GPM_RGT;} +- else if (event->x<=0) {event->x=1-i; if (!m) m = GPM_LFT;} ++ event->margin = 0; + +- event->margin=m; ++ if (event->y > console.max_y) { ++ event->y = console.max_y + extent; ++ extent = 0; ++ event->margin = GPM_BOT; ++ } else if (event->y <= 0) { ++ event->y = 1 - extent; ++ extent = 0; ++ event->margin = GPM_TOP; ++ } + +- gpm_report(GPM_PR_DEBUG,"M: %3i %3i (%3i %3i) - butt=%i vc=%i cl=%i", +- event->dx,event->dy, +- event->x,event->y, +- event->buttons, event->vc, +- event->clicks); ++ if (event->x > console.max_x) { ++ event->x = console.max_x + extent; ++ if (!event->margin) event->margin = GPM_RGT; ++ } else if (event->x <= 0) { ++ event->x = 1 - extent; ++ if (!event->margin) event->margin = GPM_LFT; ++ } ++} + +- /* update the global state */ +- statusX=event->x; statusY=event->y; ++static int more_data_waiting(int fd) ++{ ++ static struct timeval timeout = {0, 0}; ++ fd_set fdSet; + +- if (opt_special && event->type & GPM_DOWN) +- return processSpecial(event); ++ FD_ZERO(&fdSet); ++ FD_SET(fd, &fdSet); ++ select(fd + 1, &fdSet, NULL_SET, NULL_SET, &timeout/* zero */); + +- return 1; ++ return FD_ISSET(fd, &fdSet); + } + +-/*-------------------------------------------------------------------* +- * This was inline, and incurred in a compiler bug (2.7.0) +- *-------------------------------------------------------------------*/ +-static int get_data(Gpm_Connect *where, int whence) ++static int multiplex_buttons(struct micetab *mouse, int new_buttons) + { +- static int i; ++ static int left_btn_clicks, mid_btn_clicks, right_btn_clicks; ++ int mask; ++ int muxed_buttons = 0; ++ ++ new_buttons = ++ (mouse->options.sequence[new_buttons & 7] & 7) | (new_buttons & ~7); ++ mask = new_buttons ^ mouse->buttons; ++ mouse->buttons = new_buttons; + +-#ifdef GPM_USE_MAGIC +- while ((i=read(whence,&check,sizeof(int)))==4 && check!=GPM_MAGIC) +- gpm_report(GPM_PR_INFO,GPM_MESS_NO_MAGIC); +- +- if (!i) return 0; +- if (check!=GPM_MAGIC) { +- gpm_report(GPM_PR_INFO,GPM_MESS_NOTHING_MORE); +- return -1; ++ if (mask & GPM_B_LEFT) { ++ if (new_buttons & GPM_B_LEFT) left_btn_clicks++; ++ else left_btn_clicks--; + } +-#endif ++ if (left_btn_clicks) muxed_buttons |= GPM_B_LEFT; + +- if ((i=read(whence, where, sizeof(Gpm_Connect)))!=sizeof(Gpm_Connect)) { +- return i ? -1 : 0; ++ if (mask & GPM_B_MIDDLE) { ++ if (new_buttons & GPM_B_MIDDLE) mid_btn_clicks++; ++ else mid_btn_clicks--; + } ++ if (mid_btn_clicks) muxed_buttons |= GPM_B_MIDDLE; + +- return 1; +-} ++ if (mask & GPM_B_RIGHT) { ++ if (new_buttons & GPM_B_RIGHT) right_btn_clicks++; ++ else right_btn_clicks--; ++ } ++ if (right_btn_clicks) muxed_buttons |= GPM_B_RIGHT; + +-static void disable_paste(int vc) +-{ +- opt_aged++; +- gpm_report(GPM_PR_INFO,GPM_MESS_DISABLE_PASTE,vc); ++ return muxed_buttons; + } + +-/*-------------------------------------------------------------------*/ +- /* returns -1 if closing connection */ +-static inline int processRequest(Gpm_Cinfo *ci, int vc) ++/*------------------------------------------------------------------- ++ * call getMouseData to get hardware device data, call mouse device's fun() ++ * to retrieve the hardware independent event data, then optionally repeat ++ * the data via repeat_fun() to the repeater device ++ *-------------------------------------------------------------------*/ ++static enum mouse_rslt processMouse(struct micetab *mouse, int timeout, int attempt, ++ Gpm_Event *event, int text_mode) + { ++ static int last_active; ++ static int fine_dx, fine_dy; ++ static int oldB; ++ ++ static Gpm_Event nEvent; ++ struct Gpm_Type *type = mouse->type; ++ struct miceopt *opt = &mouse->options; ++ enum mouse_rslt rslt = MOUSE_DATA_OK; ++ unsigned char shift_state; ++ char *data = NULL; + int i; +- Gpm_Cinfo *cinfoPtr, *next; +- Gpm_Connect conn; +- static Gpm_Event event; +- static struct vt_stat stat; +- +- gpm_report(GPM_PR_INFO,GPM_MESS_CON_REQUEST, ci->fd, vc); +- if (vc>MAX_VC) return -1; +- +- /* itz 10-22-96 this shouldn't happen now */ +- if (vc==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_UNKNOWN_FD); +- +- i=get_data(&conn,ci->fd); +- +- if (!i) { /* no data */ +- gpm_report(GPM_PR_INFO,GPM_MESS_CLOSE); +- close(ci->fd); +- FD_CLR(ci->fd,&connSet); +- FD_CLR(ci->fd,&readySet); +- if (cinfo[vc]->fd == ci->fd) { /* it was on top of the stack */ +- cinfoPtr = cinfo[vc]; +- cinfo[vc]=cinfo[vc]->next; /* pop the stack */ +- free(cinfoPtr); +- return -1; +- } +- /* somewhere inside the stack, have to walk it */ +- cinfoPtr = cinfo[vc]; +- while (cinfoPtr && cinfoPtr->next) { +- if (cinfoPtr->next->fd == ci->fd) { +- next = cinfoPtr->next; +- cinfoPtr->next = next->next; +- free (next); ++ ++ if (attempt > 1) { /* continue interrupted cluster loop */ ++ if (opt->absolute) { ++ event->x = nEvent.x; ++ event->y = nEvent.y; ++ } ++ event->dx = nEvent.dx; ++ event->dy = nEvent.dy; ++ event->buttons = nEvent.buttons; ++ } else { ++ event->dx = event->dy = 0; ++ event->wdx = event->wdy = 0; ++ nEvent.modifiers = 0; /* some mice set them */ ++ i = 0; ++ ++ do { /* cluster loop */ ++ if (!timeout && (data = getMouseData(mouse->dev.fd, type, text_mode)) != NULL) { ++ GET_TIME(mouse->timestamp); ++ } ++ ++ /* in case of timeout data passed to typr->fun() is NULL */ ++ if ((!timeout && data == NULL) || ++ type->fun(&mouse->dev, &mouse->options, data, &nEvent) == -1) { ++ if (!i) return MOUSE_NO_DATA; ++ else break; ++ } ++ ++ event->modifiers = nEvent.modifiers; /* propagate modifiers */ ++ ++ /* propagate buttons */ ++ nEvent.buttons = multiplex_buttons(mouse, nEvent.buttons); ++ ++ if (!i) event->buttons = nEvent.buttons; ++ ++ if (oldB != nEvent.buttons) { ++ rslt = MOUSE_MORE_DATA; + break; + } +- cinfoPtr = cinfoPtr->next; +- } +- return -1; +- } /* not data */ +- +- if (i == -1) return -1; /* too few bytes */ + +- if (conn.pid!=0) { +- ci->data = conn; +- return 0; +- } +- +- /* Aha, request for information (so-called snapshot) */ +- switch(conn.vc) { +- case GPM_REQ_SNAPSHOT: +- i=open_console(O_RDONLY); +- ioctl(i,VT_GETSTATE,&stat); +- event.modifiers=6; /* code for the ioctl */ +- if (ioctl(i,TIOCLINUX,&(event.modifiers))<0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_GET_SHIFT_STATE); +- close(i); +- event.vc = stat.v_active; +- event.x=statusX; event.y=statusY; +- event.dx=maxx; event.dy=maxy; +- event.buttons= statusB; +- event.clicks=statusC; +- /* fall through */ +- /* missing break or do you want this ??? */ +- +- case GPM_REQ_BUTTONS: +- event.type= (opt_three==1 ? 3 : 2); /* buttons */ +- write(ci->fd,&event,sizeof(Gpm_Event)); +- break; ++ /* propagate movement */ ++ if (!opt->absolute) { /* mouse */ ++ if (abs(nEvent.dx) + abs(nEvent.dy) > opt->delta) ++ nEvent.dx *= opt->accel, nEvent.dy *= opt->accel; + +- case GPM_REQ_NOPASTE: +- disable_paste(vc); +- break; ++ /* increment the reported dx,dy */ ++ event->dx += nEvent.dx; ++ event->dy += nEvent.dy; ++ } else { /* a pen */ ++ /* get dx,dy to check if there has been movement */ ++ event->dx = nEvent.x - event->x; ++ event->dy = nEvent.y - event->y; ++ } ++ ++ /* propagate wheel */ ++ event->wdx += nEvent.wdx; ++ event->wdy += nEvent.wdy; ++ ++ } while (i++ < opt->cluster && more_data_waiting(mouse->dev.fd)); ++ } /* if(eventFlag) */ ++ ++ /*....................................... update the button number */ ++ ++ if ((event->buttons & GPM_B_MIDDLE) && !opt->three_button) opt->three_button++; ++ ++ /*....................................... we're a repeater, aren't we? */ ++ ++ if (!text_mode) { ++ if (repeater.fd != -1 && !repeater.raw) ++ handle_repeater(opt->absolute, &nEvent, event); ++ oldB = nEvent.buttons; ++ return MOUSE_NO_DATA; /* no events nor information for clients */ + } + +- return 0; +-} ++/*....................................... no, we arent a repeater, go on */ + +-/*-------------------------------------------------------------------*/ +-static inline int processConn(int fd) /* returns newfd or -1 */ +-{ +- Gpm_Cinfo *info; +- Gpm_Connect *request; +- Gpm_Cinfo *next; +- int vc, newfd; +-#if !defined(__GLIBC__) +- int len; +-#else /* __GLIBC__ */ +- size_t len; /* isn't that generally defined in C ??? -- nico */ +-#endif /* __GLIBC__ */ +- struct sockaddr_un addr; /* reuse this each time */ +- struct stat statbuf; +- uid_t uid; +- char *tty = NULL; +- +-/*....................................... Accept */ +- +- bzero((char *)&addr,sizeof(addr)); +- addr.sun_family=AF_UNIX; +- +- len=sizeof(addr); +- if ((newfd=accept(fd,(struct sockaddr *)&addr, &len))<0) { +- gpm_report(GPM_PR_ERR,GPM_MESS_ACCEPT_FAILED,strerror(errno)); +- return -1; +- } +- +- gpm_report(GPM_PR_INFO,GPM_MESS_CONECT_AT,newfd); +- +- info=malloc(sizeof(Gpm_Cinfo)); +- if (!info) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- request=&(info->data); +- +- if(get_data(request,newfd)==-1) { +- free(info); +- close(newfd); +- return -1; +- } +- +- if ((vc=request->vc)>MAX_VC) { +- gpm_report(GPM_PR_WARN,GPM_MESS_REQUEST_ON, vc, MAX_VC); +- free(info); +- close(newfd); +- return -1; +- } +- +-#ifndef SO_PEERCRED +- if (stat (addr.sun_path, &statbuf) == -1 || !S_ISSOCK(statbuf.st_mode)) { +- gpm_report(GPM_PR_ERR,GPM_MESS_ADDRES_NSOCKET,addr.sun_path); +- free(info); /* itz 10-12-95 verify client's right */ +- close(newfd); +- return -1; /* to read requested tty */ ++ /* use fine delta values now, if delta is the information */ ++ if (!opt->absolute) { ++ fine_dx += event->dx; ++ fine_dy += event->dy; ++ event->dx = fine_dx / opt->scalex; ++ event->dy = fine_dy / opt->scaley; ++ fine_dx %= opt->scalex; ++ fine_dy %= opt->scaley; + } +- +- unlink(addr.sun_path); /* delete socket */ + +- staletime = time(0) - 30; +- if (statbuf.st_atime < staletime +- || statbuf.st_ctime < staletime +- || statbuf.st_mtime < staletime) { +- gpm_report(GPM_PR_ERR,GPM_MESS_SOCKET_OLD); +- free (info); +- close(newfd); +- return -1; /* socket is ancient */ ++ /* up and down, up and down, ... who does a do..while(0) loop ??? ++ and then makes a break into it... argh ! */ ++ ++ if (!event->dx && !event->dy && event->buttons == oldB) { ++ static time_t awaketime; ++ /* ++ * Ret information also if never happens, but enough time has elapsed. ++ * Note: return 1 will segfault due to missing event->vc; FIXME! ++ */ ++ if (time(NULL) <= awaketime) return MOUSE_NO_DATA; ++ awaketime = time(NULL) + 1; + } + +- uid = statbuf.st_uid; /* owner of socket */ +-#else +- { +- struct ucred sucred; +- socklen_t credlen = sizeof(struct ucred); +- +- if(getsockopt(newfd, SOL_SOCKET, SO_PEERCRED, &sucred, &credlen) == -1) { +- gpm_report(GPM_PR_ERR,GPM_MESS_GETSOCKOPT, strerror(errno)); +- free(info); +- close(newfd); +- return -1; +- } +- uid = sucred.uid; +- gpm_report(GPM_PR_DEBUG,GPM_MESS_PEER_SCK_UID, uid); +- } +-#endif +- if (uid != 0) { +- if(( tty = +- malloc(strlen(option.consolename)+Gpm_cnt_digits(vc) + sizeof(char))) == NULL) +- gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- +- strncpy(tty,option.consolename,strlen(option.consolename)-1); +- sprintf(&tty[strlen(option.consolename)-1],"%d",vc); ++ /*....................................... fill missing fields */ ++ event->x += event->dx; event->y += event->dy; + +- if(stat(tty, &statbuf) == -1) { +- gpm_report(GPM_PR_ERR,GPM_MESS_STAT_FAILS,tty); +- free(info); +- free(tty); +- close(newfd); +- return -1; +- } +- if (uid != statbuf.st_uid) { +- gpm_report(GPM_PR_WARN,GPM_MESS_FAILED_CONNECT, uid, tty); /*SUSPECT!*/ +- free(info); +- free(tty); +- close(newfd); +- return -1; ++ event->vc = get_console_state(&shift_state); ++ if (event->vc != last_active) { ++ handle_console_resize(event); ++ last_active = event->vc; ++ } ++ event->modifiers |= shift_state; ++ ++ if (oldB == event->buttons) ++ event->type = (event->buttons ? (GPM_DRAG | GPM_MFLAG) : GPM_MOVE); ++ else { ++ if (event->buttons > oldB) ++ event->type = GPM_DOWN; ++ else { ++ event->type &= GPM_MFLAG; ++ event->type |= GPM_UP; ++ event->buttons ^= oldB; /* for button-up, tell which one */ + } +- free(tty); /* at least here it's not needed anymore */ + } ++ calculate_clicks(event, opt->time); ++ snap_to_screen_limits(event); ++ ++ gpm_report(GPM_PR_DEBUG,"M: %3i %3i (%3i %3i) - butt=%i vc=%i cl=%i", ++ event->dx, event->dy, event->x, event->y, ++ event->buttons, event->vc, event->clicks); + +- /* register the connection information in the right place */ +- info->next=next=cinfo[vc]; +- info->fd=newfd; +- cinfo[vc]=info; +- gpm_report(GPM_PR_DEBUG,GPM_MESS_LONG_STATUS, +- request->pid, request->vc, request->eventMask, request->defaultMask, +- request->minMod, request->maxMod); +- +- /* if the client gets motions, give it the current position */ +- if(request->eventMask & GPM_MOVE) { +- Gpm_Event event={0,0,vc,0,0,statusX,statusY,GPM_MOVE,0,0}; +- do_client(info, &event); +- } ++ oldB = nEvent.buttons; + +- return newfd; ++ if (opt_special && (event->type & GPM_DOWN) && !processSpecial(event)) ++ rslt = MOUSE_NO_DATA; ++ ++ return rslt; + } + +-/*-------------------------------------------------------------------*/ +-void get_console_size(Gpm_Event *ePtr) ++static int wait_for_data(fd_set *connSet, int maxfd, fd_set *selSet) + { +- int i, prevmaxx, prevmaxy; +- struct mouse_features *which_mouse; /* local */ ++ struct micetab *mouse; ++ struct timeval now, timeout = { 0, 0 }; ++ int mouse_tmo, tmo = INT_MAX; + +- /* before asking the new console size, save the previous values */ +- prevmaxx = maxx; prevmaxy = maxy; ++ GET_TIME(now); + +- i=open_console(O_RDONLY); +- ioctl(i, TIOCGWINSZ, &win); +- close(i); +- if (!win.ws_col || !win.ws_row) { +- gpm_report(GPM_PR_DEBUG,GPM_MESS_ZERO_SCREEN_DIM); +- win.ws_col=80; win.ws_row=25; +- } +- maxx=win.ws_col; maxy=win.ws_row; +- gpm_report(GPM_PR_DEBUG,GPM_MESS_SCREEN_SIZE,maxx,maxy); +- +- if (!prevmaxx) { /* first invocation, place the pointer in the middle */ +- statusX = ePtr->x = maxx/2; +- statusY = ePtr->y = maxy/2; +- } else { /* keep the pointer in the same position where it was */ +- statusX = ePtr->x = ePtr->x * maxx / prevmaxx; +- statusY = ePtr->y = ePtr->y * maxy / prevmaxy; +- } +- +- for (i=1; i <= 1+opt_double; i++) { +- which_mouse=mouse_table+i; /* used to access options */ +- /* +- * the following operation is based on the observation that 80x50 +- * has square cells. (An author-centric observation ;-) +- */ +- opt_scaley=opt_scale*50*maxx/80/maxy; +- gpm_report(GPM_PR_DEBUG,GPM_MESS_X_Y_VAL,opt_scale,opt_scaley); ++ *selSet = *connSet; ++ for (mouse = micelist; mouse; mouse = mouse->next) { ++ FD_SET(mouse->dev.fd, selSet); ++ maxfd = max(maxfd, mouse->dev.fd); ++ if (mouse->dev.timeout >= 0) { ++ mouse_tmo = mouse->dev.timeout - DIF_TIME(mouse->timestamp, now); ++ tmo = min(tmo, mouse_tmo); ++ } + } ++ ++ if (tmo == INT_MAX) ++ timeout.tv_sec = SELECT_TIME; ++ else if (tmo > 0) { ++ timeout.tv_sec = tmo / 1000; ++ timeout.tv_usec = (tmo % 1000) * 1000; ++ } ++ ++ return select(maxfd + 1, selSet, NULL_SET, NULL_SET, &timeout); + } + +-/*-------------------------------------------------------------------*/ +-static void gpm_killed(int signo) +-{ +- if(signo==SIGWINCH) { +- gpm_report(GPM_PR_WARN,GPM_MESS_RESIZING, option.progname, getpid()); +- opt_resize++; +- return; +- } +- if (signo==SIGUSR1) +- gpm_report(GPM_PR_WARN,GPM_MESS_KILLED_BY,option.progname, getpid(),option.progname); +- exit(0); +-} ++ + + /*-------------------------------------------------------------------*/ + int old_main() + { +- int ctlfd, newfd; +- struct sockaddr_un ctladdr; +- int i, len, kd_mode, fd; +- struct timeval timeout; +- int maxfd=-1; +- int pending; ++ int ctlfd; ++ int i, text_mode; ++ struct timeval now; ++ int maxfd = -1; ++ int pending, attempt; ++ int timed_out; + Gpm_Event event; ++ struct micetab *mouse; ++ struct client_info *ci; ++ fd_set selSet, connSet; ++ enum mouse_rslt rslt; + +- for (i = 1; i <= 1+opt_double; i++) { +- which_mouse=mouse_table+i; /* used to access options */ +- +- if (!opt_dev) gpm_report(GPM_PR_OOPS,GPM_MESS_NEED_MDEV); +- +- if(!strcmp(opt_dev,"-")) fd=0; /* use stdin */ +- else if( (fd=open(opt_dev,O_RDWR | O_NDELAY)) < 0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,opt_dev); +- +- /* and then reset the flag */ +- fcntl(fd,F_SETFL,fcntl(fd,F_GETFL) & ~O_NDELAY); +- +- /* create argc and argv for this device */ +- mouse_argv[i] = build_argv(opt_type, opt_options, &mouse_argc[i], ','); +- +- /* init the device, and use the return value as new mouse type */ +- if (m_type->init) +- m_type=(m_type->init)(fd, m_type->flags, m_type, mouse_argc[i], +- mouse_argv[i]); +- if (!m_type) gpm_report(GPM_PR_OOPS,GPM_MESS_MOUSE_INIT); +- +- which_mouse->fd=fd; +- maxfd=max(fd, maxfd); +- } +- +-/*....................................... catch interesting signals */ +- ++ /*....................................... catch interesting signals */ + signal(SIGTERM, gpm_killed); + signal(SIGINT, gpm_killed); + signal(SIGUSR1, gpm_killed); /* usr1 is used by a new gpm killing the old */ + signal(SIGWINCH,gpm_killed); /* winch can be sent if console is resized */ ++ signal(SIGPIPE, SIG_IGN); /* WARN */ + +-/*....................................... create your nodes */ +- +- /* control node */ +- +- if((ctlfd=socket(AF_UNIX,SOCK_STREAM,0))==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_SOCKET_PROB); +- bzero((char *)&ctladdr,sizeof(ctladdr)); +- ctladdr.sun_family=AF_UNIX; +- strcpy(ctladdr.sun_path,GPM_NODE_CTL); +- unlink(GPM_NODE_CTL); +- +- len=sizeof(ctladdr.sun_family)+strlen(GPM_NODE_CTL); +- if(bind(ctlfd,(struct sockaddr *)(&ctladdr),len) == -1) +- gpm_report(GPM_PR_OOPS,GPM_MESS_BIND_PROB,ctladdr.sun_path); +- maxfd=max(maxfd,ctlfd); +- +- /* needs to be 0777, so all users can _try_ to access gpm */ +- chmod(GPM_NODE_CTL,0777); +- +- get_console_size(&event); /* get screen dimensions */ +- +-/*....................................... wait for mouse and connections */ +- +- listen(ctlfd, 5); /* Queue up calls */ +- +-#define NULL_SET ((fd_set *)NULL) +-#define resetTimeout() (timeout.tv_sec=SELECT_TIME,timeout.tv_usec=0) ++ init_mice(); ++ handle_console_resize(&event); /* get screen dimensions */ ++ ctlfd = listen_for_clients(); + ++ /*....................................... wait for mouse and connections */ + FD_ZERO(&connSet); +- FD_SET(ctlfd,&connSet); +- +- if (opt_double) FD_SET(mouse_table[2].fd,&connSet); +- +- readySet=connSet; +- FD_SET(mouse_table[1].fd,&readySet); +- +- signal(SIGPIPE,SIG_IGN); /* WARN */ +- +-/*--------------------------------------- main loop begins here */ ++ FD_SET(ctlfd, &connSet); ++ maxfd = max(maxfd, ctlfd); ++ ++ /*--------------------------------------- main loop begins here */ + +- while(1) { +- selSet=readySet; +- resetTimeout(); +- if (opt_test) timeout.tv_sec=0; ++ while (1) { + +- if (eventFlag) { /* an event left over by clustering */ +- pending=1; +- FD_ZERO(&selSet); +- FD_SET(mouse_table[eventFlag].fd,&selSet); +- } +- else +- while((pending=select(maxfd+1,&selSet,NULL_SET,NULL_SET,&timeout))==0){ +- selSet=readySet; +- resetTimeout(); +- } /* go on */ +- +- if(opt_resize) { /* did the console resize? */ +- get_console_size(&event); +- opt_resize--; +- signal(SIGWINCH,gpm_killed); /* reinstall handler */ +- +- /* and notify clients */ +- for(i=0; i<MAX_VC+1; i++) { +- Gpm_Cinfo *ci; +- for (ci = cinfo[i]; ci; ci = ci->next) kill(ci->data.pid,SIGWINCH); +- } ++ pending = wait_for_data(&connSet, maxfd, &selSet); ++ ++ if (console_resized) { /* did the console resize? */ ++ handle_console_resize(&event); ++ console_resized = 0; ++ signal(SIGWINCH, gpm_killed); /* reinstall handler */ ++ notify_clients_resize(); + } + + if (pending < 0) { +- if (errno==EBADF) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB); +- gpm_report(GPM_PR_ERR,GPM_MESS_SELECT_STRING,strerror(errno)); +- selSet=readySet; +- resetTimeout(); ++ if (errno == EBADF) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB); ++ gpm_report(GPM_PR_ERR, GPM_MESS_SELECT_STRING, strerror(errno)); + continue; + } + +- gpm_report(GPM_PR_DEBUG,GPM_MESS_SELECT_TIMES,pending); ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_SELECT_TIMES, pending); + +-/*....................................... manage graphic mode */ ++ /*....................................... manage graphic mode */ + +- /* +- * Be sure to be in text mode. This used to be before select, +- * but actually it only matters if you have events. +- */ +- { +- int fd = open_console(O_RDONLY); +- if (ioctl(fd, KDGETMODE, &kd_mode) < 0) +- gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_KDGETMODE); +- close(fd); +- if(kd_mode != KD_TEXT && !option.repeater) { +- wait_text(&mouse_table[1].fd); +- maxfd=max(maxfd,mouse_table[1].fd); +- readySet=connSet; +- FD_SET(mouse_table[1].fd,&readySet); ++ /* ++ * Be sure to be in text mode. This used to be before select, ++ * but actually it only matters if you have events. ++ */ ++ text_mode = is_text_console(); ++ if (!text_mode && !repeater.type && !repeater.raw) { ++ /* if we don;t have repeater then there is only one mouse so ++ * we can safely use micelist ++ */ ++ close(micelist->dev.fd); ++ wait_text_console(); ++ /* reopen, reinit (the function is only used if we have one mouse device) */ ++ if ((micelist->dev.fd = open(micelist->device, O_RDWR)) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, micelist->device); ++ if (micelist->type->init) ++ micelist->type->init(&micelist->dev, &micelist->options, micelist->type); + continue; /* reselect */ + } +- } + +-/*....................................... got mouse, process event */ +-/* +- * Well, actually, run a loop to maintain inlining of functions without +- * lenghtening the file. This is not too clean a code, but it works.... +- */ +- +- for (i=1; i <= 1+opt_double; i++) { +- which_mouse=mouse_table+i; /* used to access options */ +- if (FD_ISSET(which_mouse->fd,&selSet)) { +- FD_CLR(which_mouse->fd,&selSet); pending--; +- if (processMouse(which_mouse->fd, &event, m_type, kd_mode)) +- /* pass it to the client, if any +- * or to the default handler, if any +- * or to the selection handler +- */ /* FIXME -- check event.vc */ +- /* can't we please rewrite the following a bit nicer?*/ +- (cinfo[event.vc] && do_client(cinfo[event.vc], &event)) +- || (cinfo[0] && do_client(cinfo[0], &event)) +- || do_selection(&event); ++ /*....................................... got mouse, process event */ ++ /* ++ * Well, actually, run a loop to maintain inlining of functions without ++ * lenghtening the file. This is not too clean a code, but it works.... ++ */ ++ GET_TIME(now); ++ for (mouse = micelist; mouse; mouse = mouse->next) { ++ timed_out = mouse->dev.timeout >= 0 && ++ DIF_TIME(mouse->timestamp, now) >= mouse->dev.timeout; ++ if (timed_out || FD_ISSET(mouse->dev.fd, &selSet)) { ++ if (FD_ISSET(mouse->dev.fd, &selSet)) { ++ FD_CLR(mouse->dev.fd, &selSet); ++ pending--; + } ++ attempt = 0; ++ do { ++ rslt = processMouse(mouse, timed_out, ++attempt, &event, text_mode); ++ if (rslt != MOUSE_NO_DATA) { ++ /* pass it to the client or to the default handler, ++ * or to the selection handler ++ */ ++ if (event.vc > MAX_VC) event.vc = 0; ++ if (event.vc == 0 || !cinfo[event.vc] || !do_client(cinfo[event.vc], &event)) ++ if (!cinfo[0] || !do_client(cinfo[0], &event)) ++ do_selection(&event, mouse->options.three_button); ++ } ++ } while (rslt == MOUSE_MORE_DATA); ++ } + } + + /*..................... got connection, process it */ +- +- if (pending && FD_ISSET(ctlfd,&selSet)) { +- FD_CLR(ctlfd,&selSet); pending--; +- newfd=processConn(ctlfd); +- if (newfd>=0) { +- FD_SET(newfd,&connSet); +- FD_SET(newfd,&readySet); +- maxfd=max(maxfd,newfd); ++ if (pending && FD_ISSET(ctlfd, &selSet)) { ++ FD_CLR(ctlfd, &selSet); ++ pending--; ++ if ((ci = accept_client_connection(ctlfd))) { ++ if (ci->data.eventMask & GPM_MOVE) { ++ Gpm_Event e = { 0, 0, ci->data.vc, 0, 0, ++ event.x, event.y, GPM_MOVE, 0, 0 }; ++ do_client(ci, &e); ++ } ++ FD_SET(ci->fd, &connSet); ++ maxfd = max(maxfd, ci->fd); + } + } + + /*........................ got request */ +- +- /* itz 10-22-96 check _all_ clients, not just those on top! */ +- for (i=0; pending && (i<=MAX_VC); i++) { +- Gpm_Cinfo* ci; ++ /* itz 10-22-96 check _all_ clients, not just those on top! */ ++ for (i = 0; pending && i <= MAX_VC; i++) { + for (ci = cinfo[i]; pending && ci; ci = ci->next) { +- if (FD_ISSET(ci->fd,&selSet)) { +- FD_CLR(ci->fd,&selSet); pending--; +- /* itz Sat Sep 12 21:10:22 PDT 1998 */ +- /* this code is clearly incorrect; the next highest +- descriptor after the one we're closing is not necessarily +- being used. Fortunately, it doesn't hurt simply to leave this +- out. */ +- +-#ifdef NOTDEF +- if ((processRequest(ci,i)==-1) && maxfd==ci->fd) maxfd--; +-#else +- (void)processRequest(ci,i); +-#endif ++ if (FD_ISSET(ci->fd, &selSet)) { ++ FD_CLR(ci->fd, &selSet); ++ pending--; ++ if (!process_client_request(ci, i, event.x, event.y, event.clicks, ++ event.buttons, micelist->options.three_button)) { ++ FD_CLR(ci->fd, &connSet); ++ remove_client(ci, i); ++ } + } + } + } + + /*.................. look for a spare fd */ +- + /* itz 10-22-96 this shouldn't happen now! */ +- for (i=0; pending && i<=maxfd; i++) { +- if (FD_ISSET(i,&selSet)) { +- FD_CLR(i,&selSet); ++ for (i = 0; pending && i <= maxfd; i++) { ++ if (FD_ISSET(i, &selSet)) { ++ FD_CLR(i, &selSet); + pending--; +- gpm_report(GPM_PR_WARN,GPM_MESS_STRANGE_DATA,i); ++ gpm_report(GPM_PR_WARN, GPM_MESS_STRANGE_DATA,i); + } + } + + /*................... all done. */ +- +- if(pending) gpm_report(GPM_PR_OOPS,GPM_MESS_SELECT_PROB); ++ if (pending) gpm_report(GPM_PR_OOPS, GPM_MESS_SELECT_PROB); + } /* while(1) */ + } +diff -urN gpm-1.20.1/src/gpn.c gpm/src/gpn.c +--- gpm-1.20.1/src/gpn.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/gpn.c 2003-10-02 01:22:42.000000000 -0500 +@@ -28,201 +28,104 @@ + #include <stdlib.h> + #include <string.h> /* strerror(); ?!? memcpy() */ + #include <ctype.h> /* isdigit */ +-#include <signal.h> +-#include <stdarg.h> /* Log uses it */ +-#include <errno.h> + #include <unistd.h> /* getopt(),symlink() */ +-#include <sys/stat.h> /* mkdir() */ +-#include <sys/param.h> +-#include <sys/time.h> /* timeval */ +-#include <sys/wait.h> /* wait() */ +-#include <sys/types.h> /* socket() */ +-#include <sys/socket.h> /* socket() */ +-#include <sys/un.h> /* struct sockaddr_un */ +-#include <asm/types.h> /* __u32 */ +- +-#ifdef SIGTSTP /* true if BSD system */ +-#include <sys/file.h> +-#include <sys/ioctl.h> +-#endif +- +-#ifndef HAVE___U32 +-# ifndef _I386_TYPES_H /* /usr/include/asm/types.h */ +-typedef unsigned int __u32; +-# endif +-#endif + + #include "headers/message.h" + #include "headers/gpmInt.h" + #include "headers/gpm.h" ++#include "headers/console.h" ++#include "headers/selection.h" + +-extern int errno; +- +-/*===================================================================*/ +-/* octal digit */ +-static int isodigit(const unsigned char c) ++/* usage: display for usage informations */ ++int usage(char *whofailed) + { +- return ((c & ~7) == '0'); ++ if (whofailed) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_SPEC_ERR, whofailed, option.progname); ++ return 1; ++ } ++ printf(GPM_MESS_USAGE, option.progname, DEF_ACCEL, DEF_BAUD, DEF_SEQUENCE, ++ DEF_DELTA, DEF_TIME, DEF_LUT, DEF_SCALE, DEF_SAMPLE, DEF_TYPE); ++ return 1; + } + +-/* routine to convert digits from octal notation (Andries Brouwer) */ +-static int getsym(const unsigned char *p0, unsigned char *res) ++/***************************************************************************** ++ * the function returns a valid type pointer or NULL if not found ++ *****************************************************************************/ ++static struct Gpm_Type *find_mouse_by_name(char *name) + { +- const unsigned char *p = p0; +- char c; ++ Gpm_Type *type; ++ char *s; ++ int len = strlen(name); + +- c = *p++; +- if (c == '\\' && *p) { +- c = *p++; +- if (isodigit(c)) { +- c -= '0'; +- if (isodigit(*p)) c = 8*c + (*p++ - '0'); +- if (isodigit(*p)) c = 8*c + (*p++ - '0'); ++ for (type = mice; type->fun; type++) { ++ if (!strcasecmp(name, type->name)) break; ++ /* otherwise, look in the synonym list */ ++ for (s = type->synonyms; s; s = strchr(s, ' ')) { ++ while (*s && isspace(*s)) s++; /* skip spaces */ ++ if (!strncasecmp(name, s, len) && !isprint(*(s + len))) break;/*found*/ + } ++ if (s) break; /* found a synonym */ + } +- *res = c; +- return (p - p0); ++ return type->fun ? type : NULL; + } + +-/* description missing! FIXME */ +-int loadlut(char *charset) ++static void init_button_sequence(struct miceopt *opt, char *arg) + { +- int i, c, fd; +- unsigned char this, next; +- static __u32 long_array[9]={ +- 0x05050505, /* ugly, but preserves alignment */ +- 0x00000000, /* control chars */ +- 0x00000000, /* digits */ +- 0x00000000, /* uppercase and '_' */ +- 0x00000000, /* lowercase */ +- 0x00000000, /* Latin-1 control */ +- 0x00000000, /* Latin-1 misc */ +- 0x00000000, /* Latin-1 uppercase */ +- 0x00000000 /* Latin-1 lowercase */ ++ int i; ++ static struct { ++ char *in; ++ char *out; ++ } seq[] = { ++ {"123", "01234567"}, ++ {"132", "02134657"}, ++ {"213", "01452367"}, /* warning: these must be readable as integers... */ ++ {"231", "02461357"}, ++ {"312", "04152637"}, ++ {"321", "04261537"}, ++ {NULL, NULL} + }; + ++ if (strlen(arg) != 3 || atoi(arg) < 100) ++ exit(usage("sequence")); + +-#define inwordLut (long_array+1) +- +- for (i=0; charset[i]; ) { +- i += getsym(charset+i, &this); +- if (charset[i] == '-' && charset[i + 1] != '\0') +- i += getsym(charset+i+1, &next) + 1; +- else +- next = this; +- for (c = this; c <= next; c++) +- inwordLut[c>>5] |= 1 << (c&0x1F); +- } +- +- if ((fd=open(option.consolename, O_WRONLY)) < 0) { +- /* try /dev/console, if /dev/tty0 failed -- is that really senseful ??? */ +- free(option.consolename); /* allocated by main */ +- if((option.consolename=malloc(strlen(GPM_SYS_CONSOLE)+1)) == NULL) +- gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- strcpy(option.consolename,GPM_SYS_CONSOLE); +- +- if ((fd=open(option.consolename, O_WRONLY)) < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN_CON); +- } +- if (ioctl(fd, TIOCLINUX, &long_array) < 0) { /* fd <0 is checked */ +- if (errno==EPERM && getuid()) +- gpm_report(GPM_PR_WARN,GPM_MESS_ROOT); /* why do we still continue?*/ +- else if (errno==EINVAL) +- gpm_report(GPM_PR_OOPS,GPM_MESS_CSELECT); +- } +- close(fd); +- +- return 0; ++ for (i = 0; seq[i].in && strcmp(seq[i].in, arg); i++); ++ if (!seq[i].in) ++ exit(usage("button sequence")); ++ opt->sequence = strdup(seq[i].out); /* I can rewrite on it */ + } + +-/* usage: display for usage informations */ +-int usage(char *whofailed) ++static void validate_mouse(struct micetab *mouse, int mouse_no) + { +- if (whofailed) { +- gpm_report(GPM_PR_ERR,GPM_MESS_SPEC_ERR,whofailed,option.progname); +- return 1; +- } +- printf(GPM_MESS_USAGE,option.progname, DEF_ACCEL, DEF_BAUD, DEF_SEQUENCE, +- DEF_DELTA, DEF_TIME, DEF_LUT,DEF_SCALE, DEF_SAMPLE, DEF_TYPE); +- return 1; +-} +- +-/* itz Sat Sep 12 10:55:51 PDT 1998 Added this as replacement for the +- unwanted functionality in check_uniqueness. */ +- +-void check_kill(void) +-{ +- int old_pid; +- FILE* fp = fopen(GPM_NODE_PID, "r"); +- +- /* if we cannot find the old pid file, leave */ +- if (fp == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN, GPM_NODE_PID); +- +- /* else read the pid */ +- if (fscanf(fp,"%d",&old_pid) != 1) +- gpm_report(GPM_PR_OOPS,GPM_MESS_READ_PROB,GPM_NODE_PID); +- fclose(fp); +- +- gpm_report(GPM_PR_DEBUG,GPM_MESS_KILLING,old_pid); +- +- /* first check if we run */ +- if (kill(old_pid,0) == -1) { +- gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID); +- unlink(GPM_NODE_PID); ++ if (!mouse->device) { ++ if (!mouse->type && mouse_no > 1) ++ gpm_report(GPM_PR_OOPS, ++ "No device/protocol specified for mouse #%d, probably extra -M option?", mouse_no); ++ else ++ gpm_report(GPM_PR_OOPS, "No device specified for mouse #%d", mouse_no); + } +- /* then kill us (not directly, but the other instance ... ) */ +- if (kill(old_pid,SIGTERM) == -1) +- gpm_report(GPM_PR_OOPS,GPM_MESS_CANT_KILL, old_pid); + +- gpm_report(GPM_PR_INFO,GPM_MESS_KILLED,old_pid); +- exit(0); +-} ++ if (!mouse->type) ++ mouse->type = find_mouse_by_name(DEF_TYPE); + +-/* itz Sat Sep 12 10:30:05 PDT 1998 this function used to mix two +- completely different things; opening a socket to a running daemon +- and checking that a running daemon existed. Ugly. */ +-/* rewritten mostly on 20th of February 2002 - nico */ +-void check_uniqueness(void) +-{ +- FILE *fp = 0; +- int old_pid = -1; ++ mouse->options.absolute = mouse->type->absolute; + +- if((fp = fopen(GPM_NODE_PID, "r")) != NULL) { +- fscanf(fp, "%d", &old_pid); +- if (kill(old_pid,0) == -1) { +- gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID); +- unlink(GPM_NODE_PID); +- } else /* we are really running, exit asap! */ +- gpm_report(GPM_PR_OOPS,GPM_MESS_ALREADY_RUN, old_pid); +- } +- /* now try to sign ourself */ +- if ((fp = fopen(GPM_NODE_PID,"w")) != NULL) { +- fprintf(fp,"%d\n",getpid()); +- fclose(fp); +- } else { +- gpm_report(GPM_PR_OOPS,GPM_MESS_NOTWRITE,GPM_NODE_PID); +- } ++ if (!mouse->options.sequence) ++ init_button_sequence(&mouse->options, DEF_SEQUENCE); + } + +-/***************************************************************************** +- * the function returns a valid type pointer or NULL if not found +- *****************************************************************************/ +-struct Gpm_Type *find_mouse_by_name(char *name) ++static void validate_repeater(char *type) + { +- Gpm_Type *type; +- char *s; +- int len = strlen(name); +- +- for (type=mice; type->fun; type++) { +- if (!strcasecmp(name, type->name)) break; +- /* otherwise, look in the synonym list */ +- for (s = type->synonyms; s; s = strchr(s, ' ')) { +- while (*s && isspace(*s)) s++; /* skip spaces */ +- if(!strncasecmp(name, s, len) && !isprint(*(s + len))) break;/*found*/ +- } +- if(s) break; /* found a synonym */ ++ if (strcmp(type, "raw") == 0) ++ repeater.raw = 1; ++ else { ++ repeater.raw = 0; ++ ++ if (!(repeater.type = find_mouse_by_name(type))) ++ exit(M_listTypes()); /* not found */ ++ ++ if (!repeater.type->repeat_fun) /* unsupported translation */ ++ gpm_report(GPM_PR_OOPS, GPM_MESS_NO_REPEAT, type); + } +- if (!type->fun) return NULL; +- return type; + } + + /***************************************************************************** +@@ -230,60 +133,86 @@ + * Can't believe it, today cmdline() really does what the name tries to say + *****************************************************************************/ + void cmdline(int argc, char **argv) +-{ +- extern struct options option; ++{ ++ struct micetab *mouse; ++ struct miceopt *opt; + char options[]="a:A::b:B:d:Dg:hi:kl:m:Mo:pr:R::s:S:t:TuvV::23"; +- int opt; ++ int opt_char, tmp; ++ int mouse_no = 1; ++ ++ mouse = add_mouse(); ++ opt = &mouse->options; + +- /* initialize for the dual mouse */ +- mouse_table[2]=mouse_table[1]=mouse_table[0]; /* copy defaults */ +- which_mouse=mouse_table+1; /* use the first */ +- +- while ((opt = getopt(argc, argv, options)) != -1) { +- switch (opt) { +- case 'a': opt_accel = atoi(optarg); break; +- case 'A': opt_aged++; +- if (optarg) +- opt_age_limit = atoi(optarg); break; +- case 'b': opt_baud = atoi(optarg); break; +- case 'B': opt_sequence = optarg; break; +- case 'd': opt_delta = atoi(optarg); break; +- case 'D': option.run_status = GPM_RUN_DEBUG; break; +- case 'g': opt_glidepoint_tap=atoi(optarg); break; +- case 'h': exit(usage(NULL)); +- case 'i': opt_time=atoi(optarg); break; +- case 'k': check_kill(); break; +- case 'l': opt_lut = optarg; break; +- case 'm': add_mouse(GPM_ADD_DEVICE,optarg); +- opt_dev = optarg; break; /* GO AWAY!*/ +- case 'M': opt_double++; option.repeater++; +- if (option.repeater_type == 0) +- option.repeater_type = "msc"; +- which_mouse=mouse_table+2; break; +- case 'o': add_mouse(GPM_ADD_OPTIONS,optarg); +- gpm_report(GPM_PR_DEBUG,"options: %s",optarg); +- opt_options = optarg; break; /* GO AWAY */ +- case 'p': opt_ptrdrag = 0; break; +- case 'r': +- /* being called responsiveness, I must take the inverse */ +- opt_scale=atoi(optarg); +- if(!opt_scale || opt_scale > 100) opt_scale=100; /* the maximum */ +- else opt_scale=100/opt_scale; break; +- case 'R': +- option.repeater++; +- if (optarg) option.repeater_type = optarg; +- else option.repeater_type = "msc"; break; +- case 's': opt_sample = atoi(optarg); break; +- case 'S': if (optarg) opt_special = optarg; +- else opt_special=""; break; +- case 't': add_mouse(GPM_ADD_TYPE,optarg); +- opt_type = optarg; break; /* GO AWAY */ +- case 'u': option.autodetect = 1; break; +- case 'T': opt_test++; break; +- case 'v': printf(GPM_MESS_VERSION "\n"); exit(0); +- case '2': opt_three = -1; break; +- case '3': opt_three = 1; break; +- default: exit(usage("commandline")); ++ while ((opt_char = getopt(argc, argv, options)) != -1) { ++ switch (opt_char) { ++ case 'a': if ((opt->accel = atoi(optarg)) < 1) ++ exit(usage("acceleration")); ++ break; ++ case 'A': sel_opts.aged = 1; ++ if (optarg) ++ sel_opts.age_limit = atoi(optarg); ++ break; ++ case 'b': opt->baud = atoi(optarg); ++ break; ++ case 'B': init_button_sequence(opt, optarg); ++ break; ++ case 'd': if ((opt->delta = atoi(optarg)) < 2) ++ exit(usage("delta")); ++ break; ++ case 'D': option.run_status = GPM_RUN_DEBUG; ++ break; ++ case 'g': if (atoi(optarg) > 3) ++ exit(usage("glidepoint tap button")); ++ opt->glidepoint_tap = GPM_B_LEFT >> (atoi(optarg) - 1); ++ break; ++ case 'h': exit(usage(NULL)); ++ case 'i': opt->time = atoi(optarg); ++ break; ++ case 'k': kill_gpm(); ++ break; ++ case 'l': console.charset = optarg; ++ break; ++ case 'm': mouse->device = optarg; ++ break; ++ case 'M': validate_mouse(mouse, mouse_no); ++ mouse = add_mouse(); ++ opt = &mouse->options; ++ mouse_no++; ++ if (!repeater.type && !repeater.raw) ++ repeater.type = find_mouse_by_name(DEF_REP_TYPE); ++ break; ++ case 'o': gpm_report(GPM_PR_DEBUG,"options: %s", optarg); ++ opt->text = optarg; ++ break; ++ case 'p': sel_opts.ptrdrag = 0; ++ break; ++ case 'r': /* being called responsiveness, I must take the inverse */ ++ tmp = atoi(optarg); ++ if (!tmp || tmp > 100) tmp = 1; ++ opt->scalex = 100 / tmp; ++ break; ++ case 'R': validate_repeater((optarg) ? optarg : DEF_REP_TYPE); ++ break; ++ case 's': opt->sample = atoi(optarg); ++ break; ++ case 'S': if (optarg) opt_special = optarg; ++ else opt_special=""; ++ break; ++ case 't': mouse->type = find_mouse_by_name(optarg); ++ if (!mouse->type) ++ exit(M_listTypes()); ++ break; ++ case 'u': option.autodetect = 1; ++ break; ++ case 'v': printf(GPM_MESS_VERSION "\n"); ++ exit(0); ++ case '2': opt->three_button = -1; ++ break; ++ case '3': opt->three_button = 1; ++ break; ++ default: exit(usage("commandline")); + } + } ++ ++ validate_mouse(micelist, mouse_no); + } +diff -urN gpm-1.20.1/src/headers/client.h gpm/src/headers/client.h +--- gpm-1.20.1/src/headers/client.h 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/headers/client.h 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,57 @@ ++/* -*-mode:C;tab-width:3-*- ++ * client.h - GPM client handling (server side) ++ * ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#ifndef __GPM_CLIENT_H ++#define __GPM_CLIENT_H_ ++ ++#ifdef HAVE_LINUX_TTY_H ++#include <linux/tty.h> ++#endif ++ ++#include "headers/gpm.h" ++ ++/* FIXME: still needed ?? */ ++/* How many virtual consoles are managed? */ ++#ifndef MAX_NR_CONSOLES ++# define MAX_NR_CONSOLES 64 /* this is always sure */ ++#endif ++ ++#define MAX_VC MAX_NR_CONSOLES /* doesn't work before 1.3.77 */ ++ ++struct client_info { ++ Gpm_Connect data; ++ int fd; ++ struct client_info *next; ++}; ++ ++struct Gpm_Event; ++ ++extern struct client_info *cinfo[MAX_VC + 1]; ++ ++int listen_for_clients(void); ++struct client_info *accept_client_connection(int fd); ++void remove_client(struct client_info *ci, int vc); ++void notify_clients_resize(void); ++int do_client(struct client_info *cinfo, struct Gpm_Event *event); ++int process_client_request(struct client_info *ci, int vc, ++ int x, int y, int buttons, int clicks, ++ int three_button_mouse); ++ ++#endif /* __GPM_CLIENT_H_ */ +diff -urN gpm-1.20.1/src/headers/console.h gpm/src/headers/console.h +--- gpm-1.20.1/src/headers/console.h 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/headers/console.h 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,42 @@ ++/* -*-mode:C;tab-width:3-*- ++ * console.h - GPM console and selection/paste handling ++ * ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#ifndef __GPM_CONSOLE_H_ ++#define __GPM_CONSOLE_H_ ++ ++struct gpm_console { ++ char *device; ++ char *charset; ++ int max_x, max_y; ++}; ++ ++extern struct gpm_console console; ++ ++int open_console(int mode); ++char *get_console_name(); ++char *compose_vc_name(int vc); ++int is_text_console(void); ++void wait_text_console(void); ++void refresh_console_size(void); ++int is_console_owner(int vc, uid_t uid); ++int get_console_state(unsigned char *shift_state); ++void console_load_lut(void); ++ ++#endif /* __GPM_CONSOLE_H_ */ +diff -urN gpm-1.20.1/src/headers/gpmInt.h gpm/src/headers/gpmInt.h +--- gpm-1.20.1/src/headers/gpmInt.h 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/headers/gpmInt.h 2003-10-02 01:22:42.000000000 -0500 +@@ -23,8 +23,7 @@ + #ifndef _GPMINT_INCLUDED + #define _GPMINT_INCLUDED + +-#include <sys/types.h> /* time_t */ /* for whom ???? FIXME */ +- ++#include <sys/time.h> /* timeval */ + #include "gpm.h" + + #if !defined(__GNUC__) +@@ -35,23 +34,12 @@ + /* timeout for the select() syscall */ + #define SELECT_TIME 86400 /* one day */ + +-#ifdef HAVE_LINUX_TTY_H +-#include <linux/tty.h> +-#endif +- +-/* FIXME: still needed ?? */ +-/* How many virtual consoles are managed? */ +-#ifndef MAX_NR_CONSOLES +-# define MAX_NR_CONSOLES 64 /* this is always sure */ +-#endif +- +-#define MAX_VC MAX_NR_CONSOLES /* doesn't work before 1.3.77 */ +- + /* How many buttons may the mouse have? */ + /* #define MAX_BUTTONS 3 ===> not used, it is hardwired :-( */ + + /* all the default values */ + #define DEF_TYPE "ms" ++#define DEF_REP_TYPE "msc" + #define DEF_DEV NULL /* use the type-related one */ + #define DEF_LUT "-a-zA-Z0-9_./\300-\326\330-\366\370-\377" + #define DEF_SEQUENCE "123" /* how buttons are reordered */ +@@ -62,12 +50,10 @@ + #define DEF_SCALE 10 + #define DEF_TIME 250 /* time interval (ms) for multiple clicks */ + #define DEF_THREE 0 /* have three buttons? */ +-#define DEF_KERNEL 0 /* no kernel module, by default */ + + /* 10 on old computers (<=386), 0 on current machines */ + #define DEF_CLUSTER 0 /* maximum number of clustered events */ + +-#define DEF_TEST 0 + #define DEF_PTRDRAG 1 /* double or triple click */ + #define DEF_GLIDEPOINT_TAP 0 /* tapping emulates no buttons by default */ + +@@ -84,11 +70,6 @@ + #define GPM_DEVFS_CONSOLE "/dev/vc/0" + #define GPM_OLD_CONSOLE "/dev/tty0" + +-/* for adding a mouse; add_mouse */ +-#define GPM_ADD_DEVICE 0 +-#define GPM_ADD_TYPE 1 +-#define GPM_ADD_OPTIONS 2 +- + /*** mouse commands ***/ + + #define GPM_AUX_SEND_ID 0xF2 +@@ -117,126 +98,95 @@ + + /*....................................... Structures */ + ++struct micedev { ++ int fd; ++ int timeout; /* the protocol driver wants to be called ++ after X msec even if there is no new data ++ arrived (-1 to disable/default) */ ++ void *private; /* private data maintained by protocol driver */ ++}; ++ ++struct miceopt { ++ char *sequence; ++ int baud; ++ int sample; ++ int delta; ++ int accel; ++ int scalex, scaley; ++ int time; ++ int cluster; ++ int three_button; ++ int glidepoint_tap; ++ int absolute; /* device reports absolute coordinates - initially copied ++ from Gpm_Type; allows same protocol (type) control devices ++ in absolute and relative mode */ ++ char *text; /* extra textual options supplied via '-o text' */ ++}; ++ + /* + * and this is the entry in the mouse-type table + */ + typedef struct Gpm_Type { +- char *name; +- char *desc; /* a descriptive line */ +- char *synonyms; /* extra names (the XFree name etc) as a list */ +- int (*fun)(Gpm_Event *state, unsigned char *data); +- struct Gpm_Type *(*init)(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv); +- unsigned short flags; +- unsigned char proto[4]; +- int packetlen; +- int howmany; /* how many bytes to read at a time */ +- int getextra; /* does it get an extra byte? (only mouseman) */ +- int absolute; /* flag indicating absolute pointing device */ ++ char *name; ++ char *desc; /* a descriptive line */ ++ char *synonyms; /* extra names (the XFree name etc) as a list */ ++ int (*fun)(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state); ++ int (*init)(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type); ++ unsigned short flags; ++ unsigned char proto[4]; ++ int packetlen; ++ int howmany; /* how many bytes to read at a time */ ++ int getextra; /* does it get an extra byte? (only mouseman) */ ++ int absolute; /* flag indicating absolute pointing device */ + +- int (*repeat_fun)(Gpm_Event *state, int fd); /* repeat this event into fd */ ++ int (*repeat_fun)(Gpm_Event *state, int fd); /* repeat this event into fd */ + /* itz Mon Jan 11 23:27:54 PST 1999 */ + } Gpm_Type; + + #define GPM_EXTRA_MAGIC_1 0xAA + #define GPM_EXTRA_MAGIC_2 0x55 + +-typedef struct Gpm_Cinfo { +- Gpm_Connect data; +- int fd; +- struct Gpm_Cinfo *next; +-} Gpm_Cinfo; +- +- +-/*....................................... Global variables */ +- +-/* this structure is used to hide the dual-mouse stuff */ +- +-struct mouse_features { +- char *opt_type, *opt_dev, *opt_sequence; +- int opt_baud,opt_sample,opt_delta, opt_accel, opt_scale, opt_scaley; +- int opt_time, opt_cluster, opt_three, opt_glidepoint_tap; +- char *opt_options; /* extra textual configuration */ +- Gpm_Type *m_type; +- int fd; +-}; +- +-extern struct mouse_features mouse_table[3], *which_mouse; /*the current one*/ +- +-// looks unused; delete +-//typedef struct Opt_struct_type {int a,B,d,i,p,r,V,A;} Opt_struct_type; +- +-/* this is not very clean, actually, but it works fine */ +-#define opt_type (which_mouse->opt_type) +-#define opt_dev (which_mouse->opt_dev) +-#define opt_sequence (which_mouse->opt_sequence) +-#define opt_baud (which_mouse->opt_baud) +-#define opt_sample (which_mouse->opt_sample) +-#define opt_delta (which_mouse->opt_delta) +-#define opt_accel (which_mouse->opt_accel) +-#define opt_scale (which_mouse->opt_scale) +-#define opt_scaley (which_mouse->opt_scaley) +-#define opt_time (which_mouse->opt_time) +-#define opt_cluster (which_mouse->opt_cluster) +-#define opt_three (which_mouse->opt_three) +-#define opt_glidepoint_tap (which_mouse->opt_glidepoint_tap) +-#define opt_options (which_mouse->opt_options) +- +-#define m_type (which_mouse->m_type) +- +-/* the other variables */ +- +-extern char *opt_lut; +-extern int opt_test, opt_ptrdrag; +-extern int opt_kill; +-extern int opt_kernel, opt_explicittype; +-extern int opt_aged; +-extern time_t opt_age_limit; + extern char *opt_special; +-extern int opt_rawrep; +-extern int fifofd; +-extern int opt_double; +- +-extern Gpm_Type *repeated_type; + extern Gpm_Type mice[]; /* where the hell are the descriptions...*/ +-extern struct winsize win; +-extern int maxx, maxy; +-extern Gpm_Cinfo *cinfo[MAX_VC+1]; + + /* new variables <CLEAN> */ + + /* structure prototypes */ ++struct repeater { ++ int fd; ++ int raw; ++ Gpm_Type *type; ++}; + + /* contains all mice */ + struct micetab { + struct micetab *next; +- char *device; +- char *protocol; +- char *options; ++ struct micedev dev; ++ struct miceopt options; ++ Gpm_Type *type; ++ char *device; ++ int buttons; /* mouse's button state from last read */ ++ struct timeval timestamp; /* last time mouse data arrived */ + }; + + struct options { + int autodetect; /* -u [aUtodetect..'A' is not available] */ +- int no_mice; /* number of mice */ +- int repeater; /* repeat data */ +- char *repeater_type; /* repeat data as which mouse type */ + int run_status; /* startup/daemon/debug */ + char *progname; /* hopefully gpm ;) */ +- struct micetab *micelist; /* mice and their options */ +- char *consolename; /* /dev/tty0 || /dev/vc/0 */ + }; + + /* global variables */ + struct options option; /* one should be enough for us */ ++extern struct repeater repeater; /* again, only one */ ++extern struct micetab *micelist; + + /* new variables </CLEAN> */ + +- + /*....................................... Prototypes */ + /* server_tools.c */ +-void add_mouse (int type, char *value); +-int init_mice (struct micetab *micelist); +-int reset_mice(struct micetab *micelist); ++struct micetab *add_mouse(void); ++void init_mice(void); ++void cleanup_mice(void); + + /* startup.c */ + void startup(int argc, char **argv); +@@ -246,17 +196,15 @@ + + /* gpn.c */ + void cmdline(int argc, char **argv); +-int giveInfo(int request, int fd); +-int loadlut(char *charset); +-int usage(char *whofailed); +-struct Gpm_Type *find_mouse_by_name(char *name); ++int giveInfo(int request, int fd); ++int usage(char *whofailed); + void check_uniqueness(void); +-void check_kill(void); +- ++void kill_gpm(void); + + /* mice.c */ + extern int M_listTypes(void); +- /* special.c */ ++ ++ /* special.c */ + int processSpecial(Gpm_Event *event); + int twiddler_key(unsigned long message); + int twiddler_key_init(void); +diff -urN gpm-1.20.1/src/headers/input-defines.h gpm/src/headers/input-defines.h +--- gpm-1.20.1/src/headers/input-defines.h 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/headers/input-defines.h 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,81 @@ ++/* ++ * input-defines.h - complements <linux/input.h> adding missing bits ++ * ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++#ifndef __GPM_INPUT_DEFINES_H ++#define __GPM_INPUT_DEFINES_H ++ ++#include <linux/input.h> ++#include "headers/config.h" ++ ++#ifndef ABS_TOOL_WIDTH ++#define ABS_TOOL_WIDTH 0x1c ++#endif ++ ++#ifndef BTN_TOOL_FINGER ++#define BTN_TOOL_FINGER 0x145 ++#endif ++ ++#ifndef BTN_TOUCH ++#define BTN_TOUCH 0x14a ++#endif ++ ++#ifndef BTN_TOOL_DOUBLETAP ++#define BTN_TOOL_DOUBLETAP 0x14d ++#endif ++ ++#ifndef BTN_TOOL_TRIPLETAP ++#define BTN_TOOL_TRIPLETAP 0x14e ++#endif ++ ++#ifndef MSC_GESTURE ++#define MSC_GESTURE 2 ++#endif ++ ++#ifndef EV_SYNC ++#define EV_SYNC 0 ++#endif ++ ++#ifndef SYN_REPORT ++#define SYN_REPORT 0 ++#endif ++ ++#ifndef PSMOUSE_SYNAPTICS ++#define PSMOUSE_SYNAPTICS 7 ++#endif ++ ++#ifndef HAVE_INPUT_ID ++struct input_id { ++ unsigned short bustype; ++ unsigned short vendor; ++ unsigned short product; ++ unsigned short version; ++}; ++#endif ++ ++#ifndef HAVE_INPUT_ABSINFO ++struct input_absinfo { ++ int value; ++ int minimum; ++ int maximum; ++ int fuzz; ++ int flat; ++}; ++#endif ++ ++#endif +diff -urN gpm-1.20.1/src/headers/message.h gpm/src/headers/message.h +--- gpm-1.20.1/src/headers/message.h 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/headers/message.h 2003-10-02 01:22:42.000000000 -0500 +@@ -96,7 +96,6 @@ + " -S [commands] enable special commands (see man page)\n" \ + " -t mouse-type sets mouse type (default '%s')\n" \ + " Use a non-existent type (e.g. \"help\") to get a list\n" \ +- " -T test: read mouse, no clients\n" \ + " -v print version and exit\n" \ + " -V verbosity increase number of logged messages\n\n\n" \ + " Examples:\n\n" \ +@@ -168,7 +167,8 @@ + #define GPM_MESS_SELECT_TIMES "selected %i times" + + #define GPM_MESS_OPTION_NO_ARG "%s: Option \"%s\" takes no argument: ignoring \"%s\"" +-#define GPM_MESS_INVALID_ARG "%s: Invalid arg. \"%s\" to \"%s\"" ++#define GPM_MESS_INVALID_ARG "%s: Invalid argument \"%s\" for option \"%s\"" ++#define GPM_MESS_MISSING_ARG "%s: Option \"%s\" requires an argument" + #define GPM_MESS_CONT_WITH_ERR "%s: Continuing despite errors in option parsing" + #define GPM_MESS_TOO_MANY_OPTS "%s: Too many options for \"-t %s\"" + +@@ -196,7 +196,7 @@ + + /* warnings */ + #define GPM_MESS_REQUEST_ON "Request on vc %i > %i" +-#define GPM_MESS_FAILED_CONNECT "Failed gpm connect attempt by uid %d for vc %s" ++#define GPM_MESS_FAILED_CONNECT "Failed gpm connect attempt by uid %d for vc %d" + #define GPM_MESS_ZERO_SCREEN_DIM "zero screen dimension, assuming 80x25" + #define GPM_MESS_STRANGE_DATA "Data on strange file descriptor %d" + #define GPM_MESS_RESIZING "%s pid %i is resizing :-)" +diff -urN gpm-1.20.1/src/headers/optparser.h gpm/src/headers/optparser.h +--- gpm-1.20.1/src/headers/optparser.h 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/headers/optparser.h 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,50 @@ ++/* ++ * optparser.h - GPM mouse options parser ++ * ++ * Copyright (C) 1993 Andrew Haylett <ajh@gec-mrc.co.uk> ++ * Copyright (C) 1994-2000 Alessandro Rubini <rubini@linux.it> ++ * Copyright (C) 1998,1999 Ian Zimmerman <itz@rahul.net> ++ * Copyright (C) 2001,2002 Nico Schottelius <nicos@pcsystems.de> ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++#ifndef __GPM_OPTPARSER_H_ ++#define __GPM_OPTPARSER_H_ ++ ++enum option_type { ++ OPT_BOOL = 1, ++ OPT_INT, /* "%i" */ ++ OPT_DEC, /* "%d" */ ++ OPT_STRING, ++ /* other types must be added */ ++ OPT_END = 0 ++}; ++ ++struct option_helper { ++ char *name; ++ enum option_type type; ++ union u { ++ int *iptr; /* used for int and bool arguments */ ++ char **sptr; /* used for string arguments, by strdup()ing the value */ ++ } u; ++ int value; /* used for boolean arguments */ ++ int present; ++}; ++ ++int parse_options(const char *who, const char *opt, char sep, struct option_helper *info); ++int check_no_options(const char *proto, const char *opts, char sep); ++int is_option_present(struct option_helper *info, const char *name); ++#endif +diff -urN gpm-1.20.1/src/headers/selection.h gpm/src/headers/selection.h +--- gpm-1.20.1/src/headers/selection.h 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/headers/selection.h 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,37 @@ ++/* ++ * console.h - GPM selection/paste handling ++ * ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#ifndef __GPM_SELECTION_H_ ++#define __GPM_SELECTION_H_ ++ ++struct sel_options { ++ int aged; ++ int age_limit; ++ int ptrdrag; ++}; ++ ++struct Gpm_Event; ++ ++extern struct sel_options sel_opts; /* only one exists */ ++ ++void do_selection(struct Gpm_Event *event, int three_button_mode); ++void selection_disable_paste(void); ++ ++#endif /* __GPM_CONSOLE_H_ */ +diff -urN gpm-1.20.1/src/headers/synaptics.h gpm/src/headers/synaptics.h +--- gpm-1.20.1/src/headers/synaptics.h 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/headers/synaptics.h 2003-10-02 01:22:42.000000000 -0500 +@@ -62,7 +62,7 @@ + ** + ** Process the touchpad 6/7/8 byte data. + */ +-void syn_process_serial_data (Gpm_Event *state, ++void syn_process_serial_data (int fd, Gpm_Event *state, + unsigned char *data); + + +@@ -72,7 +72,7 @@ + ** + ** Process the touchpad 6 byte data. + */ +-void syn_process_ps2_data (Gpm_Event *state, ++void syn_process_ps2_data (int fd, Gpm_Event *state, + unsigned char *data); + + +diff -urN gpm-1.20.1/src/lib/liblow.c gpm/src/lib/liblow.c +--- gpm-1.20.1/src/lib/liblow.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/lib/liblow.c 2003-10-02 01:22:42.000000000 -0500 +@@ -80,6 +80,8 @@ + int gpm_consolefd=-1; /* used to invoke ioctl() */ + int gpm_morekeys=0; + ++static char *consolename; ++ + int gpm_convert_event(unsigned char *mdata, Gpm_Event *ePtr); + + /*----------------------------------------------------------------------------* +@@ -192,14 +194,13 @@ + char *tty = NULL; + char *term = NULL; + int i; +- extern struct options option; + static int checked_con = 0; + struct sockaddr_un addr; + struct winsize win; + Gpm_Stst *new = NULL; + char* sock_name = 0; + +- option.consolename = NULL; ++ consolename = NULL; + + gpm_report(GPM_PR_DEBUG,"VC: %d",flag); + +@@ -216,7 +217,7 @@ + + /* check whether we know what name the console is: what's with the lib??? */ + if(checked_con == 0) { +- option.consolename = Gpm_get_console(); ++ consolename = Gpm_get_console(); + checked_con++; + } + +@@ -245,10 +246,10 @@ + conn->vc=0; /* default handler */ + if (flag > 0) { /* forced vc number */ + conn->vc=flag; +- if((tty = malloc(strlen(option.consolename)+Gpm_cnt_digits(flag))) == NULL) ++ if((tty = malloc(strlen(consolename)+Gpm_cnt_digits(flag))) == NULL) + gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- memcpy(tty,option.consolename,strlen(option.consolename)-1); +- sprintf(&tty[strlen(option.consolename)-1],"%i",flag); ++ memcpy(tty,consolename,strlen(consolename)-1); ++ sprintf(&tty[strlen(consolename)-1],"%i",flag); + } else { /* use your current vc */ + if (isatty(0)) tty = ttyname(0); /* stdin */ + if (!tty && isatty(1)) tty = ttyname(1); /* stdout */ +@@ -258,13 +259,13 @@ + goto err; + } + /* do we really need this check ? */ +- if(strncmp(tty,option.consolename,strlen(option.consolename)-1) +- || !isdigit(tty[strlen(option.consolename)-1])) { +- gpm_report(GPM_PR_ERR,"strncmp/isdigit/option.consolename failed"); ++ if(strncmp(tty,consolename,strlen(consolename)-1) ++ || !isdigit(tty[strlen(consolename)-1])) { ++ gpm_report(GPM_PR_ERR,"strncmp/isdigit/consolename failed"); + goto err; + } + +- conn->vc=atoi(&tty[strlen(option.consolename)-1]); ++ conn->vc=atoi(&tty[strlen(consolename)-1]); + } + + if (gpm_consolefd == -1) +@@ -272,6 +273,8 @@ + gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,tty,strerror(errno)); + goto err; + } ++ ++ if (flag > 0) free(tty); + } + + new->info=*conn; +diff -urN gpm-1.20.1/src/lib/tools.c gpm/src/lib/tools.c +--- gpm-1.20.1/src/lib/tools.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/lib/tools.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,93 @@ ++/* ++ * tools.c - tools which are needed by client and server ++ * ++ * Copyright (c) 2001 Nico Schottelius <nico@schottelius.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#include <stdio.h> /* NULL */ ++#include <string.h> ++#include <stdlib.h> ++#include <sys/types.h> /* these three are */ ++#include <sys/stat.h> /* needed for */ ++#include <unistd.h> /* stat() */ ++ ++#include "headers/gpmInt.h" /* only used for some defines */ ++#include "headers/message.h" ++ ++/***************************************************************************** ++ * check, whether devfs is used or not. ++ * See /usr/src/linux/Documentation/filesystems/devfs/ for details. ++ * Returns: the name of the console (/dev/tty0 or /dev/vc/0) ++ *****************************************************************************/ ++char *Gpm_get_console( void ) ++{ ++ ++ char *back = NULL, *tmp = NULL; ++ struct stat buf; ++ ++ /* first try the devfs device, because in the next time this will be ++ * the preferred one. If that fails, take the old console */ ++ ++ /* Check for open new console */ ++ if (stat(GPM_DEVFS_CONSOLE,&buf) == 0) ++ tmp = GPM_DEVFS_CONSOLE; ++ ++ /* Failed, try OLD console */ ++ else if(stat(GPM_OLD_CONSOLE,&buf) == 0) ++ tmp = GPM_OLD_CONSOLE; ++ ++ if(tmp != NULL) ++ if((back = malloc(strlen(tmp) + sizeof(char)) ) != NULL) ++ strcpy(back,tmp); ++ ++ return(back); ++} ++ ++/* what's the english name for potenz ? */ ++int Gpm_x_high_y(int base, int pot_y) ++{ ++ int val = 1; ++ ++ if(pot_y == 0) val = 1; ++ else if(pot_y < 0) val = 0; /* ugly hack ;) */ ++ else while(pot_y > 0) { ++ val = val * base; ++ pot_y--; ++ } ++ return val; ++} ++ ++/* return characters needed to display int */ ++int Gpm_cnt_digits(int number) ++{ ++ /* 0-9 = 1 10^0 <-> (10^1)-1 ++ * 10 - 99 = 2 10^1 <-> (10^2)-1 ++ * 100 - 999 = 3 10^2 <-> (10^3)-1 ++ * 1000 - 9999 = 4 ... */ ++ ++ int ret = 0, num = 0; ++ ++ /* non negative, please */ ++ if(number < 0) number *= -1; ++ else if(number == 0) ret = 1; ++ else while(number > num) { ++ ret++; ++ num = (Gpm_x_high_y(10,ret) - 1); ++ } ++ ++ return(ret); ++} +diff -urN gpm-1.20.1/src/Makefile.in gpm/src/Makefile.in +--- gpm-1.20.1/src/Makefile.in 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/Makefile.in 2003-10-02 01:22:42.000000000 -0500 +@@ -12,15 +12,16 @@ + include $(top_builddir)/Makefile.include + + # Main portion: regular build rules ++MICESRC = mice.c twiddler.c synaptics.c @EVDEV_SRCS@ + +-GSRC = main.c gpm.c gpn.c mice.c special.c twiddler.c synaptics.c \ +- startup.c server_tools.c ++GSRC = main.c gpm.c gpn.c special.c startup.c server_tools.c console.c \ ++ selection.c client.c optparser.c $(MICESRC) + +-GOBJ = $(GSRC:.c=.o) report.o tools.o ++GOBJ = $(GSRC:.c=.o) report.o + +-LSRC = lib/liblow.c lib/libhigh.c lib/libxtra.c lib/report-lib.c ++LSRC = lib/liblow.c lib/libhigh.c lib/libxtra.c lib/report-lib.c lib/tools.c + +-LOBJ = $(LSRC:.c=.o) tools.o @CURSES_OBJS@ ++LOBJ = $(LSRC:.c=.o) @CURSES_OBJS@ + + PICS = $(LOBJ:.o=.lo) + +@@ -143,7 +144,7 @@ + $(CC) -I. @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@.o $< + $(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $@.o @LIBS@ $(LIBS) lib/libgpm.a + +-prog/mouse-test: mice.o twiddler.o synaptics.o ++prog/mouse-test: $(MICESRC:.c=.o) console.o optparser.o + + $(PROG): lib/libgpm.so lib/@SHLIB@ lib/libgpm.a + +diff -urN gpm-1.20.1/src/mice.c gpm/src/mice.c +--- gpm-1.20.1/src/mice.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/mice.c 2003-10-02 01:22:42.000000000 -0500 +@@ -46,15 +46,11 @@ + #include <string.h> + #include <stdlib.h> + #include <termios.h> +-#include <fcntl.h> +-#include <termios.h> + #include <errno.h> + #include <unistd.h> + #include <ctype.h> + +-#include <sys/types.h> + #include <sys/stat.h> /* stat() */ +-#include <sys/time.h> /* select() */ + + #include <linux/kdev_t.h> /* MAJOR */ + #include <linux/keyboard.h> +@@ -72,135 +68,40 @@ + + + #include "headers/gpmInt.h" ++#include "headers/console.h" + #include "headers/twiddler.h" + #include "headers/synaptics.h" + #include "headers/message.h" +- +-/*========================================================================*/ +-/* Parsing argv: helper dats struct function (should they get elsewhere?) */ +-/*========================================================================*/ +- +-enum argv_type { +- ARGV_BOOL = 1, +- ARGV_INT, /* "%i" */ +- ARGV_DEC, /* "%d" */ +- ARGV_STRING, +- /* other types must be added */ +- ARGV_END = 0 +-}; +- +-typedef struct argv_helper { +- char *name; +- enum argv_type type; +- union u { +- int *iptr; /* used for int and bool arguments */ +- char **sptr; /* used for string arguments, by strdup()ing the value */ +- } u; +- int value; /* used for boolean arguments */ +-} argv_helper; +- +-static int parse_argv(argv_helper *info, int argc, char **argv) +-{ +- int i, j = 0, errors = 0; +- long l; +- argv_helper *p; +- char *s, *t; +- int base = 0; /* for strtol */ +- +- +- for (i=1; i<argc; i++) { +- for (p = info; p->type != ARGV_END; p++) { +- j = strlen(p->name); +- if (strncmp(p->name, argv[i], j)) +- continue; +- if (isalnum(argv[i][j])) +- continue; +- break; +- } +- if (p->type == ARGV_END) { /* not found */ +- fprintf(stderr, "%s: Uknown option \"%s\" for pointer \"%s\"\n", +- option.progname, argv[i], argv[0]); +- errors++; +- continue; +- } +- /* Found. Look for trailing stuff, if any */ +- s = argv[i]+j; +- while (*s && isspace(*s)) s++; /* skip spaces */ +- if (*s == '=') s++; /* skip equal */ +- while (*s && isspace(*s)) s++; /* skip other spaces */ +- +- /* Now parse what s is */ +- switch(p->type) { +- case ARGV_BOOL: +- if (*s) { +- gpm_report(GPM_PR_ERR,GPM_MESS_OPTION_NO_ARG,option.progname,p->name,s); +- errors++; +- } +- *(p->u.iptr) = p->value; +- break; +- +- case ARGV_DEC: +- base = 10; /* and fall through */ +- case ARGV_INT: +- l = strtol(s, &t, base); +- if (*t) { +- gpm_report(GPM_PR_ERR,GPM_MESS_INVALID_ARG, option.progname, s, p->name); +- errors++; +- break; +- } +- *(p->u.iptr) = (int)l; +- break; +- +- case ARGV_STRING: +- *(p->u.sptr) = strdup(s); +- break; +- +- case ARGV_END: /* let's please "-Wall" */ +- break; +- } +- } /* for i in argc */ +- if (errors) gpm_report(GPM_PR_ERR,GPM_MESS_CONT_WITH_ERR, option.progname); +- return errors; +-} +- +-/*========================================================================*/ +-/* Provide a common error engine by parsing with an empty option-set */ +-/*========================================================================*/ +-static volatile int check_no_argv(int argc, char **argv) +-{ +- static argv_helper optioninfo[] = { +- {"", ARGV_END} +- }; +- return parse_argv(optioninfo, argc, argv); +-} ++#include "headers/optparser.h" + + /*========================================================================*/ + /* Parse the "old" -o options */ + /*========================================================================*/ +-static int option_modem_lines(int fd, int argc, char **argv) ++static int option_modem_lines(int fd, char *proto, char *opts) + { +- static unsigned int err, lines, reallines; ++ static unsigned int lines, reallines; ++ static struct option_helper optioninfo[] = { ++ {"dtr", OPT_BOOL, u: {iptr: &lines}, value: TIOCM_DTR}, ++ {"rts", OPT_BOOL, u: {iptr: &lines}, value: TIOCM_RTS}, ++ {"both", OPT_BOOL, u: {iptr: &lines}, value: TIOCM_DTR | TIOCM_RTS}, ++ {"", OPT_END} ++ }; + +- static argv_helper optioninfo[] = { +- {"dtr", ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_DTR}, +- {"rts", ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_RTS}, +- {"both", ARGV_BOOL, u: {iptr: &lines}, value: TIOCM_DTR | TIOCM_RTS}, +- {"", ARGV_END} +- }; ++ int rslt = parse_options(proto, opts, ',', optioninfo); + +- if (argc<2) return 0; +- if (argc > 2) { +- gpm_report(GPM_PR_ERR,GPM_MESS_TOO_MANY_OPTS,option.progname, argv[0]); ++ if (rslt < 0) { ++ errno = EINVAL; ++ return -1; ++ } else if (rslt > 1) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_TOO_MANY_OPTS, option.progname, proto); + errno = EINVAL; /* used by gpm_oops(), if the caller reports failure */ + return -1; ++ } else if (rslt == 1) { ++ /* ok, move the lines */ ++ ioctl(fd, TIOCMGET, &reallines); ++ reallines &= ~lines; ++ ioctl(fd, TIOCMSET, &reallines); + } +- err = parse_argv(optioninfo, argc, argv); +- if(err) return 0; /* a message has been printed, but go on as good */ +- +- /* ok, move the lines */ +- ioctl(fd, TIOCMGET, &reallines); +- reallines &= ~lines; +- ioctl(fd, TIOCMSET, &reallines); + return 0; + } + +@@ -233,28 +134,12 @@ + /*========================================================================*/ + + #ifdef HAVE_LINUX_INPUT_H +-static int M_evdev (Gpm_Event * state, unsigned char *data) +-{ +- struct input_event thisevent; +- (void) memcpy (&thisevent, data, sizeof (struct input_event)); +- if (thisevent.type == EV_REL) { +- if (thisevent.code == REL_X) +- state->dx = (signed char) thisevent.value; +- else if (thisevent.code == REL_Y) +- state->dy = (signed char) thisevent.value; +- } else if (thisevent.type == EV_KEY) { +- switch(thisevent.code) { +- case BTN_LEFT: state->buttons ^= GPM_B_LEFT; break; +- case BTN_MIDDLE: state->buttons ^= GPM_B_MIDDLE; break; +- case BTN_RIGHT: state->buttons ^= GPM_B_RIGHT; break; +- case BTN_SIDE: state->buttons ^= GPM_B_MIDDLE; break; +- } +- } +- return 0; +-} ++/* defined in evdev.c */ ++extern int M_evdev(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state); ++extern int I_evdev(struct micedev *dev, struct miceopt *opt, Gpm_Type *type); + #endif /* HAVE_LINUX_INPUT_H */ + +-static int M_ms(Gpm_Event *state, unsigned char *data) ++static int M_ms(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* + * some devices report a change of middle-button state by +@@ -273,7 +158,7 @@ + return 0; + } + +-static int M_ms_plus(Gpm_Event *state, unsigned char *data) ++static int M_ms_plus(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + static unsigned char prev=0; + +@@ -293,7 +178,7 @@ + return 0; + } + +-static int M_ms_plus_lr(Gpm_Event *state, unsigned char *data) ++static int M_ms_plus_lr(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* + * Same as M_ms_plus but with an addition by Edmund GRIMLEY EVANS +@@ -329,19 +214,19 @@ + int SUMMA_BORDER=100; + int summamaxx,summamaxy; + char summaid=-1; +-static int M_summa(Gpm_Event *state, unsigned char *data) ++static int M_summa(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + int x, y; + + x = ((data[2]<<7) | data[1])-SUMMA_BORDER; + if (x<0) x=0; + if (x>summamaxx) x=summamaxx; +- state->x = (x * win.ws_col / summamaxx); ++ state->x = (x * console.max_x / summamaxx); + realposx = (x * 16383 / summamaxx); + + y = ((data[4]<<7) | data[3])-SUMMA_BORDER; + if (y<0) y=0; if (y>summamaxy) y=summamaxy; +- state->y = 1 + y * (win.ws_row-1)/summamaxy; ++ state->y = 1 + y * (console.max_y-1)/summamaxy; + realposy = y * 16383 / summamaxy; + + state->buttons= +@@ -396,7 +281,7 @@ + + + /* 'Genitizer' (kw@dtek.chalmers.se 11/12/97) */ +-static int M_geni(Gpm_Event *state, unsigned char *data) ++static int M_geni(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* this is a little confusing. If we use the stylus, we + * have three buttons (tip, lower, upper), and if +@@ -419,7 +304,7 @@ + + + /* m$ 'Intellimouse' (steveb 20/7/97) */ +-static int M_ms3(Gpm_Event *state, unsigned char *data) ++static int M_ms3(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->wdx = state->wdy = 0; + state->buttons= ((data[0] & 0x20) >> 3) /* left */ +@@ -470,7 +355,7 @@ + } + + /* M_brw is a variant of m$ 'Intellimouse' the middle button is different */ +-static int M_brw(Gpm_Event *state, unsigned char *data) ++static int M_brw(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= ((data[0] & 0x20) >> 3) /* left */ + | ((data[3] & 0x20) >> 4) /* middle */ +@@ -491,7 +376,7 @@ + return 0; + } + +-static int M_bare(Gpm_Event *state, unsigned char *data) ++static int M_bare(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* a bare ms protocol */ + state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4); +@@ -500,7 +385,7 @@ + return 0; + } + +-static int M_sun(Gpm_Event *state, unsigned char *data) ++static int M_sun(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= (~data[0]) & 0x07; + state->dx= (signed char)(data[1]); +@@ -508,7 +393,7 @@ + return 0; + } + +-static int M_msc(Gpm_Event *state, unsigned char *data) ++static int M_msc(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= (~data[0]) & 0x07; + state->dx= (signed char)(data[1]) + (signed char)(data[3]); +@@ -558,7 +443,7 @@ + + } + +-static int M_logimsc(Gpm_Event *state, unsigned char *data) /* same as msc */ ++static int M_logimsc(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= (~data[0]) & 0x07; + state->dx= (signed char)(data[1]) + (signed char)(data[3]); +@@ -566,7 +451,7 @@ + return 0; + } + +-static int M_mm(Gpm_Event *state, unsigned char *data) ++static int M_mm(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= data[0] & 0x07; + state->dx= (data[0] & 0x10) ? data[1] : - data[1]; +@@ -574,7 +459,7 @@ + return 0; + } + +-static int M_logi(Gpm_Event *state, unsigned char *data) /* equal to mm */ ++static int M_logi(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= data[0] & 0x07; + state->dx= (data[0] & 0x10) ? data[1] : - data[1]; +@@ -582,7 +467,7 @@ + return 0; + } + +-static int M_bm(Gpm_Event *state, unsigned char *data) /* equal to sun */ ++static int M_bm(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + state->buttons= (~data[0]) & 0x07; + state->dx= (signed char)data[1]; +@@ -590,7 +475,7 @@ + return 0; + } + +-static int M_ps2(Gpm_Event *state, unsigned char *data) ++static int M_ps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + static int tap_active=0; /* there exist glidepoint ps2 mice */ + +@@ -599,8 +484,8 @@ + !!(data[0]&2) * GPM_B_RIGHT + + !!(data[0]&4) * GPM_B_MIDDLE; + +- if (data[0]==0 && opt_glidepoint_tap) /* by default this is false */ +- state->buttons = tap_active = opt_glidepoint_tap; ++ if (data[0]==0 && opt->glidepoint_tap) /* by default this is false */ ++ state->buttons = tap_active = opt->glidepoint_tap; + else if (tap_active) { + if (data[0]==8) + state->buttons = tap_active = 0; +@@ -623,10 +508,11 @@ + state->dy= -((data[0] & 0x20) ? data[2]-256 : data[2]); + else + state->dy = 0; ++ + return 0; + } + +-static int M_imps2(Gpm_Event *state, unsigned char *data) ++static int M_imps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + + static int tap_active=0; /* there exist glidepoint ps2 mice */ +@@ -636,8 +522,8 @@ + state->buttons= ((data[0] & 1) << 2) /* left */ + | ((data[0] & 6) >> 1); /* middle and right */ + +- if (data[0]==0 && opt_glidepoint_tap) // by default this is false +- state->buttons = tap_active = opt_glidepoint_tap; ++ if (data[0]==0 && opt->glidepoint_tap) // by default this is false ++ state->buttons = tap_active = opt->glidepoint_tap; + else if (tap_active) { + if (data[0]==8) + state->buttons = tap_active = 0; +@@ -667,7 +553,7 @@ + + } + +-static int M_netmouse(Gpm_Event *state, unsigned char *data) ++static int M_netmouse(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* Avoid these beasts if you can. They connect to normal PS/2 port, + * but their protocol is one byte longer... So if you have notebook +@@ -706,47 +592,45 @@ + } + + /* standard ps2 */ +-static Gpm_Type *I_ps2(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++int I_ps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + static unsigned char s[] = { 246, 230, 244, 243, 100, 232, 3, }; +- write (fd, s, sizeof (s)); ++ write(dev->fd, s, sizeof (s)); + usleep (30000); +- tcflush (fd, TCIFLUSH); +- return type; ++ tcflush (dev->fd, TCIFLUSH); ++ return 0; + } + +-static Gpm_Type *I_netmouse(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_netmouse(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + unsigned char magic[6] = { 0xe8, 0x03, 0xe6, 0xe6, 0xe6, 0xe9 }; + int i; + +- if (check_no_argv(argc, argv)) return NULL; ++ if (!check_no_options(type->name, opt->text, ',')) return -1; + for (i=0; i<6; i++) { + unsigned char c = 0; +- write( fd, magic+i, 1 ); +- read( fd, &c, 1 ); ++ write(dev->fd, magic+i, 1 ); ++ read(dev->fd, &c, 1 ); + if (c != 0xfa) { + gpm_report(GPM_PR_ERR,GPM_MESS_NETM_NO_ACK,c); +- return NULL; ++ return -1; + } + } + { + unsigned char rep[3] = { 0, 0, 0 }; +- read( fd, rep, 1 ); +- read( fd, rep+1, 1 ); +- read( fd, rep+2, 1 ); ++ read( dev->fd, rep, 1 ); ++ read( dev->fd, rep+1, 1 ); ++ read( dev->fd, rep+2, 1 ); + if (rep[0] || (rep[1] != 0x33) || (rep[2] != 0x55)) { + gpm_report(GPM_PR_ERR,GPM_MESS_NETM_INV_MAGIC, rep[0], rep[1], rep[2]); +- return NULL; ++ return -1; + } + } +- return type; ++ return 0; + } + + #define GPM_B_BOTH (GPM_B_LEFT|GPM_B_RIGHT) +-static int M_mman(Gpm_Event *state, unsigned char *data) ++static int M_mman(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* + * the damned MouseMan has 3/4 bytes packets. The extra byte +@@ -784,7 +668,7 @@ + mytype->getextra=1; + } else { + if (b & 0x2) prev |= GPM_B_MIDDLE; +- if (b & 0x1) prev |= opt_glidepoint_tap; ++ if (b & 0x1) prev |= opt->glidepoint_tap; + } + } + state->buttons=prev; +@@ -828,7 +712,7 @@ + + #define IsA(m) ((WacomModell==(-1))? 0:!strcmp(#m,wcmodell[WacomModell].name)) + +-static int M_wacom(Gpm_Event *state, unsigned char *data) ++static int M_wacom(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + static int ox=-1, oy; + int x, y; +@@ -878,8 +762,8 @@ + if (WacomAbsoluteWanted) { /* Absolute Mode */ + if (x>wmaxx) x=wmaxx; if (x<0) x=0; + if (y>wmaxy) y=wmaxy; if (y<0) y=0; +- state->x = (x * win.ws_col / wmaxx); +- state->y = (y * win.ws_row / wmaxy); ++ state->x = (x * console.max_x / wmaxx); ++ state->y = (y * console.max_y / wmaxy); + + realposx = (x / wmaxx); /* this two lines come from the summa driver. */ + realposy = (y / wmaxy); /* they seem to be buggy (always give zero). */ +@@ -889,8 +773,8 @@ + if( abs(x-ox)>(wmaxx/wcmodell[WacomModell].treshold) + || abs(y-oy)>(wmaxy/wcmodell[WacomModell].treshold) ) ox=x; oy=y; + +- state->dx= (x-ox) / (wmaxx / win.ws_col / wcmodell[WacomModell].treshold); +- state->dy= (y-oy) / (wmaxy / win.ws_row / wcmodell[WacomModell].treshold); ++ state->dx= (x-ox) / (wmaxx / console.max_x / wcmodell[WacomModell].treshold); ++ state->dy= (y-oy) / (wmaxy / console.max_y / wcmodell[WacomModell].treshold); + } + + ox=x; oy=y; +@@ -918,7 +802,7 @@ + #define CAL_Y_MAX 0xF40 + #define CAL_Y_SIZE (CAL_Y_MAX - CAL_Y_MIN) + +-static int M_calus(Gpm_Event *state, unsigned char *data) ++static int M_calus(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + int x, y; + +@@ -932,12 +816,12 @@ + state->dx = 0; state->dy = 0; + + state->x = x < CAL_X_MIN ? 0 +- : x > CAL_X_MAX ? win.ws_col+1 +- : (long)(x-CAL_X_MIN) * (long)(win.ws_col-1) / CAL_X_SIZE+2; ++ : x > CAL_X_MAX ? console.max_x+1 ++ : (long)(x-CAL_X_MIN) * (long)(console.max_x-1) / CAL_X_SIZE+2; + +- state->y = y < CAL_Y_MIN ? win.ws_row + 1 ++ state->y = y < CAL_Y_MIN ? console.max_y + 1 + : y > CAL_Y_MAX ? 0 +- : (long)(CAL_Y_MAX-y) * (long)win.ws_row / CAL_Y_SIZE + 1; ++ : (long)(CAL_Y_MAX-y) * (long)console.max_y / CAL_Y_SIZE + 1; + + realposx = x < CAL_X_MIN ? 0 + : x > CAL_X_MAX ? 16384 +@@ -950,7 +834,7 @@ + return 0; + } + +-static int M_calus_rel(Gpm_Event *state, unsigned char *data) ++static int M_calus_rel(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + static int ox=-1, oy; + int x, y; +@@ -984,7 +868,7 @@ + #define NCR_DELTA_X (NCR_RIGHT_X - NCR_LEFT_X) + #define NCR_DELTA_Y (NCR_TOP_Y - NCR_BOTTOM_Y) + +-static int M_ncr(Gpm_Event *state, unsigned char *data) ++static int M_ncr(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + int x,y; + +@@ -1002,14 +886,14 @@ + state->x = x < NCR_LEFT_X + ? 0 + : x > NCR_RIGHT_X +- ? win.ws_col+1 +- : (long)(x-NCR_LEFT_X) * (long)(win.ws_col-1) / NCR_DELTA_X+2; ++ ? console.max_x+1 ++ : (long)(x-NCR_LEFT_X) * (long)(console.max_x-1) / NCR_DELTA_X+2; + + state->y = y < NCR_BOTTOM_Y +- ? win.ws_row + 1 ++ ? console.max_y + 1 + : y > NCR_TOP_Y + ? 0 +- : (long)(NCR_TOP_Y-y) * (long)win.ws_row / NCR_DELTA_Y + 1; ++ : (long)(NCR_TOP_Y-y) * (long)console.max_y / NCR_DELTA_Y + 1; + + realposx = x < NCR_LEFT_X + ? 0 +@@ -1026,7 +910,7 @@ + return 0; + } + +-static int M_twid(Gpm_Event *state, unsigned char *data) ++static int M_twid(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + unsigned long message=0UL; int i,h,v; + static int lasth, lastv, lastkey, key, lock=0, autorepeat=0; +@@ -1144,7 +1028,7 @@ + #ifdef HAVE_LINUX_JOYSTICK_H + /* Joystick mouse emulation (David Given) */ + +-static int M_js(Gpm_Event *state, unsigned char *data) ++static int M_js(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + struct JS_DATA_TYPE *jdata = (void*)data; + static int centerx = 0; +@@ -1193,21 +1077,21 @@ + #endif /* have joystick.h */ + + /* Synaptics TouchPad mouse emulation (Henry Davies) */ +-static int M_synaptics_serial(Gpm_Event *state, unsigned char *data) ++static int M_synaptics_serial(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { +- syn_process_serial_data (state, data); ++ syn_process_serial_data(dev->fd, state, data); + return 0; + } + + + /* Synaptics TouchPad mouse emulation (Henry Davies) */ +-static int M_synaptics_ps2(Gpm_Event *state, unsigned char *data) ++static int M_synaptics_ps2(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { +- syn_process_ps2_data(state, data); ++ syn_process_ps2_data(dev->fd, state, data); + return 0; + } + +-static int M_mtouch(Gpm_Event *state, unsigned char *data) ++static int M_mtouch(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* + * This is a simple decoder for the MicroTouch touch screen +@@ -1219,8 +1103,8 @@ + static int upx, upy; /* keep track of last finger-up place */ + static struct timeval uptv, tv; /* time of last up, and down events */ + +- #define REAL_TO_XCELL(x) (x * win.ws_col / 0x3FFF) +- #define REAL_TO_YCELL(y) (y * win.ws_row / 0x3FFF) ++ #define REAL_TO_XCELL(x) (x * console.max_x / 0x3FFF) ++ #define REAL_TO_YCELL(y) (y * console.max_y / 0x3FFF) + + #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL)) + #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \ +@@ -1245,7 +1129,7 @@ + + if (avgx < 0) { /* press event */ + GET_TIME(tv); +- if (DIF_TIME(uptv, tv) < opt_time) { ++ if (DIF_TIME(uptv, tv) < opt->time) { + /* count as button press placed at finger-up pixel */ + state->buttons = GPM_B_LEFT; + realposx = avgx = upx; state->x = REAL_TO_XCELL(realposx); +@@ -1287,7 +1171,7 @@ + static int gunze_calib[4]; /* x0,y0 x1,y1 (measured at 1/8 and 7/8) */ + static int gunze_debounce = 100; /* milliseconds: ignore shorter taps */ + +-static int M_gunze(Gpm_Event *state, unsigned char *data) ++static int M_gunze(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + /* + * This generates button-1 events, by now. +@@ -1300,8 +1184,8 @@ + static struct timeval uptv, tv; /* time of last up, and down events */ + int timediff; + +- #define REAL_TO_XCELL(x) (x * win.ws_col / 0x3FFF) +- #define REAL_TO_YCELL(y) (y * win.ws_row / 0x3FFF) ++ #define REAL_TO_XCELL(x) (x * console.max_x / 0x3FFF) ++ #define REAL_TO_YCELL(y) (y * console.max_y / 0x3FFF) + + #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL)) + #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \ +@@ -1350,7 +1234,7 @@ + GET_TIME(tv); + timediff = DIF_TIME(uptv, tv); + released = 0; +- if (timediff > gunze_debounce && timediff < opt_time) { ++ if (timediff > gunze_debounce && timediff < opt->time) { + /* count as button press placed at finger-up pixel */ + dragging = 1; + state->buttons = GPM_B_LEFT; +@@ -1399,7 +1283,7 @@ + /* corresponding correction of the protocol identification */ + /* mask) 2001/07/12 by Maciej W. Rozycki (macro@ds2.pg.gda.pl) */ + +-static int M_vsxxx_aa(Gpm_Event *state, unsigned char *data) ++static int M_vsxxx_aa(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + + /* The mouse protocol is as follows: +@@ -1449,16 +1333,16 @@ + /* Genius Wizardpad tablet -- Matt Kimball (mkimball@xmission.com) */ + static int wizardpad_width = -1; + static int wizardpad_height = -1; +-static int M_wp(Gpm_Event *state, unsigned char *data) ++static int M_wp(struct micedev *dev, struct miceopt *opt, unsigned char *data, Gpm_Event *state) + { + int x, y, pressure; + + x = ((data[4] & 0x1f) << 12) | ((data[3] & 0x3f) << 6) | (data[2] & 0x3f); +- state->x = x * win.ws_col / (wizardpad_width * 40); ++ state->x = x * console.max_x / (wizardpad_width * 40); + realposx = x * 16383 / (wizardpad_width * 40); + + y = ((data[7] & 0x1f) << 12) | ((data[6] & 0x3f) << 6) | (data[5] & 0x3f); +- state->y = win.ws_row - y * win.ws_row / (wizardpad_height * 40) - 1; ++ state->y = console.max_y - y * console.max_y / (wizardpad_height * 40) - 1; + realposy = 16383 - y * 16383 / (wizardpad_height * 40) - 1; + + pressure = ((data[9] & 0x0f) << 4) | (data[8] & 0x0f); +@@ -1475,11 +1359,9 @@ + /*========================================================================*/ + /* Then, mice should be initialized */ + +-static Gpm_Type* I_empty(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_empty(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { +- if (check_no_argv(argc, argv)) return NULL; +- return type; ++ return check_no_options(type->name, opt->text, ',') ? 0 : -1; + } + + static int setspeed(int fd,int old,int new,int needtowrite,unsigned short flags) +@@ -1536,28 +1418,27 @@ + {125,"Q"}, + {1E9,"N"}, }; + +-static Gpm_Type* I_serial(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_serial(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + int i; unsigned char c; + fd_set set; struct timeval timeout={0,0}; /* used when not debugging */ + + /* accept "-o dtr", "-o rts" and "-o both" */ +- if (option_modem_lines(fd, argc, argv)) return NULL; ++ if (option_modem_lines(dev->fd, type->name, opt->text)) return -1; + + #ifndef DEBUG + /* flush any pending input (thanks, Miguel) */ + FD_ZERO(&set); + for(i=0; /* always */ ; i++) { +- FD_SET(fd,&set); +- switch(select(fd+1,&set,(fd_set *)NULL,(fd_set *)NULL,&timeout/*zero*/)){ +- case 1: if (read(fd,&c,1)==0) break; ++ FD_SET(dev->fd,&set); ++ switch(select(dev->fd+1,&set,(fd_set *)NULL,(fd_set *)NULL,&timeout/*zero*/)){ ++ case 1: if (read(dev->fd,&c,1)==0) break; + case -1: continue; + } + break; + } + +- if (type->fun==M_logimsc) write(fd, "QU", 2 ); ++ if (type->fun==M_logimsc) write(dev->fd, "QU", 2 ); + + #if 0 /* Did this ever work? -- I don't know, but should we not remove it, + * if it doesn't work ??? -- Nico */ +@@ -1570,7 +1451,7 @@ + + /* Non mman: change from any available speed to the chosen one */ + for (i=9600; i>=1200; i/=2) +- setspeed(fd, i, opt_baud, (type->fun != M_mman) /* write */, flags); ++ setspeed(dev->fd, i, opt->baud, (type->fun != M_mman) /* write */, type->flags); + + /* + * reset the MouseMan/TrackMan to use the 3/4 byte protocol +@@ -1578,51 +1459,50 @@ + * Changed after 1.14; why not having "I_mman" now? + */ + if (type->fun==M_mman) { +- setspeed(fd, 1200, 1200, 0, flags); /* no write */ +- write(fd, "*X", 2); +- setspeed(fd, 1200, opt_baud, 0, flags); /* no write */ +- return type; ++ setspeed(dev->fd, 1200, 1200, 0, type->flags); /* no write */ ++ write(dev->fd, "*X", 2); ++ setspeed(dev->fd, 1200, opt->baud, 0, type->flags); /* no write */ ++ return 0; + } + + if(type->fun==M_geni) { + gpm_report(GPM_PR_INFO,GPM_MESS_INIT_GENI); +- setspeed(fd, 1200, 9600, 1, flags); /* write */ +- write(fd, ":" ,1); +- write(fd, "E" ,1); /* setup tablet. relative mode, resolution... */ +- write(fd, "@" ,1); /* setup tablet. relative mode, resolution... */ ++ setspeed(dev->fd, 1200, 9600, 1, type->flags); /* write */ ++ write(dev->fd, ":" ,1); ++ write(dev->fd, "E" ,1); /* setup tablet. relative mode, resolution... */ ++ write(dev->fd, "@" ,1); /* setup tablet. relative mode, resolution... */ + } + + if (type->fun==M_synaptics_serial) { + int packet_length; + +- setspeed (fd, 1200, 1200, 1, flags); +- packet_length = syn_serial_init (fd); +- setspeed (fd, 1200, 9600, 1, flags); ++ setspeed (dev->fd, 1200, 1200, 1, type->flags); ++ packet_length = syn_serial_init (dev->fd); ++ setspeed (dev->fd, 1200, 9600, 1, type->flags); + + type->packetlen = packet_length; + type->howmany = packet_length; + } + + if (type->fun==M_vsxxx_aa) { +- setspeed (fd, 4800, 4800, 0, flags); /* no write */ +- write(fd, "R", 1); /* initialize a mouse; without getting an "R" */ ++ setspeed (dev->fd, 4800, 4800, 0, type->flags); /* no write */ ++ write(dev->fd, "R", 1); /* initialize a mouse; without getting an "R" */ + /* a mouse does not send a bytestream */ + } + +- return type; ++ return 0; + } + +-static Gpm_Type* I_logi(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_logi(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + int i; + struct stat buf; + int busmouse; + +- if (check_no_argv(argc, argv)) return NULL; ++ if (!check_no_options(type->name, opt->text, ',')) return -1; + + /* is this a serial- or a bus- mouse? */ +- if(fstat(fd,&buf)==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_FSTAT); ++ if(fstat(dev->fd,&buf)==-1) gpm_report(GPM_PR_OOPS,GPM_MESS_FSTAT); + i=MAJOR(buf.st_rdev); + + /* I don't know why this is herein, but I remove it. I don't think a +@@ -1635,21 +1515,20 @@ + type->howmany = busmouse ? 3 : 1; + + /* change from any available speed to the chosen one */ +- for (i=9600; i>=1200; i/=2) setspeed(fd, i, opt_baud, 1 /* write */, flags); ++ for (i=9600; i>=1200; i/=2) setspeed(dev->fd, i, opt->baud, 1 /* write */, type->flags); + + /* this stuff is peculiar of logitech mice, also for the serial ones */ +- write(fd, "S", 1); +- setspeed(fd, opt_baud, opt_baud, 1 /* write */, ++ write(dev->fd, "S", 1); ++ setspeed(dev->fd, opt->baud, opt->baud, 1 /* write */, + CS8 |PARENB |PARODD |CREAD |CLOCAL |HUPCL); + + /* configure the sample rate */ +- for (i=0;opt_sample<=sampletab[i].sample;i++) ; +- write(fd,sampletab[i].code,1); +- return type; ++ for (i=0;opt->sample<=sampletab[i].sample;i++) ; ++ write(dev->fd,sampletab[i].code,1); ++ return 0; + } + +-static Gpm_Type *I_wacom(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_wacom(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + /* wacom graphire tablet */ + #define UD_RESETBAUD "\r$" /* reset baud rate to default (wacom V) */ +@@ -1664,19 +1543,19 @@ + { + /* Init Wacom communication; this is modified from xf86Wacom.so module */ + /* Set speed to 19200 */ +- setspeed (fd, 1200, 19200, 0, B19200|CS8|CREAD|CLOCAL|HUPCL); ++ setspeed (dev->fd, 1200, 19200, 0, B19200|CS8|CREAD|CLOCAL|HUPCL); + /* Send Reset Baudrate Command */ +- write(fd, UD_RESETBAUD, strlen(UD_RESETBAUD)); ++ write(dev->fd, UD_RESETBAUD, strlen(UD_RESETBAUD)); + usleep(250000); + /* Send Reset Command */ +- write(fd, UD_RESET, strlen(UD_RESET)); ++ write(dev->fd, UD_RESET, strlen(UD_RESET)); + usleep(75000); + /* Set speed to 9600bps */ +- setspeed (fd, 1200, 9600, 0, B9600|CS8|CREAD|CLOCAL|HUPCL); ++ setspeed (dev->fd, 1200, 9600, 0, B9600|CS8|CREAD|CLOCAL|HUPCL); + /* Send Reset Command */ +- write(fd, UD_RESET, strlen(UD_RESET)); ++ write(dev->fd, UD_RESET, strlen(UD_RESET)); + usleep(250000); +- write(fd, UD_STOP, strlen(UD_STOP)); ++ write(dev->fd, UD_STOP, strlen(UD_STOP)); + usleep(100000); + } + +@@ -1690,7 +1569,7 @@ + struct timeval timeout; + fd_set readfds; + int err; +- FD_ZERO(&readfds); FD_SET(fd, &readfds); ++ FD_ZERO(&readfds); FD_SET(dev->fd, &readfds); + timeout.tv_sec = 0; timeout.tv_usec = 200000; + err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout); + return((err>0)?1:err); +@@ -1706,11 +1585,11 @@ + * Get Data to buffer until full or timeout. + * Give back 0 for timeout and !0 for buffer full + */ +- if (cmd) write(fd,cmd,strlen(cmd)); ++ if (cmd) write(dev->fd,cmd,strlen(cmd)); + memset(buffer,0,sizeof(buffer)); p=buffer; + err=wait_wacom(); + while (err != -1 && err && (p-buffer)<(sizeof(buffer)-1)) { +- p+= read(fd,p,(sizeof(buffer)-1)-(p-buffer)); ++ p+= read(dev->fd,p,(sizeof(buffer)-1)-(p-buffer)); + err=wait_wacom(); + } + /* return 1 for buffer full */ +@@ -1728,13 +1607,14 @@ + */ + + /* accept boolean options absolute and relative */ +- static argv_helper optioninfo[] = { +- {"absolute", ARGV_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: !0}, +- {"relative", ARGV_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: 0}, +- {"", ARGV_END} ++ static struct option_helper optioninfo[] = { ++ {"absolute", OPT_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: !0}, ++ {"relative", OPT_BOOL, u: {iptr: &WacomAbsoluteWanted}, value: 0}, ++ {"", OPT_END} + }; +- parse_argv(optioninfo, argc, argv); +- type->absolute = WacomAbsoluteWanted; ++ ++ parse_options(type->name, opt->text, ',', optioninfo); ++ opt->absolute = WacomAbsoluteWanted; + reset_wacom(); + + /* "Flush" input queque */ +@@ -1756,7 +1636,7 @@ + } + if(WacomModell >= (sizeof(wcmodell) / sizeof(struct WC_MODELL))) + WacomModell=-1; +- gpm_report(GPM_PR_INFO,GPM_MESS_WACOM_MOD, type->absolute? 'A':'R', ++ gpm_report(GPM_PR_INFO,GPM_MESS_WACOM_MOD, opt->absolute? 'A':'R', + (WacomModell==(-1))? "Unknown" : wcmodell[WacomModell].name, + buffer+2); + +@@ -1767,24 +1647,23 @@ + wmaxx = (wmaxx-wcmodell[WacomModell].border); + wmaxy = (wmaxy-wcmodell[WacomModell].border); + } +- write(fd,UD_SENDCOORDS,4); ++ write(dev->fd,UD_SENDCOORDS,4); + +- return type; ++ return 0; + } + +-static Gpm_Type *I_pnp(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_pnp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + struct termios tty; + + /* accept "-o dtr", "-o rts" and "-o both" */ +- if (option_modem_lines(fd, argc, argv)) return NULL; ++ if (option_modem_lines(dev->fd, type->name, opt->text)) return -1; + + /* + * Just put the device to 1200 baud. Thanks to Francois Chastrette + * for his great help and debugging with his own pnp device. + */ +- tcgetattr(fd, &tty); ++ tcgetattr(dev->fd, &tty); + + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; +@@ -1792,15 +1671,15 @@ + tty.c_line = 0; + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; +- tty.c_cflag = flags | B1200; +- tcsetattr(fd, TCSAFLUSH, &tty); /* set parameters */ ++ tty.c_cflag = type->flags | B1200; ++ tcsetattr(dev->fd, TCSAFLUSH, &tty); /* set parameters */ + + /* + * Don't read the silly initialization string. I don't want to see + * the vendor name: it is only propaganda, with no information. + */ + +- return type; ++ return 0; + } + + /* +@@ -1848,8 +1727,7 @@ + + /* intellimouse, ps2 version: Ben Pfaff and Colin Plumb */ + /* Autodetect: Steve Bennett */ +-static Gpm_Type *I_imps2(int fd, unsigned short flags, struct Gpm_Type *type, +- int argc, char **argv) ++static int I_imps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + int id; + static unsigned char basic_init[] = { GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100 }; +@@ -1857,36 +1735,36 @@ + static unsigned char ps2_init[] = { GPM_AUX_SET_SCALE11, GPM_AUX_ENABLE_DEV, GPM_AUX_SET_SAMPLE, 100, GPM_AUX_SET_RES, 3, }; + + /* Do a basic init in case the mouse is confused */ +- write_to_mouse(fd, basic_init, sizeof (basic_init)); ++ write_to_mouse(dev->fd, basic_init, sizeof (basic_init)); + + /* Now try again and make sure we have a PS/2 mouse */ +- if (write_to_mouse(fd, basic_init, sizeof (basic_init)) != 0) { ++ if (write_to_mouse(dev->fd, basic_init, sizeof (basic_init)) != 0) { + gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_INIT); +- return(NULL); ++ return -1; + } + + /* Try to switch to 3 button mode */ +- if (write_to_mouse(fd, imps2_init, sizeof (imps2_init)) != 0) { ++ if (write_to_mouse(dev->fd, imps2_init, sizeof (imps2_init)) != 0) { + gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_FAILED); +- return(NULL); ++ return -1; + } + + /* Read the mouse id */ +- id = read_mouse_id(fd); ++ id = read_mouse_id(dev->fd); + if (id == GPM_AUX_ID_ERROR) { + gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_MID_FAIL); + id = GPM_AUX_ID_PS2; + } + + /* And do the real initialisation */ +- if (write_to_mouse(fd, ps2_init, sizeof (ps2_init)) != 0) { ++ if (write_to_mouse(dev->fd, ps2_init, sizeof (ps2_init)) != 0) { + gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_SETUP_FAIL); + } + + if (id == GPM_AUX_ID_IMPS2) { + /* Really an intellipoint, so initialise 3 button mode (4 byte packets) */ + gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_AUTO); +- return type; ++ return 0; + } + if (id != GPM_AUX_ID_PS2) { + gpm_report(GPM_PR_ERR,GPM_MESS_IMPS2_BAD_ID, id); +@@ -1894,69 +1772,64 @@ + else gpm_report(GPM_PR_INFO,GPM_MESS_IMPS2_PS2); + + for (type=mice; type->fun; type++) +- if (strcmp(type->name, "ps2") == 0) return(type); ++ if (strcmp(type->name, "ps2") == 0) return 0; + + /* ps2 was not found!!! */ +- return(NULL); ++ return -1; + } + + /* + * This works with Dexxa Optical Mouse, but because in X same initstring + * is named ExplorerPS/2 so I named it in the same way. + */ +-static Gpm_Type *I_exps2(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_exps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + static unsigned char s1[] = { 243, 200, 243, 200, 243, 80, }; + +- if (check_no_argv(argc, argv)) return NULL; ++ if (!check_no_options(type->name, opt->text, ',')) return -1; + +- write (fd, s1, sizeof (s1)); ++ write (dev->fd, s1, sizeof (s1)); + usleep (30000); +- tcflush (fd, TCIFLUSH); +- return type; ++ tcflush (dev->fd, TCIFLUSH); ++ return 0; + } + +-static Gpm_Type *I_twid(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_twid(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + +- if (check_no_argv(argc, argv)) return NULL; ++ if (!check_no_options(type->name, opt->text, ',')) return -1; + +- if (twiddler_key_init() != 0) return NULL; ++ if (twiddler_key_init() != 0) return -1; + /* + * the twiddler is a serial mouse: just drop dtr + * and run at 2400 (unless specified differently) + */ +- if(opt_baud==DEF_BAUD) opt_baud = 2400; +- argv[1] = "dtr"; /* argv[1] is guaranteed to be NULL (this is dirty) */ +- return I_serial(fd, flags, type, argc, argv); ++ if (opt->baud == DEF_BAUD) opt->baud = 2400; ++ opt->text = "dtr"; ++ return I_serial(dev, opt, type); + } + +-static Gpm_Type *I_calus(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_calus(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { +- if (check_no_argv(argc, argv)) return NULL; ++ if (!check_no_options(type->name, opt->text, ',')) return -1; + +- if (opt_baud == 1200) opt_baud=9600; /* default to 9600 */ +- return I_serial(fd, flags, type, argc, argv); ++ if (opt->baud == 1200) opt->baud = 9600; /* default to 9600 */ ++ return I_serial(dev, opt, type); + } + + /* synaptics touchpad, ps2 version: Henry Davies */ +-static Gpm_Type *I_synps2(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_synps2(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { +- syn_ps2_init (fd); +- return type; ++ syn_ps2_init (dev->fd); ++ return 0; + } + + +-static Gpm_Type *I_summa(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_summa(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + void resetsumma() + { +- write(fd,0,1); /* Reset */ ++ write(dev->fd,0,1); /* Reset */ + usleep(400000); /* wait */ + } + int waitsumma() +@@ -1964,7 +1837,7 @@ + struct timeval timeout; + fd_set readfds; + int err; +- FD_ZERO(&readfds); FD_SET(fd, &readfds); ++ FD_ZERO(&readfds); FD_SET(dev->fd, &readfds); + timeout.tv_sec = 0; timeout.tv_usec = 200000; + err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout); + return(err); +@@ -1987,34 +1860,34 @@ + char GEN_MODELL=0x7f; + + /* Set speed to 9600bps */ +- setspeed (fd, 1200, 9600, 1, B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD); ++ setspeed (dev->fd, 1200, 9600, 1, B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD); + resetsumma(); + +- write(fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE)); ++ write(dev->fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE)); + + if (strstr(type->name,"acecad")!=NULL) summaid=11; + + if (summaid<0) { /* Summagraphics test */ + /* read the Summa Firm-ID */ +- write(fd, SS_FIRMID, strlen(SS_FIRMID)); ++ write(dev->fd, SS_FIRMID, strlen(SS_FIRMID)); + err=waitsumma(); + if (!((err == -1) || (!err))) { + summaid=10; /* Original Summagraphics */ +- read(fd, buffer, 255); /* Read Firm-ID */ ++ read(dev->fd, buffer, 255); /* Read Firm-ID */ + } + } + + if (summaid<0) { /* Genius-test */ + resetsumma(); +- write(fd,GEN_MMSERIES,1); +- write(fd,&GEN_MODELL,1); /* Read modell */ ++ write(dev->fd,GEN_MMSERIES,1); ++ write(dev->fd,&GEN_MODELL,1); /* Read modell */ + err=waitsumma(); + if (!((err == -1) || (!err))) { /* read Genius-ID */ + err=waitsumma(); + if (!((err == -1) || (!err))) { + err=waitsumma(); + if (!((err == -1) || (!err))) { +- read(fd,&config,1); ++ read(dev->fd,&config,1); + summaid=(config[0] & 224) >> 5; /* genius tablet-id (0-7)*/ + } + } +@@ -2024,30 +1897,29 @@ + /* unknown tablet ?*/ + if ((summaid<0) || (summaid==11)) { + resetsumma(); +- write(fd, SS_BINARY_FMT SS_PROMPT_MODE, 3); ++ write(dev->fd, SS_BINARY_FMT SS_PROMPT_MODE, 3); + } + + /* read tablet size */ + err=waitsumma(); +- if (!((err == -1) || (!err))) read(fd,buffer,sizeof(buffer)); +- write(fd,SS_READCONFIG,1); +- read(fd,&config,5); ++ if (!((err == -1) || (!err))) read(dev->fd,buffer,sizeof(buffer)); ++ write(dev->fd,SS_READCONFIG,1); ++ read(dev->fd,&config,5); + summamaxx=(config[2]<<7 | config[1])-(SUMMA_BORDER*2); + summamaxy=(config[4]<<7 | config[3])-(SUMMA_BORDER*2); + +- write(fd,SS_ABSOLUTE SS_STREAM_MODE SS_UPPER_ORIGIN,3); +- if (summaid<0) write(fd,SS_500LPI SS_TABID0 SS_BINARY_FMT,4); ++ write(dev->fd,SS_ABSOLUTE SS_STREAM_MODE SS_UPPER_ORIGIN,3); ++ if (summaid<0) write(dev->fd,SS_500LPI SS_TABID0 SS_BINARY_FMT,4); + +- return type; ++ return 0; + } + +-static Gpm_Type *I_mtouch(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_mtouch(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + struct termios tty; + + /* Set speed to 9600bps (copied from I_summa, above :) */ +- tcgetattr(fd, &tty); ++ tcgetattr(dev->fd, &tty); + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; + tty.c_lflag = 0; +@@ -2055,18 +1927,17 @@ + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_cflag = B9600|CS8|CREAD|CLOCAL|HUPCL; +- tcsetattr(fd, TCSAFLUSH, &tty); ++ tcsetattr(dev->fd, TCSAFLUSH, &tty); + + + /* Turn it to "format tablet" and "mode stream" */ +- write(fd,"\001MS\r\n\001FT\r\n",10); ++ write(dev->fd,"\001MS\r\n\001FT\r\n",10); + +- return type; ++ return 0; + } + + /* simple initialization for the gunze touchscreen */ +-static Gpm_Type *I_gunze(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_gunze(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + struct termios tty; + FILE *f; +@@ -2075,29 +1946,29 @@ + + #define GUNZE_CALIBRATION_FILE SYSCONFDIR "/gpm-calibration" + /* accept a few options */ +- static argv_helper optioninfo[] = { +- {"smooth", ARGV_INT, u: {iptr: &gunze_avg}}, +- {"debounce", ARGV_INT, u: {iptr: &gunze_debounce}}, ++ static struct option_helper optioninfo[] = { ++ {"smooth", OPT_INT, u: {iptr: &gunze_avg}}, ++ {"debounce", OPT_INT, u: {iptr: &gunze_debounce}}, + /* FIXME: add corner tapping */ +- {"", ARGV_END} ++ {"", OPT_END} + }; +- parse_argv(optioninfo, argc, argv); ++ parse_options(type->name, opt->text, ',', optioninfo); + + /* check that the baud rate is valid */ +- if (opt_baud == DEF_BAUD) opt_baud = 19200; /* force 19200 as default */ +- if (opt_baud != 9600 && opt_baud != 19200) { +- gpm_report(GPM_PR_ERR,GPM_MESS_GUNZE_WRONG_BAUD,option.progname, argv[0]); +- opt_baud = 19200; ++ if (opt->baud == DEF_BAUD) opt->baud = 19200; /* force 19200 as default */ ++ if (opt->baud != 9600 && opt->baud != 19200) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_GUNZE_WRONG_BAUD, option.progname, type->name); ++ opt->baud = 19200; + } +- tcgetattr(fd, &tty); ++ tcgetattr(dev->fd, &tty); + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; + tty.c_lflag = 0; + tty.c_line = 0; + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; +- tty.c_cflag = (opt_baud == 9600 ? B9600 : B19200) |CS8|CREAD|CLOCAL|HUPCL; +- tcsetattr(fd, TCSAFLUSH, &tty); ++ tty.c_cflag = (opt->baud == 9600 ? B9600 : B19200) |CS8|CREAD|CLOCAL|HUPCL; ++ tcsetattr(dev->fd, TCSAFLUSH, &tty); + + /* FIXME: try to find some information about the device */ + +@@ -2120,19 +1991,18 @@ + gunze_calib[0] = gunze_calib[1] = 128; /* 1/8 */ + gunze_calib[2] = gunze_calib[3] = 896; /* 7/8 */ + } +- return type; ++ return 0; + } + + /* Genius Wizardpad tablet -- Matt Kimball (mkimball@xmission.com) */ +-static Gpm_Type *I_wp(int fd, unsigned short flags, +- struct Gpm_Type *type, int argc, char **argv) ++static int I_wp(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type) + { + struct termios tty; + char tablet_info[256]; + int count, pos, size; + + /* Set speed to 9600bps (copied from I_summa, above :) */ +- tcgetattr(fd, &tty); ++ tcgetattr(dev->fd, &tty); + tty.c_iflag = IGNBRK | IGNPAR; + tty.c_oflag = 0; + tty.c_lflag = 0; +@@ -2140,22 +2010,22 @@ + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_cflag = B9600|CS8|CREAD|CLOCAL|HUPCL; +- tcsetattr(fd, TCSAFLUSH, &tty); ++ tcsetattr(dev->fd, TCSAFLUSH, &tty); + + /* Reset the tablet (':') and put it in remote mode ('S') so that + it isn't sending anything to us. */ +- write(fd, ":S", 2); +- tcsetattr(fd, TCSAFLUSH, &tty); ++ write(dev->fd, ":S", 2); ++ tcsetattr(dev->fd, TCSAFLUSH, &tty); + + /* Query the model of the tablet */ +- write(fd, "T", 1); ++ write(dev->fd, "T", 1); + sleep(1); +- count = read(fd, tablet_info, 255); ++ count = read(dev->fd, tablet_info, 255); + + /* The tablet information should start with "KW" followed by the rest of + the model number. If it isn't there, it probably isn't a WizardPad. */ +- if(count < 2) return NULL; +- if(tablet_info[0] != 'K' || tablet_info[1] != 'W') return NULL; ++ if(count < 2) return -1; ++ if(tablet_info[0] != 'K' || tablet_info[1] != 'W') return -1; + + /* Now, we want the width and height of the tablet. They should be + of the form "X###" and "Y###" where ### is the number of units of +@@ -2177,9 +2047,9 @@ + } + + /* Set the tablet to stream mode with 180 updates per sec. ('O') */ +- write(fd, "O", 1); ++ write(dev->fd, "O", 1); + +- return type; ++ return 0; + } + + /*========================================================================*/ +@@ -2241,7 +2111,7 @@ + {0x80, 0x80, 0x80, 0x00}, 6, 6, 0, 0, 0}, + #ifdef HAVE_LINUX_INPUT_H + {"evdev", "Linux Event Device", +- "", M_evdev, I_empty, STD_FLG, ++ "", M_evdev, I_evdev, STD_FLG, + {0x00, 0x00, 0x00, 0x00} , 16, 16, 0, 0, NULL}, + #endif /* HAVE_LINUX_INPUT_H */ + {"exps2", "IntelliMouse Explorer (ps2) - 3 buttons, wheel unused", +diff -urN gpm-1.20.1/src/optparser.c gpm/src/optparser.c +--- gpm-1.20.1/src/optparser.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/optparser.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,155 @@ ++/* ++ * optparser.c - GPM mouse options parser ++ * ++ * Copyright (C) 1993 Andrew Haylett <ajh@gec-mrc.co.uk> ++ * Copyright (C) 1994-2000 Alessandro Rubini <rubini@linux.it> ++ * Copyright (C) 1998,1999 Ian Zimmerman <itz@rahul.net> ++ * Copyright (C) 2001,2002 Nico Schottelius <nicos@pcsystems.de> ++ * Copyright (C) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <ctype.h> ++ ++#include "headers/gpmInt.h" ++#include "headers/message.h" ++#include "headers/optparser.h" ++ ++int parse_options(const char *proto, const char *opts, char sep, struct option_helper *info) ++{ ++ int len, n, n_opts = 0, errors = 0; ++ long l; ++ struct option_helper *p; ++ char *s, *t, *str; ++ int base; /* for strtol */ ++ ++ for (p = info; p->type != OPT_END; p++) ++ p->present = 0; ++ ++ if (!opts) ++ return 0; ++ ++ if (!(str = strdup(opts))) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_ALLOC_FAILED); ++ ++ /* split input string */ ++ for (s = str, n = 1; sep && (s = strchr(s, sep)); s++, n++) ++ *s = '\0'; ++ ++ for (s = str; n; s += strlen(s) + 1, n--) { ++ if (strlen(s) == 0) ++ continue; ++ ++ for (p = info; p->type != OPT_END; p++) { ++ len = strlen(p->name); ++ if (!strncmp(p->name, s, len) && !isalnum(s[len])) ++ break; ++ } ++ if (p->type == OPT_END) { /* not found */ ++ gpm_report(GPM_PR_ERR, "%s: Uknown option \"%s\" for protocol \"%s\"\n", ++ option.progname, s, proto); ++ errors++; ++ continue; ++ } ++ if (p->present) { ++ gpm_report(GPM_PR_ERR, "%s: option \"%s\" has already been seen, ignored (\"%s\")\n", ++ option.progname, s, proto); ++ continue; ++ } ++ p->present = 1; ++ n_opts++; ++ /* Found. Look for trailing stuff, if any */ ++ s += len; ++ while (*s && isspace(*s)) s++; /* skip spaces */ ++ if (*s == '=') s++; /* skip equal */ ++ while (*s && isspace(*s)) s++; /* skip other spaces */ ++ ++ /* Now parse what s is */ ++ base = 0; ++ switch(p->type) { ++ case OPT_BOOL: ++ if (*s) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_OPTION_NO_ARG, option.progname, p->name, s); ++ errors++; ++ } ++ *(p->u.iptr) = p->value; ++ break; ++ ++ case OPT_DEC: ++ base = 10; /* and fall through */ ++ ++ case OPT_INT: ++ if (*s == '\0') { ++ gpm_report(GPM_PR_ERR, GPM_MESS_MISSING_ARG, option.progname, p->name); ++ } else { ++ l = strtol(s, &t, base); ++ if (*t) { ++ gpm_report(GPM_PR_ERR, GPM_MESS_INVALID_ARG, option.progname, s, p->name); ++ errors++; ++ break; ++ } ++ *(p->u.iptr) = (int)l; ++ } ++ break; ++ ++ case OPT_STRING: ++ if (*s == '\0') ++ gpm_report(GPM_PR_ERR, GPM_MESS_MISSING_ARG, option.progname, p->name); ++ else ++ *(p->u.sptr) = strdup(s); ++ break; ++ ++ case OPT_END: /* let's please "-Wall" */ ++ break; ++ } ++ } /* for i in argc */ ++ ++ free(str); ++ ++ if (errors) { ++ gpm_report(GPM_PR_ERR,GPM_MESS_CONT_WITH_ERR, option.progname); ++ return -errors; ++ } ++ return n_opts; ++} ++ ++int check_no_options(const char *proto, const char *opts, char sep) ++{ ++ static struct option_helper info[] = { ++ { "", OPT_END } ++ }; ++ ++ return parse_options(proto, opts, sep, info) == 0; ++} ++ ++int is_option_present(struct option_helper *info, const char *name) ++{ ++ struct option_helper *p; ++ int len; ++ ++ for (p = info; p->type != OPT_END; p++) { ++ len = strlen(p->name); ++ if (!strncmp(p->name, name, len) && !isalnum(name[len])) ++ return p->present; ++ } ++ ++ gpm_report(GPM_PR_ERR, "%s: Uknown option \"%s\"\n", option.progname, name); ++ return 0; ++} ++ +diff -urN gpm-1.20.1/src/prog/mouse-test.c gpm/src/prog/mouse-test.c +--- gpm-1.20.1/src/prog/mouse-test.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/prog/mouse-test.c 2003-10-02 01:22:42.000000000 -0500 +@@ -50,22 +50,9 @@ + #define max(a,b) ((a)>(b)?(a):(b)) + #endif + +- +-/* this material is needed to pass options to mice.c */ +-struct mouse_features mymouse = { +- DEF_TYPE, DEF_DEV, DEF_SEQUENCE, +- DEF_BAUD, DEF_SAMPLE, DEF_DELTA, DEF_ACCEL, DEF_SCALE, DEF_SCALE /*scaley*/, +- DEF_TIME, DEF_CLUSTER, DEF_THREE, DEF_GLIDEPOINT_TAP, +- (char *)NULL /* extra */, +- (Gpm_Type *)NULL, +- -1 /* fd */ +-}; +- + /* and this is a workaroud */ + struct winsize win; + +-struct mouse_features *which_mouse=&mymouse; +- + char *progname; + char *consolename; + int devcount=0; +@@ -78,9 +65,9 @@ + + struct device { + char *name; +- int fd; ++ struct micedev mdev; + struct device *next; +-}; ++} *devlist; + + static int message(void) + { +@@ -148,47 +135,48 @@ + /*----------------------------------------------------------------------------- + Place the description here. + -----------------------------------------------------------------------------*/ +-struct device **gpm_makedev(struct device **current, char *name) ++void gpm_makedev(char *name) + { +- int fd; int modes; ++ struct device *dev; ++ int fd; ++ int modes; ++ + if ((fd=open(name,O_RDWR|O_NONBLOCK))==-1) { + perror(name); +- return current; +- } +- modes = fcntl(fd, F_GETFL); +- if (0 > fcntl(fd, F_SETFL, modes & ~O_NONBLOCK)) { +- close(fd); +- perror(name); +- return current; ++ } else { ++ modes = fcntl(fd, F_GETFL); ++ if (0 > fcntl(fd, F_SETFL, modes & ~O_NONBLOCK)) { ++ close(fd); ++ perror(name); ++ } else { ++ dev = malloc(sizeof(struct device)); ++ if (!dev) gpm_report(GPM_PR_OOPS,"malloc()"); ++ dev->name=strdup(name); ++ if (!dev->name) gpm_report(GPM_PR_OOPS,"malloc()"); ++ dev->mdev.fd=fd; ++ dev->mdev.private = NULL; ++ dev->next=devlist; ++ devlist = dev; ++ devcount++; ++ } + } +- +- *current=malloc(sizeof(struct device)); +- if (!*current) gpm_report(GPM_PR_OOPS,"malloc()"); +- (*current)->name=strdup(name); +- if (!(*current)->name) gpm_report(GPM_PR_OOPS,"malloc()"); +- (*current)->fd=fd; +- (*current)->next=NULL; +- devcount++; +- return &((*current)->next); + } + +-Gpm_Type *(*I_serial)(int fd, unsigned short flags, struct Gpm_Type *type, +- int argc, char **argv); ++int (*I_serial)(struct micedev *dev, struct miceopt *opt, struct Gpm_Type *type); + + + /*----------------------------------------------------------------------------- + Place the description here. + -----------------------------------------------------------------------------*/ +-int mousereopen(int oldfd, char *name, Gpm_Type *type) ++int mousereopen(struct micedev *dev, char *name, Gpm_Type *type, struct miceopt *opts) + { +- int fd; + if (!type) type=mice+1; /* ms */ +- close(oldfd); ++ close(dev->fd); + usleep(100000); +- fd=open(name,O_RDWR); +- if (fd < 0) gpm_report(GPM_PR_OOPS,name); +- (*I_serial)(fd,type->flags,type,1,&type->name); /* ms initialization */ +- return fd; ++ dev->fd=open(name,O_RDWR); ++ if (dev->fd < 0) gpm_report(GPM_PR_OOPS,name); ++ I_serial(dev, opts, type); /* ms initialization */ ++ return dev->fd; + } + + int noneofthem(void) +@@ -281,10 +269,9 @@ + { + struct item *list=NULL; + struct item **nextitem; +- struct device *devlist=NULL; +- struct device **nextdev; ++ struct device *nextdev; + Gpm_Type *cursor; +- int i, mousefd; ++ int i; + char *mousename; + #define BUFLEN 512 + char buf[BUFLEN]; +@@ -294,6 +281,9 @@ + int trial, readamount,packetsize,got; + int baudtab[4]={1200,9600,4800,2400}; + #define BAUD(i) (baudtab[(i)%4]) ++ struct miceopt opt = {0}; ++ struct micedev mdev = {0}; ++ + consolename = Gpm_get_console(); + + if (!isatty(fileno(stdin))) { +@@ -306,8 +296,8 @@ + + /* init the list of possible devices */ + +- for (nextdev=&devlist, i=1; i<argc; i++) +- nextdev=gpm_makedev(nextdev,argv[i]); ++ for (i=1; i<argc; i++) ++ gpm_makedev(argv[i]); + + if (argc==1) { /* no cmdline, get all devices */ + FILE *f; +@@ -320,7 +310,7 @@ + if (!f) gpm_report(GPM_PR_OOPS,"popen()"); + while (fgets(s,64,f)) { + s[strlen(s)-1]='\0'; /* trim '\n' */ +- nextdev=gpm_makedev(nextdev,s); ++ gpm_makedev(s); + } + pclose(f); + } +@@ -345,19 +335,18 @@ + + /* BUG */ /* Logitech initialization is not performed */ + +- opt_baud=BAUD(trial); +- printf("\r\nTrying with %i baud\r\n",opt_baud); ++ opt.baud=BAUD(trial); ++ printf("\r\nTrying with %i baud\r\n",opt.baud); + trial++; + + FD_ZERO(&devSet); FD_ZERO(&gotSet); + FD_SET(fileno(stdin),&devSet); maxfd=fileno(stdin); + printf("\r\n The possible device nodes are:\r\n"); +- for (nextdev=&devlist; *nextdev; nextdev=&((*nextdev)->next)) { +- printf("\t%s\r\n", (*nextdev)->name); +- FD_SET((*nextdev)->fd,&devSet); +- maxfd=max((*nextdev)->fd,maxfd); +- (*I_serial)((*nextdev)->fd,(mice+1)->flags,mice+1, +- 1, &(mice+1)->name); /* try ms mode */ ++ for (nextdev=devlist; nextdev; nextdev=nextdev->next) { ++ printf("\t%s\r\n", nextdev->name); ++ FD_SET(nextdev->mdev.fd, &devSet); ++ maxfd=max(nextdev->mdev.fd,maxfd); ++ I_serial(&nextdev->mdev, &opt, mice+1); /* try ms mode */ + } + + savSet=devSet; +@@ -379,43 +368,43 @@ + getchar(); + break; + } +- for (nextdev=&devlist; *nextdev; nextdev=&((*nextdev)->next)) +- if (FD_ISSET((*nextdev)->fd,&devSet)) { ++ for (nextdev=devlist; nextdev; nextdev=nextdev->next) ++ if (FD_ISSET(nextdev->mdev.fd,&devSet)) { + gotthem++; +- FD_CLR((*nextdev)->fd,&savSet); +- FD_SET((*nextdev)->fd,&gotSet); ++ FD_CLR(nextdev->mdev.fd,&savSet); ++ FD_SET(nextdev->mdev.fd,&gotSet); + } + } +- if (gotthem) for (nextdev=&devlist; *nextdev; /* nothing */ ) { +- cur=*nextdev; +- if (!FD_ISSET(cur->fd,&gotSet)) { ++ if (gotthem) for (nextdev=devlist; nextdev; /* nothing */ ) { ++ cur=nextdev; ++ if (!FD_ISSET(cur->mdev.fd,&gotSet)) { + printf("removing \"%s\" from the list\r\n",cur->name); +- *nextdev=cur->next; +- close(cur->fd); ++ nextdev=cur->next; ++ close(cur->mdev.fd); + free(cur->name); + free(cur); + devcount--; + } else { +- read(cur->fd,buf,80); /* flush */ +- nextdev=&(cur->next); /* follow list */ ++ read(cur->mdev.fd,buf,80); /* flush */ ++ nextdev=cur->next; /* follow list */ + } + } + + } /* devcount>1 */ + +- mousefd=devlist->fd; ++ mdev=devlist->mdev; + mousename=devlist->name; + free(devlist); + printf("\r\nOk, so your mouse device is \"%s\"\r\n",mousename); + + /* now close and reopen it, complete with initialization */ +- opt_baud=BAUD(0); +- mousefd=mousereopen(mousefd,mousename,NULL); +- ++ opt.baud=BAUD(0); ++ mousereopen(&mdev, mousename, NULL,&opt); ++ + FD_ZERO(&checkSet); +- FD_SET(mousefd,&checkSet); ++ FD_SET(mdev.fd,&checkSet); + FD_SET(fileno(stdin),&checkSet); +- maxfd=max(mousefd,fileno(stdin)); ++ maxfd=max(mdev.fd, fileno(stdin)); + + /*====================================== Identify mouse type */ + +@@ -440,7 +429,7 @@ + printf("\r\nNow please press and release your left mouse button,\r\n" + "one time only\r\n\r\n"); + +- i=read(mousefd,buf,1); ++ i=read(mdev.fd, buf, 1); + if (i==-1 && errno==EINVAL) + readamount=3; + else +@@ -466,7 +455,7 @@ + else + nextitem=&(cur->next); + } +- read(mousefd,buf,BUFLEN); /* flush */ ++ read(mdev.fd, buf, BUFLEN); /* flush */ + + /*====================================== Packet size - second step */ + +@@ -484,12 +473,12 @@ + while (packetsize==1) { + int success3=0,success5=0; + +- opt_baud=BAUD(trial); +- printf("\tBaud rate is %i\r\n",opt_baud); +- mousefd=mousereopen(mousefd,mousename,NULL); ++ opt.baud=BAUD(trial); ++ printf("\tBaud rate is %i\r\n",opt.baud); ++ mousereopen(&mdev, mousename,NULL, &opt); + + printf("\r\n==> Detecting the packet size\r\n"); +- got=eventlist(mousefd,buf,BUFLEN,GPM_B_LEFT,readamount); ++ got=eventlist(mdev.fd,buf,BUFLEN,GPM_B_LEFT,readamount); + + /* try three -- look at repeating arrays of 6 bytes */ + for (i=0;i<got-12;i++) +@@ -512,8 +501,7 @@ + trial++; + } + +-/*====================================== Use that info to discard protocols */ +- ++/*====================================== Use that info to discard protocols */ + for (nextitem=&list; *nextitem; /* nothing */) { + struct item *cur=*nextitem; + int packetheads=0; +@@ -530,7 +518,7 @@ + if ( ((buf[i] &(cur->this->proto)[0]) == (cur->this->proto)[1]) + && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) { + packetheads++; +- if ((*(cur->this->fun))(&event,buf+i)==-1) { ++ if ((*(cur->this->fun))(&mdev, &opt, buf+i, &event)==-1) { + packetheads--; + continue; + } +@@ -594,7 +582,7 @@ + * First trial: remove the "-t ms" extension if spurious buttons come in + */ + +- got=eventlist(mousefd,buf,BUFLEN,0,readamount); ++ got=eventlist(mdev.fd,buf,BUFLEN,0,readamount); + pending=0; + for (nextitem=&list; *nextitem; /* nothing */) { + struct item *cur=*nextitem; +@@ -604,7 +592,7 @@ + for (i=0;i<got;i++) { + if ( ((buf[i] &(cur->this->proto)[0]) == (cur->this->proto)[1]) + && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) { +- if ((*(cur->this->fun))(&event,buf+i)==-1) continue; ++ if ((*(cur->this->fun))(&mdev, &opt, buf+i, &event)==-1) continue; + i+=packetsize-1; + if (event.buttons) pending--; + } +@@ -624,8 +612,8 @@ + */ + + printf("\r\n==> Looking for '-t mman'and enhanced ms\r\n"); +- mousefd=mousereopen(mousefd,mousename, mice /* mman */); +- got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount); ++ mousereopen(&mdev, mousename, mice /* mman */, &opt); ++ got=eventlist(mdev.fd, buf, BUFLEN, GPM_B_MIDDLE, readamount); + + /* if it uses the 4-byte protocol, find it in a rude way */ + for (pending=0,i=0;i<got-16;i++) +@@ -646,7 +634,7 @@ + for (i=0;i<got;i++) { + if ( ((buf[i] &(cur->this->proto)[0]) == (cur->this->proto)[1]) + && ((buf[i+1]&(cur->this->proto)[2]) == (cur->this->proto)[3]) ) { +- if ((*(cur->this->fun))(&event,buf+i)==-1) continue; ++ if ((*(cur->this->fun))(&mdev,&opt,buf+i,&event)==-1) continue; + i+=packetsize-1; + if (event.buttons && event.buttons!=GPM_B_MIDDLE) pending--; + if (event.buttons==GPM_B_MIDDLE) pending++; +@@ -677,16 +665,16 @@ + char *Xtognames[3]={"'ClearDTR' and 'ClearRTS'","'ClearDTR'","'ClearRTS'"}; + int alllines,lines, index; + +- ioctl(mousefd, TIOCMGET, &alllines); ++ ioctl(mdev.fd, TIOCMGET, &alllines); + + printf("\r\nSome mice change protocol to three-buttons-aware if some\r\n" + "\r\ncontrol lines are toggled after opening\r\n"); + for (index=0;index<3;index++) { +- mousereopen(mousefd,mousename,NULL); ++ mousereopen(&mdev, mousename, NULL, &opt); + lines = alllines & ~toggle[index]; +- ioctl(mousefd, TIOCMSET, &lines); ++ ioctl(mdev.fd, TIOCMSET, &lines); + printf("\r\n==> Trying with '-o %s'\r\n",tognames[index]); +- got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount); ++ got=eventlist(mdev.fd, buf, BUFLEN, GPM_B_MIDDLE, readamount); + + /* if it uses the 5-byte protocol, find it in a rude way */ + for (pending=0,i=0;i<got-20;i++) +@@ -717,7 +705,7 @@ + + getchar(); + +- got=eventlist(mousefd,buf,BUFLEN,GPM_B_MIDDLE,readamount); ++ got=eventlist(mdev.fd,buf,BUFLEN,GPM_B_MIDDLE,readamount); + + /* if it uses the 5-byte protocol, find it in a rude way */ + for (pending=0,i=0;i<got-20;i++) +diff -urN gpm-1.20.1/src/report.c gpm/src/report.c +--- gpm-1.20.1/src/report.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/report.c 2003-10-02 01:22:42.000000000 -0500 +@@ -31,6 +31,7 @@ + + #include "headers/gpmInt.h" + #include "headers/message.h" ++#include "headers/console.h" + + /* + * gpm_report +@@ -70,7 +71,7 @@ + + void gpm_report(int line, char *file, int stat, char *text, ... ) + { +- FILE *console = NULL; ++ FILE *f = NULL; + va_list ap; + + va_start(ap,text); +@@ -138,11 +139,11 @@ + syslog(LOG_DAEMON | LOG_WARNING, GPM_STRING_WARN); + vsyslog(LOG_DAEMON | LOG_WARNING, text, ap); + #endif +- if((console = fopen(GPM_SYS_CONSOLE,"a")) != NULL) { +- fprintf(console,GPM_STRING_WARN); +- vfprintf(console,text,ap); +- fprintf(console,"\n"); +- fclose(console); ++ if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) { ++ fprintf(f, GPM_STRING_WARN); ++ vfprintf(f, text, ap); ++ fprintf(f, "\n"); ++ fclose(f); + } + break; + +@@ -151,18 +152,18 @@ + syslog(LOG_DAEMON | LOG_ERR, GPM_STRING_ERR); + vsyslog(LOG_DAEMON | LOG_ERR, text, ap); + #endif +- if((console = fopen(GPM_SYS_CONSOLE,"a")) != NULL) { +- fprintf(console,GPM_STRING_ERR); +- vfprintf(console,text,ap); +- fprintf(console,"\n"); +- fclose(console); ++ if ((f = fopen(GPM_SYS_CONSOLE, "a")) != NULL) { ++ fprintf(f, GPM_STRING_ERR); ++ vfprintf(f, text, ap); ++ fprintf(f, "\n"); ++ fclose(f); + } + +- if((console = fopen(option.consolename,"a")) != NULL) { +- fprintf(console,GPM_STRING_ERR); +- vfprintf(console,text,ap); +- fprintf(console,"\n"); +- fclose(console); ++ if ((f = fopen(console.device, "a")) != NULL) { ++ fprintf(f, GPM_STRING_ERR); ++ vfprintf(f, text, ap); ++ fprintf(f, "\n"); ++ fclose(f); + } + break; + +@@ -184,24 +185,24 @@ + case GPM_RUN_DEBUG: + switch(stat) { + case GPM_STAT_INFO: +- console = stdout; +- fprintf(console,GPM_STRING_INFO); break; ++ f = stdout; ++ fprintf(f, GPM_STRING_INFO); break; + case GPM_STAT_WARN: +- console = stderr; +- fprintf(console,GPM_STRING_WARN); break; ++ f = stderr; ++ fprintf(f, GPM_STRING_WARN); break; + case GPM_STAT_ERR: +- console = stderr; +- fprintf(console,GPM_STRING_ERR); break; ++ f = stderr; ++ fprintf(f, GPM_STRING_ERR); break; + case GPM_STAT_DEBUG: +- console = stderr; +- fprintf(console,GPM_STRING_DEBUG); break; ++ f = stderr; ++ fprintf(f, GPM_STRING_DEBUG); break; + case GPM_STAT_OOPS: +- console = stderr; +- fprintf(console,GPM_STRING_OOPS); break; ++ f = stderr; ++ fprintf(f, GPM_STRING_OOPS); break; + } + +- vfprintf(console,text,ap); +- fprintf(console,"\n"); ++ vfprintf(f, text, ap); ++ fprintf(f, "\n"); + + if(stat == GPM_STAT_OOPS) exit(1); + +diff -urN gpm-1.20.1/src/selection.c gpm/src/selection.c +--- gpm-1.20.1/src/selection.c 1969-12-31 19:00:00.000000000 -0500 ++++ gpm/src/selection.c 2003-10-02 01:22:42.000000000 -0500 +@@ -0,0 +1,156 @@ ++/* ++ * console.c - GPM console and selection/paste handling ++ * ++ * Copyright (C) 1993 Andreq Haylett <ajh@gec-mrc.co.uk> ++ * Copyright (C) 1994-1999 Alessandro Rubini <rubini@linux.it> ++ * Copyright (C) 1998 Ian Zimmerman <itz@rahul.net> ++ * Copyright (c) 2001,2002 Nico Schottelius <nico@schottelius.org> ++ * Copyright (c) 2003 Dmitry Torokhov <dtor@mail.ru> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ ********/ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> /* strerror(); ?!? */ ++#include <errno.h> ++#include <unistd.h> /* select(); */ ++#include <time.h> /* time() */ ++#include <sys/fcntl.h> /* O_RDONLY */ ++#include <sys/stat.h> /* mkdir() */ ++#include <asm/types.h> /* __u32 */ ++ ++#include <linux/vt.h> /* VT_GETSTATE */ ++#include <sys/kd.h> /* KDGETMODE */ ++#include <termios.h> /* winsize */ ++ ++#include "headers/gpmInt.h" ++#include "headers/message.h" ++#include "headers/console.h" ++#include "headers/selection.h" ++ ++struct sel_options sel_opts = { 0, 0, DEF_PTRDRAG }; ++static time_t last_selection_time; ++ ++/*-------------------------------------------------------------------*/ ++static void selection_copy(int x1, int y1, int x2, int y2, int mode) ++{ ++/* ++ * The approach in "selection" causes a bus error when run under SunOS 4.1 ++ * due to alignment problems... ++ */ ++ unsigned char buf[6 * sizeof(short)]; ++ unsigned short *arg = (unsigned short *)buf + 1; ++ int fd; ++ ++ buf[sizeof(short) - 1] = 2; /* set selection */ ++ ++ arg[0] = (unsigned short)x1; ++ arg[1] = (unsigned short)y1; ++ arg[2] = (unsigned short)x2; ++ arg[3] = (unsigned short)y2; ++ arg[4] = (unsigned short)mode; ++ ++ if ((fd = open_console(O_WRONLY)) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN_CON); ++ ++ gpm_report(GPM_PR_DEBUG, "ctl %i, mode %i", (int)*buf, arg[4]); ++ if (ioctl(fd, TIOCLINUX, buf + sizeof(short) - 1) < 0) ++ gpm_report(GPM_PR_OOPS,GPM_MESS_IOCTL_TIOCLINUX); ++ close(fd); ++ ++ if (mode < 3) { ++ sel_opts.aged = 0; ++ last_selection_time = time(0); ++ } ++} ++ ++/*-------------------------------------------------------------------*/ ++static void selection_paste(void) ++{ ++ char c = 3; ++ int fd; ++ ++ if (!sel_opts.aged && ++ sel_opts.age_limit != 0 && ++ last_selection_time + sel_opts.age_limit < time(0)) { ++ sel_opts.aged = 1; ++ } ++ ++ if (sel_opts.aged) { ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_SKIP_PASTE); ++ } else { ++ fd = open_console(O_WRONLY); ++ if (ioctl(fd, TIOCLINUX, &c) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_IOCTL_TIOCLINUX); ++ close(fd); ++ } ++} ++ ++/*-------------------------------------------------------------------*/ ++void do_selection(Gpm_Event *event, int three_button_mode) ++{ ++ static int x1 = 1, y1 = 1; ++ int x2, y2; ++ ++ x2 = event->x; y2 = event->y; ++ switch(GPM_BARE_EVENTS(event->type)) { ++ case GPM_MOVE: ++ if (x2 < 1) x2++; else if (x2 > console.max_x) x2--; ++ if (y2 < 1) y2++; else if (y2 > console.max_y) y2--; ++ selection_copy(x2, y2, x2, y2, 3); /* just highlight pointer */ ++ break; ++ ++ case GPM_DRAG: ++ if (event->buttons == GPM_B_LEFT) { ++ switch(event->margin) { /* fix margins */ ++ case GPM_TOP: x2 = 1; y2++; break; ++ case GPM_BOT: x2 = console.max_x; y2--; break; ++ case GPM_RGT: x2--; break; ++ case GPM_LFT: y2 <= y1 ? x2++ : (x2 = console.max_x, y2--); break; ++ default: break; ++ } ++ selection_copy(x1, y1, x2, y2, event->clicks); ++ if (event->clicks >= sel_opts.ptrdrag && !event->margin) /* pointer */ ++ selection_copy(x2, y2, x2, y2, 3); ++ } /* if */ ++ break; ++ ++ case GPM_DOWN: ++ switch (event->buttons) { ++ case GPM_B_LEFT: ++ x1 = x2; y1 = y2; ++ selection_copy(x1, y1, x2, y2, event->clicks); /* start selection */ ++ break; ++ ++ case GPM_B_MIDDLE: ++ selection_paste(); ++ break; ++ ++ case GPM_B_RIGHT: ++ if (three_button_mode == 1) ++ selection_copy(x1, y1, x2, y2, event->clicks); ++ else ++ selection_paste(); ++ break; ++ } ++ } /* switch above */ ++} ++ ++/*-------------------------------------------------------------------*/ ++void selection_disable_paste(void) ++{ ++ sel_opts.aged = 1; ++} +diff -urN gpm-1.20.1/src/server_tools.c gpm/src/server_tools.c +--- gpm-1.20.1/src/server_tools.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/server_tools.c 2003-10-02 01:22:42.000000000 -0500 +@@ -21,151 +21,80 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + ********/ + ++#include <string.h> ++#include <stdlib.h> /* malloc() */ ++#include <sys/fcntl.h> ++ + #include "headers/gpmInt.h" + #include "headers/message.h" + +-#include <stdlib.h> /* malloc() */ ++struct micetab *micelist; + +-/* DESCR: add this to the list of mice. initialization follows later */ +-/* RETURN: - */ ++/* DESCR: allocate a new mouse and to the list of mice. initialization follows later */ ++/* RETURN: new mouse structure */ + /* COMMENT: does error handling and exiting itself */ +-void add_mouse(int type, char *value) ++struct micetab *add_mouse(void) + { +- struct micetab *tmp = option.micelist; ++ struct micetab *mouse; + +- /* PREAMBLE for all work: */ +- /* -m /dev/misc/psaux -t ps2 [ -o options ] */ ++ gpm_report(GPM_PR_DEBUG, "adding mouse device"); ++ if (!(mouse = malloc(sizeof(struct micetab)))) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_NO_MEM); ++ ++ memset(mouse, 0, sizeof(struct micetab)); ++ ++ mouse->dev.timeout = -1; ++ ++ mouse->options.sequence = NULL; ++ mouse->options.sample = DEF_SAMPLE; ++ mouse->options.delta = DEF_DELTA; ++ mouse->options.accel = DEF_ACCEL; ++ mouse->options.scalex = DEF_SCALE; ++ mouse->options.scaley = DEF_SCALE; ++ mouse->options.time = DEF_TIME; ++ mouse->options.cluster = DEF_CLUSTER; ++ mouse->options.three_button = DEF_THREE; ++ mouse->options.glidepoint_tap = DEF_GLIDEPOINT_TAP; ++ mouse->options.text = NULL; + +- switch(type) { ++ mouse->next = micelist; ++ micelist = mouse; + +- /*---------------------------------------------------------------------*/ +- /********************** -m mousedevice *********************************/ +- /*---------------------------------------------------------------------*/ +- +- case GPM_ADD_DEVICE: +- +- /* first invocation */ +- if(option.micelist == NULL) { +- gpm_report(GPM_PR_DEBUG,"adding mouse device: %s",value); +- option.micelist = (struct micetab *) malloc(sizeof(struct micetab)); +- if(!option.micelist) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- option.micelist->next = NULL; +- option.micelist->device = value; +- option.micelist->protocol = NULL; +- option.micelist->options = NULL; +- return; +- } +- +- /* find actual mouse */ +- while(tmp->device != NULL && tmp->protocol != NULL && tmp->next !=NULL) +- tmp = tmp->next; +- +- gpm_report(GPM_PR_DEBUG,"finished searching"); +- +- /* found end of micelist, add new mouse */ +- if(tmp->next == NULL && tmp->protocol != NULL) { +- gpm_report(GPM_PR_DEBUG,"next mouse making"); +- tmp->next = (struct micetab *) malloc(sizeof(struct micetab)); +- if(!tmp) gpm_report(GPM_PR_OOPS,GPM_MESS_NO_MEM); +- tmp->next = NULL; +- tmp->device = value; +- tmp->protocol = NULL; +- tmp->options = NULL; +- return; +- } else gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); +- +- //} else if(tmp->device != NULL && tmp->protocol == NULL) +- // gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); /* -m -m */ +- +- +- break; +- +- /*---------------------------------------------------------------------*/ +- /************************* -t type / protocol **************************/ +- /*---------------------------------------------------------------------*/ +- +- case GPM_ADD_TYPE: +- if(option.micelist == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); +- +- /* skip to next mouse, where either device or protocol is missing */ +- while(tmp->device != NULL && tmp->protocol != NULL && tmp->next !=NULL) +- tmp = tmp->next; +- +- /* check whether device (-m) is there, if so, write protocol */ +- if(tmp->device == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); +- else { +- gpm_report(GPM_PR_DEBUG,"adding mouse type: %s",value); +- tmp->protocol = value; +- option.no_mice++; /* finally we got our mouse */ +- } +- +- break; +- +- /*---------------------------------------------------------------------*/ +- /*************************** -o options ********************************/ +- /*---------------------------------------------------------------------*/ +- +- case GPM_ADD_OPTIONS: +- if(option.micelist == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); +- +- /* look for the last mouse */ +- tmp = option.micelist; +- while(tmp->next != NULL) tmp = tmp->next; +- +- /* if -m or -t are missing exit */ +- if(tmp->device == NULL || tmp->protocol == NULL) +- gpm_report(GPM_PR_OOPS,GPM_MESS_FIRST_DEV); +- else { +- gpm_report(GPM_PR_DEBUG,"adding mouse options: %s",value); +- tmp->options = value; +- } +- break; +- } ++ return mouse; + } + +-/* DESCR: mice initialization. currently print mice. */ +-/* RETURN: 0 - failed to init one or more devices +- 1 - init was fine */ ++/* DESCR: mice initialization. calls appropriate init functions. */ + /* COMMENT: does error handling and exiting itself */ +-int init_mice(struct micetab *micelist) ++void init_mice(void) + { +- struct micetab *tmp = micelist; ++ struct micetab *mouse; ++ ++ for (mouse = micelist; mouse; mouse = mouse->next) { ++ if (!strcmp(mouse->device, "-")) ++ mouse->dev.fd = 0; /* use stdin */ ++ else if ((mouse->dev.fd = open(mouse->device, O_RDWR | O_NDELAY)) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, mouse->device); + +- while(tmp != NULL) { /* there are still mice to init */ +- gpm_report(GPM_PR_DEBUG,"initialize %s with proto %s",tmp->device,tmp->protocol); +- if(tmp->options != NULL) { +- gpm_report(GPM_PR_DEBUG,"and options %s",tmp->options); +- } +- tmp = tmp->next; ++ /* and then reset the flag */ ++ fcntl(mouse->dev.fd, F_SETFL, fcntl(mouse->dev.fd, F_GETFL) & ~O_NDELAY); ++ ++ /* init the device, and use the return value as new mouse type */ ++ if (mouse->type->init) ++ if (mouse->type->init(&mouse->dev, &mouse->options, mouse->type)) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_MOUSE_INIT); + } +- +- gpm_report(GPM_PR_DEBUG,"finished initialization"); +- return 1; + } + + /* DESCR: when leaving, we should reset mice to their normal state */ +-/* RETURN: 0 - failed to reset one or more devices +- 1 - reset was fine */ + /* COMMENT: does error handling and exiting itself */ +-int reset_mice(struct micetab *micelist) ++void cleanup_mice(void) + { +- struct micetab *tmp = micelist; +- struct micetab *end = tmp; +- +- while(tmp != NULL) { /* FIXME! I never get NULL, as free()d before */ +- end = tmp; +- while(tmp->next != NULL) { /* set end to the last mouse */ +- end = tmp; +- tmp = tmp->next; +- } +- +- gpm_report(GPM_PR_DEBUG,"reset: %s with proto %s",end->device,end->protocol); +- if(tmp->options != NULL) { +- gpm_report(GPM_PR_DEBUG,"and options %s",end->options); +- } +- free(end); /* be clean() */ +- tmp = micelist; /* reset to the first mice again */ ++ struct micetab *tmp; ++ ++ while ((tmp = micelist)) { ++ if (micelist->dev.private) ++ free(micelist->dev.private); ++ micelist = micelist->next; ++ free(tmp); + } +- +- return 1; + } +diff -urN gpm-1.20.1/src/special.c gpm/src/special.c +--- gpm-1.20.1/src/special.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/special.c 2003-10-02 01:22:42.000000000 -0500 +@@ -37,6 +37,7 @@ + #include <sys/param.h> + + #include "headers/gpmInt.h" ++#include "headers/console.h" + + /* + * This function is only called at button press, to avoid unnecessary +@@ -78,7 +79,7 @@ + return 1; + + /* devfs change */ +- consolef=fopen(option.consolename,"w"); ++ consolef = fopen(console.device, "w"); + if (!consolef) consolef=stderr; + if (event->type & GPM_TRIPLE) /* just triggered: make noise and return */ + { +@@ -153,7 +154,7 @@ + case 0: /* child */ + close(0); close(1); close(2); + open(GPM_NULL_DEV,O_RDONLY); /* stdin */ +- open(option.consolename,O_WRONLY); /* stdout */ ++ open(console.device, O_WRONLY); /* stdout */ + dup(1); /* stderr */ + for (i=3;i<OPEN_MAX; i++) close(i); + execl("/bin/sh","sh","-c",command,(char *)NULL); +diff -urN gpm-1.20.1/src/startup.c gpm/src/startup.c +--- gpm-1.20.1/src/startup.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/startup.c 2003-10-02 01:22:42.000000000 -0500 +@@ -26,6 +26,7 @@ + #include <string.h> /* strlen() */ + #include <errno.h> /* errno */ + #include <unistd.h> /* unlink,geteuid */ ++#include <signal.h> + #include <sys/types.h> /* geteuid, mknod */ + #include <sys/stat.h> /* mknod */ + #include <fcntl.h> /* mknod */ +@@ -34,11 +35,13 @@ + + #include "headers/gpmInt.h" + #include "headers/message.h" ++#include "headers/console.h" ++#include "headers/selection.h" + + /* what todo atexit */ + static void gpm_exited(void) + { +- gpm_report(GPM_PR_DEBUG,GPM_MESS_REMOVE_FILES, GPM_NODE_PID, GPM_NODE_CTL); ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_REMOVE_FILES, GPM_NODE_PID, GPM_NODE_CTL); + unlink(GPM_NODE_PID); + unlink(GPM_NODE_CTL); + } +@@ -48,34 +51,12 @@ + extern struct options option; + extern int errno; + +- int i,opt; +- +- static struct { +- char *in; +- char *out; +- } seq[] = { +- {"123","01234567"}, +- {"132","02134657"}, +- {"213","01452367"}, /* warning: these must be readable as integers... */ +- {"231","02461357"}, +- {"312","04152637"}, +- {"321","04261537"}, +- {NULL,NULL} +- }; +- + /* basic settings */ + option.run_status = GPM_RUN_STARTUP; /* 10,9,8,... let's go */ + option.autodetect = 0; /* no mouse autodection */ + option.progname = argv[0]; /* who we are */ +- option.consolename = Gpm_get_console(); /* get consolename */ +- +- /* basic2: are not necessary for oops()ing, if not root */ +- option.no_mice = 0; /* counts -m + -t */ +- option.micelist = NULL; /* no mice found yet */ +- option.repeater = 0; /* repeat data */ +- option.repeater_type = NULL; /* type of */ +- + ++ get_console_name(); + cmdline(argc, argv); /* parse command line */ + + if (geteuid() != 0) gpm_report(GPM_PR_OOPS,GPM_MESS_ROOT); /* root or exit */ +@@ -87,54 +68,18 @@ + /****************** OLD CODE from gpn.c ***********************/ + + openlog(option.progname, LOG_PID, +- option.run_status != GPM_RUN_DEBUG ? LOG_DAEMON : LOG_USER); +- loadlut(opt_lut); +- +- if (option.repeater) { +- if(mkfifo(GPM_NODE_FIFO,0666) && errno!=EEXIST) +- gpm_report(GPM_PR_OOPS,GPM_MESS_CREATE_FIFO,GPM_NODE_FIFO); +- if((fifofd=open(GPM_NODE_FIFO, O_RDWR|O_NONBLOCK)) < 0) +- gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, GPM_NODE_FIFO); +- } +- +- /* duplicate initialization */ +- for (i=1; i <= 1+opt_double; i++) { +- which_mouse=mouse_table+i; /* used to access options */ +- if (opt_accel < 1) exit(usage("acceleration")); +- if (opt_delta < 2) exit(usage("delta")); +- if (strlen(opt_sequence) != 3 || atoi(opt_sequence)<100) +- exit(usage("sequence")); +- if (opt_glidepoint_tap > 3) exit(usage("glidepoint tap button")); +- if (opt_glidepoint_tap) +- opt_glidepoint_tap=GPM_B_LEFT >> (opt_glidepoint_tap-1); +- +- /* choose the sequence */ +- for (opt=0; seq[opt].in && strcmp(seq[opt].in,opt_sequence); opt++) ; +- if(!seq[opt].in) exit(usage("button sequence")); +- opt_sequence=strdup(seq[opt].out); /* I can rewrite on it */ +- +- /* look for the mouse type */ +- m_type = find_mouse_by_name(opt_type); +- if (!m_type) /* not found */ +- exit(M_listTypes()); +- } ++ option.run_status != GPM_RUN_DEBUG ? LOG_DAEMON : LOG_USER); + +- /* Check repeater status */ +- if (option.repeater) { +- if (strcmp(option.repeater_type,"raw") == 0) +- opt_rawrep = 1; +- else { +- /* look for the type */ +- repeated_type = find_mouse_by_name(option.repeater_type); ++ console_load_lut(); + +- if(!repeated_type) exit(M_listTypes()); /* not found */ +- +- if (!(repeated_type->repeat_fun)) /* unsupported translation */ +- gpm_report(GPM_PR_OOPS,GPM_MESS_NO_REPEAT,option.repeater_type); +- } ++ if (repeater.raw || repeater.type) { ++ if (mkfifo(GPM_NODE_FIFO, 0666) && errno != EEXIST) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_CREATE_FIFO, GPM_NODE_FIFO); ++ if ((repeater.fd = open(GPM_NODE_FIFO, O_RDWR|O_NONBLOCK)) < 0) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_OPEN, GPM_NODE_FIFO); + } + +- if(option.run_status == GPM_RUN_STARTUP ) { /* else is debugging */ ++ if(option.run_status == GPM_RUN_STARTUP) { /* else is debugging */ + /* goto background and become a session leader (Stefan Giessler) */ + switch(fork()) { + case -1: gpm_report(GPM_PR_OOPS,GPM_MESS_FORK_FAILED); /* error */ +@@ -152,13 +97,63 @@ + /* is changing to root needed, because of relative paths ? or can we just + * remove and ignore it ?? FIXME */ + if (chdir("/") < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_CHDIR_FAILED); +- + +- //return mouse_table[1].fd; /* the second is handled in the main() */ ++ atexit(gpm_exited); /* call gpm_exited at the end */ ++} + +- /****************** OLD CODE from gpn.c END ***********************/ ++/* itz Sat Sep 12 10:30:05 PDT 1998 this function used to mix two ++ completely different things; opening a socket to a running daemon ++ and checking that a running daemon existed. Ugly. */ ++/* rewritten mostly on 20th of February 2002 - nico */ ++void check_uniqueness(void) ++{ ++ FILE *fp = 0; ++ int old_pid = -1; + +- init_mice(option.micelist); /* reads option.micelist */ +- atexit(gpm_exited); /* call gpm_exited at the end */ ++ if ((fp = fopen(GPM_NODE_PID, "r")) != NULL) { ++ fscanf(fp, "%d", &old_pid); ++ if (kill(old_pid, 0) == -1) { ++ gpm_report(GPM_PR_INFO,GPM_MESS_STALE_PID, GPM_NODE_PID); ++ unlink(GPM_NODE_PID); ++ } else /* we are really running, exit asap! */ ++ gpm_report(GPM_PR_OOPS, GPM_MESS_ALREADY_RUN, old_pid); ++ } ++ /* now try to sign ourself */ ++ if ((fp = fopen(GPM_NODE_PID,"w")) != NULL) { ++ fprintf(fp,"%d\n",getpid()); ++ fclose(fp); ++ } else { ++ gpm_report(GPM_PR_OOPS,GPM_MESS_NOTWRITE,GPM_NODE_PID); ++ } ++} + ++/* itz Sat Sep 12 10:55:51 PDT 1998 Added this as replacement for the ++ unwanted functionality in check_uniqueness. */ ++void kill_gpm(void) ++{ ++ int old_pid; ++ FILE* fp = fopen(GPM_NODE_PID, "r"); ++ ++ /* if we cannot find the old pid file, leave */ ++ if (fp == NULL) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN, GPM_NODE_PID); ++ ++ /* else read the pid */ ++ if (fscanf(fp, "%d", &old_pid) != 1) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_READ_PROB, GPM_NODE_PID); ++ fclose(fp); ++ ++ gpm_report(GPM_PR_DEBUG, GPM_MESS_KILLING, old_pid); ++ ++ /* first check if we run */ ++ if (kill(old_pid,0) == -1) { ++ gpm_report(GPM_PR_INFO, GPM_MESS_STALE_PID, GPM_NODE_PID); ++ unlink(GPM_NODE_PID); ++ } ++ /* then kill us (not directly, but the other instance ... ) */ ++ if (kill(old_pid, SIGTERM) == -1) ++ gpm_report(GPM_PR_OOPS, GPM_MESS_CANT_KILL, old_pid); ++ ++ gpm_report(GPM_PR_INFO, GPM_MESS_KILLED, old_pid); ++ exit(0); + } ++ +diff -urN gpm-1.20.1/src/synaptics.c gpm/src/synaptics.c +--- gpm-1.20.1/src/synaptics.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/synaptics.c 2003-10-02 01:22:42.000000000 -0500 +@@ -865,7 +865,7 @@ + static int scrolling_speed_timer = 0; + static int scrolling_amount_left = 0; /* Tells how much to scroll up or down */ + +- ++static int mouse_fd; + + + +@@ -882,6 +882,7 @@ + ** which makes reading the debug data harder, only dump the report if it is different + ** than the previously dumped. + */ ++#if DEBUG_REPORTS + static void tp_dump_report_data (report_type report, + int edges, + Gpm_Event* state) +@@ -934,7 +935,7 @@ + (multi_finger_pressure>4500 && multi_finger_xy>50000? 'f':' ')); + + } +- ++#endif + + /* syn_dump_info + ** +@@ -1158,8 +1159,8 @@ + status = GPM_B_NOT_SET; + break; + case Reset_Touchpad_Action: +- syn_ps2_reset(which_mouse->fd); +- syn_ps2_absolute_mode(which_mouse->fd); ++ syn_ps2_reset(mouse_fd); ++ syn_ps2_absolute_mode(mouse_fd); + status = GPM_B_NOT_SET; + break; + case Toggle_Four_Way_Button_Action: +@@ -2950,10 +2951,8 @@ + data [0],data [1],data [2],data [3],data [4],data [5]); + + if (reset_on_error_enabled) { +- /* Hack to get the fd: which_mouse is the current mouse, +- and as the synaptic code is called, it is the current mouse. */ +- syn_ps2_reset(which_mouse->fd); +- syn_ps2_absolute_mode(which_mouse->fd); ++ syn_ps2_reset(mouse_fd); ++ syn_ps2_absolute_mode(mouse_fd); + } + + report->left = 0; +@@ -3108,7 +3107,7 @@ + ** + ** Process the touchpad 6 byte report. + */ +-void syn_process_serial_data (Gpm_Event *state, ++void syn_process_serial_data (int fd, Gpm_Event *state, + unsigned char *data) + { + /* initialize the state */ +@@ -3116,6 +3115,8 @@ + state->dx = 0; + state->dy = 0; + ++ mouse_fd = fd; /* cheat */ ++ + syn_serial_translate_data (data, &cur_report); + if (wmode_enabled){ + syn_process_wmode_report(&cur_report); +@@ -3196,7 +3197,7 @@ + ** + ** Process the touchpad 6 byte report. + */ +-void syn_process_ps2_data (Gpm_Event *state, ++void syn_process_ps2_data (int fd, Gpm_Event *state, + unsigned char *data) + { + /* gpm_report(GPM_PR_DEBUG,"Data %02x %02x %02x %02x %02x %02x",data[0],data[1],data[2],data[3],data[4],data[5]); */ +@@ -3206,6 +3207,7 @@ + state->dx = 0; + state->dy = 0; + ++ mouse_fd = fd; /* cheat */ + + if (wmode_enabled) { + syn_ps2_translate_wmode_data (data, &cur_report); +diff -urN gpm-1.20.1/src/tools.c gpm/src/tools.c +--- gpm-1.20.1/src/tools.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/tools.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,93 +0,0 @@ +-/* +- * tools.c - tools which are needed by client and server +- * +- * Copyright (c) 2001 Nico Schottelius <nico@schottelius.org> +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +- ********/ +- +-#include <stdio.h> /* NULL */ +-#include <string.h> +-#include <stdlib.h> +-#include <sys/types.h> /* these three are */ +-#include <sys/stat.h> /* needed for */ +-#include <unistd.h> /* stat() */ +- +-#include "headers/gpmInt.h" /* only used for some defines */ +-#include "headers/message.h" +- +-/***************************************************************************** +- * check, whether devfs is used or not. +- * See /usr/src/linux/Documentation/filesystems/devfs/ for details. +- * Returns: the name of the console (/dev/tty0 or /dev/vc/0) +- *****************************************************************************/ +-char *Gpm_get_console( void ) +-{ +- +- char *back = NULL, *tmp = NULL; +- struct stat buf; +- +- /* first try the devfs device, because in the next time this will be +- * the preferred one. If that fails, take the old console */ +- +- /* Check for open new console */ +- if (stat(GPM_DEVFS_CONSOLE,&buf) == 0) +- tmp = GPM_DEVFS_CONSOLE; +- +- /* Failed, try OLD console */ +- else if(stat(GPM_OLD_CONSOLE,&buf) == 0) +- tmp = GPM_OLD_CONSOLE; +- +- if(tmp != NULL) +- if((back = malloc(strlen(tmp) + sizeof(char)) ) != NULL) +- strcpy(back,tmp); +- +- return(back); +-} +- +-/* what's the english name for potenz ? */ +-int Gpm_x_high_y(int base, int pot_y) +-{ +- int val = 1; +- +- if(pot_y == 0) val = 1; +- else if(pot_y < 0) val = 0; /* ugly hack ;) */ +- else while(pot_y > 0) { +- val = val * base; +- pot_y--; +- } +- return val; +-} +- +-/* return characters needed to display int */ +-int Gpm_cnt_digits(int number) +-{ +- /* 0-9 = 1 10^0 <-> (10^1)-1 +- * 10 - 99 = 2 10^1 <-> (10^2)-1 +- * 100 - 999 = 3 10^2 <-> (10^3)-1 +- * 1000 - 9999 = 4 ... */ +- +- int ret = 0, num = 0; +- +- /* non negative, please */ +- if(number < 0) number *= -1; +- else if(number == 0) ret = 1; +- else while(number > num) { +- ret++; +- num = (Gpm_x_high_y(10,ret) - 1); +- } +- +- return(ret); +-} +diff -urN gpm-1.20.1/src/twiddler.c gpm/src/twiddler.c +--- gpm-1.20.1/src/twiddler.c 2002-12-24 17:57:16.000000000 -0500 ++++ gpm/src/twiddler.c 2003-10-02 01:22:42.000000000 -0500 +@@ -54,6 +54,7 @@ + #include "headers/gpm.h" + #include "headers/gpmInt.h" + #include "headers/message.h" ++#include "headers/console.h" + #include "headers/twiddler.h" + + +@@ -134,17 +135,6 @@ + int (*fun)(char *string); + }; + +- +-/* The same silly function as in gpm.c */ +-static inline int open_console(const int mode) +-{ +- int fd; +- extern struct options option; +- if ((fd=open(option.consolename, mode)) < 0) gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,option.consolename); +- return fd; +-} +- +- + /*===================================================================*/ + /* This part deals with pushing keys */ + +@@ -175,7 +165,7 @@ + int twiddler_exec(char *s) + { + int pid; +- extern struct options option; ++ + switch(pid=fork()) { + case -1: return -1; + case 0: +@@ -184,7 +174,7 @@ + close(2); /* very rude! */ + + open(GPM_NULL_DEV,O_RDONLY); +- open(option.consolename,O_WRONLY); ++ open(console.device, O_WRONLY); + dup(1); + execl("/bin/sh", "sh", "-c", s, NULL); + exit(1); /* shouldn't happen */ diff --git a/source/a/gpm/gpm.SlackBuild b/source/a/gpm/gpm.SlackBuild new file mode 100755 index 00000000..b0352fe8 --- /dev/null +++ b/source/a/gpm/gpm.SlackBuild @@ -0,0 +1,149 @@ +#!/bin/sh + +# Copyright 2008, 2009 Patrick J. Volkerding, Sebeka, Minnesota, USA +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# by: volkerdi@slackware.com + +VERSION=1.20.1 +ARCH=${ARCH:-x86_64} +BUILD=${BUILD:-5} + +CWD=$(pwd) +TMP=${TMP:-/tmp} +PKG=$TMP/package-gpm + +if [ "$ARCH" = "i486" ]; then + SLKCFLAGS="-O2 -march=i486 -mtune=i686" + LIBDIRSUFFIX="" +elif [ "$ARCH" = "s390" ]; then + SLKCFLAGS="-O2" + LIBDIRSUFFIX="" +elif [ "$ARCH" = "x86_64" ]; then + SLKCFLAGS="-O2 -fPIC" + LIBDIRSUFFIX="64" +fi + +rm -rf $PKG +mkdir -p $TMP $PKG + +cd $TMP +rm -rf gpm-$VERSION +tar xjvf $CWD/gpm-$VERSION.tar.bz2 +cd gpm-$VERSION +sed -i -e "s/OPEN_MAX/NR_OPEN/" $(grep -lr OPEN_MAX *) +chown -R root:root . +find . \ + \( -perm 700 -o -perm 777 -o -perm 775 -o -perm 711 -o -perm 555 -o -perm 511 \) \ + -exec chmod 755 {} \; -o \ + \( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \ + -exec chmod 644 {} \; + +zcat $CWD/gpm-evdev-cumulative.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm.evdevmakefile.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-math.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-weak-wgetch.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-nodebug.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-gpmopen.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-idie.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-subscript.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-input.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-consolename.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-multilib.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-no-console-error.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-lib-silent.patch.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1.send-noise-to-syslogs.diff.gz | patch -p1 --verbose || exit 1 +zcat $CWD/gpm-1.20.1-input-defines.diff.gz | patch -p1 --verbose || exit 1 + +autoconf + +CFLAGS="$SLKCFLAGS" \ +./configure \ + --prefix=/usr \ + --sysconfdir=/etc \ + $ARCH-slackware-linux + +make || exit 1 +zcat $CWD/inputattach.c.gz > inputattach.c +gcc $SLKCFLAGS -o inputattach inputattach.c || exit + +mkdir -p $PKG/usr/bin $PKG/etc/rc.d +cat inputattach > $PKG/usr/bin/inputattach +( cd src + mkdir -p $PKG/usr/sbin + cat gpm > $PKG/usr/sbin/gpm + cat prog/disable-paste > $PKG/usr/bin/disable-paste + cat prog/gpm-root > $PKG/usr/bin/gpm-root + cat prog/hltest > $PKG/usr/bin/hltest + cat prog/mev > $PKG/usr/bin/mev + cat prog/mouse-test > $PKG/usr/bin/mouse-test + mkdir -p $PKG/usr/include + cp headers/gpm.h $PKG/usr/include/gpm.h + chmod 644 $PKG/usr/include/gpm.h + mkdir -p $PKG/usr/lib${LIBDIRSUFFIX} $PKG/lib${LIBDIRSUFFIX} + cat lib/libgpm.a > $PKG/usr/lib${LIBDIRSUFFIX}/libgpm.a + cat lib/libgpm.so.1.19.0 > $PKG/lib${LIBDIRSUFFIX}/libgpm.so.1.19.0 + chmod 755 $PKG/lib${LIBDIRSUFFIX}/libgpm.so.1.19.0 +) +( cd conf + mkdir -p $PKG/etc + cat gpm-root.conf > $PKG/etc/gpm-root.conf + cat gpm-syn.conf > $PKG/etc/gpm-syn.conf + cat gpm-twiddler.conf > $PKG/etc/gpm-twiddler.conf +) +( cd contrib/emacs + mkdir -p $PKG/usr/share/emacs/site-lisp + cat t-mouse.el > $PKG/usr/share/emacs/site-lisp/t-mouse.el +) +mkdir -p $PKG/usr/doc/gpm-$VERSION +cp -a \ + BUGS COPYING Changelog Changes MANIFEST README TODO \ + $PKG/usr/doc/gpm-$VERSION +( cd doc + for page in *.1 *.7 *.8 ; do + CHAPTER=`echo $page | cut -f 2 -d .` + mkdir -p $PKG/usr/man/man$CHAPTER + cat $page | gzip -9c > $PKG/usr/man/man${CHAPTER}/$page.gz + done + mkdir -p $PKG/usr/info + cat gpm.info | gzip -9c > $PKG/usr/info/gpm.info.gz + cp -a \ + Announce FAQ HACK_GPM README* \ + $PKG/usr/doc/gpm-$VERSION +) +( cd $PKG/usr/lib${LIBDIRSUFFIX} + ln -sf ../../lib${LIBDIRSUFFIX}/libgpm.so.1 libgpm.so ) +( cd $PKG/lib${LIBDIRSUFFIX} ; ln -sf libgpm.so.1.19.0 libgpm.so.1 ) +zcat $CWD/mouseconfig.gz > $PKG/usr/sbin/mouseconfig +chmod 755 $PKG/usr/bin/* $PKG/usr/sbin/* +mkdir -p $PKG/var/log/setup +zcat $CWD/setup.mouse.gz > $PKG/var/log/setup/setup.mouse +chmod 755 $PKG/var/log/setup/setup.mouse +( cd $PKG + find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null + find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null +) +mkdir -p $PKG/install +cat $CWD/slack-desc > $PKG/install/slack-desc + +# Build the package: +cd $PKG +makepkg -l y -c n $TMP/gpm-$VERSION-$ARCH-$BUILD.txz + diff --git a/source/a/gpm/gpm.evdevmakefile.patch b/source/a/gpm/gpm.evdevmakefile.patch new file mode 100644 index 00000000..bd56c3aa --- /dev/null +++ b/source/a/gpm/gpm.evdevmakefile.patch @@ -0,0 +1,11 @@ +--- ./src/Makefile.in.orig 2006-02-07 15:24:17.000000000 -0600 ++++ ./src/Makefile.in 2006-02-07 15:26:03.000000000 -0600 +@@ -12,7 +12,7 @@ + include $(top_builddir)/Makefile.include + + # Main portion: regular build rules +-MICESRC = mice.c twiddler.c synaptics.c @EVDEV_SRCS@ ++MICESRC = mice.c twiddler.c synaptics.c evdev.c + + GSRC = main.c gpm.c gpn.c special.c startup.c server_tools.c console.c \ + selection.c client.c optparser.c $(MICESRC) diff --git a/source/a/gpm/inputattach.c b/source/a/gpm/inputattach.c new file mode 100644 index 00000000..c47fad13 --- /dev/null +++ b/source/a/gpm/inputattach.c @@ -0,0 +1,472 @@ +/* + * $Id: inputattach.c,v 1.21 2002/07/10 22:34:01 vojtech Exp $ + * + * Copyright (c) 1999-2000 Vojtech Pavlik + * + * Sponsored by SuSE + * + * Twiddler support Copyright (c) 2001 Arndt Schoenewald + * Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany + */ + +/* + * Input line discipline attach program + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include <linux/serio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +int readchar(int fd, unsigned char *c, int timeout) +{ + struct timeval tv; + fd_set set; + + tv.tv_sec = 0; + tv.tv_usec = timeout * 1000; + + FD_ZERO(&set); + FD_SET(fd, &set); + + if (!select(fd+1, &set, NULL, NULL, &tv)) return -1; + if (read(fd, c, 1) != 1) return -1; + + return 0; +} + + + +void setline(int fd, int flags, int speed) +{ + struct termios t; + + tcgetattr(fd, &t); + + t.c_cflag = flags | CREAD | HUPCL | CLOCAL; + t.c_iflag = IGNBRK | IGNPAR; + t.c_oflag = 0; + t.c_lflag = 0; + t.c_cc[VMIN ] = 1; + t.c_cc[VTIME] = 0; + + cfsetispeed(&t, speed); + cfsetospeed(&t, speed); + + tcsetattr(fd, TCSANOW, &t); +} + +int logitech_command(int fd, char *c) +{ + int i; + unsigned char d; + for (i = 0; c[i]; i++) { + write(fd, c + i, 1); + if (readchar(fd, &d, 1000)) + return -1; + if (c[i] != d) + return -1; + } + return 0; +} + +int magellan_init(int fd, long *id, long *extra) +{ + write(fd, "m3\rpBB\rz\r", 9); + return 0; +} + +int warrior_init(int fd, long *id, long *extra) +{ + if (logitech_command(fd, "*S")) return -1; + setline(fd, CS8, B4800); + return 0; +} + +int spaceball_waitchar(int fd, unsigned char c, unsigned char *d, int timeout) +{ + unsigned char b = 0; + + while (!readchar(fd, &b, timeout)) { + if (b == 0x0a) continue; + *d++ = b; + if (b == c) break; + } + + *d = 0; + + return -(b != c); +} + +int spaceball_waitcmd(int fd, char c, char *d) +{ + int i; + + for (i = 0; i < 8; i++) { + if (spaceball_waitchar(fd, 0x0d, d, 1000)) + return -1; + if (d[0] == c) + return 0; + } + + return -1; +} + +int spaceball_cmd(int fd, char *c, char *d) +{ + int i; + + for (i = 0; c[i]; i++) + write(fd, c + i, 1); + write(fd, "\r", 1); + + i = spaceball_waitcmd(fd, toupper(c[0]), d); + + return i; +} + +#define SPACEBALL_1003 1 +#define SPACEBALL_2003B 3 +#define SPACEBALL_2003C 4 +#define SPACEBALL_3003C 7 +#define SPACEBALL_4000FLX 8 +#define SPACEBALL_4000FLX_L 9 + +int spaceball_init(int fd, long *id, long *extra) +{ + char r[64]; + + if (spaceball_waitchar(fd, 0x11, r, 4000) || + spaceball_waitchar(fd, 0x0d, r, 1000)) + return -1; + + if (spaceball_waitcmd(fd, '@', r)) + return -1; + + if (strncmp("@1 Spaceball alive", r, 18)) + return -1; + + if (spaceball_waitcmd(fd, '@', r)) + return -1; + + if (spaceball_cmd(fd, "hm", r)) + return -1; + + if (!strncmp("Hm2003B", r, 7)) + *id = SPACEBALL_2003B; + if (!strncmp("Hm2003C", r, 7)) + *id = SPACEBALL_2003C; + if (!strncmp("Hm3003C", r, 7)) + *id = SPACEBALL_3003C; + + if (!strncmp("HvFirmware", r, 10)) { + + if (spaceball_cmd(fd, "\"", r)) + return -1; + + if (strncmp("\"1 Spaceball 4000 FLX", r, 21)) + return -1; + + if (spaceball_waitcmd(fd, '"', r)) + return -1; + + if (strstr(r, " L ")) + *id = SPACEBALL_4000FLX_L; + else + *id = SPACEBALL_4000FLX; + + if (spaceball_waitcmd(fd, '"', r)) + return -1; + + if (spaceball_cmd(fd, "YS", r)) + return -1; + + if (spaceball_cmd(fd, "M", r)) + return -1; + + return 0; + } + + if (spaceball_cmd(fd, "P@A@A", r) || + spaceball_cmd(fd, "FT@", r) || + spaceball_cmd(fd, "MSS", r)) + return -1; + + return 0; +} + +int stinger_init(int fd, long *id, long *extra) +{ + int i; + unsigned char c; + unsigned char *response = "\r\n0600520058C272"; + + if (write(fd, " E5E5", 5) != 5) /* Enable command */ + return -1; + + for (i = 0; i < 16; i++) /* Check for Stinger */ + if (readchar(fd, &c, 200) || (c != response[i])) + return -1; + + return 0; +} + +int mzp_init(int fd, long *id, long *extra) +{ + if (logitech_command(fd, "*X*q")) return -1; + setline(fd, CS8, B9600); + return 0; +} + +int newton_init(int fd, long *id, long *extra) +{ + int i; + unsigned char c; + unsigned char response[35] = + { 0x16, 0x10, 0x02, 0x64, 0x5f, 0x69, 0x64, 0x00, + 0x00, 0x00, 0x0c, 0x6b, 0x79, 0x62, 0x64, 0x61, + 0x70, 0x70, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x6e, + 0x6f, 0x66, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x03, 0xdd, 0xe7 }; + + for (i = 0; i < 35; i++) + if (readchar(fd, &c, 400) || (c != response[i])) + return -1; + + return 0; +} + +int twiddler_init(int fd, long *id, long *extra) +{ + unsigned char c[10]; + int count, line; + + /* Turn DTR off, otherwise the Twiddler won't send any data. */ + if (ioctl(fd, TIOCMGET, &line)) return -1; + line &= ~TIOCM_DTR; + if (ioctl(fd, TIOCMSET, &line)) return -1; + + /* Check whether the device on the serial line is the Twiddler. + * + * The Twiddler sends data packets of 5 bytes which have the following + * properties: the MSB is 0 on the first and 1 on all other bytes, and + * the high order nibble of the last byte is always 0x8. + * + * We read and check two of those 5 byte packets to be sure that we + * are indeed talking to a Twiddler. */ + + /* Read at most 5 bytes until we find one with the MSB set to 0 */ + for (count = 0; count < 5; count++) { + if (readchar(fd, c+0, 500)) return -1; + if ((c[0] & 0x80) == 0) break; + } + + if (count == 5) { + /* Could not find header byte in data stream */ + return -1; + } + + /* Read remaining 4 bytes plus the full next data packet */ + for (count = 1; count < 10; count++) { + if (readchar(fd, c+count, 500)) return -1; + } + + /* Check whether the bytes of both data packets obey the rules */ + for (count = 1; count < 10; count++) { + if ((count % 5 == 0 && (c[count] & 0x80) != 0) + || (count % 5 == 4 && (c[count] & 0xF0) != 0x80) + || (count % 5 != 0 && (c[count] & 0x80) != 0x80)) { + /* Invalid byte in data packet */ + return -1; + } + } + + return 0; +} + +int dump_init(int fd, long *id, long *extra) +{ + unsigned char c, o = 0; + + c = 0x80; + + if (write(fd, &c, 1) != 1) /* Enable command */ + return -1; + + while (1) + if (!readchar(fd, &c, 1)) { + printf("%02x (%c) ", c, ((c > 32) && (c < 127)) ? c : 'x'); + o = 1; + } else { + if (o) { + printf("\n"); + o = 0; + } + } +} + +struct input_types { + char name[16]; + char name2[16]; + int speed; + int flags; + unsigned long type; + unsigned long extra; + int flush; + int (*init)(int fd, long *id, long *extra); +}; + +struct input_types input_types[] = { + +{ "--sunkbd", "-skb", B1200, CS8, SERIO_SUNKBD, 0x00, 1, NULL }, +{ "--spaceorb", "-orb", B9600, CS8, SERIO_SPACEORB, 0x00, 1, NULL }, +{ "--spaceball", "-sbl", B9600, CS8, SERIO_SPACEBALL,0x00, 0, spaceball_init }, +{ "--magellan", "-mag", B9600, CS8 | CSTOPB | CRTSCTS, SERIO_MAGELLAN, 0x00, 1, magellan_init }, +{ "--warrior", "-war", B1200, CS7 | CSTOPB, SERIO_WARRIOR, 0x00, 1, warrior_init }, +{ "--stinger", "-sting", B1200, CS8, SERIO_STINGER, 0x00, 1, stinger_init }, +{ "--mousesystems", "-msc", B1200, CS8, SERIO_MSC, 0x01, 1, NULL }, +{ "--sunmouse", "-sun", B1200, CS8, SERIO_SUN, 0x01, 1, NULL }, +{ "--microsoft", "-bare", B1200, CS7, SERIO_MS, 0x00, 1, NULL }, +{ "--mshack", "-ms", B1200, CS7, SERIO_MS, 0x01, 1, NULL }, +{ "--mouseman", "-mman", B1200, CS7, SERIO_MP, 0x01, 1, NULL }, +{ "--intellimouse", "-ms3", B1200, CS7, SERIO_MZ, 0x11, 1, NULL }, +{ "--mmwheel", "-mmw", B1200, CS7 | CSTOPB, SERIO_MZP, 0x13, 1, mzp_init }, +{ "--iforce", "-ifor", B38400, CS8, SERIO_IFORCE, 0x00, 0, NULL }, +{ "--newtonkbd", "-newt", B9600, CS8, SERIO_NEWTON, 0x00, 0, newton_init }, +{ "--h3600ts", "-ipaq", B115200, CS8, SERIO_H3600, 0x00, 0, NULL }, +{ "--stowawaykbd", "-ipaqkbd", B115200, CS8, SERIO_STOWAWAY, 0x00, 0, NULL }, +{ "--ps2serkbd", "-ps2ser", B1200, CS8, SERIO_PS2SER, 0x00, 1, NULL }, +#if 0 +{ "--twiddler", "-twid", B2400, CS8, SERIO_TWIDKBD, 0x00, 0, twiddler_init }, +{ "--twiddler-joy", "-twidjoy", B2400, CS8, SERIO_TWIDJOY, 0x00, 0, twiddler_init }, +{ "--ipod-remote", "-ipod", B9600, CS8, SERIO_IPOD_REM, 0x00, 0, NULL }, +#endif +{ "--dump", "-dump", B2400, CS8, 0, 0x00, 0, dump_init }, +{ "", "", 0, 0 } + +}; + +int main(int argc, char **argv) +{ + unsigned long devt; + int ldisc; + int type; + long id, extra; + int fd; + char c; + + if (argc < 2 || argc > 4 || (argc == 4 && strcmp(argv[3], "--daemon")) || !strcmp("--help", argv[1])) { + puts(""); + puts("Usage: inputttach <mode> <device>"); + puts(""); + puts("Modes:"); + puts(" --sunkbd -skb Sun Type 4 and Type 5 keyboards"); + puts(" --spaceorb -orb SpaceOrb 360 / SpaceBall Avenger"); + puts(" --spaceball -sbl SpaceBall 2003 / 3003 / 4000 FLX"); + puts(" --magellan -mag Magellan / SpaceMouse"); + puts(" --warrior -war WingMan Warrior"); + puts(" --stinger -stng Gravis Stinger"); + puts(" --mousesystems -msc 3-button Mouse Systems mice"); + puts(" --sunmouse -sun 3-button Sun mice"); + puts(" --microsoft -bare 2-button Microsoft mice"); + puts(" --mshack -ms 3-button mice in Microsoft mode"); + puts(" --mouseman -mman 3-button Logitech and Genius mice"); + puts(" --intellimouse -ms3 Microsoft IntelliMouse"); + puts(" --mmwheel -mmw Logitech mice with 4-5 buttons or wheel"); + puts(" --iforce -ifor I-Force joysticks and wheels"); + puts(" --h3600ts -ipaq Ipaq h3600 touchscreen"); + puts(" --stowawaykbd -ipaqkbd Stowaway keyboard"); + puts(" --ps2serkbd -ps2ser PS/2 via serial keyboard"); +#if 0 + puts(" --twiddler -twid Handykey Twiddler chording keyboard"); + puts(" --twiddler-joy -twidjoy Handykey Twiddler used as a joystick"); + puts(" --ipod-remote -ipod iPod remote control"); +#endif + puts(""); + return 1; + } + + for (type = 0; input_types[type].speed; type++) { + if (!strncasecmp(argv[1], input_types[type].name, 16) || + !strncasecmp(argv[1], input_types[type].name2, 16)) + break; + } + + if (!input_types[type].speed) { + fprintf(stderr, "inputattach: invalid mode\n"); + return 1; + } + + if ((fd = open(argv[2], O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) { + perror("inputattach"); + return 1; + } + + setline(fd, input_types[type].flags, input_types[type].speed); + + if (input_types[type].flush) + while (!readchar(fd, &c, 100)); + + id = 0; + extra = input_types[type].extra; + + if (input_types[type].init && input_types[type].init(fd, &id, &extra)) { + fprintf(stderr, "inputattach: device initialization failed\n"); + return 1; + } + + ldisc = N_MOUSE; + if(ioctl(fd, TIOCSETD, &ldisc)) { + fprintf(stderr, "inputattach: can't set line discipline\n"); + return 1; + } + + devt = SERIO_RS232 | input_types[type].type | (id << 8) | (extra << 16); + + if(ioctl(fd, SPIOCSTYPE, &devt)) { + fprintf(stderr, "inputattach: can't set device type\n"); + return 1; + } + + if (argc == 4 && !strcmp(argv[3],"--daemon")) + daemon(0,0); + + read(fd, NULL, 0); + + ldisc = 0; + ioctl(fd, TIOCSETD, &ldisc); + close(fd); + + return 0; +} diff --git a/source/a/gpm/mouseconfig b/source/a/gpm/mouseconfig new file mode 100644 index 00000000..4e9575f5 --- /dev/null +++ b/source/a/gpm/mouseconfig @@ -0,0 +1,7 @@ +#!/bin/sh +# Starts the Slackware mouse configuration menu, where you can set your +# /dev/mouse link and configure gpm. +COLOR=on +export COLOR +cd / +/bin/sh /var/log/setup/setup.mouse / diff --git a/source/a/gpm/setup.mouse b/source/a/gpm/setup.mouse new file mode 100644 index 00000000..dcdc6a8f --- /dev/null +++ b/source/a/gpm/setup.mouse @@ -0,0 +1,154 @@ +#!/bin/sh +#BLURB="Configure the console mouse support (GPM)." +T_PX=$1 +TMP=/var/log/setup/tmp +GPM=/usr/sbin/gpm +# If the mouse is USB, we can autodetect it: +if [ -r /proc/bus/usb/devices ]; then + if cat /proc/bus/usb/devices | grep usb_mouse 1> /dev/null 2> /dev/null ; then + MOUSE_TYPE=usb + MTYPE="imps2" + ( cd $T_PX/dev ; rm -f mouse ; ln -sf input/mice mouse ) + fi +fi + +if [ "$MOUSE_TYPE" = "" ]; then + dialog --title "MOUSE CONFIGURATION" --default-item "imps2" --menu \ +"This part of the configuration \ +process will create a /dev/mouse link pointing to your default mouse device. \ +You can change the /dev/mouse link later if the mouse doesn't work, or if \ +you switch to a different type of pointing device. We will also use the \ +information about the mouse to set the correct protocol for gpm, the Linux \ +mouse server. Please select a mouse type \ +from the list below:" 20 76 8 \ + "ps2" "PS/2 port mouse (most desktops and laptops)" \ + "usb" "USB connected mouse" \ + "imps2" "Microsoft PS/2 Intellimouse" \ + "exps2" "Intellimouse Explorer PS/2" \ + "bare" "2 button Microsoft compatible serial mouse" \ + "ms" "3 button Microsoft compatible serial mouse" \ + "mman" "Logitech serial MouseMan and similar devices" \ + "msc" "MouseSystems serial (most 3 button serial mice)" \ + "pnp" "Plug and Play (serial mice that do not work with ms)" \ + "ms3" "Microsoft serial Intellimouse" \ + "netmouse" "Genius Netmouse on PS/2 port" \ + "logi" "Some serial Logitech devices" \ + "logim" "Make serial Logitech behave like msc" \ + "atibm" "ATI XL busmouse (mouse card)" \ + "inportbm" "Microsoft busmouse (mouse card)" \ + "logibm" "Logitech busmouse (mouse card)" \ + "ncr" "A pointing pen (NCR3125) on some laptops" \ + "twid" "Twiddler keyboard, by HandyKey Corp" \ + "genitizer" "Genitizer tablet (relative mode)" \ + "js" "Use a joystick as a mouse" \ + "wacom" "Wacom serial graphics tablet" \ + 2> $TMP/mtype + if [ ! $? = 0 ]; then + rm -f $TMP/mtype + exit + fi + if [ -f $TMP/mtype ]; then + MOUSE_TYPE="`cat $TMP/mtype`" + else + unset MOUSE_TYPE + fi + rm -f $TMP/mtype + if [ "$MOUSE_TYPE" = "bare" -o "$MOUSE_TYPE" = "ms" \ + -o "$MOUSE_TYPE" = "mman" -o "$MOUSE_TYPE" = "msc" \ + -o "$MOUSE_TYPE" = "genitizer" \ + -o "$MOUSE_TYPE" = "pnp" -o "$MOUSE_TYPE" = "ms3" \ + -o "$MOUSE_TYPE" = "logi" -o "$MOUSE_TYPE" = "logim" \ + -o "$MOUSE_TYPE" = "wacom" -o "$MOUSE_TYPE" = "twid" ]; then + dialog --title "SELECT SERIAL PORT" --menu "Your mouse requires a \ +serial port. Which one would you like to use?" 12 50 4 \ + "/dev/ttyS0" "(COM1: under DOS)" \ + "/dev/ttyS1" "(COM2: under DOS)" \ + "/dev/ttyS2" "(COM3: under DOS)" \ + "/dev/ttyS3" "(COM4: under DOS)" 2> $TMP/mport + if [ ! $? = 0 ]; then + rm -f $TMP/mport + exit + fi + MDEVICE="`cat $TMP/mport`" + SHORT_MDEVICE=`basename $MDEVICE` + ( cd $T_PX/dev ; rm -f mouse ; ln -sf $SHORT_MDEVICE mouse ) + # For the serial mice, the protocol is the same as the mouse type: + MTYPE=$MOUSE_TYPE + rm -f $TMP/mport + elif [ "$MOUSE_TYPE" = "ps2" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf psaux mouse ) + MTYPE="ps2" + elif [ "$MOUSE_TYPE" = "ncr" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf psaux mouse ) + MTYPE="ncr" + elif [ "$MOUSE_TYPE" = "exps2" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf psaux mouse ) + MTYPE="exps2" + elif [ "$MOUSE_TYPE" = "imps2" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf psaux mouse ) + MTYPE="imps2" + elif [ "$MOUSE_TYPE" = "logibm" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf logibm mouse ) + MTYPE="ps2" + elif [ "$MOUSE_TYPE" = "atibm" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf atibm mouse ) + MTYPE="ps2" + elif [ "$MOUSE_TYPE" = "inportbm" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf inportbm mouse ) + MTYPE="bm" + elif [ "$MOUSE_TYPE" = "js" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf js0 mouse ) + MTYPE="js" + elif [ "$MOUSE_TYPE" = "usb" ]; then + ( cd $T_PX/dev ; rm -f mouse ; ln -sf input/mice mouse ) + MTYPE="imps2" + fi +fi + +# OK, we know enough now to create a sample rc.gpm: +cat << EOF > $T_PX/etc/rc.d/rc.gpm-sample +#!/bin/sh +# Start/stop/restart the GPM mouse server: + +if [ "\$1" = "stop" ]; then + echo "Stopping gpm..." + $GPM -k +elif [ "\$1" = "restart" ]; then + echo "Restarting gpm..." + $GPM -k + sleep 1 + $GPM -m /dev/mouse -t $MTYPE +else # assume \$1 = start: + echo "Starting gpm: $GPM -m /dev/mouse -t $MTYPE" + $GPM -m /dev/mouse -t $MTYPE +fi + +# There is another way to run GPM, where it acts as a repeater outputting a +# virtual MouseSystems mouse on /dev/gpmdata. This is useful for feeding +# gpm's data to X, especially if you've got a busmouse (in that situation X +# and gpm may not coexist without using a repeater). To try running a GPM +# repeater for X, change the gpm command line to look like this: +# $GPM -R msc -m /dev/mouse -t $MTYPE +# Then, make sure that the mouse configuration in your XF86Config file refers +# to the repeater device (/dev/gpmdata) and a MouseSystems mouse type. If you +# edit the file directly, you'll want the lines to look like this (minus the +# comment marks '#' shown here, of course): +#Section "Pointer" +# Protocol "MouseSystems" +# Device "/dev/gpmdata" + +EOF +chmod 755 $T_PX/etc/rc.d/rc.gpm-sample +# Now ask if this should be the new rc.gpm: + dialog --title "GPM CONFIGURATION" --yesno \ +"The gpm program allows you to cut and paste text on\n\ +the virtual consoles using a mouse. If you choose to\n\ +run it at boot time, this line will be added to your\n\ +/etc/rc.d/rc.gpm:\n\ +\n\ + $GPM -m /dev/mouse -t $MTYPE \n\ +\n\ +Shall we load the gpm program at boot time?" 12 58 + if [ $? = 0 ]; then + mv $T_PX/etc/rc.d/rc.gpm-sample $T_PX/etc/rc.d/rc.gpm + fi diff --git a/source/a/gpm/slack-desc b/source/a/gpm/slack-desc new file mode 100644 index 00000000..17774f10 --- /dev/null +++ b/source/a/gpm/slack-desc @@ -0,0 +1,19 @@ +# HOW TO EDIT THIS FILE: +# The "handy ruler" below makes it easier to edit a package description. Line +# up the first '|' above the ':' following the base package name, and the '|' +# on the right side marks the last column you can put a character in. You must +# make exactly 11 lines for the formatting to be correct. It's also +# customary to leave one space after the ':'. + + |-----handy-ruler------------------------------------------------------| +gpm: gpm (general purpose mouse server) +gpm: +gpm: The general purpose mouse server, or gpm, allows you to use the mouse +gpm: to cut and paste text from the screen. It also acts as a mouse +gpm: server for applications running on the Linux console, such as the +gpm: Midnight Commander file manager. +gpm: +gpm: NOTE: This program may cause problems when you start X on systems +gpm: that do not use a serial mouse. If you get an 'unable to open mouse +gpm: device' error from X, disable /etc/rc.d/rc.gpm. +gpm: |