]> git.decadent.org.uk Git - ion3.git/blob - ioncore/gr.c
d4f5a151959e6c7242284647a50e8bc2b1da9f7c
[ion3.git] / ioncore / gr.c
1 /*
2  * ion/ioncore/gr.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 <libextl/readconfig.h>
16 #include <libmainloop/hooks.h>
17 #include "common.h"
18 #include "global.h"
19 #include "modules.h"
20 #include "gr.h"
21
22
23 /*{{{ Lookup and registration */
24
25 INTRSTRUCT(GrEngine);
26
27 DECLSTRUCT(GrEngine){
28     char *name;
29     GrGetBrushFn *fn;
30     GrEngine *next, *prev;
31 };
32
33
34 static GrEngine *engines=NULL, *current_engine=NULL;
35
36
37 bool gr_register_engine(const char *engine, GrGetBrushFn *fn)
38 {
39     GrEngine *eng;
40     
41     if(engine==NULL || fn==NULL)
42         return FALSE;
43     
44     eng=ALLOC(GrEngine);
45     
46     if(eng==NULL)
47         return FALSE;
48     
49     eng->name=scopy(engine);
50     
51     if(eng->name==NULL){
52         free(eng);
53         return FALSE;
54     }
55     
56     eng->fn=fn;
57     
58     LINK_ITEM(engines, eng, next, prev);
59
60     return TRUE;
61 }
62
63
64 void gr_unregister_engine(const char *engine)
65 {
66     GrEngine *eng;
67     
68     for(eng=engines; eng!=NULL; eng=eng->next){
69         if(strcmp(eng->name, engine)==0)
70             break;
71     }
72     
73     if(eng==NULL)
74         return;
75     
76     UNLINK_ITEM(engines, eng, next, prev);
77     free(eng->name);
78     if(current_engine==eng)
79         current_engine=NULL;
80     free(eng);
81 }
82
83
84 static bool gr_do_select_engine(const char *engine)
85 {
86     GrEngine *eng;
87
88     for(eng=engines; eng!=NULL; eng=eng->next){
89         if(strcmp(eng->name, engine)==0){
90             current_engine=eng;
91             return TRUE;
92         }
93     }
94     
95     return FALSE;
96 }
97
98
99 /*EXTL_DOC
100  * Future requests for ''brushes'' are to be forwarded to the drawing engine
101  * \var{engine}. If no engine of such name is known, a module with that name
102  * is attempted to be loaded. This function is only intended to be called from
103  * colour scheme etc. configuration files and can not be used to change the
104  * look of existing objects; for that use \fnref{gr.read_config}.
105  */
106 EXTL_EXPORT_AS(gr, select_engine)
107 bool gr_select_engine(const char *engine)
108 {
109     if(engine==NULL)
110         return FALSE;
111     
112     if(gr_do_select_engine(engine))
113         return TRUE;
114     
115     if(!ioncore_load_module(engine))
116         return FALSE;
117     
118     if(!gr_do_select_engine(engine)){
119         warn(TR("Drawing engine %s is not registered!"), engine);
120         return FALSE;
121     }
122     
123     return TRUE;
124 }
125
126
127 GrBrush *gr_get_brush(Window win, WRootWin *rootwin, const char *style)
128 {
129     GrEngine *eng=(current_engine!=NULL ? current_engine : engines);
130     GrBrush *ret;
131     
132     if(eng==NULL || eng->fn==NULL)
133         return NULL;
134     
135     ret=(eng->fn)(win, rootwin, style);
136     
137     if(ret==NULL)
138         warn(TR("Unable to find brush for style '%s'."), style);
139         
140     return ret;
141 }
142
143
144 /*}}}*/
145
146
147 /*{{{ Scoring */
148
149
150 uint gr_stylespec_score2(const char *spec, const char *attrib, 
151                          const char *attrib_p2)
152 {
153     uint score=0;
154     uint a=0;
155     uint mult=1;
156
157     if(attrib==NULL){
158         if(spec==NULL || strcmp(spec, "*")==0)
159             return 1;
160         return 0;
161     }
162     
163     while(1){
164         if(*spec=='*'){
165             score=score+mult;
166             spec++;
167             attrib=strchr(attrib, '-');
168         }else{
169             while(1){
170                 if(*attrib=='\0'){
171                     attrib=NULL;
172                     break;
173                 }
174                 if(*attrib=='-')
175                     break;
176                 if(*spec!=*attrib)
177                     return 0;
178                 attrib++;
179                 spec++;
180             }
181             score=score+2*mult;
182         }
183         
184         if(*spec=='\0')
185             return score;
186         else if(*spec!='-')
187             return 0;
188         
189         if(attrib==NULL){
190             if(a==0 && attrib_p2!=NULL){
191                 attrib=attrib_p2;
192                 a++;
193             }else{
194                 return 0;
195             }
196         }else{
197             attrib++;
198         }
199
200         spec++;
201         mult=mult*3;
202     }
203 }
204
205
206 uint gr_stylespec_score(const char *spec, const char *attrib)
207 {
208     return gr_stylespec_score2(spec, attrib, NULL);
209 }
210
211
212 /*}}}*/
213
214
215 /*{{{ Init, deinit */
216
217
218 bool grbrush_init(GrBrush *brush)
219 {
220     return TRUE;
221 }
222
223
224 void grbrush_deinit(GrBrush *brush)
225 {
226 }
227
228
229 void grbrush_release(GrBrush *brush)
230 {
231     CALL_DYN(grbrush_release, brush, (brush));
232 }
233
234
235 GrBrush *grbrush_get_slave(GrBrush *brush, WRootWin *rootwin, 
236                            const char *style)
237 {
238     GrBrush *slave=NULL;
239     CALL_DYN_RET(slave, GrBrush*, grbrush_get_slave, brush,
240                  (brush, rootwin, style));
241     return slave;
242 }
243
244
245 /*}}}*/
246
247
248 /*{{{ Dynfuns/begin/end/replay */
249
250
251 void grbrush_begin(GrBrush *brush, const WRectangle *geom, int flags)
252 {
253     CALL_DYN(grbrush_begin, brush, (brush, geom, flags));
254 }
255
256
257 void grbrush_end(GrBrush *brush)
258 {
259     CALL_DYN(grbrush_end, brush, (brush));
260 }
261
262
263 /*}}}*/
264
265
266 /*{{{ Dynfuns/values */
267
268
269 void grbrush_get_font_extents(GrBrush *brush, GrFontExtents *fnte)
270 {
271     CALL_DYN(grbrush_get_font_extents, brush, (brush, fnte));
272 }
273
274
275 void grbrush_get_border_widths(GrBrush *brush, GrBorderWidths *bdw)
276 {
277     CALL_DYN(grbrush_get_border_widths, brush, (brush, bdw));
278 }
279
280
281 DYNFUN bool grbrush_get_extra(GrBrush *brush, const char *key, 
282                               char type, void *data)
283 {
284     bool ret=FALSE;
285     CALL_DYN_RET(ret, bool, grbrush_get_extra, brush,
286                  (brush, key, type, data));
287     return ret;
288 }
289
290
291 /*}}}*/
292
293
294 /*{{{ Dynfuns/Borders */
295
296
297 void grbrush_draw_border(GrBrush *brush, const WRectangle *geom,
298                          const char *attrib)
299 {
300     CALL_DYN(grbrush_draw_border, brush, (brush, geom, attrib));
301 }
302
303
304 void grbrush_draw_borderline(GrBrush *brush, const WRectangle *geom,
305                              const char *attrib, GrBorderLine line)
306 {
307     CALL_DYN(grbrush_draw_borderline, brush, (brush, geom, attrib, line));
308 }
309
310
311 /*}}}*/
312
313
314 /*{{{ Dynfuns/Strings */
315
316
317 void grbrush_draw_string(GrBrush *brush, int x, int y,
318                          const char *str, int len, bool needfill,
319                          const char *attrib)
320 {
321     CALL_DYN(grbrush_draw_string, brush, 
322              (brush, x, y, str, len, needfill, attrib));
323 }
324
325
326 uint grbrush_get_text_width(GrBrush *brush, const char *text, uint len)
327 {
328     uint ret=0;
329     CALL_DYN_RET(ret, uint, grbrush_get_text_width, brush, 
330                  (brush, text, len));
331     return ret;
332 }
333
334
335 /*}}}*/
336
337
338 /*{{{ Dynfuns/Textboxes */
339
340
341 void grbrush_draw_textbox(GrBrush *brush, const WRectangle *geom,
342                           const char *text, const char *attr,
343                           bool needfill)
344 {
345     CALL_DYN(grbrush_draw_textbox, brush, 
346              (brush, geom, text, attr, needfill));
347 }
348
349 void grbrush_draw_textboxes(GrBrush *brush, const WRectangle *geom,
350                             int n, const GrTextElem *elem, 
351                             bool needfill, const char *common_attrib)
352 {
353     CALL_DYN(grbrush_draw_textboxes, brush, 
354              (brush, geom, n, elem, needfill, common_attrib));
355 }
356
357
358 /*}}}*/
359
360
361 /*{{{ Dynfuns/Misc */
362
363
364 void grbrush_set_window_shape(GrBrush *brush, bool rough,
365                               int n, const WRectangle *rects)
366 {
367     CALL_DYN(grbrush_set_window_shape, brush, (brush, rough, n, rects));
368 }
369
370
371 void grbrush_enable_transparency(GrBrush *brush, GrTransparency tr)
372 {
373     CALL_DYN(grbrush_enable_transparency, brush, (brush, tr));
374 }
375
376
377 void grbrush_fill_area(GrBrush *brush, const WRectangle *geom,
378                        const char *attr)
379 {
380     CALL_DYN(grbrush_fill_area, brush, (brush, geom, attr));
381 }
382
383
384 void grbrush_clear_area(GrBrush *brush, const WRectangle *geom)
385 {
386     CALL_DYN(grbrush_clear_area, brush, (brush, geom));
387 }
388
389
390 /*}}}*/
391
392
393 /*{{{ ioncore_read_config/refresh */
394
395
396 /*EXTL_DOC
397  * Read drawing engine configuration file \file{draw.lua}.
398  */
399 EXTL_EXPORT_AS(gr, read_config)
400 void gr_read_config()
401 {
402     extl_read_config("look", NULL, TRUE);
403     
404     /* If nothing has been loaded, try the default engine with
405      * default settings.
406      */
407     if(engines==NULL){
408         warn(TR("No drawing engines loaded, trying \"de\"."));
409         gr_select_engine("de");
410     }
411 }
412
413
414 /*EXTL_DOC
415  * Refresh objects' brushes to update them to use newly loaded style.
416  */
417 EXTL_EXPORT_AS(gr, refresh)
418 void gr_refresh()
419 {
420     WRootWin *rootwin;
421     
422     FOR_ALL_ROOTWINS(rootwin){
423         region_updategr((WRegion*)rootwin);
424     }
425 }
426
427
428 /*}}}*/
429
430
431 /*{{{ Class implementation */
432
433
434 static DynFunTab grbrush_dynfuntab[]={
435     END_DYNFUNTAB
436 };
437                                        
438
439 IMPLCLASS(GrBrush, Obj, grbrush_deinit, grbrush_dynfuntab);
440
441
442 /*}}}*/
443