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"
34 #include <libextl/readconfig.h>
41 /*{{{ Error handling */
44 static bool redirect_error
=FALSE
;
45 static bool ignore_badwindow
=TRUE
;
48 static int my_redirect_error_handler(Display
*dpy
, XErrorEvent
*ev
)
55 static int my_error_handler(Display
*dpy
, XErrorEvent
*ev
)
57 static char msg
[128], request
[64], num
[32];
59 /* Just ignore bad window and similar errors; makes the rest of
62 * Apparently XGetWindowProperty can return BadMatch on a race
63 * condition where the server is already reusing the XID for a
64 * non-window drawable, so let's just ignore BadMatch entirely...
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
)
167 rootwin
->dummy_win
=XCreateWindow(ioncore_g
.dpy
, WROOTWIN_ROOT(rootwin
),
169 CopyFromParent
, InputOnly
,
170 CopyFromParent
, 0, NULL
);
173 xwindow_set_text_property(rootwin
->dummy_win
, XA_WM_NAME
, p
, 1);
175 XSelectInput(ioncore_g
.dpy
, rootwin
->dummy_win
, PropertyChangeMask
);
179 static void preinit_gr(WRootWin
*rootwin
)
184 /* Create XOR gc (for resize) */
185 gcv
.line_style
=LineSolid
;
186 gcv
.join_style
=JoinBevel
;
187 gcv
.cap_style
=CapButt
;
188 gcv
.fill_style
=FillSolid
;
190 gcv
.subwindow_mode
=IncludeInferiors
;
194 gcvmask
=(GCLineStyle
|GCLineWidth
|GCFillStyle
|
195 GCJoinStyle
|GCCapStyle
|GCFunction
|
196 GCSubwindowMode
|GCForeground
);
198 rootwin
->xor_gc
=XCreateGC(ioncore_g
.dpy
, WROOTWIN_ROOT(rootwin
),
203 static Atom net_virtual_roots
=None
;
206 static bool rootwin_init(WRootWin
*rootwin
, int xscr
)
208 Display
*dpy
=ioncore_g
.dpy
;
213 /* Try to select input on the root window */
214 root
=RootWindow(dpy
, xscr
);
216 redirect_error
=FALSE
;
218 XSetErrorHandler(my_redirect_error_handler
);
219 XSelectInput(dpy
, root
, IONCORE_EVENTMASK_ROOT
);
221 XSetErrorHandler(my_error_handler
);
224 warn(TR("Unable to redirect root window events for screen %d."
225 "Maybe another window manager is running?"),
231 rootwin
->default_cmap
=DefaultColormap(dpy
, xscr
);
232 rootwin
->tmpwins
=NULL
;
234 rootwin
->dummy_win
=None
;
235 rootwin
->xor_gc
=None
;
237 fp
.mode
=REGION_FIT_EXACT
;
239 fp
.g
.w
=DisplayWidth(dpy
, xscr
);
240 fp
.g
.h
=DisplayHeight(dpy
, xscr
);
242 if(!window_do_init((WWindow
*)rootwin
, NULL
, &fp
, root
, "WRootWin")){
247 ((WWindow
*)rootwin
)->event_mask
=IONCORE_EVENTMASK_ROOT
;
248 ((WRegion
*)rootwin
)->flags
|=REGION_BINDINGS_ARE_GRABBED
|REGION_PLEASE_WARP
;
249 ((WRegion
*)rootwin
)->rootwin
=rootwin
;
251 REGION_MARK_MAPPED(rootwin
);
253 scan_initial_windows(rootwin
);
255 create_wm_windows(rootwin
);
257 netwm_init_rootwin(rootwin
);
259 region_add_bindmap((WRegion
*)rootwin
, ioncore_screen_bindmap
);
261 scr
=create_screen(rootwin
, &fp
, xscr
);
266 region_set_manager((WRegion
*)scr
, (WRegion
*)rootwin
);
267 region_map((WRegion
*)scr
);
269 LINK_ITEM(*(WRegion
**)&ioncore_g
.rootwins
, (WRegion
*)rootwin
, p_next
, p_prev
);
271 ioncore_screens_updated(rootwin
);
273 xwindow_set_cursor(root
, IONCORE_CURSOR_DEFAULT
);
279 WRootWin
*create_rootwin(int xscr
)
281 CREATEOBJ_IMPL(WRootWin
, rootwin
, (p
, xscr
));
285 void rootwin_deinit(WRootWin
*rw
)
289 FOR_ALL_SCREENS_W_NEXT(scr
, next
){
290 if(REGION_MANAGER(scr
)==(WRegion
*)rw
)
291 destroy_obj((Obj
*)scr
);
294 UNLINK_ITEM(*(WRegion
**)&ioncore_g
.rootwins
, (WRegion
*)rw
, p_next
, p_prev
);
296 XSelectInput(ioncore_g
.dpy
, WROOTWIN_ROOT(rw
), 0);
298 XFreeGC(ioncore_g
.dpy
, rw
->xor_gc
);
300 window_deinit((WWindow
*)rw
);
307 /*{{{ region dynfun implementations */
310 static void rootwin_do_set_focus(WRootWin
*rootwin
, bool warp
)
314 sub
=REGION_ACTIVE_SUB(rootwin
);
316 if(sub
==NULL
|| !REGION_IS_MAPPED(sub
)){
318 FOR_ALL_SCREENS(scr
){
319 if(REGION_IS_MAPPED(scr
)){
327 region_do_set_focus(sub
, warp
);
329 window_do_set_focus((WWindow
*)rootwin
, warp
);
333 static bool rootwin_fitrep(WRootWin
*rootwin
, WWindow
*par
,
334 const WFitParams
*fp
)
336 D(warn("Don't know how to reparent or fit root windows."));
341 static void rootwin_map(WRootWin
*rootwin
)
343 D(warn("Attempt to map a root window."));
347 static void rootwin_unmap(WRootWin
*rootwin
)
349 D(warn("Attempt to unmap a root window -- impossible."));
353 static void rootwin_managed_remove(WRootWin
*rootwin
, WRegion
*reg
)
355 region_unset_manager(reg
, (WRegion
*)rootwin
);
358 static WRegion
*rootwin_managed_disposeroot(WRootWin
*rootwin
, WRegion
*reg
)
360 WScreen
*scr
=OBJ_CAST(reg
, WScreen
);
361 if(scr
!=NULL
&& scr
==scr
->prev_scr
){
362 warn(TR("Only screen may not be destroyed/detached."));
371 static Window
rootwin_x_window(WRootWin
*rootwin
)
373 return WROOTWIN_ROOT(rootwin
);
383 static bool scr_ok(WRegion
*r
)
385 return (OBJ_IS(r
, WScreen
) && REGION_IS_MAPPED(r
));
390 * Returns previously active screen on root window \var{rootwin}.
394 WScreen
*rootwin_current_scr(WRootWin
*rootwin
)
396 WRegion
*r
=REGION_ACTIVE_SUB(rootwin
);
399 /* There should be no non-WScreen as children or managed by us, but... */
401 if(r
!=NULL
&& scr_ok(r
))
404 FOR_ALL_SCREENS(scr
){
405 if(REGION_MANAGER(scr
)==(WRegion
*)rootwin
406 && REGION_IS_MAPPED(scr
)){
416 * Returns the first WRootWin
420 WRootWin
*ioncore_rootwin()
422 return ioncore_g
.rootwins
;
429 /*{{{ Dynamic function table and class implementation */
432 static DynFunTab rootwin_dynfuntab
[]={
433 {region_map
, rootwin_map
},
434 {region_unmap
, rootwin_unmap
},
435 {region_do_set_focus
, rootwin_do_set_focus
},
436 {(DynFun
*)region_xwindow
, (DynFun
*)rootwin_x_window
},
437 {(DynFun
*)region_fitrep
, (DynFun
*)rootwin_fitrep
},
438 {region_managed_remove
, rootwin_managed_remove
},
439 {(DynFun
*)region_managed_disposeroot
,
440 (DynFun
*)rootwin_managed_disposeroot
},
446 IMPLCLASS(WRootWin
, WWindow
, rootwin_deinit
, rootwin_dynfuntab
);