2 * ion/ioncore/rootwin.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
13 #include <sys/types.h>
22 #include <X11/Xproto.h>
24 #include <libtu/objp.h>
31 #include "clientwin.h"
38 #include <libextl/readconfig.h>
45 /*{{{ Error handling */
48 static bool redirect_error=FALSE;
49 static bool ignore_badwindow=TRUE;
52 static int my_redirect_error_handler(Display *dpy, XErrorEvent *ev)
59 static int my_error_handler(Display *dpy, XErrorEvent *ev)
61 static char msg[128], request[64], num[32];
63 /* Just ignore bad window and similar errors; makes the rest of
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)) &&
73 XmuPrintDefaultErrorMessage(dpy, ev, stderr);
75 XGetErrorText(dpy, ev->error_code, msg, 128);
76 snprintf(num, 32, "%d", ev->request_code);
77 XGetErrorDatabaseText(dpy, "XRequest", num, "", request, 64);
80 snprintf(request, 64, "<unknown request>");
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);
86 warn("[%d] %s (%d) %#lx: %s", ev->serial, request,
87 ev->request_code, ev->resourceid,msg);
91 kill(getpid(), SIGTRAP);
103 static void scan_initial_windows(WRootWin *rootwin)
105 Window dummy_root, dummy_parent, *wins=NULL;
109 XQueryTree(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), &dummy_root, &dummy_parent,
112 for(i=0; i<nwins; i++){
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){
128 rootwin->tmpwins=wins;
129 rootwin->tmpnwins=nwins;
133 void rootwin_manage_initial_windows(WRootWin *rootwin)
135 Window *wins=rootwin->tmpwins;
137 int i, nwins=rootwin->tmpnwins;
139 rootwin->tmpwins=NULL;
142 for(i=0; i<nwins; i++){
143 if(XWINDOW_REGION_OF(wins[i])!=NULL)
147 if(XGetTransientForHint(ioncore_g.dpy, wins[i], &tfor))
149 ioncore_manage_clientwin(wins[i], FALSE);
153 for(i=0; i<nwins; i++){
156 ioncore_manage_clientwin(wins[i], FALSE);
163 static void create_wm_windows(WRootWin *rootwin)
165 rootwin->dummy_win=XCreateWindow(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
167 CopyFromParent, InputOnly,
168 CopyFromParent, 0, NULL);
170 XSelectInput(ioncore_g.dpy, rootwin->dummy_win, PropertyChangeMask);
174 static void preinit_gr(WRootWin *rootwin)
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;
185 gcv.subwindow_mode=IncludeInferiors;
189 gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
190 GCJoinStyle|GCCapStyle|GCFunction|
191 GCSubwindowMode|GCForeground);
193 rootwin->xor_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
198 static Atom net_virtual_roots=None;
201 static bool rootwin_init(WRootWin *rootwin, int xscr)
203 Display *dpy=ioncore_g.dpy;
207 /* Try to select input on the root window */
208 root=RootWindow(dpy, xscr);
210 redirect_error=FALSE;
212 XSetErrorHandler(my_redirect_error_handler);
213 XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN);
215 XSetErrorHandler(my_error_handler);
218 warn(TR("Unable to redirect root window events for screen %d."),
224 rootwin->default_cmap=DefaultColormap(dpy, xscr);
225 rootwin->tmpwins=NULL;
227 rootwin->dummy_win=None;
228 rootwin->xor_gc=None;
230 fp.mode=REGION_FIT_EXACT;
232 fp.g.w=DisplayWidth(dpy, xscr);
233 fp.g.h=DisplayHeight(dpy, xscr);
235 if(!screen_init((WScreen*)rootwin, NULL, &fp, xscr, root)){
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;
244 REGION_MARK_MAPPED(rootwin);
246 scan_initial_windows(rootwin);
248 create_wm_windows(rootwin);
250 netwm_init_rootwin(rootwin);
252 net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
253 XDeleteProperty(ioncore_g.dpy, root, net_virtual_roots);
255 LINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rootwin, p_next, p_prev);
257 xwindow_set_cursor(root, IONCORE_CURSOR_DEFAULT);
263 WRootWin *create_rootwin(int xscr)
265 CREATEOBJ_IMPL(WRootWin, rootwin, (p, xscr));
269 void rootwin_deinit(WRootWin *rw)
273 FOR_ALL_SCREENS_W_NEXT(scr, next){
274 if(REGION_MANAGER(scr)==(WRegion*)rw)
275 destroy_obj((Obj*)scr);
278 UNLINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rw, p_next, p_prev);
280 XSelectInput(ioncore_g.dpy, WROOTWIN_ROOT(rw), 0);
282 XFreeGC(ioncore_g.dpy, rw->xor_gc);
284 rw->scr.mplex.win.win=None;
286 screen_deinit(&rw->scr);
293 /*{{{ region dynfun implementations */
296 static bool rootwin_fitrep(WRootWin *rootwin, WWindow *par,
297 const WFitParams *fp)
299 D(warn("Don't know how to reparent or fit root windows."));
304 static void rootwin_map(WRootWin *rootwin)
306 D(warn("Attempt to map a root window."));
310 static void rootwin_unmap(WRootWin *rootwin)
312 D(warn("Attempt to unmap a root window -- impossible."));
323 * Returns previously active screen on root window \var{rootwin}.
327 WScreen *rootwin_current_scr(WRootWin *rootwin)
329 WScreen *scr, *fb=NULL;
331 FOR_ALL_SCREENS(scr){
332 if(REGION_MANAGER(scr)==(WRegion*)rootwin && REGION_IS_MAPPED(scr)){
334 if(REGION_IS_ACTIVE(scr))
339 return (fb ? fb : &rootwin->scr);
346 /*{{{ Dynamic function table and class implementation */
349 static DynFunTab rootwin_dynfuntab[]={
350 {region_map, rootwin_map},
351 {region_unmap, rootwin_unmap},
352 {(DynFun*)region_fitrep, (DynFun*)rootwin_fitrep},
358 IMPLCLASS(WRootWin, WScreen, rootwin_deinit, rootwin_dynfuntab);