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