2 * ion/panews/splitext.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 <ioncore/common.h>
17 #include <ioncore/global.h>
18 #include <ioncore/rootwin.h>
19 #include <ioncore/xwindow.h>
20 #include <ioncore/window.h>
21 #include <mod_tiling/split.h>
23 #include "unusedwin.h"
26 #define GEOM(X) (((WSplit*)(X))->geom)
32 bool splitunused_init(WSplitUnused *split, const WRectangle *geom,
35 WWindow *par=REGION_PARENT(ws);
42 fp.mode=REGION_FIT_EXACT;
44 uwin=create_unusedwin(par, &fp);
49 if(!splitregion_init(&(split->regnode), geom, (WRegion*)uwin)){
50 destroy_obj((Obj*)uwin);
54 if(!tiling_managed_add(&ws->tiling, (WRegion*)uwin)){
55 split->regnode.reg=NULL;
56 destroy_obj((Obj*)uwin);
64 WSplitUnused *create_splitunused(const WRectangle *geom, WPaneWS *ws)
66 CREATEOBJ_IMPL(WSplitUnused, splitunused, (p, geom, ws));
70 bool splitpane_init(WSplitPane *pane, const WRectangle *geom, WSplit *cnt)
75 if(!splitinner_init(&(pane->isplit), geom))
82 WSplitPane *create_splitpane(const WRectangle *geom, WSplit *cnt)
84 CREATEOBJ_IMPL(WSplitPane, splitpane, (p, geom, cnt));
88 void splitunused_deinit(WSplitUnused *split)
90 if(split->regnode.reg!=NULL){
91 destroy_obj((Obj*)split->regnode.reg);
92 split->regnode.reg=NULL;
95 splitregion_deinit(&(split->regnode));
99 void splitpane_deinit(WSplitPane *split)
101 if(split->contents!=NULL){
102 WSplit *tmp=split->contents;
103 split->contents=NULL;
105 destroy_obj((Obj*)tmp);
107 splitinner_deinit(&(split->isplit));
114 /*{{{ X window handling */
117 static void splitpane_stacking(WSplitPane *pane,
118 Window *bottomret, Window *topret)
124 if(pane->contents!=NULL)
125 split_stacking(pane->contents, bottomret, topret);
129 static void splitpane_restack(WSplitPane *pane, Window other, int mode)
131 if(pane->contents!=None)
132 split_restack(pane->contents, other, mode);
136 static void stack_restack_reg(WRegion *reg, Window *other, int *mode)
138 Window b=None, t=None;
141 region_restack(reg, *other, *mode);
142 region_stacking(reg, &b, &t);
151 static void stack_restack_split(WSplit *split, Window *other, int *mode)
153 Window b=None, t=None;
156 split_restack(split, *other, *mode);
157 split_stacking(split, &b, &t);
166 static void splitpane_reparent(WSplitPane *pane, WWindow *target)
168 if(pane->contents!=NULL)
169 split_reparent(pane->contents, target);
173 static void reparentreg(WRegion *reg, WWindow *target)
175 WRectangle g=REGION_GEOM(reg);
176 region_reparent(reg, target, &g, REGION_FIT_EXACT);
186 static void set_unused_bounds(WSplit *node)
192 node->unused_w=node->geom.w;
193 node->unused_h=node->geom.h;
197 static void copy_bounds(WSplit *dst, const WSplit *src)
199 dst->min_w=src->min_w;
200 dst->min_h=src->min_h;
201 dst->max_w=src->max_w;
202 dst->max_h=src->max_h;
203 dst->unused_w=src->unused_w;
204 dst->unused_h=src->unused_h;
208 static void splitunused_update_bounds(WSplitUnused *node, bool recursive)
210 set_unused_bounds((WSplit*)node);
214 static void splitpane_update_bounds(WSplitPane *node, bool recursive)
216 if(node->contents!=NULL){
218 split_update_bounds(node->contents, recursive);
219 copy_bounds((WSplit*)node, node->contents);
221 set_unused_bounds((WSplit*)node);
226 static int infadd(int x, int y)
228 return ((x==INT_MAX || y==INT_MAX) ? INT_MAX : (x+y));
232 static void splitpane_do_resize(WSplitPane *pane, const WRectangle *ng,
233 int hprimn, int vprimn, bool transpose)
235 if(transpose && pane->marker!=NULL){
236 char *growdir=strchr(pane->marker, ':');
238 const char *newdir=NULL;
241 if(strcmp(growdir, "right")==0)
243 else if(strcmp(growdir, "left")==0)
245 if(strcmp(growdir, "down")==0)
247 else if(strcmp(growdir, "up")==0)
251 char *newmarker=NULL;
253 libtu_asprintf(&newmarker, "%s:%s", pane->marker, newdir);
258 pane->marker=newmarker;
265 ((WSplit*)pane)->geom=*ng;
267 if(pane->contents!=NULL)
268 split_do_resize(pane->contents, ng, hprimn, vprimn, transpose);
272 static void splitpane_do_rqsize(WSplitPane *pane, WSplit *node,
273 RootwardAmount *ha, RootwardAmount *va,
274 WRectangle *rg, bool tryonly)
276 WSplitInner *par=((WSplit*)pane)->parent;
279 splitinner_do_rqsize(par, (WSplit*)pane, ha, va, rg, tryonly);
281 ((WSplit*)pane)->geom=*rg;
291 /*{{{ Tree manipulation */
294 static void splitpane_replace(WSplitPane *pane, WSplit *child, WSplit *what)
296 assert(child==pane->contents && what!=NULL);
300 what->parent=(WSplitInner*)pane;
301 what->ws_if_root=NULL; /* May not be needed */
305 static WPaneWS *find_ws(WSplit *split)
307 if(split->parent!=NULL)
308 return find_ws((WSplit*)split->parent);
310 if(split->ws_if_root!=NULL)
311 return OBJ_CAST(split->ws_if_root, WPaneWS);
317 static void splitpane_remove(WSplitPane *pane, WSplit *child,
320 WSplitInner *parent=((WSplit*)pane)->parent;
322 WPaneWS *ws=find_ws((WSplit*)pane);
324 assert(child==pane->contents);
330 && !OBJ_IS_BEING_DESTROYED(ws)
331 && !OBJ_IS_BEING_DESTROYED(pane)){
332 pane->contents=(WSplit*)create_splitunused(&GEOM(pane), ws);
333 if(pane->contents!=NULL){
334 pane->contents->parent=(WSplitInner*)pane;
340 splitinner_remove(parent, (WSplit*)pane, reclaim_space);
342 splittree_changeroot((WSplit*)pane, NULL);
344 destroy_obj((Obj*)pane);
351 /*{{{ Tree traversal */
354 static bool filter_any(WSplit *split)
356 return OBJ_IS(split, WSplitRegion);
360 static bool filter_no_unused(WSplit *split)
362 return (OBJ_IS(split, WSplitRegion)
363 && !OBJ_IS(split, WSplitUnused));
367 static bool filter_no_stdisp(WSplit *split)
369 return (OBJ_IS(split, WSplitRegion)
370 && !OBJ_IS(split, WSplitST));
374 static bool filter_no_stdisp_unused(WSplit *split)
376 return (OBJ_IS(split, WSplitRegion)
377 && !OBJ_IS(split, WSplitST)
378 && !OBJ_IS(split, WSplitUnused));
383 static WSplit *splitpane_current_todir(WSplitPane *pane, int dir, int primn,
384 WSplitFilter *filter)
388 if(pane->contents==NULL)
391 /* Try non-unused first */
392 if(filter==filter_no_stdisp){
393 ret=split_current_todir(pane->contents, dir, primn,
394 filter_no_stdisp_unused);
395 }else if(filter==filter_any){
396 ret=split_current_todir(pane->contents, dir, primn,
401 ret=split_current_todir(pane->contents, dir, primn, filter);
407 static void splitpane_forall(WSplitPane *pane, WSplitFn *fn)
409 if(pane->contents!=NULL)
414 static WSplit *splitpane_current(WSplitPane *pane)
416 return pane->contents;
420 static WSplitRegion *get_node_check(WPaneWS *ws, WRegion *reg)
427 node=splittree_node_of(reg);
429 if(node==NULL || REGION_MANAGER(reg)!=(WRegion*)ws)
436 static WSplitRegion *do_get_nextto(WSplit *node, int dir, int primn,
437 bool any, bool paneonly)
439 WSplitFilter *filter=(any ? filter_no_unused : filter_no_stdisp_unused);
442 while(node->parent!=NULL){
443 if(OBJ_IS(node, WSplitPane)){
446 filter=(any ? filter_any : filter_no_stdisp);
448 nextto=splitinner_nextto(node->parent, node, dir, primn, filter);
451 node=(WSplit*)(node->parent);
454 if(OBJ_IS(nextto, WSplitRegion))
455 return (WSplitRegion*)nextto;
460 WRegion *panews_do_get_nextto(WPaneWS *ws, WRegion *reg,
461 int dir, int primn, bool any)
463 WSplitRegion *node=get_node_check(ws, reg), *nextto=NULL;
468 nextto=do_get_nextto((WSplit*)node, dir, primn, TRUE, FALSE);
476 WRegion *panews_do_get_farthest(WPaneWS *ws,
477 int dir, int primn, bool any)
479 WSplitFilter *filter=(any ? filter_any : filter_no_stdisp);
481 if(ws->tiling.split_tree!=NULL)
482 node=split_current_todir(ws->tiling.split_tree, dir, primn, filter);
483 if(node!=NULL && OBJ_IS(node, WSplitRegion))
484 return ((WSplitRegion*)node)->reg;
489 WSplitRegion *split_tree_find_region_in_pane_of(WSplit *node)
491 return do_get_nextto(node, SPLIT_ANY, PRIMN_ANY, FALSE, TRUE);
498 /*{{{ Markers and other exports */
506 const char *splitpane_marker(WSplitPane *pane)
516 bool splitpane_set_marker(WSplitPane *pane, const char *s)
526 if(pane->marker==NULL)
536 * Get root of contained sub-split tree.
540 WSplit *splitpane_contents(WSplitPane *pane)
542 return pane->contents;
549 /*{{{ Save support */
552 static bool splitunused_get_config(WSplitUnused *node, ExtlTab *ret)
554 *ret=split_base_config((WSplit*)node);
559 static bool splitpane_get_config(WSplitPane *pane, ExtlTab *ret)
561 *ret=split_base_config((WSplit*)pane);
563 if(pane->contents!=NULL){
565 if(!split_get_config(pane->contents, &t)){
566 extl_unref_table(*ret);
569 extl_table_sets_t(*ret, "contents", t);
573 extl_table_sets_s(*ret, "marker", pane->marker);
585 static DynFunTab splitunused_dynfuntab[]={
586 {split_update_bounds, splitunused_update_bounds},
587 {(DynFun*)split_get_config, (DynFun*)splitunused_get_config},
592 static DynFunTab splitpane_dynfuntab[]={
593 {split_update_bounds, splitpane_update_bounds},
594 {split_do_resize, splitpane_do_resize},
595 {splitinner_do_rqsize, splitpane_do_rqsize},
596 {splitinner_replace, splitpane_replace},
597 {splitinner_remove, splitpane_remove},
598 {(DynFun*)split_current_todir, (DynFun*)splitpane_current_todir},
599 {(DynFun*)splitinner_current, (DynFun*)splitpane_current},
600 {(DynFun*)split_get_config, (DynFun*)splitpane_get_config},
601 {splitinner_forall, splitpane_forall},
602 {split_stacking, splitpane_stacking},
603 {split_restack, splitpane_restack},
604 {split_reparent, splitpane_reparent},
610 IMPLCLASS(WSplitUnused, WSplitRegion, splitunused_deinit, splitunused_dynfuntab);
613 IMPLCLASS(WSplitPane, WSplitInner, splitpane_deinit, splitpane_dynfuntab);