]> git.decadent.org.uk Git - ion3.git/blob - de/style.c
[svn-inject] Installing original source of ion3
[ion3.git] / de / style.c
1 /*
2  * ion/de/style.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 <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 char *stylename)
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->style, stylename);
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     if(style->style!=NULL)
164         free(style->style);
165     
166     if(style->font!=NULL){
167         de_free_font(style->font);
168         style->font=NULL;
169     }
170     
171     if(style->cgrp_alloced)
172         de_free_colour_group(style->rootwin, &(style->cgrp));
173     
174     for(i=0; i<style->n_extra_cgrps; i++)
175         de_free_colour_group(style->rootwin, style->extra_cgrps+i);
176     
177     if(style->extra_cgrps!=NULL)
178         free(style->extra_cgrps);
179     
180     extl_unref_table(style->data_table);
181     
182     XFreeGC(ioncore_g.dpy, style->normal_gc);
183     
184     if(style->tabbrush_data_ok){
185         XFreeGC(ioncore_g.dpy, style->copy_gc);
186         XFreeGC(ioncore_g.dpy, style->stipple_gc);
187         XFreePixmap(ioncore_g.dpy, style->tag_pixmap);
188     }
189     
190     XSync(ioncore_g.dpy, False);
191     
192     if(style->based_on!=NULL){
193         destyle_unref(style->based_on);
194         style->based_on=NULL;
195     }
196 }
197
198
199 static void dump_style(DEStyle *style)
200 {
201     /* Allow the style still be used but get if off the list. */
202     UNLINK_ITEM(styles, style, next, prev);
203     destyle_unref(style);
204 }
205
206
207 bool destyle_init(DEStyle *style, WRootWin *rootwin, const char *name)
208 {
209     style->style=scopy(name);
210     if(style->style==NULL)
211         return FALSE;
212     
213     style->based_on=NULL;
214     
215     style->usecount=1;
216     /* Fallback brushes are not released on de_reset() */
217     style->is_fallback=FALSE;
218     
219     style->rootwin=rootwin;
220     
221     style->border.sh=1;
222     style->border.hl=1;
223     style->border.pad=1;
224     style->border.style=DEBORDER_INLAID;
225
226     style->spacing=0;
227     
228     style->textalign=DEALIGN_CENTER;
229
230     style->cgrp_alloced=FALSE;
231     style->cgrp.spec=NULL;
232     style->cgrp.bg=DE_BLACK(rootwin);
233     style->cgrp.pad=DE_BLACK(rootwin);
234     style->cgrp.fg=DE_WHITE(rootwin);
235     style->cgrp.hl=DE_WHITE(rootwin);
236     style->cgrp.sh=DE_WHITE(rootwin);
237     
238     style->font=NULL;
239     
240     style->transparency_mode=GR_TRANSPARENCY_NO;
241     
242     style->n_extra_cgrps=0;
243     style->extra_cgrps=NULL;
244     
245     style->data_table=extl_table_none();
246     
247     create_normal_gc(style, rootwin);
248     
249     style->tabbrush_data_ok=FALSE;
250     
251     return TRUE;
252 }
253
254
255 static DEStyle *do_create_style(WRootWin *rootwin, const char *name)
256 {
257     DEStyle *style=ALLOC(DEStyle);
258     if(style!=NULL){
259         if(!destyle_init(style, rootwin, name)){
260             free(style);
261             return NULL;
262         }
263     }
264     return style;
265 }
266
267
268 DEStyle *de_create_style(WRootWin *rootwin, const char *name)
269 {
270     DEStyle *oldstyle, *style;
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 && oldstyle->style!=NULL && 
279            strcmp(oldstyle->style, name)==0){
280             break;
281         }
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 %s still in use [%d] but the module "
316                     "is being unloaded!"), style->style, style->usecount);
317         }
318         dump_style(style);
319     }
320 }
321
322
323 /*}}}*/
324
325