2 * ion/mod_panews/panews.c
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.
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libextl/extl.h>
17 #include <libmainloop/defer.h>
19 #include <ioncore/common.h>
20 #include <ioncore/global.h>
21 #include <ioncore/region.h>
22 #include <ioncore/focus.h>
23 #include <ioncore/manage.h>
24 #include <ioncore/saveload.h>
25 #include <ioncore/attach.h>
26 #include <ioncore/regbind.h>
27 #include <ioncore/extlconv.h>
28 #include <ioncore/frame.h>
29 #include <mod_tiling/tiling.h>
30 #include <mod_tiling/split.h>
32 #include "placement.h"
37 /*{{{ Create/destroy */
40 bool panews_managed_add(WPaneWS *ws, WRegion *reg)
42 if(OBJ_IS(reg, WFrame))
43 region_add_bindmap(reg, mod_panews_frame_bindmap);
45 return tiling_managed_add_default(&(ws->tiling), reg);
49 static WRegion *create_frame_panews(WWindow *parent, const WFitParams *fp)
51 return (WRegion*)create_frame(parent, fp, "frame-tiled-panews");
55 static bool mrsh_init_layout_extl(ExtlFn fn, WPaneWSInitParams *p)
57 ExtlTab t=extl_create_table();
60 extl_table_sets_o(t, "ws", (Obj*)p->ws);
63 ret=extl_call(fn, "t", "b", t, &ret);
67 ret=extl_table_gets_t(t, "layout", &(p->layout));
74 static bool panews_init_layout(WPaneWS *ws)
79 p.layout=extl_table_none();
81 hook_call_p(panews_init_layout_alt, &p,
82 (WHookMarshallExtl*)mrsh_init_layout_extl);
84 if(p.layout!=extl_table_none()){
85 ws->tiling.split_tree=tiling_load_node(&(ws->tiling),
88 extl_unref_table(p.layout);
91 if(ws->tiling.split_tree==NULL)
92 ws->tiling.split_tree=(WSplit*)create_splitunused(®ION_GEOM(ws), ws);
94 if(ws->tiling.split_tree!=NULL)
95 ws->tiling.split_tree->ws_if_root=&(ws->tiling);
97 return (ws->tiling.split_tree!=NULL);
101 bool panews_init(WPaneWS *ws, WWindow *parent, const WFitParams *fp,
104 if(!tiling_init(&(ws->tiling), parent, fp,
105 create_frame_panews, FALSE))
108 region_add_bindmap((WRegion*)ws, mod_panews_panews_bindmap);
110 assert(ws->tiling.split_tree==NULL);
113 if(!panews_init_layout(ws)){
123 WPaneWS *create_panews(WWindow *parent, const WFitParams *fp, bool cu)
125 CREATEOBJ_IMPL(WPaneWS, panews, (p, parent, fp, cu));
129 WPaneWS *create_panews_simple(WWindow *parent, const WFitParams *fp)
131 return create_panews(parent, fp, TRUE);
135 void panews_deinit(WPaneWS *ws)
137 tiling_deinit(&(ws->tiling));
141 static WSplitRegion *get_node_check(WPaneWS *ws, WRegion *reg)
148 node=splittree_node_of(reg);
150 if(node==NULL || REGION_MANAGER(reg)!=(WRegion*)ws)
157 static void panews_do_managed_remove(WPaneWS *ws, WRegion *reg)
159 tiling_do_managed_remove(&(ws->tiling), reg);
160 if(OBJ_IS(reg, WFrame))
161 region_remove_bindmap(reg, mod_panews_frame_bindmap);
165 static bool plainregionfilter(WSplit *node)
167 return (strcmp(OBJ_TYPESTR(node), "WSplitRegion")==0);
172 void panews_managed_remove(WPaneWS *ws, WRegion *reg)
174 bool ds=OBJ_IS_BEING_DESTROYED(ws);
175 bool act=REGION_IS_ACTIVE(reg);
176 bool mcf=region_may_control_focus((WRegion*)ws);
177 WSplitRegion *node=get_node_check(ws, reg);
180 other=tiling_do_get_nextto(&(ws->tiling), reg, SPLIT_ANY, PRIMN_ANY, FALSE);
182 panews_do_managed_remove(ws, reg);
184 if(node==(WSplitRegion*)(ws->tiling.stdispnode))
185 ws->tiling.stdispnode=NULL;
190 splittree_remove((WSplit*)node, !ds);
194 if(ws->tiling.split_tree==NULL){
195 warn(TR("Unable to re-initialise workspace. Destroying."));
196 mainloop_defer_destroy((Obj*)ws);
197 }else if(act && mcf){
198 /* We don't want to give the stdisp focus, even if one exists.
201 tiling_fallback_focus(&ws->tiling, FALSE);
203 }else if(act && mcf){
216 bool panews_managed_prepare_focus(WPaneWS *ws, WRegion *reg,
217 int flags, WPrepareFocusResult *res)
219 if(flags®ION_GOTO_ENTERWINDOW){
220 WSplitRegion *other, *node=get_node_check(ws, reg);
221 if(node!=NULL && OBJ_IS(node, WSplitUnused)){
222 /* An unused region - do not focus unless there are no
223 * normal regions in its pane.
225 other=split_tree_find_region_in_pane_of((WSplit*)node);
227 tiling_managed_prepare_focus(&(ws->tiling), other->reg,
228 flags&~REGION_GOTO_ENTERWINDOW,
235 return tiling_managed_prepare_focus(&(ws->tiling), reg, flags, res);
239 static bool filter_no_stdisp_unused(WSplit *split)
241 return (OBJ_IS(split, WSplitRegion)
242 && !OBJ_IS(split, WSplitST)
243 && !OBJ_IS(split, WSplitUnused));
247 bool panews_managed_may_destroy(WPaneWS *ws, WRegion *reg)
249 if(region_manager_allows_destroying((WRegion*)ws))
252 if(tiling_do_get_nextto(&(ws->tiling), reg,
253 SPLIT_ANY, PRIMN_ANY, FALSE)==NULL){
261 bool panews_may_destroy(WPaneWS *ws)
263 if(split_current_todir(ws->tiling.split_tree, SPLIT_ANY, PRIMN_ANY,
264 filter_no_stdisp_unused)!=NULL){
265 warn(TR("Refusing to close non-empty workspace."));
274 static WRegion *panews_rqclose_propagate(WPaneWS *ws, WRegion *sub)
276 WSplitRegion *node=NULL;
280 if(ws->tiling.split_tree!=NULL){
281 node=(WSplitRegion*)split_current_todir(ws->tiling.split_tree,
282 SPLIT_ANY, PRIMN_ANY,
283 filter_no_stdisp_unused);
286 mainloop_defer_destroy((Obj*)ws);
293 node=get_node_check(ws, sub);
299 return (region_rqclose(sub) ? sub : NULL);
310 ExtlTab panews_get_configuration(WPaneWS *ws)
312 return tiling_get_configuration(&(ws->tiling));
322 static WSplit *load_splitunused(WPaneWS *ws, const WRectangle *geom,
325 return (WSplit*)create_splitunused(geom, (WPaneWS*)ws);
329 static WSplit *load_splitpane(WPaneWS *ws, const WRectangle *geom, ExtlTab tab)
335 pane=create_splitpane(geom, NULL);
339 if(extl_table_gets_t(tab, "contents", &t)){
340 cnt=tiling_load_node(&(ws->tiling), geom, t);
343 cnt=load_splitunused(ws, geom, extl_table_none());
347 destroy_obj((Obj*)pane);
352 cnt->parent=&(pane->isplit);
354 assert(pane->marker==NULL);
355 extl_table_gets_s(tab, "marker", &(pane->marker));
357 return (WSplit*)pane;
361 static WSplit *panews_load_node(WPaneWS *ws, const WRectangle *geom,
366 if(!extl_table_gets_s(tab, "type", &s)){
368 /* Shortcuts for templates.lua */
369 if(extl_table_gets_o(tab, "reg", (Obj**)®)){
370 if(OBJ_IS(reg, WRegion))
371 return load_splitregion_doit(&(ws->tiling), geom, tab);
373 return load_splitunused(ws, geom, tab);
376 if(strcmp(s, "WSplitPane")==0)
377 return load_splitpane(ws, geom, tab);
378 else if(strcmp(s, "WSplitUnused")==0)
379 return load_splitunused(ws, geom, tab);
382 return tiling_load_node_default(&(ws->tiling), geom, tab);
386 WRegion *panews_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
391 ws=create_panews(par, fp, FALSE);
396 if(extl_table_gets_t(tab, "split_tree", &treetab)){
397 ws->tiling.split_tree=tiling_load_node(&(ws->tiling), ®ION_GEOM(ws),
399 extl_unref_table(treetab);
402 if(ws->tiling.split_tree==NULL){
403 if(!panews_init_layout(ws)){
404 destroy_obj((Obj*)ws);
409 ws->tiling.split_tree->ws_if_root=ws;
410 split_restack(ws->tiling.split_tree, ws->tiling.dummywin, Above);
419 /*{{{ Dynamic function table and class implementation */
422 static DynFunTab panews_dynfuntab[]={
423 {region_managed_remove,
424 panews_managed_remove},
426 {(DynFun*)region_prepare_manage,
427 (DynFun*)panews_prepare_manage},
429 {(DynFun*)region_get_configuration,
430 (DynFun*)panews_get_configuration},
432 {(DynFun*)region_may_destroy,
433 (DynFun*)panews_may_destroy},
435 {(DynFun*)region_managed_may_destroy,
436 (DynFun*)panews_managed_may_destroy},
438 {(DynFun*)tiling_managed_add,
439 (DynFun*)panews_managed_add},
441 {(DynFun*)tiling_load_node,
442 (DynFun*)panews_load_node},
444 {(DynFun*)tiling_do_get_nextto,
445 (DynFun*)panews_do_get_nextto},
447 {(DynFun*)tiling_do_get_farthest,
448 (DynFun*)panews_do_get_farthest},
450 {(DynFun*)region_managed_prepare_focus,
451 (DynFun*)panews_managed_prepare_focus},
454 {(DynFun*)region_rqclose_propagate,
455 (DynFun*)panews_rqclose_propagate},*/
462 IMPLCLASS(WPaneWS, WTiling, panews_deinit, panews_dynfuntab);