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