]> code.delx.au - spectrwm/blob - lib/swm_hack.c
Cleanup libswmhack.so.
[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 <stdbool.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <dlfcn.h>
48 #include <X11/Xlib.h>
49 #include <X11/X.h>
50 #include <X11/Xatom.h>
51 #include <X11/Intrinsic.h>
52
53 /* dlopened libs so we can find the symbols in the real one to call them */
54 static void *lib_xlib = NULL;
55 static void *lib_xtlib = NULL;
56
57 static Window root = None;
58 static bool xterm = false;
59 static Display *display = NULL;
60
61 void set_property(Display *, Window, char *, char *);
62
63 #ifdef _GNU_SOURCE
64 #define DLOPEN(s) RTLD_NEXT
65 #else
66 #define DLOPEN(s) dlopen((s), RTLD_GLOBAL | RTLD_LAZY)
67 #endif
68
69 /* Find our root window */
70 static Window
71 MyRoot(Display * dpy)
72 {
73 char *s;
74
75 if (root != None)
76 return root;
77
78 root = DefaultRootWindow(dpy);
79
80 s = getenv("ENL_WM_ROOT");
81 if (s == NULL)
82 return root;
83
84 sscanf(s, "%lx", &root);
85 return root;
86 }
87
88
89 typedef Atom (XIA) (Display *display, char *atom_name, Bool
90 only_if_exists);
91
92 typedef int (XCP) (Display *display, Window w, Atom property,
93 Atom type, int format, int mode, unsigned char *data,
94 int nelements);
95
96 #define SWM_PROPLEN (16)
97 void
98 set_property(Display *dpy, Window id, char *name, char *val)
99 {
100 Atom atom = 0;
101 char prop[SWM_PROPLEN];
102 static XIA *xia = NULL;
103 static XCP *xcp = NULL;
104
105 if (lib_xlib == NULL)
106 lib_xlib = DLOPEN("libX11.so");
107 if (lib_xlib) {
108 if (xia == NULL)
109 xia = (XIA *) dlsym(lib_xlib, "XInternAtom");
110 if (xcp == NULL)
111 xcp = (XCP *) dlsym(lib_xlib, "XChangeProperty");
112 }
113 if (xia == NULL || xcp == NULL) {
114 fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
115 return;
116 }
117
118 /* Try to update the window's workspace property */
119 atom = (*xia)(dpy, name, False);
120 if (atom)
121 if (snprintf(prop, SWM_PROPLEN, "%s", val) < SWM_PROPLEN)
122 (*xcp)(dpy, id, atom, XA_STRING,
123 8, PropModeReplace, (unsigned char *)prop,
124 strlen((char *)prop));
125 }
126
127 typedef Window(CWF) (Display * _display, Window _parent, int _x,
128 int _y, unsigned int _width,
129 unsigned int _height,
130 unsigned int _border_width, int _depth,
131 unsigned int _class, Visual * _visual,
132 unsigned long _valuemask,
133 XSetWindowAttributes * _attributes);
134
135 /* XCreateWindow intercept hack */
136 Window
137 XCreateWindow(Display *dpy, Window parent, int x, int y,
138 unsigned int width, unsigned int height,
139 unsigned int border_width,
140 int depth, unsigned int clss, Visual * visual,
141 unsigned long valuemask, XSetWindowAttributes * attributes)
142 {
143 static CWF *func = NULL;
144 char *env;
145 Window id;
146
147 if (lib_xlib == NULL)
148 lib_xlib = DLOPEN("libX11.so");
149 if (lib_xlib && func == NULL) {
150 func = (CWF *) dlsym(lib_xlib, "XCreateWindow");
151 display = dpy;
152 }
153 if (func == NULL) {
154 fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
155 return None;
156 }
157
158 if (parent == DefaultRootWindow(dpy))
159 parent = MyRoot(dpy);
160
161 id = (*func) (dpy, parent, x, y, width, height, border_width,
162 depth, clss, visual, valuemask, attributes);
163
164 if (id) {
165 if ((env = getenv("_SWM_WS")) != NULL)
166 set_property(dpy, id, "_SWM_WS", env);
167 if ((env = getenv("_SWM_PID")) != NULL)
168 set_property(dpy, id, "_SWM_PID", env);
169 if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
170 unsetenv("_SWM_XTERM_FONTADJ");
171 xterm = true;
172 }
173 }
174 return (id);
175 }
176
177 typedef Window(CSWF) (Display * _display, Window _parent, int _x,
178 int _y, unsigned int _width,
179 unsigned int _height,
180 unsigned int _border_width,
181 unsigned long _border,
182 unsigned long _background);
183
184 /* XCreateSimpleWindow intercept hack */
185 Window
186 XCreateSimpleWindow(Display *dpy, Window parent, int x, int y,
187 unsigned int width, unsigned int height,
188 unsigned int border_width,
189 unsigned long border, unsigned long background)
190 {
191 static CSWF *func = NULL;
192 char *env;
193 Window id;
194
195 if (lib_xlib == NULL)
196 lib_xlib = DLOPEN("libX11.so");
197 if (lib_xlib && func == NULL)
198 func = (CSWF *) dlsym(lib_xlib, "XCreateSimpleWindow");
199 if (func == NULL) {
200 fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
201 return None;
202 }
203
204 if (parent == DefaultRootWindow(dpy))
205 parent = MyRoot(dpy);
206
207 id = (*func) (dpy, parent, x, y, width, height,
208 border_width, border, background);
209
210 if (id) {
211 if ((env = getenv("_SWM_WS")) != NULL)
212 set_property(dpy, id, "_SWM_WS", env);
213 if ((env = getenv("_SWM_PID")) != NULL)
214 set_property(dpy, id, "_SWM_PID", env);
215 if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
216 unsetenv("_SWM_XTERM_FONTADJ");
217 xterm = true;
218 }
219 }
220 return (id);
221 }
222
223 typedef int (RWF) (Display * _display, Window _window, Window _parent,
224 int x, int y);
225
226 /* XReparentWindow intercept hack */
227 int
228 XReparentWindow(Display *dpy, Window window, Window parent, int x, int y)
229 {
230 static RWF *func = NULL;
231
232 if (lib_xlib == NULL)
233 lib_xlib = DLOPEN("libX11.so");
234 if (lib_xlib && func == NULL)
235 func = (RWF *) dlsym(lib_xlib, "XReparentWindow");
236 if (func == NULL) {
237 fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
238 /* Xlib function always returns 1, so return 0 here. */
239 return 0;
240 }
241
242 if (parent == DefaultRootWindow(dpy))
243 parent = MyRoot(dpy);
244
245 return (*func) (dpy, window, parent, x, y);
246 }
247
248 typedef void (ANEF) (XtAppContext app_context, XEvent *event_return);
249 int evcount = 0;
250
251 /*
252 * XtAppNextEvent Intercept Hack
253 * Normally xterm rejects "synthetic" (XSendEvent) events to prevent spoofing.
254 * We don't want to disable this completely, it's insecure. But hook here
255 * and allow these mostly harmless ones that we use to adjust fonts.
256 */
257 void
258 XtAppNextEvent(XtAppContext app_context, XEvent *event_return)
259 {
260 static ANEF *func = NULL;
261 static KeyCode kp_add = 0, kp_subtract = 0;
262
263 if (lib_xtlib == NULL)
264 lib_xtlib = DLOPEN("libXt.so");
265 if (lib_xtlib && func == NULL) {
266 func = (ANEF *) dlsym(lib_xtlib, "XtAppNextEvent");
267 if (display) {
268 kp_add = XKeysymToKeycode(display, XK_KP_Add);
269 kp_subtract = XKeysymToKeycode(display, XK_KP_Subtract);
270 }
271 }
272 if (func == NULL) {
273 fprintf(stderr, "libswmhack.so: ERROR: %s\n", dlerror());
274 return;
275 }
276
277 (*func) (app_context, event_return);
278
279 /* Return here if it's not an Xterm. */
280 if (!xterm)
281 return;
282
283 /* Allow spoofing of font change keystrokes. */
284 if ((event_return->type == KeyPress ||
285 event_return->type == KeyRelease) &&
286 event_return->xkey.state == ShiftMask &&
287 (event_return->xkey.keycode == kp_add ||
288 event_return->xkey.keycode == kp_subtract))
289 event_return->xkey.send_event = 0;
290 }