2 * ion/ioncore/stacking.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
10 #include <libtu/minmax.h>
16 #include "sizepolicy.h"
22 WStacking
*create_stacking()
24 WStacking
*st
=ALLOC(WStacking
);
30 st
->szplcy
=SIZEPOLICY_DEFAULT
;
33 st
->pseudomodal
=FALSE
;
40 void stacking_free(WStacking
*st
)
42 assert(st
->mgr_next
==NULL
&& st
->mgr_prev
==NULL
&&
43 st
->next
==NULL
&& st
->prev
==NULL
&&
44 /*st->above==NULL &&*/
58 static Rb_node stacking_of_reg
=NULL
;
61 WStacking
*ioncore_find_stacking(WRegion
*reg
)
66 if(stacking_of_reg
!=NULL
)
67 node
=rb_find_pkey_n(stacking_of_reg
, reg
, &found
);
69 return (found
? (WStacking
*)node
->v
.val
: NULL
);
73 void stacking_unassoc(WStacking
*st
)
81 if(stacking_of_reg
!=NULL
)
82 node
=rb_find_pkey_n(stacking_of_reg
, st
->reg
, &found
);
91 bool stacking_assoc(WStacking
*st
, WRegion
*reg
)
93 assert(st
->reg
==NULL
);
95 if(stacking_of_reg
==NULL
){
96 stacking_of_reg
=make_rb();
97 if(stacking_of_reg
==NULL
)
101 if(rb_insertp(stacking_of_reg
, reg
, st
)==NULL
)
113 /*{{{ List processing */
116 static WStacking
*link_lists(WStacking
*l1
, WStacking
*l2
)
118 /* As everywhere, doubly-linked lists without the forward
121 WStacking
*tmp
=l2
->prev
;
129 static WStacking
*link_list_before(WStacking
*l1
,
136 return link_lists(l2
, l1
);
148 static WStacking
*link_list_after(WStacking
*l1
,
155 return link_lists(l1
, l2
);
157 i1
->next
->prev
=l2
->prev
;
158 l2
->prev
->next
=i1
->next
;
166 WStacking
*stacking_unstack(WWindow
*par
, WStacking
*regst
)
168 WStacking
*nxt
=NULL
, *st
;
172 UNLINK_ITEM(par
->stacking
, regst
, next
, prev
);
175 for(st
=par
->stacking
; st
!=NULL
; st
=st
->next
){
176 if(st
->above
==regst
){
186 if(regst
->above
==NULL
)
193 static bool cf(WStackingFilter
*filt
, void *filt_data
, WStacking
*st
)
195 return (filt
==NULL
|| filt(st
, filt_data
));
199 static bool check_unweave(WStacking
*st
)
201 /* 2: unknown, 1: yes, 0: no */
203 if(st
->to_unweave
==2){
205 st
->to_unweave
=check_unweave(st
->above
);
210 return st
->to_unweave
;
214 WStacking
*stacking_unweave(WStacking
**stacking
,
215 WStackingFilter
*filt
, void *filt_data
)
218 WStacking
*st
, *next
;
220 for(st
=*stacking
; st
!=NULL
; st
=st
->next
){
222 if(st
->above
==NULL
&& cf(filt
, filt_data
, st
))
226 for(st
=*stacking
; st
!=NULL
; st
=st
->next
)
229 for(st
=*stacking
; st
!=NULL
; st
=next
){
231 if(st
->to_unweave
==1){
232 UNLINK_ITEM(*stacking
, st
, next
, prev
);
233 LINK_ITEM(np
, st
, next
, prev
);
241 static int check_above_lvl(WStacking
*st
)
245 st
->level
=check_above_lvl(st
->above
);
250 static void enforce_level_sanity(WStacking
**np
)
254 /* Make sure that the levels of stuff stacked 'above' match
255 * the level of the thing stacked above.
257 for(st
=*np
; st
!=NULL
; st
=st
->next
)
260 /* And now make sure things are ordered by levels. */
262 while(st
->next
!=NULL
){
263 if(st
->next
->level
< st
->level
){
264 WStacking
*st2
=st
->next
;
265 UNLINK_ITEM(*np
, st2
, next
, prev
);
266 LINK_ITEM_BEFORE(*np
, st2
, st
, next
, prev
);
276 static void get_bottom(WStacking
*st
, Window fb_win
,
277 Window
*other
, int *mode
)
279 Window bottom
=None
, top
=None
;
283 region_stacking(st
->reg
, &bottom
, &top
);
298 static void stacking_do_weave(WStacking
**stacking
, WStacking
**np
,
299 bool below
, Window fb_win
)
309 /* Should do nothing.. */
310 enforce_level_sanity(np
);
318 if(ab
->level
>lvl
|| (below
&& ab
->level
==lvl
))
322 get_bottom(ab
, fb_win
, &other
, &mode
);
326 UNLINK_ITEM(*np
, st
, next
, prev
);
328 region_restack(st
->reg
, other
, mode
);
331 LINK_ITEM_BEFORE(*stacking
, ab
, st
, next
, prev
);
333 LINK_ITEM_LAST(*stacking
, st
, next
, prev
);
339 void stacking_weave(WStacking
**stacking
, WStacking
**np
, bool below
)
341 stacking_do_weave(stacking
, np
, below
, None
);
351 static bool is_above(WStacking
*st
, WStacking
*p
)
355 else if(st
->above
==p
)
358 return is_above(st
->above
, p
);
362 static void collect_first(WStacking
**dst
, WStacking
**src
, WStacking
*st
)
364 UNLINK_ITEM(*src
, st
, next
, prev
);
365 LINK_ITEM_FIRST(*dst
, st
, next
, prev
);
369 static void collect_last(WStacking
**dst
, WStacking
**src
, WStacking
*st
)
371 UNLINK_ITEM(*src
, st
, next
, prev
);
372 LINK_ITEM_LAST(*dst
, st
, next
, prev
);
376 static void collect_above(WStacking
**dst
, WStacking
**src
, WStacking
*regst
)
378 WStacking
*stabove
, *stnext
;
380 for(stabove
=*src
; stabove
!=NULL
; stabove
=stnext
){
381 stnext
=stabove
->next
;
383 if(is_above(stabove
, regst
))
384 collect_last(dst
, src
, stabove
);
389 static WStacking
*unweave_subtree(WStacking
**stacking
, WStacking
*regst
,
397 collect_first(&tmp
, stacking
, st
);
401 collect_first(&tmp
, stacking
, regst
);
404 collect_above(&tmp
, stacking
, regst
);
410 void stacking_restack(WStacking
**stacking
, WStacking
*st
, Window fb_win
,
411 WStackingFilter
*filt
, void *filt_data
, bool lower
)
413 WStacking
*tmp
=unweave_subtree(stacking
, st
, lower
);
415 stacking_do_weave(stacking
, &tmp
, lower
, fb_win
);
424 /*{{{ Stacking lists */
427 WStacking
**window_get_stackingp(WWindow
*wwin
)
429 return &(wwin
->stacking
);
433 WStacking
*window_get_stacking(WWindow
*wwin
)
435 return wwin
->stacking
;
442 /*{{{ Stacking list iteration */
445 void stacking_iter_init(WStackingIterTmp
*tmp
,
447 WStackingFilter
*filt
,
452 tmp
->filt_data
=filt_data
;
456 WStacking
*stacking_iter_nodes(WStackingIterTmp
*tmp
)
458 WStacking
*next
=NULL
;
460 while(tmp
->st
!=NULL
){
462 tmp
->st
=tmp
->st
->next
;
463 if(cf(tmp
->filt
, tmp
->filt_data
, next
))
472 WRegion
*stacking_iter(WStackingIterTmp
*tmp
)
474 WStacking
*st
=stacking_iter_nodes(tmp
);
475 return (st
!=NULL
? st
->reg
: NULL
);
479 void stacking_iter_mgr_init(WStackingIterTmp
*tmp
,
481 WStackingFilter
*filt
,
486 tmp
->filt_data
=filt_data
;
490 WStacking
*stacking_iter_mgr_nodes(WStackingIterTmp
*tmp
)
492 WStacking
*next
=NULL
;
494 while(tmp
->st
!=NULL
){
496 tmp
->st
=tmp
->st
->mgr_next
;
497 if(cf(tmp
->filt
, tmp
->filt_data
, next
))
506 WRegion
*stacking_iter_mgr(WStackingIterTmp
*tmp
)
508 WStacking
*st
=stacking_iter_mgr_nodes(tmp
);
509 return (st
!=NULL
? st
->reg
: NULL
);
519 uint
stacking_min_level(WStacking
*stacking
,
520 WStackingFilter
*include_filt
,
523 uint min_level
=STACKING_LEVEL_BOTTOM
;
527 return STACKING_LEVEL_BOTTOM
;
534 && !(st
->reg
->flags
®ION_SKIP_FOCUS
)
535 && cf(include_filt
, filt_data
, st
)){
537 if(st
->level
>=STACKING_LEVEL_MODAL1
)
542 }while(st
!=stacking
);
548 WStacking
*stacking_find_to_focus(WStacking
*stacking
,
550 WStackingFilter
*include_filt
,
551 WStackingFilter
*approve_filt
,
554 uint min_level
=STACKING_LEVEL_BOTTOM
;
555 WStacking
*st
=NULL
, *found
=NULL
;
567 if(st
!=to_try
&& (st
->reg
->flags
®ION_SKIP_FOCUS
||
568 !cf(include_filt
, filt_data
, st
))){
573 if(st
->level
<min_level
)
579 if(found
==NULL
&& cf(approve_filt
, filt_data
, st
)){
585 if(st
->level
>=STACKING_LEVEL_MODAL1
)
586 min_level
=maxof(min_level
, st
->level
);
587 }while(st
!=stacking
);
593 static bool mapped_filt(WStacking
*st
, void *unused
)
595 return (st
->reg
!=NULL
&& REGION_IS_MAPPED(st
->reg
));
599 static bool mapped_filt_neq(WStacking
*st
, void *st_neq
)
601 return (st
!=(WStacking
*)st_neq
&& mapped_filt(st
, NULL
));
605 static bool mgr_filt(WStacking
*st
, void *mgr_
)
607 return (st
->reg
!=NULL
&& REGION_MANAGER(st
->reg
)==(WRegion
*)mgr_
);
611 WStacking
*stacking_find_to_focus_mapped(WStacking
*stacking
,
616 return stacking_find_to_focus(stacking
, to_try
, mapped_filt
,
619 return stacking_find_to_focus(stacking
, to_try
, mapped_filt
,
625 uint
stacking_min_level_mapped(WStacking
*stacking
)
627 return stacking_min_level(stacking
, mapped_filt
, NULL
);
631 bool stacking_must_focus(WStacking
*stacking
, WStacking
*st
)
633 WStacking
*stf
=stacking_find_to_focus(stacking
, NULL
,
634 mapped_filt_neq
, NULL
, st
);
637 (st
->level
>stf
->level
&&
638 st
->level
>=STACKING_LEVEL_MODAL1
));