10bbfda8aSnia/*
20bbfda8aSnia * Forward key and mouse button events from one window to another.
30bbfda8aSnia *
40bbfda8aSnia * This is useful to use a Desktop window as a Root window.
50bbfda8aSnia */
60bbfda8aSnia
70bbfda8aSnia#include <stdio.h>
80bbfda8aSnia#include <stdlib.h>
90bbfda8aSnia#include <X11/Xlocale.h>
100bbfda8aSnia#include <X11/Xlib.h>
110bbfda8aSnia
120bbfda8aSniachar *ProgramName;
130bbfda8aSniaDisplay *dpy;
140bbfda8aSniaint screen;
150bbfda8aSnia
160bbfda8aSniastatic void
170bbfda8aSniausage(void)
180bbfda8aSnia{
190bbfda8aSnia	static const char *msg[] = {
200bbfda8aSnia		"    -display displayname                X server to contact",
210bbfda8aSnia		"    -id windowid                        use existing window",
220bbfda8aSnia		"    -root                               use root window",
230bbfda8aSnia		"    -name string                        window name",
240bbfda8aSnia		"",
250bbfda8aSnia		NULL
260bbfda8aSnia	};
270bbfda8aSnia	const char **cpp;
280bbfda8aSnia
290bbfda8aSnia	fprintf(stderr, "usage:  %s [-options ...]\n", ProgramName);
300bbfda8aSnia	fprintf(stderr, "where options include:\n");
310bbfda8aSnia
320bbfda8aSnia	for(cpp = msg; *cpp; cpp++) {
330bbfda8aSnia		fprintf(stderr, "%s\n", *cpp);
340bbfda8aSnia	}
350bbfda8aSnia
360bbfda8aSnia	exit(1);
370bbfda8aSnia}
380bbfda8aSnia
390bbfda8aSniaint
400bbfda8aSniamain(int argc, char **argv)
410bbfda8aSnia{
420bbfda8aSnia	char *displayname = NULL;
430bbfda8aSnia	int i;
440bbfda8aSnia	Window w;
450bbfda8aSnia	XWindowAttributes wattr;
460bbfda8aSnia	long event_mask;
470bbfda8aSnia	int done;
480bbfda8aSnia	Window ws[2];   /* from-window, to-window */
490bbfda8aSnia	int wi = 0;
500bbfda8aSnia	char *name;
510bbfda8aSnia
520bbfda8aSnia	ProgramName = argv[0];
530bbfda8aSnia
540bbfda8aSnia	if(setlocale(LC_ALL, "") == NULL) {
550bbfda8aSnia		fprintf(stderr, "%s: warning: could not set default locale\n",
560bbfda8aSnia		        ProgramName);
570bbfda8aSnia	}
580bbfda8aSnia
590bbfda8aSnia	w = 0;
600bbfda8aSnia	for(i = 1; i < argc; i++) {
610bbfda8aSnia		char *arg = argv[i];
620bbfda8aSnia
630bbfda8aSnia		if(arg[0] == '-') {
640bbfda8aSnia			switch(arg[1]) {
650bbfda8aSnia				case 'd':                 /* -display host:dpy */
660bbfda8aSnia					if(++i >= argc) {
670bbfda8aSnia						usage();
680bbfda8aSnia					}
690bbfda8aSnia					displayname = argv[i];
700bbfda8aSnia					continue;
710bbfda8aSnia				case 'i':                 /* -id */
720bbfda8aSnia					if(++i >= argc || wi > 1) {
730bbfda8aSnia						usage();
740bbfda8aSnia					}
750bbfda8aSnia					sscanf(argv[i], "0x%lx", &w);
760bbfda8aSnia					if(!w) {
770bbfda8aSnia						sscanf(argv[i], "%lu", &w);
780bbfda8aSnia					}
790bbfda8aSnia					if(!w) {
800bbfda8aSnia						usage();
810bbfda8aSnia					}
820bbfda8aSnia					ws[wi++] = w;
830bbfda8aSnia					continue;
840bbfda8aSnia				case 'n':                 /* -name */
850bbfda8aSnia					if(++i >= argc || wi > 1) {
860bbfda8aSnia						usage();
870bbfda8aSnia					}
880bbfda8aSnia					name = argv[i]; /* not implemented yet */
890bbfda8aSnia					(void)name; // Silence unused warning
900bbfda8aSnia					continue;
910bbfda8aSnia				case 'r':
920bbfda8aSnia					switch(arg[2]) {
930bbfda8aSnia						case 'o':             /* -root */
940bbfda8aSnia							if(wi > 1) {
950bbfda8aSnia								usage();
960bbfda8aSnia							}
970bbfda8aSnia							ws[wi++] = -1;
980bbfda8aSnia							continue;
990bbfda8aSnia						default:
1000bbfda8aSnia							usage();
1010bbfda8aSnia					}
1020bbfda8aSnia					continue;
1030bbfda8aSnia				default:
1040bbfda8aSnia					usage();
1050bbfda8aSnia			}                           /* end switch on - */
1060bbfda8aSnia		}
1070bbfda8aSnia		else {
1080bbfda8aSnia			usage();
1090bbfda8aSnia		}
1100bbfda8aSnia	}                                   /* end for over argc */
1110bbfda8aSnia
1120bbfda8aSnia	dpy = XOpenDisplay(displayname);
1130bbfda8aSnia	if(!dpy) {
1140bbfda8aSnia		fprintf(stderr, "%s:  unable to open display '%s'\n",
1150bbfda8aSnia		        ProgramName, XDisplayName(displayname));
1160bbfda8aSnia		exit(1);
1170bbfda8aSnia	}
1180bbfda8aSnia	screen = DefaultScreen(dpy);
1190bbfda8aSnia
1200bbfda8aSnia	if(ws[0] == -1) {
1210bbfda8aSnia		ws[0] = RootWindow(dpy, screen);
1220bbfda8aSnia	}
1230bbfda8aSnia	if(ws[1] == -1) {
1240bbfda8aSnia		ws[1] = RootWindow(dpy, screen);
1250bbfda8aSnia	}
1260bbfda8aSnia
1270bbfda8aSnia	if(ws[0] == ws[1]) {
1280bbfda8aSnia		fprintf(stderr, "error: from-window and to-window must differ.\n");
1290bbfda8aSnia		exit(1);
1300bbfda8aSnia	}
1310bbfda8aSnia
1320bbfda8aSnia	event_mask = KeyPressMask | KeyReleaseMask |
1330bbfda8aSnia	             ButtonPressMask | ButtonReleaseMask;
1340bbfda8aSnia
1350bbfda8aSnia	if(ws[0]) {
1360bbfda8aSnia		XGetWindowAttributes(dpy, ws[0], &wattr);
1370bbfda8aSnia		/* We can't select on button presses if someone else already does... */
1380bbfda8aSnia		if(wattr.all_event_masks & ButtonPressMask) {
1390bbfda8aSnia			event_mask &= ~ButtonPressMask;
1400bbfda8aSnia			fprintf(stderr, "warning: can't forward button presses.\n");
1410bbfda8aSnia		}
1420bbfda8aSnia		event_mask &= ~SubstructureRedirectMask;
1430bbfda8aSnia		printf("XSelectInput 0x%x %lx\n", (unsigned int)ws[0], event_mask);
1440bbfda8aSnia		XSelectInput(dpy, ws[0], event_mask);
1450bbfda8aSnia	}
1460bbfda8aSnia
1470bbfda8aSnia	for(done = 0; !done;) {
1480bbfda8aSnia		XEvent event;
1490bbfda8aSnia
1500bbfda8aSnia		XNextEvent(dpy, &event);
1510bbfda8aSnia
1520bbfda8aSnia		switch(event.type) {
1530bbfda8aSnia			case KeyPress:
1540bbfda8aSnia			case KeyRelease:
1550bbfda8aSnia				printf("KeyPress/KeyRelease\n");
1560bbfda8aSnia				event.xkey.window = ws[1];
1570bbfda8aSnia				XSendEvent(dpy, ws[1], False, KeyPressMask, &event);
1580bbfda8aSnia				break;
1590bbfda8aSnia			case ButtonPress:
1600bbfda8aSnia			case ButtonRelease:
1610bbfda8aSnia				printf("ButtonPress/ButtonRelease\n");
1620bbfda8aSnia				event.xbutton.window = ws[1];
1630bbfda8aSnia				XSendEvent(dpy, ws[1], False, KeyPressMask, &event);
1640bbfda8aSnia				break;
1650bbfda8aSnia			default:
1660bbfda8aSnia				printf("some other event\n");
1670bbfda8aSnia		}
1680bbfda8aSnia	}
1690bbfda8aSnia
1700bbfda8aSnia	XCloseDisplay(dpy);
1710bbfda8aSnia	return 0;
1720bbfda8aSnia}
173