]> git.decadent.org.uk Git - ion3.git/blob - de/style.c
b4493373e49b3e237726da77d1b0fd6e4cacd46f
[ion3.git] / de / style.c
1 /*
2  * ion/de/style.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
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 <libextl/extl.h>
15
16 #include <ioncore/common.h>
17 #include <ioncore/rootwin.h>
18 #include <ioncore/extlconv.h>
19 #include <ioncore/ioncore.h>
20
21 #include "brush.h"
22 #include "font.h"
23 #include "colour.h"
24 #include "private.h"
25 #include "style.h"
26
27
28 /*{{{ GC creation */
29
30
31 static void create_normal_gc(DEStyle *style, WRootWin *rootwin)
32 {
33     XGCValues gcv;
34     ulong gcvmask;
35     GC gc;
36
37     /* Create normal gc */
38     gcv.line_style=LineSolid;
39     gcv.line_width=1;
40     gcv.join_style=JoinBevel;
41     gcv.cap_style=CapButt;
42     gcv.fill_style=FillSolid;
43     gcvmask=(GCLineStyle|GCLineWidth|GCFillStyle|
44              GCJoinStyle|GCCapStyle);
45     
46     style->normal_gc=XCreateGC(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), 
47                                gcvmask, &gcv);
48 }
49
50
51 void destyle_create_tab_gcs(DEStyle *style)
52 {
53     Display *dpy=ioncore_g.dpy;
54     WRootWin *rootwin=style->rootwin;
55     Window root=WROOTWIN_ROOT(rootwin);
56     Pixmap stipple_pixmap;
57     XGCValues gcv;
58     ulong gcvmask;
59     GC tmp_gc;
60
61     /* Create a temporary 1-bit GC for drawing the tag and stipple pixmaps */
62     stipple_pixmap=XCreatePixmap(dpy, root, 2, 2, 1);
63     gcv.foreground=1;
64     tmp_gc=XCreateGC(dpy, stipple_pixmap, GCForeground, &gcv);
65
66     /* Create stipple pattern and stipple GC */
67     XDrawPoint(dpy, stipple_pixmap, tmp_gc, 0, 0);
68     XDrawPoint(dpy, stipple_pixmap, tmp_gc, 1, 1);
69     XSetForeground(dpy, tmp_gc, 0);
70     XDrawPoint(dpy, stipple_pixmap, tmp_gc, 1, 0);
71     XDrawPoint(dpy, stipple_pixmap, tmp_gc, 0, 1);
72     
73     gcv.fill_style=FillStippled;
74     /*gcv.function=GXclear;*/
75     gcv.stipple=stipple_pixmap;
76     gcvmask=GCFillStyle|GCStipple/*|GCFunction*/;
77     if(style->font!=NULL && style->font->fontstruct!=NULL){
78         gcv.font=style->font->fontstruct->fid;
79         gcvmask|=GCFont;
80     }
81
82     style->stipple_gc=XCreateGC(dpy, root, gcvmask, &gcv);
83     XCopyGC(dpy, style->normal_gc, 
84             GCLineStyle|GCLineWidth|GCJoinStyle|GCCapStyle,
85             style->stipple_gc);
86             
87     XFreePixmap(dpy, stipple_pixmap);
88     
89     /* Create tag pixmap and copying GC */
90     style->tag_pixmap_w=5;
91     style->tag_pixmap_h=5;
92     style->tag_pixmap=XCreatePixmap(dpy, root, 5, 5, 1);
93     
94     XSetForeground(dpy, tmp_gc, 0);
95     XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 0, 0, 5, 5);
96     XSetForeground(dpy, tmp_gc, 1);
97     XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 0, 0, 5, 2);
98     XFillRectangle(dpy, style->tag_pixmap, tmp_gc, 3, 2, 2, 3);
99     
100     gcv.foreground=DE_BLACK(rootwin);
101     gcv.background=DE_WHITE(rootwin);
102     gcv.line_width=2;
103     gcvmask=GCLineWidth|GCForeground|GCBackground;
104     
105     style->copy_gc=XCreateGC(dpy, root, gcvmask, &gcv);
106     
107     XFreeGC(dpy, tmp_gc);
108     
109     style->tabbrush_data_ok=TRUE;
110 }
111
112
113 /*}}}*/
114
115
116 /*{{{ Style lookup */
117
118
119 static DEStyle *styles=NULL;
120
121
122 DEStyle *de_get_style(WRootWin *rootwin, const GrStyleSpec *spec)
123 {
124     DEStyle *style, *maxstyle=NULL;
125     int score, maxscore=0;
126     
127     for(style=styles; style!=NULL; style=style->next){
128         if(style->rootwin!=rootwin)
129             continue;
130         score=gr_stylespec_score(&style->spec, spec);
131         if(score>maxscore){
132             maxstyle=style;
133             maxscore=score;
134         }
135     }
136     
137     return maxstyle;
138 }
139
140
141 /*}}}*/
142
143
144 /*{{{ Style initialisation and deinitialisation */
145
146
147 void destyle_unref(DEStyle *style)
148 {
149     style->usecount--;
150     if(style->usecount==0){
151         destyle_deinit(style);
152         free(style);
153     }
154 }
155
156
157 void destyle_deinit(DEStyle *style)
158 {
159     int i;
160     
161     UNLINK_ITEM(styles, style, next, prev);
162     
163     gr_stylespec_unalloc(&style->spec);
164     
165     if(style->font!=NULL){
166         de_free_font(style->font);
167         style->font=NULL;
168     }
169     
170     if(style->cgrp_alloced)
171         de_free_colour_group(style->rootwin, &(style->cgrp));
172     
173     for(i=0; i<style->n_extra_cgrps; i++)
174         de_free_colour_group(style->rootwin, style->extra_cgrps+i);
175     
176     if(style->extra_cgrps!=NULL)
177         free(style->extra_cgrps);
178     
179     extl_unref_table(style->data_table);
180     
181     XFreeGC(ioncore_g.dpy, style->normal_gc);
182     
183     if(style->tabbrush_data_ok){
184         XFreeGC(ioncore_g.dpy, style->copy_gc);
185         XFreeGC(ioncore_g.dpy, style->stipple_gc);
186         XFreePixmap(ioncore_g.dpy, style->tag_pixmap);
187     }
188     
189     XSync(ioncore_g.dpy, False);
190     
191     if(style->based_on!=NULL){
192         destyle_unref(style->based_on);
193         style->based_on=NULL;
194     }
195 }
196
197
198 static void dump_style(DEStyle *style)
199 {
200     /* Allow the style still be used but get if off the list. */
201     UNLINK_ITEM(styles, style, next, prev);
202     destyle_unref(style);
203 }
204
205
206 bool destyle_init(DEStyle *style, WRootWin *rootwin, const char *name)
207 {
208     if(!gr_stylespec_load(&style->spec, name))
209         return FALSE;
210     
211     style->based_on=NULL;
212     
213     style->usecount=1;
214     /* Fallback brushes are not released on de_reset() */
215     style->is_fallback=FALSE;
216     
217     style->rootwin=rootwin;
218     
219     style->border.sh=1;
220     style->border.hl=1;
221     style->border.pad=1;
222     style->border.style=DEBORDER_INLAID;
223     style->border.sides=DEBORDER_ALL;
224
225     style->spacing=0;
226     
227     style->textalign=DEALIGN_CENTER;
228
229     style->cgrp_alloced=FALSE;
230     style->cgrp.bg=DE_BLACK(rootwin);
231     style->cgrp.pad=DE_BLACK(rootwin);
232     style->cgrp.fg=DE_WHITE(rootwin);
233     style->cgrp.hl=DE_WHITE(rootwin);
234     style->cgrp.sh=DE_WHITE(rootwin);
235     gr_stylespec_init(&style->cgrp.spec);
236     
237     style->font=NULL;
238     
239     style->transparency_mode=GR_TRANSPARENCY_NO;
240     
241     style->n_extra_cgrps=0;
242     style->extra_cgrps=NULL;
243     
244     style->data_table=extl_table_none();
245     
246     create_normal_gc(style, rootwin);
247     
248     style->tabbrush_data_ok=FALSE;
249     
250     return TRUE;
251 }
252
253
254 static DEStyle *do_create_style(WRootWin *rootwin, const char *name)
255 {
256     DEStyle *style=ALLOC(DEStyle);
257     if(style!=NULL){
258         if(!destyle_init(style, rootwin, name)){
259             free(style);
260             return NULL;
261         }
262     }
263     return style;
264 }
265
266
267 DEStyle *de_create_style(WRootWin *rootwin, const char *name)
268 {
269     DEStyle *oldstyle, *style;
270     uint score;
271     
272     style=do_create_style(rootwin, name);
273     
274     if(style==NULL)
275         return NULL;
276     
277     for(oldstyle=styles; oldstyle!=NULL; oldstyle=oldstyle->next){
278         if(oldstyle->rootwin!=rootwin)
279             continue;
280         if(gr_stylespec_equals(&oldstyle->spec, &style->spec))
281             break;
282     }
283     
284     if(oldstyle!=NULL && !oldstyle->is_fallback)
285         dump_style(oldstyle);
286     
287     LINK_ITEM_FIRST(styles, style, next, prev);
288     
289     return style;
290 }
291
292
293
294 /*EXTL_DOC
295  * Clear all styles from drawing engine memory.
296  */
297 EXTL_EXPORT
298 void de_reset()
299 {
300     DEStyle *style, *next;
301     for(style=styles; style!=NULL; style=next){
302         next=style->next;
303         if(!style->is_fallback)
304             dump_style(style);
305     }
306 }
307
308
309 void de_deinit_styles()
310 {
311     DEStyle *style, *next;
312     for(style=styles; style!=NULL; style=next){
313         next=style->next;
314         if(style->usecount>1){
315             warn(TR("Style is still in use [%d] but the module "
316                     "is being unloaded!"), style->usecount);
317         }
318         dump_style(style);
319     }
320 }
321
322
323 /*}}}*/
324
325