This is the Debian patch set for X2X (x2x_1.27-5.1.diff.gz)

Index: Imakefile
--- Imakefile.orig	1997-08-20 18:14:52 +0200
+++ Imakefile	2004-08-28 20:56:14 +0200
@@ -2,7 +2,7 @@
         DEPLIBS = $(DEPXTESTLIB) $(DEPEXTENSIONLIB) $(DEPXLIB)
 LOCAL_LIBRARIES = $(XTESTLIB) $(EXTENSIONLIB) $(XLIB)
 
-           SRCS = lawyerese.c x2x.c format.c
-           OBJS = lawyerese.o x2x.o format.o
+           SRCS = lawyerese.c x2x.c
+           OBJS = lawyerese.o x2x.o
   PROTO_DEFINES = 
 
--- format.c.orig	1997-08-20 18:14:52 +0200
+++ format.c	2004-08-28 20:56:14 +0200
@@ -199,7 +199,6 @@
 {
   int           fontheight, fontwidth;
   int           width, height;
-  int           len;
   int           format;
   unsigned      minchar, maxchar;
   unsigned char *buffer, thechar;
--- x2x.1.orig	1997-08-20 18:14:51 +0200
+++ x2x.1	2004-08-28 20:56:14 +0200
@@ -3,7 +3,7 @@
 .SH NAME
 x2x \- X to X connection
 .SH SYNTAX
-\f x2x\fR  <[-to <DISPLAY>] | [-from <DISPLAY>]> [options...]
+\fB x2x\fR  <[-to <DISPLAY>] | [-from <DISPLAY>]> [options...]
 .SH DESCRIPTION
 x2x allows the keyboard and mouse on one ("from") X display to be used to
 control another ("to") X display.  Since x2x uses the XTEST extension,
@@ -17,12 +17,12 @@
 a subsequent multiple button click on the "to" display returns control
 to the "from" display.
 
-If the -east or -west options are specified on the command line, x2x
-starts up with a different interface.  When the mouse moves to the
-(east or west) side of the default screen on the "from" display, the
-cursor slides over to the "to" display.  When the mouse returns to
-to side of the "to" display that it entered, it slides back onto
-the "from" display.
+If the -north, -south, -east or -west options are specified on the
+command line, x2x starts up with a different interface.  When the mouse
+moves to the top, bottom, east side or west side of the default screen
+on the "from" display, the cursor slides over to the "to" display.
+When the mouse returns to to side of the "to" display that it entered,
+it slides back onto the "from" display.
 
 Unless the -nosel option is specified, x2x relays X selections from
 one display to the other.
@@ -55,6 +55,14 @@
 Indicates the ("from") display that remotely controls the "to" display.
 Default is equivalent to the default display.
 .TP
+.B \-north
+.IP 
+Slide off the north side of the "to" display onto the "from" display.
+.TP
+.B \-south
+.IP 
+Slide off the south side of the "to" display onto the "from" display.
+.TP
 .B \-east
 .IP 
 Slide off the east side of the "to" display onto the "from" display.
@@ -70,7 +78,7 @@
 .B \-geometry \fIspecification\fP
 .IP 
 The X geometry specification for the x2x window.  
-(Overridden by -east or -west.)
+(Overridden by -north, -south, -east or -west.)
 .TP
 .B \-wait
 .IP 
@@ -85,14 +93,21 @@
 .TP
 .B \-buttonblock
 .IP 
-If this option is enabled with -east or -west, the cursor will not
-slide back onto the "from" display when one or more mouse buttons
-are pressed.
+If this option is enabled with -north, -south, -east or -west, the
+cursor will not slide back onto the "from" display when one or more
+mouse buttons are pressed.
+.TP
+.B \-buttonmap \fIbutton#\fP \fR"\fP\fIKeySym ...\fP\fR"\fP
+.IP 
+Map a mouse button to one or more keyboard events on the "to" display.
+This is useful if you have a mouse with more buttons than the remote X
+server can handle (e.g. a wheel mouse on a PC, merged with a Sun/Sparc
+OpenWindows display).
 .TP
 .B \-nomouse
 .IP 
 Don't capture the mouse.
-(Overridden by -east or -west.)
+(Overridden by -north, -south, -east or -west.)
 .TP
 .B \-nopointermap
 .IP 
@@ -119,11 +134,12 @@
 .TP
 .B \-resurface
 .IP 
-Ugly hack to work-around window manager ugliness.  The -east and -west
-modes actually put a small window on the side of the "from" display.
-This option causes this window to resurface itself if another window
-ever obscures it.  This option can cause really nasty behavior if another
-application tries to do the same thing.  Useful for login scripts.
+Ugly hack to work-around window manager ugliness.  The -north, -south,
+-east and -west modes actually put a small window on the side of the
+"from" display.  This option causes this window to resurface itself if
+another window ever obscures it.  This option can cause really nasty
+behavior if another application tries to do the same thing.  Useful for
+login scripts.
 .TP
 .B \-shadow \fIdisplay\fP
 .IP 
@@ -137,10 +153,17 @@
 sticky option prevents autoup for the specified key.  Look in
 /usr/include/X11/keysymdef.h for a list of valid names of keys
 (remove the leading XK_).
+.TP
+.B \-label \fIlabel\fP
+Override the title of the control window (useful when running over ssh).
+.IP 
 .SH AUTHOR
 David Chaiken
 .br
 (chaiken@pa.dec.com)
+.PP
+Addition of -north and -south options by Charles Briscoe-Smith
+<cpbs@debian.org>.
 .SH BUGS
 This software is experimental!  Heaven help you if your network
 connection should go down.  Caveat hacker.  TANSTAAFL.
--- x2x.c.orig	1997-08-20 18:14:52 +0200
+++ x2x.c	2004-08-28 20:58:23 +0200
@@ -1,7 +1,7 @@
 /*
- * x2x: Uses the XTEST extension to forward keystrokes from a window on
- *      one display to another display.  Useful for desks
- *      with multiple keyboards.
+ * x2x: Uses the XTEST extension to forward mouse movements and keystrokes
+ *      from a window on one display to another display.  Useful for
+ *      desks with multiple keyboards.
  *
  * Copyright (c) 1997
  * Digital Equipment Corporation.  All rights reserved.
@@ -37,26 +37,37 @@
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <X11/Xlib.h>
 #include <X11/Xresource.h>
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/Xatom.h> /* for selection */
+#include <X11/extensions/XTest.h>
 #include <sys/types.h> /* for select */
 #include <sys/time.h> /* for select */
-#include "format.h"
 
 /*#define DEBUG*/
 
+#ifndef MIN
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#endif
+#ifndef MAX
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#endif
+
 /**********
  * definitions for edge
  **********/
 #define EDGE_NONE   0 /* don't transfer between edges of screens */
-#define EDGE_EAST   1 /* from display is on the east side of to display */
-#define EDGE_WEST   2 /* from display is on the west side of to display */
+#define EDGE_NORTH  1 /* from display is on the north side of to display */
+#define EDGE_SOUTH  2 /* from display is on the south side of to display */
+#define EDGE_EAST   3 /* from display is on the east side of to display */
+#define EDGE_WEST   4 /* from display is on the west side of to display */
 
 /**********
  * functions
@@ -92,25 +103,6 @@
 static void    Usage();
 
 /**********
- * text formatting instructions
- **********/
-#define toDpyFormatLength (sizeof(toDpyFormat) / sizeof(Format))
-static Format toDpyFormat[] = {
-  FormatMeasureText,
-  FormatSetLeft,      0,
-  FormatSetTop,       0,
-  FormatAddHalfTextX, 1,
-  FormatAddHalfTextY, 3,
-  FormatString, (Format)"unknown",
-  FormatAddHalfTextX, 1,
-  FormatAddHalfTextY, 1
-  };
-/* indexes of values to be filled in at runtime */
-#define toDpyLeftIndex    2
-#define toDpyTopIndex     4
-#define toDpyStringIndex 10 
-
-/**********
  * stuff for selection forwarding
  **********/
 typedef struct _dpyxtra {
@@ -135,6 +127,8 @@
 
 #define N_BUTTONS   5
 
+#define MAX_BUTTONMAPEVENTS 20
+
 #define GETDPYXTRA(DPY,PDPYINFO)\
    (((DPY) == (PDPYINFO)->fromDpy) ?\
     &((PDPYINFO)->fromDpyXtra) : &((PDPYINFO)->toDpyXtra))
@@ -161,9 +155,10 @@
   GC      textGC;
   Atom    wmpAtom, wmdwAtom;
   Cursor  grabCursor;
-  XFS     *font;
-  int     twidth, theight;
-  int     lastFromX;
+  Font    fid;
+  int     width, height, twidth, theight, tascent;
+  Bool    vertical;
+  int     lastFromCoord;
   int     unreasonableDelta;
   
   /* stuff on "to" display */
@@ -180,8 +175,10 @@
   int     nScreens;
   short   **xTables; /* precalculated conversion tables */
   short   **yTables;
-  int     fromXConn, fromXDisc; /* location of cursor after conn/disc ops */
-  int     fromXIncr, fromXDecr; /* location of cursor after incr/decr ops */
+  int     fromConnCoord; /* location of cursor after conn/disc ops */
+  int     fromDiscCoord;
+  int     fromIncrCoord; /* location of cursor after incr/decr ops */
+  int     fromDecrCoord;
 
   /* selection forwarding info */
   DPYXTRA fromDpyXtra;
@@ -218,6 +215,7 @@
 static char    *toDpyName   = NULL;
 static char    *defaultFN   = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
 static char    *fontName    = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
+static char    *label       = NULL;
 static char    *pingStr     = "PING"; /* atom for ping request */
 static char    *geomStr     = NULL;
 static Bool    waitDpy      = False;
@@ -232,13 +230,13 @@
 static Bool    doPointerMap = True;
 static PSTICKY stickies     = NULL;
 static Bool    doBtnBlock   = False;
+static int     nButtons     = 0;
+static KeySym  buttonmap[N_BUTTONS + 1][MAX_BUTTONMAPEVENTS + 1];
 
 /**********
  * main
  **********/
-main(argc, argv)
-int  argc;
-char **argv;
+int main(int argc, char **argv)
 {
   Display *fromDpy;
   PSHADOW pShadow;
@@ -253,7 +251,7 @@
     exit(1);
   }
 
-  /* no OS independent wat to stop Xlib from complaining via stderr,
+  /* no OS independent way to stop Xlib from complaining via stderr,
      but can always pipe stdout/stderr to /dev/null */
   /* convert to real name: */
   while ((fromDpy = XOpenDisplay(fromDpyName)) == NULL) {
@@ -326,11 +324,18 @@
   extern  char *lawyerese;
   PSTICKY pNewSticky;
   KeySym  keysym;
+  int     button;
+  int     eventno;
+  char    *keyname, *argptr;
 
 #ifdef DEBUG
   printf ("programStr = %s\n", programStr);
 #endif  
 
+  /* Clear button map */
+  for (button = 0; button <= N_BUTTONS; button++)
+      buttonmap[button][0] = NoSymbol;
+
   for (arg = 1; arg < argc; ++arg) {
     if (!strcasecmp(argv[arg], "-from")) {
       if (++arg >= argc) Usage();
@@ -353,6 +358,13 @@
 #ifdef DEBUG
       printf ("fontName = %s\n", fontName);
 #endif
+    } else if (!strcasecmp(argv[arg], "-label")) {
+      if (++arg >= argc) Usage();
+      label = argv[arg];
+
+#ifdef DEBUG
+      printf ("label = %s\n", label);
+#endif
     } else if (!strcasecmp(argv[arg], "-geometry")) {
       if (++arg >= argc) Usage();
       geomStr = argv[arg];
@@ -384,6 +396,16 @@
 #ifdef DEBUG
       printf("will not do pointer mapping\n");
 #endif
+    } else if (!strcasecmp(argv[arg], "-north")) {
+      doEdge = EDGE_NORTH;
+#ifdef DEBUG
+      printf("\"from\" is on the north side of \"to\"\n");
+#endif
+    } else if (!strcasecmp(argv[arg], "-south")) {
+      doEdge = EDGE_SOUTH;
+#ifdef DEBUG
+      printf("\"from\" is on the south side of \"to\"\n");
+#endif
     } else if (!strcasecmp(argv[arg], "-east")) {
       doEdge = EDGE_EAST;
 #ifdef DEBUG
@@ -422,6 +444,34 @@
       } else {
 	printf("x2x: warning: can't translate %s\n", argv[arg]);
       }
+    } else if (!strcasecmp(argv[arg], "-buttonmap")) {
+	if (++arg >= argc) Usage();
+	button = atoi(argv[arg]);
+
+	if ((button < 1) || (button > N_BUTTONS))
+	    printf("x2x: warning: invalid button %d\n", button);
+	else if (++arg >= argc)
+	    Usage();
+	else
+	{
+#ifdef DEBUG
+	    printf("will map button %d to keysyms '%s'\n", button, argv[arg]);
+#endif
+	    argptr  = argv[arg];
+	    eventno = 0;
+	    while ((keyname = strtok(argptr, " \t\n\r")) != NULL)
+	    {
+		if ((keysym = XStringToKeysym(keyname)) == NoSymbol)
+		    printf("x2x: warning: can't translate %s\n", keyname);
+		else if (eventno + 1 >= MAX_BUTTONMAPEVENTS)
+		    printf("x2x: warning: too many keys mapped to button %d\n",
+			   button);
+		else
+		    buttonmap[button][eventno++] = keysym;
+		argptr = NULL;
+	    }
+	    buttonmap[button][eventno] = NoSymbol;
+	}
     } else if (!strcasecmp(argv[arg], "-resurface")) {
       doResurface = True;
 #ifdef DEBUG
@@ -458,6 +508,9 @@
   printf("       -big\n");
   printf("       -buttonblock\n");
   printf("       -nomouse\n");
+  printf("       -nopointermap\n");
+  printf("       -north\n");
+  printf("       -south\n");
   printf("       -east\n");
   printf("       -west\n");
   printf("       -nosel\n");
@@ -465,6 +518,8 @@
   printf("       -resurface\n");
   printf("       -shadow <DISPLAY>\n");
   printf("       -sticky <sticky key>\n");
+  printf("       -label <LABEL>\n");
+  printf("       -buttonmap <button#> \"<keysym> ...\"\n");
   exit(4);
 
 } /* END Usage */
@@ -510,7 +565,7 @@
   toConn   = XConnectionNumber(toDpy);
 
   while (True) { /* FOREVER */
-    if (fromPending = XPending(fromDpy))
+    if ((fromPending = XPending(fromDpy)))
       if (ProcessEvent(fromDpy, &dpyInfo)) /* done! */
 	break;
 
@@ -534,7 +589,7 @@
 PDPYINFO pDpyInfo;
 {
   Display   *fromDpy, *toDpy;
-  Screen    *fromScreen, *toScreen;
+  Screen    *fromScreen;
   long      black, white;
   int       fromHeight, fromWidth, toHeight, toWidth;
   Pixmap    nullPixmap;
@@ -544,7 +599,7 @@
   int       *heights, *widths;
   int       counter;
   int       nScreens, screenNum;
-  int       twidth, theight; /* text dimensions */
+  int       twidth, theight, tascent; /* text dimensions */
   int       xoff, yoff; /* window offsets */
   unsigned int width, height; /* window width, height */
   int       geomMask;		/* mask returned by parse */
@@ -556,9 +611,10 @@
   int       eventMask;
   GC        textGC;
   char      *windowName;  
-  XFS       *font;
+  Font      fid;
   PSHADOW   pShadow;
   int       triggerLoc;
+  Bool      vertical;
 
   /* cache commonly used variables */
   fromDpy = pDpyInfo->fromDpy;
@@ -574,10 +630,12 @@
   /* values also in dpyinfo */
   root       = pDpyInfo->root      = XDefaultRootWindow(fromDpy); 
   nScreens   = pDpyInfo->nScreens  = XScreenCount(toDpy);
+  vertical   = pDpyInfo->vertical  = (doEdge == EDGE_NORTH
+                                      || doEdge == EDGE_SOUTH);
 
   /* other dpyinfo values */
   pDpyInfo->mode        = X2X_DISCONNECTED;
-  pDpyInfo->unreasonableDelta = fromWidth / 2;
+  pDpyInfo->unreasonableDelta = (vertical ? fromHeight : fromWidth) / 2;
   pDpyInfo->pFakeThings = NULL;
 
   /* window init structures */
@@ -586,54 +644,76 @@
   eventMask = KeyPressMask | KeyReleaseMask;
 
   /* cursor locations for moving between screens */
-  pDpyInfo->fromXIncr = triggerw;
-  pDpyInfo->fromXDecr = fromWidth - triggerw - 1;
+  pDpyInfo->fromIncrCoord = triggerw;
+  pDpyInfo->fromDecrCoord = (vertical ? fromHeight : fromWidth) - triggerw - 1;
   if (doEdge) { /* edge triggers x2x */
     nullPixmap = XCreatePixmap(fromDpy, root, 1, 1, 1);
     eventMask |= EnterWindowMask;
     pDpyInfo->grabCursor = 
       XCreatePixmapCursor(fromDpy, nullPixmap, nullPixmap,
 			  &dummyColor, &dummyColor, 0, 0);
-    if (doEdge == EDGE_EAST) {
-      /* trigger window location */
+    /* trigger window location */
+    if (doEdge == EDGE_NORTH) {
+      triggerLoc = 0;
+      pDpyInfo->fromConnCoord = fromHeight - triggerw - 1;
+      pDpyInfo->fromDiscCoord = triggerw;
+    } else if (doEdge == EDGE_SOUTH) {
+      triggerLoc = fromHeight - triggerw;
+      pDpyInfo->fromConnCoord = 1;
+      pDpyInfo->fromDiscCoord = triggerLoc - 1;
+    } else if (doEdge == EDGE_EAST) {
       triggerLoc = fromWidth - triggerw;
-      toHeight = XHeightOfScreen(XScreenOfDisplay(toDpy, 0));
-      pDpyInfo->fromXConn = 1;
-      pDpyInfo->fromXDisc = fromWidth - triggerw - 1;
-    } else {
-      /* trigger window location */
+      pDpyInfo->fromConnCoord = 1;
+      pDpyInfo->fromDiscCoord = triggerLoc - 1;
+    } else /* doEdge == EDGE_WEST */ {
       triggerLoc = 0;
-      toHeight = XHeightOfScreen(XScreenOfDisplay(toDpy, nScreens - 1));
-      toWidth  = XWidthOfScreen(XScreenOfDisplay(toDpy, nScreens - 1));
-      pDpyInfo->fromXConn = fromWidth - triggerw - 1;
-      pDpyInfo->fromXDisc = triggerw;
+      pDpyInfo->fromConnCoord = fromWidth - triggerw - 1;
+      pDpyInfo->fromDiscCoord = triggerw;
     } /* END if doEdge == ... */
 
     xswa.background_pixel = black;
     /* fromWidth - 1 doesn't seem to work for some reason */
+    /* Use triggerw offsets so that if an x2x is running
+       along the left edge and along the north edge, both with
+       -resurface, we don't get a feedback loop of them each
+       fighting to be on top.
+        --09/27/99 Greg J. Badros <gjb@cs.washington.edu> */
+    /* also, make it an InputOnly window so I don't lose 
+       screen real estate --09/29/99 gjb */
     trigger = pDpyInfo->trigger = 
-      XCreateWindow(fromDpy, root, triggerLoc, 0, triggerw, fromHeight,
-		    0, 0, InputOutput, 0, 
-		    CWBackPixel | CWOverrideRedirect, &xswa);
-    font = NULL;
+      XCreateWindow(fromDpy, root,
+		    vertical ? triggerw : triggerLoc,
+		    vertical ? triggerLoc : triggerw,
+		    vertical ? fromWidth - (2*triggerw) : triggerw,
+		    vertical ? triggerw : fromHeight - (2*triggerw),
+		    0, 0, InputOnly, 0, 
+		    CWOverrideRedirect, &xswa);
+    fid = 0;
 
   } else { /* normal window for text: do size grovelling */
     pDpyInfo->grabCursor = XCreateFontCursor(fromDpy, XC_exchange);
     eventMask |= StructureNotifyMask | ExposureMask;
     if (doMouse) eventMask |= ButtonPressMask | ButtonReleaseMask;
 
+    if (label == NULL)
+      label = toDpyName;
     /* determine size of text */
-    if (((font = XLoadQueryFont(fromDpy, fontName)) != NULL) ||
-	((font = XLoadQueryFont(fromDpy, defaultFN)) != NULL) ||
-	((font = XLoadQueryFont(fromDpy, "fixed")) != NULL)) { 
+    if (((fid = XLoadFont(fromDpy, fontName)) != 0) ||
+      ((fid = XLoadFont(fromDpy, defaultFN)) != 0) ||
+      ((fid = XLoadFont(fromDpy, "fixed")) != 0)) {
       /* have a font */
-      toDpyFormat[toDpyStringIndex] = (Format)toDpyName;
-      formatText(NULL, NULL, NULL, font, 
-		 toDpyFormatLength, toDpyFormat, &twidth, &theight);
+      int ascent, descent, direction;
+      XCharStruct overall;
+
+      XQueryTextExtents(fromDpy, fid, label, strlen(label),
+			&direction, &ascent, &descent, &overall);
+      twidth =  - overall.lbearing + overall.rbearing;
+      theight = ascent + descent;
+      tascent = ascent;
 
       textGC = pDpyInfo->textGC = XCreateGC(fromDpy, root, 0, NULL);
       XSetState(fromDpy, textGC, black, white, GXcopy, AllPlanes);
-      XSetFont(fromDpy, textGC, font->fid);
+      XSetFont(fromDpy, textGC, fid);
 
     } else { /* should not have to execute this clause: */
       twidth = theight = 100; /* default window size */
@@ -641,8 +721,8 @@
 
     /* determine size of window */
     xoff = yoff = 0;
-    width = twidth;
-    height = theight;
+    width = twidth + 4; /* XXX gap around text -- should be configurable */
+    height = theight + 4;
     geomMask = XParseGeometry(geomStr, &xoff, &yoff, &width, &height);
     switch (gravMask = (geomMask & (XNegative | YNegative))) {
     case (XNegative | YNegative): gravity = SouthEastGravity; break;
@@ -711,7 +791,8 @@
   free(windowName);
 
   /* conversion stuff */
-  pDpyInfo->toScreen = (doEdge == EDGE_WEST) ? (nScreens - 1) : 0;
+  pDpyInfo->toScreen = (doEdge == EDGE_WEST || doEdge == EDGE_NORTH)
+			? (nScreens - 1) : 0;
 
   /* construct table lookup for screen coordinate conversion */
   pDpyInfo->xTables = (short **)malloc(sizeof(short *) * nScreens);
@@ -739,13 +820,25 @@
       xTable[counter] = (counter * toWidth) / fromWidth;
 
     /* adjustment for boundaries */
-    if ((screenNum != 0) || (doEdge == EDGE_EAST))
-      xTable[0] = COORD_DECR;
-    if (((screenNum + 1) < nScreens) || (doEdge == EDGE_WEST)) {
-      xTable[fromWidth - 1] = COORD_INCR;
-      /* work-around for bug: on at least one tested screen, cursor
-	 never moved past fromWidth - 2 */
-      xTable[fromWidth - 2] = COORD_INCR;
+    if (vertical) {
+      if ((screenNum != 0) || (doEdge == EDGE_SOUTH))
+        yTable[0] = COORD_DECR;
+      if (((screenNum + 1) < nScreens) || (doEdge == EDGE_NORTH)) {
+        yTable[fromHeight - 1] = COORD_INCR;
+	/* work-around for bug: on at least one tested screen, cursor
+	   never moved past fromWidth - 2  (I'll assume this might apply
+	   in the vertical case, too. --cpbs) */
+        yTable[fromHeight - 2] = COORD_INCR;
+      }
+    } else {
+      if ((screenNum != 0) || (doEdge == EDGE_EAST))
+        xTable[0] = COORD_DECR;
+      if (((screenNum + 1) < nScreens) || (doEdge == EDGE_WEST)) {
+        xTable[fromWidth - 1] = COORD_INCR;
+        /* work-around for bug: on at least one tested screen, cursor
+	   never moved past fromWidth - 2 */
+        xTable[fromWidth - 2] = COORD_INCR;
+      }
     }
 
   } /* END for screenNum */
@@ -787,15 +880,18 @@
   pDpyInfo->eventMask = eventMask; /* save for future munging */
   if (doSel) XSetSelectionOwner(fromDpy, XA_PRIMARY, trigger, CurrentTime);
   XMapRaised(fromDpy, trigger);
-  if (pDpyInfo->font = font) { /* paint text */
+  if (pDpyInfo->fid = fid) { /* paint text */
     /* position text */
     pDpyInfo->twidth = twidth;
     pDpyInfo->theight = theight;
-    toDpyFormat[toDpyLeftIndex] = MAX(0,((width - twidth) / 2));
-    toDpyFormat[toDpyTopIndex]  = MAX(0,((height - theight) / 2));
-
-    formatText(fromDpy, trigger, &(textGC), font, 
-	       toDpyFormatLength, toDpyFormat, NULL, NULL);
+    pDpyInfo->tascent = tascent;
+    pDpyInfo->width = width;
+    pDpyInfo->height = height;
+
+    XDrawImageString(fromDpy, trigger, textGC,
+		     MAX(0,((width - twidth) / 2)),
+		     MAX(0,((height - theight) / 2)) + tascent, label,
+		     strlen(label));
   } /* END if font */
 
   for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
@@ -937,33 +1033,36 @@
 
   int       toScreenNum;
   PSHADOW   pShadow;
-  int       toX, fromX, delta;
+  int       toCoord, fromCoord, delta;
   Display   *fromDpy;
   Bool      bAbortedDisconnect;
+  Bool      vert;
+
+  vert = pDpyInfo->vertical;
 
   /* find the screen */
   toScreenNum = pDpyInfo->toScreen;
-  fromX = pEv->x_root;
+  fromCoord = vert ? pEv->y_root : pEv->x_root;
 
   /* check to make sure the cursor is still on the from screen */
   if (!(pEv->same_screen)) {
-    toX = (pDpyInfo->lastFromX < fromX) ? COORD_DECR : COORD_INCR;
+    toCoord = (pDpyInfo->lastFromCoord < fromCoord) ? COORD_DECR : COORD_INCR;
   } else {
-    toX = pDpyInfo->xTables[toScreenNum][fromX];
+    toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][fromCoord];
 
     /* sanity check motion: necessary for nondeterminism surrounding warps */
-    delta = pDpyInfo->lastFromX - fromX;
+    delta = pDpyInfo->lastFromCoord - fromCoord;
     if (delta < 0) delta = -delta;
     if (delta > pDpyInfo->unreasonableDelta) return False;
   }
 
-  if (SPECIAL_COORD(toX) != 0) { /* special coordinate */
+  if (SPECIAL_COORD(toCoord) != 0) { /* special coordinate */
     bAbortedDisconnect = False;
-    if (toX == COORD_INCR) {
+    if (toCoord == COORD_INCR) {
       if (toScreenNum != (pDpyInfo->nScreens - 1)) { /* next screen */
 	toScreenNum = ++(pDpyInfo->toScreen);
-	fromX = pDpyInfo->fromXIncr;
-	toX = pDpyInfo->xTables[toScreenNum][fromX];
+	fromCoord = pDpyInfo->fromIncrCoord;
+	toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][fromCoord];
       } else { /* disconnect! */
 	if (doBtnBlock &&
 	    (pEv->state & (Button1Mask | Button2Mask | Button3Mask |
@@ -971,15 +1070,15 @@
 	  bAbortedDisconnect = True;
 	else {
 	  DoDisconnect(pDpyInfo);
-	  fromX = pDpyInfo->fromXDisc;
+	  fromCoord = pDpyInfo->fromDiscCoord;
 	}
-	toX = pDpyInfo->xTables[toScreenNum][pDpyInfo->fromXConn];
+	toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][pDpyInfo->fromConnCoord];
       }
     } else { /* DECR */
       if (toScreenNum != 0) { /* previous screen */
 	toScreenNum = --(pDpyInfo->toScreen);
-	fromX = pDpyInfo->fromXDecr;
-	toX = pDpyInfo->xTables[toScreenNum][fromX];
+	fromCoord = pDpyInfo->fromDecrCoord;
+	toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][fromCoord];
       } else { /* disconnect! */
 	if (doBtnBlock &&
 	    (pEv->state & (Button1Mask | Button2Mask | Button3Mask |
@@ -987,23 +1086,26 @@
 	  bAbortedDisconnect = True;
 	else {
 	  DoDisconnect(pDpyInfo);
-	  fromX = pDpyInfo->fromXDisc;
+	  fromCoord = pDpyInfo->fromDiscCoord;
 	}
-	toX = pDpyInfo->xTables[toScreenNum][pDpyInfo->fromXConn];
+	toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][pDpyInfo->fromConnCoord];
       }
-    } /* END if toX */
+    } /* END if toCoord */
     if (!bAbortedDisconnect) {
       fromDpy = pDpyInfo->fromDpy;
       XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0, 
-		   fromX, pEv->y_root);
+		   vert ? pEv->x_root : fromCoord,
+		   vert ? fromCoord : pEv->y_root);
       XFlush(fromDpy);
     }
   } /* END if SPECIAL_COORD */
-  pDpyInfo->lastFromX = fromX;
+  pDpyInfo->lastFromCoord = fromCoord;
 
   for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
-    XTestFakeMotionEvent(pShadow->dpy, toScreenNum, toX,
-			 pDpyInfo->yTables[toScreenNum][pEv->y_root], 0);
+    XTestFakeMotionEvent(pShadow->dpy, toScreenNum,
+		      vert?pDpyInfo->xTables[toScreenNum][pEv->x_root]:toCoord,
+		      vert?toCoord:pDpyInfo->yTables[toScreenNum][pEv->y_root],
+		      0);
     XFlush(pShadow->dpy);
   } /* END for */
     
@@ -1017,10 +1119,12 @@
 XExposeEvent *pEv;
 {
   XClearWindow(pDpyInfo->fromDpy, pDpyInfo->trigger);
-  if (pDpyInfo->font)
-    formatText(pDpyInfo->fromDpy, pDpyInfo->trigger, 
-	       &(pDpyInfo->textGC), pDpyInfo->font, 
-	       toDpyFormatLength, toDpyFormat, NULL, NULL);
+  if (pDpyInfo->fid)
+    XDrawImageString(pDpyInfo->fromDpy, pDpyInfo->trigger, pDpyInfo->textGC,
+		     MAX(0,((pDpyInfo->width - pDpyInfo->twidth) / 2)),
+		     MAX(0,((pDpyInfo->height - pDpyInfo->theight) / 2)) +
+		     pDpyInfo->tascent, label, strlen(label));
+
   return False;
   
 } /* END ProcessExpose */
@@ -1036,10 +1140,17 @@
   if ((pEv->mode == NotifyNormal) &&
       (pDpyInfo->mode == X2X_DISCONNECTED) && (dpy == pDpyInfo->fromDpy)) {
     DoConnect(pDpyInfo);
-    XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0, 
-		 pDpyInfo->fromXConn, pEv->y_root);
-    xmev.x_root = pDpyInfo->lastFromX = pDpyInfo->fromXConn;
-    xmev.y_root = pEv->y_root;
+    if (pDpyInfo->vertical) {
+      XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0, 
+		   pEv->x_root, pDpyInfo->fromConnCoord);
+      xmev.x_root = pEv->x_root;
+      xmev.y_root = pDpyInfo->lastFromCoord = pDpyInfo->fromConnCoord;
+    } else {
+      XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0, 
+		   pDpyInfo->fromConnCoord, pEv->y_root);
+      xmev.x_root = pDpyInfo->lastFromCoord = pDpyInfo->fromConnCoord;
+      xmev.y_root = pEv->y_root;
+    }
     xmev.same_screen = True;
     ProcessMotionNotify(NULL, pDpyInfo, &xmev);
   }  /* END if NotifyNormal... */
@@ -1055,7 +1166,10 @@
   int state;
   PSHADOW   pShadow;
   unsigned int toButton;
-
+  KeySym  keysym;
+  KeyCode keycode;
+  int     eventno;
+   
   switch (pDpyInfo->mode) {
   case X2X_DISCONNECTED:
     pDpyInfo->mode = X2X_AWAIT_RELEASE;
@@ -1064,17 +1178,48 @@
 #endif
     break;
   case X2X_CONNECTED:
-    if (pEv->button <= N_BUTTONS) toButton = pDpyInfo->inverseMap[pEv->button];
-    for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
-      XTestFakeButtonEvent(pShadow->dpy, toButton, True, 0);
-#ifdef DEBUG
-      printf("from button %d down, to button %d down\n", pEv->button,toButton);
-#endif
-      XFlush(pShadow->dpy);
-    } /* END for */
-    if (doAutoUp)
-      FakeAction(pDpyInfo, FAKE_BUTTON, toButton, True);
-    if (doEdge) break;
+	if ((pEv->button <= N_BUTTONS) &&
+	    (buttonmap[pEv->button][0] != NoSymbol))
+	{
+	    for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
+	    {
+#ifdef DEBUG
+		printf("Button %d is mapped, sending keys: ", pEv->button);
+#endif
+		for (eventno = 0;
+		     (keysym = buttonmap[pEv->button][eventno]) != NoSymbol;
+		     eventno++)
+		{
+		    if (keycode = XKeysymToKeycode(pShadow->dpy, keysym)) {
+			XTestFakeKeyEvent(pShadow->dpy, keycode, True, 0);
+			XTestFakeKeyEvent(pShadow->dpy, keycode, False, 0);
+			XFlush(pShadow->dpy);
+#ifdef DEBUG
+			printf(" (0x%04X)", keycode);
+#endif
+		    }
+#ifdef DEBUG
+		    else
+			printf(" (no code)");
+#endif
+		}
+#ifdef DEBUG
+		printf("\n");
+#endif
+	    }
+	} else if (pEv->button <= nButtons) {
+	    toButton = pDpyInfo->inverseMap[pEv->button];
+	    for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+		XTestFakeButtonEvent(pShadow->dpy, toButton, True, 0);
+#ifdef DEBUG
+		printf("from button %d down, to button %d down\n", pEv->button,toButton);
+#endif
+		XFlush(pShadow->dpy);
+	    } /* END for */
+	    if (doAutoUp)
+		FakeAction(pDpyInfo, FAKE_BUTTON, toButton, True);
+	}
+     if (doEdge) break;
 
     /* check if more than one button pressed */
     state = pEv->state;
@@ -1113,16 +1258,21 @@
 
   if ((pDpyInfo->mode == X2X_CONNECTED) || 
       (pDpyInfo->mode == X2X_CONN_RELEASE)) {
-    if (pEv->button <= N_BUTTONS) toButton = pDpyInfo->inverseMap[pEv->button];
-    for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
-      XTestFakeButtonEvent(pShadow->dpy, toButton, False, 0);
-#ifdef DEBUG
-      printf("from button %d up, to button %d up\n", pEv->button, toButton);
-#endif
-      XFlush(pShadow->dpy);
-    } /* END for */
-    if (doAutoUp)
-      FakeAction(pDpyInfo, FAKE_BUTTON, toButton, False);
+	if ((pEv->button <= nButtons) &&
+	    (buttonmap[pEv->button][0] == NoSymbol))
+	    // Do not process button release if it was mapped to keys
+	{
+	    toButton = pDpyInfo->inverseMap[pEv->button];
+	    for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+		XTestFakeButtonEvent(pShadow->dpy, toButton, False, 0);
+#ifdef DEBUG
+		printf("from button %d up, to button %d up\n", pEv->button, toButton);
+#endif
+		XFlush(pShadow->dpy);
+	    } /* END for */
+	    if (doAutoUp)
+		FakeAction(pDpyInfo, FAKE_BUTTON, toButton, False);
+	}  
   } /* END if */
 
   if (doEdge) return False;
@@ -1145,8 +1295,13 @@
     if (!state) { /* all buttons up: time to (dis)connect */
       if (pDpyInfo->mode == X2X_AWAIT_RELEASE) { /* connect */
 	DoConnect(pDpyInfo);
-	xmev.x_root = pDpyInfo->lastFromX = pEv->x_root;
-	xmev.y_root = pEv->y_root;
+	if (pDpyInfo->vertical) {
+	  xmev.x_root = pEv->x_root;
+	  xmev.y_root = pDpyInfo->lastFromCoord = pEv->y_root;
+	} else {
+	  xmev.x_root = pDpyInfo->lastFromCoord = pEv->x_root;
+	  xmev.y_root = pEv->y_root;
+	}
 	xmev.same_screen = True;
 	ProcessMotionNotify(NULL, pDpyInfo, &xmev);
       } else { /* disconnect */
@@ -1204,12 +1359,10 @@
 PDPYINFO pDpyInfo;
 XConfigureEvent *pEv;
 {
-  if (pDpyInfo->font) {
+  if (pDpyInfo->fid) {
     /* reposition text */
-    toDpyFormat[toDpyLeftIndex] = 
-      MAX(0,((pEv->width - pDpyInfo->twidth) / 2));
-    toDpyFormat[toDpyTopIndex]  = 
-      MAX(0,((pEv->height - pDpyInfo->theight) / 2));
+    pDpyInfo->width = pEv->width;
+    pDpyInfo->height = pEv->height;
   } /* END if font */
   return False;
 
@@ -1276,7 +1429,6 @@
 PDPYINFO pDpyInfo;
 XPropertyEvent *pEv;
 {
-  XSelectionRequestEvent *pSelReq;
   PDPYXTRA pDpyXtra = GETDPYXTRA(dpy, pDpyInfo);
 
 #ifdef DEBUG
@@ -1535,7 +1687,6 @@
 {
   unsigned int buttCtr;
   unsigned char buttonMap[N_BUTTONS];
-  int nButtons;
 
   if (dpy == pDpyInfo->toDpy) { /* only care about toDpy */
     /* straightforward mapping */
