6 #include <X11/Xft/Xft.h>
7 #include <fontconfig/fontconfig.h>
9 #if defined(HAVE_MBSNRTOWCS)
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)
32 wmbsnrtowcs(wchar_t *dest
, const char **src
, size_t nbytes
, size_t len
)
37 memset(&ps
, 0, sizeof(mbstate_t));
38 n
= mbsnrtowcs(dest
, src
, nbytes
, len
, &ps
);
39 if (n
!=(size_t)-1 && *src
) {
46 #elif defined(HAVE_MBRTOWC)
48 // This is 8 times slower than the version above.
50 wmbsnrtowcs(wchar_t *dest
, const char **src
, size_t nbytes
, size_t len
)
60 memset(&ps
, 0, sizeof(mbstate_t));
63 for (ptr
=*src
, n
=0; nbytes
>0; n
++) {
64 nb
= mbrtowc(NULL
, ptr
, nbytes
, &ps
);
67 } else if (nb
==0 || nb
==-2) {
75 for (ptr
=*src
, n
=0; n
<len
&& nbytes
>0; n
++, dest
++) {
76 nb
= mbrtowc(dest
, ptr
, nbytes
, &ps
);
80 } else if (nb
== -1) {
97 // Not only 8 times slower than the version based on mbsnrtowcs
98 // but also this version is not thread safe nor reentrant
101 wmbsnrtowcs(wchar_t *dest
, const char **src
, size_t nbytes
, size_t len
)
110 mbtowc(NULL
, NULL
, 0); /* reset shift state */
113 for (ptr
=*src
, n
=0; nbytes
>0; n
++) {
114 nb
= mbtowc(NULL
, ptr
, nbytes
);
116 mbtowc(NULL
, NULL
, 0);
117 nb
= mbtowc(NULL
, ptr
, strlen(ptr
));
118 return (nb
== -1 ? (size_t)-1 : n
);
127 for (ptr
=*src
, n
=0; n
<len
&& nbytes
>0; n
++, dest
++) {
128 nb
= mbtowc(dest
, ptr
, nbytes
);
130 mbtowc(NULL
, NULL
, 0);
131 nb
= mbtowc(NULL
, ptr
, strlen(ptr
));
133 return (nb
== -1 ? (size_t)-1 : n
);
134 } else if (nb
== 0) {
149 #define DEFAULT_SIZE 12
152 fixXLFD(char *xlfd
, int size
)
156 fname
= wmalloc(strlen(xlfd
) + 20);
157 if (strstr(xlfd
, "%d")!=NULL
)
158 sprintf(fname
, xlfd
, size
? size
: DEFAULT_SIZE
);
162 if ((ptr
= strchr(fname
, ','))) {
171 hasProperty(FcPattern
*pattern
, const char *property
)
175 if (FcPatternGet(pattern
, property
, 0, &val
)==FcResultMatch
) {
184 hasPropertyWithStringValue(FcPattern
*pattern
, const char *object
, char *value
)
189 if (!value
|| value
[0]==0)
193 while (FcPatternGetString(pattern
, object
, id
, &str
)==FcResultMatch
) {
194 if (strcasecmp(value
, (char*)str
) == 0) {
204 // also handle an xlfd with %d for size?
206 makeFontOfSize(char *font
, int size
, char *fallback
)
214 fname
= fixXLFD(font
, size
);
215 pattern
= XftXlfdParse(fname
, False
, False
);
218 pattern
= FcNameParse(font
);
221 //FcPatternPrint(pattern);
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
);
242 WMCreateFont(WMScreen
*scrPtr
, char *fontName
)
245 Display
*display
= scrPtr
->display
;
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;
255 fname
= wstrdup(fontName
);
258 font
= WMHashGet(scrPtr
->fontCache
, fname
);
265 font
= wmalloc(sizeof(WMFont
));
266 memset(font
, 0, sizeof(WMFont
));
268 font
->screen
= scrPtr
;
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
);
277 font
->font
= XftFontOpenName(display
, scrPtr
->screen
, fname
);
284 font
->height
= font
->font
->ascent
+font
->font
->descent
;
285 font
->y
= font
->font
->ascent
;
291 assert(WMHashInsert(scrPtr
->fontCache
, font
->name
, font
)==NULL
);
298 WMRetainFont(WMFont
*font
)
300 wassertrv(font
!=NULL
, NULL
);
309 WMReleaseFont(WMFont
*font
)
311 wassertr(font
!=NULL
);
314 if (font
->refCount
< 1) {
315 XftFontClose(font
->screen
->display
, font
->font
);
317 WMHashRemove(font
->screen
->fontCache
, font
->name
);
326 WMIsAntialiasingEnabled(WMScreen
*scrPtr
)
328 return scrPtr
->antialiasedText
;
333 WMFontHeight(WMFont
*font
)
335 wassertrv(font
!=NULL
, 0);
342 WMGetFontName(WMFont
*font
)
344 wassertrv(font
!=NULL
, NULL
);
351 WMDefaultSystemFont(WMScreen
*scrPtr
)
353 return WMRetainFont(scrPtr
->normalFont
);
358 WMDefaultBoldSystemFont(WMScreen
*scrPtr
)
360 return WMRetainFont(scrPtr
->boldFont
);
365 WMSystemFontOfSize(WMScreen
*scrPtr
, int size
)
370 fontSpec
= makeFontOfSize(WINGsConfiguration
.systemFont
, size
, "sans");
372 font
= WMCreateFont(scrPtr
, fontSpec
);
375 wwarning(_("could not load font %s."), fontSpec
);
385 WMBoldSystemFontOfSize(WMScreen
*scrPtr
, int size
)
390 fontSpec
= makeFontOfSize(WINGsConfiguration
.boldSystemFont
, size
, "sans");
392 font
= WMCreateFont(scrPtr
, fontSpec
);
395 wwarning(_("could not load font %s."), fontSpec
);
405 WMWidthOfString(WMFont
*font
, char *text
, int length
)
409 wassertrv(font
!=NULL
, 0);
410 wassertrv(text
!=NULL
, 0);
412 if (font
->screen
->useWideChar
) {
417 wtext
= (wchar_t *)wmalloc(sizeof(wchar_t)*(length
+1));
419 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
421 wtext
[len
] = L
'\0'; /* not really necessary here */
422 XftTextExtents32(font
->screen
->display
, font
->font
,
423 (XftChar32
*)wtext
, len
, &extents
);
426 wwarning(_("Conversion to widechar failed (possible "
427 "invalid multibyte sequence): '%s':(pos %d)\n"),
433 } else if (font
->screen
->useMultiByte
) {
434 XftTextExtentsUtf8(font
->screen
->display
, font
->font
,
435 (XftChar8
*)text
, length
, &extents
);
437 XftTextExtents8(font
->screen
->display
, font
->font
,
438 (XftChar8
*)text
, length
, &extents
);
441 return extents
.xOff
; /* don't ask :P */
447 WMDrawString(WMScreen
*scr
, Drawable d
, WMColor
*color
, WMFont
*font
,
448 int x
, int y
, char *text
, int length
)
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
) {
467 wtext
= (wchar_t *)wmalloc(sizeof(wchar_t)*(length
+1));
469 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
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"),
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);*/
483 } else if (font
->screen
->useMultiByte
) {
484 XftDrawStringUtf8(scr
->xftdraw
, &xftcolor
, font
->font
,
485 x
, y
+ font
->y
, (XftChar8
*)text
, length
);
487 XftDrawString8(scr
->xftdraw
, &xftcolor
, font
->font
,
488 x
, y
+ font
->y
, (XftChar8
*)text
, length
);
494 WMDrawImageString(WMScreen
*scr
, Drawable d
, WMColor
*color
, WMColor
*background
,
495 WMFont
*font
, int x
, int y
, char *text
, int length
)
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
),
520 if (font
->screen
->useWideChar
) {
526 wtext
= (wchar_t *)wmalloc(sizeof(wchar_t)*(length
+1));
527 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
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"),
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);*/
541 } else if (font
->screen
->useMultiByte
) {
542 XftDrawStringUtf8(scr
->xftdraw
, &textColor
, font
->font
,
543 x
, y
+ font
->y
, (XftChar8
*)text
, length
);
545 XftDrawString8(scr
->xftdraw
, &textColor
, font
->font
,
546 x
, y
+ font
->y
, (XftChar8
*)text
, length
);
552 WMCopyFontWithStyle(WMScreen
*scrPtr
, WMFont
*font
, WMFontStyle style
)
561 pattern
= FcNameParse(WMGetFontName(font
));
564 FcPatternDel(pattern
, "weight");
565 FcPatternDel(pattern
, "slant");
566 FcPatternAddString(pattern
, "weight", "regular");
567 FcPatternAddString(pattern
, "weight", "medium");
568 FcPatternAddString(pattern
, "slant", "roman");
571 FcPatternDel(pattern
, "weight");
572 FcPatternAddString(pattern
, "weight", "bold");
575 FcPatternDel(pattern
, "slant");
576 FcPatternAddString(pattern
, "slant", "italic");
577 FcPatternAddString(pattern
, "slant", "oblique");
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");
588 name
= FcNameUnparse(pattern
);
589 copy
= WMCreateFont(scrPtr
, name
);
590 FcPatternDestroy(pattern
);