- Added xdnd v3 support in WINGs (Sylvain Reynal <sreynal@nerim.net>)
[wmaker-crm.git] / WINGs / wfont.c
blob6acc278d9a094e9c1968925396f21cc20176b7a9
2 #include "wconfig.h"
4 #ifdef XFT
5 # include <X11/Xft/Xft.h>
6 # ifdef HAVE_WCHAR_H
7 # include <wchar.h>
8 # endif
9 # include <stdlib.h>
10 #endif
12 #include "WINGsP.h"
14 #include <wraster.h>
15 #include <assert.h>
16 #include <X11/Xlocale.h>
19 #ifdef XFT
21 #if defined(HAVE_MBSNRTOWCS)
23 static size_t
24 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
26 mbstate_t ps;
27 size_t n;
29 memset(&ps, 0, sizeof(mbstate_t));
30 n = mbsnrtowcs(dest, src, nbytes, len, &ps);
31 if (n!=(size_t)-1 && *src) {
32 *src -= ps.__count;
35 return n;
38 #elif defined(HAVE_MBRTOWC)
40 // This is 8 times slower than the version above.
41 static size_t
42 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
44 mbstate_t ps;
45 const char *ptr;
46 size_t n;
47 int nb;
49 if (nbytes==0)
50 return 0;
52 memset(&ps, 0, sizeof(mbstate_t));
54 if (dest == NULL) {
55 for (ptr=*src, n=0; nbytes>0; n++) {
56 nb = mbrtowc(NULL, ptr, nbytes, &ps);
57 if (nb == -1) {
58 return ((size_t)-1);
59 } else if (nb==0 || nb==-2) {
60 return n;
62 ptr += nb;
63 nbytes -= nb;
67 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
68 nb = mbrtowc(dest, ptr, nbytes, &ps);
69 if (nb == -2) {
70 *src = ptr;
71 return n;
72 } else if (nb == -1) {
73 *src = ptr;
74 return ((size_t)-1);
75 } else if (nb == 0) {
76 *src = NULL;
77 return n;
79 ptr += nb;
80 nbytes -= nb;
83 *src = ptr;
84 return n;
87 #else
89 // Not only 8 times slower than the version based on mbsnrtowcs
90 // but also this version is not thread safe nor reentrant
92 static size_t
93 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
95 const char *ptr;
96 size_t n;
97 int nb;
99 if (nbytes==0)
100 return 0;
102 mbtowc(NULL, NULL, 0); /* reset shift state */
104 if (dest == NULL) {
105 for (ptr=*src, n=0; nbytes>0; n++) {
106 nb = mbtowc(NULL, ptr, nbytes);
107 if (nb == -1) {
108 mbtowc(NULL, NULL, 0);
109 nb = mbtowc(NULL, ptr, strlen(ptr));
110 return (nb == -1 ? (size_t)-1 : n);
111 } else if (nb==0) {
112 return n;
114 ptr += nb;
115 nbytes -= nb;
119 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
120 nb = mbtowc(dest, ptr, nbytes);
121 if (nb == -1) {
122 mbtowc(NULL, NULL, 0);
123 nb = mbtowc(NULL, ptr, strlen(ptr));
124 *src = ptr;
125 return (nb == -1 ? (size_t)-1 : n);
126 } else if (nb == 0) {
127 *src = NULL;
128 return n;
130 ptr += nb;
131 nbytes -= nb;
134 *src = ptr;
135 return n;
138 #endif
141 static Bool
142 alreadyHasStringValue(XftPattern *pattern, const char *object, char *value)
144 XftResult r;
145 char *s;
146 int id;
148 if (!value || value[0]==0)
149 return True;
151 id = 0;
152 while ((r=XftPatternGetString(pattern, object, id, &s))==XftResultMatch) {
153 if (strcasecmp(value, s) == 0) {
154 return True;
156 id++;
159 return False;
163 // check if to add a fallback size too. -Dan
164 // also handle an xlfd with %d for size?
165 static char*
166 makeFontOfSize(char *font, int size, char *fallback)
168 FcPattern *pattern;
169 char *result;
171 pattern = XftNameParse(font);
172 XftPatternDel(pattern, "pixelsize");
173 XftPatternAddDouble(pattern, "pixelsize", (double)size);
175 if (fallback) {
176 if (!alreadyHasStringValue(pattern, "family", fallback)) {
177 XftPatternAddString(pattern, "family", fallback);
181 result = FcNameUnparse(pattern);
182 FcPatternDestroy(pattern);
184 return result;
188 WMFont*
189 WMCreateFont(WMScreen *scrPtr, char *fontName)
191 WMFont *font;
192 Display *display = scrPtr->display;
193 char *fname, *ptr;
195 /* This is for back-compat (to allow reading of old xlfd descriptions) */
196 if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) {
197 // warn for deprecation
198 fname = wmalloc(ptr - fontName + 1);
199 strncpy(fname, fontName, ptr - fontName);
200 fname[ptr - fontName] = 0;
201 } else {
202 fname = wstrdup(fontName);
205 font = WMHashGet(scrPtr->fontCache, fname);
206 if (font) {
207 WMRetainFont(font);
208 wfree(fname);
209 return font;
212 font = wmalloc(sizeof(WMFont));
213 memset(font, 0, sizeof(WMFont));
215 font->screen = scrPtr;
217 // remove
218 printf("WMCreateFont: %s\n", fname);
220 if (fname[0] == '-') {
221 // Backward compat thing. Remove in a later version
222 font->font = XftFontOpenXlfd(display, scrPtr->screen, fname);
223 } else {
224 font->font = XftFontOpenName(display, scrPtr->screen, fname);
226 if (!font->font) {
227 wfree(font);
228 wfree(fname);
229 return NULL;
231 font->height = font->font->ascent+font->font->descent;
232 font->y = font->font->ascent;
234 font->refCount = 1;
236 font->name = fname;
238 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
240 return font;
244 WMFont*
245 WMRetainFont(WMFont *font)
247 wassertrv(font!=NULL, NULL);
249 font->refCount++;
251 return font;
255 void
256 WMReleaseFont(WMFont *font)
258 wassertr(font!=NULL);
260 font->refCount--;
261 if (font->refCount < 1) {
262 XftFontClose(font->screen->display, font->font);
263 if (font->name) {
264 WMHashRemove(font->screen->fontCache, font->name);
265 wfree(font->name);
267 wfree(font);
272 Bool
273 WMIsAntialiasingEnabled(WMScreen *scrPtr)
275 return scrPtr->antialiasedText;
279 unsigned int
280 WMFontHeight(WMFont *font)
282 wassertrv(font!=NULL, 0);
284 return font->height;
288 char*
289 WMGetFontName(WMFont *font)
291 wassertrv(font!=NULL, NULL);
293 return font->name;
297 WMFont*
298 WMDefaultSystemFont(WMScreen *scrPtr)
300 return WMRetainFont(scrPtr->normalFont);
304 WMFont*
305 WMDefaultBoldSystemFont(WMScreen *scrPtr)
307 return WMRetainFont(scrPtr->boldFont);
311 WMFont*
312 WMSystemFontOfSize(WMScreen *scrPtr, int size)
314 WMFont *font;
315 char *fontSpec;
317 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans");
319 font = WMCreateFont(scrPtr, fontSpec);
321 if (!font) {
322 wwarning(_("could not load font %s."), fontSpec);
325 wfree(fontSpec);
327 return font;
331 WMFont*
332 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
334 WMFont *font;
335 char *fontSpec;
337 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans");
339 font = WMCreateFont(scrPtr, fontSpec);
341 if (!font) {
342 wwarning(_("could not load font %s."), fontSpec);
345 wfree(fontSpec);
347 return font;
352 WMWidthOfString(WMFont *font, char *text, int length)
354 XGlyphInfo extents;
356 wassertrv(font!=NULL, 0);
357 wassertrv(text!=NULL, 0);
359 if (font->screen->useWideChar) {
360 wchar_t *wtext;
361 const char *mtext;
362 int len;
364 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
365 mtext = text;
366 len = wmbsnrtowcs(wtext, &mtext, length, length);
367 if (len>0) {
368 wtext[len] = L'\0'; /* not really necessary here */
369 XftTextExtents32(font->screen->display, font->font,
370 (XftChar32 *)wtext, len, &extents);
371 } else {
372 if (len==-1) {
373 wwarning(_("Conversion to widechar failed (possible "
374 "invalid multibyte sequence): '%s':(pos %d)\n"),
375 text, mtext-text+1);
377 extents.xOff = 0;
379 wfree(wtext);
380 } else {
381 XftTextExtents8(font->screen->display, font->font,
382 (XftChar8 *)text, length, &extents);
385 return extents.xOff; /* don't ask :P */
390 void
391 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
392 int x, int y, char *text, int length)
394 XftColor xftcolor;
396 wassertr(font!=NULL);
398 xftcolor.color.red = color->color.red;
399 xftcolor.color.green = color->color.green;
400 xftcolor.color.blue = color->color.blue;
401 xftcolor.color.alpha = color->alpha;;
402 xftcolor.pixel = W_PIXEL(color);
404 XftDrawChange(scr->xftdraw, d);
406 if (font->screen->useWideChar) {
407 wchar_t *wtext;
408 const char *mtext;
409 int len;
411 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
412 mtext = text;
413 len = wmbsnrtowcs(wtext, &mtext, length, length);
414 if (len>0) {
415 XftDrawString32(scr->xftdraw, &xftcolor, font->font,
416 x, y + font->y, (XftChar32*)wtext, len);
417 } else if (len==-1) {
418 wwarning(_("Conversion to widechar failed (possible invalid "
419 "multibyte sequence): '%s':(pos %d)\n"),
420 text, mtext-text+1);
421 /* we can draw normal text, or we can draw as much widechar
422 * text as was already converted until the error. go figure */
423 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font,
424 x, y + font->y, (XftChar8*)text, length);*/
426 wfree(wtext);
427 } else {
428 XftDrawString8(scr->xftdraw, &xftcolor, font->font,
429 x, y + font->y, (XftChar8*)text, length);
434 void
435 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
436 WMFont *font, int x, int y, char *text, int length)
438 XftColor textColor;
439 XftColor bgColor;
441 wassertr(font!=NULL);
443 textColor.color.red = color->color.red;
444 textColor.color.green = color->color.green;
445 textColor.color.blue = color->color.blue;
446 textColor.color.alpha = color->alpha;;
447 textColor.pixel = W_PIXEL(color);
449 bgColor.color.red = background->color.red;
450 bgColor.color.green = background->color.green;
451 bgColor.color.blue = background->color.blue;
452 bgColor.color.alpha = background->alpha;;
453 bgColor.pixel = W_PIXEL(background);
455 XftDrawChange(scr->xftdraw, d);
457 XftDrawRect(scr->xftdraw, &bgColor, x, y,
458 WMWidthOfString(font, text, length),
459 font->height);
461 if (font->screen->useWideChar) {
462 wchar_t *wtext;
463 const char *mtext;
464 int len;
466 mtext = text;
467 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
468 len = wmbsnrtowcs(wtext, &mtext, length, length);
469 if (len>0) {
470 XftDrawString32(scr->xftdraw, &textColor, font->font,
471 x, y + font->y, (XftChar32*)wtext, len);
472 } else if (len==-1) {
473 wwarning(_("Conversion to widechar failed (possible invalid "
474 "multibyte sequence): '%s':(pos %d)\n"),
475 text, mtext-text+1);
476 /* we can draw normal text, or we can draw as much widechar
477 * text as was already converted until the error. go figure */
478 /*XftDrawString8(scr->xftdraw, &textColor, font->font,
479 x, y + font->y, (XftChar8*)text, length);*/
481 wfree(wtext);
482 } else {
483 XftDrawString8(scr->xftdraw, &textColor, font->font,
484 x, y + font->y, (XftChar8*)text, length);
489 WMFont*
490 WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style)
492 FcPattern *pattern;
493 WMFont *copy;
494 char *name;
496 if (!font)
497 return NULL;
499 pattern = XftNameParse(WMGetFontName(font));
500 switch (style) {
501 case WFSNormal:
502 XftPatternDel(pattern, "weight");
503 XftPatternDel(pattern, "slant");
504 XftPatternAddString(pattern, "weight", "medium");
505 XftPatternAddString(pattern, "slant", "roman");
506 break;
507 case WFSBold:
508 XftPatternDel(pattern, "weight");
509 XftPatternAddString(pattern, "weight", "bold");
510 break;
511 case WFSEmphasized:
512 XftPatternDel(pattern, "slant");
513 XftPatternAddString(pattern, "slant", "italic");
514 XftPatternAddString(pattern, "slant", "oblique");
515 break;
516 case WFSBoldEmphasized:
517 XftPatternDel(pattern, "weight");
518 XftPatternDel(pattern, "slant");
519 XftPatternAddString(pattern, "weight", "bold");
520 XftPatternAddString(pattern, "slant", "italic");
521 XftPatternAddString(pattern, "slant", "oblique");
522 break;
525 name = FcNameUnparse(pattern);
526 copy = WMCreateFont(scrPtr, name);
527 FcPatternDestroy(pattern);
528 wfree(name);
530 return copy;
534 #else /* No XFT support */
537 static char *makeFontSetOfSize(char *fontset, int size);
541 /* XLFD pattern matching */
542 static char*
543 getElementFromXLFD(const char *xlfd, int index)
545 const char *p = xlfd;
546 while (*p != 0) {
547 if (*p == '-' && --index == 0) {
548 const char *end = strchr(p + 1, '-');
549 char *buf;
550 size_t len;
551 if (end == 0) end = p + strlen(p);
552 len = end - (p + 1);
553 buf = wmalloc(len);
554 memcpy(buf, p + 1, len);
555 buf[len] = 0;
556 return buf;
558 p++;
560 return strdup("*");
564 /* XLFD pattern matching */
565 static char*
566 generalizeXLFD(const char *xlfd)
568 char *buf;
569 int len;
570 char *weight = getElementFromXLFD(xlfd, 3);
571 char *slant = getElementFromXLFD(xlfd, 4);
572 char *pxlsz = getElementFromXLFD(xlfd, 7);
574 #define Xstrlen(A) ((A)?strlen(A):0)
575 len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60;
576 #undef Xstrlen
578 buf = wmalloc(len + 1);
579 snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*,"
580 "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*",
581 xlfd, weight, slant, pxlsz, pxlsz);
583 wfree(pxlsz);
584 wfree(slant);
585 wfree(weight);
587 return buf;
590 /* XLFD pattern matching */
591 static XFontSet
592 W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing,
593 int *nmissing, char **def_string)
595 XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
597 if (fs != NULL && *nmissing == 0) return fs;
599 /* for non-iso8859-1 language and iso8859-1 specification
600 (this fontset is only for pattern analysis) */
601 if (fs == NULL) {
602 if (*nmissing != 0) XFreeStringList(*missing);
603 setlocale(LC_CTYPE, "C");
604 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
605 setlocale(LC_CTYPE, "");
608 /* make XLFD font name for pattern analysis */
609 if (fs != NULL) {
610 XFontStruct **fontstructs;
611 char **fontnames;
612 if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0)
613 xlfd = fontnames[0];
616 xlfd = generalizeXLFD(xlfd);
618 if (*nmissing != 0) XFreeStringList(*missing);
619 if (fs != NULL) XFreeFontSet(dpy, fs);
621 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
623 wfree(xlfd);
624 return fs;
628 static char*
629 xlfdFromFontName(char *fontName, Bool antialiased)
631 char *systemFont, *boldSystemFont;
632 char *font;
633 int size;
635 if (antialiased) {
636 systemFont = WINGsConfiguration.antialiasedSystemFont;
637 boldSystemFont = WINGsConfiguration.antialiasedBoldSystemFont;
638 } else {
639 systemFont = WINGsConfiguration.systemFont;
640 boldSystemFont = WINGsConfiguration.boldSystemFont;
643 size = WINGsConfiguration.defaultFontSize;
645 if (strcmp(fontName, "SystemFont")==0) {
646 font = systemFont;
647 size = WINGsConfiguration.defaultFontSize;
648 } else if (strncmp(fontName, "SystemFont-", 11)==0) {
649 font = systemFont;
650 if (sscanf(&fontName[11], "%i", &size)!=1) {
651 size = WINGsConfiguration.defaultFontSize;
652 wwarning(_("Invalid size specification '%s' in %s. "
653 "Using default %d\n"), &fontName[11], fontName, size);
655 } else if (strcmp(fontName, "BoldSystemFont")==0) {
656 font = boldSystemFont;
657 size = WINGsConfiguration.defaultFontSize;
658 } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) {
659 font = boldSystemFont;
660 if (sscanf(&fontName[15], "%i", &size)!=1) {
661 size = WINGsConfiguration.defaultFontSize;
662 wwarning(_("Invalid size specification '%s' in %s. "
663 "Using default %d\n"), &fontName[15], fontName, size);
665 } else {
666 font = NULL;
669 return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName));
673 WMFont*
674 WMCreateFontSet(WMScreen *scrPtr, char *fontName)
676 WMFont *font;
677 Display *display = scrPtr->display;
678 char **missing;
679 int nmissing = 0;
680 char *defaultString;
681 char *fname;
682 XFontSetExtents *extents;
684 fname = xlfdFromFontName(fontName, False);
686 font = WMHashGet(scrPtr->fontSetCache, fname);
687 if (font) {
688 WMRetainFont(font);
689 wfree(fname);
690 return font;
693 font = wmalloc(sizeof(WMFont));
694 memset(font, 0, sizeof(WMFont));
696 font->notFontSet = 0;
697 font->antialiased = 0;
699 font->screen = scrPtr;
701 font->font.set = W_CreateFontSetWithGuess(display, fname, &missing,
702 &nmissing, &defaultString);
703 if (nmissing > 0 && font->font.set) {
704 int i;
706 wwarning(_("the following character sets are missing in %s:"), fname);
707 for (i = 0; i < nmissing; i++) {
708 wwarning(missing[i]);
710 XFreeStringList(missing);
711 if (defaultString)
712 wwarning(_("the string \"%s\" will be used in place of any characters from those sets."),
713 defaultString);
715 if (!font->font.set) {
716 wfree(font);
717 wfree(fname);
718 return NULL;
721 extents = XExtentsOfFontSet(font->font.set);
723 font->height = extents->max_logical_extent.height;
724 font->y = font->height - (font->height + extents->max_logical_extent.y);
726 font->refCount = 1;
728 font->name = fname;
730 assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL);
732 return font;
737 WMFont*
738 WMCreateNormalFont(WMScreen *scrPtr, char *fontName)
740 WMFont *font;
741 Display *display = scrPtr->display;
742 char *fname, *ptr;
744 fontName = xlfdFromFontName(fontName, False);
746 if ((ptr = strchr(fontName, ','))) {
747 fname = wmalloc(ptr - fontName + 1);
748 strncpy(fname, fontName, ptr - fontName);
749 fname[ptr - fontName] = 0;
750 } else {
751 fname = wstrdup(fontName);
754 wfree(fontName);
756 font = WMHashGet(scrPtr->fontCache, fname);
757 if (font) {
758 WMRetainFont(font);
759 wfree(fname);
760 return font;
763 font = wmalloc(sizeof(WMFont));
764 memset(font, 0, sizeof(WMFont));
766 font->notFontSet = 1;
767 font->antialiased = 0;
769 font->screen = scrPtr;
771 font->font.normal = XLoadQueryFont(display, fname);
772 if (!font->font.normal) {
773 wfree(font);
774 wfree(fname);
775 return NULL;
777 font->height = font->font.normal->ascent+font->font.normal->descent;
778 font->y = font->font.normal->ascent;
780 font->refCount = 1;
782 font->name = fname;
784 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
786 return font;
790 WMFont*
791 WMCreateAntialiasedFont(WMScreen *scrPtr, char *fontName)
793 #ifdef XFT
794 WMFont *font;
795 Display *display = scrPtr->display;
796 char *fname, *ptr;
798 fontName = xlfdFromFontName(fontName, True);
800 if ((ptr = strchr(fontName, ','))) {
801 fname = wmalloc(ptr - fontName + 1);
802 strncpy(fname, fontName, ptr - fontName);
803 fname[ptr - fontName] = 0;
804 } else {
805 fname = wstrdup(fontName);
808 wfree(fontName);
810 font = WMHashGet(scrPtr->xftFontCache, fname);
811 if (font) {
812 WMRetainFont(font);
813 wfree(fname);
814 return font;
817 font = wmalloc(sizeof(WMFont));
818 memset(font, 0, sizeof(WMFont));
820 font->notFontSet = 1;
821 font->antialiased = 1;
823 font->screen = scrPtr;
825 /* Xft sux. Loading a font with an invalid XLFD will give strange results
826 * sometimes without returning any warning or error.
827 * However Xft's idea of what font is invalid is quite strange:
828 * 1. If the XLFD doesn't have all its fields present will fail and
829 * return NULL.
830 * 2. If all fields are present, but hold invalid values then it will:
831 * a. If family is invalid, will load a default font without warning.
832 * b. If the font size is invalid (non-numerical) it will fail and
833 * return NULL.
834 * c. If other fields are invalid, will load the font specified by
835 * the valid family name, ignoring any invalid fields. It will
836 * use a default medium weight and a default roman slant if they
837 * are invalid.
839 printf("%s\n", fname);
840 if (fname[0] == '-') {
841 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
842 } else {
843 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
845 if (!font->font.xft) {
846 wfree(font);
847 wfree(fname);
848 return NULL;
850 font->height = font->font.xft->ascent+font->font.xft->descent;
851 font->y = font->font.xft->ascent;
853 font->refCount = 1;
855 font->name = fname;
857 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
859 return font;
860 #else
861 return NULL;
862 #endif
866 WMFont*
867 WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName)
869 #ifdef XFT
870 WMFont *font;
871 Display *display = scrPtr->display;
872 char *fname, *ptr;
874 fontName = xlfdFromFontName(fontName, True);
876 if ((ptr = strchr(fontName, ','))) {
877 fname = wmalloc(ptr - fontName + 1);
878 strncpy(fname, fontName, ptr - fontName);
879 fname[ptr - fontName] = 0;
880 } else {
881 fname = wstrdup(fontName);
884 wfree(fontName);
886 font = WMHashGet(scrPtr->xftFontSetCache, fname);
887 if (font) {
888 WMRetainFont(font);
889 wfree(fname);
890 return font;
893 font = wmalloc(sizeof(WMFont));
894 memset(font, 0, sizeof(WMFont));
896 font->notFontSet = 0;
897 font->antialiased = 1;
899 font->screen = scrPtr;
901 /* Xft sux. Loading a font with an invalid XLFD will give strange results
902 * sometimes without returning any warning or error.
903 * However Xft's idea of what font is invalid is quite strange:
904 * 1. If the XLFD doesn't have all its fields present will fail and
905 * return NULL.
906 * 2. If all fields are present, but hold invalid values then it will:
907 * a. If family is invalid, will load a default font without warning.
908 * b. If the font size is invalid (non-numerical) it will fail and
909 * return NULL.
910 * c. If other fields are invalid, will load the font specified by
911 * the valid family name, ignoring any invalid fields. It will
912 * use a default medium weight and a default roman slant if they
913 * are invalid.
915 if (fname[0] == '-') {
916 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
917 } else {
918 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
920 if (!font->font.xft) {
921 wfree(font);
922 wfree(fname);
923 return NULL;
925 font->height = font->font.xft->ascent+font->font.xft->descent;
926 font->y = font->font.xft->ascent;
928 font->refCount = 1;
930 font->name = fname;
932 assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL);
934 return font;
935 #else
936 return NULL;
937 #endif
941 WMFont*
942 WMCreateFont(WMScreen *scrPtr, char *fontName)
944 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
948 WMFont*
949 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
951 Bool multiByte = scrPtr->useMultiByte;
952 Bool antialiased = scrPtr->antialiasedText;
953 WMFont *font;
955 if (flags & WFFontSet) {
956 multiByte = True;
957 } else if (flags & WFNormalFont) {
958 multiByte = False;
960 if (flags & WFAntialiased) {
961 antialiased = True;
962 } else if (flags & WFNotAntialiased) {
963 antialiased = False;
966 if (antialiased && multiByte) {
967 font = WMCreateAntialiasedFontSet(scrPtr, fontName);
968 /* If we cannot create an antialiased font set and antialiasing is
969 * not explicitly requested in flags, fallback to standard font sets */
970 if (!font && (flags & WFAntialiased)==0) {
971 font = WMCreateFontSet(scrPtr, fontName);
973 } else if (antialiased) {
974 font = WMCreateAntialiasedFont(scrPtr, fontName);
975 /* If we cannot create an antialiased font and antialiasing is
976 * not explicitly requested in flags, fallback to normal font */
977 if (!font && (flags & WFAntialiased)==0) {
978 font = WMCreateNormalFont(scrPtr, fontName);
980 } else if (multiByte) {
981 font = WMCreateFontSet(scrPtr, fontName);
982 } else {
983 font = WMCreateNormalFont(scrPtr, fontName);
986 return font;
990 WMFont*
991 WMRetainFont(WMFont *font)
993 wassertrv(font!=NULL, NULL);
995 font->refCount++;
997 return font;
1001 void
1002 WMReleaseFont(WMFont *font)
1004 wassertr(font!=NULL);
1006 font->refCount--;
1007 if (font->refCount < 1) {
1008 if (font->antialiased) {
1009 #ifdef XFT
1010 XftFontClose(font->screen->display, font->font.xft);
1011 #else
1012 assert(False);
1013 #endif
1014 } else if (font->notFontSet) {
1015 XFreeFont(font->screen->display, font->font.normal);
1016 } else {
1017 XFreeFontSet(font->screen->display, font->font.set);
1020 if (font->name) {
1021 if (font->antialiased && !font->notFontSet) {
1022 WMHashRemove(font->screen->xftFontSetCache, font->name);
1023 } else if (font->antialiased) {
1024 WMHashRemove(font->screen->xftFontCache, font->name);
1025 } else if (font->notFontSet) {
1026 WMHashRemove(font->screen->fontCache, font->name);
1027 } else {
1028 WMHashRemove(font->screen->fontSetCache, font->name);
1030 wfree(font->name);
1032 wfree(font);
1037 Bool
1038 WMIsAntialiasingEnabled(WMScreen *scrPtr)
1040 return scrPtr->antialiasedText;
1044 Bool
1045 WMIsAntialiasedFont(WMFont *font)
1047 wassertrv(font!=NULL, False);
1049 return font->antialiased;
1053 unsigned int
1054 WMFontHeight(WMFont *font)
1056 wassertrv(font!=NULL, 0);
1058 return font->height;
1062 char*
1063 WMGetFontName(WMFont *font)
1065 wassertrv(font!=NULL, NULL);
1067 return font->name;
1071 WMFont*
1072 WMDefaultSystemFont(WMScreen *scrPtr)
1074 return WMRetainFont(scrPtr->normalFont);
1078 WMFont*
1079 WMDefaultBoldSystemFont(WMScreen *scrPtr)
1081 return WMRetainFont(scrPtr->boldFont);
1085 static WMFont*
1086 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
1088 WMFont *font;
1089 char *fontSpec, *xftFontSpec;
1091 #define WConf WINGsConfiguration
1092 if (bold) {
1093 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
1094 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
1095 } else {
1096 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
1097 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
1099 #undef WConf
1101 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
1102 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
1103 } else if (scrPtr->antialiasedText) {
1104 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
1105 } else if (scrPtr->useMultiByte) {
1106 font = WMCreateFontSet(scrPtr, fontSpec);
1107 } else {
1108 font = WMCreateNormalFont(scrPtr, fontSpec);
1111 if (!font) {
1112 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
1113 // is arial a good fallback for multibyte?
1114 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
1115 if (bold) {
1116 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
1117 } else {
1118 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
1120 if (!font) {
1121 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
1122 font = WMCreateFontSet(scrPtr, fontSpec);
1123 if (!font) {
1124 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
1125 font = WMCreateFontSet(scrPtr, "fixed");
1128 } else if (scrPtr->antialiasedText) {
1129 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
1130 if (bold) {
1131 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
1132 } else {
1133 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
1135 if (!font) {
1136 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
1137 font = WMCreateNormalFont(scrPtr, fontSpec);
1138 if (!font) {
1139 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
1140 font = WMCreateNormalFont(scrPtr, "fixed");
1143 } else if (scrPtr->useMultiByte) {
1144 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
1145 font = WMCreateFontSet(scrPtr, "fixed");
1146 if (!font) {
1147 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
1149 } else {
1150 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
1151 font = WMCreateNormalFont(scrPtr, "fixed");
1153 if (!font) {
1154 wwarning(_("could not load fixed font!"));
1155 wfree(fontSpec);
1156 wfree(xftFontSpec);
1157 return NULL;
1160 wfree(fontSpec);
1161 wfree(xftFontSpec);
1163 return font;
1167 WMFont*
1168 WMSystemFontOfSize(WMScreen *scrPtr, int size)
1170 return makeSystemFontOfSize(scrPtr, size, False);
1174 WMFont*
1175 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
1177 return makeSystemFontOfSize(scrPtr, size, True);
1181 XFontSet
1182 WMGetFontFontSet(WMFont *font)
1184 wassertrv(font!=NULL, NULL);
1186 if (!font->notFontSet && !font->antialiased)
1187 return font->font.set;
1189 return NULL;
1194 WMWidthOfString(WMFont *font, char *text, int length)
1196 wassertrv(font!=NULL, 0);
1197 wassertrv(text!=NULL, 0);
1199 if (font->antialiased) {
1200 #ifdef XFT
1201 XGlyphInfo extents;
1203 if (!font->notFontSet) {
1204 wchar_t *wtext;
1205 char *mtext;
1206 int len;
1208 /* Use mtext instead of text, because mbstrtowcs() alters it */
1209 mtext = text;
1210 wtext = (wchar_t *)wmalloc(4*length+4);
1211 /* pass a real ps instead of NULL below? for multithread safety
1212 * as from manual page */
1213 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
1214 if (len>0) {
1215 XftTextExtents32(font->screen->display, font->font.xft,
1216 (XftChar32 *)wtext, len, &extents);
1217 } else {
1218 if (len==-1) {
1219 wwarning(_("Conversion to widechar failed (possible "
1220 "invalid multibyte sequence): '%s':(pos %d)\n"),
1221 text, mtext-text+1);
1223 extents.xOff = 0;
1225 wfree(wtext);
1226 } else {
1227 XftTextExtents8(font->screen->display, font->font.xft,
1228 (XftChar8 *)text, length, &extents);
1231 return extents.xOff; /* don't ask :P */
1232 #else
1233 wassertrv(False, 0);
1234 #endif
1235 } else if (font->notFontSet) {
1236 return XTextWidth(font->font.normal, text, length);
1237 } else {
1238 XRectangle rect;
1239 XRectangle AIXsucks;
1241 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
1243 return rect.width;
1249 void
1250 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
1251 int x, int y, char *text, int length)
1253 wassertr(font!=NULL);
1255 if (font->antialiased) {
1256 #ifdef XFT
1257 XftColor xftcolor;
1259 xftcolor.color.red = color->color.red;
1260 xftcolor.color.green = color->color.green;
1261 xftcolor.color.blue = color->color.blue;
1262 xftcolor.color.alpha = color->alpha;;
1263 xftcolor.pixel = W_PIXEL(color);
1265 XftDrawChange(scr->xftdraw, d);
1267 if (!font->notFontSet) {
1268 wchar_t *wtext;
1269 char *mtext;
1270 int len;
1272 /* Use mtext instead of text, because mbstrtowcs() alters it */
1273 mtext = text;
1274 wtext = (wchar_t *)wmalloc(4*length+4);
1275 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
1276 if (len>0) {
1277 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
1278 x, y + font->y, (XftChar32*)wtext, len);
1279 } else if (len==-1) {
1280 wwarning(_("Conversion to widechar failed (possible invalid "
1281 "multibyte sequence): '%s':(pos %d)\n"),
1282 text, mtext-text+1);
1283 /* we can draw normal text, or we can draw as much widechar
1284 * text as was already converted until the error. go figure */
1285 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
1286 x, y + font->y, (XftChar8*)text, length);*/
1288 wfree(wtext);
1289 } else {
1290 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
1291 x, y + font->y, (XftChar8*)text, length);
1293 #else
1294 wassertr(False);
1295 #endif
1296 } else if (font->notFontSet) {
1297 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
1298 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
1299 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
1300 text, length);
1301 } else {
1302 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
1303 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
1304 x, y + font->y, text, length);
1309 void
1310 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
1311 WMFont *font, int x, int y, char *text, int length)
1313 wassertr(font!=NULL);
1315 if (font->antialiased) {
1316 #ifdef XFT
1317 XftColor textColor;
1318 XftColor bgColor;
1320 textColor.color.red = color->color.red;
1321 textColor.color.green = color->color.green;
1322 textColor.color.blue = color->color.blue;
1323 textColor.color.alpha = color->alpha;;
1324 textColor.pixel = W_PIXEL(color);
1326 bgColor.color.red = background->color.red;
1327 bgColor.color.green = background->color.green;
1328 bgColor.color.blue = background->color.blue;
1329 bgColor.color.alpha = background->alpha;;
1330 bgColor.pixel = W_PIXEL(background);
1333 XftDrawChange(scr->xftdraw, d);
1335 XftDrawRect(scr->xftdraw, &bgColor, x, y,
1336 WMWidthOfString(font, text, length), font->height);
1338 if (!font->notFontSet) {
1339 wchar_t *wtext;
1340 char *mtext;
1341 int len;
1343 /* Use mtext instead of text, because mbstrtowcs() alters it */
1344 mtext = text;
1345 wtext = (wchar_t *)wmalloc(4*length+4);
1346 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
1347 if (len>0) {
1348 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
1349 x, y + font->y, (XftChar32*)wtext, len);
1350 } else if (len==-1) {
1351 wwarning(_("Conversion to widechar failed (possible invalid "
1352 "multibyte sequence): '%s':(pos %d)\n"),
1353 text, mtext-text+1);
1354 /* we can draw normal text, or we can draw as much widechar
1355 * text as was already converted until the error. go figure */
1356 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
1357 x, y + font->y, (XftChar8*)text, length);*/
1359 wfree(wtext);
1360 } else {
1361 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
1362 x, y + font->y, (XftChar8*)text, length);
1364 #else
1365 wassertr(False);
1366 #endif
1367 } else if (font->notFontSet) {
1368 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
1369 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
1370 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
1371 XDrawImageString(scr->display, d, scr->drawImStringGC,
1372 x, y + font->y, text, length);
1373 } else {
1374 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
1375 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
1376 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
1377 x, y + font->y, text, length);
1384 static char*
1385 makeFontSetOfSize(char *fontset, int size)
1387 char font[300], *f;
1388 char *newfs = NULL;
1389 char *ptr;
1391 do {
1392 char *tmp;
1393 int end;
1396 f = fontset;
1397 ptr = strchr(fontset, ',');
1398 if (ptr) {
1399 int count = ptr-fontset;
1401 if (count > 255) {
1402 wwarning(_("font description %s is too large."), fontset);
1403 } else {
1404 memcpy(font, fontset, count);
1405 font[count] = 0;
1406 f = (char*)font;
1410 if (newfs)
1411 end = strlen(newfs);
1412 else
1413 end = 0;
1415 tmp = wmalloc(end + strlen(f) + 8);
1416 if (end != 0) {
1417 sprintf(tmp, "%s,", newfs);
1418 sprintf(tmp + end + 1, f, size);
1419 } else {
1420 sprintf(tmp + end, f, size);
1423 if (newfs)
1424 wfree(newfs);
1425 newfs = tmp;
1427 fontset = ptr+1;
1428 } while (ptr!=NULL);
1430 return newfs;
1434 #define FONT_PROPS 14
1436 typedef struct {
1437 char *props[FONT_PROPS];
1438 } W_FontAttributes;
1441 static void
1442 changeFontProp(char *buf, char *newprop, int position)
1444 char buf2[512];
1445 char *ptr, *pptr, *rptr;
1446 int count;
1448 if (buf[0]!='-') {
1449 /* // remove warning later. or maybe not */
1450 wwarning(_("Invalid font specification: '%s'\n"), buf);
1451 return;
1454 ptr = pptr = rptr = buf;
1455 count = 0;
1456 while (*ptr && *ptr!=',') {
1457 if (*ptr == '-') {
1458 count++;
1459 if (count-1==position+1) {
1460 rptr = ptr;
1461 break;
1463 if (count-1==position) {
1464 pptr = ptr+1;
1467 ptr++;
1469 if (position==FONT_PROPS-1) {
1470 rptr = ptr;
1473 *pptr = 0;
1474 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
1475 strcpy(buf, buf2);
1479 static WMArray*
1480 getOptions(char *options)
1482 char *ptr, *ptr2, *str;
1483 WMArray *result;
1484 int count;
1486 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
1488 ptr = options;
1489 while (1) {
1490 ptr2 = strchr(ptr, ',');
1491 if (!ptr2) {
1492 WMAddToArray(result, wstrdup(ptr));
1493 break;
1494 } else {
1495 count = ptr2 - ptr;
1496 str = wmalloc(count+1);
1497 memcpy(str, ptr, count);
1498 str[count] = 0;
1499 WMAddToArray(result, str);
1500 ptr = ptr2 + 1;
1504 return result;
1508 #define WFAUnchanged (NULL)
1509 /* Struct for font change operations */
1510 typedef struct WMFontAttributes {
1511 char *foundry;
1512 char *family;
1513 char *weight;
1514 char *slant;
1515 char *setWidth;
1516 char *addStyle;
1517 char *pixelSize;
1518 char *pointSize;
1519 char *resolutionX;
1520 char *resolutionY;
1521 char *spacing;
1522 char *averageWidth;
1523 char *registry;
1524 char *encoding;
1525 } WMFontAttributes;
1527 WMFont*
1528 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
1529 const WMFontAttributes *changes)
1531 int index[FONT_PROPS], count[FONT_PROPS];
1532 int totalProps, i, j, carry;
1533 char fname[512];
1534 WMFontFlags fFlags;
1535 WMBag *props;
1536 WMArray *options;
1537 WMFont *result;
1538 char *prop;
1540 snprintf(fname, 512, "%s", font->name);
1542 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
1543 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
1545 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
1547 totalProps = 0;
1548 for (i=0; i<FONT_PROPS; i++) {
1549 prop = ((W_FontAttributes*)changes)->props[i];
1550 count[i] = index[i] = 0;
1551 if (!prop) {
1552 /* No change for this property */
1553 continue;
1554 } else if (strchr(prop, ',')==NULL) {
1555 /* Simple option */
1556 changeFontProp(fname, prop, i);
1557 } else {
1558 /* Option with fallback alternatives */
1559 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1560 font->antialiased && strcmp(prop, "o,i")==0) {
1561 options = getOptions("i,o");
1562 } else {
1563 options = getOptions(prop);
1565 WMInsertInBag(props, i, options);
1566 count[i] = WMGetArrayItemCount(options);
1567 if (totalProps==0)
1568 totalProps = 1;
1569 totalProps = totalProps * count[i];
1573 if (totalProps == 0) {
1574 /* No options with fallback alternatives at all */
1575 WMFreeBag(props);
1576 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1579 for (i=0; i<totalProps; i++) {
1580 for (j=0; j<FONT_PROPS; j++) {
1581 if (count[j]!=0) {
1582 options = WMGetFromBag(props, j);
1583 prop = WMGetFromArray(options, index[j]);
1584 if (prop) {
1585 changeFontProp(fname, prop, j);
1589 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1590 if (result) {
1591 WMFreeBag(props);
1592 return result;
1594 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1595 if (count[j]!=0) {
1596 index[j] += carry;
1597 carry = (index[j]==count[j]);
1598 index[j] %= count[j];
1603 WMFreeBag(props);
1605 return NULL;
1608 // should WFANormal also set "normal" or leave it alone?
1609 static const WMFontAttributes W_FANormal = {
1610 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1611 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1612 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1616 static const WMFontAttributes W_FABold = {
1617 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1618 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1619 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1623 static const WMFontAttributes W_FANotBold = {
1624 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1625 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1626 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1630 static const WMFontAttributes W_FAEmphasized = {
1631 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1632 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1633 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1637 static const WMFontAttributes W_FANotEmphasized = {
1638 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1639 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1640 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1644 static const WMFontAttributes W_FABoldEmphasized = {
1645 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1646 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1647 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1651 const WMFontAttributes *WFANormal = &W_FANormal;
1652 const WMFontAttributes *WFABold = &W_FABold;
1653 const WMFontAttributes *WFANotBold = &W_FANotBold;
1654 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1655 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1656 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;
1659 #endif