Fix periodic focus bug
[wmaker-crm.git] / WINGs / wfont_wchar.c
blobcfc6f03ce83ca53c712bdd371bef1f9a13e1e3f6
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>
26 // && defined(HAVE_MBSTATE_T___COUNT)
27 // in configure.ac use AC_CHECK_MEMBER(struct mbstate_t.__count,
28 // have=1, have=0, [#include <wchar.h>])
29 #if defined(HAVE_MBSNRTOWCS)
31 static size_t
32 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
34 mbstate_t ps;
35 size_t n;
37 memset(&ps, 0, sizeof(mbstate_t));
38 n = mbsnrtowcs(dest, src, nbytes, len, &ps);
39 if (n!=(size_t)-1 && *src) {
40 *src -= ps.__count;
43 return n;
46 #elif defined(HAVE_MBRTOWC)
48 // This is 8 times slower than the version above.
49 static size_t
50 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
52 mbstate_t ps;
53 const char *ptr;
54 size_t n;
55 int nb;
57 if (nbytes==0)
58 return 0;
60 memset(&ps, 0, sizeof(mbstate_t));
62 if (dest == NULL) {
63 for (ptr=*src, n=0; nbytes>0; n++) {
64 nb = mbrtowc(NULL, ptr, nbytes, &ps);
65 if (nb == -1) {
66 return ((size_t)-1);
67 } else if (nb==0 || nb==-2) {
68 return n;
70 ptr += nb;
71 nbytes -= nb;
75 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
76 nb = mbrtowc(dest, ptr, nbytes, &ps);
77 if (nb == -2) {
78 *src = ptr;
79 return n;
80 } else if (nb == -1) {
81 *src = ptr;
82 return ((size_t)-1);
83 } else if (nb == 0) {
84 *src = NULL;
85 return n;
87 ptr += nb;
88 nbytes -= nb;
91 *src = ptr;
92 return n;
95 #else
97 // Not only 8 times slower than the version based on mbsnrtowcs
98 // but also this version is not thread safe nor reentrant
100 static size_t
101 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
103 const char *ptr;
104 size_t n;
105 int nb;
107 if (nbytes==0)
108 return 0;
110 mbtowc(NULL, NULL, 0); /* reset shift state */
112 if (dest == NULL) {
113 for (ptr=*src, n=0; nbytes>0; n++) {
114 nb = mbtowc(NULL, ptr, nbytes);
115 if (nb == -1) {
116 mbtowc(NULL, NULL, 0);
117 nb = mbtowc(NULL, ptr, strlen(ptr));
118 return (nb == -1 ? (size_t)-1 : n);
119 } else if (nb==0) {
120 return n;
122 ptr += nb;
123 nbytes -= nb;
127 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
128 nb = mbtowc(dest, ptr, nbytes);
129 if (nb == -1) {
130 mbtowc(NULL, NULL, 0);
131 nb = mbtowc(NULL, ptr, strlen(ptr));
132 *src = ptr;
133 return (nb == -1 ? (size_t)-1 : n);
134 } else if (nb == 0) {
135 *src = NULL;
136 return n;
138 ptr += nb;
139 nbytes -= nb;
142 *src = ptr;
143 return n;
146 #endif
149 #define DEFAULT_SIZE 12
151 static char*
152 fixXLFD(char *xlfd, int size)
154 char *fname, *ptr;
156 fname = wmalloc(strlen(xlfd) + 20);
157 if (strstr(xlfd, "%d")!=NULL)
158 sprintf(fname, xlfd, size ? size : DEFAULT_SIZE);
159 else
160 strcpy(fname, xlfd);
162 if ((ptr = strchr(fname, ','))) {
163 *ptr = 0;
166 return fname;
170 static Bool
171 hasProperty(FcPattern *pattern, const char *property)
173 FcValue val;
175 if (FcPatternGet(pattern, property, 0, &val)==FcResultMatch) {
176 return True;
179 return False;
183 static Bool
184 hasPropertyWithStringValue(FcPattern *pattern, const char *object, char *value)
186 FcChar8 *str;
187 int id;
189 if (!value || value[0]==0)
190 return True;
192 id = 0;
193 while (FcPatternGetString(pattern, object, id, &str)==FcResultMatch) {
194 if (strcasecmp(value, (char*)str) == 0) {
195 return True;
197 id++;
200 return False;
204 // also handle an xlfd with %d for size?
205 static char*
206 makeFontOfSize(char *font, int size, char *fallback)
208 FcPattern *pattern;
209 char *result;
211 if (font[0]=='-') {
212 char *fname;
214 fname = fixXLFD(font, size);
215 pattern = XftXlfdParse(fname, False, False);
216 wfree(fname);
217 } else {
218 pattern = FcNameParse(font);
221 //FcPatternPrint(pattern);
222 if (size > 0) {
223 FcPatternDel(pattern, "pixelsize");
224 FcPatternAddDouble(pattern, "pixelsize", (double)size);
225 } else if (size==0 && !hasProperty(pattern, "size") &&
226 !hasProperty(pattern, "pixelsize")) {
227 FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE);
230 if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) {
231 FcPatternAddString(pattern, "family", fallback);
234 result = FcNameUnparse(pattern);
235 FcPatternDestroy(pattern);
237 return result;
241 WMFont*
242 WMCreateFont(WMScreen *scrPtr, char *fontName)
244 WMFont *font;
245 Display *display = scrPtr->display;
246 char *fname, *ptr;
248 /* This is for back-compat (to allow reading of old xlfd descriptions) */
249 if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) {
250 // warn for deprecation
251 fname = wmalloc(ptr - fontName + 1);
252 strncpy(fname, fontName, ptr - fontName);
253 fname[ptr - fontName] = 0;
254 } else {
255 fname = wstrdup(fontName);
258 font = WMHashGet(scrPtr->fontCache, fname);
259 if (font) {
260 WMRetainFont(font);
261 wfree(fname);
262 return font;
265 font = wmalloc(sizeof(WMFont));
266 memset(font, 0, sizeof(WMFont));
268 font->screen = scrPtr;
270 // remove
271 printf("WMCreateFont: %s\n", fname);
273 if (fname[0] == '-') {
274 // Backward compat thing. Remove in a later version
275 font->font = XftFontOpenXlfd(display, scrPtr->screen, fname);
276 } else {
277 font->font = XftFontOpenName(display, scrPtr->screen, fname);
279 if (!font->font) {
280 wfree(font);
281 wfree(fname);
282 return NULL;
284 font->height = font->font->ascent+font->font->descent;
285 font->y = font->font->ascent;
287 font->refCount = 1;
289 font->name = fname;
291 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
293 return font;
297 WMFont*
298 WMRetainFont(WMFont *font)
300 wassertrv(font!=NULL, NULL);
302 font->refCount++;
304 return font;
308 void
309 WMReleaseFont(WMFont *font)
311 wassertr(font!=NULL);
313 font->refCount--;
314 if (font->refCount < 1) {
315 XftFontClose(font->screen->display, font->font);
316 if (font->name) {
317 WMHashRemove(font->screen->fontCache, font->name);
318 wfree(font->name);
320 wfree(font);
325 Bool
326 WMIsAntialiasingEnabled(WMScreen *scrPtr)
328 return scrPtr->antialiasedText;
332 unsigned int
333 WMFontHeight(WMFont *font)
335 wassertrv(font!=NULL, 0);
337 return font->height;
341 char*
342 WMGetFontName(WMFont *font)
344 wassertrv(font!=NULL, NULL);
346 return font->name;
350 WMFont*
351 WMDefaultSystemFont(WMScreen *scrPtr)
353 return WMRetainFont(scrPtr->normalFont);
357 WMFont*
358 WMDefaultBoldSystemFont(WMScreen *scrPtr)
360 return WMRetainFont(scrPtr->boldFont);
364 WMFont*
365 WMSystemFontOfSize(WMScreen *scrPtr, int size)
367 WMFont *font;
368 char *fontSpec;
370 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans");
372 font = WMCreateFont(scrPtr, fontSpec);
374 if (!font) {
375 wwarning(_("could not load font %s."), fontSpec);
378 wfree(fontSpec);
380 return font;
384 WMFont*
385 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
387 WMFont *font;
388 char *fontSpec;
390 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans");
392 font = WMCreateFont(scrPtr, fontSpec);
394 if (!font) {
395 wwarning(_("could not load font %s."), fontSpec);
398 wfree(fontSpec);
400 return font;
405 WMWidthOfString(WMFont *font, char *text, int length)
407 XGlyphInfo extents;
409 wassertrv(font!=NULL, 0);
410 wassertrv(text!=NULL, 0);
412 if (font->screen->useWideChar) {
413 wchar_t *wtext;
414 const char *mtext;
415 int len;
417 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
418 mtext = text;
419 len = wmbsnrtowcs(wtext, &mtext, length, length);
420 if (len>0) {
421 wtext[len] = L'\0'; /* not really necessary here */
422 XftTextExtents32(font->screen->display, font->font,
423 (XftChar32 *)wtext, len, &extents);
424 } else {
425 if (len==-1) {
426 wwarning(_("Conversion to widechar failed (possible "
427 "invalid multibyte sequence): '%s':(pos %d)\n"),
428 text, mtext-text+1);
430 extents.xOff = 0;
432 wfree(wtext);
433 } else if (font->screen->useMultiByte) {
434 XftTextExtentsUtf8(font->screen->display, font->font,
435 (XftChar8 *)text, length, &extents);
436 } else {
437 XftTextExtents8(font->screen->display, font->font,
438 (XftChar8 *)text, length, &extents);
441 return extents.xOff; /* don't ask :P */
446 void
447 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
448 int x, int y, char *text, int length)
450 XftColor xftcolor;
452 wassertr(font!=NULL);
454 xftcolor.color.red = color->color.red;
455 xftcolor.color.green = color->color.green;
456 xftcolor.color.blue = color->color.blue;
457 xftcolor.color.alpha = color->alpha;;
458 xftcolor.pixel = W_PIXEL(color);
460 XftDrawChange(scr->xftdraw, d);
462 if (font->screen->useWideChar) {
463 wchar_t *wtext;
464 const char *mtext;
465 int len;
467 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
468 mtext = text;
469 len = wmbsnrtowcs(wtext, &mtext, length, length);
470 if (len>0) {
471 XftDrawString32(scr->xftdraw, &xftcolor, font->font,
472 x, y + font->y, (XftChar32*)wtext, len);
473 } else if (len==-1) {
474 wwarning(_("Conversion to widechar failed (possible invalid "
475 "multibyte sequence): '%s':(pos %d)\n"),
476 text, mtext-text+1);
477 /* we can draw normal text, or we can draw as much widechar
478 * text as was already converted until the error. go figure */
479 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font,
480 x, y + font->y, (XftChar8*)text, length);*/
482 wfree(wtext);
483 } else if (font->screen->useMultiByte) {
484 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font,
485 x, y + font->y, (XftChar8*)text, length);
486 } else {
487 XftDrawString8(scr->xftdraw, &xftcolor, font->font,
488 x, y + font->y, (XftChar8*)text, length);
493 void
494 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
495 WMFont *font, int x, int y, char *text, int length)
497 XftColor textColor;
498 XftColor bgColor;
500 wassertr(font!=NULL);
502 textColor.color.red = color->color.red;
503 textColor.color.green = color->color.green;
504 textColor.color.blue = color->color.blue;
505 textColor.color.alpha = color->alpha;;
506 textColor.pixel = W_PIXEL(color);
508 bgColor.color.red = background->color.red;
509 bgColor.color.green = background->color.green;
510 bgColor.color.blue = background->color.blue;
511 bgColor.color.alpha = background->alpha;;
512 bgColor.pixel = W_PIXEL(background);
514 XftDrawChange(scr->xftdraw, d);
516 XftDrawRect(scr->xftdraw, &bgColor, x, y,
517 WMWidthOfString(font, text, length),
518 font->height);
520 if (font->screen->useWideChar) {
521 wchar_t *wtext;
522 const char *mtext;
523 int len;
525 mtext = text;
526 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
527 len = wmbsnrtowcs(wtext, &mtext, length, length);
528 if (len>0) {
529 XftDrawString32(scr->xftdraw, &textColor, font->font,
530 x, y + font->y, (XftChar32*)wtext, len);
531 } else if (len==-1) {
532 wwarning(_("Conversion to widechar failed (possible invalid "
533 "multibyte sequence): '%s':(pos %d)\n"),
534 text, mtext-text+1);
535 /* we can draw normal text, or we can draw as much widechar
536 * text as was already converted until the error. go figure */
537 /*XftDrawString8(scr->xftdraw, &textColor, font->font,
538 x, y + font->y, (XftChar8*)text, length);*/
540 wfree(wtext);
541 } else if (font->screen->useMultiByte) {
542 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font,
543 x, y + font->y, (XftChar8*)text, length);
544 } else {
545 XftDrawString8(scr->xftdraw, &textColor, font->font,
546 x, y + font->y, (XftChar8*)text, length);
551 WMFont*
552 WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style)
554 FcPattern *pattern;
555 WMFont *copy;
556 char *name;
558 if (!font)
559 return NULL;
561 pattern = FcNameParse(WMGetFontName(font));
562 switch (style) {
563 case WFSNormal:
564 FcPatternDel(pattern, "weight");
565 FcPatternDel(pattern, "slant");
566 FcPatternAddString(pattern, "weight", "regular");
567 FcPatternAddString(pattern, "weight", "medium");
568 FcPatternAddString(pattern, "slant", "roman");
569 break;
570 case WFSBold:
571 FcPatternDel(pattern, "weight");
572 FcPatternAddString(pattern, "weight", "bold");
573 break;
574 case WFSEmphasized:
575 FcPatternDel(pattern, "slant");
576 FcPatternAddString(pattern, "slant", "italic");
577 FcPatternAddString(pattern, "slant", "oblique");
578 break;
579 case WFSBoldEmphasized:
580 FcPatternDel(pattern, "weight");
581 FcPatternDel(pattern, "slant");
582 FcPatternAddString(pattern, "weight", "bold");
583 FcPatternAddString(pattern, "slant", "italic");
584 FcPatternAddString(pattern, "slant", "oblique");
585 break;
588 name = FcNameUnparse(pattern);
589 copy = WMCreateFont(scrPtr, name);
590 FcPatternDestroy(pattern);
591 wfree(name);
593 return copy;
597 #endif /* XFT */