You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
919 lines
31 KiB
919 lines
31 KiB
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 */
|
|
|