4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libextl/readconfig.h>
17 #include <libmainloop/hooks.h>
24 /*{{{ Lookup and registration */
31 GrEngine *next, *prev;
35 static GrEngine *engines=NULL, *current_engine=NULL;
38 bool gr_register_engine(const char *engine, GrGetBrushFn *fn)
42 if(engine==NULL || fn==NULL)
50 eng->name=scopy(engine);
59 LINK_ITEM(engines, eng, next, prev);
65 void gr_unregister_engine(const char *engine)
69 for(eng=engines; eng!=NULL; eng=eng->next){
70 if(strcmp(eng->name, engine)==0)
77 UNLINK_ITEM(engines, eng, next, prev);
79 if(current_engine==eng)
85 static bool gr_do_select_engine(const char *engine)
89 for(eng=engines; eng!=NULL; eng=eng->next){
90 if(strcmp(eng->name, engine)==0){
101 * Future requests for ''brushes'' are to be forwarded to the drawing engine
102 * \var{engine}. If no engine of such name is known, a module with that name
103 * is attempted to be loaded. This function is only intended to be called from
104 * colour scheme etc. configuration files and can not be used to change the
105 * look of existing objects; for that use \fnref{gr.read_config}.
107 EXTL_EXPORT_AS(gr, select_engine)
108 bool gr_select_engine(const char *engine)
113 if(gr_do_select_engine(engine))
116 if(!ioncore_load_module(engine))
119 if(!gr_do_select_engine(engine)){
120 warn(TR("Drawing engine %s is not registered!"), engine);
128 GrBrush *gr_get_brush(Window win, WRootWin *rootwin, const char *style)
130 GrEngine *eng=(current_engine!=NULL ? current_engine : engines);
133 if(eng==NULL || eng->fn==NULL)
136 ret=(eng->fn)(win, rootwin, style);
139 warn(TR("Unable to find brush for style '%s'."), style);
151 static GrAttr star_id=STRINGID_NONE;
154 static int cmp(const void *a_, const void *b_)
156 StringId a=*(const StringId*)a_;
157 StringId b=((const GrAttrScore*)b_)->attr;
159 return (a < b ? -1 : ((a == b) ? 0 : 1));
163 static uint scorefind(const GrStyleSpec *attr, const GrAttrScore *spec)
167 if(attr->attrs==NULL)
170 if(star_id==STRINGID_NONE)
171 star_id=stringstore_alloc("*");
173 if(spec->attr==star_id){
174 /* Since every item occurs only once on the list, with a score,
175 * return the score of the star in the spec, instead of one.
180 res=bsearch(&spec->attr, attr->attrs, attr->n, sizeof(GrAttrScore), cmp);
182 return (res==NULL ? 0 : 2*res->score);
186 uint gr_stylespec_score2(const GrStyleSpec *spec, const GrStyleSpec *attr1,
187 const GrStyleSpec *attr2)
192 for(i=0; i<spec->n; i++){
193 int sc=scorefind(attr1, &spec->attrs[i]);
196 sc=maxof(sc, scorefind(attr2, &spec->attrs[i]));
210 uint gr_stylespec_score(const GrStyleSpec *spec, const GrStyleSpec *attr)
212 return gr_stylespec_score2(spec, attr, NULL);
216 static uint count_dashes(const char *str)
222 const char *p=strchr(str, '-');
234 bool gr_stylespec_load_(GrStyleSpec *spec, const char *str, bool no_order_score)
236 uint score=(no_order_score ? 1 : count_dashes(str)+1);
238 gr_stylespec_init(spec);
242 const char *p=strchr(str, '-');
245 a=stringstore_alloc(str);
248 a=stringstore_alloc_n(str, p-str);
255 if(!gr_stylespec_add(spec, a, score))
267 gr_stylespec_unalloc(spec);
273 bool gr_stylespec_load(GrStyleSpec *spec, const char *str)
275 return gr_stylespec_load_(spec, str, FALSE);
279 void gr_stylespec_unalloc(GrStyleSpec *spec)
283 for(i=0; i<spec->n; i++)
284 stringstore_free(spec->attrs[i].attr);
286 if(spec->attrs!=NULL){
295 void gr_stylespec_init(GrStyleSpec *spec)
302 static bool gr_stylespec_find_(GrStyleSpec *spec, GrAttr a, int *idx_ge)
307 for(i=0; i<spec->n; i++){
308 if(spec->attrs[i].attr>=a){
309 found=(spec->attrs[i].attr==a);
318 bool gr_stylespec_add(GrStyleSpec *spec, GrAttr a, uint score)
320 static const uint sz=sizeof(GrAttrScore);
324 if(a==GRATTR_NONE || score==0)
327 if(gr_stylespec_find_(spec, a, &idx_ge)){
328 spec->attrs[idx_ge].score+=score;
332 idsn=(GrAttrScore*)realloc(spec->attrs, (spec->n+1)*sz);
339 memmove(idsn+idx_ge+1, idsn+idx_ge, (spec->n-idx_ge)*sz);
342 idsn[idx_ge].score=score;
350 bool gr_stylespec_set(GrStyleSpec *spec, GrAttr a)
352 return gr_stylespec_add(spec, a, 1);
356 void gr_stylespec_unset(GrStyleSpec *spec, GrAttr a)
358 static const uint sz=sizeof(GrAttrScore);
365 if(!gr_stylespec_find_(spec, a, &idx_ge))
368 stringstore_free(spec->attrs[idx_ge].attr);
370 memmove(spec->attrs+idx_ge, spec->attrs+idx_ge+1,
371 (spec->n-idx_ge-1)*sz);
375 idsn=(GrAttrScore*)realloc(spec->attrs, (spec->n)*sz);
377 if(idsn!=NULL || spec->n==0)
382 static bool gr_stylespec_do_init_from(GrStyleSpec *dst, const GrStyleSpec *src)
389 dst->attrs=ALLOC_N(GrAttrScore, src->n);
394 for(i=0; i<src->n; i++){
395 dst->attrs[i]=src->attrs[i];
396 stringstore_ref(dst->attrs[i].attr);
405 bool gr_stylespec_append(GrStyleSpec *dst, const GrStyleSpec *src)
410 if(dst->attrs==NULL){
411 ok=gr_stylespec_do_init_from(dst, src);
413 for(i=0; i<src->n; i++){
414 if(!gr_stylespec_add(dst, src->attrs[i].attr, src->attrs[i].score))
423 bool gr_stylespec_equals(const GrStyleSpec *s1, const GrStyleSpec *s2)
430 for(i=0; i<s1->n; i++){
431 if(s1->attrs[i].attr!=s2->attrs[i].attr)
442 /*{{{ Init, deinit */
445 bool grbrush_init(GrBrush *brush)
451 void grbrush_deinit(GrBrush *brush)
456 void grbrush_release(GrBrush *brush)
458 CALL_DYN(grbrush_release, brush, (brush));
462 GrBrush *grbrush_get_slave(GrBrush *brush, WRootWin *rootwin,
466 CALL_DYN_RET(slave, GrBrush*, grbrush_get_slave, brush,
467 (brush, rootwin, style));
475 /*{{{ Dynfuns/begin/end/replay */
478 void grbrush_begin(GrBrush *brush, const WRectangle *geom, int flags)
480 CALL_DYN(grbrush_begin, brush, (brush, geom, flags));
484 void grbrush_end(GrBrush *brush)
486 CALL_DYN(grbrush_end, brush, (brush));
493 /*{{{ Dynfuns/values */
496 void grbrush_get_font_extents(GrBrush *brush, GrFontExtents *fnte)
498 CALL_DYN(grbrush_get_font_extents, brush, (brush, fnte));
502 void grbrush_get_border_widths(GrBrush *brush, GrBorderWidths *bdw)
504 CALL_DYN(grbrush_get_border_widths, brush, (brush, bdw));
508 DYNFUN bool grbrush_get_extra(GrBrush *brush, const char *key,
509 char type, void *data)
512 CALL_DYN_RET(ret, bool, grbrush_get_extra, brush,
513 (brush, key, type, data));
521 /*{{{ Dynfuns/Borders */
524 void grbrush_draw_border(GrBrush *brush, const WRectangle *geom)
526 CALL_DYN(grbrush_draw_border, brush, (brush, geom));
530 void grbrush_draw_borderline(GrBrush *brush, const WRectangle *geom,
533 CALL_DYN(grbrush_draw_borderline, brush, (brush, geom, line));
540 /*{{{ Dynfuns/Strings */
543 void grbrush_draw_string(GrBrush *brush, int x, int y,
544 const char *str, int len, bool needfill)
546 CALL_DYN(grbrush_draw_string, brush, (brush, x, y, str, len, needfill));
550 uint grbrush_get_text_width(GrBrush *brush, const char *text, uint len)
553 CALL_DYN_RET(ret, uint, grbrush_get_text_width, brush,
562 /*{{{ Dynfuns/Textboxes */
565 void grbrush_draw_textbox(GrBrush *brush, const WRectangle *geom,
566 const char *text, bool needfill)
568 CALL_DYN(grbrush_draw_textbox, brush, (brush, geom, text, needfill));
571 void grbrush_draw_textboxes(GrBrush *brush, const WRectangle *geom,
572 int n, const GrTextElem *elem,
575 CALL_DYN(grbrush_draw_textboxes, brush, (brush, geom, n, elem, needfill));
582 /*{{{ Dynfuns/Misc */
585 void grbrush_set_window_shape(GrBrush *brush, bool rough,
586 int n, const WRectangle *rects)
588 CALL_DYN(grbrush_set_window_shape, brush, (brush, rough, n, rects));
592 void grbrush_enable_transparency(GrBrush *brush, GrTransparency tr)
594 CALL_DYN(grbrush_enable_transparency, brush, (brush, tr));
598 void grbrush_fill_area(GrBrush *brush, const WRectangle *geom)
600 CALL_DYN(grbrush_fill_area, brush, (brush, geom));
604 void grbrush_clear_area(GrBrush *brush, const WRectangle *geom)
606 CALL_DYN(grbrush_clear_area, brush, (brush, geom));
610 void grbrush_init_attr(GrBrush *brush, const GrStyleSpec *spec)
612 CALL_DYN(grbrush_init_attr, brush, (brush, spec));
616 void grbrush_set_attr(GrBrush *brush, GrAttr attr)
618 CALL_DYN(grbrush_set_attr, brush, (brush, attr));
622 void grbrush_unset_attr(GrBrush *brush, GrAttr attr)
624 CALL_DYN(grbrush_unset_attr, brush, (brush, attr));
631 /*{{{ ioncore_read_config/refresh */
635 * Read drawing engine configuration file \file{draw.lua}.
637 EXTL_EXPORT_AS(gr, read_config)
638 void gr_read_config()
640 extl_read_config("look", NULL, TRUE);
642 /* If nothing has been loaded, try the default engine with
646 warn(TR("No drawing engines loaded, trying \"de\"."));
647 gr_select_engine("de");
653 * Refresh objects' brushes to update them to use newly loaded style.
655 EXTL_EXPORT_AS(gr, refresh)
660 FOR_ALL_ROOTWINS(rootwin){
661 region_updategr((WRegion*)rootwin);
669 /*{{{ Class implementation */
672 static DynFunTab grbrush_dynfuntab[]={
677 IMPLCLASS(GrBrush, Obj, grbrush_deinit, grbrush_dynfuntab);