4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
13 #include <libextl/readconfig.h>
14 #include <libmainloop/hooks.h>
21 /*{{{ Lookup and registration */
28 GrEngine
*next
, *prev
;
32 static GrEngine
*engines
=NULL
, *current_engine
=NULL
;
35 bool gr_register_engine(const char *engine
, GrGetBrushFn
*fn
)
39 if(engine
==NULL
|| fn
==NULL
)
47 eng
->name
=scopy(engine
);
56 LINK_ITEM(engines
, eng
, next
, prev
);
62 void gr_unregister_engine(const char *engine
)
66 for(eng
=engines
; eng
!=NULL
; eng
=eng
->next
){
67 if(strcmp(eng
->name
, engine
)==0)
74 UNLINK_ITEM(engines
, eng
, next
, prev
);
76 if(current_engine
==eng
)
82 static bool gr_do_select_engine(const char *engine
)
86 for(eng
=engines
; eng
!=NULL
; eng
=eng
->next
){
87 if(strcmp(eng
->name
, engine
)==0){
98 * Future requests for ``brushes'' are to be forwarded to the drawing engine
99 * \var{engine}. If no engine of such name is known, a module with that name
100 * is attempted to be loaded. This function is only intended to be called from
101 * colour scheme etc. configuration files and can not be used to change the
102 * look of existing objects; for that use \fnref{gr.read_config}.
104 EXTL_EXPORT_AS(gr
, select_engine
)
105 bool gr_select_engine(const char *engine
)
110 if(gr_do_select_engine(engine
))
113 if(!ioncore_load_module(engine
))
116 if(!gr_do_select_engine(engine
)){
117 warn(TR("Drawing engine %s is not registered!"), engine
);
125 GrBrush
*gr_get_brush(Window win
, WRootWin
*rootwin
, const char *style
)
127 GrEngine
*eng
=(current_engine
!=NULL
? current_engine
: engines
);
130 if(eng
==NULL
|| eng
->fn
==NULL
)
133 ret
=(eng
->fn
)(win
, rootwin
, style
);
136 warn(TR("Unable to find brush for style '%s'."), style
);
148 static GrAttr star_id
=STRINGID_NONE
;
151 static int cmp(const void *a_
, const void *b_
)
153 StringId a
=*(const StringId
*)a_
;
154 StringId b
=((const GrAttrScore
*)b_
)->attr
;
156 return (a
< b
? -1 : ((a
== b
) ? 0 : 1));
160 static uint
scorefind(const GrStyleSpec
*attr
, const GrAttrScore
*spec
)
164 if(attr
->attrs
==NULL
)
167 if(star_id
==STRINGID_NONE
)
168 star_id
=stringstore_alloc("*");
170 if(spec
->attr
==star_id
){
171 /* Since every item occurs only once on the list, with a score,
172 * return the score of the star in the spec, instead of one.
177 res
=bsearch(&spec
->attr
, attr
->attrs
, attr
->n
, sizeof(GrAttrScore
), cmp
);
179 return (res
==NULL
? 0 : 2*res
->score
);
183 uint
gr_stylespec_score2(const GrStyleSpec
*spec
, const GrStyleSpec
*attr1
,
184 const GrStyleSpec
*attr2
)
189 for(i
=0; i
<spec
->n
; i
++){
190 int sc
=scorefind(attr1
, &spec
->attrs
[i
]);
193 sc
=maxof(sc
, scorefind(attr2
, &spec
->attrs
[i
]));
207 uint
gr_stylespec_score(const GrStyleSpec
*spec
, const GrStyleSpec
*attr
)
209 return gr_stylespec_score2(spec
, attr
, NULL
);
213 static uint
count_dashes(const char *str
)
219 const char *p
=strchr(str
, '-');
231 bool gr_stylespec_load_(GrStyleSpec
*spec
, const char *str
, bool no_order_score
)
233 uint score
=(no_order_score
? 1 : count_dashes(str
)+1);
235 gr_stylespec_init(spec
);
239 const char *p
=strchr(str
, '-');
242 a
=stringstore_alloc(str
);
245 a
=stringstore_alloc_n(str
, p
-str
);
252 if(!gr_stylespec_add(spec
, a
, score
))
264 gr_stylespec_unalloc(spec
);
270 bool gr_stylespec_load(GrStyleSpec
*spec
, const char *str
)
272 return gr_stylespec_load_(spec
, str
, FALSE
);
276 void gr_stylespec_unalloc(GrStyleSpec
*spec
)
280 for(i
=0; i
<spec
->n
; i
++)
281 stringstore_free(spec
->attrs
[i
].attr
);
283 if(spec
->attrs
!=NULL
){
292 void gr_stylespec_init(GrStyleSpec
*spec
)
299 static bool gr_stylespec_find_(const GrStyleSpec
*spec
, GrAttr a
, int *idx_ge
)
304 for(i
=0; i
<spec
->n
; i
++){
305 if(spec
->attrs
[i
].attr
>=a
){
306 found
=(spec
->attrs
[i
].attr
==a
);
316 bool gr_stylespec_isset(const GrStyleSpec
*spec
, GrAttr a
)
320 return gr_stylespec_find_(spec
, a
, &idx_ge
);
324 bool gr_stylespec_add(GrStyleSpec
*spec
, GrAttr a
, uint score
)
326 static const uint sz
=sizeof(GrAttrScore
);
330 if(a
==GRATTR_NONE
|| score
==0)
333 if(gr_stylespec_find_(spec
, a
, &idx_ge
)){
334 spec
->attrs
[idx_ge
].score
+=score
;
338 idsn
=(GrAttrScore
*)realloc(spec
->attrs
, (spec
->n
+1)*sz
);
345 memmove(idsn
+idx_ge
+1, idsn
+idx_ge
, (spec
->n
-idx_ge
)*sz
);
348 idsn
[idx_ge
].score
=score
;
356 bool gr_stylespec_set(GrStyleSpec
*spec
, GrAttr a
)
358 return gr_stylespec_add(spec
, a
, 1);
362 void gr_stylespec_unset(GrStyleSpec
*spec
, GrAttr a
)
364 static const uint sz
=sizeof(GrAttrScore
);
371 if(!gr_stylespec_find_(spec
, a
, &idx_ge
))
374 stringstore_free(spec
->attrs
[idx_ge
].attr
);
376 memmove(spec
->attrs
+idx_ge
, spec
->attrs
+idx_ge
+1,
377 (spec
->n
-idx_ge
-1)*sz
);
381 idsn
=(GrAttrScore
*)realloc(spec
->attrs
, (spec
->n
)*sz
);
383 if(idsn
!=NULL
|| spec
->n
==0)
388 static bool gr_stylespec_do_init_from(GrStyleSpec
*dst
, const GrStyleSpec
*src
)
395 dst
->attrs
=ALLOC_N(GrAttrScore
, src
->n
);
400 for(i
=0; i
<src
->n
; i
++){
401 dst
->attrs
[i
]=src
->attrs
[i
];
402 stringstore_ref(dst
->attrs
[i
].attr
);
411 bool gr_stylespec_append(GrStyleSpec
*dst
, const GrStyleSpec
*src
)
416 if(dst
->attrs
==NULL
){
417 ok
=gr_stylespec_do_init_from(dst
, src
);
419 for(i
=0; i
<src
->n
; i
++){
420 if(!gr_stylespec_add(dst
, src
->attrs
[i
].attr
, src
->attrs
[i
].score
))
429 bool gr_stylespec_equals(const GrStyleSpec
*s1
, const GrStyleSpec
*s2
)
436 for(i
=0; i
<s1
->n
; i
++){
437 if(s1
->attrs
[i
].attr
!=s2
->attrs
[i
].attr
)
448 /*{{{ Init, deinit */
451 bool grbrush_init(GrBrush
*brush
)
457 void grbrush_deinit(GrBrush
*brush
)
462 void grbrush_release(GrBrush
*brush
)
464 CALL_DYN(grbrush_release
, brush
, (brush
));
468 GrBrush
*grbrush_get_slave(GrBrush
*brush
, WRootWin
*rootwin
,
472 CALL_DYN_RET(slave
, GrBrush
*, grbrush_get_slave
, brush
,
473 (brush
, rootwin
, style
));
481 /*{{{ Dynfuns/begin/end/replay */
484 void grbrush_begin(GrBrush
*brush
, const WRectangle
*geom
, int flags
)
486 CALL_DYN(grbrush_begin
, brush
, (brush
, geom
, flags
));
490 void grbrush_end(GrBrush
*brush
)
492 CALL_DYN(grbrush_end
, brush
, (brush
));
499 /*{{{ Dynfuns/values */
502 void grbrush_get_font_extents(GrBrush
*brush
, GrFontExtents
*fnte
)
504 CALL_DYN(grbrush_get_font_extents
, brush
, (brush
, fnte
));
508 void grbrush_get_border_widths(GrBrush
*brush
, GrBorderWidths
*bdw
)
510 CALL_DYN(grbrush_get_border_widths
, brush
, (brush
, bdw
));
514 DYNFUN
bool grbrush_get_extra(GrBrush
*brush
, const char *key
,
515 char type
, void *data
)
518 CALL_DYN_RET(ret
, bool, grbrush_get_extra
, brush
,
519 (brush
, key
, type
, data
));
527 /*{{{ Dynfuns/Borders */
530 void grbrush_draw_border(GrBrush
*brush
, const WRectangle
*geom
)
532 CALL_DYN(grbrush_draw_border
, brush
, (brush
, geom
));
536 void grbrush_draw_borderline(GrBrush
*brush
, const WRectangle
*geom
,
539 CALL_DYN(grbrush_draw_borderline
, brush
, (brush
, geom
, line
));
546 /*{{{ Dynfuns/Strings */
549 void grbrush_draw_string(GrBrush
*brush
, int x
, int y
,
550 const char *str
, int len
, bool needfill
)
552 CALL_DYN(grbrush_draw_string
, brush
, (brush
, x
, y
, str
, len
, needfill
));
556 uint
grbrush_get_text_width(GrBrush
*brush
, const char *text
, uint len
)
559 CALL_DYN_RET(ret
, uint
, grbrush_get_text_width
, brush
,
568 /*{{{ Dynfuns/Textboxes */
571 void grbrush_draw_textbox(GrBrush
*brush
, const WRectangle
*geom
,
572 const char *text
, bool needfill
)
574 CALL_DYN(grbrush_draw_textbox
, brush
, (brush
, geom
, text
, needfill
));
577 void grbrush_draw_textboxes(GrBrush
*brush
, const WRectangle
*geom
,
578 int n
, const GrTextElem
*elem
,
581 CALL_DYN(grbrush_draw_textboxes
, brush
, (brush
, geom
, n
, elem
, needfill
));
588 /*{{{ Dynfuns/Misc */
591 void grbrush_set_window_shape(GrBrush
*brush
, bool rough
,
592 int n
, const WRectangle
*rects
)
594 CALL_DYN(grbrush_set_window_shape
, brush
, (brush
, rough
, n
, rects
));
598 void grbrush_enable_transparency(GrBrush
*brush
, GrTransparency tr
)
600 CALL_DYN(grbrush_enable_transparency
, brush
, (brush
, tr
));
604 void grbrush_fill_area(GrBrush
*brush
, const WRectangle
*geom
)
606 CALL_DYN(grbrush_fill_area
, brush
, (brush
, geom
));
610 void grbrush_clear_area(GrBrush
*brush
, const WRectangle
*geom
)
612 CALL_DYN(grbrush_clear_area
, brush
, (brush
, geom
));
616 void grbrush_init_attr(GrBrush
*brush
, const GrStyleSpec
*spec
)
618 CALL_DYN(grbrush_init_attr
, brush
, (brush
, spec
));
622 void grbrush_set_attr(GrBrush
*brush
, GrAttr attr
)
624 CALL_DYN(grbrush_set_attr
, brush
, (brush
, attr
));
628 void grbrush_unset_attr(GrBrush
*brush
, GrAttr attr
)
630 CALL_DYN(grbrush_unset_attr
, brush
, (brush
, attr
));
637 /*{{{ ioncore_read_config/refresh */
641 * Read drawing engine configuration file \file{look.lua}.
643 EXTL_EXPORT_AS(gr
, read_config
)
644 void gr_read_config()
646 extl_read_config("look", NULL
, TRUE
);
648 /* If nothing has been loaded, try the default engine with
652 warn(TR("No drawing engines loaded, trying \"de\"."));
653 gr_select_engine("de");
659 * Refresh objects' brushes to update them to use newly loaded style.
661 EXTL_EXPORT_AS(gr
, refresh
)
666 FOR_ALL_ROOTWINS(rootwin
){
667 region_updategr((WRegion
*)rootwin
);
675 /*{{{ Class implementation */
678 static DynFunTab grbrush_dynfuntab
[]={
683 IMPLCLASS(GrBrush
, Obj
, grbrush_deinit
, grbrush_dynfuntab
);