2 * ion/mod_panews/placement.h
4 * Copyright (c) Tuomo Valkonen 1999-2006.
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/resize.h>
29 #include <mod_tiling/split.h>
30 #include <mod_tiling/split-stdisp.h>
31 #include "placement.h"
34 #include "unusedwin.h"
37 WHook *panews_init_layout_alt=NULL;
38 WHook *panews_make_placement_alt=NULL;
41 /*{{{ create_frame_for */
44 static WFrame *create_frame_for(WPaneWS *ws, WRegion *reg)
46 WWindow *par=REGION_PARENT(ws);
55 fp.mode=REGION_FIT_BOUNDS;
57 frame=(WFrame*)ws->tiling.create_frame_fn(par, &fp);
62 frame->flags|=FRAME_DEST_EMPTY;
64 mplex_managed_geom((WMPlex*)frame, &mg);
66 fp.g.w=REGION_GEOM(reg).w+(REGION_GEOM(frame).w-mg.w);
67 fp.g.h=REGION_GEOM(reg).h+(REGION_GEOM(frame).h-mg.h);
68 fp.mode=REGION_FIT_EXACT;
70 region_fitrep((WRegion*)frame, NULL, &fp);
72 return (WFrame*)frame;
79 /*{{{ Placement scan */
82 static bool mrsh_layout_extl(ExtlFn fn, WPaneWSPlacementParams *p)
84 ExtlTab t=extl_create_table();
87 extl_table_sets_o(t, "ws", (Obj*)p->ws);
88 extl_table_sets_o(t, "frame", (Obj*)p->frame);
89 extl_table_sets_o(t, "reg", (Obj*)p->reg);
90 extl_table_sets_o(t, "specifier", (Obj*)p->specifier);
93 extl_call(fn, "t", "b", t, &ret);
99 extl_table_gets_i(t, "res_w", &(p->res_w));
100 extl_table_gets_i(t, "res_h", &(p->res_h));
102 if(extl_table_gets_o(t, "res_node", (Obj**)&(p->res_node))){
103 if(OBJ_IS(p->res_node, WSplitUnused)){
104 if(!extl_table_gets_t(t, "res_config", &(p->res_config))){
105 warn(TR("Malfunctioning placement hook; condition #%d."), 1);
108 }else if(!OBJ_IS(p->res_node, WSplitRegion)){
109 warn(TR("Malfunctioning placement hook; condition #%d."), 2);
126 static bool plainregionfilter(WSplit *node)
128 return (strcmp(OBJ_TYPESTR(node), "WSplitRegion")==0);
132 static bool fallback_filter(WSplit *node)
134 return (OBJ_IS(node, WSplitUnused) || plainregionfilter(node));
138 static bool fallback_layout(WPaneWSPlacementParams *p)
140 if(p->ws->tiling.split_tree==NULL)
143 if(p->specifier!=NULL){
144 p->res_node=(WSplit*)p->specifier;
146 p->res_node=split_current_todir(p->ws->tiling.split_tree, SPLIT_ANY,
147 PRIMN_ANY, fallback_filter);
150 if(p->res_node!=NULL && OBJ_IS(p->res_node, WSplitUnused)){
151 p->res_config=extl_create_table();
152 if(p->res_config==extl_table_none() || p->frame==NULL)
154 extl_table_sets_o(p->res_config, "reg", (Obj*)(p->frame));
157 return (p->res_node!=NULL);
164 /*{{{ Split/replace unused code */
167 static bool do_replace(WPaneWS *ws, WFrame *frame, WRegion *reg,
168 WPaneWSPlacementParams *rs)
170 WSplit *u=rs->res_node;
171 WSplit *node=tiling_load_node(&(ws->tiling), &(u->geom), rs->res_config);
173 assert(OBJ_IS(u, WSplitUnused));
176 warn(TR("Malfunctioning placement hook; condition #%d."), 3);
180 if(REGION_MANAGER(frame)!=(WRegion*)ws){
181 warn(TR("Malfunctioning placement hook; condition #%d."), 4);
182 destroy_obj((Obj*)node);
187 splitinner_replace(u->parent, u, node);
189 splittree_changeroot((WSplit*)u, node);
192 mainloop_defer_destroy((Obj*)u);
194 if(ws->tiling.stdispnode!=NULL)
195 split_regularise_stdisp(ws->tiling.stdispnode);
197 if(ws->tiling.split_tree!=NULL)
198 split_restack(ws->tiling.split_tree, ws->tiling.dummywin, Above);
206 /*{{{ The main dynfun */
209 static bool current_unused(WPaneWS *ws)
211 return OBJ_IS(tiling_current(&ws->tiling), WUnusedWin);
215 static WRegion *panews_get_target(WPaneWS *ws, WSplitUnused *specifier,
218 WRegion *target=NULL;
219 WFrame *frame=create_frame_for(ws, reg);
220 WSplit **tree=&(ws->tiling.split_tree);
221 WPaneWSPlacementParams rs;
223 assert(ws->tiling.split_tree!=NULL);
228 rs.specifier=specifier;
230 rs.res_config=extl_table_none();
235 split_update_bounds(*tree, TRUE);
237 assert(panews_make_placement_alt!=NULL);
239 hook_call_p(panews_make_placement_alt, &rs,
240 (WHookMarshallExtl*)mrsh_layout_extl);
243 if(rs.res_node==NULL && specifier==NULL)
244 fallback_layout(&rs);
246 if(rs.res_node!=NULL){
248 if(rs.res_w>0 || rs.res_h>0){
249 WRectangle grq=rs.res_node->geom;
250 int gflags=REGION_RQGEOM_WEAK_ALL;
254 gflags&=~REGION_RQGEOM_WEAK_W;
259 gflags&=~REGION_RQGEOM_WEAK_H;
262 splittree_rqgeom(rs.res_node, gflags, &grq, NULL);
265 if(OBJ_IS(rs.res_node, WSplitUnused)){
267 if(do_replace(ws, frame, reg, &rs))
268 target=(WRegion*)frame;
271 assert(OBJ_IS(rs.res_node, WSplitRegion));
272 target=((WSplitRegion*)rs.res_node)->reg;
275 extl_unref_table(rs.res_config);
278 if(frame!=NULL && target!=(WRegion*)frame)
279 destroy_obj((Obj*)frame);
281 if(target!=NULL && current_unused(ws))
288 WPHolder *panews_prepare_manage(WPaneWS *ws, const WClientWin *cwin,
289 const WManageParams *param, int redir)
291 WRegion *target=panews_get_target(ws, NULL, (WRegion*)cwin);
295 ph=region_prepare_manage(target, cwin, param, MANAGE_REDIR_PREFER_YES);
300 warn(TR("Ooops... could not find a region to attach client window to "
301 "on workspace %s."), region_name((WRegion*)ws));
306 bool panews_handle_unused_drop(WPaneWS *ws, WSplitUnused *specifier,
309 WRegion *target=panews_get_target(ws, specifier, reg);
311 if(target==NULL || !OBJ_IS(target, WMPlex))
314 return (mplex_attach_simple((WMPlex*)target, reg,
315 MPLEX_ATTACH_SWITCHTO)!=NULL);