JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
merge upstream
[spectrwm.git] / 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         /* 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, (unsigned char *)prop,
112                             strlen((char *)prop));
113 }
114
115 typedef             Window(CWF) (Display * _display, Window _parent, int _x,
116                                  int _y, unsigned int _width,
117                                  unsigned int _height,
118                                  unsigned int _border_width, int _depth,
119                                  unsigned int _class, Visual * _visual,
120                                  unsigned long _valuemask,
121                                  XSetWindowAttributes * _attributes);
122
123 /* XCreateWindow intercept hack */
124 Window
125 XCreateWindow(Display *dpy, Window parent, int x, int y,
126    unsigned int width, unsigned int height,
127    unsigned int border_width,
128    int depth, unsigned int clss, Visual * visual,
129    unsigned long valuemask, XSetWindowAttributes * attributes)
130 {
131         static CWF      *func = NULL;
132         char            *env;
133         Window          id;
134
135         /* find the real Xlib and the real X function */
136         if (!lib_xlib)
137                 lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY);
138         if (!func) {
139                 func = (CWF *) dlsym(lib_xlib, "XCreateWindow");
140                 display = dpy;
141         }
142
143         if (parent == DefaultRootWindow(dpy))
144                 parent = MyRoot(dpy);
145         
146         id = (*func) (dpy, parent, x, y, width, height, border_width,
147             depth, clss, visual, valuemask, attributes);
148
149         if (id) {
150                 if ((env = getenv("_SWM_WS")) != NULL) 
151                         set_property(dpy, id, "_SWM_WS", env);
152                 if ((env = getenv("_SWM_PID")) != NULL)
153                         set_property(dpy, id, "_SWM_PID", env);
154                 if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
155                         unsetenv("_SWM_XTERM_FONTADJ");
156                         xterm = 1;
157                 }
158         }
159         return (id);
160 }
161
162 typedef             Window(CSWF) (Display * _display, Window _parent, int _x,
163                                   int _y, unsigned int _width,
164                                   unsigned int _height,
165                                   unsigned int _border_width,
166                                   unsigned long _border,
167                                   unsigned long _background);
168
169 /* XCreateSimpleWindow intercept hack */
170 Window
171 XCreateSimpleWindow(Display *dpy, Window parent, int x, int y,
172     unsigned int width, unsigned int height,
173     unsigned int border_width,
174     unsigned long border, unsigned long background)
175 {
176         static CSWF     *func = NULL;
177         char            *env;
178         Window          id;
179
180         /* find the real Xlib and the real X function */
181         if (!lib_xlib)
182                 lib_xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY);
183         if (!func)
184                 func = (CSWF *) dlsym(lib_xlib, "XCreateSimpleWindow");
185
186         if (parent == DefaultRootWindow(dpy))
187                 parent = MyRoot(dpy);
188
189         id = (*func) (dpy, parent, x, y, width, height,
190             border_width, border, background);
191
192         if (id) {
193                 if ((env = getenv("_SWM_WS")) != NULL) 
194                         set_property(dpy, id, "_SWM_WS", env);
195                 if ((env = getenv("_SWM_PID")) != NULL)
196                         set_property(dpy, id, "_SWM_PID", env);
197                 if ((env = getenv("_SWM_XTERM_FONTADJ")) != NULL) {
198                         unsetenv("_SWM_XTERM_FONTADJ");
199                         xterm = 1;
200                 }
201         }
202         return (id);
203 }
204
205 typedef int         (RWF) (Display * _display, Window _window, Window _parent,
206                            int x, int y);
207
208 /* XReparentWindow intercept hack */
209 int
210 XReparentWindow(Display *dpy, Window window, Window parent, int x, int y)
211 {
212         static RWF         *func = NULL;
213
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         if (!func)
218                 func = (RWF *) dlsym(lib_xlib, "XReparentWindow");
219
220         if (parent == DefaultRootWindow(dpy))
221                 parent = MyRoot(dpy);
222
223         return (*func) (dpy, window, parent, x, y);
224 }
225
226 typedef         void (ANEF) (XtAppContext app_context, XEvent *event_return);
227 int             evcount = 0;
228
229 /*
230  * XtAppNextEvent Intercept Hack
231  * Normally xterm rejects "synthetic" (XSendEvent) events to prevent spoofing.
232  * We don't want to disable this completely, it's insecure. But hook here
233  * and allow these mostly harmless ones that we use to adjust fonts.
234  */
235 void
236 XtAppNextEvent(XtAppContext app_context, XEvent *event_return)
237 {
238         static ANEF     *func = NULL;
239         static KeyCode  kp_add = 0, kp_subtract = 0;
240
241         /* find the real Xlib and the real X function */
242         if (!lib_xtlib)
243                 lib_xtlib = dlopen("libXt.so", RTLD_GLOBAL | RTLD_LAZY);
244         if (!func) {
245                 func = (ANEF *) dlsym(lib_xtlib, "XtAppNextEvent");
246                 if (display != NULL) {
247                         kp_add = XKeysymToKeycode(display, XK_KP_Add);
248                         kp_subtract = XKeysymToKeycode(display, XK_KP_Subtract);
249                 }
250         }
251
252         (*func) (app_context, event_return);
253
254         /* Return here if it's not an Xterm. */
255         if (!xterm)
256                 return;
257         
258         /* Allow spoofing of font change keystrokes. */
259         if ((event_return->type == KeyPress ||  
260            event_return->type == KeyRelease) &&
261            event_return->xkey.state == ShiftMask &&
262            (event_return->xkey.keycode == kp_add ||
263            event_return->xkey.keycode == kp_subtract))
264                 event_return->xkey.send_event = 0;
265 }