Add fake-xinerama, create test that tests spurious screens are removed
[notion/jeffpc.git] / mod_tiling / splitfloat.c
blob479045eb034a292367fb9c28b24d93e63d72b929
1 /*
2 * ion/mod_tiling/splitext.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
10 #include <limits.h>
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <ioncore/common.h>
14 #include <ioncore/global.h>
15 #include <ioncore/rootwin.h>
16 #include <ioncore/xwindow.h>
17 #include <ioncore/window.h>
19 #include "tiling.h"
20 #include "split.h"
21 #include "splitfloat.h"
22 #include "panehandle.h"
25 #define GEOM(X) (((WSplit*)(X))->geom)
28 /*{{{ Init/deinit */
31 static void splitfloat_set_borderlines(WSplitFloat *split)
33 int dir=split->ssplit.dir;
35 split->tlpwin->bline=(dir==SPLIT_HORIZONTAL
36 ? GR_BORDERLINE_RIGHT
37 : GR_BORDERLINE_BOTTOM);
39 split->brpwin->bline=(dir==SPLIT_HORIZONTAL
40 ? GR_BORDERLINE_LEFT
41 : GR_BORDERLINE_TOP);
45 bool splitfloat_init(WSplitFloat *split, const WRectangle *geom,
46 WTiling *ws, int dir)
48 WFitParams fp;
49 WWindow *par=REGION_PARENT(ws);
51 assert(par!=NULL);
53 fp.g=*geom;
54 fp.mode=REGION_FIT_EXACT;
55 split->tlpwin=create_panehandle(par, &fp);
56 if(split->tlpwin==NULL)
57 return FALSE;
59 fp.g=*geom;
60 fp.mode=REGION_FIT_EXACT;
61 split->brpwin=create_panehandle(par, &fp);
62 if(split->brpwin==NULL){
63 destroy_obj((Obj*)split->tlpwin);
64 return FALSE;
67 ((WRegion*)split->brpwin)->flags|=REGION_SKIP_FOCUS;
68 ((WRegion*)split->tlpwin)->flags|=REGION_SKIP_FOCUS;
70 if(!splitsplit_init(&(split->ssplit), geom, dir)){
71 destroy_obj((Obj*)split->brpwin);
72 destroy_obj((Obj*)split->tlpwin);
73 return FALSE;
76 split->tlpwin->splitfloat=split;
77 split->brpwin->splitfloat=split;
79 splitfloat_set_borderlines(split);
81 if(REGION_IS_MAPPED(ws)){
82 region_map((WRegion*)(split->tlpwin));
83 region_map((WRegion*)(split->brpwin));
86 return TRUE;
90 WSplitFloat *create_splitfloat(const WRectangle *geom, WTiling *ws, int dir)
92 CREATEOBJ_IMPL(WSplitFloat, splitfloat, (p, geom, ws, dir));
96 void splitfloat_deinit(WSplitFloat *split)
98 if(split->tlpwin!=NULL){
99 WPaneHandle *tmp=split->tlpwin;
100 split->tlpwin=NULL;
101 tmp->splitfloat=NULL;
102 destroy_obj((Obj*)tmp);
105 if(split->brpwin!=NULL){
106 WPaneHandle *tmp=split->brpwin;
107 split->brpwin=NULL;
108 tmp->splitfloat=NULL;
109 destroy_obj((Obj*)tmp);
112 splitsplit_deinit(&(split->ssplit));
116 /*}}}*/
119 /*{{{ X window handling */
122 static void stack_stacking_reg(WRegion *reg,
123 Window *bottomret, Window *topret)
125 Window b=None, t=None;
127 if(reg!=NULL){
128 region_stacking(reg, &b, &t);
129 if(*bottomret==None)
130 *bottomret=b;
131 if(t!=None)
132 *topret=t;
137 static void stack_stacking_split(WSplit *split,
138 Window *bottomret, Window *topret)
140 Window b=None, t=None;
142 if(split!=NULL){
143 split_stacking(split, &b, &t);
144 if(*bottomret==None)
145 *bottomret=b;
146 if(t!=None)
147 *topret=t;
152 static void splitfloat_stacking(WSplitFloat *split,
153 Window *bottomret, Window *topret)
155 *bottomret=None;
156 *topret=None;
158 if(split->ssplit.current!=SPLIT_CURRENT_TL){
159 stack_stacking_reg((WRegion*)split->tlpwin, bottomret, topret);
160 stack_stacking_split(split->ssplit.tl, bottomret, topret);
161 stack_stacking_reg((WRegion*)split->brpwin, bottomret, topret);
162 stack_stacking_split(split->ssplit.br, bottomret, topret);
163 }else{
164 stack_stacking_reg((WRegion*)split->brpwin, bottomret, topret);
165 stack_stacking_split(split->ssplit.br, bottomret, topret);
166 stack_stacking_reg((WRegion*)split->tlpwin, bottomret, topret);
167 stack_stacking_split(split->ssplit.tl, bottomret, topret);
172 static void stack_restack_reg(WRegion *reg, Window *other, int *mode)
174 Window b=None, t=None;
176 if(reg!=NULL){
177 region_restack(reg, *other, *mode);
178 region_stacking(reg, &b, &t);
179 if(t!=None){
180 *other=t;
181 *mode=Above;
187 static void stack_restack_split(WSplit *split, Window *other, int *mode)
189 Window b=None, t=None;
191 if(split!=NULL){
192 split_restack(split, *other, *mode);
193 split_stacking(split, &b, &t);
194 if(t!=None){
195 *other=t;
196 *mode=Above;
203 static void splitfloat_restack(WSplitFloat *split, Window other, int mode)
205 if(split->ssplit.current!=SPLIT_CURRENT_TL){
206 stack_restack_reg((WRegion*)split->tlpwin, &other, &mode);
207 stack_restack_split(split->ssplit.tl, &other, &mode);
208 stack_restack_reg((WRegion*)split->brpwin, &other, &mode);
209 stack_restack_split(split->ssplit.br, &other, &mode);
210 }else{
211 stack_restack_reg((WRegion*)split->brpwin, &other, &mode);
212 stack_restack_split(split->ssplit.br, &other, &mode);
213 stack_restack_reg((WRegion*)split->tlpwin, &other, &mode);
214 stack_restack_split(split->ssplit.tl, &other, &mode);
219 static void splitfloat_map(WSplitFloat *split)
221 region_map((WRegion*)(split->tlpwin));
222 region_map((WRegion*)(split->brpwin));
223 splitinner_forall((WSplitInner*)split, split_map);
227 static void splitfloat_unmap(WSplitFloat *split)
229 region_unmap((WRegion*)(split->tlpwin));
230 region_unmap((WRegion*)(split->brpwin));
231 splitinner_forall((WSplitInner*)split, split_unmap);
235 static void reparentreg(WRegion *reg, WWindow *target)
237 WRectangle g=REGION_GEOM(reg);
238 region_reparent(reg, target, &g, REGION_FIT_EXACT);
242 static void splitfloat_reparent(WSplitFloat *split, WWindow *target)
244 if(split->ssplit.current!=SPLIT_CURRENT_TL){
245 reparentreg((WRegion*)split->tlpwin, target);
246 split_reparent(split->ssplit.tl, target);
247 reparentreg((WRegion*)split->brpwin, target);
248 split_reparent(split->ssplit.br, target);
249 }else{
250 reparentreg((WRegion*)split->brpwin, target);
251 split_reparent(split->ssplit.br, target);
252 reparentreg((WRegion*)split->tlpwin, target);
253 split_reparent(split->ssplit.tl, target);
258 /*}}}*/
261 /*{{{ Geometry */
264 #define TL_BORDER(SF) ((SF)->ssplit.dir==SPLIT_VERTICAL \
265 ? (SF)->tlpwin->bdw.bottom \
266 : (SF)->tlpwin->bdw.right)
268 #define BR_BORDER(SF) ((SF)->ssplit.dir==SPLIT_VERTICAL \
269 ? (SF)->brpwin->bdw.top \
270 : (SF)->brpwin->bdw.left)
273 void splitfloat_tl_pwin_to_cnt(WSplitFloat *split, WRectangle *g)
275 if(split->ssplit.dir==SPLIT_HORIZONTAL)
276 g->w=maxof(1, g->w-split->tlpwin->bdw.right);
277 else
278 g->h=maxof(1, g->h-split->tlpwin->bdw.bottom);
282 void splitfloat_br_pwin_to_cnt(WSplitFloat *split, WRectangle *g)
284 if(split->ssplit.dir==SPLIT_HORIZONTAL){
285 int delta=split->tlpwin->bdw.left;
286 g->w=maxof(1, g->w-delta);
287 g->x+=delta;
288 }else{
289 int delta=split->tlpwin->bdw.top;
290 g->h=maxof(1, g->h-delta);
291 g->y+=delta;
296 void splitfloat_tl_cnt_to_pwin(WSplitFloat *split, WRectangle *g)
298 if(split->ssplit.dir==SPLIT_HORIZONTAL)
299 g->w=maxof(1, g->w+split->tlpwin->bdw.right);
300 else
301 g->h=maxof(1, g->h+split->tlpwin->bdw.bottom);
305 void splitfloat_br_cnt_to_pwin(WSplitFloat *split, WRectangle *g)
307 if(split->ssplit.dir==SPLIT_HORIZONTAL){
308 int delta=split->tlpwin->bdw.left;
309 g->w=maxof(1, g->w+delta);
310 g->x-=delta;
311 }else{
312 int delta=split->tlpwin->bdw.top;
313 g->h=maxof(1, g->h+delta);
314 g->y-=delta;
319 static int infadd(int x, int y)
321 return ((x==INT_MAX || y==INT_MAX) ? INT_MAX : (x+y));
325 static int splitfloat_get_handle(WSplitFloat *split, int dir,
326 WSplit *other)
328 assert(other==split->ssplit.tl || other==split->ssplit.br);
330 if(dir!=split->ssplit.dir)
331 return 0;
333 if(dir==SPLIT_VERTICAL){
334 if(other==split->ssplit.tl)
335 return split->tlpwin->bdw.right;
336 else if(other==split->ssplit.br)
337 return split->tlpwin->bdw.left;
338 }else{
339 if(other==split->ssplit.tl)
340 return split->tlpwin->bdw.bottom;
341 else if(other==split->ssplit.br)
342 return split->tlpwin->bdw.top;
345 return 0;
349 static int splitfloat_get_max(WSplitFloat *split, int dir, WSplit *other)
351 return infadd((dir==SPLIT_VERTICAL ? other->max_h : other->max_w),
352 splitfloat_get_handle(split, dir, other));
356 static int splitfloat_get_min(WSplitFloat *split, int dir, WSplit *other)
358 return ((dir==SPLIT_VERTICAL ? other->min_h : other->min_w)
359 +splitfloat_get_handle(split, dir, other));
363 static void splitfloat_update_bounds(WSplitFloat *split, bool recursive)
365 WSplit *tl=split->ssplit.tl, *br=split->ssplit.br;
366 WSplit *node=(WSplit*)split;
367 int tl_max_w, br_max_w, tl_max_h, br_max_h;
368 int tl_min_w, br_min_w, tl_min_h, br_min_h;
370 if(recursive){
371 split_update_bounds(tl, recursive);
372 split_update_bounds(br, recursive);
375 tl_max_w=splitfloat_get_max(split, SPLIT_HORIZONTAL, tl);
376 br_max_w=splitfloat_get_max(split, SPLIT_HORIZONTAL, br);
377 tl_max_h=splitfloat_get_max(split, SPLIT_VERTICAL, tl);
378 br_max_h=splitfloat_get_max(split, SPLIT_VERTICAL, br);
379 tl_min_w=splitfloat_get_min(split, SPLIT_HORIZONTAL, tl);
380 br_min_w=splitfloat_get_min(split, SPLIT_HORIZONTAL, br);
381 tl_min_h=splitfloat_get_min(split, SPLIT_VERTICAL, tl);
382 br_min_h=splitfloat_get_min(split, SPLIT_VERTICAL, br);
384 if(split->ssplit.dir==SPLIT_HORIZONTAL){
385 node->max_w=infadd(tl_max_w, br_max_w);
386 node->min_w=minof(tl_min_w, br_min_w);
387 node->unused_w=0;
388 node->min_h=maxof(tl_min_h, br_min_h);
389 node->max_h=maxof(minof(tl_max_h, br_max_h), node->min_h);
390 node->unused_h=minof(tl->unused_h, br->unused_h);
391 }else{
392 node->max_h=infadd(tl_max_h, br_max_h);
393 node->min_h=minof(tl_min_h, br_min_h);
394 node->unused_h=0;
395 node->min_w=maxof(tl_min_w, br_min_w);
396 node->max_w=maxof(minof(tl_max_w, br_max_w), node->min_w);
397 node->unused_w=minof(tl->unused_w, br->unused_w);
402 void splitfloat_update_handles(WSplitFloat *split, const WRectangle *tlg_,
403 const WRectangle *brg_)
405 WRectangle tlg=*tlg_, brg=*brg_;
407 if(split->ssplit.dir==SPLIT_HORIZONTAL){
408 tlg.w=split->tlpwin->bdw.right;
409 tlg.x=tlg_->x+tlg_->w-tlg.w;
410 brg.w=split->brpwin->bdw.left;
411 }else{
412 tlg.h=split->tlpwin->bdw.bottom;
413 tlg.y=tlg_->y+tlg_->h-tlg.h;
414 brg.h=split->brpwin->bdw.top;
417 region_fit((WRegion*)split->tlpwin, &tlg, REGION_FIT_EXACT);
418 region_fit((WRegion*)split->brpwin, &brg, REGION_FIT_EXACT);
422 static void bound(int *what, int min, int max)
424 if(*what<min)
425 *what=min;
426 else if(*what>max)
427 *what=max;
431 static void adjust_sizes(int *tls_, int *brs_, int nsize,
432 int tlmin, int brmin, int tlmax, int brmax,
433 int primn)
435 int tls=maxof(0, *tls_);
436 int brs=maxof(0, *brs_);
437 nsize=maxof(1, nsize);
439 if(primn==PRIMN_TL){
440 tls=maxof(1, nsize-brs);
441 bound(&tls, tlmin, tlmax);
442 brs=nsize-tls;
443 bound(&brs, brmin, brmax);
444 tls=nsize-brs;
445 bound(&tls, tlmin, tlmax);
446 }else if(primn==PRIMN_BR){
447 brs=maxof(1, nsize-tls);
448 bound(&brs, brmin, brmax);
449 tls=nsize-brs;
450 bound(&tls, tlmin, tlmax);
451 brs=nsize-tls;
452 bound(&brs, brmin, brmax);
453 }else{ /* && PRIMN_ANY */
454 tls=tls*nsize/maxof(2, tls+brs);
455 bound(&tls, tlmin, tlmax);
456 brs=nsize-tls;
457 bound(&brs, brmin, brmax);
458 tls=nsize-brs;
459 bound(&tls, tlmin, tlmax);
462 *tls_=tls;
463 *brs_=brs;
467 static void adjust_size(int *sz, int dir, WSplitFloat *f, WSplit *s)
469 int mi=splitfloat_get_min(f, dir, s);
470 int ma=splitfloat_get_max(f, dir, s);
471 *sz=maxof(mi, minof(*sz, ma));
475 static void splitfloat_do_resize(WSplitFloat *split, const WRectangle *ng,
476 int hprimn, int vprimn, bool transpose)
478 WRectangle tlg=GEOM(split->ssplit.tl);
479 WRectangle brg=GEOM(split->ssplit.br);
480 WRectangle ntlg=*ng, nbrg=*ng;
481 WRectangle *og=&((WSplit*)split)->geom;
482 int dir=split->ssplit.dir;
483 bool adjust=TRUE;
485 splitfloat_tl_cnt_to_pwin(split, &tlg);
486 splitfloat_br_cnt_to_pwin(split, &brg);
488 if(transpose){
489 if(dir==SPLIT_VERTICAL){
490 dir=SPLIT_HORIZONTAL;
491 split->tlpwin->bline=GR_BORDERLINE_RIGHT;
492 split->brpwin->bline=GR_BORDERLINE_LEFT;
493 }else{
494 dir=SPLIT_VERTICAL;
495 split->tlpwin->bline=GR_BORDERLINE_BOTTOM;
496 split->brpwin->bline=GR_BORDERLINE_TOP;
498 split->ssplit.dir=dir;
501 if(dir==SPLIT_VERTICAL){
502 if(ng->h<=tlg.h+brg.h){
503 if(transpose){
504 ntlg.h=minof(tlg.w, ng->h*2/3);
505 nbrg.h=minof(brg.w, ng->h*2/3);
506 adjust_size(&ntlg.h, dir, split, split->ssplit.tl);
507 adjust_size(&nbrg.h, dir, split, split->ssplit.br);
508 adjust=(ng->h>ntlg.h+nbrg.h);
509 }else{
510 ntlg.h=minof(ng->h, tlg.h);
511 nbrg.h=minof(ng->h, brg.h);
512 adjust=FALSE;
514 }else{
515 ntlg.h=tlg.h;
516 nbrg.h=brg.h;
519 if(adjust){
520 adjust_sizes(&ntlg.h, &nbrg.h, ng->h,
521 splitfloat_get_min(split, dir, split->ssplit.tl),
522 splitfloat_get_min(split, dir, split->ssplit.br),
523 splitfloat_get_max(split, dir, split->ssplit.tl),
524 splitfloat_get_max(split, dir, split->ssplit.br),
525 vprimn);
528 nbrg.y=ng->y+ng->h-nbrg.h;
529 }else{
530 if(ng->w<=tlg.w+brg.w){
531 if(transpose){
532 ntlg.w=minof(tlg.h, ng->w*2/3);
533 nbrg.w=minof(brg.h, ng->w*2/3);
534 adjust_size(&ntlg.w, dir, split, split->ssplit.tl);
535 adjust_size(&nbrg.w, dir, split, split->ssplit.br);
536 adjust=(ng->w>ntlg.w+nbrg.w);
537 }else{
538 ntlg.w=minof(ng->w, tlg.w);
539 nbrg.w=minof(ng->w, brg.w);
540 adjust=FALSE;
542 }else{
543 ntlg.w=tlg.w;
544 nbrg.w=brg.w;
547 if(adjust){
548 adjust_sizes(&ntlg.w, &nbrg.w, ng->w,
549 splitfloat_get_min(split, dir, split->ssplit.tl),
550 splitfloat_get_min(split, dir, split->ssplit.br),
551 splitfloat_get_max(split, dir, split->ssplit.tl),
552 splitfloat_get_max(split, dir, split->ssplit.br),
553 hprimn);
556 nbrg.x=ng->x+ng->w-nbrg.w;
559 GEOM(split)=*ng;
561 splitfloat_update_handles(split, &ntlg, &nbrg);
563 splitfloat_tl_pwin_to_cnt(split, &ntlg);
564 split_do_resize(split->ssplit.tl, &ntlg, hprimn, vprimn, transpose);
565 splitfloat_br_pwin_to_cnt(split, &nbrg);
566 split_do_resize(split->ssplit.br, &nbrg, hprimn, vprimn, transpose);
570 static void calc_amount(int *amount, int *oamount,
571 int rs, WSplitSplit *p, int omax,
572 const WRectangle *ng, const WRectangle *og)
574 *oamount=0;
576 if(rs>=0){
577 if(p->dir==SPLIT_VERTICAL)
578 *amount=maxof(0, minof(rs, GEOM(p).h-ng->h));
579 else
580 *amount=maxof(0, minof(rs, GEOM(p).w-ng->w));
581 }else{
582 if(p->dir==SPLIT_VERTICAL){
583 int overlap=maxof(0, og->h-(GEOM(p).h-ng->h));
584 *amount=-minof(-rs, overlap);
585 *oamount=maxof(0, minof(*amount-rs, omax-og->h));
586 *amount-=*oamount;
587 }else{
588 int overlap=maxof(0, og->w-(GEOM(p).w-ng->w));
589 *amount=-minof(-rs, overlap);
590 *oamount=maxof(0, minof(*amount-rs, omax-og->w));
591 *amount-=*oamount;
597 static void splitfloat_do_rqsize(WSplitFloat *split, WSplit *node,
598 RootwardAmount *ha, RootwardAmount *va,
599 WRectangle *rg, bool tryonly)
601 int hprimn=PRIMN_ANY, vprimn=PRIMN_ANY;
602 WRectangle pg, og, ng, nog, nng;
603 RootwardAmount *ca;
604 WSplit *other;
605 int amount=0, oamount=0, omax;
606 int thisnode;
607 WSplitSplit *p=&(split->ssplit);
609 assert(!ha->any || ha->tl==0);
610 assert(!va->any || va->tl==0);
611 assert(p->tl==node || p->br==node);
613 if(p->tl==node){
614 other=p->br;
615 thisnode=PRIMN_TL;
616 }else{
617 other=p->tl;
618 thisnode=PRIMN_BR;
621 ng=GEOM(node);
622 og=GEOM(other);
624 if(thisnode==PRIMN_TL){
625 splitfloat_tl_cnt_to_pwin(split, &ng);
626 splitfloat_br_cnt_to_pwin(split, &og);
627 }else{
628 splitfloat_br_cnt_to_pwin(split, &ng);
629 splitfloat_tl_cnt_to_pwin(split, &og);
632 ca=(p->dir==SPLIT_VERTICAL ? va : ha);
634 omax=splitfloat_get_max(split, p->dir, other);
636 if(thisnode==PRIMN_TL || ca->any){
637 calc_amount(&amount, &oamount, ca->br, p, omax, &ng, &og);
638 ca->br-=amount;
639 }else/*if(thisnode==PRIMN_BR)*/{
640 calc_amount(&amount, &oamount, ca->tl, p, omax, &ng, &og);
641 ca->tl-=amount;
644 if(((WSplit*)p)->parent==NULL /*||
645 (ha->tl==0 && ha->br==0 && va->tl==0 && va->br==0)*/){
646 pg=((WSplit*)p)->geom;
647 }else{
648 splitinner_do_rqsize(((WSplit*)p)->parent, (WSplit*)p, ha, va,
649 &pg, tryonly);
652 assert(pg.w>=0 && pg.h>=0);
654 nog=pg;
655 nng=pg;
657 if(p->dir==SPLIT_VERTICAL){
658 nog.h=minof(pg.h, maxof(0, og.h+oamount));
659 nng.h=minof(pg.h, maxof(0, ng.h+amount+pg.h-GEOM(p).h));
660 if(thisnode==PRIMN_TL)
661 nog.y=pg.y+pg.h-nog.h;
662 else
663 nng.y=pg.y+pg.h-nng.h;
664 vprimn=thisnode;
665 }else{
666 nog.w=minof(pg.w, maxof(0, og.w+oamount));
667 nng.w=minof(pg.w, maxof(0, ng.w+amount+pg.w-GEOM(p).w));
668 if(thisnode==PRIMN_TL)
669 nog.x=pg.x+pg.w-nog.w;
670 else
671 nng.x=pg.x+pg.w-nng.w;
672 hprimn=thisnode;
675 if(!tryonly){
676 GEOM(p)=pg;
678 if(thisnode==PRIMN_TL){
679 splitfloat_update_handles(split, &nng, &nog);
680 splitfloat_br_pwin_to_cnt(split, &nog);
681 }else{
682 splitfloat_update_handles(split, &nog, &nng);
683 splitfloat_tl_pwin_to_cnt(split, &nog);
686 /* Entä jos 'other' on stdisp? */
687 split_do_resize(other, &nog, hprimn, vprimn, FALSE);
690 *rg=nng;
691 if(thisnode==PRIMN_TL)
692 splitfloat_tl_pwin_to_cnt(split, rg);
693 else
694 splitfloat_br_pwin_to_cnt(split, rg);
698 void splitfloat_flip(WSplitFloat *split)
700 WRectangle tlg, brg;
702 splitsplit_flip_default(&split->ssplit);
704 tlg=split->ssplit.tl->geom;
705 brg=split->ssplit.br->geom;
707 splitfloat_tl_cnt_to_pwin(split, &tlg);
708 splitfloat_br_cnt_to_pwin(split, &brg);
709 splitfloat_update_handles(split, &tlg, &brg);
713 /*}}}*/
716 /*{{{ Loading code */
719 #define MINS 8
721 static void adjust_tls_brs(int *tls, int *brs, int total)
723 if(*tls<=0)
724 *tls=MINS;
725 if(*brs<=0)
726 *brs=MINS;
728 if(*tls+*brs<total){
729 *tls=total*(*tls)/(*tls+*brs);
730 *brs=total-(*tls);
733 *tls=minof(maxof(MINS, *tls), total);
734 *brs=minof(maxof(MINS, *brs), total);
738 static void calc_tlg_brg(const WRectangle *geom, int tls, int brs, int dir,
739 WRectangle *tlg, WRectangle *brg)
741 *tlg=*geom;
742 *brg=*geom;
744 if(dir==SPLIT_HORIZONTAL){
745 adjust_tls_brs(&tls, &brs, geom->w);
746 tlg->w=tls;
747 brg->w=brs;
748 brg->x=geom->x+geom->w-brs;
749 }else{
750 adjust_tls_brs(&tls, &brs, geom->h);
751 tlg->h=tls;
752 brg->h=brs;
753 brg->y=geom->y+geom->h-brs;
758 WSplit *load_splitfloat(WTiling *ws, const WRectangle *geom, ExtlTab tab)
760 WSplit *tl=NULL, *br=NULL;
761 WSplitFloat *split;
762 char *dir_str;
763 int dir, brs, tls;
764 ExtlTab subtab;
765 WRectangle tlg, brg;
766 int set=0;
768 set+=(extl_table_gets_i(tab, "tls", &tls)==TRUE);
769 set+=(extl_table_gets_i(tab, "brs", &brs)==TRUE);
770 set+=(extl_table_gets_s(tab, "dir", &dir_str)==TRUE);
772 if(set!=3)
773 return NULL;
775 if(strcmp(dir_str, "vertical")==0){
776 dir=SPLIT_VERTICAL;
777 }else if(strcmp(dir_str, "horizontal")==0){
778 dir=SPLIT_HORIZONTAL;
779 }else{
780 warn(TR("Invalid direction."));
781 free(dir_str);
782 return NULL;
784 free(dir_str);
786 split=create_splitfloat(geom, ws, dir);
787 if(split==NULL)
788 return NULL;
790 if(!extl_table_is_bool_set(tab, "tls_brs_incl_handles")){
791 if(split->ssplit.dir==SPLIT_HORIZONTAL){
792 tls+=split->tlpwin->bdw.right;
793 brs+=split->brpwin->bdw.left;
794 }else{
795 tls+=split->tlpwin->bdw.bottom;
796 brs+=split->brpwin->bdw.top;
800 calc_tlg_brg(geom, tls, brs, dir, &tlg, &brg);
802 splitfloat_update_handles(split, &tlg, &brg);
804 if(extl_table_gets_t(tab, "tl", &subtab)){
805 WRectangle g=tlg;
806 splitfloat_tl_pwin_to_cnt(split, &g);
807 tl=tiling_load_node(ws, &g, subtab);
808 extl_unref_table(subtab);
811 if(extl_table_gets_t(tab, "br", &subtab)){
812 WRectangle g;
813 if(tl==NULL){
814 g=*geom;
815 }else{
816 g=brg;
817 splitfloat_br_pwin_to_cnt(split, &g);
819 br=tiling_load_node(ws, &g, subtab);
820 extl_unref_table(subtab);
823 if(tl==NULL || br==NULL){
824 destroy_obj((Obj*)split);
825 if(tl!=NULL){
826 split_do_resize(tl, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
827 return tl;
829 if(br!=NULL){
830 split_do_resize(br, geom, PRIMN_ANY, PRIMN_ANY, FALSE);
831 return br;
833 return NULL;
836 tl->parent=(WSplitInner*)split;
837 br->parent=(WSplitInner*)split;
839 split->ssplit.tl=tl;
840 split->ssplit.br=br;
842 return (WSplit*)split;
846 /*}}}*/
849 /*{{{ Split */
852 WSplitRegion *splittree_split_floating(WSplit *node, int dir, int primn,
853 int nmins, WRegionSimpleCreateFn *fn,
854 WTiling *ws)
856 WSplitFloat *sf;
857 int omins, mins;
858 int sn, so, s, rs;
859 int bn, bo;
860 WRectangle gn, go, gnc, goc;
861 WFitParams fp;
862 WRegion *nreg;
863 WSplitRegion *nnode;
864 WSplitInner *psplit;
866 if(primn!=PRIMN_TL && primn!=PRIMN_BR)
867 primn=PRIMN_BR;
869 split_update_bounds(split_find_root(node), TRUE);
871 sf=create_splitfloat(&node->geom, ws, dir);
873 if(sf==NULL)
874 return NULL;
876 omins=(dir==SPLIT_VERTICAL ? node->min_h : node->min_w);
877 s=split_size(node, dir);
879 if(primn==PRIMN_BR){
880 bn=BR_BORDER(sf);
881 bo=TL_BORDER(sf);
882 }else{
883 bn=TL_BORDER(sf);
884 bo=BR_BORDER(sf);
887 mins=maxof(omins+bo, nmins+bn);
889 /* Potentially resize old node. */
891 splittree_begin_resize();
893 if(mins>s){
894 WRectangle ng=node->geom, rg;
895 if(dir==SPLIT_VERTICAL)
896 ng.h=mins;
897 else
898 ng.w=mins;
900 split_do_rqgeom_(node, &ng, TRUE, TRUE, &rg, TRUE);
901 rs=(dir==SPLIT_VERTICAL ? rg.h : rg.w);
902 if(rs<mins){
903 warn(TR("Unable to split: not enough free space."));
904 destroy_obj((Obj*)sf);
905 return NULL;
907 split_do_rqgeom_(node, &ng, TRUE, TRUE, &rg, FALSE);
908 s=split_size(node, dir);
909 }else{
910 splittree_scan_stdisp_rootward(node);
913 /* Calculate geometries. */
915 sn=maxof(nmins+bn, s/2);
916 so=maxof(omins+bo, s-s/2);
918 ((WSplit*)sf)->geom=node->geom;
920 if(primn==PRIMN_TL){
921 calc_tlg_brg(&(node->geom), sn, so, dir, &gn, &go);
922 splitfloat_update_handles(sf, &gn, &go);
923 gnc=gn; splitfloat_tl_pwin_to_cnt(sf, &gnc);
924 goc=go; splitfloat_br_pwin_to_cnt(sf, &goc);
925 }else{
926 calc_tlg_brg(&(node->geom), so, sn, dir, &go, &gn);
927 splitfloat_update_handles(sf, &go, &gn);
928 goc=go; splitfloat_tl_pwin_to_cnt(sf, &goc);
929 gnc=gn; splitfloat_br_pwin_to_cnt(sf, &gnc);
932 /* Create the region. */
934 fp.mode=REGION_FIT_EXACT;
935 fp.g=gnc;
937 nreg=fn(REGION_PARENT(ws), &fp);
939 if(nreg==NULL){
940 destroy_obj((Obj*)sf);
941 return NULL;
944 nnode=create_splitregion(&(fp.g), nreg);
945 if(nnode==NULL){
946 destroy_obj((Obj*)nreg);
947 destroy_obj((Obj*)sf);
948 return NULL;
951 /* Now that everything's ok, resize and move original node. */
953 split_do_resize(node, &goc,
954 (dir==SPLIT_HORIZONTAL ? primn : PRIMN_ANY),
955 (dir==SPLIT_VERTICAL ? primn : PRIMN_ANY),
956 FALSE);
958 /* Set up split structure. */
960 psplit=node->parent;
962 if(psplit!=NULL)
963 splitinner_replace(psplit, node, (WSplit*)sf);
964 else
965 splittree_changeroot(node, (WSplit*)sf);
967 node->parent=(WSplitInner*)sf;
968 ((WSplit*)nnode)->parent=(WSplitInner*)sf;
970 if(primn==PRIMN_BR){
971 sf->ssplit.tl=node;
972 sf->ssplit.br=(WSplit*)nnode;
973 }else{
974 sf->ssplit.tl=(WSplit*)nnode;
975 sf->ssplit.br=node;
978 /*splittree_end_resize();*/
980 return nnode;
984 /*}}}*/
987 /*{{{ The class */
990 static DynFunTab splitfloat_dynfuntab[]={
991 {split_update_bounds, splitfloat_update_bounds},
992 {split_do_resize, splitfloat_do_resize},
993 {splitinner_do_rqsize, splitfloat_do_rqsize},
994 {split_stacking, splitfloat_stacking},
995 {split_restack, splitfloat_restack},
996 {split_reparent, splitfloat_reparent},
997 {split_map, splitfloat_map},
998 {split_unmap, splitfloat_unmap},
999 {splitsplit_flip, splitfloat_flip},
1000 END_DYNFUNTAB,
1004 EXTL_EXPORT
1005 IMPLCLASS(WSplitFloat, WSplitSplit, splitfloat_deinit, splitfloat_dynfuntab);
1008 /*}}}*/