Released version 3-2015061300
[notion.git] / mod_statusbar / statusbar.c
blob3b2a728de0c7dde618033f0a03038c28aed32b1c
1 /*
2 * ion/mod_statusbar/statusbar.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
10 #include <limits.h>
12 #include <libtu/objp.h>
13 #include <libtu/minmax.h>
14 #include <libtu/ptrlist.h>
15 #include <libtu/misc.h>
16 #include <ioncore/common.h>
17 #include <ioncore/global.h>
18 #include <ioncore/window.h>
19 #include <ioncore/binding.h>
20 #include <ioncore/regbind.h>
21 #include <ioncore/event.h>
22 #include <ioncore/resize.h>
23 #include <ioncore/gr.h>
24 #include <ioncore/gr-util.h>
25 #include <ioncore/names.h>
26 #include <ioncore/strings.h>
27 #include <ioncore/basicpholder.h>
28 #include <ioncore/sizehint.h>
30 #include "statusbar.h"
31 #include "main.h"
32 #include "draw.h"
35 static void statusbar_set_elems(WStatusBar *sb, ExtlTab t);
36 static void statusbar_free_elems(WStatusBar *sb);
37 static void statusbar_arrange_systray(WStatusBar *p);
38 static void statusbar_rearrange(WStatusBar *sb, bool rs);
39 static void do_calc_systray_w(WStatusBar *p, WSBElem *el);
40 static void statusbar_calc_systray_w(WStatusBar *p);
42 static WStatusBar *statusbars=NULL;
45 /*{{{ Init/deinit */
48 bool statusbar_init(WStatusBar *p, WWindow *parent, const WFitParams *fp)
50 if(!window_init(&(p->wwin), parent, fp, "WStatusBar"))
51 return FALSE;
53 p->brush=NULL;
54 p->elems=NULL;
55 p->nelems=0;
56 p->natural_w=1;
57 p->natural_h=1;
58 p->filleridx=-1;
59 p->sb_next=NULL;
60 p->sb_prev=NULL;
61 p->traywins=NULL;
62 p->systray_enabled=TRUE;
64 statusbar_updategr(p);
66 if(p->brush==NULL){
67 window_deinit(&(p->wwin));
68 return FALSE;
71 window_select_input(&(p->wwin), IONCORE_EVENTMASK_CWINMGR);
73 region_register((WRegion*)p);
75 region_add_bindmap((WRegion*)p, mod_statusbar_statusbar_bindmap);
77 LINK_ITEM(statusbars, p, sb_next, sb_prev);
79 return TRUE;
84 WStatusBar *create_statusbar(WWindow *parent, const WFitParams *fp)
86 CREATEOBJ_IMPL(WStatusBar, statusbar, (p, parent, fp));
90 void statusbar_deinit(WStatusBar *p)
92 UNLINK_ITEM(statusbars, p, sb_next, sb_prev);
94 statusbar_free_elems(p);
96 if(p->brush!=NULL){
97 grbrush_release(p->brush);
98 p->brush=NULL;
101 window_deinit(&(p->wwin));
105 /*}}}*/
108 /*{{{ Content stuff */
111 static void init_sbelem(WSBElem *el)
113 el->type=WSBELEM_NONE;
114 el->text_w=0;
115 el->text=NULL;
116 el->max_w=0;
117 el->tmpl=NULL;
118 el->meter=STRINGID_NONE;
119 el->attr=STRINGID_NONE;
120 el->stretch=0;
121 el->align=WSBELEM_ALIGN_CENTER;
122 el->zeropad=0;
123 el->x=0;
124 el->traywins=NULL;
128 static bool gets_stringstore(ExtlTab t, const char *str, StringId *id)
130 char *s;
132 if(extl_table_gets_s(t, str, &s)){
133 *id=stringstore_alloc(s);
134 free(s);
135 return (*id!=STRINGID_NONE);
138 return FALSE;
142 static WSBElem *get_sbelems(ExtlTab t, int *nret, int *filleridxret)
144 int i, n=extl_table_get_n(t);
145 WSBElem *el;
146 int systrayidx=-1;
148 *nret=0;
149 *filleridxret=-1;
151 if(n<=0)
152 return NULL;
154 el=ALLOC_N(WSBElem, n);
156 if(el==NULL)
157 return NULL;
159 for(i=0; i<n; i++){
160 ExtlTab tt;
162 init_sbelem(&el[i]);
164 if(extl_table_geti_t(t, i+1, &tt)){
165 if(extl_table_gets_i(tt, "type", &(el[i].type))){
166 if(el[i].type==WSBELEM_TEXT || el[i].type==WSBELEM_STRETCH){
167 extl_table_gets_s(tt, "text", &(el[i].text));
168 }else if(el[i].type==WSBELEM_METER){
169 gets_stringstore(tt, "meter", &(el[i].meter));
170 extl_table_gets_s(tt, "tmpl", &(el[i].tmpl));
171 extl_table_gets_i(tt, "align", &(el[i].align));
172 extl_table_gets_i(tt, "zeropad", &(el[i].zeropad));
173 el[i].zeropad=MAXOF(el[i].zeropad, 0);
174 }else if(el[i].type==WSBELEM_SYSTRAY){
175 const char *tmp;
177 gets_stringstore(tt, "meter", &(el[i].meter));
178 extl_table_gets_i(tt, "align", &(el[i].align));
180 tmp=stringstore_get(el[i].meter);
182 if(tmp==NULL || strcmp(tmp, "systray")==0)
183 systrayidx=i;
184 }else if(el[i].type==WSBELEM_FILLER){
185 *filleridxret=i;
188 extl_unref_table(tt);
192 if(systrayidx==-1){
193 WSBElem *el2=REALLOC_N(el, WSBElem, n, n+1);
194 if(el2!=NULL){
195 el=el2;
196 init_sbelem(&el[n]);
197 el[n].type=WSBELEM_SYSTRAY;
198 n++;
202 *nret=n;
204 return el;
208 static void free_sbelems(WSBElem *el, int n)
210 int i;
212 for(i=0; i<n; i++){
213 if(el[i].text!=NULL)
214 free(el[i].text);
215 if(el[i].tmpl!=NULL)
216 free(el[i].tmpl);
217 if(el[i].meter!=STRINGID_NONE)
218 stringstore_free(el[i].meter);
219 if(el[i].attr!=STRINGID_NONE)
220 stringstore_free(el[i].attr);
221 if(el[i].traywins!=NULL)
222 ptrlist_clear(&el[i].traywins);
225 free(el);
229 static void statusbar_set_elems(WStatusBar *sb, ExtlTab t)
231 statusbar_free_elems(sb);
233 sb->elems=get_sbelems(t, &(sb->nelems), &(sb->filleridx));
237 static void statusbar_free_elems(WStatusBar *sb)
239 if(sb->elems!=NULL){
240 free_sbelems(sb->elems, sb->nelems);
241 sb->elems=NULL;
242 sb->nelems=0;
243 sb->filleridx=-1;
248 /*}}}*/
252 /*{{{ Size stuff */
255 static void statusbar_resize(WStatusBar *p)
257 WRQGeomParams rq=RQGEOMPARAMS_INIT;
259 rq.flags=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
261 rq.geom.w=p->natural_w;
262 rq.geom.h=p->natural_h;
263 rq.geom.x=REGION_GEOM(p).x;
264 rq.geom.y=REGION_GEOM(p).y;
266 if(rectangle_compare(&rq.geom, &REGION_GEOM(p))!=RECTANGLE_SAME)
267 region_rqgeom((WRegion*)p, &rq, NULL);
271 static void calc_elem_w(WStatusBar *p, WSBElem *el, GrBrush *brush)
273 const char *str;
275 if(el->type==WSBELEM_SYSTRAY){
276 do_calc_systray_w(p, el);
277 return;
280 if(brush==NULL){
281 el->text_w=0;
282 return;
285 if(el->type==WSBELEM_METER){
286 int str_w = 0;
288 str=(el->text!=NULL ? el->text : STATUSBAR_NX_STR);
289 el->text_w=grbrush_get_text_width(brush, str, strlen(str));
290 str=el->tmpl;
292 str_w=str!=NULL ? grbrush_get_text_width(brush, str, strlen(str)) : 0;
293 el->max_w=MAXOF(str_w, el->text_w);
294 }else{
295 str=el->text;
296 el->text_w=(str!=NULL
297 ? grbrush_get_text_width(brush, str, strlen(str))
298 : 0);
299 el->max_w=el->text_w;
304 static void statusbar_calc_widths(WStatusBar *sb)
306 int i;
308 for(i=0; i<sb->nelems; i++)
309 calc_elem_w(sb, &(sb->elems[i]), sb->brush);
313 static void statusbar_do_update_natural_size(WStatusBar *p)
315 GrBorderWidths bdw;
316 GrFontExtents fnte;
317 WRegion *reg;
318 PtrListIterTmp tmp;
319 int totw=0, stmh=0;
320 int i;
322 if(p->brush==NULL){
323 bdw.left=0; bdw.right=0;
324 bdw.top=0; bdw.bottom=0;
325 fnte.max_height=4;
326 }else{
327 grbrush_get_border_widths(p->brush, &bdw);
328 grbrush_get_font_extents(p->brush, &fnte);
331 for(i=0; i<p->nelems; i++)
332 totw+=p->elems[i].max_w;
334 FOR_ALL_ON_PTRLIST(WRegion*, reg, p->traywins, tmp){
335 stmh=MAXOF(stmh, REGION_GEOM(reg).h);
338 p->natural_w=bdw.left+totw+bdw.right;
339 p->natural_h=MAXOF(stmh, fnte.max_height)+bdw.top+bdw.bottom;
343 void statusbar_size_hints(WStatusBar *p, WSizeHints *h)
345 h->min_set=TRUE;
346 h->min_width=p->natural_w;
347 h->min_height=p->natural_h;
349 h->max_set=TRUE;
350 h->max_width=INT_MAX;/*p->natural_w;*/
351 h->max_height=p->natural_h;
355 /*}}}*/
358 /*{{{ Systray */
361 static WSBElem *statusbar_associate_systray(WStatusBar *sb, WRegion *reg)
363 WClientWin *cwin=OBJ_CAST(reg, WClientWin);
364 WSBElem *el=NULL, *fbel=NULL;
365 char *name=NULL;
366 int i;
368 if(cwin!=NULL)
369 extl_table_gets_s(cwin->proptab, "statusbar", &name);
371 for(i=0; i<sb->nelems; i++){
372 const char *meter;
374 if(sb->elems[i].type!=WSBELEM_SYSTRAY)
375 continue;
377 meter=stringstore_get(sb->elems[i].meter);
379 if(meter==NULL){
380 fbel=&sb->elems[i];
381 continue;
383 if(name!=NULL && strcmp(meter, name)==0){
384 el=&sb->elems[i];
385 break;
387 if(strcmp(meter, "systray")==0)
388 fbel=&sb->elems[i];
391 if(name!=NULL)
392 free(name);
394 if(el==NULL)
395 el=fbel;
397 if(el==NULL)
398 return NULL;
400 ptrlist_insert_last(&el->traywins, (Obj*)reg);
402 return el;
406 static WSBElem *statusbar_unassociate_systray(WStatusBar *sb, WRegion *reg)
408 int i;
410 for(i=0; i<sb->nelems; i++){
411 if(ptrlist_remove(&(sb->elems[i].traywins), (Obj*)reg))
412 return &sb->elems[i];
415 return NULL;
420 static void do_calc_systray_w(WStatusBar *p, WSBElem *el)
422 WRegion *reg;
423 PtrListIterTmp tmp;
424 int padding=0;
425 int w=-padding;
427 FOR_ALL_ON_PTRLIST(WRegion*, reg, el->traywins, tmp){
428 w=w+REGION_GEOM(reg).w+padding;
431 el->text_w=MAXOF(0, w);
432 el->max_w=el->text_w; /* for now */
436 static void statusbar_calc_systray_w(WStatusBar *p)
438 int i;
440 for(i=0; i<p->nelems; i++){
441 if(p->elems[i].type==WSBELEM_SYSTRAY)
442 do_calc_systray_w(p, &p->elems[i]);
447 static void statusbar_arrange_systray(WStatusBar *p)
449 WRegion *reg;
450 PtrListIterTmp tmp;
451 GrBorderWidths bdw;
452 int padding=0, ymiddle;
453 int i, x;
455 if(p->brush!=NULL){
456 grbrush_get_border_widths(p->brush, &bdw);
457 }else{
458 bdw.top=0;
459 bdw.bottom=0;
462 ymiddle=bdw.top+(REGION_GEOM(p).h-bdw.top-bdw.bottom)/2;
464 for(i=0; i<p->nelems; i++){
465 WSBElem *el=&p->elems[i];
466 if(el->type!=WSBELEM_SYSTRAY)
467 continue;
468 x=el->x;
469 FOR_ALL_ON_PTRLIST(WRegion*, reg, el->traywins, tmp){
470 WRectangle g=REGION_GEOM(reg);
471 g.x=x;
472 g.y=ymiddle-g.h/2;
473 region_fit(reg, &g, REGION_FIT_EXACT);
474 x=x+g.w+padding;
480 static void systray_adjust_size(WRegion *reg, WRectangle *g)
482 g->h=CF_STATUSBAR_SYSTRAY_HEIGHT;
484 region_size_hints_correct(reg, &g->w, &g->h, TRUE);
489 static WRegion *statusbar_do_attach_final(WStatusBar *sb,
490 WRegion *reg,
491 void *UNUSED(unused))
493 WFitParams fp;
494 WSBElem *el;
496 if(!ptrlist_insert_last(&sb->traywins, (Obj*)reg))
497 return NULL;
499 el=statusbar_associate_systray(sb, reg);
500 if(el==NULL){
501 ptrlist_remove(&sb->traywins, (Obj*)reg);
502 return NULL;
505 fp.g=REGION_GEOM(reg);
506 fp.mode=REGION_FIT_EXACT;
507 systray_adjust_size(reg, &fp.g);
509 region_fitrep(reg, NULL, &fp);
511 do_calc_systray_w(sb, el);
513 region_set_manager(reg, (WRegion*)sb);
515 statusbar_rearrange(sb, TRUE);
517 if(REGION_IS_MAPPED(sb))
518 region_map(reg);
520 return reg;
524 static WRegion *statusbar_do_attach(WStatusBar *sb, WRegionAttachData *data)
526 WFitParams fp;
528 fp.g.x=0;
529 fp.g.y=0;
530 fp.g.h=CF_STATUSBAR_SYSTRAY_HEIGHT;
531 fp.g.w=CF_STATUSBAR_SYSTRAY_HEIGHT;
532 fp.mode=REGION_FIT_WHATEVER|REGION_FIT_BOUNDS;
534 return region_attach_helper((WRegion*)sb, (WWindow*)sb, &fp,
535 (WRegionDoAttachFn*)statusbar_do_attach_final,
536 NULL, data);
540 static WRegion *statusbar_attach_ph(WStatusBar *sb, int UNUSED(flags),
541 WRegionAttachData *data)
543 return statusbar_do_attach(sb, data);
547 static WPHolder *statusbar_prepare_manage(WStatusBar *sb,
548 const WClientWin *UNUSED(cwin),
549 const WManageParams *UNUSED(param),
550 int priority)
552 if(!MANAGE_PRIORITY_OK(priority, MANAGE_PRIORITY_LOW))
553 return NULL;
555 return (WPHolder*)create_basicpholder((WRegion*)sb,
556 ((WBasicPHolderHandler*)
557 statusbar_attach_ph));
561 static void statusbar_managed_remove(WStatusBar *sb, WRegion *reg)
563 WSBElem *el;
565 ptrlist_remove(&sb->traywins, (Obj*)reg);
567 el=statusbar_unassociate_systray(sb, reg);
569 region_unset_manager(reg, (WRegion*)sb);
571 if(el!=NULL && ioncore_g.opmode!=IONCORE_OPMODE_DEINIT){
572 do_calc_systray_w(sb, el);
573 statusbar_rearrange(sb, TRUE);
578 static void statusbar_managed_rqgeom(WStatusBar *sb, WRegion *reg,
579 const WRQGeomParams *rq,
580 WRectangle *geomret)
582 WRectangle g;
584 g.x=REGION_GEOM(reg).x;
585 g.y=REGION_GEOM(reg).y;
586 g.w=rq->geom.w;
587 g.h=rq->geom.h;
589 systray_adjust_size(reg, &g);
591 if(rq->flags&REGION_RQGEOM_TRYONLY){
592 if(geomret!=NULL)
593 *geomret=g;
594 return;
597 region_fit(reg, &g, REGION_FIT_EXACT);
599 statusbar_calc_systray_w(sb);
600 statusbar_rearrange(sb, TRUE);
602 if(geomret!=NULL)
603 *geomret=REGION_GEOM(reg);
608 void statusbar_map(WStatusBar *sb)
610 WRegion *reg;
611 PtrListIterTmp tmp;
613 window_map((WWindow*)sb);
615 FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp)
616 region_map(reg);
620 void statusbar_unmap(WStatusBar *sb)
622 WRegion *reg;
623 PtrListIterTmp tmp;
625 window_unmap((WWindow*)sb);
627 FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp)
628 region_unmap(reg);
632 bool statusbar_fitrep(WStatusBar *sb, WWindow *par, const WFitParams *fp)
634 bool wchg=(REGION_GEOM(sb).w!=fp->g.w);
635 bool hchg=(REGION_GEOM(sb).h!=fp->g.h);
637 if(!window_fitrep(&(sb->wwin), par, fp))
638 return FALSE;
640 if(wchg || hchg){
641 statusbar_calculate_xs(sb);
642 statusbar_arrange_systray(sb);
643 statusbar_draw(sb, TRUE);
646 return TRUE;
650 WPHolder *statusbar_prepare_manage_transient(WStatusBar *sb,
651 const WClientWin *cwin,
652 const WManageParams *param,
653 int UNUSED(unused))
655 WRegion *mgr=REGION_MANAGER(sb);
657 if(mgr==NULL)
658 mgr=(WRegion*)region_screen_of((WRegion*)sb);
660 if(mgr!=NULL)
661 return region_prepare_manage(mgr, cwin, param,
662 MANAGE_PRIORITY_NONE);
663 else
664 return NULL;
669 /*}}}*/
672 /*{{{ Exports */
675 static ExtlFn parse_template_fn;
676 static bool parse_template_fn_set=FALSE;
679 EXTL_EXPORT
680 void mod_statusbar__set_template_parser(ExtlFn fn)
682 if(parse_template_fn_set)
683 extl_unref_fn(parse_template_fn);
684 parse_template_fn=extl_ref_fn(fn);
685 parse_template_fn_set=TRUE;
689 /*EXTL_DOC
690 * Set statusbar template.
692 EXTL_EXPORT_MEMBER
693 void statusbar_set_template(WStatusBar *sb, const char *tmpl)
695 ExtlTab t=extl_table_none();
696 bool ok=FALSE;
698 if(parse_template_fn_set){
699 extl_protect(NULL);
700 ok=extl_call(parse_template_fn, "s", "t", tmpl, &t);
701 extl_unprotect(NULL);
704 if(ok)
705 statusbar_set_template_table(sb, t);
709 /*EXTL_DOC
710 * Set statusbar template as table.
712 EXTL_EXPORT_MEMBER
713 void statusbar_set_template_table(WStatusBar *sb, ExtlTab t)
715 WRegion *reg;
716 PtrListIterTmp tmp;
718 statusbar_set_elems(sb, t);
720 FOR_ALL_ON_PTRLIST(WRegion*, reg, sb->traywins, tmp){
721 statusbar_associate_systray(sb, reg);
724 statusbar_calc_widths(sb);
725 statusbar_rearrange(sb, FALSE);
729 /*EXTL_DOC
730 * Get statusbar template as table.
732 EXTL_EXPORT_MEMBER
733 ExtlTab statusbar_get_template_table(WStatusBar *sb)
735 int count = sb->nelems;
736 int i;
738 ExtlTab t = extl_create_table();
740 for(i=0; i<count; i++){
741 ExtlTab tt = extl_create_table();
743 extl_table_sets_i(tt, "type", sb->elems[i].type);
744 extl_table_sets_s(tt, "text", sb->elems[i].text);
745 extl_table_sets_s(tt, "meter", stringstore_get(sb->elems[i].meter));
746 extl_table_sets_s(tt, "tmpl", sb->elems[i].tmpl);
747 extl_table_sets_i(tt, "align", sb->elems[i].align);
748 extl_table_sets_i(tt, "zeropad", sb->elems[i].zeropad);
750 extl_table_seti_t(t, (i+1), tt);
751 extl_unref_table(tt);
754 return t;
758 static void reset_stretch(WStatusBar *sb)
760 int i;
762 for(i=0; i<sb->nelems; i++)
763 sb->elems[i].stretch=0;
767 static void positive_stretch(WStatusBar *sb)
769 int i;
771 for(i=0; i<sb->nelems; i++)
772 sb->elems[i].stretch=MAXOF(0, sb->elems[i].stretch);
776 static void spread_stretch(WStatusBar *sb)
778 int i, j, k;
779 int diff;
780 WSBElem *el, *lel, *rel;
782 for(i=0; i<sb->nelems; i++){
783 el=&(sb->elems[i]);
785 if(el->type!=WSBELEM_METER && el->type!=WSBELEM_SYSTRAY)
786 continue;
788 diff=el->max_w-el->text_w;
790 lel=NULL;
791 rel=NULL;
793 if(el->align!=WSBELEM_ALIGN_RIGHT){
794 for(j=i+1; j<sb->nelems; j++){
795 if(sb->elems[j].type==WSBELEM_STRETCH){
796 rel=&(sb->elems[j]);
797 break;
802 if(el->align!=WSBELEM_ALIGN_LEFT){
803 for(k=i-1; k>=0; k--){
804 if(sb->elems[k].type==WSBELEM_STRETCH){
805 lel=&(sb->elems[k]);
806 break;
811 if(rel!=NULL && lel!=NULL){
812 int l=diff/2;
813 int r=diff-l;
814 lel->stretch+=l;
815 rel->stretch+=r;
816 }else if(lel!=NULL){
817 lel->stretch+=diff;
818 }else if(rel!=NULL){
819 rel->stretch+=diff;
825 static void statusbar_rearrange(WStatusBar *sb, bool rs)
827 if(rs){
828 int onw=sb->natural_w;
829 int onh=sb->natural_h;
831 statusbar_do_update_natural_size(sb);
833 if( (sb->natural_h>onh && REGION_GEOM(sb).h>=onh)
834 || (sb->natural_h<onh && REGION_GEOM(sb).h<=onh)
835 || (sb->natural_w>onw && REGION_GEOM(sb).w>=onw)
836 || (sb->natural_w<onw && REGION_GEOM(sb).w<=onw)){
838 statusbar_resize(sb);
842 reset_stretch(sb);
843 spread_stretch(sb);
844 positive_stretch(sb);
845 statusbar_calculate_xs(sb);
847 if(rs)
848 statusbar_arrange_systray(sb);
853 /*EXTL_DOC
854 * Set statusbar template.
856 EXTL_EXPORT_MEMBER
857 void statusbar_update(WStatusBar *sb, ExtlTab t)
859 int i;
860 WSBElem *el;
861 bool grow=FALSE;
863 if(sb->brush==NULL)
864 return;
866 for(i=0; i<sb->nelems; i++){
867 const char *meter;
869 el=&(sb->elems[i]);
871 if(el->type!=WSBELEM_METER)
872 continue;
874 if(el->text!=NULL){
875 free(el->text);
876 el->text=NULL;
879 if(el->attr!=GRATTR_NONE){
880 stringstore_free(el->attr);
881 el->attr=GRATTR_NONE;
884 meter=stringstore_get(el->meter);
886 if(meter!=NULL){
887 const char *str;
888 char *attrnm;
890 extl_table_gets_s(t, meter, &(el->text));
892 if(el->text==NULL){
893 str=STATUSBAR_NX_STR;
894 }else{
895 /* Zero-pad */
896 int l=strlen(el->text);
897 int ml=str_len(el->text);
898 int diff=el->zeropad-ml;
899 if(diff>0){
900 char *tmp=ALLOC_N(char, l+diff+1);
901 if(tmp!=NULL){
902 memset(tmp, '0', diff);
903 memcpy(tmp+diff, el->text, l+1);
904 free(el->text);
905 el->text=tmp;
908 str=el->text;
911 if(el->tmpl!=NULL && el->text!=NULL){
912 char *tmp=grbrush_make_label(sb->brush, el->text, el->max_w);
913 if(tmp!=NULL){
914 free(el->text);
915 el->text=tmp;
916 str=tmp;
920 el->text_w=grbrush_get_text_width(sb->brush, str, strlen(str));
922 if(el->text_w>el->max_w && el->tmpl==NULL){
923 el->max_w=el->text_w;
924 grow=TRUE;
927 attrnm=scat(meter, "_hint");
928 if(attrnm!=NULL){
929 char *s;
930 if(extl_table_gets_s(t, attrnm, &s)){
931 el->attr=stringstore_alloc(s);
932 free(s);
934 free(attrnm);
939 statusbar_rearrange(sb, grow);
941 window_draw((WWindow*)sb, FALSE);
945 /*}}}*/
948 /*{{{ Updategr */
951 void statusbar_updategr(WStatusBar *p)
953 GrBrush *nbrush;
955 nbrush=gr_get_brush(p->wwin.win, region_rootwin_of((WRegion*)p),
956 "stdisp-statusbar");
957 if(nbrush==NULL)
958 return;
960 if(p->brush!=NULL)
961 grbrush_release(p->brush);
963 p->brush=nbrush;
965 statusbar_calc_widths(p);
966 statusbar_rearrange(p, TRUE);
968 window_draw(&(p->wwin), TRUE);
972 /*}}}*/
975 /*{{{ Misc */
978 int statusbar_orientation(WStatusBar *UNUSED(sb))
980 return REGION_ORIENTATION_HORIZONTAL;
984 /*EXTL_DOC
985 * Returns a list of all statusbars.
987 EXTL_EXPORT
988 ExtlTab mod_statusbar_statusbars()
990 ExtlTab t=extl_create_table();
991 WStatusBar *sb;
992 int i=1;
994 for(sb=statusbars; sb!=NULL; sb=sb->sb_next){
995 extl_table_seti_o(t, i, (Obj*)sb);
996 i++;
999 return t;
1003 WStatusBar *mod_statusbar_find_suitable(WClientWin *cwin,
1004 const WManageParams *param)
1006 WStatusBar *sb;
1008 for(sb=statusbars; sb!=NULL; sb=sb->sb_next){
1009 /*if(!sb->is_auto)
1010 continue;*/
1011 if(!sb->systray_enabled)
1012 continue;
1013 if(!region_same_rootwin((WRegion*)sb, (WRegion*)cwin))
1014 continue;
1015 break;
1018 return sb;
1022 bool statusbar_set_systray(WStatusBar *sb, int sp)
1024 bool set=sb->systray_enabled;
1025 bool nset=libtu_do_setparam(sp, set);
1027 sb->systray_enabled=nset;
1029 return nset;
1033 /*EXTL_DOC
1034 * Enable or disable use of \var{sb} as systray.
1035 * The parameter \var{how} can be one of
1036 * \codestr{set}, \codestr{unset}, or \codestr{toggle}.
1037 * Resulting state is returned.
1039 EXTL_EXPORT_AS(WStatusBar, set_systray)
1040 bool statusbar_set_systray_extl(WStatusBar *sb, const char *how)
1042 return statusbar_set_systray(sb, libtu_string_to_setparam(how));
1046 /*EXTL_DOC
1047 * Is \var{sb} used as a systray?
1049 EXTL_EXPORT_AS(WStatusBar, is_systray)
1050 bool statusbar_is_systray_extl(WStatusBar *sb)
1052 return sb->systray_enabled;
1056 /*}}}*/
1059 /*{{{ Load */
1062 WRegion *statusbar_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
1064 WStatusBar *sb=create_statusbar(par, fp);
1066 if(sb!=NULL){
1067 char *tmpl=NULL;
1068 ExtlTab t=extl_table_none();
1069 if(extl_table_gets_s(tab, "template", &tmpl)){
1070 statusbar_set_template(sb, tmpl);
1071 free(tmpl);
1072 }else if(extl_table_gets_t(tab, "template_table", &t)){
1073 statusbar_set_template_table(sb, t);
1074 extl_unref_table(t);
1075 }else{
1076 const char *tmpl=TR("[ %date || load: %load ] %filler%systray");
1077 statusbar_set_template(sb, tmpl);
1080 extl_table_gets_b(tab, "systray", &sb->systray_enabled);
1083 return (WRegion*)sb;
1087 /*}}}*/
1090 /*{{{ Dynamic function table and class implementation */
1093 static DynFunTab statusbar_dynfuntab[]={
1094 {window_draw, statusbar_draw},
1095 {region_updategr, statusbar_updategr},
1096 {region_size_hints, statusbar_size_hints},
1097 {(DynFun*)region_orientation, (DynFun*)statusbar_orientation},
1099 {region_managed_rqgeom, statusbar_managed_rqgeom},
1100 {(DynFun*)region_prepare_manage, (DynFun*)statusbar_prepare_manage},
1101 {region_managed_remove, statusbar_managed_remove},
1103 {(DynFun*)region_prepare_manage_transient,
1104 (DynFun*)statusbar_prepare_manage_transient},
1106 {region_map, statusbar_map},
1107 {region_unmap, statusbar_unmap},
1109 {(DynFun*)region_fitrep,
1110 (DynFun*)statusbar_fitrep},
1112 END_DYNFUNTAB
1116 EXTL_EXPORT
1117 IMPLCLASS(WStatusBar, WWindow, statusbar_deinit, statusbar_dynfuntab);
1120 /*}}}*/