2 * ion/mod_panews/placement.h
4 * Copyright (c) Tuomo Valkonen 1999-2005.
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.
16 #include <libtu/minmax.h>
17 #include <libtu/objp.h>
18 #include <libextl/extl.h>
19 #include <libmainloop/defer.h>
21 #include <ioncore/common.h>
22 #include <ioncore/global.h>
23 #include <ioncore/clientwin.h>
24 #include <ioncore/attach.h>
25 #include <ioncore/manage.h>
26 #include <ioncore/framep.h>
27 #include <ioncore/names.h>
28 #include <ioncore/region-iter.h>
29 #include <ioncore/resize.h>
30 #include <mod_ionws/split.h>
31 #include <mod_ionws/split-stdisp.h>
32 #include "placement.h"
35 #include "unusedwin.h"
38 WHook
*panews_init_layout_alt
=NULL
;
39 WHook
*panews_make_placement_alt
=NULL
;
42 /*{{{ create_frame_for */
45 static WFrame
*create_frame_for(WPaneWS
*ws
, WRegion
*reg
)
47 WWindow
*par
=REGION_PARENT(ws
);
56 fp
.mode
=REGION_FIT_BOUNDS
;
58 frame
=(WFrame
*)ws
->ionws
.create_frame_fn(par
, &fp
);
63 frame
->flags
|=FRAME_DEST_EMPTY
;
65 mplex_managed_geom((WMPlex
*)frame
, &mg
);
67 fp
.g
.w
=REGION_GEOM(reg
).w
+(REGION_GEOM(frame
).w
-mg
.w
);
68 fp
.g
.h
=REGION_GEOM(reg
).h
+(REGION_GEOM(frame
).h
-mg
.h
);
69 fp
.mode
=REGION_FIT_EXACT
;
71 region_fitrep((WRegion
*)frame
, NULL
, &fp
);
73 return (WFrame
*)frame
;
80 /*{{{ Placement scan */
83 static bool mrsh_layout_extl(ExtlFn fn
, WPaneWSPlacementParams
*p
)
85 ExtlTab t
=extl_create_table();
88 extl_table_sets_o(t
, "ws", (Obj
*)p
->ws
);
89 extl_table_sets_o(t
, "frame", (Obj
*)p
->frame
);
90 extl_table_sets_o(t
, "reg", (Obj
*)p
->reg
);
91 extl_table_sets_o(t
, "specifier", (Obj
*)p
->specifier
);
93 extl_call(fn
, "t", "b", t
, &ret
);
98 extl_table_gets_i(t
, "res_w", &(p
->res_w
));
99 extl_table_gets_i(t
, "res_h", &(p
->res_h
));
101 if(extl_table_gets_o(t
, "res_node", (Obj
**)&(p
->res_node
))){
102 if(OBJ_IS(p
->res_node
, WSplitUnused
)){
103 if(!extl_table_gets_t(t
, "res_config", &(p
->res_config
))){
104 warn(TR("Malfunctioning placement hook; condition #%d."), 1);
107 }else if(!OBJ_IS(p
->res_node
, WSplitRegion
)){
108 warn(TR("Malfunctioning placement hook; condition #%d."), 2);
125 static bool plainregionfilter(WSplit
*node
)
127 return (strcmp(OBJ_TYPESTR(node
), "WSplitRegion")==0);
131 static bool fallback_filter(WSplit
*node
)
133 return (OBJ_IS(node
, WSplitUnused
) || plainregionfilter(node
));
137 static bool fallback_layout(WPaneWSPlacementParams
*p
)
139 if(p
->ws
->ionws
.split_tree
==NULL
)
142 if(p
->specifier
!=NULL
){
143 p
->res_node
=(WSplit
*)p
->specifier
;
145 p
->res_node
=split_current_todir(p
->ws
->ionws
.split_tree
, SPLIT_ANY
,
146 PRIMN_ANY
, fallback_filter
);
149 if(p
->res_node
!=NULL
&& OBJ_IS(p
->res_node
, WSplitUnused
)){
150 p
->res_config
=extl_create_table();
151 if(p
->res_config
==extl_table_none() || p
->frame
==NULL
)
153 extl_table_sets_o(p
->res_config
, "reg", (Obj
*)(p
->frame
));
156 return (p
->res_node
!=NULL
);
163 /*{{{ Split/replace unused code */
166 static bool do_replace(WPaneWS
*ws
, WFrame
*frame
, WRegion
*reg
,
167 WPaneWSPlacementParams
*rs
)
169 WSplit
*u
=rs
->res_node
;
170 WSplit
*node
=ionws_load_node(&(ws
->ionws
), &(u
->geom
), rs
->res_config
);
172 assert(OBJ_IS(u
, WSplitUnused
));
175 warn(TR("Malfunctioning placement hook; condition #%d."), 3);
179 if(REGION_MANAGER(frame
)!=(WRegion
*)ws
){
180 warn(TR("Malfunctioning placement hook; condition #%d."), 4);
181 destroy_obj((Obj
*)node
);
186 splitinner_replace(u
->parent
, u
, node
);
188 splittree_changeroot((WSplit
*)u
, node
);
191 mainloop_defer_destroy((Obj
*)u
);
193 if(ws
->ionws
.stdispnode
!=NULL
)
194 split_regularise_stdisp(ws
->ionws
.stdispnode
);
196 if(ws
->ionws
.split_tree
!=NULL
)
197 split_restack(ws
->ionws
.split_tree
, ((WGenWS
*)ws
)->dummywin
, Above
);
205 /*{{{ The main dynfun */
208 static bool current_unused(WPaneWS
*ws
)
210 return OBJ_IS(ionws_current(&ws
->ionws
), WUnusedWin
);
214 static WRegion
*panews_get_target(WPaneWS
*ws
, WSplitUnused
*specifier
,
217 WRegion
*target
=NULL
;
218 WFrame
*frame
=create_frame_for(ws
, reg
);
219 WSplit
**tree
=&(ws
->ionws
.split_tree
);
220 WPaneWSPlacementParams rs
;
222 assert(ws
->ionws
.split_tree
!=NULL
);
227 rs
.specifier
=specifier
;
229 rs
.res_config
=extl_table_none();
234 split_update_bounds(*tree
, TRUE
);
236 assert(panews_make_placement_alt
!=NULL
);
238 hook_call_p(panews_make_placement_alt
, &rs
,
239 (WHookMarshallExtl
*)mrsh_layout_extl
);
242 if(rs
.res_node
==NULL
&& specifier
==NULL
)
243 fallback_layout(&rs
);
245 if(rs
.res_node
!=NULL
){
247 if(rs
.res_w
>0 || rs
.res_h
>0){
248 WRectangle grq
=rs
.res_node
->geom
;
249 int gflags
=REGION_RQGEOM_WEAK_ALL
;
253 gflags
&=~REGION_RQGEOM_WEAK_W
;
258 gflags
&=~REGION_RQGEOM_WEAK_H
;
261 splittree_rqgeom(rs
.res_node
, gflags
, &grq
, NULL
);
264 if(OBJ_IS(rs
.res_node
, WSplitUnused
)){
266 if(do_replace(ws
, frame
, reg
, &rs
))
267 target
=(WRegion
*)frame
;
270 assert(OBJ_IS(rs
.res_node
, WSplitRegion
));
271 target
=((WSplitRegion
*)rs
.res_node
)->reg
;
274 extl_unref_table(rs
.res_config
);
277 if(frame
!=NULL
&& target
!=(WRegion
*)frame
)
278 destroy_obj((Obj
*)frame
);
280 if(target
!=NULL
&& current_unused(ws
))
287 bool panews_manage_clientwin(WPaneWS
*ws
, WClientWin
*cwin
,
288 const WManageParams
*param
, int redir
)
290 WRegion
*target
=panews_get_target(ws
, NULL
, (WRegion
*)cwin
);
293 if(region_manage_clientwin(target
, cwin
, param
,
294 MANAGE_REDIR_PREFER_YES
)){
299 warn(TR("Ooops... could not find a region to attach client window to "
300 "on workspace %s."), region_name((WRegion
*)ws
));
305 bool panews_handle_unused_drop(WPaneWS
*ws
, WSplitUnused
*specifier
,
308 WRegion
*target
=panews_get_target(ws
, specifier
, reg
);
310 if(target
==NULL
|| !OBJ_IS(target
, WMPlex
))
313 return (mplex_attach_simple((WMPlex
*)target
, reg
,
314 MPLEX_ATTACH_SWITCHTO
)!=NULL
);