2 * ion/ioncore/rootwin.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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 * 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...
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)) &&
74 XmuPrintDefaultErrorMessage(dpy, ev, stderr);
76 XGetErrorText(dpy, ev->error_code, msg, 128);
77 snprintf(num, 32, "%d", ev->request_code);
78 XGetErrorDatabaseText(dpy, "XRequest", num, "", request, 64);
81 snprintf(request, 64, "<unknown request>");
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);
87 warn("[%d] %s (%d) %#lx: %s", ev->serial, request,
88 ev->request_code, ev->resourceid,msg);
92 kill(getpid(), SIGTRAP);
104 static void scan_initial_windows(WRootWin *rootwin)
106 Window dummy_root, dummy_parent, *wins=NULL;
110 XQueryTree(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), &dummy_root, &dummy_parent,
113 for(i=0; i<nwins; i++){
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){
129 rootwin->tmpwins=wins;
130 rootwin->tmpnwins=nwins;
134 void rootwin_manage_initial_windows(WRootWin *rootwin)
136 Window *wins=rootwin->tmpwins;
138 int i, nwins=rootwin->tmpnwins;
140 rootwin->tmpwins=NULL;
143 for(i=0; i<nwins; i++){
144 if(XWINDOW_REGION_OF(wins[i])!=NULL)
148 if(XGetTransientForHint(ioncore_g.dpy, wins[i], &tfor))
150 ioncore_manage_clientwin(wins[i], FALSE);
154 for(i=0; i<nwins; i++){
157 ioncore_manage_clientwin(wins[i], FALSE);
164 static void create_wm_windows(WRootWin *rootwin)
166 rootwin->dummy_win=XCreateWindow(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
168 CopyFromParent, InputOnly,
169 CopyFromParent, 0, NULL);
171 XSelectInput(ioncore_g.dpy, rootwin->dummy_win, PropertyChangeMask);
175 static void preinit_gr(WRootWin *rootwin)
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;
186 gcv.subwindow_mode=IncludeInferiors;
190 gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
191 GCJoinStyle|GCCapStyle|GCFunction|
192 GCSubwindowMode|GCForeground);
194 rootwin->xor_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin),
199 static Atom net_virtual_roots=None;
202 static bool rootwin_init(WRootWin *rootwin, int xscr)
204 Display *dpy=ioncore_g.dpy;
208 /* Try to select input on the root window */
209 root=RootWindow(dpy, xscr);
211 redirect_error=FALSE;
213 XSetErrorHandler(my_redirect_error_handler);
214 XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN);
216 XSetErrorHandler(my_error_handler);
219 warn(TR("Unable to redirect root window events for screen %d."),
225 rootwin->default_cmap=DefaultColormap(dpy, xscr);
226 rootwin->tmpwins=NULL;
228 rootwin->dummy_win=None;
229 rootwin->xor_gc=None;
231 fp.mode=REGION_FIT_EXACT;
233 fp.g.w=DisplayWidth(dpy, xscr);
234 fp.g.h=DisplayHeight(dpy, xscr);
236 if(!screen_init((WScreen*)rootwin, NULL, &fp, xscr, root)){
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;
245 REGION_MARK_MAPPED(rootwin);
247 scan_initial_windows(rootwin);
249 create_wm_windows(rootwin);
251 netwm_init_rootwin(rootwin);
253 net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
254 XDeleteProperty(ioncore_g.dpy, root, net_virtual_roots);
256 LINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rootwin, p_next, p_prev);
258 xwindow_set_cursor(root, IONCORE_CURSOR_DEFAULT);
264 WRootWin *create_rootwin(int xscr)
266 CREATEOBJ_IMPL(WRootWin, rootwin, (p, xscr));
270 void rootwin_deinit(WRootWin *rw)
274 FOR_ALL_SCREENS_W_NEXT(scr, next){
275 if(REGION_MANAGER(scr)==(WRegion*)rw)
276 destroy_obj((Obj*)scr);
279 UNLINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rw, p_next, p_prev);
281 XSelectInput(ioncore_g.dpy, WROOTWIN_ROOT(rw), 0);
283 XFreeGC(ioncore_g.dpy, rw->xor_gc);
285 rw->scr.mplex.win.win=None;
287 screen_deinit(&rw->scr);
294 /*{{{ region dynfun implementations */
297 static bool rootwin_fitrep(WRootWin *rootwin, WWindow *par,
298 const WFitParams *fp)
300 D(warn("Don't know how to reparent or fit root windows."));
305 static void rootwin_map(WRootWin *rootwin)
307 D(warn("Attempt to map a root window."));
311 static void rootwin_unmap(WRootWin *rootwin)
313 D(warn("Attempt to unmap a root window -- impossible."));
324 * Returns previously active screen on root window \var{rootwin}.
328 WScreen *rootwin_current_scr(WRootWin *rootwin)
330 WScreen *scr, *fb=NULL;
332 FOR_ALL_SCREENS(scr){
333 if(REGION_MANAGER(scr)==(WRegion*)rootwin && REGION_IS_MAPPED(scr)){
335 if(REGION_IS_ACTIVE(scr))
340 return (fb ? fb : &rootwin->scr);
347 /*{{{ Dynamic function table and class implementation */
350 static DynFunTab rootwin_dynfuntab[]={
351 {region_map, rootwin_map},
352 {region_unmap, rootwin_unmap},
353 {(DynFun*)region_fitrep, (DynFun*)rootwin_fitrep},
359 IMPLCLASS(WRootWin, WScreen, rootwin_deinit, rootwin_dynfuntab);