Mac OS X-style window cycling.
[wmaker-crm.git] / WINGs / wfont_wchar.c
blob85c75a123e4cba0f33d0f8c77149026841cd20cc
2 #include "wconfig.h"
4 #ifdef XFT
6 #include <X11/Xft/Xft.h>
7 #include <fontconfig/fontconfig.h>
9 #if defined(HAVE_MBSNRTOWCS)
10 # define __USE_GNU
11 #endif
13 #ifdef HAVE_WCHAR_H
14 # include <wchar.h>
15 #endif
17 #include <stdlib.h>
19 #include "WINGsP.h"
21 #include <wraster.h>
22 #include <assert.h>
23 #include <X11/Xlocale.h>
25 // && defined(HAVE_MBSTATE_T___COUNT)
26 // in configure.ac use AC_CHECK_MEMBER(struct mbstate_t.__count,
27 // have=1, have=0, [#include <wchar.h>])
28 #if defined(HAVE_MBSNRTOWCS)
30 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
32 mbstate_t ps;
33 size_t n;
35 memset(&ps, 0, sizeof(mbstate_t));
36 n = mbsnrtowcs(dest, src, nbytes, len, &ps);
37 if (n != (size_t) - 1 && *src) {
38 *src -= ps.__count;
41 return n;
44 #elif defined(HAVE_MBRTOWC)
46 // This is 8 times slower than the version above.
47 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
49 mbstate_t ps;
50 const char *ptr;
51 size_t n;
52 int nb;
54 if (nbytes == 0)
55 return 0;
57 memset(&ps, 0, sizeof(mbstate_t));
59 if (dest == NULL) {
60 for (ptr = *src, n = 0; nbytes > 0; n++) {
61 nb = mbrtowc(NULL, ptr, nbytes, &ps);
62 if (nb == -1) {
63 return ((size_t) - 1);
64 } else if (nb == 0 || nb == -2) {
65 return n;
67 ptr += nb;
68 nbytes -= nb;
72 for (ptr = *src, n = 0; n < len && nbytes > 0; n++, dest++) {
73 nb = mbrtowc(dest, ptr, nbytes, &ps);
74 if (nb == -2) {
75 *src = ptr;
76 return n;
77 } else if (nb == -1) {
78 *src = ptr;
79 return ((size_t) - 1);
80 } else if (nb == 0) {
81 *src = NULL;
82 return n;
84 ptr += nb;
85 nbytes -= nb;
88 *src = ptr;
89 return n;
92 #else
94 // Not only 8 times slower than the version based on mbsnrtowcs
95 // but also this version is not thread safe nor reentrant
97 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
99 const char *ptr;
100 size_t n;
101 int nb;
103 if (nbytes == 0)
104 return 0;
106 mbtowc(NULL, NULL, 0); /* reset shift state */
108 if (dest == NULL) {
109 for (ptr = *src, n = 0; nbytes > 0; n++) {
110 nb = mbtowc(NULL, ptr, nbytes);
111 if (nb == -1) {
112 mbtowc(NULL, NULL, 0);
113 nb = mbtowc(NULL, ptr, strlen(ptr));
114 return (nb == -1 ? (size_t) - 1 : n);
115 } else if (nb == 0) {
116 return n;
118 ptr += nb;
119 nbytes -= nb;
123 for (ptr = *src, n = 0; n < len && nbytes > 0; n++, dest++) {
124 nb = mbtowc(dest, ptr, nbytes);
125 if (nb == -1) {
126 mbtowc(NULL, NULL, 0);
127 nb = mbtowc(NULL, ptr, strlen(ptr));
128 *src = ptr;
129 return (nb == -1 ? (size_t) - 1 : n);
130 } else if (nb == 0) {
131 *src = NULL;
132 return n;
134 ptr += nb;
135 nbytes -= nb;
138 *src = ptr;
139 return n;
142 #endif
144 #define DEFAULT_SIZE 12
146 static char *fixXLFD(char *xlfd, int size)
148 char *fname, *ptr;
150 fname = wmalloc(strlen(xlfd) + 20);
151 if (strstr(xlfd, "%d") != NULL)
152 sprintf(fname, xlfd, size ? size : DEFAULT_SIZE);
153 else
154 strcpy(fname, xlfd);
156 if ((ptr = strchr(fname, ','))) {
157 *ptr = 0;
160 return fname;
163 static Bool hasProperty(FcPattern * pattern, const char *property)
165 FcValue val;
167 if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) {
168 return True;
171 return False;
174 static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, char *value)
176 FcChar8 *str;
177 int id;
179 if (!value || value[0] == 0)
180 return True;
182 id = 0;
183 while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) {
184 if (strcasecmp(value, (char *)str) == 0) {
185 return True;
187 id++;
190 return False;
193 // also handle an xlfd with %d for size?
194 static char *makeFontOfSize(char *font, int size, char *fallback)
196 FcPattern *pattern;
197 char *result;
199 if (font[0] == '-') {
200 char *fname;
202 fname = fixXLFD(font, size);
203 pattern = XftXlfdParse(fname, False, False);
204 wfree(fname);
205 } else {
206 pattern = FcNameParse(font);
209 //FcPatternPrint(pattern);
210 if (size > 0) {
211 FcPatternDel(pattern, "pixelsize");
212 FcPatternAddDouble(pattern, "pixelsize", (double)size);
213 } else if (size == 0 && !hasProperty(pattern, "size") && !hasProperty(pattern, "pixelsize")) {
214 FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE);
217 if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) {
218 FcPatternAddString(pattern, "family", fallback);
221 result = FcNameUnparse(pattern);
222 FcPatternDestroy(pattern);
224 return result;
227 WMFont *WMCreateFont(WMScreen * scrPtr, char *fontName)
229 WMFont *font;
230 Display *display = scrPtr->display;
231 char *fname, *ptr;
233 /* This is for back-compat (to allow reading of old xlfd descriptions) */
234 if (fontName[0] == '-' && (ptr = strchr(fontName, ','))) {
235 // warn for deprecation
236 fname = wmalloc(ptr - fontName + 1);
237 strncpy(fname, fontName, ptr - fontName);
238 fname[ptr - fontName] = 0;
239 } else {
240 fname = wstrdup(fontName);
243 font = WMHashGet(scrPtr->fontCache, fname);
244 if (font) {
245 WMRetainFont(font);
246 wfree(fname);
247 return font;
250 font = wmalloc(sizeof(WMFont));
251 memset(font, 0, sizeof(WMFont));
253 font->screen = scrPtr;
255 // remove
256 printf("WMCreateFont: %s\n", fname);
258 if (fname[0] == '-') {
259 // Backward compat thing. Remove in a later version
260 font->font = XftFontOpenXlfd(display, scrPtr->screen, fname);
261 } else {
262 font->font = XftFontOpenName(display, scrPtr->screen, fname);
264 if (!font->font) {
265 wfree(font);
266 wfree(fname);
267 return NULL;
269 font->height = font->font->ascent + font->font->descent;
270 font->y = font->font->ascent;
272 font->refCount = 1;
274 font->name = fname;
276 assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
278 return font;
281 WMFont *WMRetainFont(WMFont * font)
283 wassertrv(font != NULL, NULL);
285 font->refCount++;
287 return font;
290 void WMReleaseFont(WMFont * font)
292 wassertr(font != NULL);
294 font->refCount--;
295 if (font->refCount < 1) {
296 XftFontClose(font->screen->display, font->font);
297 if (font->name) {
298 WMHashRemove(font->screen->fontCache, font->name);
299 wfree(font->name);
301 wfree(font);
305 Bool WMIsAntialiasingEnabled(WMScreen * scrPtr)
307 return scrPtr->antialiasedText;
310 unsigned int WMFontHeight(WMFont * font)
312 wassertrv(font != NULL, 0);
314 return font->height;
317 char *WMGetFontName(WMFont * font)
319 wassertrv(font != NULL, NULL);
321 return font->name;
324 WMFont *WMDefaultSystemFont(WMScreen * scrPtr)
326 return WMRetainFont(scrPtr->normalFont);
329 WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr)
331 return WMRetainFont(scrPtr->boldFont);
334 WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
336 WMFont *font;
337 char *fontSpec;
339 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans");
341 font = WMCreateFont(scrPtr, fontSpec);
343 if (!font) {
344 wwarning(_("could not load font %s."), fontSpec);
347 wfree(fontSpec);
349 return font;
352 WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
354 WMFont *font;
355 char *fontSpec;
357 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans");
359 font = WMCreateFont(scrPtr, fontSpec);
361 if (!font) {
362 wwarning(_("could not load font %s."), fontSpec);
365 wfree(fontSpec);
367 return font;
370 int WMWidthOfString(WMFont * font, char *text, int length)
372 XGlyphInfo extents;
374 wassertrv(font != NULL, 0);
375 wassertrv(text != NULL, 0);
377 if (font->screen->useWideChar) {
378 wchar_t *wtext;
379 const char *mtext;
380 int len;
382 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
383 mtext = text;
384 len = wmbsnrtowcs(wtext, &mtext, length, length);
385 if (len > 0) {
386 wtext[len] = L'\0'; /* not really necessary here */
387 XftTextExtents32(font->screen->display, font->font, (XftChar32 *) wtext, len, &extents);
388 } else {
389 if (len == -1) {
390 wwarning(_("Conversion to widechar failed (possible "
391 "invalid multibyte sequence): '%s':(pos %d)\n"),
392 text, mtext - text + 1);
394 extents.xOff = 0;
396 wfree(wtext);
397 } else if (font->screen->useMultiByte) {
398 XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
399 } else {
400 XftTextExtents8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
403 return extents.xOff; /* don't ask :P */
406 void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, char *text, int length)
408 XftColor xftcolor;
410 wassertr(font != NULL);
412 xftcolor.color.red = color->color.red;
413 xftcolor.color.green = color->color.green;
414 xftcolor.color.blue = color->color.blue;
415 xftcolor.color.alpha = color->alpha;;
416 xftcolor.pixel = W_PIXEL(color);
418 XftDrawChange(scr->xftdraw, d);
420 if (font->screen->useWideChar) {
421 wchar_t *wtext;
422 const char *mtext;
423 int len;
425 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
426 mtext = text;
427 len = wmbsnrtowcs(wtext, &mtext, length, length);
428 if (len > 0) {
429 XftDrawString32(scr->xftdraw, &xftcolor, font->font,
430 x, y + font->y, (XftChar32 *) wtext, len);
431 } else if (len == -1) {
432 wwarning(_("Conversion to widechar failed (possible invalid "
433 "multibyte sequence): '%s':(pos %d)\n"), text, mtext - text + 1);
434 /* we can draw normal text, or we can draw as much widechar
435 * text as was already converted until the error. go figure */
436 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font,
437 x, y + font->y, (XftChar8*)text, length); */
439 wfree(wtext);
440 } else if (font->screen->useMultiByte) {
441 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
442 } else {
443 XftDrawString8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
447 void
448 WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background,
449 WMFont * font, int x, int y, char *text, int length)
451 XftColor textColor;
452 XftColor bgColor;
454 wassertr(font != NULL);
456 textColor.color.red = color->color.red;
457 textColor.color.green = color->color.green;
458 textColor.color.blue = color->color.blue;
459 textColor.color.alpha = color->alpha;;
460 textColor.pixel = W_PIXEL(color);
462 bgColor.color.red = background->color.red;
463 bgColor.color.green = background->color.green;
464 bgColor.color.blue = background->color.blue;
465 bgColor.color.alpha = background->alpha;;
466 bgColor.pixel = W_PIXEL(background);
468 XftDrawChange(scr->xftdraw, d);
470 XftDrawRect(scr->xftdraw, &bgColor, x, y, WMWidthOfString(font, text, length), font->height);
472 if (font->screen->useWideChar) {
473 wchar_t *wtext;
474 const char *mtext;
475 int len;
477 mtext = text;
478 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
479 len = wmbsnrtowcs(wtext, &mtext, length, length);
480 if (len > 0) {
481 XftDrawString32(scr->xftdraw, &textColor, font->font,
482 x, y + font->y, (XftChar32 *) wtext, len);
483 } else if (len == -1) {
484 wwarning(_("Conversion to widechar failed (possible invalid "
485 "multibyte sequence): '%s':(pos %d)\n"), text, mtext - text + 1);
486 /* we can draw normal text, or we can draw as much widechar
487 * text as was already converted until the error. go figure */
488 /*XftDrawString8(scr->xftdraw, &textColor, font->font,
489 x, y + font->y, (XftChar8*)text, length); */
491 wfree(wtext);
492 } else if (font->screen->useMultiByte) {
493 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
494 } else {
495 XftDrawString8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
499 WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
501 FcPattern *pattern;
502 WMFont *copy;
503 char *name;
505 if (!font)
506 return NULL;
508 pattern = FcNameParse(WMGetFontName(font));
509 switch (style) {
510 case WFSNormal:
511 FcPatternDel(pattern, "weight");
512 FcPatternDel(pattern, "slant");
513 FcPatternAddString(pattern, "weight", "regular");
514 FcPatternAddString(pattern, "weight", "medium");
515 FcPatternAddString(pattern, "slant", "roman");
516 break;
517 case WFSBold:
518 FcPatternDel(pattern, "weight");
519 FcPatternAddString(pattern, "weight", "bold");
520 break;
521 case WFSEmphasized:
522 FcPatternDel(pattern, "slant");
523 FcPatternAddString(pattern, "slant", "italic");
524 FcPatternAddString(pattern, "slant", "oblique");
525 break;
526 case WFSBoldEmphasized:
527 FcPatternDel(pattern, "weight");
528 FcPatternDel(pattern, "slant");
529 FcPatternAddString(pattern, "weight", "bold");
530 FcPatternAddString(pattern, "slant", "italic");
531 FcPatternAddString(pattern, "slant", "oblique");
532 break;
535 name = FcNameUnparse(pattern);
536 copy = WMCreateFont(scrPtr, name);
537 FcPatternDestroy(pattern);
538 wfree(name);
540 return copy;
543 #endif /* XFT */