JWM Source Documentation
font.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "font.h"
12 #include "main.h"
13 #include "error.h"
14 #include "misc.h"
15 
16 #ifdef USE_ICONV
17 # ifdef HAVE_LANGINFO_H
18 # include <langinfo.h>
19 # endif
20 # ifdef HAVE_ICONV_H
21 # include <iconv.h>
22 # endif
23 #endif
24 
25 #ifdef USE_XFT
26 static const char *DEFAULT_FONT = "FreeSans-9";
27 #else
28 static const char *DEFAULT_FONT = "fixed";
29 #endif
30 
31 static const struct {
32  const FontType src;
33  const FontType dest;
34 } INHERITED_FONTS[] = {
35  { FONT_TRAY, FONT_PAGER },
36  { FONT_TRAY, FONT_CLOCK },
39 };
40 
41 static char *GetUTF8String(const char *str);
42 static void ReleaseUTF8String(char *utf8String);
43 
44 static char *fontNames[FONT_COUNT];
45 
46 #ifdef USE_ICONV
47 static const char *UTF8_CODESET = "UTF-8";
48 static iconv_t fromUTF8 = (iconv_t)-1;
49 static iconv_t toUTF8 = (iconv_t)-1;
50 #endif
51 
52 #ifdef USE_XFT
53 static XftFont *fonts[FONT_COUNT];
54 #else
55 static XFontStruct *fonts[FONT_COUNT];
56 #endif
57 
59 void InitializeFonts(void)
60 {
61 #ifdef USE_ICONV
62  const char *codeset;
63 #endif
64  unsigned int x;
65 
66  for(x = 0; x < FONT_COUNT; x++) {
67  fonts[x] = NULL;
68  fontNames[x] = NULL;
69  }
70 
71  /* Allocate a conversion descriptor if we're not using UTF-8. */
72 #ifdef USE_ICONV
73  codeset = nl_langinfo(CODESET);
74  if(strcmp(codeset, UTF8_CODESET)) {
75  toUTF8 = iconv_open(UTF8_CODESET, codeset);
76  fromUTF8 = iconv_open(codeset, UTF8_CODESET);
77  } else {
78  toUTF8 = (iconv_t)-1;
79  fromUTF8 = (iconv_t)-1;
80  }
81 #endif
82 
83 }
84 
86 void StartupFonts(void)
87 {
88 
89  unsigned int x;
90 
91  /* Inherit unset fonts from the tray for tray items. */
92  for(x = 0; x < ARRAY_LENGTH(INHERITED_FONTS); x++) {
93  const FontType dest = INHERITED_FONTS[x].dest;
94  if(!fontNames[dest]) {
95  const FontType src = INHERITED_FONTS[x].src;
97  }
98  }
99 
100 #ifdef USE_XFT
101 
102  for(x = 0; x < FONT_COUNT; x++) {
103  if(fontNames[x]) {
105  if(!fonts[x]) {
107  }
108  if(JUNLIKELY(!fonts[x])) {
109  Warning(_("could not load font: %s"), fontNames[x]);
110  }
111  }
112  if(!fonts[x]) {
114  }
115  if(JUNLIKELY(!fonts[x])) {
116  FatalError(_("could not load the default font: %s"), DEFAULT_FONT);
117  }
118  }
119 
120 #else /* USE_XFT */
121 
122  for(x = 0; x < FONT_COUNT; x++) {
123  if(fontNames[x]) {
125  if(JUNLIKELY(!fonts[x] && fontNames[x])) {
126  Warning(_("could not load font: %s"), fontNames[x]);
127  }
128  }
129  if(!fonts[x]) {
131  }
132  if(JUNLIKELY(!fonts[x])) {
133  FatalError(_("could not load the default font: %s"), DEFAULT_FONT);
134  }
135  }
136 
137 #endif /* USE_XFT */
138 
139 }
140 
142 void ShutdownFonts(void)
143 {
144  unsigned int x;
145  for(x = 0; x < FONT_COUNT; x++) {
146  if(fonts[x]) {
147 #ifdef USE_XFT
149 #else
150  JXFreeFont(display, fonts[x]);
151 #endif
152  fonts[x] = NULL;
153  }
154  }
155 }
156 
158 void DestroyFonts(void)
159 {
160  unsigned int x;
161  for(x = 0; x < FONT_COUNT; x++) {
162  if(fontNames[x]) {
163  Release(fontNames[x]);
164  fontNames[x] = NULL;
165  }
166  }
167 #ifdef USE_ICONV
168  if(fromUTF8 != (iconv_t)-1) {
169  iconv_close(fromUTF8);
170  fromUTF8 = (iconv_t)-1;
171  }
172  if(toUTF8 != (iconv_t)-1) {
173  iconv_close(toUTF8);
174  toUTF8 = (iconv_t)-1;
175  }
176 #endif
177 }
178 
180 char *ConvertFromUTF8(char *str)
181 {
182  char *result = (char*)str;
183 #ifdef USE_ICONV
184  if(fromUTF8 != (iconv_t)-1) {
185  ICONV_CONST char *inBuf = (ICONV_CONST char*)str;
186  char *outBuf;
187  size_t inLeft = strlen(str);
188  size_t outLeft = 4 * inLeft;
189  size_t rc;
190  result = Allocate(outLeft + 1);
191  outBuf = result;
192  rc = iconv(fromUTF8, &inBuf, &inLeft, &outBuf, &outLeft);
193  if(rc == (size_t)-1) {
194  Warning("iconv conversion from UTF-8 failed");
195  iconv_close(fromUTF8);
196  fromUTF8 = (iconv_t)-1;
197  Release(result);
198  result = (char*)str;
199  } else {
200  Release(str);
201  *outBuf = 0;
202  }
203  }
204 #endif
205  return result;
206 }
207 
209 char *GetUTF8String(const char *str)
210 {
211  char *utf8String = (char*)str;
212 #ifdef USE_ICONV
213  if(toUTF8 != (iconv_t)-1) {
214  ICONV_CONST char *inBuf = (ICONV_CONST char*)str;
215  char *outBuf;
216  size_t inLeft = strlen(str);
217  size_t outLeft = 4 * inLeft;
218  size_t rc;
219  utf8String = Allocate(outLeft + 1);
220  outBuf = utf8String;
221  rc = iconv(toUTF8, &inBuf, &inLeft, &outBuf, &outLeft);
222  if(rc == (size_t)-1) {
223  Warning("iconv conversion to UTF-8 failed");
224  iconv_close(toUTF8);
225  toUTF8 = (iconv_t)-1;
226  Release(utf8String);
227  utf8String = (char*)str;
228  } else {
229  *outBuf = 0;
230  }
231  }
232 #endif
233  return utf8String;
234 }
235 
237 void ReleaseUTF8String(char *utf8String)
238 {
239 #ifdef USE_ICONV
240  if(toUTF8 != (iconv_t)-1) {
241  Release(utf8String);
242  }
243 #endif
244 }
245 
247 int GetStringWidth(FontType ft, const char *str)
248 {
249 #ifdef USE_XFT
250  XGlyphInfo extents;
251 #endif
252 #ifdef USE_FRIBIDI
253  FriBidiChar *temp_i;
254  FriBidiChar *temp_o;
255  FriBidiParType type = FRIBIDI_PAR_ON;
256  int unicodeLength;
257 #endif
258  int len;
259  char *output;
260  int result;
261  char *utf8String;
262 
263  /* Convert to UTF-8 if necessary. */
264  utf8String = GetUTF8String(str);
265 
266  /* Length of the UTF-8 string. */
267  len = strlen(utf8String);
268 
269  /* Apply the bidi algorithm if requested. */
270 #ifdef USE_FRIBIDI
271  temp_i = AllocateStack((len + 1) * sizeof(FriBidiChar));
272  temp_o = AllocateStack((len + 1) * sizeof(FriBidiChar));
273  unicodeLength = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
274  utf8String, len, temp_i);
275  fribidi_log2vis(temp_i, unicodeLength, &type, temp_o, NULL, NULL, NULL);
276  output = AllocateStack(4 * len + 1);
277  fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, temp_o, unicodeLength,
278  (char*)output);
279  len = strlen(output);
280 #else
281  output = utf8String;
282 #endif
283 
284  /* Get the width of the string. */
285 #ifdef USE_XFT
286  JXftTextExtentsUtf8(display, fonts[ft], (const unsigned char*)output,
287  len, &extents);
288  result = extents.xOff;
289 #else
290  result = XTextWidth(fonts[ft], output, len);
291 #endif
292 
293  /* Clean up. */
294 #ifdef USE_FRIBIDI
295  ReleaseStack(temp_i);
296  ReleaseStack(temp_o);
297  ReleaseStack(output);
298 #endif
299  ReleaseUTF8String(utf8String);
300 
301  return result;
302 }
303 
306 {
307  Assert(fonts[ft]);
308  return fonts[ft]->ascent + fonts[ft]->descent;
309 }
310 
312 void SetFont(FontType type, const char *value)
313 {
314  if(JUNLIKELY(!value)) {
315  Warning(_("empty Font tag"));
316  return;
317  }
318  if(fontNames[type]) {
319  Release(fontNames[type]);
320  }
321  fontNames[type] = CopyString(value);
322 }
323 
325 void RenderString(Drawable d, FontType font, ColorType color,
326  int x, int y, int width, const char *str)
327 {
328  XRectangle rect;
329  Region renderRegion;
330  int len;
331  char *output;
332 #ifdef USE_FRIBIDI
333  FriBidiChar *temp_i;
334  FriBidiChar *temp_o;
335  FriBidiParType type = FRIBIDI_PAR_ON;
336  int unicodeLength;
337 #endif
338 #ifdef USE_XFT
339  XftDraw *xd;
340  XGlyphInfo extents;
341 #else
342  XGCValues gcValues;
343  unsigned long gcMask;
344  GC gc;
345 #endif
346  char *utf8String;
347 
348  /* Early return for empty strings. */
349  if(!str || !str[0]) {
350  return;
351  }
352 
353  /* Convert to UTF-8 if necessary. */
354  utf8String = GetUTF8String(str);
355 
356  /* Get the length of the UTF-8 string. */
357  len = strlen(utf8String);
358 
359 #ifdef USE_XFT
360  xd = XftDrawCreate(display, d, rootVisual, rootColormap);
361 #else
362  gcMask = GCGraphicsExposures;
363  gcValues.graphics_exposures = False;
364  gc = JXCreateGC(display, d, gcMask, &gcValues);
365 #endif
366 
367 
368  /* Apply the bidi algorithm if requested. */
369 #ifdef USE_FRIBIDI
370  temp_i = AllocateStack((len + 1) * sizeof(FriBidiChar));
371  temp_o = AllocateStack((len + 1) * sizeof(FriBidiChar));
372  unicodeLength = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
373  utf8String, len, temp_i);
374  fribidi_log2vis(temp_i, unicodeLength, &type, temp_o, NULL, NULL, NULL);
375  output = AllocateStack(4 * len + 1);
376  fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, temp_o, unicodeLength,
377  (char*)output);
378  len = strlen(output);
379 #else
380  output = utf8String;
381 #endif
382 
383  /* Get the bounds for the string based on the specified width. */
384  rect.x = x;
385  rect.y = y;
386  rect.height = GetStringHeight(font);
387 #ifdef USE_XFT
388  JXftTextExtentsUtf8(display, fonts[font], (const unsigned char*)output,
389  len, &extents);
390  rect.width = extents.xOff;
391 #else
392  rect.width = XTextWidth(fonts[font], output, len);
393 #endif
394  rect.width = Min(rect.width, width) + 2;
395 
396  /* Combine the width bounds with the region to use. */
397  renderRegion = XCreateRegion();
398  XUnionRectWithRegion(&rect, renderRegion, renderRegion);
399 
400  /* Display the string. */
401 #ifdef USE_XFT
402  JXftDrawSetClip(xd, renderRegion);
403  JXftDrawStringUtf8(xd, GetXftColor(color), fonts[font],
404  x, y + fonts[font]->ascent,
405  (const unsigned char*)output, len);
407 #else
408  JXSetForeground(display, gc, colors[color]);
409  JXSetRegion(display, gc, renderRegion);
410  JXSetFont(display, gc, fonts[font]->fid);
411  JXDrawString(display, d, gc, x, y + fonts[font]->ascent, output, len);
412 #endif
413 
414  /* Free any memory used for UTF conversion. */
415 #ifdef USE_FRIBIDI
416  ReleaseStack(temp_i);
417  ReleaseStack(temp_o);
418  ReleaseStack(output);
419 #endif
420  ReleaseUTF8String(utf8String);
421 
422  XDestroyRegion(renderRegion);
423 
424 #ifdef USE_XFT
425  XftDrawDestroy(xd);
426 #else
427  JXFreeGC(display, gc);
428 #endif
429 
430 }

joewing.net / Projects / JWM