1 /*
2  * Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
3  * Copyright (c) 2009 Ryan McBride <mcbride@countersiege.com>
4  * Copyright (c) 2011-2018 Reginald Kennedy <rk@rejii.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * Copyright (C) 2005-2007 Carsten Haitzler
20  * Copyright (C) 2006-2007 Kim Woelders
21  *
22  * Permission is hereby granted, free of charge, to any person obtaining a copy
23  * of this software and associated documentation files (the "Software"), to
24  * deal in the Software without restriction, including without limitation the
25  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
26  * sell copies of the Software, and to permit persons to whom the Software is
27  * furnished to do so, subject to the following conditions:
28  *
29  * The above copyright notice and this permission notice shall be included in
30  * all copies of the Software, its documentation and marketing & publicity
31  * materials, and acknowledgment shall be given in the documentation, materials
32  * and software packages that this Software was used.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40  */
41 /*
42  * Basic hack mechanism (dlopen etc.) taken from e_hack.c in e17.
43  */
44 #include <string.h>
45 #include <stdbool.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <dlfcn.h>
49 #include <X11/Xlib.h>
50 #include <X11/X.h>
51 #include <X11/Xatom.h>
52 #include <X11/Intrinsic.h>
53 
54 /* dlopened libs so we can find the symbols in the real one to call them */
55 static void		*lib_xlib = NULL;
56 static void		*lib_xtlib = NULL;
57 
58 static bool		xterm = false;
59 static Display		*display = NULL;
60 
61 static Atom		swmws = None, swmpid = None;
62 
63 void	set_property(Display *, Window, Atom, char *);
64 Atom	get_atom_from_string(Display *, char *);
65 
66 #if defined(_GNU_SOURCE) && !defined(__CYGWIN__)
67 #define DLOPEN(s)	RTLD_NEXT
68 #else
69 #define DLOPEN(s)	dlopen((s), RTLD_GLOBAL | RTLD_LAZY)
70 #endif
71 
72 typedef Atom (XIA)(Display *_display, char *atom_name, Bool only_if_exists);
73 
74 Atom
get_atom_from_string(Display * dpy,char * name)75 get_atom_from_string(Display *dpy, char *name)
76 {
77 	Atom			atom = None;
78 	static XIA		*xia = NULL;
79 
80 	if (lib_xlib == NULL)
81 		lib_xlib = DLOPEN("libX11.so");
82 	if (lib_xlib) {
83 		if (xia == NULL)
84 			xia = (XIA *) dlsym(lib_xlib, "XInternAtom");
85 	}
86 	if (xia == NULL) {
87 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
88 		return (atom);
89 	}
90 
91 	atom = (*xia)(dpy, name, False);
92 	return (atom);
93 }
94 
95 typedef int (XCP)(Display *_display, Window w, Atom property, Atom type,
96     int format, int mode, unsigned char *data, int nelements);
97 
98 #define SWM_PROPLEN	(16)
99 void
set_property(Display * dpy,Window id,Atom atom,char * val)100 set_property(Display *dpy, Window id, Atom atom, char *val)
101 {
102 	char			prop[SWM_PROPLEN];
103 	static XCP		*xcp = NULL;
104 
105 	if (lib_xlib == NULL)
106 		lib_xlib = DLOPEN("libX11.so");
107 	if (lib_xlib) {
108 		if (xcp == NULL)
109 			xcp = (XCP *) dlsym(lib_xlib, "XChangeProperty");
110 	}
111 	if (xcp == NULL) {
112 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
113 		return;
114 	}
115 
116 	/* Try to update the window's workspace property */
117 	if (atom)
118 		if (snprintf(prop, SWM_PROPLEN, "%s", val) < SWM_PROPLEN)
119 			(*xcp)(dpy, id, atom, XA_STRING,
120 			    8, PropModeReplace, (unsigned char *)prop,
121 			    strlen((char *)prop));
122 }
123 
124 typedef Display *(ODF)(register _Xconst char *_display);
125 
126 /* XOpenDisplay intercept hack */
127 Display *
XOpenDisplay(register _Xconst char * _display)128 XOpenDisplay(register _Xconst char *_display)
129 {
130 	static ODF	*func = NULL;
131 
132 	if (lib_xlib == NULL)
133 		lib_xlib = DLOPEN("libX11.so");
134 	if (lib_xlib && func == NULL)
135 		func = (ODF *) dlsym(lib_xlib, "XOpenDisplay");
136 	if (func == NULL) {
137 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
138 		return (None);
139 	}
140 
141 	display = (*func) (_display);
142 
143 	/* Preload atoms to prevent deadlock. */
144 	if (swmws == None)
145 		swmws = get_atom_from_string(display, "_SWM_WS");
146 	if (swmpid == None)
147 		swmpid = get_atom_from_string(display, "_SWM_PID");
148 
149 	return (display);
150 }
151 
152 typedef Window (CWF)(Display * _display, Window _parent, int _x, int _y,
153     unsigned int _width, unsigned int _height, unsigned int _border_width,
154     int _depth, unsigned int _class, Visual * _visual, unsigned long _valuemask,
155     XSetWindowAttributes * _attributes);
156 
157 /* XCreateWindow intercept hack */
158 Window
XCreateWindow(Display * dpy,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,int depth,unsigned int clss,Visual * visual,unsigned long valuemask,XSetWindowAttributes * attributes)159 XCreateWindow(Display *dpy, Window parent, int x, int y, unsigned int width,
160     unsigned int height, unsigned int border_width, int depth,
161     unsigned int clss, Visual * visual, unsigned long valuemask,
162     XSetWindowAttributes * attributes)
163 {
164 	static CWF	*func = NULL;
165 	char		*env;
166 	Window		id;
167 
168 	if (lib_xlib == NULL)
169 		lib_xlib = DLOPEN("libX11.so");
170 	if (lib_xlib && func == NULL)
171 		func = (CWF *) dlsym(lib_xlib, "XCreateWindow");
172 	if (func == NULL) {
173 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
174 		return (None);
175 	}
176 
177 	id = (*func) (dpy, parent, x, y, width, height, border_width,
178 	    depth, clss, visual, valuemask, attributes);
179 
180 	if (id) {
181 		if ((env = getenv("_SWM_WS")) != NULL)
182 			set_property(dpy, id, swmws, env);
183 		if ((env = getenv("_SWM_PID")) != NULL)
184 			set_property(dpy, id, swmpid, env);
185 		if (getenv("_SWM_XTERM_FONTADJ") != NULL) {
186 			unsetenv("_SWM_XTERM_FONTADJ");
187 			xterm = true;
188 		}
189 	}
190 	return (id);
191 }
192 
193 typedef Window (CSWF)(Display * _display, Window _parent, int _x, int _y,
194     unsigned int _width, unsigned int _height, unsigned int _border_width,
195     unsigned long _border, unsigned long _background);
196 
197 /* XCreateSimpleWindow intercept hack */
198 Window
XCreateSimpleWindow(Display * dpy,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,unsigned long border,unsigned long background)199 XCreateSimpleWindow(Display *dpy, Window parent, int x, int y,
200     unsigned int width, unsigned int height, unsigned int border_width,
201     unsigned long border, unsigned long background)
202 {
203 	static CSWF	*func = NULL;
204 	char		*env;
205 	Window		id;
206 
207 	if (lib_xlib == NULL)
208 		lib_xlib = DLOPEN("libX11.so");
209 	if (lib_xlib && func == NULL)
210 		func = (CSWF *) dlsym(lib_xlib, "XCreateSimpleWindow");
211 	if (func == NULL) {
212 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
213 		return (None);
214 	}
215 
216 	id = (*func) (dpy, parent, x, y, width, height,
217 	    border_width, border, background);
218 
219 	if (id) {
220 		if ((env = getenv("_SWM_WS")) != NULL)
221 			set_property(dpy, id, swmws, env);
222 		if ((env = getenv("_SWM_PID")) != NULL)
223 			set_property(dpy, id, swmpid, env);
224 		if (getenv("_SWM_XTERM_FONTADJ") != NULL) {
225 			unsetenv("_SWM_XTERM_FONTADJ");
226 			xterm = true;
227 		}
228 	}
229 	return (id);
230 }
231 
232 typedef void (ANEF)(XtAppContext app_context, XEvent *event_return);
233 
234 /*
235  * XtAppNextEvent Intercept Hack
236  * Normally xterm rejects "synthetic" (XSendEvent) events to prevent spoofing.
237  * We don't want to disable this completely, it's insecure. But hook here
238  * and allow these mostly harmless ones that we use to adjust fonts.
239  */
240 void
XtAppNextEvent(XtAppContext app_context,XEvent * event_return)241 XtAppNextEvent(XtAppContext app_context, XEvent *event_return)
242 {
243 	static ANEF	*func = NULL;
244 	static KeyCode	kp_add = 0, kp_subtract = 0;
245 
246 	if (lib_xtlib == NULL)
247 		lib_xtlib = DLOPEN("libXt.so");
248 	if (lib_xtlib && func == NULL) {
249 		func = (ANEF *) dlsym(lib_xtlib, "XtAppNextEvent");
250 		if (display) {
251 			kp_add = XKeysymToKeycode(display, XK_KP_Add);
252 			kp_subtract = XKeysymToKeycode(display, XK_KP_Subtract);
253 		}
254 	}
255 	if (func == NULL) {
256 		fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
257 		return;
258 	}
259 
260 	(*func) (app_context, event_return);
261 
262 	/* Return here if it's not an Xterm. */
263 	if (!xterm)
264 		return;
265 
266 	/* Allow spoofing of font change keystrokes. */
267 	if ((event_return->type == KeyPress ||
268 	   event_return->type == KeyRelease) &&
269 	   event_return->xkey.state == ShiftMask &&
270 	   (event_return->xkey.keycode == kp_add ||
271 	   event_return->xkey.keycode == kp_subtract))
272 		event_return->xkey.send_event = 0;
273 }
274