4 * Copyright (c) Tuomo Valkonen 1999-2001.
5 * See the included file LICENSE for details.
12 #include "workspace.h"
22 IMPLOBJ(WWsSplit
, WObj
, NULL
)
28 int wwin_size(WWindow
*wwin
, int dir
)
36 int wwin_other_size(WWindow
*wwin
, int dir
)
44 int wwin_pos(WWindow
*wwin
, int dir
)
52 int tree_size(WObj
*obj
, int dir
)
54 if(WOBJ_IS(obj
, WWindow
))
55 return wwin_size((WWindow
*)obj
, dir
);
58 return ((WWsSplit
*)obj
)->geom
.w
;
59 return ((WWsSplit
*)obj
)->geom
.h
;
63 int tree_pos(WObj
*obj
, int dir
)
65 if(WOBJ_IS(obj
, WWindow
))
66 return wwin_pos((WWindow
*)obj
, dir
);
69 return ((WWsSplit
*)obj
)->geom
.x
;
70 return ((WWsSplit
*)obj
)->geom
.y
;
74 static WRectangle
tree_geom(WObj
*obj
)
76 if(WOBJ_IS(obj
, WWindow
))
77 return ((WWindow
*)obj
)->geom
;
79 return ((WWsSplit
*)obj
)->geom
;
83 int tree_other_size(WObj
*obj
, int dir
)
85 if(WOBJ_IS(obj
, WWindow
))
86 return wwin_other_size((WWindow
*)obj
, dir
);
89 return ((WWsSplit
*)obj
)->geom
.h
;
90 return ((WWsSplit
*)obj
)->geom
.w
;
94 static int wwin_calcresize(WWindow
*wwin
, int dir
, int nsize
)
100 if(nsize
<wwin
->min_h
)
108 static int wwin_resize(WWindow
*wwin
, int dir
, int npos
, int nsize
)
117 wwin
->flags
&=~WWINDOW_HFORCED
;
123 wwin
->flags
&=~WWINDOW_WFORCED
;
126 if(WTHING_IS(wwin
, WFrame
))
127 set_frame_geom((WFrame
*)wwin
, geom
);
133 static WWsSplit
*split_of(WObj
*obj
)
135 if(WOBJ_IS(obj
, WWindow
))
136 return ((WWindow
*)obj
)->split
;
138 assert(WOBJ_IS(obj
, WWsSplit
));
140 return ((WWsSplit
*)obj
)->parent
;
144 static void set_split_of(WObj
*obj
, WWsSplit
*split
)
146 if(WOBJ_IS(obj
, WWindow
)){
147 ((WWindow
*)obj
)->split
=split
;
151 assert(WOBJ_IS(obj
, WWsSplit
));
153 ((WWsSplit
*)obj
)->parent
=split
;
160 /*{{{ Low-level resize code */
163 static int tree_calcresize(WObj
*node_
, int dir
, int primn
,
168 int s1
, s2
, ns1
, ns2
;
172 /* Reached a window? */
173 if(!WTHING_IS(node_
, WWsSplit
)){
174 assert(WTHING_IS(node_
, WWindow
));
175 return wwin_calcresize((WWindow
*)node_
, dir
, nsize
);
178 node
=(WWsSplit
*)node_
;
181 /* Found a split in the other direction than the resize */
182 s1
=tree_calcresize(node
->tl
, dir
, primn
, nsize
);
183 s2
=tree_calcresize(node
->br
, dir
, primn
, nsize
);
186 /*if(nsize>tree_size(node->tl, dir)){
187 tree_calcresize(node->tl, dir, primn, s2);
190 tree_calcresize(node
->br
, dir
, primn
, s1
);
193 /*if(nsize>tree_size(node->br, dir)){
194 tree_calcresize(node->br, dir, primn, s1);
196 tree_calcresize(node
->tl
, dir
, primn
, s2
);
202 return (node
->tmpsize
=s1
);
204 if(primn
==TOP_OR_LEFT
){
205 /* Resize top or left node first */
209 /* Resize bottom or right node first */
212 primn
=BOTTOM_OR_RIGHT
;
215 s2
=tree_size(o2
, dir
);
217 s1
=tree_calcresize(o1
, dir
, primn
, ns1
);
221 s2
=tree_calcresize(o2
, dir
, primn
, ns2
);
227 node
->knowsize
=primn
;
234 /* Resize according to parameters calculated by wcalcres
236 int tree_do_resize(WObj
*node_
, int dir
, int npos
, int nsize
)
248 /* Reached a window? */
249 if(!WTHING_IS(node_
, WWsSplit
)){
250 assert(WTHING_IS(node_
, WWindow
));
251 return wwin_resize((WWindow
*)node_
, dir
, npos
, nsize
);
254 node
=(WWsSplit
*)node_
;
257 tree_do_resize(node
->tl
, dir
, npos
, nsize
);
258 s
=tree_do_resize(node
->br
, dir
, npos
, nsize
);
260 if(node
->knowsize
==TOP_OR_LEFT
){
263 }else if(node
->knowsize
==BOTTOM_OR_RIGHT
){
267 fprintf(stderr
, "Resize is broken!");
273 /*if(node->res!=BOTTOM_OR_RIGHT)*/
274 s
+=tree_do_resize(node
->tl
, dir
, npos
, tls
);
276 s+=tree_size(node->tl, dir);*/
280 /*if(node->res!=TOP_OR_LEFT)*/
281 s
+=tree_do_resize(node
->br
, dir
, npos
, brs
);
283 s+=tree_size(node->br, dir);*/
298 /* Calculate parameters for resizing <split> and possibly anything
299 * above it so that the <dir>-dimension of <from> becomes <nsize>
302 static void wcalcres(WWsSplit
*split
, int dir
, int primn
,
303 int nsize
, int from
, WResizeTmp
*ret
)
305 int s
, s2
, ds
, rs
, rp
;
306 WObj
*other
=(from
==TOP_OR_LEFT
? split
->br
: split
->tl
);
309 s
=tree_size((WObj
*)split
, dir
);
312 /* It might not be possible to shrink the other as much */
313 ds
=tree_calcresize(other
, dir
, primn
, nsize
);
318 s2
=tree_calcresize(other
, dir
, from
, s
-nsize
);
320 s2
=tree_calcresize(other
, dir
, from
, tree_size(other
, dir
));
326 if(p
==NULL
|| ds
==s
){
328 rp
=tree_pos((WObj
*)split
, dir
);
331 /* Don't have to resize the other branch if the split is not
332 * in the wanted direction
335 ret
->startnode
=(from
==TOP_OR_LEFT
? split
->tl
: split
->br
);
337 ret
->startnode
=(WObj
*)split
;
339 wcalcres(p
, dir
, primn
, ds
,
340 (p
->tl
==(WObj
*)split
? TOP_OR_LEFT
: BOTTOM_OR_RIGHT
),
345 if(rs
!=ds
&& dir
!=split
->dir
)
346 tree_calcresize(other
, dir
, primn
, rs
);
351 split
->knowsize
=from
;
352 split
->tmpsize
=nsize
;
355 if(from
==TOP_OR_LEFT
)
358 ret
->winpostmp
=rp
+s2
;
359 ret
->winsizetmp
=nsize
;
363 static int calcresize_obj(WObj
*obj
, int dir
, int primn
, int nsize
,
366 WWsSplit
*split
=split_of(obj
);
368 nsize
=tree_calcresize(obj
, dir
, primn
, nsize
);
373 ret
->winsizetmp
=ret
->sizetmp
=tree_size(obj
, dir
);
374 ret
->winpostmp
=ret
->postmp
=tree_pos(obj
, dir
);
378 wcalcres(split
, dir
, primn
, nsize
,
379 (split
->tl
==obj
? TOP_OR_LEFT
: BOTTOM_OR_RIGHT
),
382 return ret
->winsizetmp
;
390 /*{{{ Resize interface */
393 int calcresize_window(WWindow
*wwin
, int dir
, int primn
, int nsize
,
396 return calcresize_obj((WObj
*)wwin
, dir
, primn
, nsize
, ret
);
400 void resize_tmp(const WResizeTmp
*tmp
)
402 tree_do_resize(tmp
->startnode
, tmp
->dir
, tmp
->postmp
, tmp
->sizetmp
);
412 WWsSplit
*create_split(int dir
, WObj
*tl
, WObj
*br
, WRectangle geom
)
414 WWsSplit
*split
=ALLOC(WWsSplit
);
421 WOBJ_INIT(split
, WWsSplit
);
434 static WWindow
*do_split_at(WWorkspace
*ws
, WObj
*obj
, int dir
, int primn
,
435 int minsize
, WSplitCreate
*fn
)
438 WWsSplit
*split
, *nsplit
;
445 if(primn
!=TOP_OR_LEFT
&& primn
!=BOTTOM_OR_RIGHT
)
446 primn
=BOTTOM_OR_RIGHT
;
447 if(dir
!=HORIZONTAL
&& dir
!=VERTICAL
)
450 /* First possibly resize <obj> so that the area allocated by it
451 * is big enough to fit the new object and <obj> itself without
452 * them becoming too small.
455 s
=tree_size(obj
, dir
);
461 gs
=tree_calcresize(obj
, dir
, primn
, s
-sn
);
464 s
=calcresize_obj(obj
, dir
, ANY
, gs
+sn
, &rtmp
);
466 warn("Cannot resize: minimum size reached");
472 /* Create split and new window
476 nsplit
=create_split(dir
, NULL
, NULL
, geom
);
482 if(primn
==BOTTOM_OR_RIGHT
)
486 if(primn
==BOTTOM_OR_RIGHT
)
491 nwin
=fn(SCREEN_OF(ws
), geom
);
498 add_workspace_window(ws
, nwin
);
500 /* Now that everything's ok, resize (and move) the original
503 pos
=tree_pos(obj
, dir
);
504 if(primn
!=BOTTOM_OR_RIGHT
)
506 s
=tree_calcresize(obj
, dir
, primn
, gs
);
507 tree_do_resize(obj
, dir
, pos
, s
);
509 /* Set up split structure
513 set_split_of(obj
, nsplit
);
516 if(primn
==BOTTOM_OR_RIGHT
){
518 nsplit
->br
=(WObj
*)nwin
;
520 nsplit
->tl
=(WObj
*)nwin
;
526 split
->tl
=(WObj
*)nsplit
;
528 split
->br
=(WObj
*)nsplit
;
529 nsplit
->parent
=split
;
531 ws
->splitree
=(WObj
*)nsplit
;
538 WWindow
*split_window(WWindow
*wwin
, int dir
, int minsize
, WSplitCreate
*fn
)
540 WWorkspace
*ws
=FIND_PARENT(wwin
, WWorkspace
);
544 return do_split_at(ws
, (WObj
*)wwin
, dir
, BOTTOM_OR_RIGHT
, minsize
, fn
);
548 WWindow
*split_toplevel(WWorkspace
*ws
, int dir
, int primn
, int minsize
,
551 if(ws
->splitree
==NULL
)
554 return do_split_at(ws
, ws
->splitree
, dir
, primn
, minsize
, fn
);
564 static WWindow
*left_or_topmost_current(WObj
*obj
, int dir
)
569 if(WOBJ_IS(obj
, WWindow
))
570 return (WWindow
*)obj
;
572 assert(WOBJ_IS(obj
, WWsSplit
));
574 split
=(WWsSplit
*)obj
;
581 obj
=(split
->current
==0 ? split
->tl
: split
->br
);
588 static WWindow
*right_or_bottomost_current(WObj
*obj
, int dir
)
593 if(WOBJ_IS(obj
, WWindow
))
594 return (WWindow
*)obj
;
596 assert(WOBJ_IS(obj
, WWsSplit
));
598 split
=(WWsSplit
*)obj
;
605 obj
=(split
->current
==0 ? split
->tl
: split
->br
);
612 WWindow
*find_current(WWorkspace
*ws
)
614 return left_or_topmost_current(ws
->splitree
, -1);
618 static WWsSplit
*find_split(WObj
*obj
, int dir
, int *from
)
622 if(WOBJ_IS(obj
, WWindow
))
623 split
=((WWindow
*)obj
)->split
;
625 split
=((WWsSplit
*)obj
)->parent
;
632 *from
=BOTTOM_OR_RIGHT
;
644 static WWindow
*right_or_down(WWindow
*wwin
, int dir
)
646 WObj
*prev
=(WObj
*)wwin
;
652 split
=find_split(prev
, dir
, &from
);
657 if(from
==TOP_OR_LEFT
)
658 return left_or_topmost_current(split
->br
, dir
);
663 return left_or_topmost_current(prev
, dir
);
667 static WWindow
*up_or_left(WWindow
*wwin
, int dir
)
669 WObj
*prev
=(WObj
*)wwin
;
675 split
=find_split(prev
, dir
, &from
);
680 if(from
==BOTTOM_OR_RIGHT
)
681 return right_or_bottomost_current(split
->tl
, dir
);
686 return right_or_bottomost_current(prev
, dir
);
690 static void goto_wwin(WWindow
*wwin
)
692 if(wwin
==NULL
|| wglobal
.current_wswindow
==wwin
)
694 set_previous((WThing
*)wwin
);
698 void goto_above(WWindow
*wwin
)
701 goto_wwin(up_or_left(wwin
, VERTICAL
));
704 void goto_below(WWindow
*wwin
)
707 goto_wwin(right_or_down(wwin
, VERTICAL
));
710 void goto_left(WWindow
*wwin
)
713 goto_wwin(up_or_left(wwin
, HORIZONTAL
));
717 void goto_right(WWindow
*wwin
)
720 goto_wwin(right_or_down(wwin
, HORIZONTAL
));
730 void workspace_remove_window(WWorkspace
*ws
, WWindow
*wwin
)
741 if(split
->tl
==(WObj
*)wwin
)
746 remove_split(ws
, split
);
750 bool remove_split(WWorkspace
*ws
, WWsSplit
*split
)
754 int osize
, nsize
, npos
;
762 primn
=BOTTOM_OR_RIGHT
;
765 split2
=split
->parent
;
768 if((WObj
*)split
==split2
->tl
)
779 if(WOBJ_IS(other
, WWindow
))
780 ((WWindow
*)other
)->split
=split2
;
782 ((WWsSplit
*)other
)->parent
=split2
;
784 if(wglobal
.opmode
!=OPMODE_DEINIT
){
785 nsize
=tree_size((WObj
*)split
, split
->dir
);
786 npos
=tree_pos((WObj
*)split
, split
->dir
);
787 nsize
=tree_calcresize(other
, split
->dir
, primn
, nsize
);
788 tree_do_resize(other
, split
->dir
, npos
, nsize
);
803 void set_current_wswindow(WWindow
*wwin
)
805 WWsSplit
*split
=wwin
->split
;
806 WObj
*prev
=(WObj
*)wwin
;
809 split
->current
=(split
->tl
==prev
? 0 : 1);
814 wglobal
.current_wswindow
=wwin
;