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