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