A final catch-all fallback when failing to load a font
[notion/jeffpc.git] / mod_tiling / split-stdisp.c
blob8c34579b17ab5aebc7f6bf3c18619c3ad2151531
1 /*
2 * ion/mod_tiling/split-stdisp.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <libtu/minmax.h>
10 #include <ioncore/common.h>
11 #include <ioncore/mplex.h>
12 #include <ioncore/resize.h>
13 #include "split.h"
14 #include "split-stdisp.h"
15 #include "tiling.h"
18 /*{{{ Helper routines */
21 #define STDISP_IS_HORIZONTAL(STDISP) \
22 ((STDISP)->orientation==REGION_ORIENTATION_HORIZONTAL)
24 #define STDISP_IS_VERTICAL(STDISP) \
25 ((STDISP)->orientation==REGION_ORIENTATION_VERTICAL)
27 #define STDISP_GROWS_L_TO_R(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
28 ((STDISP)->corner==MPLEX_STDISP_TL || \
29 (STDISP)->corner==MPLEX_STDISP_BL))
31 #define STDISP_GROWS_R_TO_L(STDISP) (STDISP_IS_HORIZONTAL(STDISP) && \
32 ((STDISP)->corner==MPLEX_STDISP_TR || \
33 (STDISP)->corner==MPLEX_STDISP_BR))
35 #define STDISP_GROWS_T_TO_B(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
36 ((STDISP)->corner==MPLEX_STDISP_TL || \
37 (STDISP)->corner==MPLEX_STDISP_TR))
39 #define STDISP_GROWS_B_TO_T(STDISP) (STDISP_IS_VERTICAL(STDISP) && \
40 ((STDISP)->corner==MPLEX_STDISP_BL || \
41 (STDISP)->corner==MPLEX_STDISP_BR))
43 #define GEOM(S) (((WSplit*)S)->geom)
45 #define IMPLIES(X, Y) (!(X) || (Y))
48 static int other_dir(int dir)
50 return (dir==SPLIT_VERTICAL ? SPLIT_HORIZONTAL : SPLIT_VERTICAL);
54 static void swap(int *x, int *y)
56 int z=*x;
57 *x=*y;
58 *y=z;
62 static void swapptr(WSplit **x, WSplit **y)
64 void *z=*x;
65 *x=*y;
66 *y=z;
70 static void swapgeom(WRectangle *g, WRectangle *h)
72 WRectangle tmp=*g;
73 *g=*h;
74 *h=tmp;
78 int stdisp_recommended_w(WSplitST *stdisp)
80 if(stdisp->regnode.reg==NULL)
81 return CF_STDISP_MIN_SZ;
83 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_HORIZONTAL){
84 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
85 assert(ws!=NULL);
86 return REGION_GEOM(ws).w;
89 return maxof(CF_STDISP_MIN_SZ, region_min_w(stdisp->regnode.reg));
93 int stdisp_recommended_h(WSplitST *stdisp)
95 if(stdisp->regnode.reg==NULL)
96 return CF_STDISP_MIN_SZ;
98 if(stdisp->fullsize && stdisp->orientation==REGION_ORIENTATION_VERTICAL){
99 WTiling *ws=REGION_MANAGER_CHK(stdisp->regnode.reg, WTiling);
100 assert(ws!=NULL);
101 return REGION_GEOM(ws).h;
104 return maxof(CF_STDISP_MIN_SZ, region_min_h(stdisp->regnode.reg));
108 static bool stdisp_dir_ok(WSplitSplit *p, WSplitST *stdisp)
110 assert(p->tl==(WSplit*)stdisp || p->br==(WSplit*)stdisp);
112 return (IMPLIES(STDISP_IS_HORIZONTAL(stdisp), p->dir==SPLIT_VERTICAL) &&
113 IMPLIES(STDISP_IS_VERTICAL(stdisp), p->dir==SPLIT_HORIZONTAL));
117 /*}}}*/
120 /*{{{ New rotation and flipping primitives */
123 static void replace(WSplitSplit *a, WSplitSplit *p)
125 if(((WSplit*)a)->parent!=NULL)
126 splitinner_replace(((WSplit*)a)->parent, (WSplit*)a, (WSplit*)p);
127 else
128 splittree_changeroot((WSplit*)a, (WSplit*)p);
132 /* Yes, it is overparametrised */
133 static void rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
135 assert(a->tl==(WSplit*)p && p->tl==y);
137 /* Right rotation:
138 * a p
139 * / \ / \
140 * p x => y a
141 * / \ / \
142 * y ? ? x
145 a->tl=p->br;
146 a->tl->parent=(WSplitInner*)a;
147 replace(a, p);
148 p->br=(WSplit*)a;
149 ((WSplit*)a)->parent=(WSplitInner*)p;
153 static void rot_rs_rotate_right(WSplitSplit *a, WSplitSplit *p, WSplit *y)
155 WRectangle xg, yg, pg, ag, qg;
156 WSplit *x=a->br, *q=p->br;
158 assert(a->dir==other_dir(p->dir));
160 qg=GEOM(q);
161 xg=GEOM(x);
162 yg=GEOM(y);
163 pg=GEOM(p);
164 ag=GEOM(a);
166 if(a->dir==SPLIT_HORIZONTAL){
167 /* yyxx yyyy
168 * ??xx => ??xx
169 * ??xx ??xx
171 yg.w=ag.w;
172 pg.w=ag.w;
173 xg.h=qg.h;
174 ag.h=qg.h;
175 xg.y=qg.y;
176 ag.y=qg.y;
177 }else{
178 /* y?? y??
179 * y?? y??
180 * xxx => yxx
181 * xxx yxx
183 yg.h=ag.h;
184 pg.h=ag.h;
185 xg.w=qg.w;
186 ag.w=qg.w;
187 xg.x=qg.x;
188 ag.x=qg.x;
191 rotate_right(a, p, y);
193 GEOM(p)=pg;
194 GEOM(a)=ag;
196 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
197 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
202 static void rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
204 assert(a->br==(WSplit*)p && p->br==y);
206 /* Left rotation:
207 * a p
208 * / \ / \
209 * x p => a y
210 * / \ / \
211 * ? y x ?
214 a->br=p->tl;
215 a->br->parent=(WSplitInner*)a;
216 replace(a, p);
217 p->tl=(WSplit*)a;
218 ((WSplit*)a)->parent=(WSplitInner*)p;
222 static void rot_rs_rotate_left(WSplitSplit *a, WSplitSplit *p, WSplit *y)
224 WRectangle xg, yg, pg, ag, qg;
225 WSplit *x=a->tl, *q=p->tl;
227 assert(a->dir==other_dir(p->dir));
229 qg=GEOM(q);
230 xg=GEOM(x);
231 yg=GEOM(y);
232 pg=GEOM(p);
233 ag=GEOM(a);
235 if(a->dir==SPLIT_HORIZONTAL){
236 /* xx?? xx??
237 * xx?? => xx??
238 * xxyy yyyy
240 yg.w=ag.w;
241 yg.x=ag.x;
242 pg.w=ag.w;
243 pg.x=ag.x;
244 xg.h=qg.h;
245 ag.h=qg.h;
246 }else{
247 /* xxx xxy
248 * xxx xxy
249 * ??y => ??y
250 * ??y ??y
252 yg.h=ag.h;
253 yg.y=ag.y;
254 pg.h=ag.h;
255 pg.y=ag.y;
256 xg.w=qg.w;
257 ag.w=qg.w;
260 rotate_left(a, p, y);
262 GEOM(p)=pg;
263 GEOM(a)=ag;
265 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
266 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
271 static void flip_right(WSplitSplit *a, WSplitSplit *p)
273 WSplit *tmp;
275 assert(a->tl==(WSplit*)p);
277 /* Right flip:
278 * a p
279 * / \ / \
280 * p x => a y
281 * / \ / \
282 * ? y ? x
285 a->tl=p->tl;
286 a->tl->parent=(WSplitInner*)a;
287 replace(a, p);
288 p->tl=(WSplit*)a;
289 ((WSplit*)a)->parent=(WSplitInner*)p;
293 static void rot_rs_flip_right(WSplitSplit *a, WSplitSplit *p)
295 WRectangle xg, yg, pg, ag, qg;
296 WSplit *x=a->br, *q=p->tl, *y=p->br;
298 assert(a->dir==other_dir(p->dir));
300 qg=GEOM(q);
301 xg=GEOM(x);
302 yg=GEOM(y);
303 pg=GEOM(p);
304 ag=GEOM(a);
306 if(a->dir==SPLIT_HORIZONTAL){
307 /* ??xx ??xx
308 * ??xx => ??xx
309 * yyxx yyyy
311 yg.w=ag.w;
312 pg.w=ag.w;
313 ag.h=qg.h;
314 xg.h=qg.h;
315 }else{
316 /* ??y ??y
317 * ??y ??y
318 * xxx => xxy
319 * xxx xxy
321 yg.h=ag.h;
322 pg.h=ag.h;
323 ag.w=qg.w;
324 xg.w=qg.w;
327 flip_right(a, p);
329 GEOM(p)=pg;
330 GEOM(a)=ag;
332 split_do_resize(x, &xg, PRIMN_BR, PRIMN_BR, FALSE);
333 split_do_resize(y, &yg, PRIMN_BR, PRIMN_BR, FALSE);
337 static void flip_left(WSplitSplit *a, WSplitSplit *p)
339 WSplit *tmp;
341 assert(a->br==(WSplit*)p);
343 /* Left flip:
344 * a p
345 * / \ / \
346 * x p => y a
347 * / \ / \
348 * y ? x ?
351 a->br=p->br;
352 a->br->parent=(WSplitInner*)a;
353 replace(a, p);
354 p->br=(WSplit*)a;
355 ((WSplit*)a)->parent=(WSplitInner*)p;
359 static void rot_rs_flip_left(WSplitSplit *a, WSplitSplit *p)
361 WRectangle xg, yg, pg, ag, qg;
362 WSplit *x=a->tl, *q=p->br, *y=p->tl;
364 assert(a->dir==other_dir(p->dir));
366 qg=GEOM(q);
367 xg=GEOM(x);
368 yg=GEOM(y);
369 pg=GEOM(p);
370 ag=GEOM(a);
372 if(a->dir==SPLIT_HORIZONTAL){
373 /* xxyy yyyy
374 * xx?? => xx??
375 * xx?? xx??
377 yg.x=ag.x;
378 yg.w=ag.w;
379 pg.x=ag.x;
380 pg.w=ag.w;
381 xg.h=qg.h;
382 xg.y=qg.y;
383 ag.h=qg.h;
384 ag.y=qg.y;
385 }else{
386 /* xxx yxx
387 * xxx yxx
388 * y?? => y??
389 * y?? y??
391 yg.y=ag.y;
392 yg.h=ag.h;
393 pg.y=ag.y;
394 pg.h=ag.h;
395 xg.w=qg.w;
396 xg.x=qg.x;
397 ag.w=qg.w;
398 ag.x=qg.x;
401 flip_left(a, p);
403 GEOM(p)=pg;
404 GEOM(a)=ag;
406 split_do_resize(x, &xg, PRIMN_TL, PRIMN_TL, FALSE);
407 split_do_resize(y, &yg, PRIMN_TL, PRIMN_TL, FALSE);
411 static void rot_para_right(WSplitSplit *a, WSplitSplit *p,
412 WSplit *y)
414 rotate_right(a, p, y);
415 if(a->dir==SPLIT_VERTICAL){
416 GEOM(p).y=GEOM(a).y;
417 GEOM(p).h=GEOM(a).h;
418 GEOM(a).y=GEOM(a->tl).y;
419 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
420 }else{
421 GEOM(p).x=GEOM(a).x;
422 GEOM(p).w=GEOM(a).w;
423 GEOM(a).x=GEOM(a->tl).x;
424 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
429 static void rot_para_left(WSplitSplit *a, WSplitSplit *p,
430 WSplit *y)
432 rotate_left(a, p, y);
433 if(a->dir==SPLIT_VERTICAL){
434 GEOM(p).y=GEOM(a).y;
435 GEOM(p).h=GEOM(a).h;
436 GEOM(a).h=GEOM(a->br).y+GEOM(a->br).h-GEOM(a).y;
437 }else{
438 GEOM(p).x=GEOM(a).x;
439 GEOM(p).w=GEOM(a).w;
440 GEOM(a).w=GEOM(a->br).x+GEOM(a->br).w-GEOM(a).x;
445 /*}}}*/
448 /*{{{ Sink */
451 static bool do_try_sink_stdisp_orth(WSplitSplit *p, WSplitST *stdisp,
452 WSplitSplit *other, bool force)
454 bool doit=force;
456 assert(p->dir==other_dir(other->dir));
457 assert(stdisp_dir_ok(p, stdisp));
459 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
460 if(STDISP_GROWS_L_TO_R(stdisp)){
461 assert(other->dir==SPLIT_HORIZONTAL);
462 if(other->tl->geom.w>=stdisp_recommended_w(stdisp))
463 doit=TRUE;
464 }else{ /* STDISP_GROWS_T_TO_B */
465 assert(other->dir==SPLIT_VERTICAL);
466 if(other->tl->geom.h>=stdisp_recommended_h(stdisp))
467 doit=TRUE;
470 if(doit){
471 if(p->br==(WSplit*)stdisp)
472 rot_rs_flip_right(p, other);
473 else /* p->tl==stdisp */
474 rot_rs_rotate_left(p, other, other->br);
476 }else{ /* STDISP_GROWS_B_TO_T or STDISP_GROW_R_TO_L */
477 if(STDISP_GROWS_R_TO_L(stdisp)){
478 assert(other->dir==SPLIT_HORIZONTAL);
479 if(other->br->geom.w>=stdisp_recommended_w(stdisp))
480 doit=TRUE;
481 }else{ /* STDISP_GROWS_B_TO_T */
482 assert(other->dir==SPLIT_VERTICAL);
483 if(other->br->geom.h>=stdisp_recommended_h(stdisp))
484 doit=TRUE;
487 if(doit){
488 if(p->tl==(WSplit*)stdisp)
489 rot_rs_flip_left(p, other);
490 else /* p->br==stdisp */
491 rot_rs_rotate_right(p, other, other->tl);
495 return doit;
499 static bool do_try_sink_stdisp_para(WSplitSplit *p, WSplitST *stdisp,
500 WSplitSplit *other, bool force)
502 if(!force){
503 if(STDISP_IS_HORIZONTAL(stdisp)){
504 if(stdisp_recommended_w(stdisp)>=GEOM(p).w)
505 return FALSE;
506 }else{
507 if(stdisp_recommended_h(stdisp)>=GEOM(p).h)
508 return FALSE;
512 if(p->tl==(WSplit*)stdisp)
513 rot_para_left(p, other, other->br);
514 else
515 rot_para_right(p, other, other->tl);
517 return TRUE;
521 bool split_try_sink_stdisp(WSplitSplit *node, bool iterate, bool force)
523 bool didsomething=FALSE;
524 bool more=TRUE;
526 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
528 while(more){
529 WSplit *tl=node->tl;
530 WSplit *br=node->br;
531 WSplitSplit *other=NULL;
532 WSplitST *st;
534 if(OBJ_IS(tl, WSplitST)){
535 st=(WSplitST*)tl;
536 other=OBJ_CAST(br, WSplitSplit);
537 }else if(OBJ_IS(br, WSplitST)){
538 st=(WSplitST*)br;
539 other=OBJ_CAST(tl, WSplitSplit);
540 }else{
541 break;
544 if(other==NULL)
545 break;
547 if(!stdisp_dir_ok(node, st))
548 break;
550 if(other->dir==other_dir(node->dir)){
551 if(!do_try_sink_stdisp_orth(node, st, other, force))
552 break;
553 }else /*if(br->dir==node->dir)*/{
554 if(!do_try_sink_stdisp_para(node, st, other, force))
555 break;
557 didsomething=TRUE;
558 more=iterate;
561 return didsomething;
565 /*}}}*/
568 /*{{{ Unsink */
571 static bool do_try_unsink_stdisp_orth(WSplitSplit *a, WSplitSplit *p,
572 WSplitST *stdisp, bool force)
574 bool doit=force;
576 assert(p->dir==other_dir(a->dir));
577 assert(stdisp_dir_ok(p, stdisp));
579 if(STDISP_GROWS_T_TO_B(stdisp) || STDISP_GROWS_L_TO_R(stdisp)){
580 if(STDISP_GROWS_L_TO_R(stdisp)){
581 assert(a->dir==SPLIT_HORIZONTAL);
582 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
583 doit=TRUE;
584 }else{ /* STDISP_GROWS_T_TO_B */
585 assert(a->dir==SPLIT_VERTICAL);
586 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
587 doit=TRUE;
590 if(doit){
591 if((WSplit*)p==a->tl){
592 if((WSplit*)stdisp==p->br)
593 rot_rs_flip_right(a, p);
594 else /*stdisp==p->tl*/
595 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
596 }else{ /*p==a->br*/
597 #if 0
598 /* abnormal cases. */
599 warn(TR("Status display in bad split configuration."));
600 return FALSE;
601 #else
602 if((WSplit*)stdisp==p->br)
603 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
604 else /*stdisp==p->tl*/
605 rot_rs_flip_left(a, p);
606 #endif
609 }else{ /*STDISP_GROWS_B_TO_T || STDISP_GROWS_R_TO_L*/
610 if(STDISP_GROWS_R_TO_L(stdisp)){
611 assert(a->dir==SPLIT_HORIZONTAL);
612 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
613 doit=TRUE;
614 }else{ /* STDISP_GROWS_B_TO_T */
615 assert(a->dir==SPLIT_VERTICAL);
616 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
617 doit=TRUE;
620 if(doit){
621 if((WSplit*)p==a->tl){
622 #if 0
623 /* abnormal cases. */
624 warn(TR("Status display in bad split configuration."));
625 return FALSE;
626 #else
627 if((WSplit*)stdisp==p->br)
628 rot_rs_flip_right(a, p);
629 else /*stdisp==p->tl*/
630 rot_rs_rotate_right(a, p, (WSplit*)stdisp);
631 #endif
632 }else{ /*p==a->br*/
633 if((WSplit*)stdisp==p->br)
634 rot_rs_rotate_left(a, p, (WSplit*)stdisp);
635 else /*stdisp==p->tl*/
636 rot_rs_flip_left(a, p);
641 return doit;
645 static bool do_try_unsink_stdisp_para(WSplitSplit *a, WSplitSplit *p,
646 WSplitST *stdisp, bool force)
648 if(!force){
649 if(STDISP_IS_HORIZONTAL(stdisp)){
650 if(stdisp_recommended_w(stdisp)<=GEOM(p).w)
651 return FALSE;
652 }else{
653 if(stdisp_recommended_h(stdisp)<=GEOM(p).h)
654 return FALSE;
659 if(a->tl==(WSplit*)p && p->tl==(WSplit*)stdisp){
660 rot_para_right(a, p, (WSplit*)stdisp);
661 }else if(a->br==(WSplit*)p && p->br==(WSplit*)stdisp){
662 rot_para_left(a, p, (WSplit*)stdisp);
663 }else{
664 warn(TR("Status display badly located in split tree."));
665 return FALSE;
668 return TRUE;
672 bool split_try_unsink_stdisp(WSplitSplit *node, bool iterate, bool force)
674 bool didsomething=FALSE;
675 bool more=TRUE;
677 /*assert(OBJ_IS_EXACTLY(node, WSplitSplit));*/
679 while(more){
680 WSplitSplit *p=OBJ_CAST(((WSplit*)node)->parent, WSplitSplit);
681 WSplit *tl=node->tl;
682 WSplit *br=node->br;
683 WSplitST *st;
685 if(p==NULL)
686 break;
688 if(OBJ_IS(tl, WSplitST))
689 st=(WSplitST*)tl;
690 else if(OBJ_IS(br, WSplitST))
691 st=(WSplitST*)br;
692 else
693 break;
695 if(!stdisp_dir_ok(node, st))
696 break;
698 if(p->dir==other_dir(node->dir)){
699 if(!do_try_unsink_stdisp_orth(p, node, st, force))
700 break;
701 }else /*if(p->dir==node->dir)*/{
702 if(!do_try_unsink_stdisp_para(p, node, st, force))
703 break;
706 didsomething=TRUE;
707 more=iterate;
710 return didsomething;
714 /*}}}*/
717 /*{{{ Sink or unsink */
720 bool split_regularise_stdisp(WSplitST *stdisp)
722 WSplitSplit *node=OBJ_CAST(((WSplit*)stdisp)->parent, WSplitSplit);
724 if(node==NULL)
725 return FALSE;
727 if(STDISP_IS_HORIZONTAL(stdisp)){
728 if(GEOM(stdisp).w<stdisp_recommended_w(stdisp))
729 return split_try_unsink_stdisp(node, TRUE, FALSE);
730 else if(GEOM(stdisp).w>stdisp_recommended_w(stdisp))
731 return split_try_sink_stdisp(node, TRUE, FALSE);
732 }else{
733 if(GEOM(stdisp).h<stdisp_recommended_h(stdisp))
734 return split_try_unsink_stdisp(node, TRUE, FALSE);
735 else if(GEOM(stdisp).h>stdisp_recommended_h(stdisp))
736 return split_try_sink_stdisp(node, TRUE, FALSE);
739 return FALSE;
743 /*}}}*/