]> git.decadent.org.uk Git - ion3.git/blob - de/font.c
0f6fab71a11fa9f09162dddcc32b2032b6dc04f4
[ion3.git] / de / font.c
1 /*
2  * ion/de/font.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libtu/objp.h>
12 #include <ioncore/common.h>
13 #include "font.h"
14 #include "fontset.h"
15 #include "brush.h"
16
17
18 /*{{{ Load/free */
19
20
21 static DEFont *fonts=NULL;
22
23
24 DEFont *de_load_font(const char *fontname)
25 {
26     DEFont *fnt;
27     XFontSet fontset=NULL;
28     XFontStruct *fontstruct=NULL;
29     
30     assert(fontname!=NULL);
31     
32     /* There shouldn't be that many fonts... */
33     for(fnt=fonts; fnt!=NULL; fnt=fnt->next){
34         if(strcmp(fnt->pattern, fontname)==0){
35             fnt->refcount++;
36             return fnt;
37         }
38     }
39     
40     if(ioncore_g.use_mb){
41         fontset=de_create_font_set(fontname);
42         if(fontset!=NULL){
43             if(XContextDependentDrawing(fontset)){
44                 warn(TR("Fontset for font pattern '%s' implements context "
45                         "dependent drawing, which is unsupported. Expect "
46                         "clutter."), fontname);
47             }
48         }
49     }else{
50         fontstruct=XLoadQueryFont(ioncore_g.dpy, fontname);
51     }
52     
53     if(fontstruct==NULL && fontset==NULL){
54         if(strcmp(fontname, CF_FALLBACK_FONT_NAME)!=0){
55             DEFont *fnt;
56             warn(TR("Could not load font \"%s\", trying \"%s\""),
57                  fontname, CF_FALLBACK_FONT_NAME);
58             fnt=de_load_font(CF_FALLBACK_FONT_NAME);
59             if(fnt==NULL)
60                 warn(TR("Failed to load fallback font."));
61             return fnt;
62         }
63         return NULL;
64     }
65     
66     fnt=ALLOC(DEFont);
67     
68     if(fnt==NULL)
69         return NULL;
70     
71     fnt->fontset=fontset;
72     fnt->fontstruct=fontstruct;
73     fnt->pattern=scopy(fontname);
74     fnt->next=NULL;
75     fnt->prev=NULL;
76     fnt->refcount=1;
77     
78     LINK_ITEM(fonts, fnt, next, prev);
79     
80     return fnt;
81 }
82
83
84 bool de_set_font_for_style(DEStyle *style, DEFont *font)
85 {
86     if(style->font!=NULL)
87         de_free_font(style->font);
88     
89     style->font=font;
90     font->refcount++;
91     
92     if(style->font->fontstruct!=NULL){
93         XSetFont(ioncore_g.dpy, style->normal_gc, 
94                  style->font->fontstruct->fid);
95     }
96
97     return TRUE;
98 }
99
100
101 bool de_load_font_for_style(DEStyle *style, const char *fontname)
102 {
103     if(style->font!=NULL)
104         de_free_font(style->font);
105     
106     style->font=de_load_font(fontname);
107
108     if(style->font==NULL)
109         return FALSE;
110     
111     if(style->font->fontstruct!=NULL){
112         XSetFont(ioncore_g.dpy, style->normal_gc, 
113                  style->font->fontstruct->fid);
114     }
115     
116     return TRUE;
117 }
118
119
120 void de_free_font(DEFont *font)
121 {
122     if(--font->refcount!=0)
123         return;
124     
125     if(font->fontset!=NULL)
126         XFreeFontSet(ioncore_g.dpy, font->fontset);
127     if(font->fontstruct!=NULL)
128         XFreeFont(ioncore_g.dpy, font->fontstruct);
129     if(font->pattern!=NULL)
130         free(font->pattern);
131     
132     UNLINK_ITEM(fonts, font, next, prev);
133     free(font);
134 }
135
136
137 /*}}}*/
138
139
140 /*{{{ Lengths */
141
142
143 void debrush_get_font_extents(DEBrush *brush, GrFontExtents *fnte)
144 {
145     if(brush->d->font==NULL){
146         DE_RESET_FONT_EXTENTS(fnte);
147         return;
148     }
149     
150     defont_get_font_extents(brush->d->font, fnte);
151 }
152
153
154 void defont_get_font_extents(DEFont *font, GrFontExtents *fnte)
155 {
156     if(font->fontset!=NULL){
157         XFontSetExtents *ext=XExtentsOfFontSet(font->fontset);
158         if(ext==NULL)
159             goto fail;
160         fnte->max_height=ext->max_logical_extent.height;
161         fnte->max_width=ext->max_logical_extent.width;
162         fnte->baseline=-ext->max_logical_extent.y;
163         return;
164     }else if(font->fontstruct!=NULL){
165         XFontStruct *fnt=font->fontstruct;
166         fnte->max_height=fnt->ascent+fnt->descent;
167         fnte->max_width=fnt->max_bounds.width;
168         fnte->baseline=fnt->ascent;
169         return;
170     }
171     
172 fail:
173     DE_RESET_FONT_EXTENTS(fnte);
174 }
175
176
177 uint debrush_get_text_width(DEBrush *brush, const char *text, uint len)
178 {
179     if(brush->d->font==NULL || text==NULL || len==0)
180         return 0;
181     
182     return defont_get_text_width(brush->d->font, text, len);
183 }
184
185
186 uint defont_get_text_width(DEFont *font, const char *text, uint len)
187 {
188     if(font->fontset!=NULL){
189         XRectangle lext;
190 #ifdef CF_DE_USE_XUTF8
191         if(ioncore_g.enc_utf8)
192             Xutf8TextExtents(font->fontset, text, len, NULL, &lext);
193         else
194 #endif
195             XmbTextExtents(font->fontset, text, len, NULL, &lext);
196         return lext.width;
197     }else if(font->fontstruct!=NULL){
198         return XTextWidth(font->fontstruct, text, len);
199     }else{
200         return 0;
201     }
202 }
203
204
205 /*}}}*/
206
207
208 /*{{{ String drawing */
209
210
211 void debrush_do_draw_string_default(DEBrush *brush, int x, int y,
212                                     const char *str, int len, bool needfill, 
213                                     DEColourGroup *colours)
214 {
215     GC gc=brush->d->normal_gc;
216
217     if(brush->d->font==NULL)
218         return;
219     
220     XSetForeground(ioncore_g.dpy, gc, colours->fg);
221     
222     if(!needfill){
223         if(brush->d->font->fontset!=NULL){
224 #ifdef CF_DE_USE_XUTF8
225             if(ioncore_g.enc_utf8)
226                 Xutf8DrawString(ioncore_g.dpy, brush->win, 
227                                 brush->d->font->fontset,
228                                 gc, x, y, str, len);
229             else
230 #endif
231                 XmbDrawString(ioncore_g.dpy, brush->win, 
232                               brush->d->font->fontset,
233                               gc, x, y, str, len);
234         }else if(brush->d->font->fontstruct!=NULL){
235             XDrawString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
236         }
237     }else{
238         XSetBackground(ioncore_g.dpy, gc, colours->bg);
239         if(brush->d->font->fontset!=NULL){
240 #ifdef CF_DE_USE_XUTF8
241             if(ioncore_g.enc_utf8)
242                 Xutf8DrawImageString(ioncore_g.dpy, brush->win, 
243                                      brush->d->font->fontset,
244                                      gc, x, y, str, len);
245             else
246 #endif
247                 XmbDrawImageString(ioncore_g.dpy, brush->win, 
248                                    brush->d->font->fontset,
249                                    gc, x, y, str, len);
250         }else if(brush->d->font->fontstruct!=NULL){
251             XDrawImageString(ioncore_g.dpy, brush->win, gc, x, y, str, len);
252         }
253     }
254 }
255
256
257 void debrush_do_draw_string(DEBrush *brush, int x, int y,
258                             const char *str, int len, bool needfill, 
259                             DEColourGroup *colours)
260 {
261     CALL_DYN(debrush_do_draw_string, brush, (brush, x, y, str, len,
262                                              needfill, colours));
263 }
264
265
266 void debrush_draw_string(DEBrush *brush, int x, int y,
267                          const char *str, int len, bool needfill)
268 {
269     DEColourGroup *cg=debrush_get_current_colour_group(brush);
270     if(cg!=NULL)
271         debrush_do_draw_string(brush, x, y, str, len, needfill, cg);
272 }
273
274
275 /*}}}*/
276