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