-
Notifications
You must be signed in to change notification settings - Fork 59
/
x2x.c
3697 lines (3223 loc) · 113 KB
/
x2x.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* 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.
*
* By downloading, installing, using, modifying or distributing this
* software, you agree to the following:
*
* 1. CONDITIONS. Subject to the following conditions, you may download,
* install, use, modify and distribute this software in source and binary
* forms:
*
* a) Any source code, binary code and associated documentation
* (including the online manual) used, modified or distributed must
* reproduce and retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* b) No right is granted to use any trade name, trademark or logo of
* Digital Equipment Corporation. Neither the "Digital Equipment
* Corporation" name nor any trademark or logo of Digital Equipment
* Corporation may be used to endorse or promote products derived from
* this software without the prior written permission of Digital
* Equipment Corporation.
*
* 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "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 DIGITAL 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.
*/
/*
* Modified on 3 Oct 1998 by Charles Briscoe-Smith:
* added options -north and -south
*/
/* Cygwin version with -fromwin to allow source to be a Windows
* machine that is not running a X server.
* Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code
*
* Original win2vnc copyright follows:
*/
// win2vnc, adapted from vncviewer by Fredrik Hubinette 2001
//
// Original copyright follows:
//
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of the VNC system.
//
// The VNC system 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.
//
// If the source code for the VNC system is not available from the place
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on [email protected] for information on obtaining it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.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/Xos.h>
#include <X11/extensions/XTest.h>
#include <X11/extensions/dpms.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#ifdef WIN_2_X
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include <assert.h>
#include "keymap.h"
#include "resource.h"
#define X2X_MSG_HOTKEY (WM_USER + 1)
#define DPMSModeOn 0
extern Status DPMSForceLevel(Display *, unsigned short);
/* We always support this: */
#define DPMSQueryExtension(DPY, EVBASE, ERBASE) TRUE
#else
#include <X11/extensions/dpms.h>
#endif
/*#define DEBUG*/
#ifndef MIN
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif
#define UTF8_STRING "UTF8_STRING"
/**********
* definitions for edge
**********/
#define EDGE_NONE 0 /* don't transfer between edges of screens */
#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
**********/
static void ParseCommandLine();
static Display *OpenAndCheckDisplay();
static Bool CheckTestExtension();
#ifndef WIN_2_X
static int ErrorHandler();
#endif
static void DoDPMSForceLevel();
static void DoX2X();
static void InitDpyInfo();
static void DoConnect();
static void DoDisconnect();
static void RegisterEventHandlers();
static Bool ProcessEvent();
static Bool ProcessMotionNotify();
static Bool ProcessExpose();
static void DrawWindowText();
static Bool ProcessEnterNotify();
static Bool ProcessButtonPress();
static Bool ProcessButtonRelease();
static Bool ProcessKeyEvent();
static Bool ProcessConfigureNotify();
static Bool ProcessClientMessage();
static Bool ProcessSelectionRequest();
static void SendPing();
static Bool ProcessPropertyNotify();
static Bool ProcessSelectionNotify();
static void SendSelectionNotify();
static Bool ProcessSelectionClear();
static Bool ProcessVisibility();
static Bool ProcessMapping();
static void FakeThingsUp();
static void FakeAction();
static void RefreshPointerMapping();
static void Usage();
static void *xmalloc();
/**********
* stuff for selection forwarding
**********/
typedef struct _dpyxtra {
Display *otherDpy;
int sState;
Atom pingAtom;
Bool pingInProg;
Window propWin;
} DPYXTRA, *PDPYXTRA;
/**********
* structures for recording state of buttons and keys
**********/
typedef struct _fakestr {
struct _fakestr *pNext;
int type;
KeySym thing;
KeyCode code;
} FAKE, *PFAKE;
#define FAKE_KEY 0
#define FAKE_BUTTON 1
#define N_BUTTONS 20
#define MAX_BUTTONMAPEVENTS 20
#define GETDPYXTRA(DPY,PDPYINFO)\
(((DPY) == (PDPYINFO)->fromDpy) ?\
&((PDPYINFO)->fromDpyXtra) : &((PDPYINFO)->toDpyXtra))
/* values for sState */
#define SELSTATE_ON 0
#define SELSTATE_OFF 1
#define SELSTATE_WAIT 2
/* special values for translated coordinates */
#define COORD_INCR -1
#define COORD_DECR -2
#define SPECIAL_COORD(COORD) (((COORD) < 0) ? (COORD) : 0)
/* max unreasonable coordinates before accepting it */
#define MAX_UNREASONABLES 10
/**********
* display information
**********/
typedef struct {
/* stuff on "from" display */
Display *fromDpy;
Atom fromDpyUtf8String;
Window root;
Window trigger;
Window big;
Window selWinFrom;
int selRevFrom;
GC textGC;
Atom wmpAtom, wmdwAtom;
Atom netWmWindowTypeAtom, netWmWindowTypeDockAtom;
Atom netWmStrutAtom;
Cursor grabCursor;
Font fid;
int width, height, twidth, theight, tascent;
Bool vertical;
int lastFromCoord;
int unreasonableDelta;
#ifdef WIN_2_X
int unreasonableCount;
/* From display info for Windows */
HWND bigwindow;
HWND edgewindow;
int onedge;
int fromWidth, fromHeight;
int wdelta;
int lastFromY;
HWND hwndNextViewer;
// int initialClipboardSeen;
char *winSelText;
int owntoXsel;
int expectSelNotify;
int expectOwnClip;
int winSSave;
int nXbuttons;
RECT monitorRect;
RECT screenRect;
int screenHeight;
int screenWidth;
int lastFromX;
#endif /* WIN_2_X */
/* stuff on "to" display */
Display *toDpy;
Atom toDpyUtf8String;
Atom toDpyTargets;
Window selWinTo;
int selRevTo;
unsigned int inverseMap[N_BUTTONS + 1]; /* inverse of button mapping */
/* state of connection */
int signal; /* gort signal? */
int mode; /* connection */
int eventMask; /* trigger */
/* coordinate conversion stuff */
int toScreen;
int nScreens;
short **xTables; /* precalculated conversion tables */
short **yTables;
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;
DPYXTRA toDpyXtra;
Display *sDpy;
XSelectionRequestEvent sEv;
Time sTime;
/* for recording state of buttons and keys */
PFAKE pFakeThings;
} DPYINFO, *PDPYINFO;
static DPYINFO dpyInfo;
/* shadow displays */
typedef struct _shadow {
struct _shadow *pNext;
char *name;
Display *dpy;
long led_mask;
Bool flush;
int DPMSstatus; /* -1: not queried, 0: not supported, 1: supported */
} SHADOW, *PSHADOW;
/* sticky keys */
typedef struct _sticky {
struct _sticky *pNext;
KeySym keysym;
} STICKY, *PSTICKY;
typedef int (*HANDLER)(); /* event handler function */
/* These prototypes need the typedefs */
#ifdef WIN_2_X
static void MoveWindowToEdge(PDPYINFO);
static int MoveWindowToScreen(PDPYINFO);
static void DoWinConnect(PDPYINFO, int, int);
static void DoWinDisconnect(PDPYINFO, int, int);
static void SendButtonClick(PDPYINFO, int);
LRESULT CALLBACK WinProcessMessage (HWND, UINT, WPARAM, LPARAM);
void WinPointerEvent(PDPYINFO, int, int, DWORD, UINT);
void WinKeyEvent(PDPYINFO, int, DWORD);
void SendKeyEvent(PDPYINFO, KeySym, int, int, int);
static Bool ProcessSelectionRequestW();
static Bool ProcessSelectionNotifyW();
static Bool ProcessSelectionClearW();
#ifdef DEBUGCHATTY
char *msgtotext(int);
#endif
#endif /* WIN_2_X */
/**********
* top-level variables
**********/
static char *programStr = "x2x";
static char *fromDpyName = NULL;
static char *toDpyName = NULL;
static char *defaultFN = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
static char *fontName = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
static char *label = NULL;
static char *title = NULL;
static char *pingStr = "PING"; /* atom for ping request */
static char *geomStr = NULL;
static Bool waitDpy = False;
static Bool doBig = False;
static Bool doMouse = True;
static int doEdge = EDGE_NONE;
static Bool doSel = True;
static Bool doAutoUp = True;
static Bool doResurface = False;
static Bool winTransparent = False;
static Bool doInputOnly = True;
static PSHADOW shadows = NULL;
static int triggerw = 2;
static Bool doPointerMap = True;
static PSTICKY stickies = NULL;
static Bool doBtnBlock = False;
static Bool doCapsLkHack = False;
static Bool doClipCheck = False;
static Bool doDpmsMouse = False;
static int logicalOffset= 0;
static int nButtons = 0;
static KeySym buttonmap[N_BUTTONS + 1][MAX_BUTTONMAPEVENTS + 1];
static Bool noScale = False;
static int compRegLeft = 0;
static int compRegRight = 0;
static int compRegUp = 0;
static int compRegLow = 0;
static Bool useStruts = False;
#ifdef WIN_2_X
/* These are used to allow pointer comparisons */
static char *fromWinName = "x2xFromWin";
static int dummy;
static Display *fromWin = (Display *)&dummy;
static HWND hWndSave;
static HINSTANCE m_instance;
#endif
#ifdef DEBUG_COMPLREG
#define debug_cmpreg printf
#else
void debug_cmpreg(const char *fmt, ...)
{
}
#endif
#ifdef DEBUG
#define debug printf
#else
void debug(const char* fmt, ...)
{
}
#endif
#ifdef WIN_2_X
#define MAX_WIN_ARGS 40
int STDCALL
WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
Display *fromDpy;
PSHADOW pShadow;
int argc;
char *argv[MAX_WIN_ARGS];
char *ap;
if (lpCmd[0] == ' ')
{
lpCmd++;
}
argv[0] = programStr;
argc = 1;
ap = lpCmd;
/* XXX mdh - Should probably deal with quotes properly too */
while (*ap && (argc < MAX_WIN_ARGS)) {
argv[argc++] = ap;
while (*ap && (*ap != ' ')) ap++;
if (*ap == ' ') *ap++ = 0;
}
m_instance = hInst;
#else /* Not WIN_2_X */
/**********
* main
**********/
int main(argc, argv)
int argc;
char **argv;
{
Display *fromDpy;
PSHADOW pShadow;
#endif /* WIN_2_X */
#ifdef DEBUG
setvbuf(stdout, NULL, _IONBF, 0);
#endif
XrmInitialize();
ParseCommandLine(argc, argv);
#ifdef WIN_2_X
if (fromDpyName != fromWinName)
fromDpyName = XDisplayName(fromDpyName);
#else
fromDpyName = XDisplayName(fromDpyName);
#endif
toDpyName = XDisplayName(toDpyName);
if (!strcasecmp(toDpyName, fromDpyName)) {
fprintf(stderr, "%s: display names are both %s\n", programStr, toDpyName);
exit(1);
}
/* no OS independent way to stop Xlib from complaining via stderr,
but can always pipe stdout/stderr to /dev/null */
/* convert to real name: */
#ifdef WIN_2_X
if (fromDpyName == fromWinName) {
/* From is Windows, don't need to open */
fromDpy = fromWin;
} else
/* This ugly hanging else... */
#endif /* WIN_2_X */
/* ... qualifies this while in WIN_2_X case with an X source */
while ((fromDpy = XOpenDisplay(fromDpyName)) == NULL) {
if (!waitDpy) {
fprintf(stderr, "%s - error: can not open display %s\n",
programStr, fromDpyName);
exit(2);
} /* END if */
sleep(10);
} /* END while fromDpy */
(void)XSynchronize(fromDpy, True);
/* toDpy is always the first shadow */
pShadow = (PSHADOW)xmalloc(sizeof(SHADOW));
pShadow->DPMSstatus = -1;
pShadow->name = toDpyName;
/* link into the global list */
pShadow->pNext = shadows;
shadows = pShadow;
/* initialize all of the shadows, including the toDpy */
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
pShadow->led_mask = 0;
pShadow->flush = False;
if (!(pShadow->dpy = OpenAndCheckDisplay(pShadow->name)))
exit(3);
}
(void)XSynchronize(shadows->dpy, True);
#ifndef WIN_2_X
/* set error handler,
so that program does not abort on non-critcal errors */
XSetErrorHandler(ErrorHandler);
#endif
/* run the x2x loop */
DoX2X(fromDpy, shadows->dpy);
/* shut down gracefully */
#ifdef WIN_2_X
/* Only close if it is a real X from display */
if (fromDpy != fromWin)
XCloseDisplay(fromDpy);
#else
XCloseDisplay(fromDpy);
#endif
for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
XCloseDisplay(pShadow->dpy);
exit(0);
} /* END main */
static Display *OpenAndCheckDisplay(name)
char *name;
{
Display *openDpy;
/* convert to real name: */
name = XDisplayName(name);
while ((openDpy = XOpenDisplay(name)) == NULL) {
if (!waitDpy) {
fprintf(stderr, "%s - error: can not open display %s\n",
programStr, name);
return NULL;
} /* END if */
sleep(10);
} /* END while openDpy */
if (!CheckTestExtension(openDpy)) {
fprintf(stderr,
"%s - error: display %s does not support the test extension\n",
programStr, name);
return NULL;
}
return (openDpy);
} /* END OpenAndCheckDisplay */
/**********
* use standard X functions to parse the command line
**********/
static void ParseCommandLine(argc, argv)
int argc;
char **argv;
{
int arg;
PSHADOW pShadow;
extern char *lawyerese;
PSTICKY pNewSticky;
KeySym keysym;
int button;
int eventno;
char *keyname, *argptr;
debug("programStr = %s\n", programStr);
/* Clear button map */
for (button = 0; button <= N_BUTTONS; button++)
buttonmap[button][0] = NoSymbol;
for (arg = 1; arg < argc; ++arg) {
#ifdef WIN_2_X
if (!strcasecmp(argv[arg], "-fromWin")) {
fromDpyName = fromWinName;
/* XXX mdh - For now only support edge windows getting big */
/* Note: -east will override correctly (even if earlier on the line) */
doBig = True;
if (doEdge == EDGE_NONE) doEdge = EDGE_WEST;
doCapsLkHack = True;
debug("fromDpyName = %s\n", fromDpyName);
} else
/* Note this else will qualify the if below... */
#endif /* WIN_2_X */
if (!strcasecmp(argv[arg], "-from")) {
if (++arg >= argc) Usage();
fromDpyName = argv[arg];
debug("fromDpyName = %s\n", fromDpyName);
} else if (!strcasecmp(argv[arg], "-to")) {
if (++arg >= argc) Usage();
toDpyName = argv[arg];
debug("toDpyName = %s\n", toDpyName);
} else if (!strcasecmp(argv[arg], "-font")) {
if (++arg >= argc) Usage();
fontName = argv[arg];
debug("fontName = %s\n", fontName);
} else if (!strcasecmp(argv[arg], "-label")) {
if (++arg >= argc) Usage();
label = argv[arg];
debug("label = %s\n", label);
} else if (!strcasecmp(argv[arg], "-title")) {
if (++arg > argc) Usage();
title = argv[arg];
debug("title = %s\n", title);
} else if (!strcasecmp(argv[arg], "-geometry")) {
if (++arg >= argc) Usage();
geomStr = argv[arg];
debug("geometry = %s\n", geomStr);
} else if (!strcasecmp(argv[arg], "-wait")) {
waitDpy = True;
debug("will wait for displays\n");
} else if (!strcasecmp(argv[arg], "-big")) {
doBig = True;
debug("will create big window on from display\n");
} else if (!strcasecmp(argv[arg], "-nomouse")) {
doMouse = False;
debug("will not capture mouse (eek!)\n");
} else if (!strcasecmp(argv[arg], "-nopointermap")) {
doPointerMap = False;
debug("will not do pointer mapping\n");
} else if (!strcasecmp(argv[arg], "-north")) {
doEdge = EDGE_NORTH;
debug("\"from\" is on the north side of \"to\"\n");
} else if (!strcasecmp(argv[arg], "-south")) {
doEdge = EDGE_SOUTH;
debug("\"from\" is on the south side of \"to\"\n");
} else if (!strcasecmp(argv[arg], "-east")) {
doEdge = EDGE_EAST;
debug("\"from\" is on the east side of \"to\"\n");
} else if (!strcasecmp(argv[arg], "-west")) {
doEdge = EDGE_WEST;
debug("\"from\" is on the west side of \"to\"\n");
} else if (!strcasecmp(argv[arg], "-nosel")) {
doSel = False;
debug("will not transmit X selections between displays\n");
} else if (!strcasecmp(argv[arg], "-noautoup")) {
doAutoUp = False;
debug("will not automatically lift keys and buttons\n");
} else if (!strcasecmp(argv[arg], "-buttonblock")) {
doBtnBlock = True;
debug("mouse buttons down will block disconnects\n");
} else if (!strcasecmp(argv[arg], "-capslockhack")) {
doCapsLkHack = True;
debug("behavior of CapsLock will be hacked\n");
} else if (!strcasecmp(argv[arg], "-dpmsmouse")) {
doDpmsMouse = True;
debug("mouse movement wakes monitor\n");
} else if (!strcasecmp(argv[arg], "-offset")) {
if (++arg >= argc) Usage();
logicalOffset = atoi(argv[arg]);
debug("logicalOffset %d\n", logicalOffset);
} else if (!strcasecmp(argv[arg], "-clipcheck")) {
doClipCheck = True;
debug("Clipboard type will be checked for XA_STRING\n");
} else if (!strcasecmp(argv[arg], "-nocapslockhack")) {
doCapsLkHack = False;
debug("behavior of CapsLock will not be hacked\n");
} else if (!strcasecmp(argv[arg], "-sticky")) {
if (++arg >= argc) Usage();
if ((keysym = XStringToKeysym(argv[arg])) != NoSymbol) {
pNewSticky = (PSTICKY)xmalloc(sizeof(STICKY));
pNewSticky->pNext = stickies;
pNewSticky->keysym = keysym;
stickies = pNewSticky;
debug("will press/release sticky key: %s\n", argv[arg]);
} 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
{
debug("will map button %d to keysyms '%s'\n", button, argv[arg]);
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;
debug("will resurface the trigger window when obscured\n");
} else if (!strcasecmp(argv[arg], "-win-output")) {
doInputOnly = False;
debug("trigger window will be an InputOutput window\n");
} else if (!strcasecmp(argv[arg], "-win-transparent")) {
winTransparent = True;
debug("trigger window will be transparent\n");
} else if (!strcasecmp(argv[arg], "-shadow")) {
if (++arg >= argc) Usage();
pShadow = (PSHADOW)xmalloc(sizeof(SHADOW));
pShadow->DPMSstatus = -1;
pShadow->name = argv[arg];
/* into the global list of shadows */
pShadow->pNext = shadows;
shadows = pShadow;
} else if (!strcasecmp(argv[arg], "-triggerw")) {
if (++arg >= argc) Usage();
triggerw = atoi(argv[arg]);
} else if (!strcasecmp(argv[arg], "-copyright")) {
puts(lawyerese);
} else if (!strcasecmp(argv[arg], "-noscale")) {
noScale = True;
} else if (!strcasecmp(argv[arg], "-completeregionleft")) {
if (++arg >= argc) Usage();
compRegLeft = atoi(argv[arg]);
} else if (!strcasecmp(argv[arg], "-completeregionright")) {
if (++arg >= argc) Usage();
compRegRight = atoi(argv[arg]);
} else if (!strcasecmp(argv[arg], "-completeregionup")) {
if (++arg >= argc) Usage();
compRegUp = atoi(argv[arg]);
} else if (!strcasecmp(argv[arg], "-completeregionlow")) {
if (++arg >= argc) Usage();
compRegLow = atoi(argv[arg]);
} else if (!strcasecmp(argv[arg], "-struts")) {
useStruts = True;
debug("will advertise struts in _NET_WM_STRUT\n");
} else {
Usage();
} /* END if... */
} /* END for */
} /* END ParseCommandLine */
static void Usage()
{
#ifdef WIN_2_X
printf("Usage: x2x [-fromwin | -from <DISPLAY>][-to <DISPLAY>] options..\n");
#else
printf("Usage: x2x [-to <DISPLAY> | -from <DISPLAY>] options...\n");
#endif
printf(" -copyright\n");
printf(" -font <FONTNAME>\n");
printf(" -geometry <GEOMETRY>\n");
printf(" -wait\n");
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");
printf(" -noautoup\n");
printf(" -resurface\n");
printf(" -win-output\n");
printf(" -win-transparent\n");
printf(" -capslockhack\n");
printf(" -nocapslockhack\n");
printf(" -clipcheck\n");
printf(" -shadow <DISPLAY>\n");
printf(" -sticky <STICKY KEY>\n");
printf(" -label <LABEL>\n");
printf(" -title <TITLE>\n");
printf(" -buttonmap <BUTTON#> \"<KEYSYM> ...\"\n");
printf(" -completeregionleft <COORDINATE>\n");
printf(" -completeregionright <COORDINATE>\n");
printf(" -completeregionup <COORDINATE>\n");
printf(" -completeregionlow <COORDINATE>\n");
printf(" -struts\n");
#ifdef WIN_2_X
printf(" -offset [-]<pixel offset of \"to\">\n");
printf("WIN_2_X build allows Windows or X as -from display\n");
printf("Note that -fromwin sets default to -big -west -capslockhack\n");
printf("A Windows shortcut of the form:\n");
printf("C:\\cygwin\\usr\\X11R6\\bin\\run.exe /usr/X11R6/bin/x2x -fromwin -to <to> -east\n");
printf("Should work to start the app from the desktop or start menu, but\n");
printf("c:\\cygwin\\bin may need to be added to the PATH to get cygwin1.dll\n");
#endif
exit(4);
} /* END Usage */
/**********
* call the library to check for the test extension
**********/
static Bool CheckTestExtension(dpy)
Display *dpy;
{
int eventb, errorb;
int vmajor, vminor;
return (XTestQueryExtension(dpy, &eventb, &errorb, &vmajor, &vminor));
} /* END CheckTestExtension */
#ifndef WIN_2_X
int ErrorHandler(Display *disp, XErrorEvent *event) {
int bufflen = 1024;
char *buff;
buff = malloc(bufflen);
XGetErrorText(disp,event->error_code,buff,bufflen);
debug("x2x:ErrHandler(): Display:`%s` \t error_code:`%i` \n",
XDisplayName(NULL),event->error_code);
printf(" %s \n",buff);
free(buff);
return True;
}
#endif
#define X2X_DISCONNECTED 0
#define X2X_AWAIT_RELEASE 1
#define X2X_CONNECTED 2
#define X2X_CONN_RELEASE 3
static void signal_handler(int sig)
{
if (dpyInfo.mode == X2X_CONNECTED)
DoDisconnect(&dpyInfo);
dpyInfo.signal = sig;
}
static void DoX2X(fromDpy, toDpy)
Display *fromDpy;
Display *toDpy;
{
int nfds;
fd_set fdset;
Bool fromPending;
int fromConn, toConn;
/* set up displays */
dpyInfo.fromDpy = fromDpy;
dpyInfo.toDpy = toDpy;
InitDpyInfo(&dpyInfo);
RegisterEventHandlers(&dpyInfo);
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* set up for select */
#ifdef WIN_2_X
fromConn = (fromDpy == fromWin) ? 0 : XConnectionNumber(fromDpy);
#else
fromConn = XConnectionNumber(fromDpy);
#endif /* WIN_2_X */
toConn = XConnectionNumber(toDpy);
nfds = (fromConn > toConn ? fromConn : toConn) + 1;
#ifdef WIN_2_X
if (fromDpy == fromWin) {
MSG msg; /* A Win32 message structure. */
int nowQuit;
nowQuit = 0;
/* XXX mdh - This is not quite right becaue it only does To events */
/* XXX mdh - when there are From events */
/* This is mostly ok, but can cause windows->X paste to take a while */
/* As a compromise, try a 1 second tick to cause polling */
SetTimer(dpyInfo.bigwindow, 1, 1000 /* in ms */, NULL);
/* GetMessage blocks until the next Windows event */
/* It returns 0 if the app should quit */
while (!nowQuit && GetMessage (&msg, NULL, 0, 0)) {
/* XXX mdh - Translate may not be needed if all Key processing is */
/* XXX mdh - done using the Key events rather than CHAR events */
TranslateMessage (&msg);
DispatchMessage (&msg);
/* Done a Windows event, now loop while -to has something */
while (XPending(toDpy) || dpyInfo.expectSelNotify) {
if (ProcessEvent(toDpy, &dpyInfo)) { /* done! */
nowQuit = 1;
break;
}
/* PeekMessage is a non-blocking version of GetMessage */
/* But it returns 0 for no messages rather than for quit */
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
/* need explicit check for quit */
if (msg.message == WM_QUIT) {
nowQuit = 1;
break; /* from the while(XPending... )*/
}
/* XXX mdh - see above */
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
}
} else
/* Again, the else qualifies the while below */
#endif /* WIN_2_X */
while (dpyInfo.signal == 0) { /* FOREVER */
if ((fromPending = XPending(fromDpy)))
if (ProcessEvent(fromDpy, &dpyInfo)) /* done! */
break;
if (XPending(toDpy)) {
if (ProcessEvent(toDpy, &dpyInfo)) /* done! */
break;
} else if (!fromPending) {
FD_ZERO(&fdset);
FD_SET(fromConn, &fdset);
FD_SET(toConn, &fdset);
select(nfds, &fdset, NULL, NULL, NULL);
}
} /* END FOREVER */
} /* END DoX2X() */
static void InitDpyInfo(pDpyInfo)
PDPYINFO pDpyInfo;
{
Display *fromDpy, *toDpy;
Screen *fromScreen;
long black, white;
int fromHeight, fromWidth, toHeight, toWidth;
Pixmap nullPixmap;
XColor dummyColor;
Window root, trigger, big, rret, toRoot, propWin;
short *xTable, *yTable; /* short: what about dimensions > 2^15? */
int *heights, *widths;
int counter;
int nScreens, screenNum;
int twidth, theight, tascent; /* text dimensions */
int xoff, yoff; /* window offsets */
unsigned int width, height; /* window width, height */
int geomMask; /* mask returned by parse */
int gravMask;
int gravity;
int xret, yret;
unsigned int wret, hret, bret, dret;
XSetWindowAttributes xswa;
XSizeHints *xsh;
int eventMask;
GC textGC;
char *windowName;
Font fid;
PSHADOW pShadow;
int triggerLoc;
Bool vertical;
/* cache commonly used variables */
fromDpy = pDpyInfo->fromDpy;
toDpy = pDpyInfo->toDpy;
pDpyInfo->toDpyXtra.propWin = (Window) 0;