]> git.decadent.org.uk Git - ion3.git/blob - ioncore/stacking.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / stacking.c
1 /*
2  * ion/ioncore/stacking.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009.
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <libtu/rb.h>
10 #include <libtu/minmax.h>
11
12 #include "common.h"
13 #include "region.h"
14 #include "stacking.h"
15 #include "window.h"
16 #include "sizepolicy.h"
17
18
19 /*{{{ Alloc */
20
21
22 WStacking *create_stacking()
23 {
24     WStacking *st=ALLOC(WStacking);
25     
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;
34     }
35     
36     return st;
37 }
38
39
40 void stacking_free(WStacking *st)
41 {
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);
47     
48     free(st);
49 }
50
51
52 /*}}}*/
53
54
55 /*{{{ Lookup */
56
57
58 static Rb_node stacking_of_reg=NULL;
59
60
61 WStacking *ioncore_find_stacking(WRegion *reg)
62 {
63     Rb_node node=NULL;
64     int found=0;
65     
66     if(stacking_of_reg!=NULL)
67         node=rb_find_pkey_n(stacking_of_reg, reg, &found);
68     
69     return (found ? (WStacking*)node->v.val : NULL);
70 }
71
72
73 void stacking_unassoc(WStacking *st)
74 {
75     Rb_node node=NULL;
76     int found=0;
77     
78     if(st->reg==NULL)
79         return;
80     
81     if(stacking_of_reg!=NULL)
82         node=rb_find_pkey_n(stacking_of_reg, st->reg, &found);
83     
84     if(node!=NULL)
85         rb_delete_node(node);
86     
87     st->reg=NULL;
88 }
89
90
91 bool stacking_assoc(WStacking *st, WRegion *reg)
92 {
93     assert(st->reg==NULL);
94     
95     if(stacking_of_reg==NULL){
96         stacking_of_reg=make_rb();
97         if(stacking_of_reg==NULL)
98             return FALSE;
99     }
100
101     if(rb_insertp(stacking_of_reg, reg, st)==NULL)
102         return FALSE;
103     
104     st->reg=reg;
105     return TRUE;
106 }
107
108
109 /*}}}*/
110
111
112
113 /*{{{ List processing */
114
115
116 static WStacking *link_lists(WStacking *l1, WStacking *l2)
117 {
118     /* As everywhere, doubly-linked lists without the forward 
119      * link in last item! 
120      */
121     WStacking *tmp=l2->prev;
122     l1->prev->next=l2;
123     l2->prev=l1->prev;
124     l1->prev=tmp;
125     return l1;
126 }
127
128
129 static WStacking *link_list_before(WStacking *l1, 
130                                    WStacking *i1,
131                                    WStacking *l2)
132 {
133     WStacking *tmp;
134     
135     if(i1==l1)
136         return link_lists(l2, l1);
137     
138     l2->prev->next=i1;
139     i1->prev->next=l2;
140     tmp=i1->prev;
141     i1->prev=l2->prev;
142     l2->prev=tmp;
143     
144     return l1;
145 }
146
147
148 static WStacking *link_list_after(WStacking *l1, 
149                                   WStacking *i1,
150                                   WStacking *l2)
151 {
152     WStacking *tmp;
153     
154     if(i1==l1->prev)
155         return link_lists(l1, l2);
156     
157     i1->next->prev=l2->prev;
158     l2->prev->next=i1->next;
159     i1->next=l2;
160     l2->prev=i1;
161     
162     return l1;
163 }
164
165
166 WStacking *stacking_unstack(WWindow *par, WStacking *regst)
167 {
168     WStacking *nxt=NULL, *st;
169     
170     /*st=regst->next;*/
171     
172     UNLINK_ITEM(par->stacking, regst, next, prev);
173             
174     /*while(st!=NULL){*/
175     for(st=par->stacking; st!=NULL; st=st->next){
176         if(st->above==regst){
177             st->above=NULL;
178             nxt=st;
179         }
180         /*st=st->next;*/
181     }
182     
183     if(nxt==NULL)
184         nxt=regst->above;
185     
186     if(regst->above==NULL)
187         regst->above=NULL;
188     
189     return nxt;
190 }
191
192
193 static bool cf(WStackingFilter *filt, void *filt_data, WStacking *st)
194 {
195     return (filt==NULL || filt(st, filt_data));
196 }
197
198
199 static bool check_unweave(WStacking *st)
200 {
201     /* 2: unknown, 1: yes, 0: no */
202     
203     if(st->to_unweave==2){
204         if(st->above!=NULL)
205             st->to_unweave=check_unweave(st->above);
206         else
207             st->to_unweave=0;
208     }
209     
210     return st->to_unweave;
211 }
212
213
214 WStacking *stacking_unweave(WStacking **stacking, 
215                             WStackingFilter *filt, void *filt_data)
216 {
217     WStacking *np=NULL;
218     WStacking *st, *next;
219
220     for(st=*stacking; st!=NULL; st=st->next){
221         st->to_unweave=2;
222         if(st->above==NULL && cf(filt, filt_data, st))
223             st->to_unweave=1;
224     }
225     
226     for(st=*stacking; st!=NULL; st=st->next)
227         check_unweave(st);
228     
229     for(st=*stacking; st!=NULL; st=next){
230         next=st->next;
231         if(st->to_unweave==1){
232             UNLINK_ITEM(*stacking, st, next, prev);
233             LINK_ITEM(np, st, next, prev);
234         }
235     }
236     
237     return np;
238 }
239
240
241 static int check_above_lvl(WStacking *st)
242 {
243     if(st->above==NULL)
244         return st->level;
245     st->level=check_above_lvl(st->above);
246     return st->level;
247 }
248
249     
250 static void enforce_level_sanity(WStacking **np)
251 {
252     WStacking *st;
253     
254     /* Make sure that the levels of stuff stacked 'above' match
255      * the level of the thing stacked above.
256      */
257     for(st=*np; st!=NULL; st=st->next)
258         check_above_lvl(st);
259
260     /* And now make sure things are ordered by levels. */
261     st=*np; 
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);
267             if(st2->prev!=NULL)
268                 st=st2->prev;
269         }else{
270             st=st->next;
271         }
272     }
273 }
274
275
276 static void get_bottom(WStacking *st, Window fb_win,
277                        Window *other, int *mode)
278 {
279     Window bottom=None, top=None;
280     
281     while(st!=NULL){
282         if(st->reg!=NULL){
283             region_stacking(st->reg, &bottom, &top);
284             if(bottom!=None){
285                 *other=bottom;
286                 *mode=Below;
287                 return;
288             }
289         }
290         st=st->next;
291     }
292     
293     *other=fb_win;
294     *mode=Above;
295 }
296
297
298 static void stacking_do_weave(WStacking **stacking, WStacking **np, 
299                               bool below, Window fb_win)
300 {
301     WStacking *st, *ab;
302     uint lvl;
303     Window other;
304     int mode;
305
306     if(*np==NULL)
307         return;
308     
309     /* Should do nothing.. */
310     enforce_level_sanity(np);
311     
312     ab=*stacking;
313     
314     while(*np!=NULL){
315         lvl=(*np)->level;
316         
317         while(ab!=NULL){
318             if(ab->level>lvl || (below && ab->level==lvl))
319                 break;
320             ab=ab->next;
321         }
322         get_bottom(ab, fb_win, &other, &mode);
323         
324         st=*np;
325
326         UNLINK_ITEM(*np, st, next, prev);
327         
328         region_restack(st->reg, other, mode);
329
330         if(ab!=NULL){
331             LINK_ITEM_BEFORE(*stacking, ab, st, next, prev);
332         }else{
333             LINK_ITEM_LAST(*stacking, st, next, prev);
334         }
335     }
336 }
337
338
339 void stacking_weave(WStacking **stacking, WStacking **np, bool below)
340 {
341     stacking_do_weave(stacking, np, below, None);
342 }
343
344
345 /*}}}*/
346
347
348 /*{{{ Raise/lower */
349
350
351 static bool is_above(WStacking *st, WStacking *p)
352 {
353     if(st->above==NULL)
354         return FALSE;
355     else if(st->above==p)
356         return TRUE;
357     else
358         return is_above(st->above, p);
359 }
360
361
362 static void collect_first(WStacking **dst, WStacking **src, WStacking *st)
363 {
364     UNLINK_ITEM(*src, st, next, prev);
365     LINK_ITEM_FIRST(*dst, st, next, prev);
366 }
367
368
369 static void collect_last(WStacking **dst, WStacking **src, WStacking *st)
370 {
371     UNLINK_ITEM(*src, st, next, prev);
372     LINK_ITEM_LAST(*dst, st, next, prev);
373 }
374
375
376 static void collect_above(WStacking **dst, WStacking **src, WStacking *regst)
377 {
378     WStacking *stabove, *stnext;
379     
380     for(stabove=*src; stabove!=NULL; stabove=stnext){
381         stnext=stabove->next;
382         
383         if(is_above(stabove, regst))
384             collect_last(dst, src, stabove);
385     }
386 }
387
388
389 static WStacking *unweave_subtree(WStacking **stacking, WStacking *regst,
390                                   bool parents)
391 {
392     WStacking *tmp=NULL;
393     
394     if(parents){
395         WStacking *st=regst;
396         while(st!=NULL){
397             collect_first(&tmp, stacking, st);
398             st=st->above;
399         }
400     }else{
401         collect_first(&tmp, stacking, regst);
402     }
403     
404     collect_above(&tmp, stacking, regst);
405     
406     return tmp;
407 }
408
409
410 void stacking_restack(WStacking **stacking, WStacking *st, Window fb_win,
411                       WStackingFilter *filt, void *filt_data, bool lower)
412 {
413     WStacking *tmp=unweave_subtree(stacking, st, lower);
414
415     stacking_do_weave(stacking, &tmp, lower, fb_win);
416
417     assert(tmp==NULL);
418 }
419
420
421 /*}}}*/
422
423
424 /*{{{ Stacking lists */
425
426
427 WStacking **window_get_stackingp(WWindow *wwin)
428 {
429     return &(wwin->stacking);
430 }
431
432
433 WStacking *window_get_stacking(WWindow *wwin)
434 {
435     return wwin->stacking;
436 }
437
438
439 /*}}}*/
440
441
442 /*{{{ Stacking list iteration */
443
444
445 void stacking_iter_init(WStackingIterTmp *tmp, 
446                         WStacking *st,
447                         WStackingFilter *filt,
448                         void *filt_data)
449 {
450     tmp->st=st;
451     tmp->filt=filt;
452     tmp->filt_data=filt_data;
453 }
454
455
456 WStacking *stacking_iter_nodes(WStackingIterTmp *tmp)
457 {
458     WStacking *next=NULL;
459     
460     while(tmp->st!=NULL){
461         next=tmp->st;
462         tmp->st=tmp->st->next;
463         if(cf(tmp->filt, tmp->filt_data, next))
464             break;
465         next=NULL;
466     }
467     
468     return next;
469 }
470
471
472 WRegion *stacking_iter(WStackingIterTmp *tmp)
473 {
474     WStacking *st=stacking_iter_nodes(tmp);
475     return (st!=NULL ? st->reg : NULL);
476 }
477
478
479 void stacking_iter_mgr_init(WStackingIterTmp *tmp, 
480                             WStacking *st,
481                             WStackingFilter *filt,
482                             void *filt_data)
483 {
484     tmp->st=st;
485     tmp->filt=filt;
486     tmp->filt_data=filt_data;
487 }
488
489
490 WStacking *stacking_iter_mgr_nodes(WStackingIterTmp *tmp)
491 {
492     WStacking *next=NULL;
493     
494     while(tmp->st!=NULL){
495         next=tmp->st;
496         tmp->st=tmp->st->mgr_next;
497         if(cf(tmp->filt, tmp->filt_data, next))
498             break;
499         next=NULL;
500     }
501     
502     return next;
503 }
504
505
506 WRegion *stacking_iter_mgr(WStackingIterTmp *tmp)
507 {
508     WStacking *st=stacking_iter_mgr_nodes(tmp);
509     return (st!=NULL ? st->reg : NULL);
510 }
511
512     
513 /*}}}*/
514
515
516 /*{{{ Focus */
517
518
519 uint stacking_min_level(WStacking *stacking, 
520                         WStackingFilter *include_filt, 
521                         void *filt_data)
522 {
523     uint min_level=STACKING_LEVEL_BOTTOM;
524     WStacking *st=NULL;
525     
526     if(stacking==NULL)
527         return STACKING_LEVEL_BOTTOM;
528     
529     st=stacking;
530     do{
531         st=st->prev;
532         
533         if(st->reg!=NULL 
534            && !(st->reg->flags&REGION_SKIP_FOCUS)
535            && cf(include_filt, filt_data, st)){
536             
537             if(st->level>=STACKING_LEVEL_MODAL1)
538                 min_level=st->level;
539             
540             break;
541         }
542     }while(st!=stacking);
543     
544     return min_level;
545 }
546
547
548 WStacking *stacking_find_to_focus(WStacking *stacking, 
549                                   WStacking *to_try,
550                                   WStackingFilter *include_filt, 
551                                   WStackingFilter *approve_filt, 
552                                   void *filt_data)
553 {
554     uint min_level=STACKING_LEVEL_BOTTOM;
555     WStacking *st=NULL, *found=NULL;
556     
557     if(stacking==NULL)
558         return NULL;
559     
560     st=stacking;
561     do{
562         st=st->prev;
563         
564         if(st->reg==NULL)
565             continue;
566         
567         if(st!=to_try && (st->reg->flags&REGION_SKIP_FOCUS ||
568                           !cf(include_filt, filt_data, st))){
569             /* skip */
570             continue;
571         }
572         
573         if(st->level<min_level)
574             break; /* no luck */
575         
576         if(st==to_try)
577             return st;
578             
579         if(found==NULL && cf(approve_filt, filt_data, st)){
580             found=st;
581             if(to_try==NULL)
582                 break;
583         }
584             
585         if(st->level>=STACKING_LEVEL_MODAL1)
586             min_level=maxof(min_level, st->level);
587     }while(st!=stacking);
588     
589     return found;
590 }
591
592
593 static bool mapped_filt(WStacking *st, void *unused)
594 {
595     return (st->reg!=NULL && REGION_IS_MAPPED(st->reg));
596 }
597
598
599 static bool mapped_filt_neq(WStacking *st, void *st_neq)
600 {
601     return (st!=(WStacking*)st_neq && mapped_filt(st, NULL));
602 }
603
604
605 static bool mgr_filt(WStacking *st, void *mgr_)
606 {
607     return (st->reg!=NULL && REGION_MANAGER(st->reg)==(WRegion*)mgr_);
608 }
609
610
611 WStacking *stacking_find_to_focus_mapped(WStacking *stacking, 
612                                          WStacking *to_try,
613                                          WRegion *mgr)
614 {
615     if(mgr==NULL){
616         return stacking_find_to_focus(stacking, to_try, mapped_filt, 
617                                       NULL, NULL);
618     }else{
619         return stacking_find_to_focus(stacking, to_try, mapped_filt, 
620                                       mgr_filt, mgr);
621     }
622 }
623
624
625 uint stacking_min_level_mapped(WStacking *stacking)
626 {
627     return stacking_min_level(stacking, mapped_filt, NULL);
628 }
629
630
631 bool stacking_must_focus(WStacking *stacking, WStacking *st)
632 {
633     WStacking *stf=stacking_find_to_focus(stacking, NULL, 
634                                           mapped_filt_neq, NULL, st);
635     
636     return (stf==NULL || 
637             (st->level>stf->level &&
638              st->level>=STACKING_LEVEL_MODAL1));
639 }
640
641
642 /*}}}*/
643