]> git.decadent.org.uk Git - ion3.git/blob - ioncore/rootwin.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / rootwin.c
1 /*
2  * ion/ioncore/rootwin.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <sys/time.h>
13 #include <time.h>
14 #include <signal.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xproto.h>
20
21 #include <libtu/objp.h>
22 #include "common.h"
23 #include "rootwin.h"
24 #include "cursor.h"
25 #include "global.h"
26 #include "event.h"
27 #include "gr.h"
28 #include "clientwin.h"
29 #include "property.h"
30 #include "focus.h"
31 #include "regbind.h"
32 #include "screen.h"
33 #include "screen.h"
34 #include "bindmaps.h"
35 #include <libextl/readconfig.h>
36 #include "resize.h"
37 #include "saveload.h"
38 #include "netwm.h"
39 #include "xwindow.h"
40
41
42 /*{{{ Error handling */
43
44
45 static bool redirect_error=FALSE;
46 static bool ignore_badwindow=TRUE;
47
48
49 static int my_redirect_error_handler(Display *dpy, XErrorEvent *ev)
50 {
51     redirect_error=TRUE;
52     return 0;
53 }
54
55
56 static int my_error_handler(Display *dpy, XErrorEvent *ev)
57 {
58     static char msg[128], request[64], num[32];
59     
60     /* Just ignore bad window and similar errors; makes the rest of
61      * the code simpler.
62      * 
63      * Apparently XGetWindowProperty can return BadMatch on a race
64      * condition where the server is already reusing the XID for a 
65      * non-window drawable, so let's just ignore BadMatch entirely...
66      */
67     if((ev->error_code==BadWindow ||
68         (ev->error_code==BadMatch /*&& ev->request_code==X_SetInputFocus*/) ||
69         (ev->error_code==BadDrawable && ev->request_code==X_GetGeometry)) &&
70        ignore_badwindow)
71         return 0;
72
73 #if 0
74     XmuPrintDefaultErrorMessage(dpy, ev, stderr);
75 #else
76     XGetErrorText(dpy, ev->error_code, msg, 128);
77     snprintf(num, 32, "%d", ev->request_code);
78     XGetErrorDatabaseText(dpy, "XRequest", num, "", request, 64);
79
80     if(request[0]=='\0')
81         snprintf(request, 64, "<unknown request>");
82
83     if(ev->minor_code!=0){
84         warn("[%d] %s (%d.%d) %#lx: %s", ev->serial, request,
85              ev->request_code, ev->minor_code, ev->resourceid,msg);
86     }else{
87         warn("[%d] %s (%d) %#lx: %s", ev->serial, request,
88              ev->request_code, ev->resourceid,msg);
89     }
90 #endif
91
92     kill(getpid(), SIGTRAP);
93     
94     return 0;
95 }
96
97
98 /*}}}*/
99
100
101 /*{{{ Init/deinit */
102
103
104 static void scan_initial_windows(WRootWin *rootwin)
105 {
106     Window dummy_root, dummy_parent, *wins=NULL;
107     uint nwins=0, i, j;
108     XWMHints *hints;
109     
110     XQueryTree(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), &dummy_root, &dummy_parent,
111                &wins, &nwins);
112     
113     for(i=0; i<nwins; i++){
114         if(wins[i]==None)
115             continue;
116         hints=XGetWMHints(ioncore_g.dpy, wins[i]);
117         if(hints!=NULL && hints->flags&IconWindowHint){
118             for(j=0; j<nwins; j++){
119                 if(wins[j]==hints->icon_window){
120                     wins[j]=None;
121                     break;
122                 }
123             }
124         }
125         if(hints!=NULL)
126             XFree((void*)hints);
127     }
128     
129     rootwin->tmpwins=wins;
130     rootwin->tmpnwins=nwins;
131 }
132
133
134 void rootwin_manage_initial_windows(WRootWin *rootwin)
135 {
136     Window *wins=rootwin->tmpwins;
137     Window tfor=None;
138     int i, nwins=rootwin->tmpnwins;
139
140     rootwin->tmpwins=NULL;
141     rootwin->tmpnwins=0;
142     
143     for(i=0; i<nwins; i++){
144         if(XWINDOW_REGION_OF(wins[i])!=NULL)
145             wins[i]=None;
146         if(wins[i]==None)
147             continue;
148         if(XGetTransientForHint(ioncore_g.dpy, wins[i], &tfor))
149             continue;
150         ioncore_manage_clientwin(wins[i], FALSE);
151         wins[i]=None;
152     }
153
154     for(i=0; i<nwins; i++){
155         if(wins[i]==None)
156             continue;
157         ioncore_manage_clientwin(wins[i], FALSE);
158     }
159     
160     XFree((void*)wins);
161 }
162
163
164 static void create_wm_windows(WRootWin *rootwin)
165 {
166     rootwin->dummy_win=XCreateWindow(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
167                                      0, 0, 1, 1, 0,
168                                      CopyFromParent, InputOnly,
169                                      CopyFromParent, 0, NULL);
170
171     XSelectInput(ioncore_g.dpy, rootwin->dummy_win, PropertyChangeMask);
172 }
173
174
175 static void preinit_gr(WRootWin *rootwin)
176 {
177     XGCValues gcv;
178     ulong gcvmask;
179
180     /* Create XOR gc (for resize) */
181     gcv.line_style=LineSolid;
182     gcv.join_style=JoinBevel;
183     gcv.cap_style=CapButt;
184     gcv.fill_style=FillSolid;
185     gcv.line_width=2;
186     gcv.subwindow_mode=IncludeInferiors;
187     gcv.function=GXxor;
188     gcv.foreground=~0L;
189     
190     gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
191              GCJoinStyle|GCCapStyle|GCFunction|
192              GCSubwindowMode|GCForeground);
193
194     rootwin->xor_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), 
195                               gcvmask, &gcv);
196 }
197
198
199 static Atom net_virtual_roots=None;
200
201
202 static bool rootwin_init(WRootWin *rootwin, int xscr)
203 {
204     Display *dpy=ioncore_g.dpy;
205     WFitParams fp;
206     Window root;
207     
208     /* Try to select input on the root window */
209     root=RootWindow(dpy, xscr);
210     
211     redirect_error=FALSE;
212
213     XSetErrorHandler(my_redirect_error_handler);
214     XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN);
215     XSync(dpy, 0);
216     XSetErrorHandler(my_error_handler);
217
218     if(redirect_error){
219         warn(TR("Unable to redirect root window events for screen %d."),
220              xscr);
221         return FALSE;
222     }
223     
224     rootwin->xscr=xscr;
225     rootwin->default_cmap=DefaultColormap(dpy, xscr);
226     rootwin->tmpwins=NULL;
227     rootwin->tmpnwins=0;
228     rootwin->dummy_win=None;
229     rootwin->xor_gc=None;
230
231     fp.mode=REGION_FIT_EXACT;
232     fp.g.x=0; fp.g.y=0;
233     fp.g.w=DisplayWidth(dpy, xscr);
234     fp.g.h=DisplayHeight(dpy, xscr);
235     
236     if(!screen_init((WScreen*)rootwin, NULL, &fp, xscr, root)){
237         free(rootwin);
238         return FALSE;
239     }
240
241     ((WWindow*)rootwin)->event_mask=IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN;
242     ((WRegion*)rootwin)->flags|=REGION_BINDINGS_ARE_GRABBED|REGION_PLEASE_WARP;
243     ((WRegion*)rootwin)->rootwin=rootwin;
244     
245     REGION_MARK_MAPPED(rootwin);
246     
247     scan_initial_windows(rootwin);
248
249     create_wm_windows(rootwin);
250     preinit_gr(rootwin);
251     netwm_init_rootwin(rootwin);
252     
253     net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
254     XDeleteProperty(ioncore_g.dpy, root, net_virtual_roots);
255
256     LINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rootwin, p_next, p_prev);
257
258     xwindow_set_cursor(root, IONCORE_CURSOR_DEFAULT);
259     
260     return TRUE;
261 }
262
263
264 WRootWin *create_rootwin(int xscr)
265 {
266     CREATEOBJ_IMPL(WRootWin, rootwin, (p, xscr));
267 }
268
269
270 void rootwin_deinit(WRootWin *rw)
271 {
272     WScreen *scr, *next;
273
274     FOR_ALL_SCREENS_W_NEXT(scr, next){
275         if(REGION_MANAGER(scr)==(WRegion*)rw)
276             destroy_obj((Obj*)scr);
277     }
278     
279     UNLINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rw, p_next, p_prev);
280     
281     XSelectInput(ioncore_g.dpy, WROOTWIN_ROOT(rw), 0);
282     
283     XFreeGC(ioncore_g.dpy, rw->xor_gc);
284     
285     rw->scr.mplex.win.win=None;
286
287     screen_deinit(&rw->scr);
288 }
289
290
291 /*}}}*/
292
293
294 /*{{{ region dynfun implementations */
295
296
297 static bool rootwin_fitrep(WRootWin *rootwin, WWindow *par, 
298                            const WFitParams *fp)
299 {
300     D(warn("Don't know how to reparent or fit root windows."));
301     return FALSE;
302 }
303
304
305 static void rootwin_map(WRootWin *rootwin)
306 {
307     D(warn("Attempt to map a root window."));
308 }
309
310
311 static void rootwin_unmap(WRootWin *rootwin)
312 {
313     D(warn("Attempt to unmap a root window -- impossible."));
314 }
315
316
317 /*}}}*/
318
319
320 /*{{{ Misc */
321
322
323 /*EXTL_DOC
324  * Returns previously active screen on root window \var{rootwin}.
325  */
326 EXTL_SAFE
327 EXTL_EXPORT_MEMBER
328 WScreen *rootwin_current_scr(WRootWin *rootwin)
329 {
330     WScreen *scr, *fb=NULL;
331     
332     FOR_ALL_SCREENS(scr){
333         if(REGION_MANAGER(scr)==(WRegion*)rootwin && REGION_IS_MAPPED(scr)){
334             fb=scr;
335             if(REGION_IS_ACTIVE(scr))
336                 return scr;
337         }
338     }
339     
340     return (fb ? fb : &rootwin->scr);
341 }
342
343
344 /*}}}*/
345
346
347 /*{{{ Dynamic function table and class implementation */
348
349
350 static DynFunTab rootwin_dynfuntab[]={
351     {region_map, rootwin_map},
352     {region_unmap, rootwin_unmap},
353     {(DynFun*)region_fitrep, (DynFun*)rootwin_fitrep},
354     END_DYNFUNTAB
355 };
356
357
358 EXTL_EXPORT
359 IMPLCLASS(WRootWin, WScreen, rootwin_deinit, rootwin_dynfuntab);
360
361     
362 /*}}}*/