]> git.decadent.org.uk Git - ion3.git/blob - mod_statusbar/statusbar.c
[svn-inject] Installing original source of ion3
[ion3.git] / mod_statusbar / statusbar.c
1 /*
2  * ion/mod_statusbar/statusbar.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2006. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libtu/ptrlist.h>
17 #include <libtu/misc.h>
18 #include <ioncore/common.h>
19 #include <ioncore/global.h>
20 #include <ioncore/window.h>
21 #include <ioncore/binding.h>
22 #include <ioncore/regbind.h>
23 #include <ioncore/event.h>
24 #include <ioncore/resize.h>
25 #include <ioncore/gr.h>
26 #include <ioncore/names.h>
27 #include <ioncore/strings.h>
28 #include <ioncore/basicpholder.h>
29 #include <ioncore/sizehint.h>
30
31 #include "statusbar.h"
32 #include "main.h"
33 #include "draw.h"
34
35
36 static void statusbar_set_elems(WStatusBar *sb, ExtlTab t);
37 static void statusbar_free_elems(WStatusBar *sb);
38 static void statusbar_update_natural_size(WStatusBar *p);
39 static void statusbar_arrange_systray(WStatusBar *p);
40 static int statusbar_systray_x(WStatusBar *p);
41 static void statusbar_rearrange(WStatusBar *sb, bool rs);
42 static void do_calc_systray_w(WStatusBar *p, WSBElem *el);
43 static void statusbar_calc_systray_w(WStatusBar *p);
44
45
46 static WStatusBar *statusbars=NULL;
47
48
49 /*{{{ Init/deinit */
50
51
52 bool statusbar_init(WStatusBar *p, WWindow *parent, const WFitParams *fp)
53 {
54     if(!window_init(&(p->wwin), parent, fp))
55         return FALSE;
56
57     p->brush=NULL;
58     p->elems=NULL;
59     p->nelems=0;
60     p->natural_w=1;
61     p->natural_h=1;
62     p->filleridx=-1;
63     p->sb_next=NULL;
64     p->sb_prev=NULL;
65     p->traywins=NULL;
66     p->systray_enabled=TRUE;
67     
68     statusbar_updategr(p);
69
70     if(p->brush==NULL){
71         window_deinit(&(p->wwin));
72         return FALSE;
73     }
74     
75     window_select_input(&(p->wwin), IONCORE_EVENTMASK_NORMAL);
76     
77     region_register((WRegion*)p);
78
79     region_add_bindmap((WRegion*)p, mod_statusbar_statusbar_bindmap);
80     
81     ((WRegion*)p)->flags|=REGION_SKIP_FOCUS;
82
83     LINK_ITEM(statusbars, p, sb_next, sb_prev);
84     
85     return TRUE;
86 }
87
88
89
90 WStatusBar *create_statusbar(WWindow *parent, const WFitParams *fp)
91 {
92     CREATEOBJ_IMPL(WStatusBar, statusbar, (p, parent, fp));
93 }
94
95
96 void statusbar_deinit(WStatusBar *p)
97 {
98     UNLINK_ITEM(statusbars, p, sb_next, sb_prev);
99
100     statusbar_free_elems(p);
101     
102     if(p->brush!=NULL){
103         grbrush_release(p->brush);
104         p->brush=NULL;
105     }
106     
107     window_deinit(&(p->wwin));
108 }
109
110
111 /*}}}*/
112
113
114 /*{{{ Content stuff */
115
116 static void init_sbelem(WSBElem *el)
117 {
118     el->type=WSBELEM_NONE;
119     el->meter=NULL;
120     el->text_w=0;
121     el->text=NULL;
122     el->max_w=0;
123     el->tmpl=NULL;
124     el->attr=NULL;
125     el->stretch=0;
126     el->align=WSBELEM_ALIGN_CENTER;
127     el->zeropad=0;
128     el->x=0;
129     el->traywins=NULL;
130 }
131
132
133 static WSBElem *get_sbelems(ExtlTab t, int *nret, int *filleridxret)
134 {
135     int i, n=extl_table_get_n(t);
136     WSBElem *el;
137     int systrayidx=-1;
138     
139     *nret=0;
140     *filleridxret=-1;
141     
142     if(n<=0)
143         return NULL;
144     
145     el=ALLOC_N(WSBElem, n); 
146     
147     if(el==NULL)
148         return NULL;
149     
150     for(i=0; i<n; i++){
151         ExtlTab tt;
152         
153         init_sbelem(&el[i]);
154
155         if(extl_table_geti_t(t, i+1, &tt)){
156             if(extl_table_gets_i(tt, "type", &(el[i].type))){
157                 if(el[i].type==WSBELEM_TEXT || el[i].type==WSBELEM_STRETCH){
158                     extl_table_gets_s(tt, "text", &(el[i].text));
159                 }else if(el[i].type==WSBELEM_METER){
160                     extl_table_gets_s(tt, "meter", &(el[i].meter));
161                     extl_table_gets_s(tt, "tmpl", &(el[i].tmpl));
162                     extl_table_gets_i(tt, "align", &(el[i].align));
163                     extl_table_gets_i(tt, "zeropad", &(el[i].zeropad));
164                     el[i].zeropad=maxof(el[i].zeropad, 0);
165                 }else if(el[i].type==WSBELEM_SYSTRAY){
166                     extl_table_gets_s(tt, "meter", &(el[i].meter));
167                     extl_table_gets_i(tt, "align", &(el[i].align));
168                     if(el[i].meter==NULL || strcmp(el[i].meter, "systray")==0)
169                         systrayidx=i;
170                 }else if(el[i].type==WSBELEM_FILLER){
171                     *filleridxret=i;
172                 }
173             }
174             extl_unref_table(tt);
175         }
176     }
177     
178     if(systrayidx==-1){
179         WSBElem *el2=REALLOC_N(el, WSBElem, n, n+1);
180         if(el2!=NULL){
181             el=el2;
182             init_sbelem(&el[n]);
183             el[n].type=WSBELEM_SYSTRAY;
184             n++;
185         }
186     }
187     
188     *nret=n;
189     
190     return el;
191 }
192     
193
194 static void free_sbelems(WSBElem *el, int n)
195 {
196     int i;
197     
198     for(i=0; i<n; i++){
199         if(el[i].text!=NULL)
200             free(el[i].text);
201         if(el[i].meter!=NULL)
202             free(el[i].meter);
203         if(el[i].tmpl!=NULL)
204             free(el[i].tmpl);
205         if(el[i].attr!=NULL)
206             free(el[i].attr);
207         if(el[i].traywins!=NULL)
208             ptrlist_clear(&el[i].traywins);
209     }
210     
211     free(el);
212 }
213
214
215 static void statusbar_set_elems(WStatusBar *sb, ExtlTab t)
216 {
217     statusbar_free_elems(sb);
218     
219     sb->elems=get_sbelems(t, &(sb->nelems), &(sb->filleridx));
220 }
221
222
223 static void statusbar_free_elems(WStatusBar *sb)
224 {
225     if(sb->elems!=NULL){
226         free_sbelems(sb->elems, sb->nelems);
227         sb->elems=NULL;
228         sb->nelems=0;
229         sb->filleridx=-1;
230     }
231 }
232
233
234 /*}}}*/
235
236
237
238 /*{{{ Size stuff */
239
240
241 static void statusbar_resize(WStatusBar *p)
242 {
243     WRQGeomParams rq=RQGEOMPARAMS_INIT;
244     
245     rq.flags=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
246     
247     rq.geom.w=p->natural_w;
248     rq.geom.h=p->natural_h;
249     rq.geom.x=REGION_GEOM(p).x;
250     rq.geom.y=REGION_GEOM(p).y;
251
252     if(rectangle_compare(&rq.geom, &REGION_GEOM(p))!=RECTANGLE_SAME)
253         region_rqgeom((WRegion*)p, &rq, NULL);
254 }
255
256
257 static void calc_elem_w(WStatusBar *p, WSBElem *el, GrBrush *brush)
258 {
259     const char *str;
260
261     if(el->type==WSBELEM_SYSTRAY){
262         do_calc_systray_w(p, el);
263         return;
264     }
265     
266     if(brush==NULL){
267         el->text_w=0;
268         return;
269     }
270     
271     if(el->type==WSBELEM_METER){
272         str=(el->text!=NULL ? el->text : STATUSBAR_NX_STR);
273         el->text_w=grbrush_get_text_width(brush, str, strlen(str));
274         str=el->tmpl;
275         el->max_w=maxof((str!=NULL
276                          ? grbrush_get_text_width(brush, str, strlen(str))
277                          : 0),
278                         el->text_w);
279     }else{
280         str=el->text;
281         el->text_w=(str!=NULL
282                     ? grbrush_get_text_width(brush, str, strlen(str))
283                     : 0);
284         el->max_w=el->text_w;
285     }
286 }
287
288
289 static void statusbar_calc_widths(WStatusBar *sb)
290 {
291     int i;
292     
293     for(i=0; i<sb->nelems; i++)
294         calc_elem_w(sb, &(sb->elems[i]), sb->brush);
295 }
296
297
298 static void statusbar_do_update_natural_size(WStatusBar *p)
299 {
300     GrBorderWidths bdw;
301     GrFontExtents fnte;
302     WRegion *reg;
303     PtrListIterTmp tmp;
304     int totw=0, stmh=0;
305     int i;
306
307     if(p->brush==NULL){
308         bdw.left=0; bdw.right=0;
309         bdw.top=0; bdw.bottom=0;
310         fnte.max_height=4;
311     }else{
312         grbrush_get_border_widths(p->brush, &bdw);
313         grbrush_get_font_extents(p->brush, &fnte);
314     }
315     
316     for(i=0; i<p->nelems; i++)
317         totw+=p->elems[i].max_w;
318         
319     FOR_ALL_ON_PTRLIST(WRegion*, reg, p->traywins, tmp){
320         stmh=maxof(stmh, REGION_GEOM(reg).h);
321     }
322     
323     p->natural_w=bdw.left+totw+bdw.right;
324     p->natural_h=maxof(stmh, fnte.max_height)+bdw.top+bdw.bottom;
325 }
326
327
328 void statusbar_size_hints(WStatusBar *p, WSizeHints *h)
329 {
330     h->min_set=TRUE;
331     h->min_width=p->natural_w;
332     h->min_height=p->natural_h;
333     
334     h->max_set=TRUE;
335     h->max_width=p->natural_w;
336     h->max_height=p->natural_h;
337 }
338
339
340 /*}}}*/
341
342
343 /*{{{ Systray */
344
345
346 static WSBElem *statusbar_associate_systray(WStatusBar *sb, WRegion *reg)
347 {
348     WClientWin *cwin=OBJ_CAST(reg, WClientWin);
349     WSBElem *el=NULL, *fbel=NULL;
350     char *name=NULL;
351     int i;
352     
353     if(cwin!=NULL)
354         extl_table_gets_s(cwin->proptab, "statusbar", &name);
355     
356     for(i=0; i<sb->nelems; i++){
357         if(sb->elems[i].type!=WSBELEM_SYSTRAY)
358             continue;
359         if(sb->elems[i].meter==NULL){
360             fbel=&sb->elems[i];
361             continue;
362         }
363         if(name!=NULL && strcmp(sb->elems[i].meter, name)==0){
364             el=&sb->elems[i];
365             break;
366         }
367         if(strcmp(sb->elems[i].meter, "systray")==0)
368             fbel=&sb->elems[i];
369     }
370     
371     if(name!=NULL)
372         free(name);
373         
374     if(el==NULL)
375         el=fbel;
376     
377     if(el==NULL)
378         return NULL;
379     
380     ptrlist_insert_last(&el->traywins, (Obj*)reg);
381     
382     return el;
383 }
384
385
386 static WSBElem *statusbar_unassociate_systray(WStatusBar *sb, WRegion *reg)
387 {
388     int i;
389     
390     for(i=0; i<sb->nelems; i++){
391         if(ptrlist_remove(&(sb->elems[i].traywins), (Obj*)reg))
392             return &sb->elems[i];
393     }
394     
395     return NULL;
396 }
397
398     
399
400 static void do_calc_systray_w(WStatusBar *p, WSBElem *el)
401 {
402     WRegion *reg;
403     PtrListIterTmp tmp;
404     int padding=0;
405     int w=-padding;
406     
407     FOR_ALL_ON_PTRLIST(WRegion*, reg, el->traywins, tmp){
408         w=w+REGION_GEOM(reg).w+padding;
409     }
410     
411     el->text_w=maxof(0, w);
412     el->max_w=el->text_w; /* for now */
413 }
414
415
416 static void statusbar_calc_systray_w(WStatusBar *p)
417 {
418     int i;
419     
420     for(i=0; i<p->nelems; i++){
421         if(p->elems[i].type==WSBELEM_SYSTRAY)
422             do_calc_systray_w(p, &p->elems[i]);
423     }
424 }
425
426
427 static void statusbar_arrange_systray(WStatusBar *p)
428 {
429     WRegion *reg;
430     PtrListIterTmp tmp;
431     GrBorderWidths bdw;
432     int padding=0, ymiddle;
433     int i, x;
434     
435     if(p->brush!=NULL){
436         grbrush_get_border_widths(p->brush, &bdw);
437     }else{
438         bdw.top=0;
439         bdw.bottom=0;
440     }
441     
442     ymiddle=bdw.top+(REGION_GEOM(p).h-bdw.top-bdw.bottom)/2;
443     
444     for(i=0; i<p->nelems; i++){
445         WSBElem *el=&p->elems[i];
446         if(el->type!=WSBELEM_SYSTRAY)
447             continue;
448         x=el->x;
449         FOR_ALL_ON_PTRLIST(WRegion*, reg, el->traywins, tmp){
450             WRectangle g=REGION_GEOM(reg);
451             g.x=x;
452             g.y=ymiddle-g.h/2;
453             region_fit(reg, &g, REGION_FIT_EXACT);
454             x=x+g.w+padding;
455         }
456     }
457 }
458
459
460 static void systray_adjust_size(WRegion *reg, WRectangle *g)
461 {
462     g->h=CF_STATUSBAR_SYSTRAY_HEIGHT;
463     
464     region_size_hints_correct(reg, &g->w, &g->h, TRUE);
465 }
466
467
468
469 static WRegion *statusbar_do_attach_final(WStatusBar *sb,
470                                           WRegion *reg,
471                                           void *unused)
472 {
473     WFitParams fp;
474     WSBElem *el;
475     
476     if(!ptrlist_insert_last(&sb->traywins, (Obj*)reg))
477         return NULL;
478     
479     el=statusbar_associate_systray(sb, reg);
480     if(el==NULL){
481         ptrlist_remove(&sb->traywins, (Obj*)reg);
482         return NULL;
483     }
484
485     fp.g=REGION_GEOM(reg);
486     fp.mode=REGION_FIT_EXACT;
487     systray_adjust_size(reg, &fp.g);
488     
489     region_fitrep(reg, NULL, &fp);
490     
491     do_calc_systray_w(sb, el);
492
493     region_set_manager(reg, (WRegion*)sb);
494     
495     statusbar_rearrange(sb, TRUE);
496     
497     if(REGION_IS_MAPPED(sb))
498         region_map(reg);
499     
500     return reg;
501 }
502
503
504 static WRegion *statusbar_do_attach(WStatusBar *sb, WRegionAttachData *data)
505 {
506     WFitParams fp;
507     
508     fp.g.x=0;
509     fp.g.y=0;
510     fp.g.h=CF_STATUSBAR_SYSTRAY_HEIGHT;
511     fp.g.w=CF_STATUSBAR_SYSTRAY_HEIGHT;
512     fp.mode=REGION_FIT_WHATEVER|REGION_FIT_BOUNDS;
513     
514     return region_attach_helper((WRegion*)sb, (WWindow*)sb, &fp,
515                                 (WRegionDoAttachFn*)statusbar_do_attach_final, 
516                                 NULL, data);
517 }
518
519
520 static WRegion *statusbar_attach_ph(WStatusBar *sb, int flags,
521                                     WRegionAttachData *data)
522 {
523     return statusbar_do_attach(sb, data);
524 }
525
526
527 static WPHolder *statusbar_prepare_manage(WStatusBar *sb, 
528                                           const WClientWin *cwin,
529                                           const WManageParams *param,
530                                           int redir)
531 {
532     if(redir==MANAGE_REDIR_STRICT_YES)
533         return NULL;
534     
535     return (WPHolder*)create_basicpholder((WRegion*)sb, 
536                                           ((WBasicPHolderHandler*)
537                                            statusbar_attach_ph));
538 }
539
540
541 static void statusbar_managed_remove(WStatusBar *sb, WRegion *reg)
542 {
543     WSBElem *el;
544         
545     ptrlist_remove(&sb->traywins, (Obj*)reg);
546     
547     el=statusbar_unassociate_systray(sb, reg);
548     
549     region_unset_manager(reg, (WRegion*)sb);
550
551     if(el!=NULL && ioncore_g.opmode!=IONCORE_OPMODE_DEINIT){
552         do_calc_systray_w(sb, el);
553         statusbar_rearrange(sb, TRUE);
554     }
555 }
556
557
558 static void statusbar_managed_rqgeom(WStatusBar *sb, WRegion *reg, 
559                                      const WRQGeomParams *rq,
560                                      WRectangle *geomret)
561 {
562     WRectangle g;
563     
564     g.x=REGION_GEOM(reg).x;
565     g.y=REGION_GEOM(reg).y;
566     g.w=rq->geom.w;
567     g.h=rq->geom.h;
568
569     systray_adjust_size(reg, &g);
570
571     if(rq->flags&REGION_RQGEOM_TRYONLY){
572         if(geomret!=NULL)
573             *geomret=g;
574         return;
575     }
576     
577     region_fit(reg, &g, REGION_FIT_EXACT);
578     
579     statusbar_calc_systray_w(sb);
580     statusbar_rearrange(sb, TRUE);
581     
582     if(geomret!=NULL)
583         *geomret=REGION_GEOM(reg);
584     
585 }
586
587
588 void statusbar_map(WStatusBar *sb)
589 {
590     WRegion *reg;
591     PtrListIterTmp tmp;
592     
593     window_map((WWindow*)sb);
594     
595     FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp)
596         region_map(reg);
597 }
598
599
600 void statusbar_unmap(WStatusBar *sb)
601 {
602     WRegion *reg;
603     PtrListIterTmp tmp;
604     
605     window_unmap((WWindow*)sb);
606     
607     FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp)
608         region_unmap(reg);
609 }
610
611
612 bool statusbar_fitrep(WStatusBar *sb, WWindow *par, const WFitParams *fp)
613 {
614     bool wchg=(REGION_GEOM(sb).w!=fp->g.w);
615     bool hchg=(REGION_GEOM(sb).h!=fp->g.h);
616     
617     window_do_fitrep(&(sb->wwin), par, &(fp->g));
618     
619     if(wchg || hchg){
620         statusbar_calculate_xs(sb);
621         statusbar_arrange_systray(sb);
622         statusbar_draw(sb, TRUE);
623     }
624     
625     return TRUE;
626 }
627
628
629 WPHolder *statusbar_prepare_manage_transient(WStatusBar *sb, 
630                                              const WClientWin *cwin,
631                                              const WManageParams *param,
632                                              int unused)
633 {
634     WRegion *mgr=REGION_MANAGER(sb);
635     
636     if(mgr==NULL)
637         mgr=(WRegion*)region_screen_of((WRegion*)sb);
638     
639     if(mgr!=NULL)
640         return region_prepare_manage(mgr, cwin, param, 
641                                      MANAGE_REDIR_PREFER_NO);
642     else
643         return NULL;
644 }
645
646     
647
648 /*}}}*/
649
650
651 /*{{{ Exports */
652
653
654 static ExtlFn parse_template_fn;
655 static bool parse_template_fn_set=FALSE;
656
657
658 EXTL_EXPORT
659 void mod_statusbar__set_template_parser(ExtlFn fn)
660 {
661     if(parse_template_fn_set)
662         extl_unref_fn(parse_template_fn);
663     parse_template_fn=extl_ref_fn(fn);
664     parse_template_fn_set=TRUE;
665 }
666
667
668 /*EXTL_DOC
669  * Set statusbar template.
670  */
671 EXTL_EXPORT_MEMBER
672 void statusbar_set_template(WStatusBar *sb, const char *tmpl)
673 {
674     ExtlTab t=extl_table_none();
675     bool ok=FALSE;
676     
677     if(parse_template_fn_set){
678         extl_protect(NULL);
679         ok=extl_call(parse_template_fn, "s", "t", tmpl, &t);
680         extl_unprotect(NULL);
681     }
682
683     if(ok)
684         statusbar_set_template_table(sb, t);
685 }
686
687
688 /*EXTL_DOC
689  * Set statusbar template as table.
690  */
691 EXTL_EXPORT_MEMBER
692 void statusbar_set_template_table(WStatusBar *sb, ExtlTab t)
693 {
694     WRegion *reg;
695     PtrListIterTmp tmp;
696     
697     statusbar_set_elems(sb, t);
698
699     FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp){
700         statusbar_associate_systray(sb, reg);
701     }
702     
703     statusbar_calc_widths(sb);
704     statusbar_rearrange(sb, FALSE);
705 }
706
707
708 /*EXTL_DOC
709  * Get statusbar template as table.
710  */
711 EXTL_EXPORT_MEMBER
712 ExtlTab statusbar_get_template_table(WStatusBar *sb)
713 {
714     int count = sb->nelems;
715     int i;
716
717     ExtlTab t = extl_create_table();
718
719     for(i=0; i<count; i++){
720         ExtlTab tt = extl_create_table();
721         
722         extl_table_sets_i(tt, "type", sb->elems[i].type);
723         extl_table_sets_s(tt, "text", sb->elems[i].text);
724         extl_table_sets_s(tt, "meter", sb->elems[i].meter);
725         extl_table_sets_s(tt, "tmpl", sb->elems[i].tmpl);
726         extl_table_sets_i(tt, "align", sb->elems[i].align);
727         extl_table_sets_i(tt, "zeropad", sb->elems[i].zeropad);
728
729         extl_table_seti_t(t, (i+1), tt);
730         extl_unref_table(tt);
731     }
732
733     return t;
734 }
735
736
737 static void reset_stretch(WStatusBar *sb)
738 {
739     int i;
740     
741     for(i=0; i<sb->nelems; i++)
742         sb->elems[i].stretch=0;
743 }
744
745
746 static void positive_stretch(WStatusBar *sb)
747 {
748     int i;
749     
750     for(i=0; i<sb->nelems; i++)
751         sb->elems[i].stretch=maxof(0, sb->elems[i].stretch);
752 }
753
754
755 static void spread_stretch(WStatusBar *sb)
756 {
757     int i, j, k;
758     int diff;
759     WSBElem *el, *lel, *rel;
760     const char *str;
761     
762     for(i=0; i<sb->nelems; i++){
763         el=&(sb->elems[i]);
764
765         if(el->type!=WSBELEM_METER && el->type!=WSBELEM_SYSTRAY)
766             continue;
767         
768         diff=el->max_w-el->text_w;
769         
770         lel=NULL;
771         rel=NULL;
772         
773         if(el->align!=WSBELEM_ALIGN_RIGHT){
774             for(j=i+1; j<sb->nelems; j++){
775                 if(sb->elems[j].type==WSBELEM_STRETCH){
776                     rel=&(sb->elems[j]);
777                     break;
778                 }
779             }
780         }
781         
782         if(el->align!=WSBELEM_ALIGN_LEFT){
783             for(k=i-1; k>=0; k--){
784                 if(sb->elems[k].type==WSBELEM_STRETCH){
785                     lel=&(sb->elems[k]);
786                     break;
787                 }
788             }
789         }
790         
791         if(rel!=NULL && lel!=NULL){
792             int l=diff/2;
793             int r=diff-l;
794             lel->stretch+=l;
795             rel->stretch+=r;
796         }else if(lel!=NULL){
797             lel->stretch+=diff;
798         }else if(rel!=NULL){
799             rel->stretch+=diff;
800         }
801     }
802 }
803
804
805 static void statusbar_rearrange(WStatusBar *sb, bool rs)
806 {
807     if(rs){
808         int onw=sb->natural_w;
809         int onh=sb->natural_h;
810         
811         statusbar_do_update_natural_size(sb);
812         
813         if(    (sb->natural_h>onh && REGION_GEOM(sb).h>=onh)
814             || (sb->natural_h<onh && REGION_GEOM(sb).h<=onh)
815             || (sb->natural_w>onw && REGION_GEOM(sb).w>=onw)
816             || (sb->natural_w<onw && REGION_GEOM(sb).w<=onw)){
817             
818             statusbar_resize(sb);
819         }
820     }
821
822     reset_stretch(sb);
823     spread_stretch(sb);
824     positive_stretch(sb);
825     statusbar_calculate_xs(sb);
826     
827     if(rs)
828         statusbar_arrange_systray(sb);
829 }
830
831
832
833 /*EXTL_DOC
834  * Set statusbar template.
835  */
836 EXTL_EXPORT_MEMBER
837 void statusbar_update(WStatusBar *sb, ExtlTab t)
838 {
839     int i;
840     WSBElem *el;
841     bool grow=FALSE;
842     
843     if(sb->brush==NULL)
844         return;
845     
846     for(i=0; i<sb->nelems; i++){
847         el=&(sb->elems[i]);
848         
849         if(el->type!=WSBELEM_METER)
850             continue;
851         
852         if(el->text!=NULL){
853             free(el->text);
854             el->text=NULL;
855         }
856
857         if(el->attr!=NULL){
858             free(el->attr);
859             el->attr=NULL;
860         }
861         
862         if(el->meter!=NULL){
863             const char *str;
864             char *attrnm;
865             
866             extl_table_gets_s(t, el->meter, &(el->text));
867             
868             if(el->text==NULL){
869                 str=STATUSBAR_NX_STR;
870             }else{
871                 /* Zero-pad */
872                 int l=strlen(el->text);
873                 int ml=str_len(el->text);
874                 int diff=el->zeropad-ml;
875                 if(diff>0){
876                     char *tmp=ALLOC_N(char, l+diff+1);
877                     if(tmp!=NULL){
878                         memset(tmp, '0', diff);
879                         memcpy(tmp+diff, el->text, l+1);
880                         free(el->text);
881                         el->text=tmp;
882                     }
883                 }
884                 str=el->text;
885             }
886             
887             if(el->tmpl!=NULL && el->text!=NULL){
888                 char *tmp=grbrush_make_label(sb->brush, el->text, el->max_w);
889                 if(tmp!=NULL){
890                     free(el->text);
891                     el->text=tmp;
892                     str=tmp;
893                 }
894             }
895
896             el->text_w=grbrush_get_text_width(sb->brush, str, strlen(str));
897             
898             if(el->text_w>el->max_w && el->tmpl==NULL){
899                 el->max_w=el->text_w;
900                 grow=TRUE;
901             }
902             
903             attrnm=scat(el->meter, "_hint");
904             if(attrnm!=NULL){
905                 extl_table_gets_s(t, attrnm, &(el->attr));
906                 free(attrnm);
907             }
908         }
909     }
910
911     statusbar_rearrange(sb, grow);
912     
913     window_draw((WWindow*)sb, FALSE);
914 }
915
916
917 /*}}}*/
918
919
920 /*{{{ Updategr */
921
922
923 void statusbar_updategr(WStatusBar *p)
924 {
925     GrBrush *nbrush;
926     
927     nbrush=gr_get_brush(p->wwin.win, region_rootwin_of((WRegion*)p),
928                         "stdisp-statusbar");
929     if(nbrush==NULL)
930         return;
931     
932     if(p->brush!=NULL)
933         grbrush_release(p->brush);
934     
935     p->brush=nbrush;
936
937     statusbar_calc_widths(p);
938     statusbar_rearrange(p, TRUE);
939     
940     window_draw(&(p->wwin), TRUE);
941 }
942
943
944 /*}}}*/
945
946
947 /*{{{ Misc */
948
949
950 int statusbar_orientation(WStatusBar *sb)
951 {
952     return REGION_ORIENTATION_HORIZONTAL;
953 }
954
955
956 /*EXTL_DOC
957  * Returns a list of all statusbars.
958  */
959 EXTL_EXPORT
960 ExtlTab mod_statusbar_statusbars()
961 {
962     ExtlTab t=extl_create_table();
963     WStatusBar *sb;
964     int i=1;
965     
966     for(sb=statusbars; sb!=NULL; sb=sb->sb_next){
967         extl_table_seti_o(t, i, (Obj*)sb);
968         i++;
969     }
970     
971     return t;
972 }
973
974
975 WStatusBar *mod_statusbar_find_suitable(WClientWin *cwin,
976                                         const WManageParams *param)
977 {
978     WStatusBar *sb;
979
980     for(sb=statusbars; sb!=NULL; sb=sb->sb_next){
981         /*if(!sb->is_auto)
982             continue;*/
983         if(!sb->systray_enabled)
984             continue;
985         if(!region_same_rootwin((WRegion*)sb, (WRegion*)cwin))
986             continue;
987         break;
988     }
989
990     return sb;
991 }
992
993
994 bool statusbar_set_systray(WStatusBar *sb, int sp)
995 {
996     bool set=sb->systray_enabled;
997     bool nset=libtu_do_setparam(sp, set);
998     
999     sb->systray_enabled=nset;
1000     
1001     return nset;
1002 }
1003
1004
1005 /*EXTL_DOC
1006  * Enable or disable use of \var{sb} as systray.
1007  * The parameter \var{how} can be one of (set/unset/toggle). 
1008  * Resulting state is returned.
1009  */
1010 EXTL_EXPORT_AS(WStatusBar, set_systray)
1011 bool statusbar_set_systray_extl(WStatusBar *sb, const char *how)
1012 {
1013     return statusbar_set_systray(sb, libtu_string_to_setparam(how));
1014 }
1015
1016
1017 /*EXTL_DOC
1018  * Is \var{sb} used as a systray?
1019  */
1020 EXTL_EXPORT_MEMBER
1021 bool statusbar_is_systray_extl(WStatusBar *sb)
1022 {
1023     return sb->systray_enabled;
1024 }
1025
1026
1027 /*}}}*/
1028
1029
1030 /*{{{ Load */
1031
1032
1033 WRegion *statusbar_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
1034 {
1035     WStatusBar *sb=create_statusbar(par, fp);
1036
1037     if(sb!=NULL){
1038         char *tmpl=NULL;
1039         ExtlTab t=extl_table_none();
1040         if(extl_table_gets_s(tab, "template", &tmpl)){
1041             statusbar_set_template(sb, tmpl);
1042             free(tmpl);
1043         }else if(extl_table_gets_t(tab, "template_table", &t)){
1044             statusbar_set_template_table(sb, t);
1045             extl_unref_table(t);
1046         }else{
1047             const char *tmpl=TR("[ %date || load: %load ] %filler%systray");
1048             statusbar_set_template(sb, tmpl);
1049         }
1050         
1051         extl_table_gets_b(tab, "systray", &sb->systray_enabled);
1052     }
1053     
1054     return (WRegion*)sb;
1055 }
1056
1057
1058 /*}}}*/
1059
1060
1061 /*{{{ Dynamic function table and class implementation */
1062
1063
1064 static DynFunTab statusbar_dynfuntab[]={
1065     {window_draw, statusbar_draw},
1066     {region_updategr, statusbar_updategr},
1067     {region_size_hints, statusbar_size_hints},
1068     {(DynFun*)region_orientation, (DynFun*)statusbar_orientation},
1069
1070     {region_managed_rqgeom, statusbar_managed_rqgeom},
1071     {(DynFun*)region_prepare_manage, (DynFun*)statusbar_prepare_manage},
1072     {region_managed_remove, statusbar_managed_remove},
1073     
1074     {(DynFun*)region_prepare_manage_transient, 
1075      (DynFun*)statusbar_prepare_manage_transient},
1076     
1077     {region_map, statusbar_map},
1078     {region_unmap, statusbar_unmap},
1079     
1080     {(DynFun*)region_fitrep,
1081      (DynFun*)statusbar_fitrep},
1082     
1083     END_DYNFUNTAB
1084 };
1085
1086
1087 EXTL_EXPORT
1088 IMPLCLASS(WStatusBar, WWindow, statusbar_deinit, statusbar_dynfuntab);
1089
1090     
1091 /*}}}*/
1092