]> git.decadent.org.uk Git - ion3.git/blob - de/init.c
Merged upstream version 20071109 (now without docs kluged into it).
[ion3.git] / de / init.c
1 /*
2  * ion/de/init.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libextl/readconfig.h>
12 #include <libextl/extl.h>
13
14 #include <ioncore/common.h>
15 #include <ioncore/global.h>
16 #include <ioncore/rootwin.h>
17 #include <ioncore/extlconv.h>
18 #include <ioncore/ioncore.h>
19
20 #include "brush.h"
21 #include "font.h"
22 #include "colour.h"
23 #include "private.h"
24 #include "init.h"
25 #include "exports.h"
26
27
28 /*{{{ Style specifications */
29
30
31 static bool get_spec(ExtlTab tab, const char *name, GrStyleSpec *spec,
32                      char **pat_ret)
33 {
34     char *str;
35     bool res;
36     
37     if(!extl_table_gets_s(tab, name, &str))
38         return FALSE;
39         
40     res=gr_stylespec_load(spec, str);
41     
42     if(pat_ret==NULL)
43         free(str);
44     else
45         *pat_ret=str;
46     
47     return res;
48 }
49
50
51 /*}}}*/
52
53
54 /*{{{ Borders */
55
56
57 #define CF_BORDER_VAL_SANITY_CHECK 16
58
59 void de_get_border_val(uint *val, ExtlTab tab, const char *what)
60 {
61     int g;
62     
63     if(extl_table_gets_i(tab, what, &g)){
64         if(g>CF_BORDER_VAL_SANITY_CHECK || g<0)
65             warn(TR("Border attribute %s sanity check failed."), what);
66         else
67             *val=g;
68     }
69 }
70
71
72 void de_get_border_style(uint *ret, ExtlTab tab)
73 {
74     char *style=NULL;
75     
76     if(!extl_table_gets_s(tab, "border_style", &style))
77         return;
78     
79     if(strcmp(style, "inlaid")==0)
80         *ret=DEBORDER_INLAID;
81     else if(strcmp(style, "elevated")==0)
82         *ret=DEBORDER_ELEVATED;
83     else if(strcmp(style, "groove")==0)
84         *ret=DEBORDER_GROOVE;
85     else if(strcmp(style, "ridge")==0)
86         *ret=DEBORDER_RIDGE;
87     else
88         warn(TR("Unknown border style \"%s\"."), style);
89     
90     free(style);
91 }
92
93
94 void de_get_border_sides(uint *ret, ExtlTab tab)
95 {
96     char *style=NULL;
97     
98     if(!extl_table_gets_s(tab, "border_sides", &style))
99         return;
100     
101     if(strcmp(style, "all")==0)
102         *ret=DEBORDER_ALL;
103     else if(strcmp(style, "tb")==0)
104         *ret=DEBORDER_TB;
105     else if(strcmp(style, "lr")==0)
106         *ret=DEBORDER_LR;
107     else
108         warn(TR("Unknown border side configuration \"%s\"."), style);
109     
110     free(style);
111 }
112
113
114 void de_get_border(DEBorder *border, ExtlTab tab)
115 {
116     de_get_border_val(&(border->sh), tab, "shadow_pixels");
117     de_get_border_val(&(border->hl), tab, "highlight_pixels");
118     de_get_border_val(&(border->pad), tab, "padding_pixels");
119     de_get_border_style(&(border->style), tab);
120     de_get_border_sides(&(border->sides), tab);
121 }
122
123
124 /*}}}*/
125
126
127 /*{{{ Colours */
128
129
130 static bool de_get_colour_(WRootWin *rootwin, DEColour *ret, 
131                            ExtlTab tab, const char *what, 
132                            DEColour substitute, DEColour inherit)
133 {
134     char *name=NULL;
135     bool set=FALSE;
136     
137     if(extl_table_gets_s(tab, what, &name)){
138         if(strcmp(name, "inherit")==0){
139             set=de_duplicate_colour(rootwin, inherit, ret);
140         }else{
141             set=de_alloc_colour(rootwin, ret, name);
142     
143             if(!set)
144                 warn(TR("Unable to allocate colour \"%s\"."), name);
145         }
146         free(name);
147     }
148     
149     if(!set)
150         de_duplicate_colour(rootwin, substitute, ret);
151     
152     return set;
153 }
154
155
156 static bool de_get_colour(WRootWin *rootwin, DEColour *ret, 
157                           ExtlTab tab, const char *what, DEColour substitute)
158 {
159     return de_get_colour_(rootwin, ret, tab, what, substitute, substitute);
160 }
161                           
162
163 void de_get_colour_group(WRootWin *rootwin, DEColourGroup *cg, 
164                          ExtlTab tab, DEStyle *based_on)
165 {
166     bool bgset;
167     DEColour padinh;
168     
169     de_get_colour(rootwin, &(cg->hl), tab, "highlight_colour",
170                   (based_on ? based_on->cgrp.hl : DE_WHITE(rootwin)));
171     de_get_colour(rootwin, &(cg->sh), tab, "shadow_colour",
172                   (based_on ? based_on->cgrp.sh : DE_WHITE(rootwin)));
173     de_get_colour(rootwin, &(cg->fg), tab, "foreground_colour",
174                   (based_on ? based_on->cgrp.fg : DE_WHITE(rootwin)));
175     bgset=de_get_colour(rootwin, &(cg->bg), tab, "background_colour",
176                         (based_on ? based_on->cgrp.bg : DE_BLACK(rootwin)));
177                         
178     padinh=(based_on ? based_on->cgrp.pad : DE_WHITE(rootwin));
179     
180     de_get_colour_(rootwin, &(cg->pad), tab, "padding_colour", 
181                    (bgset ? cg->bg : padinh), padinh);
182 }
183
184
185 void de_get_extra_cgrps(WRootWin *rootwin, DEStyle *style, ExtlTab tab)
186 {
187     
188     uint i=0, nfailed=0, n=extl_table_get_n(tab);
189     char *name;
190     ExtlTab sub;
191     
192     if(n==0)
193         return;
194     
195     style->extra_cgrps=ALLOC_N(DEColourGroup, n);
196     
197     if(style->extra_cgrps==NULL)
198         return;
199
200     for(i=0; i<n-nfailed; i++){
201         GrStyleSpec spec;
202         
203         if(!extl_table_geti_t(tab, i+1, &sub))
204             goto err;
205         
206         if(!get_spec(sub, "substyle_pattern", &spec, NULL)){
207             extl_unref_table(sub);
208             goto err;
209         }
210         
211         style->extra_cgrps[i-nfailed].spec=spec;
212         
213         de_get_colour_group(rootwin, style->extra_cgrps+i-nfailed, sub, 
214                             style);
215         
216         extl_unref_table(sub);
217         continue;
218         
219     err:
220         warn(TR("Corrupt substyle table %d."), i);
221         nfailed++;
222     }
223     
224     if(n-nfailed==0){
225         free(style->extra_cgrps);
226         style->extra_cgrps=NULL;
227     }
228     
229     style->n_extra_cgrps=n-nfailed;
230 }
231
232
233 /*}}}*/
234
235
236 /*{{{ Misc. */
237
238
239 void de_get_text_align(int *alignret, ExtlTab tab)
240 {
241     char *align=NULL;
242     
243     if(!extl_table_gets_s(tab, "text_align", &align))
244         return;
245     
246     if(strcmp(align, "left")==0)
247         *alignret=DEALIGN_LEFT;
248     else if(strcmp(align, "right")==0)
249         *alignret=DEALIGN_RIGHT;
250     else if(strcmp(align, "center")==0)
251         *alignret=DEALIGN_CENTER;
252     else
253         warn(TR("Unknown text alignment \"%s\"."), align);
254     
255     free(align);
256 }
257
258
259 void de_get_transparent_background(uint *mode, ExtlTab tab)
260 {
261     bool b;
262     
263     if(extl_table_gets_b(tab, "transparent_background", &b))
264         *mode=b;
265 }
266
267
268 /*}}}*/
269
270
271 /*{{{ Extras filter/copy */
272
273
274 static const char * const known_values[]={
275     "based_on",
276     "font",
277     "shadow_pixels",
278     "highlight_pixels",
279     "padding_pixels",
280     "border_style",
281     "border_sides",
282     "spacing",
283     "foreground_colour",
284     "background_colour",
285     "shadow_colour",
286     "highlight_colour",
287     "padding_colour",
288     "text_align",
289     NULL
290 };
291
292
293 static bool filter_extras_iter_fn(ExtlAny k, ExtlAny v, void *p)
294 {
295     ExtlTab *tgt=(ExtlTab*)p;
296     const char *s;
297     int i;
298     
299     if(k.type!='s' && k.type!='S')
300         return TRUE;
301     
302     for(i=0; known_values[i]; i++){
303         if(strcmp(known_values[i], k.value.s)==0)
304             return TRUE;
305     }
306     
307     if(*tgt==extl_table_none())
308         *tgt=extl_create_table();
309         
310     extl_table_set(*tgt, 'a', 'a', k, v);
311     
312     return TRUE;
313 }
314
315
316 static void filter_extras(ExtlTab *tgt, ExtlTab src)
317 {
318     /* Copy any unknown string-keyed values from src to tgt,
319      * possibly creating tgt.
320      */
321     extl_table_iter(src, filter_extras_iter_fn, tgt);
322 }
323
324
325 /*}}}*/
326
327
328 /*{{{ de_defstyle */
329
330
331 void de_get_nonfont(WRootWin *rootwin, DEStyle *style, ExtlTab tab)
332 {
333     DEStyle *based_on=style->based_on;
334     
335     if(based_on!=NULL){
336         style->border=based_on->border;
337         style->transparency_mode=based_on->transparency_mode;
338         style->textalign=based_on->textalign;
339         style->spacing=based_on->spacing;
340     }
341     
342     de_get_border(&(style->border), tab);
343     de_get_border_val(&(style->spacing), tab, "spacing");
344
345     de_get_text_align(&(style->textalign), tab);
346
347     de_get_transparent_background(&(style->transparency_mode), tab);
348
349     style->cgrp_alloced=TRUE;
350     de_get_colour_group(rootwin, &(style->cgrp), tab, based_on);
351     de_get_extra_cgrps(rootwin, style, tab);
352 }
353
354
355
356
357 /*EXTL_DOC
358  * Define a style for the root window \var{rootwin}. 
359  */
360 EXTL_EXPORT
361 bool de_defstyle_rootwin(WRootWin *rootwin, const char *name, ExtlTab tab)
362 {
363     DEStyle *style, *based_on=NULL;
364     int based_on_score=-1;
365     char *fnt, *bss;
366     uint n;
367
368     if(name==NULL)
369         return FALSE;
370     
371     style=de_create_style(rootwin, name);
372     
373     if(style==NULL)
374         return FALSE;
375     
376     if(extl_table_gets_s(tab, "based_on", &bss)){
377         GrStyleSpec bs;
378         
379         gr_stylespec_load(&bs, bss);
380         
381         based_on=de_get_style(rootwin, &bs);
382         
383         gr_stylespec_unalloc(&bs);
384         free(bss);
385     }else{
386         based_on=de_get_style(rootwin, &style->spec);
387     }
388     
389     if(based_on!=NULL){
390         style->based_on=based_on;
391         based_on->usecount++;
392     }
393     
394     de_get_nonfont(rootwin, style, tab);
395
396     if(extl_table_gets_s(tab, "font", &fnt)){
397         de_load_font_for_style(style, fnt);
398         free(fnt);
399     }else if(based_on!=NULL && based_on->font!=NULL){
400         de_set_font_for_style(style, based_on->font);
401     }
402     
403     if(style->font==NULL)
404         de_load_font_for_style(style, CF_FALLBACK_FONT_NAME);
405     
406     if(based_on!=NULL && 
407        gr_stylespec_equals(&based_on->spec, &style->spec)){
408        
409         /* The new style replaces based_on, so it may be dumped. */
410         if(!based_on->is_fallback)
411             destyle_dump(based_on);
412         
413         if(based_on->usecount==1){
414             uint nb=based_on->n_extra_cgrps;
415             uint ns=style->n_extra_cgrps;
416             /* Nothing else is using based_on: optimise and move
417              * extra colour groups here, so that based_on can be freed.
418              */
419             
420             if(nb>0){
421                 DEColourGroup *cgs=ALLOC_N(DEColourGroup, nb+ns);
422                 
423                 if(cgs!=NULL){
424                     memcpy(cgs, based_on->extra_cgrps, sizeof(DEColourGroup)*nb);
425                     memcpy(cgs+nb, style->extra_cgrps, sizeof(DEColourGroup)*ns);
426                 
427                     free(style->extra_cgrps);
428                     style->extra_cgrps=cgs;
429                     style->n_extra_cgrps=nb+ns;
430                 
431                     free(based_on->extra_cgrps);
432                     based_on->extra_cgrps=NULL;
433                     based_on->n_extra_cgrps=0;
434                     
435                 }
436             }
437             
438             /* style->extras_table should be none still */
439             style->extras_table=based_on->extras_table;
440             based_on->extras_table=extl_table_none();
441             
442             style->based_on=based_on->based_on;
443             based_on->based_on=NULL;
444             
445             destyle_unref(based_on);
446         }
447         
448     }
449     
450     filter_extras(&style->extras_table, tab);
451     
452     destyle_add(style);
453     
454     return TRUE;
455 }
456
457
458 /*EXTL_DOC
459  * Define a style.
460  */
461 EXTL_EXPORT
462 bool de_defstyle(const char *name, ExtlTab tab)
463 {
464     bool ok=TRUE;
465     WRootWin *rw;
466     
467     FOR_ALL_ROOTWINS(rw){
468         if(!de_defstyle_rootwin(rw, name, tab))
469             ok=FALSE;
470     }
471     
472     return ok;
473 }
474
475
476 /*EXTL_DOC
477  * Define a substyle.
478  */
479 EXTL_SAFE
480 EXTL_EXPORT
481 ExtlTab de_substyle(const char *pattern, ExtlTab tab)
482 {
483     extl_table_sets_s(tab, "substyle_pattern", pattern);
484     return extl_ref_table(tab);
485 }
486
487
488 /*}}}*/
489
490
491 /*{{{ Module initialisation */
492
493
494 #include "../version.h"
495
496 char de_ion_api_version[]=ION_API_VERSION;
497
498
499 bool de_init()
500 {
501     WRootWin *rootwin;
502     DEStyle *style;
503     
504     if(!de_register_exports())
505         return FALSE;
506     
507     if(!gr_register_engine("de", (GrGetBrushFn*)&de_get_brush))
508         goto fail;
509     
510     /* Create fallback brushes */
511     FOR_ALL_ROOTWINS(rootwin){
512         style=de_create_style(rootwin, "*");
513         if(style!=NULL){
514             style->is_fallback=TRUE;
515             de_load_font_for_style(style, CF_FALLBACK_FONT_NAME);
516         }
517     }
518     
519     return TRUE;
520     
521 fail:
522     de_unregister_exports();
523     return FALSE;
524 }
525
526
527 void de_deinit()
528 {
529     gr_unregister_engine("de");
530     de_unregister_exports();
531     de_deinit_styles();
532 }
533
534
535 /*}}}*/
536