37
37
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
38
38
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
* Modified on 3 Oct 1998 by Charles Briscoe-Smith:
43
* added options -north and -south
41
47
#include <stdlib.h>
42
48
#include <string.h>
43
50
#include <X11/Xlib.h>
44
51
#include <X11/Xresource.h>
45
52
#include <X11/Xutil.h>
46
53
#include <X11/cursorfont.h>
47
54
#include <X11/Xatom.h> /* for selection */
55
#include <X11/extensions/XTest.h>
48
56
#include <sys/types.h> /* for select */
49
57
#include <sys/time.h> /* for select */
62
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
65
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
55
69
* definitions for edge
57
71
#define EDGE_NONE 0 /* don't transfer between edges of screens */
58
#define EDGE_EAST 1 /* from display is on the east side of to display */
59
#define EDGE_WEST 2 /* from display is on the west side of to display */
72
#define EDGE_NORTH 1 /* from display is on the north side of to display */
73
#define EDGE_SOUTH 2 /* from display is on the south side of to display */
74
#define EDGE_EAST 3 /* from display is on the east side of to display */
75
#define EDGE_WEST 4 /* from display is on the west side of to display */
423
450
printf("x2x: warning: can't translate %s\n", argv[arg]);
452
} else if (!strcasecmp(argv[arg], "-buttonmap")) {
453
if (++arg >= argc) Usage();
454
button = atoi(argv[arg]);
456
if ((button < 1) || (button > N_BUTTONS))
457
printf("x2x: warning: invalid button %d\n", button);
458
else if (++arg >= argc)
463
printf("will map button %d to keysyms '%s'\n", button, argv[arg]);
467
while ((keyname = strtok(argptr, " \t\n\r")) != NULL)
469
if ((keysym = XStringToKeysym(keyname)) == NoSymbol)
470
printf("x2x: warning: can't translate %s\n", keyname);
471
else if (eventno + 1 >= MAX_BUTTONMAPEVENTS)
472
printf("x2x: warning: too many keys mapped to button %d\n",
475
buttonmap[button][eventno++] = keysym;
478
buttonmap[button][eventno] = NoSymbol;
425
480
} else if (!strcasecmp(argv[arg], "-resurface")) {
426
481
doResurface = True;
586
649
eventMask = KeyPressMask | KeyReleaseMask;
588
651
/* cursor locations for moving between screens */
589
pDpyInfo->fromXIncr = triggerw;
590
pDpyInfo->fromXDecr = fromWidth - triggerw - 1;
652
pDpyInfo->fromIncrCoord = triggerw;
653
pDpyInfo->fromDecrCoord = (vertical ? fromHeight : fromWidth) - triggerw - 1;
591
654
if (doEdge) { /* edge triggers x2x */
592
655
nullPixmap = XCreatePixmap(fromDpy, root, 1, 1, 1);
593
656
eventMask |= EnterWindowMask;
594
657
pDpyInfo->grabCursor =
595
658
XCreatePixmapCursor(fromDpy, nullPixmap, nullPixmap,
596
659
&dummyColor, &dummyColor, 0, 0);
597
if (doEdge == EDGE_EAST) {
598
/* trigger window location */
660
/* trigger window location */
661
if (doEdge == EDGE_NORTH) {
663
pDpyInfo->fromConnCoord = fromHeight - triggerw - 1;
664
pDpyInfo->fromDiscCoord = triggerw;
665
} else if (doEdge == EDGE_SOUTH) {
666
triggerLoc = fromHeight - triggerw;
667
pDpyInfo->fromConnCoord = 1;
668
pDpyInfo->fromDiscCoord = triggerLoc - 1;
669
} else if (doEdge == EDGE_EAST) {
599
670
triggerLoc = fromWidth - triggerw;
600
toHeight = XHeightOfScreen(XScreenOfDisplay(toDpy, 0));
601
pDpyInfo->fromXConn = 1;
602
pDpyInfo->fromXDisc = fromWidth - triggerw - 1;
604
/* trigger window location */
671
pDpyInfo->fromConnCoord = 1;
672
pDpyInfo->fromDiscCoord = triggerLoc - 1;
673
} else /* doEdge == EDGE_WEST */ {
606
toHeight = XHeightOfScreen(XScreenOfDisplay(toDpy, nScreens - 1));
607
toWidth = XWidthOfScreen(XScreenOfDisplay(toDpy, nScreens - 1));
608
pDpyInfo->fromXConn = fromWidth - triggerw - 1;
609
pDpyInfo->fromXDisc = triggerw;
675
pDpyInfo->fromConnCoord = fromWidth - triggerw - 1;
676
pDpyInfo->fromDiscCoord = triggerw;
610
677
} /* END if doEdge == ... */
612
679
xswa.background_pixel = black;
613
680
/* fromWidth - 1 doesn't seem to work for some reason */
681
/* Use triggerw offsets so that if an x2x is running
682
along the left edge and along the north edge, both with
683
-resurface, we don't get a feedback loop of them each
684
fighting to be on top.
685
--09/27/99 Greg J. Badros <gjb@cs.washington.edu> */
686
/* also, make it an InputOnly window so I don't lose
687
screen real estate --09/29/99 gjb */
614
688
trigger = pDpyInfo->trigger =
615
XCreateWindow(fromDpy, root, triggerLoc, 0, triggerw, fromHeight,
616
0, 0, InputOutput, 0,
617
CWBackPixel | CWOverrideRedirect, &xswa);
689
XCreateWindow(fromDpy, root,
690
vertical ? triggerw : triggerLoc,
691
vertical ? triggerLoc : triggerw,
692
vertical ? fromWidth - (2*triggerw) : triggerw,
693
vertical ? triggerw : fromHeight - (2*triggerw),
695
CWOverrideRedirect, &xswa);
620
698
} else { /* normal window for text: do size grovelling */
621
699
pDpyInfo->grabCursor = XCreateFontCursor(fromDpy, XC_exchange);
622
700
eventMask |= StructureNotifyMask | ExposureMask;
623
701
if (doMouse) eventMask |= ButtonPressMask | ButtonReleaseMask;
625
705
/* determine size of text */
626
if (((font = XLoadQueryFont(fromDpy, fontName)) != NULL) ||
627
((font = XLoadQueryFont(fromDpy, defaultFN)) != NULL) ||
628
((font = XLoadQueryFont(fromDpy, "fixed")) != NULL)) {
706
if (((fid = XLoadFont(fromDpy, fontName)) != 0) ||
707
((fid = XLoadFont(fromDpy, defaultFN)) != 0) ||
708
((fid = XLoadFont(fromDpy, "fixed")) != 0)) {
629
709
/* have a font */
630
toDpyFormat[toDpyStringIndex] = (Format)toDpyName;
631
formatText(NULL, NULL, NULL, font,
632
toDpyFormatLength, toDpyFormat, &twidth, &theight);
710
int ascent, descent, direction;
713
XQueryTextExtents(fromDpy, fid, label, strlen(label),
714
&direction, &ascent, &descent, &overall);
715
twidth = - overall.lbearing + overall.rbearing;
716
theight = ascent + descent;
634
719
textGC = pDpyInfo->textGC = XCreateGC(fromDpy, root, 0, NULL);
635
720
XSetState(fromDpy, textGC, black, white, GXcopy, AllPlanes);
636
XSetFont(fromDpy, textGC, font->fid);
721
XSetFont(fromDpy, textGC, fid);
638
723
} else { /* should not have to execute this clause: */
639
724
twidth = theight = 100; /* default window size */
739
825
xTable[counter] = (counter * toWidth) / fromWidth;
741
827
/* adjustment for boundaries */
742
if ((screenNum != 0) || (doEdge == EDGE_EAST))
743
xTable[0] = COORD_DECR;
744
if (((screenNum + 1) < nScreens) || (doEdge == EDGE_WEST)) {
745
xTable[fromWidth - 1] = COORD_INCR;
746
/* work-around for bug: on at least one tested screen, cursor
747
never moved past fromWidth - 2 */
748
xTable[fromWidth - 2] = COORD_INCR;
829
if ((screenNum != 0) || (doEdge == EDGE_SOUTH))
830
yTable[0] = COORD_DECR;
831
if (((screenNum + 1) < nScreens) || (doEdge == EDGE_NORTH)) {
832
yTable[fromHeight - 1] = COORD_INCR;
833
/* work-around for bug: on at least one tested screen, cursor
834
never moved past fromWidth - 2 (I'll assume this might apply
835
in the vertical case, too. --cpbs) */
836
yTable[fromHeight - 2] = COORD_INCR;
839
if ((screenNum != 0) || (doEdge == EDGE_EAST))
840
xTable[0] = COORD_DECR;
841
if (((screenNum + 1) < nScreens) || (doEdge == EDGE_WEST)) {
842
xTable[fromWidth - 1] = COORD_INCR;
843
/* work-around for bug: on at least one tested screen, cursor
844
never moved past fromWidth - 2 */
845
xTable[fromWidth - 2] = COORD_INCR;
751
849
} /* END for screenNum */
787
885
pDpyInfo->eventMask = eventMask; /* save for future munging */
788
886
if (doSel) XSetSelectionOwner(fromDpy, XA_PRIMARY, trigger, CurrentTime);
789
887
XMapRaised(fromDpy, trigger);
790
if (pDpyInfo->font = font) { /* paint text */
888
if (pDpyInfo->fid = fid) { /* paint text */
791
889
/* position text */
792
890
pDpyInfo->twidth = twidth;
793
891
pDpyInfo->theight = theight;
794
toDpyFormat[toDpyLeftIndex] = MAX(0,((width - twidth) / 2));
795
toDpyFormat[toDpyTopIndex] = MAX(0,((height - theight) / 2));
892
pDpyInfo->tascent = tascent;
893
pDpyInfo->width = width;
894
pDpyInfo->height = height;
797
formatText(fromDpy, trigger, &(textGC), font,
798
toDpyFormatLength, toDpyFormat, NULL, NULL);
896
XDrawImageString(fromDpy, trigger, textGC,
897
MAX(0,((width - twidth) / 2)),
898
MAX(0,((height - theight) / 2)) + tascent, label,
799
900
} /* END if font */
801
902
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
938
1039
int toScreenNum;
939
1040
PSHADOW pShadow;
940
int toX, fromX, delta;
1041
int toCoord, fromCoord, delta;
941
1042
Display *fromDpy;
942
1043
Bool bAbortedDisconnect;
1046
vert = pDpyInfo->vertical;
944
1048
/* find the screen */
945
1049
toScreenNum = pDpyInfo->toScreen;
1050
fromCoord = vert ? pEv->y_root : pEv->x_root;
948
1052
/* check to make sure the cursor is still on the from screen */
949
1053
if (!(pEv->same_screen)) {
950
toX = (pDpyInfo->lastFromX < fromX) ? COORD_DECR : COORD_INCR;
1054
toCoord = (pDpyInfo->lastFromCoord < fromCoord) ? COORD_DECR : COORD_INCR;
952
toX = pDpyInfo->xTables[toScreenNum][fromX];
1056
toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][fromCoord];
954
1058
/* sanity check motion: necessary for nondeterminism surrounding warps */
955
delta = pDpyInfo->lastFromX - fromX;
1059
delta = pDpyInfo->lastFromCoord - fromCoord;
956
1060
if (delta < 0) delta = -delta;
957
1061
if (delta > pDpyInfo->unreasonableDelta) return False;
960
if (SPECIAL_COORD(toX) != 0) { /* special coordinate */
1064
if (SPECIAL_COORD(toCoord) != 0) { /* special coordinate */
961
1065
bAbortedDisconnect = False;
962
if (toX == COORD_INCR) {
1066
if (toCoord == COORD_INCR) {
963
1067
if (toScreenNum != (pDpyInfo->nScreens - 1)) { /* next screen */
964
1068
toScreenNum = ++(pDpyInfo->toScreen);
965
fromX = pDpyInfo->fromXIncr;
966
toX = pDpyInfo->xTables[toScreenNum][fromX];
1069
fromCoord = pDpyInfo->fromIncrCoord;
1070
toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][fromCoord];
967
1071
} else { /* disconnect! */
968
1072
if (doBtnBlock &&
969
1073
(pEv->state & (Button1Mask | Button2Mask | Button3Mask |
987
1091
bAbortedDisconnect = True;
989
1093
DoDisconnect(pDpyInfo);
990
fromX = pDpyInfo->fromXDisc;
1094
fromCoord = pDpyInfo->fromDiscCoord;
992
toX = pDpyInfo->xTables[toScreenNum][pDpyInfo->fromXConn];
1096
toCoord = (vert?pDpyInfo->yTables:pDpyInfo->xTables)[toScreenNum][pDpyInfo->fromConnCoord];
1098
} /* END if toCoord */
995
1099
if (!bAbortedDisconnect) {
996
1100
fromDpy = pDpyInfo->fromDpy;
997
1101
XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
1102
vert ? pEv->x_root : fromCoord,
1103
vert ? fromCoord : pEv->y_root);
999
1104
XFlush(fromDpy);
1001
1106
} /* END if SPECIAL_COORD */
1002
pDpyInfo->lastFromX = fromX;
1107
pDpyInfo->lastFromCoord = fromCoord;
1004
1109
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
1005
XTestFakeMotionEvent(pShadow->dpy, toScreenNum, toX,
1006
pDpyInfo->yTables[toScreenNum][pEv->y_root], 0);
1110
XTestFakeMotionEvent(pShadow->dpy, toScreenNum,
1111
vert?pDpyInfo->xTables[toScreenNum][pEv->x_root]:toCoord,
1112
vert?toCoord:pDpyInfo->yTables[toScreenNum][pEv->y_root],
1007
1114
XFlush(pShadow->dpy);
1008
1115
} /* END for */
1036
1145
if ((pEv->mode == NotifyNormal) &&
1037
1146
(pDpyInfo->mode == X2X_DISCONNECTED) && (dpy == pDpyInfo->fromDpy)) {
1038
1147
DoConnect(pDpyInfo);
1039
XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
1040
pDpyInfo->fromXConn, pEv->y_root);
1041
xmev.x_root = pDpyInfo->lastFromX = pDpyInfo->fromXConn;
1042
xmev.y_root = pEv->y_root;
1148
if (pDpyInfo->vertical) {
1149
XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
1150
pEv->x_root, pDpyInfo->fromConnCoord);
1151
xmev.x_root = pEv->x_root;
1152
xmev.y_root = pDpyInfo->lastFromCoord = pDpyInfo->fromConnCoord;
1154
XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
1155
pDpyInfo->fromConnCoord, pEv->y_root);
1156
xmev.x_root = pDpyInfo->lastFromCoord = pDpyInfo->fromConnCoord;
1157
xmev.y_root = pEv->y_root;
1043
1159
xmev.same_screen = True;
1044
1160
ProcessMotionNotify(NULL, pDpyInfo, &xmev);
1045
1161
} /* END if NotifyNormal... */
1066
1185
case X2X_CONNECTED:
1067
if (pEv->button <= N_BUTTONS) toButton = pDpyInfo->inverseMap[pEv->button];
1068
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
1069
XTestFakeButtonEvent(pShadow->dpy, toButton, True, 0);
1071
printf("from button %d down, to button %d down\n", pEv->button,toButton);
1073
XFlush(pShadow->dpy);
1076
FakeAction(pDpyInfo, FAKE_BUTTON, toButton, True);
1186
if ((pEv->button <= N_BUTTONS) &&
1187
(buttonmap[pEv->button][0] != NoSymbol))
1189
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
1192
printf("Button %d is mapped, sending keys: ", pEv->button);
1195
(keysym = buttonmap[pEv->button][eventno]) != NoSymbol;
1198
if (keycode = XKeysymToKeycode(pShadow->dpy, keysym)) {
1199
XTestFakeKeyEvent(pShadow->dpy, keycode, True, 0);
1200
XTestFakeKeyEvent(pShadow->dpy, keycode, False, 0);
1201
XFlush(pShadow->dpy);
1203
printf(" (0x%04X)", keycode);
1208
printf(" (no code)");
1215
} else if (pEv->button <= nButtons) {
1216
toButton = pDpyInfo->inverseMap[pEv->button];
1217
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
1218
XTestFakeButtonEvent(pShadow->dpy, toButton, True, 0);
1220
printf("from button %d down, to button %d down\n", pEv->button,toButton);
1222
XFlush(pShadow->dpy);
1225
FakeAction(pDpyInfo, FAKE_BUTTON, toButton, True);
1079
1229
/* check if more than one button pressed */
1080
1230
state = pEv->state;
1114
1264
if ((pDpyInfo->mode == X2X_CONNECTED) ||
1115
1265
(pDpyInfo->mode == X2X_CONN_RELEASE)) {
1116
if (pEv->button <= N_BUTTONS) toButton = pDpyInfo->inverseMap[pEv->button];
1117
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
1118
XTestFakeButtonEvent(pShadow->dpy, toButton, False, 0);
1266
if ((pEv->button <= nButtons) &&
1267
(buttonmap[pEv->button][0] == NoSymbol))
1268
// Do not process button release if it was mapped to keys
1270
toButton = pDpyInfo->inverseMap[pEv->button];
1271
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
1272
XTestFakeButtonEvent(pShadow->dpy, toButton, False, 0);
1120
printf("from button %d up, to button %d up\n", pEv->button, toButton);
1274
printf("from button %d up, to button %d up\n", pEv->button, toButton);
1122
XFlush(pShadow->dpy);
1125
FakeAction(pDpyInfo, FAKE_BUTTON, toButton, False);
1276
XFlush(pShadow->dpy);
1279
FakeAction(pDpyInfo, FAKE_BUTTON, toButton, False);
1128
1283
if (doEdge) return False;