Started to move towards using xft2 only, for a unified font/locale handling
[wmaker-crm.git] / WINGs / wfont.c
blob47d8715278481d9604c6d29c2c2ccfb27feadf77
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>
20 static char *makeFontSetOfSize(char *fontset, int size);
24 /* XLFD pattern matching */
25 static char*
26 getElementFromXLFD(const char *xlfd, int index)
28 const char *p = xlfd;
29 while (*p != 0) {
30 if (*p == '-' && --index == 0) {
31 const char *end = strchr(p + 1, '-');
32 char *buf;
33 size_t len;
34 if (end == 0) end = p + strlen(p);
35 len = end - (p + 1);
36 buf = wmalloc(len);
37 memcpy(buf, p + 1, len);
38 buf[len] = 0;
39 return buf;
41 p++;
43 return strdup("*");
47 /* XLFD pattern matching */
48 static char*
49 generalizeXLFD(const char *xlfd)
51 char *buf;
52 int len;
53 char *weight = getElementFromXLFD(xlfd, 3);
54 char *slant = getElementFromXLFD(xlfd, 4);
55 char *pxlsz = getElementFromXLFD(xlfd, 7);
57 #define Xstrlen(A) ((A)?strlen(A):0)
58 len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60;
59 #undef Xstrlen
61 buf = wmalloc(len + 1);
62 snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*,"
63 "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*",
64 xlfd, weight, slant, pxlsz, pxlsz);
66 wfree(pxlsz);
67 wfree(slant);
68 wfree(weight);
70 return buf;
73 /* XLFD pattern matching */
74 static XFontSet
75 W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing,
76 int *nmissing, char **def_string)
78 XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
80 if (fs != NULL && *nmissing == 0) return fs;
82 /* for non-iso8859-1 language and iso8859-1 specification
83 (this fontset is only for pattern analysis) */
84 if (fs == NULL) {
85 if (*nmissing != 0) XFreeStringList(*missing);
86 setlocale(LC_CTYPE, "C");
87 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
88 setlocale(LC_CTYPE, "");
91 /* make XLFD font name for pattern analysis */
92 if (fs != NULL) {
93 XFontStruct **fontstructs;
94 char **fontnames;
95 if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0)
96 xlfd = fontnames[0];
99 xlfd = generalizeXLFD(xlfd);
101 if (*nmissing != 0) XFreeStringList(*missing);
102 if (fs != NULL) XFreeFontSet(dpy, fs);
104 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
106 wfree(xlfd);
107 return fs;
111 static char*
112 xlfdFromFontName(char *fontName, Bool antialiased)
114 char *systemFont, *boldSystemFont;
115 char *font;
116 int size;
118 if (antialiased) {
119 systemFont = WINGsConfiguration.antialiasedSystemFont;
120 boldSystemFont = WINGsConfiguration.antialiasedBoldSystemFont;
121 } else {
122 systemFont = WINGsConfiguration.systemFont;
123 boldSystemFont = WINGsConfiguration.boldSystemFont;
126 size = WINGsConfiguration.defaultFontSize;
128 if (strcmp(fontName, "SystemFont")==0) {
129 font = systemFont;
130 size = WINGsConfiguration.defaultFontSize;
131 } else if (strncmp(fontName, "SystemFont-", 11)==0) {
132 font = systemFont;
133 if (sscanf(&fontName[11], "%i", &size)!=1) {
134 size = WINGsConfiguration.defaultFontSize;
135 wwarning(_("Invalid size specification '%s' in %s. "
136 "Using default %d\n"), &fontName[11], fontName, size);
138 } else if (strcmp(fontName, "BoldSystemFont")==0) {
139 font = boldSystemFont;
140 size = WINGsConfiguration.defaultFontSize;
141 } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) {
142 font = boldSystemFont;
143 if (sscanf(&fontName[15], "%i", &size)!=1) {
144 size = WINGsConfiguration.defaultFontSize;
145 wwarning(_("Invalid size specification '%s' in %s. "
146 "Using default %d\n"), &fontName[15], fontName, size);
148 } else {
149 font = NULL;
152 return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName));
156 WMFont*
157 WMCreateFontSet(WMScreen *scrPtr, char *fontName)
159 WMFont *font;
160 Display *display = scrPtr->display;
161 char **missing;
162 int nmissing = 0;
163 char *defaultString;
164 char *fname;
165 XFontSetExtents *extents;
167 fname = xlfdFromFontName(fontName, False);
169 font = WMHashGet(scrPtr->fontSetCache, fname);
170 if (font) {
171 WMRetainFont(font);
172 wfree(fname);
173 return font;
176 font = wmalloc(sizeof(WMFont));
177 memset(font, 0, sizeof(WMFont));
179 font->notFontSet = 0;
180 font->antialiased = 0;
182 font->screen = scrPtr;
184 font->font.set = W_CreateFontSetWithGuess(display, fname, &missing,
185 &nmissing, &defaultString);
186 if (nmissing > 0 && font->font.set) {
187 int i;
189 wwarning(_("the following character sets are missing in %s:"), fname);
190 for (i = 0; i < nmissing; i++) {
191 wwarning(missing[i]);
193 XFreeStringList(missing);
194 if (defaultString)
195 wwarning(_("the string \"%s\" will be used in place of any characters from those sets."),
196 defaultString);
198 if (!font->font.set) {
199 wfree(font);
200 wfree(fname);
201 return NULL;
204 extents = XExtentsOfFontSet(font->font.set);
206 font->height = extents->max_logical_extent.height;
207 font->y = font->height - (font->height + extents->max_logical_extent.y);
209 font->refCount = 1;
211 font->name = fname;
213 assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL);
215 return font;
220 WMFont*
221 WMCreateNormalFont(WMScreen *scrPtr, char *fontName)
223 WMFont *font;
224 Display *display = scrPtr->display;
225 char *fname, *ptr;
227 fontName = xlfdFromFontName(fontName, False);
229 if ((ptr = strchr(fontName, ','))) {
230 fname = wmalloc(ptr - fontName + 1);
231 strncpy(fname, fontName, ptr - fontName);
232 fname[ptr - fontName] = 0;
233 } else {
234 fname = wstrdup(fontName);
237 wfree(fontName);
239 font = WMHashGet(scrPtr->fontCache, fname);
240 if (font) {
241 WMRetainFont(font);
242 wfree(fname);
243 return font;
246 font = wmalloc(sizeof(WMFont));
247 memset(font, 0, sizeof(WMFont));
249 font->notFontSet = 1;
250 font->antialiased = 0;
252 font->screen = scrPtr;
254 font->font.normal = XLoadQueryFont(display, fname);
255 if (!font->font.normal) {
256 wfree(font);
257 wfree(fname);
258 return NULL;
260 font->height = font->font.normal->ascent+font->font.normal->descent;
261 font->y = font->font.normal->ascent;
263 font->refCount = 1;
265 font->name = fname;
267 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
269 return font;
273 WMFont*
274 WMCreateAntialiasedFont(WMScreen *scrPtr, char *fontName)
276 #ifdef XFT
277 WMFont *font;
278 Display *display = scrPtr->display;
279 char *fname, *ptr;
281 fontName = xlfdFromFontName(fontName, True);
283 if ((ptr = strchr(fontName, ','))) {
284 fname = wmalloc(ptr - fontName + 1);
285 strncpy(fname, fontName, ptr - fontName);
286 fname[ptr - fontName] = 0;
287 } else {
288 fname = wstrdup(fontName);
291 wfree(fontName);
293 font = WMHashGet(scrPtr->xftFontCache, fname);
294 if (font) {
295 WMRetainFont(font);
296 wfree(fname);
297 return font;
300 font = wmalloc(sizeof(WMFont));
301 memset(font, 0, sizeof(WMFont));
303 font->notFontSet = 1;
304 font->antialiased = 1;
306 font->screen = scrPtr;
308 /* Xft sux. Loading a font with an invalid XLFD will give strange results
309 * sometimes without returning any warning or error.
310 * However Xft's idea of what font is invalid is quite strange:
311 * 1. If the XLFD doesn't have all its fields present will fail and
312 * return NULL.
313 * 2. If all fields are present, but hold invalid values then it will:
314 * a. If family is invalid, will load a default font without warning.
315 * b. If the font size is invalid (non-numerical) it will fail and
316 * return NULL.
317 * c. If other fields are invalid, will load the font specified by
318 * the valid family name, ignoring any invalid fields. It will
319 * use a default medium weight and a default roman slant if they
320 * are invalid.
322 printf("%s\n", fname);
323 if (fname[0] == '-') {
324 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
325 } else {
326 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
328 if (!font->font.xft) {
329 wfree(font);
330 wfree(fname);
331 return NULL;
333 font->height = font->font.xft->ascent+font->font.xft->descent;
334 font->y = font->font.xft->ascent;
336 font->refCount = 1;
338 font->name = fname;
340 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
342 return font;
343 #else
344 return NULL;
345 #endif
349 WMFont*
350 WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName)
352 #ifdef XFT
353 WMFont *font;
354 Display *display = scrPtr->display;
355 char *fname, *ptr;
357 fontName = xlfdFromFontName(fontName, True);
359 if ((ptr = strchr(fontName, ','))) {
360 fname = wmalloc(ptr - fontName + 1);
361 strncpy(fname, fontName, ptr - fontName);
362 fname[ptr - fontName] = 0;
363 } else {
364 fname = wstrdup(fontName);
367 wfree(fontName);
369 font = WMHashGet(scrPtr->xftFontSetCache, fname);
370 if (font) {
371 WMRetainFont(font);
372 wfree(fname);
373 return font;
376 font = wmalloc(sizeof(WMFont));
377 memset(font, 0, sizeof(WMFont));
379 font->notFontSet = 0;
380 font->antialiased = 1;
382 font->screen = scrPtr;
384 /* Xft sux. Loading a font with an invalid XLFD will give strange results
385 * sometimes without returning any warning or error.
386 * However Xft's idea of what font is invalid is quite strange:
387 * 1. If the XLFD doesn't have all its fields present will fail and
388 * return NULL.
389 * 2. If all fields are present, but hold invalid values then it will:
390 * a. If family is invalid, will load a default font without warning.
391 * b. If the font size is invalid (non-numerical) it will fail and
392 * return NULL.
393 * c. If other fields are invalid, will load the font specified by
394 * the valid family name, ignoring any invalid fields. It will
395 * use a default medium weight and a default roman slant if they
396 * are invalid.
398 if (fname[0] == '-') {
399 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
400 } else {
401 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
403 if (!font->font.xft) {
404 wfree(font);
405 wfree(fname);
406 return NULL;
408 font->height = font->font.xft->ascent+font->font.xft->descent;
409 font->y = font->font.xft->ascent;
411 font->refCount = 1;
413 font->name = fname;
415 assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL);
417 return font;
418 #else
419 return NULL;
420 #endif
424 WMFont*
425 WMCreateFont(WMScreen *scrPtr, char *fontName)
427 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
431 WMFont*
432 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
434 Bool multiByte = scrPtr->useMultiByte;
435 Bool antialiased = scrPtr->antialiasedText;
436 WMFont *font;
438 if (flags & WFFontSet) {
439 multiByte = True;
440 } else if (flags & WFNormalFont) {
441 multiByte = False;
443 if (flags & WFAntialiased) {
444 antialiased = True;
445 } else if (flags & WFNotAntialiased) {
446 antialiased = False;
449 if (antialiased && multiByte) {
450 font = WMCreateAntialiasedFontSet(scrPtr, fontName);
451 /* If we cannot create an antialiased font set and antialiasing is
452 * not explicitly requested in flags, fallback to standard font sets */
453 if (!font && (flags & WFAntialiased)==0) {
454 font = WMCreateFontSet(scrPtr, fontName);
456 } else if (antialiased) {
457 font = WMCreateAntialiasedFont(scrPtr, fontName);
458 /* If we cannot create an antialiased font and antialiasing is
459 * not explicitly requested in flags, fallback to normal font */
460 if (!font && (flags & WFAntialiased)==0) {
461 font = WMCreateNormalFont(scrPtr, fontName);
463 } else if (multiByte) {
464 font = WMCreateFontSet(scrPtr, fontName);
465 } else {
466 font = WMCreateNormalFont(scrPtr, fontName);
469 return font;
473 WMFont*
474 WMRetainFont(WMFont *font)
476 wassertrv(font!=NULL, NULL);
478 font->refCount++;
480 return font;
484 void
485 WMReleaseFont(WMFont *font)
487 wassertr(font!=NULL);
489 font->refCount--;
490 if (font->refCount < 1) {
491 if (font->antialiased) {
492 #ifdef XFT
493 XftFontClose(font->screen->display, font->font.xft);
494 #else
495 assert(False);
496 #endif
497 } else if (font->notFontSet) {
498 XFreeFont(font->screen->display, font->font.normal);
499 } else {
500 XFreeFontSet(font->screen->display, font->font.set);
503 if (font->name) {
504 if (font->antialiased && !font->notFontSet) {
505 WMHashRemove(font->screen->xftFontSetCache, font->name);
506 } else if (font->antialiased) {
507 WMHashRemove(font->screen->xftFontCache, font->name);
508 } else if (font->notFontSet) {
509 WMHashRemove(font->screen->fontCache, font->name);
510 } else {
511 WMHashRemove(font->screen->fontSetCache, font->name);
513 wfree(font->name);
515 wfree(font);
520 Bool
521 WMIsAntialiasingEnabled(WMScreen *scrPtr)
523 return scrPtr->antialiasedText;
527 Bool
528 WMIsAntialiasedFont(WMFont *font)
530 wassertrv(font!=NULL, False);
532 return font->antialiased;
536 unsigned int
537 WMFontHeight(WMFont *font)
539 wassertrv(font!=NULL, 0);
541 return font->height;
545 char*
546 WMGetFontName(WMFont *font)
548 wassertrv(font!=NULL, NULL);
550 return font->name;
554 WMFont*
555 WMDefaultSystemFont(WMScreen *scrPtr)
557 return WMRetainFont(scrPtr->normalFont);
561 WMFont*
562 WMDefaultBoldSystemFont(WMScreen *scrPtr)
564 return WMRetainFont(scrPtr->boldFont);
568 static WMFont*
569 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
571 WMFont *font;
572 char *fontSpec, *xftFontSpec;
574 #define WConf WINGsConfiguration
575 if (bold) {
576 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
577 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
578 } else {
579 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
580 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
582 #undef WConf
584 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
585 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
586 } else if (scrPtr->antialiasedText) {
587 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
588 } else if (scrPtr->useMultiByte) {
589 font = WMCreateFontSet(scrPtr, fontSpec);
590 } else {
591 font = WMCreateNormalFont(scrPtr, fontSpec);
594 if (!font) {
595 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
596 // is arial a good fallback for multibyte?
597 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
598 if (bold) {
599 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
600 } else {
601 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
603 if (!font) {
604 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
605 font = WMCreateFontSet(scrPtr, fontSpec);
606 if (!font) {
607 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
608 font = WMCreateFontSet(scrPtr, "fixed");
611 } else if (scrPtr->antialiasedText) {
612 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
613 if (bold) {
614 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
615 } else {
616 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
618 if (!font) {
619 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
620 font = WMCreateNormalFont(scrPtr, fontSpec);
621 if (!font) {
622 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
623 font = WMCreateNormalFont(scrPtr, "fixed");
626 } else if (scrPtr->useMultiByte) {
627 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
628 font = WMCreateFontSet(scrPtr, "fixed");
629 if (!font) {
630 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
632 } else {
633 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
634 font = WMCreateNormalFont(scrPtr, "fixed");
636 if (!font) {
637 wwarning(_("could not load fixed font!"));
638 wfree(fontSpec);
639 wfree(xftFontSpec);
640 return NULL;
643 wfree(fontSpec);
644 wfree(xftFontSpec);
646 return font;
650 WMFont*
651 WMSystemFontOfSize(WMScreen *scrPtr, int size)
653 return makeSystemFontOfSize(scrPtr, size, False);
657 WMFont*
658 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
660 return makeSystemFontOfSize(scrPtr, size, True);
664 XFontSet
665 WMGetFontFontSet(WMFont *font)
667 wassertrv(font!=NULL, NULL);
669 if (!font->notFontSet && !font->antialiased)
670 return font->font.set;
672 return NULL;
677 WMWidthOfString(WMFont *font, char *text, int length)
679 wassertrv(font!=NULL, 0);
680 wassertrv(text!=NULL, 0);
682 if (font->antialiased) {
683 #ifdef XFT
684 XGlyphInfo extents;
686 if (!font->notFontSet) {
687 wchar_t *wtext;
688 char *mtext;
689 int len;
691 /* Use mtext instead of text, because mbstrtowcs() alters it */
692 mtext = text;
693 wtext = (wchar_t *)wmalloc(4*length+4);
694 /* pass a real ps instead of NULL below? for multithread safety
695 * as from manual page */
696 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
697 if (len>0) {
698 XftTextExtents32(font->screen->display, font->font.xft,
699 (XftChar32 *)wtext, len, &extents);
700 } else {
701 if (len==-1) {
702 wwarning(_("Conversion to widechar failed (possible "
703 "invalid multibyte sequence): '%s':(pos %d)\n"),
704 text, mtext-text+1);
706 extents.xOff = 0;
708 wfree(wtext);
709 } else {
710 XftTextExtents8(font->screen->display, font->font.xft,
711 (XftChar8 *)text, length, &extents);
714 return extents.xOff; /* don't ask :P */
715 #else
716 wassertrv(False, 0);
717 #endif
718 } else if (font->notFontSet) {
719 return XTextWidth(font->font.normal, text, length);
720 } else {
721 XRectangle rect;
722 XRectangle AIXsucks;
724 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
726 return rect.width;
732 void
733 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
734 int x, int y, char *text, int length)
736 wassertr(font!=NULL);
738 if (font->antialiased) {
739 #ifdef XFT
740 XftColor xftcolor;
742 xftcolor.color.red = color->color.red;
743 xftcolor.color.green = color->color.green;
744 xftcolor.color.blue = color->color.blue;
745 xftcolor.color.alpha = color->alpha;;
746 xftcolor.pixel = W_PIXEL(color);
748 XftDrawChange(scr->xftdraw, d);
750 if (!font->notFontSet) {
751 wchar_t *wtext;
752 char *mtext;
753 int len;
755 /* Use mtext instead of text, because mbstrtowcs() alters it */
756 mtext = text;
757 wtext = (wchar_t *)wmalloc(4*length+4);
758 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
759 if (len>0) {
760 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
761 x, y + font->y, (XftChar32*)wtext, len);
762 } else if (len==-1) {
763 wwarning(_("Conversion to widechar failed (possible invalid "
764 "multibyte sequence): '%s':(pos %d)\n"),
765 text, mtext-text+1);
766 /* we can draw normal text, or we can draw as much widechar
767 * text as was already converted until the error. go figure */
768 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
769 x, y + font->y, (XftChar8*)text, length);*/
771 wfree(wtext);
772 } else {
773 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
774 x, y + font->y, (XftChar8*)text, length);
776 #else
777 wassertr(False);
778 #endif
779 } else if (font->notFontSet) {
780 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
781 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
782 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
783 text, length);
784 } else {
785 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
786 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
787 x, y + font->y, text, length);
792 void
793 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
794 WMFont *font, int x, int y, char *text, int length)
796 wassertr(font!=NULL);
798 if (font->antialiased) {
799 #ifdef XFT
800 XftColor textColor;
801 XftColor bgColor;
803 textColor.color.red = color->color.red;
804 textColor.color.green = color->color.green;
805 textColor.color.blue = color->color.blue;
806 textColor.color.alpha = color->alpha;;
807 textColor.pixel = W_PIXEL(color);
809 bgColor.color.red = background->color.red;
810 bgColor.color.green = background->color.green;
811 bgColor.color.blue = background->color.blue;
812 bgColor.color.alpha = background->alpha;;
813 bgColor.pixel = W_PIXEL(background);
816 XftDrawChange(scr->xftdraw, d);
818 XftDrawRect(scr->xftdraw, &bgColor, x, y,
819 WMWidthOfString(font, text, length), font->height);
821 if (!font->notFontSet) {
822 wchar_t *wtext;
823 char *mtext;
824 int len;
826 /* Use mtext instead of text, because mbstrtowcs() alters it */
827 mtext = text;
828 wtext = (wchar_t *)wmalloc(4*length+4);
829 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
830 if (len>0) {
831 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
832 x, y + font->y, (XftChar32*)wtext, len);
833 } else if (len==-1) {
834 wwarning(_("Conversion to widechar failed (possible invalid "
835 "multibyte sequence): '%s':(pos %d)\n"),
836 text, mtext-text+1);
837 /* we can draw normal text, or we can draw as much widechar
838 * text as was already converted until the error. go figure */
839 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
840 x, y + font->y, (XftChar8*)text, length);*/
842 wfree(wtext);
843 } else {
844 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
845 x, y + font->y, (XftChar8*)text, length);
847 #else
848 wassertr(False);
849 #endif
850 } else if (font->notFontSet) {
851 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
852 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
853 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
854 XDrawImageString(scr->display, d, scr->drawImStringGC,
855 x, y + font->y, text, length);
856 } else {
857 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
858 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
859 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
860 x, y + font->y, text, length);
867 static char*
868 makeFontSetOfSize(char *fontset, int size)
870 char font[300], *f;
871 char *newfs = NULL;
872 char *ptr;
874 do {
875 char *tmp;
876 int end;
879 f = fontset;
880 ptr = strchr(fontset, ',');
881 if (ptr) {
882 int count = ptr-fontset;
884 if (count > 255) {
885 wwarning(_("font description %s is too large."), fontset);
886 } else {
887 memcpy(font, fontset, count);
888 font[count] = 0;
889 f = (char*)font;
893 if (newfs)
894 end = strlen(newfs);
895 else
896 end = 0;
898 tmp = wmalloc(end + strlen(f) + 8);
899 if (end != 0) {
900 sprintf(tmp, "%s,", newfs);
901 sprintf(tmp + end + 1, f, size);
902 } else {
903 sprintf(tmp + end, f, size);
906 if (newfs)
907 wfree(newfs);
908 newfs = tmp;
910 fontset = ptr+1;
911 } while (ptr!=NULL);
913 return newfs;
917 #define FONT_PROPS 14
919 typedef struct {
920 char *props[FONT_PROPS];
921 } W_FontAttributes;
924 static void
925 changeFontProp(char *buf, char *newprop, int position)
927 char buf2[512];
928 char *ptr, *pptr, *rptr;
929 int count;
931 if (buf[0]!='-') {
932 /* // remove warning later. or maybe not */
933 wwarning(_("Invalid font specification: '%s'\n"), buf);
934 return;
937 ptr = pptr = rptr = buf;
938 count = 0;
939 while (*ptr && *ptr!=',') {
940 if (*ptr == '-') {
941 count++;
942 if (count-1==position+1) {
943 rptr = ptr;
944 break;
946 if (count-1==position) {
947 pptr = ptr+1;
950 ptr++;
952 if (position==FONT_PROPS-1) {
953 rptr = ptr;
956 *pptr = 0;
957 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
958 strcpy(buf, buf2);
962 static WMArray*
963 getOptions(char *options)
965 char *ptr, *ptr2, *str;
966 WMArray *result;
967 int count;
969 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
971 ptr = options;
972 while (1) {
973 ptr2 = strchr(ptr, ',');
974 if (!ptr2) {
975 WMAddToArray(result, wstrdup(ptr));
976 break;
977 } else {
978 count = ptr2 - ptr;
979 str = wmalloc(count+1);
980 memcpy(str, ptr, count);
981 str[count] = 0;
982 WMAddToArray(result, str);
983 ptr = ptr2 + 1;
987 return result;
991 WMFont*
992 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
993 const WMFontAttributes *changes)
995 int index[FONT_PROPS], count[FONT_PROPS];
996 int totalProps, i, j, carry;
997 char fname[512];
998 WMFontFlags fFlags;
999 WMBag *props;
1000 WMArray *options;
1001 WMFont *result;
1002 char *prop;
1004 snprintf(fname, 512, "%s", font->name);
1006 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
1007 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
1009 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
1011 totalProps = 0;
1012 for (i=0; i<FONT_PROPS; i++) {
1013 prop = ((W_FontAttributes*)changes)->props[i];
1014 count[i] = index[i] = 0;
1015 if (!prop) {
1016 /* No change for this property */
1017 continue;
1018 } else if (strchr(prop, ',')==NULL) {
1019 /* Simple option */
1020 changeFontProp(fname, prop, i);
1021 } else {
1022 /* Option with fallback alternatives */
1023 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1024 font->antialiased && strcmp(prop, "o,i")==0) {
1025 options = getOptions("i,o");
1026 } else {
1027 options = getOptions(prop);
1029 WMInsertInBag(props, i, options);
1030 count[i] = WMGetArrayItemCount(options);
1031 if (totalProps==0)
1032 totalProps = 1;
1033 totalProps = totalProps * count[i];
1037 if (totalProps == 0) {
1038 /* No options with fallback alternatives at all */
1039 WMFreeBag(props);
1040 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1043 for (i=0; i<totalProps; i++) {
1044 for (j=0; j<FONT_PROPS; j++) {
1045 if (count[j]!=0) {
1046 options = WMGetFromBag(props, j);
1047 prop = WMGetFromArray(options, index[j]);
1048 if (prop) {
1049 changeFontProp(fname, prop, j);
1053 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1054 if (result) {
1055 WMFreeBag(props);
1056 return result;
1058 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1059 if (count[j]!=0) {
1060 index[j] += carry;
1061 carry = (index[j]==count[j]);
1062 index[j] %= count[j];
1067 WMFreeBag(props);
1069 return NULL;
1074 // should WFANormal also set "normal" or leave it alone?
1075 static const WMFontAttributes W_FANormal = {
1076 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1077 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1078 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1082 static const WMFontAttributes W_FABold = {
1083 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1084 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1085 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1089 static const WMFontAttributes W_FANotBold = {
1090 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1091 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1092 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1096 static const WMFontAttributes W_FAEmphasized = {
1097 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1098 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1099 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1103 static const WMFontAttributes W_FANotEmphasized = {
1104 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1105 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1106 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1110 static const WMFontAttributes W_FABoldEmphasized = {
1111 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1112 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1113 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1117 const WMFontAttributes *WFANormal = &W_FANormal;
1118 const WMFontAttributes *WFABold = &W_FABold;
1119 const WMFontAttributes *WFANotBold = &W_FANotBold;
1120 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1121 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1122 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;