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