2 * ion/ioncore/rootwin.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
10 #include <sys/types.h>
19 #include <X11/Xproto.h>
21 #include <libtu/objp.h>
28 #include "clientwin.h"
35 #include <libextl/readconfig.h>
42 /*{{{ Error handling */
45 static bool redirect_error=FALSE;
46 static bool ignore_badwindow=TRUE;
49 static int my_redirect_error_handler(Display *dpy, XErrorEvent *ev)
56 static int my_error_handler(Display *dpy, XErrorEvent *ev)
58 static char msg[128], request[64], num[32];
60 /* Just ignore bad window and similar errors; makes the rest of
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)) &&
70 XmuPrintDefaultErrorMessage(dpy, ev, stderr);
72 XGetErrorText(dpy, ev->error_code, msg, 128);
73 snprintf(num, 32, "%d", ev->request_code);
74 XGetErrorDatabaseText(dpy, "XRequest", num, "", request, 64);
77 snprintf(request, 64, "<unknown request>");
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);
83 warn("[%d] %s (%d) %#lx: %s", ev->serial, request,
84 ev->request_code, ev->resourceid,msg);
88 kill(getpid(), SIGTRAP);
100 static void scan_initial_windows(WRootWin *rootwin)
102 Window dummy_root, dummy_parent, *wins=NULL;
106 XQueryTree(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), &dummy_root, &dummy_parent,
109 for(i=0; i<nwins; i++){
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){
125 rootwin->tmpwins=wins;
126 rootwin->tmpnwins=nwins;
130 void rootwin_manage_initial_windows(WRootWin *rootwin)
132 Window *wins=rootwin->tmpwins;
134 int i, nwins=rootwin->tmpnwins;
136 rootwin->tmpwins=NULL;
139 for(i=0; i<nwins; i++){
140 if(XWINDOW_REGION_OF(wins[i])!=NULL)
144 if(XGetTransientForHint(ioncore_g.dpy, wins[i], &tfor))
146 ioncore_manage_clientwin(wins[i], FALSE);
150 for(i=0; i<nwins; i++){
153 ioncore_manage_clientwin(wins[i], FALSE);
160 static void create_wm_windows(WRootWin *rootwin)
162 rootwin->dummy_win=XCreateWindow(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
164 CopyFromParent, InputOnly,
165 CopyFromParent, 0, NULL);
167 XSelectInput(ioncore_g.dpy, rootwin->dummy_win, PropertyChangeMask);
171 static void preinit_gr(WRootWin *rootwin)
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;
182 gcv.subwindow_mode=IncludeInferiors;
186 gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
187 GCJoinStyle|GCCapStyle|GCFunction|
188 GCSubwindowMode|GCForeground);
190 rootwin->xor_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
195 static Atom net_virtual_roots=None;
198 static bool rootwin_init(WRootWin *rootwin, int xscr)
200 Display *dpy=ioncore_g.dpy;
204 /* Try to select input on the root window */
205 root=RootWindow(dpy, xscr);
207 redirect_error=FALSE;
209 XSetErrorHandler(my_redirect_error_handler);
210 XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN);
212 XSetErrorHandler(my_error_handler);
215 warn(TR("Unable to redirect root window events for screen %d."),
221 rootwin->default_cmap=DefaultColormap(dpy, xscr);
222 rootwin->tmpwins=NULL;
224 rootwin->dummy_win=None;
225 rootwin->xor_gc=None;
227 fp.mode=REGION_FIT_EXACT;
229 fp.g.w=DisplayWidth(dpy, xscr);
230 fp.g.h=DisplayHeight(dpy, xscr);
232 if(!screen_init((WScreen*)rootwin, NULL, &fp, xscr, root)){
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;
241 REGION_MARK_MAPPED(rootwin);
243 scan_initial_windows(rootwin);
245 create_wm_windows(rootwin);
247 netwm_init_rootwin(rootwin);
249 net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
250 XDeleteProperty(ioncore_g.dpy, root, net_virtual_roots);
252 LINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rootwin, p_next, p_prev);
254 xwindow_set_cursor(root, IONCORE_CURSOR_DEFAULT);
260 WRootWin *create_rootwin(int xscr)
262 CREATEOBJ_IMPL(WRootWin, rootwin, (p, xscr));
266 void rootwin_deinit(WRootWin *rw)
270 FOR_ALL_SCREENS_W_NEXT(scr, next){
271 if(REGION_MANAGER(scr)==(WRegion*)rw)
272 destroy_obj((Obj*)scr);
275 UNLINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rw, p_next, p_prev);
277 XSelectInput(ioncore_g.dpy, WROOTWIN_ROOT(rw), 0);
279 XFreeGC(ioncore_g.dpy, rw->xor_gc);
281 rw->scr.mplex.win.win=None;
283 screen_deinit(&rw->scr);
290 /*{{{ region dynfun implementations */
293 static bool rootwin_fitrep(WRootWin *rootwin, WWindow *par,
294 const WFitParams *fp)
296 D(warn("Don't know how to reparent or fit root windows."));
301 static void rootwin_map(WRootWin *rootwin)
303 D(warn("Attempt to map a root window."));
307 static void rootwin_unmap(WRootWin *rootwin)
309 D(warn("Attempt to unmap a root window -- impossible."));
320 * Returns previously active screen on root window \var{rootwin}.
324 WScreen *rootwin_current_scr(WRootWin *rootwin)
326 WScreen *scr, *fb=NULL;
328 FOR_ALL_SCREENS(scr){
329 if(REGION_MANAGER(scr)==(WRegion*)rootwin && REGION_IS_MAPPED(scr)){
331 if(REGION_IS_ACTIVE(scr))
336 return (fb ? fb : &rootwin->scr);
343 /*{{{ Dynamic function table and class implementation */
346 static DynFunTab rootwin_dynfuntab[]={
347 {region_map, rootwin_map},
348 {region_unmap, rootwin_unmap},
349 {(DynFun*)region_fitrep, (DynFun*)rootwin_fitrep},
355 IMPLCLASS(WRootWin, WScreen, rootwin_deinit, rootwin_dynfuntab);