Remove/mark some unused functions and parameters
[notion.git] / ioncore / stacking.c
blob5e213e2244a1b5cd05d1375bb8822dc05b5b5294
1 /*
2 * ion/ioncore/stacking.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <libtu/rb.h>
10 #include <libtu/minmax.h>
12 #include "common.h"
13 #include "region.h"
14 #include "stacking.h"
15 #include "window.h"
16 #include "sizepolicy.h"
19 /*{{{ Alloc */
22 WStacking *create_stacking()
24 WStacking *st=ALLOC(WStacking);
26 if(st!=NULL){
27 st->reg=NULL;
28 st->above=NULL;
29 st->level=0;
30 st->szplcy=SIZEPOLICY_DEFAULT;
31 st->hidden=FALSE;
32 st->lnode=NULL;
33 st->pseudomodal=FALSE;
36 return st;
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 &&*/
45 st->lnode==NULL &&
46 st->reg==NULL);
48 free(st);
52 /*}}}*/
55 /*{{{ Lookup */
58 static Rb_node stacking_of_reg=NULL;
61 WStacking *ioncore_find_stacking(WRegion *reg)
63 Rb_node node=NULL;
64 int found=0;
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)
75 Rb_node node=NULL;
76 int found=0;
78 if(st->reg==NULL)
79 return;
81 if(stacking_of_reg!=NULL)
82 node=rb_find_pkey_n(stacking_of_reg, st->reg, &found);
84 if(node!=NULL)
85 rb_delete_node(node);
87 st->reg=NULL;
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)
98 return FALSE;
101 if(rb_insertp(stacking_of_reg, reg, st)==NULL)
102 return FALSE;
104 st->reg=reg;
105 return TRUE;
109 /*}}}*/
113 /*{{{ List processing */
116 static WStacking *link_lists(WStacking *l1, WStacking *l2)
118 /* As everywhere, doubly-linked lists without the forward
119 * link in last item!
121 WStacking *tmp=l2->prev;
122 l1->prev->next=l2;
123 l2->prev=l1->prev;
124 l1->prev=tmp;
125 return l1;
129 static WStacking *link_list_before(WStacking *l1,
130 WStacking *i1,
131 WStacking *l2)
133 WStacking *tmp;
135 if(i1==l1)
136 return link_lists(l2, l1);
138 l2->prev->next=i1;
139 i1->prev->next=l2;
140 tmp=i1->prev;
141 i1->prev=l2->prev;
142 l2->prev=tmp;
144 return l1;
148 static WStacking *link_list_after(WStacking *l1,
149 WStacking *i1,
150 WStacking *l2)
152 if(i1==l1->prev)
153 return link_lists(l1, l2);
155 i1->next->prev=l2->prev;
156 l2->prev->next=i1->next;
157 i1->next=l2;
158 l2->prev=i1;
160 return l1;
164 WStacking *stacking_unstack(WWindow *par, WStacking *regst)
166 WStacking *nxt=NULL, *st;
168 /*st=regst->next;*/
170 UNLINK_ITEM(par->stacking, regst, next, prev);
172 /*while(st!=NULL){*/
173 for(st=par->stacking; st!=NULL; st=st->next){
174 if(st->above==regst){
175 st->above=NULL;
176 nxt=st;
178 /*st=st->next;*/
181 if(nxt==NULL)
182 nxt=regst->above;
184 if(regst->above==NULL)
185 regst->above=NULL;
187 return nxt;
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){
202 if(st->above!=NULL)
203 st->to_unweave=check_unweave(st->above);
204 else
205 st->to_unweave=0;
208 return st->to_unweave;
212 WStacking *stacking_unweave(WStacking **stacking,
213 WStackingFilter *filt, void *filt_data)
215 WStacking *np=NULL;
216 WStacking *st, *next;
218 for(st=*stacking; st!=NULL; st=st->next){
219 st->to_unweave=2;
220 if(st->above==NULL && cf(filt, filt_data, st))
221 st->to_unweave=1;
224 for(st=*stacking; st!=NULL; st=st->next)
225 check_unweave(st);
227 for(st=*stacking; st!=NULL; st=next){
228 next=st->next;
229 if(st->to_unweave==1){
230 UNLINK_ITEM(*stacking, st, next, prev);
231 LINK_ITEM(np, st, next, prev);
235 return np;
239 static int check_above_lvl(WStacking *st)
241 if(st->above==NULL)
242 return st->level;
243 st->level=check_above_lvl(st->above);
244 return st->level;
248 static void enforce_level_sanity(WStacking **np)
250 WStacking *st;
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)
256 check_above_lvl(st);
258 /* And now make sure things are ordered by levels. */
259 st=*np;
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);
265 if(st2->prev!=NULL)
266 st=st2->prev;
267 }else{
268 st=st->next;
274 static void get_bottom(WStacking *st, Window fb_win,
275 Window *other, int *mode)
277 Window bottom=None, top=None;
279 while(st!=NULL){
280 if(st->reg!=NULL){
281 region_stacking(st->reg, &bottom, &top);
282 if(bottom!=None){
283 *other=bottom;
284 *mode=Below;
285 return;
288 st=st->next;
291 *other=fb_win;
292 *mode=Above;
296 static void stacking_do_weave(WStacking **stacking, WStacking **np,
297 bool below, Window fb_win)
299 WStacking *st, *ab;
300 uint lvl;
301 Window other;
302 int mode;
304 if(*np==NULL)
305 return;
307 /* Should do nothing.. */
308 enforce_level_sanity(np);
310 ab=*stacking;
312 while(*np!=NULL){
313 lvl=(*np)->level;
315 while(ab!=NULL){
316 if(ab->level>lvl || (below && ab->level==lvl))
317 break;
318 ab=ab->next;
320 get_bottom(ab, fb_win, &other, &mode);
322 st=*np;
324 UNLINK_ITEM(*np, st, next, prev);
326 region_restack(st->reg, other, mode);
328 if(ab!=NULL){
329 LINK_ITEM_BEFORE(*stacking, ab, st, next, prev);
330 }else{
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);
343 /*}}}*/
346 /*{{{ Raise/lower */
349 static bool is_above(WStacking *st, WStacking *p)
351 if(st->above==NULL)
352 return FALSE;
353 else if(st->above==p)
354 return TRUE;
355 else
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,
388 bool parents)
390 WStacking *tmp=NULL;
392 if(parents){
393 WStacking *st=regst;
394 while(st!=NULL){
395 collect_first(&tmp, stacking, st);
396 st=st->above;
398 }else{
399 collect_first(&tmp, stacking, regst);
402 collect_above(&tmp, stacking, regst);
404 return tmp;
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);
415 assert(tmp==NULL);
419 /*}}}*/
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;
437 /*}}}*/
440 /*{{{ Stacking list iteration */
443 void stacking_iter_init(WStackingIterTmp *tmp,
444 WStacking *st,
445 WStackingFilter *filt,
446 void *filt_data)
448 tmp->st=st;
449 tmp->filt=filt;
450 tmp->filt_data=filt_data;
454 WStacking *stacking_iter_nodes(WStackingIterTmp *tmp)
456 WStacking *next=NULL;
458 while(tmp->st!=NULL){
459 next=tmp->st;
460 tmp->st=tmp->st->next;
461 if(cf(tmp->filt, tmp->filt_data, next))
462 break;
463 next=NULL;
466 return 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,
478 WStacking *st,
479 WStackingFilter *filt,
480 void *filt_data)
482 tmp->st=st;
483 tmp->filt=filt;
484 tmp->filt_data=filt_data;
488 WStacking *stacking_iter_mgr_nodes(WStackingIterTmp *tmp)
490 WStacking *next=NULL;
492 while(tmp->st!=NULL){
493 next=tmp->st;
494 tmp->st=tmp->st->mgr_next;
495 if(cf(tmp->filt, tmp->filt_data, next))
496 break;
497 next=NULL;
500 return next;
504 WRegion *stacking_iter_mgr(WStackingIterTmp *tmp)
506 WStacking *st=stacking_iter_mgr_nodes(tmp);
507 return (st!=NULL ? st->reg : NULL);
511 /*}}}*/
514 /*{{{ Focus */
517 uint stacking_min_level(WStacking *stacking,
518 WStackingFilter *include_filt,
519 void *filt_data)
521 uint min_level=STACKING_LEVEL_BOTTOM;
522 WStacking *st=NULL;
524 if(stacking==NULL)
525 return STACKING_LEVEL_BOTTOM;
527 st=stacking;
529 st=st->prev;
531 if(st->reg!=NULL
532 && !(st->reg->flags&REGION_SKIP_FOCUS)
533 && cf(include_filt, filt_data, st)){
535 if(st->level>=STACKING_LEVEL_MODAL1)
536 min_level=st->level;
538 break;
540 }while(st!=stacking);
542 return min_level;
546 WStacking *stacking_find_to_focus(WStacking *stacking,
547 WStacking *to_try,
548 WStackingFilter *include_filt,
549 WStackingFilter *approve_filt,
550 void *filt_data)
552 uint min_level=STACKING_LEVEL_BOTTOM;
553 WStacking *st=NULL, *found=NULL;
555 if(stacking==NULL)
556 return NULL;
558 st=stacking;
560 st=st->prev;
562 if(st->reg==NULL)
563 continue;
565 if(st!=to_try && (st->reg->flags&REGION_SKIP_FOCUS ||
566 !cf(include_filt, filt_data, st))){
567 /* skip */
568 continue;
571 if(st->level<min_level)
572 break; /* no luck */
574 if(st==to_try)
575 return st;
577 if(found==NULL && cf(approve_filt, filt_data, st)){
578 found=st;
579 if(to_try==NULL)
580 break;
583 if(st->level>=STACKING_LEVEL_MODAL1)
584 min_level=maxof(min_level, st->level);
585 }while(st!=stacking);
587 return found;
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,
610 WStacking *to_try,
611 WRegion *mgr)
613 if(mgr==NULL){
614 return stacking_find_to_focus(stacking, to_try, mapped_filt,
615 NULL, NULL);
616 }else{
617 return stacking_find_to_focus(stacking, to_try, mapped_filt,
618 mgr_filt, mgr);
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);
634 return (stf==NULL ||
635 (st->level>stf->level &&
636 st->level>=STACKING_LEVEL_MODAL1));
640 /*}}}*/