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
,
153 return link_lists(l1
, l2
);
155 i1
->next
->prev
=l2
->prev
;
156 l2
->prev
->next
=i1
->next
;
164 WStacking
*stacking_unstack(WWindow
*par
, WStacking
*regst
)
166 WStacking
*nxt
=NULL
, *st
;
170 UNLINK_ITEM(par
->stacking
, regst
, next
, prev
);
173 for(st
=par
->stacking
; st
!=NULL
; st
=st
->next
){
174 if(st
->above
==regst
){
184 if(regst
->above
==NULL
)
191 static bool cf(WStackingFilter
*filt
, void *filt_data
, WStacking
*st
)
193 return (filt
==NULL
|| filt(st
, filt_data
));
197 static bool check_unweave(WStacking
*st
)
199 /* 2: unknown, 1: yes, 0: no */
201 if(st
->to_unweave
==2){
203 st
->to_unweave
=check_unweave(st
->above
);
208 return st
->to_unweave
;
212 WStacking
*stacking_unweave(WStacking
**stacking
,
213 WStackingFilter
*filt
, void *filt_data
)
216 WStacking
*st
, *next
;
218 for(st
=*stacking
; st
!=NULL
; st
=st
->next
){
220 if(st
->above
==NULL
&& cf(filt
, filt_data
, st
))
224 for(st
=*stacking
; st
!=NULL
; st
=st
->next
)
227 for(st
=*stacking
; st
!=NULL
; st
=next
){
229 if(st
->to_unweave
==1){
230 UNLINK_ITEM(*stacking
, st
, next
, prev
);
231 LINK_ITEM(np
, st
, next
, prev
);
239 static int check_above_lvl(WStacking
*st
)
243 st
->level
=check_above_lvl(st
->above
);
248 static void enforce_level_sanity(WStacking
**np
)
252 /* Make sure that the levels of stuff stacked 'above' match
253 * the level of the thing stacked above.
255 for(st
=*np
; st
!=NULL
; st
=st
->next
)
258 /* And now make sure things are ordered by levels. */
260 while(st
->next
!=NULL
){
261 if(st
->next
->level
< st
->level
){
262 WStacking
*st2
=st
->next
;
263 UNLINK_ITEM(*np
, st2
, next
, prev
);
264 LINK_ITEM_BEFORE(*np
, st2
, st
, next
, prev
);
274 static void get_bottom(WStacking
*st
, Window fb_win
,
275 Window
*other
, int *mode
)
277 Window bottom
=None
, top
=None
;
281 region_stacking(st
->reg
, &bottom
, &top
);
296 static void stacking_do_weave(WStacking
**stacking
, WStacking
**np
,
297 bool below
, Window fb_win
)
307 /* Should do nothing.. */
308 enforce_level_sanity(np
);
316 if(ab
->level
>lvl
|| (below
&& ab
->level
==lvl
))
320 get_bottom(ab
, fb_win
, &other
, &mode
);
324 UNLINK_ITEM(*np
, st
, next
, prev
);
326 region_restack(st
->reg
, other
, mode
);
329 LINK_ITEM_BEFORE(*stacking
, ab
, st
, next
, prev
);
331 LINK_ITEM_LAST(*stacking
, st
, next
, prev
);
337 void stacking_weave(WStacking
**stacking
, WStacking
**np
, bool below
)
339 stacking_do_weave(stacking
, np
, below
, None
);
349 static bool is_above(WStacking
*st
, WStacking
*p
)
353 else if(st
->above
==p
)
356 return is_above(st
->above
, p
);
360 static void collect_first(WStacking
**dst
, WStacking
**src
, WStacking
*st
)
362 UNLINK_ITEM(*src
, st
, next
, prev
);
363 LINK_ITEM_FIRST(*dst
, st
, next
, prev
);
367 static void collect_last(WStacking
**dst
, WStacking
**src
, WStacking
*st
)
369 UNLINK_ITEM(*src
, st
, next
, prev
);
370 LINK_ITEM_LAST(*dst
, st
, next
, prev
);
374 static void collect_above(WStacking
**dst
, WStacking
**src
, WStacking
*regst
)
376 WStacking
*stabove
, *stnext
;
378 for(stabove
=*src
; stabove
!=NULL
; stabove
=stnext
){
379 stnext
=stabove
->next
;
381 if(is_above(stabove
, regst
))
382 collect_last(dst
, src
, stabove
);
387 static WStacking
*unweave_subtree(WStacking
**stacking
, WStacking
*regst
,
395 collect_first(&tmp
, stacking
, st
);
399 collect_first(&tmp
, stacking
, regst
);
402 collect_above(&tmp
, stacking
, regst
);
408 void stacking_restack(WStacking
**stacking
, WStacking
*st
, Window fb_win
,
409 WStackingFilter
*filt
, void *filt_data
, bool lower
)
411 WStacking
*tmp
=unweave_subtree(stacking
, st
, lower
);
413 stacking_do_weave(stacking
, &tmp
, lower
, fb_win
);
422 /*{{{ Stacking lists */
425 WStacking
**window_get_stackingp(WWindow
*wwin
)
427 return &(wwin
->stacking
);
431 WStacking
*window_get_stacking(WWindow
*wwin
)
433 return wwin
->stacking
;
440 /*{{{ Stacking list iteration */
443 void stacking_iter_init(WStackingIterTmp
*tmp
,
445 WStackingFilter
*filt
,
450 tmp
->filt_data
=filt_data
;
454 WStacking
*stacking_iter_nodes(WStackingIterTmp
*tmp
)
456 WStacking
*next
=NULL
;
458 while(tmp
->st
!=NULL
){
460 tmp
->st
=tmp
->st
->next
;
461 if(cf(tmp
->filt
, tmp
->filt_data
, next
))
470 WRegion
*stacking_iter(WStackingIterTmp
*tmp
)
472 WStacking
*st
=stacking_iter_nodes(tmp
);
473 return (st
!=NULL
? st
->reg
: NULL
);
477 void stacking_iter_mgr_init(WStackingIterTmp
*tmp
,
479 WStackingFilter
*filt
,
484 tmp
->filt_data
=filt_data
;
488 WStacking
*stacking_iter_mgr_nodes(WStackingIterTmp
*tmp
)
490 WStacking
*next
=NULL
;
492 while(tmp
->st
!=NULL
){
494 tmp
->st
=tmp
->st
->mgr_next
;
495 if(cf(tmp
->filt
, tmp
->filt_data
, next
))
504 WRegion
*stacking_iter_mgr(WStackingIterTmp
*tmp
)
506 WStacking
*st
=stacking_iter_mgr_nodes(tmp
);
507 return (st
!=NULL
? st
->reg
: NULL
);
517 uint
stacking_min_level(WStacking
*stacking
,
518 WStackingFilter
*include_filt
,
521 uint min_level
=STACKING_LEVEL_BOTTOM
;
525 return STACKING_LEVEL_BOTTOM
;
532 && !(st
->reg
->flags
®ION_SKIP_FOCUS
)
533 && cf(include_filt
, filt_data
, st
)){
535 if(st
->level
>=STACKING_LEVEL_MODAL1
)
540 }while(st
!=stacking
);
546 WStacking
*stacking_find_to_focus(WStacking
*stacking
,
548 WStackingFilter
*include_filt
,
549 WStackingFilter
*approve_filt
,
552 uint min_level
=STACKING_LEVEL_BOTTOM
;
553 WStacking
*st
=NULL
, *found
=NULL
;
565 if(st
!=to_try
&& (st
->reg
->flags
®ION_SKIP_FOCUS
||
566 !cf(include_filt
, filt_data
, st
))){
571 if(st
->level
<min_level
)
577 if(found
==NULL
&& cf(approve_filt
, filt_data
, st
)){
583 if(st
->level
>=STACKING_LEVEL_MODAL1
)
584 min_level
=maxof(min_level
, st
->level
);
585 }while(st
!=stacking
);
591 static bool mapped_filt(WStacking
*st
, void *UNUSED(unused
))
593 return (st
->reg
!=NULL
&& REGION_IS_MAPPED(st
->reg
));
597 static bool mapped_filt_neq(WStacking
*st
, void *st_neq
)
599 return (st
!=(WStacking
*)st_neq
&& mapped_filt(st
, NULL
));
603 static bool mgr_filt(WStacking
*st
, void *mgr_
)
605 return (st
->reg
!=NULL
&& REGION_MANAGER(st
->reg
)==(WRegion
*)mgr_
);
609 WStacking
*stacking_find_to_focus_mapped(WStacking
*stacking
,
614 return stacking_find_to_focus(stacking
, to_try
, mapped_filt
,
617 return stacking_find_to_focus(stacking
, to_try
, mapped_filt
,
623 uint
stacking_min_level_mapped(WStacking
*stacking
)
625 return stacking_min_level(stacking
, mapped_filt
, NULL
);
629 bool stacking_must_focus(WStacking
*stacking
, WStacking
*st
)
631 WStacking
*stf
=stacking_find_to_focus(stacking
, NULL
,
632 mapped_filt_neq
, NULL
, st
);
635 (st
->level
>stf
->level
&&
636 st
->level
>=STACKING_LEVEL_MODAL1
));