e61e50fb895958b7f81405a4c5e46656a013d10b
[wmaker-crm.git] / WINGs / wfont.c
blobe61e50fb895958b7f81405a4c5e46656a013d10b
2 #include "wconfig.h"
4 #ifdef XFT
5 # include <X11/Xft/Xft.h>
6 #endif
8 #include "WINGsP.h"
11 #include <wraster.h>
12 #include <assert.h>
13 #include <X11/Xlocale.h>
15 #include <wchar.h>
18 static char *makeFontSetOfSize(char *fontset, int size);
22 /* XLFD pattern matching */
23 static char*
24 getElementFromXLFD(const char *xlfd, int index)
26 const char *p = xlfd;
27 while (*p != 0) {
28 if (*p == '-' && --index == 0) {
29 const char *end = strchr(p + 1, '-');
30 char *buf;
31 size_t len;
32 if (end == 0) end = p + strlen(p);
33 len = end - (p + 1);
34 buf = wmalloc(len);
35 memcpy(buf, p + 1, len);
36 buf[len] = 0;
37 return buf;
39 p++;
41 return strdup("*");
45 /* XLFD pattern matching */
46 static char*
47 generalizeXLFD(const char *xlfd)
49 char *buf;
50 int len;
51 char *weight = getElementFromXLFD(xlfd, 3);
52 char *slant = getElementFromXLFD(xlfd, 4);
53 char *pxlsz = getElementFromXLFD(xlfd, 7);
55 #define Xstrlen(A) ((A)?strlen(A):0)
56 len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60;
57 #undef Xstrlen
59 buf = wmalloc(len + 1);
60 snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*,"
61 "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*",
62 xlfd, weight, slant, pxlsz, pxlsz);
64 wfree(pxlsz);
65 wfree(slant);
66 wfree(weight);
68 return buf;
71 /* XLFD pattern matching */
72 static XFontSet
73 W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing,
74 int *nmissing, char **def_string)
76 XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
78 if (fs != NULL && *nmissing == 0) return fs;
80 /* for non-iso8859-1 language and iso8859-1 specification
81 (this fontset is only for pattern analysis) */
82 if (fs == NULL) {
83 if (*nmissing != 0) XFreeStringList(*missing);
84 setlocale(LC_CTYPE, "C");
85 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
86 setlocale(LC_CTYPE, "");
89 /* make XLFD font name for pattern analysis */
90 if (fs != NULL) {
91 XFontStruct **fontstructs;
92 char **fontnames;
93 if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0)
94 xlfd = fontnames[0];
97 xlfd = generalizeXLFD(xlfd);
99 if (*nmissing != 0) XFreeStringList(*missing);
100 if (fs != NULL) XFreeFontSet(dpy, fs);
102 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
104 wfree(xlfd);
105 return fs;
109 static char*
110 xlfdFromFontName(char *fontName, Bool antialiased)
112 char *systemFont, *boldSystemFont;
113 char *font;
114 int size;
116 if (antialiased) {
117 systemFont = WINGsConfiguration.antialiasedSystemFont;
118 boldSystemFont = WINGsConfiguration.antialiasedBoldSystemFont;
119 } else {
120 systemFont = WINGsConfiguration.systemFont;
121 boldSystemFont = WINGsConfiguration.boldSystemFont;
124 size = WINGsConfiguration.defaultFontSize;
126 if (strcmp(fontName, "SystemFont")==0) {
127 font = systemFont;
128 size = WINGsConfiguration.defaultFontSize;
129 } else if (strncmp(fontName, "SystemFont-", 11)==0) {
130 font = systemFont;
131 if (sscanf(&fontName[11], "%i", &size)!=1) {
132 size = WINGsConfiguration.defaultFontSize;
133 wwarning(_("Invalid size specification '%s' in %s. "
134 "Using default %d\n"), &fontName[11], fontName, size);
136 } else if (strcmp(fontName, "BoldSystemFont")==0) {
137 font = boldSystemFont;
138 size = WINGsConfiguration.defaultFontSize;
139 } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) {
140 font = boldSystemFont;
141 if (sscanf(&fontName[15], "%i", &size)!=1) {
142 size = WINGsConfiguration.defaultFontSize;
143 wwarning(_("Invalid size specification '%s' in %s. "
144 "Using default %d\n"), &fontName[15], fontName, size);
146 } else {
147 font = NULL;
150 return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName));
154 WMFont*
155 WMCreateFontSet(WMScreen *scrPtr, char *fontName)
157 WMFont *font;
158 Display *display = scrPtr->display;
159 char **missing;
160 int nmissing = 0;
161 char *defaultString;
162 char *fname;
163 XFontSetExtents *extents;
165 fname = xlfdFromFontName(fontName, False);
167 font = WMHashGet(scrPtr->fontSetCache, fname);
168 if (font) {
169 WMRetainFont(font);
170 wfree(fname);
171 return font;
174 font = wmalloc(sizeof(WMFont));
175 memset(font, 0, sizeof(WMFont));
177 font->notFontSet = 0;
178 font->antialiased = 0;
180 font->screen = scrPtr;
182 font->font.set = W_CreateFontSetWithGuess(display, fname, &missing,
183 &nmissing, &defaultString);
184 if (nmissing > 0 && font->font.set) {
185 int i;
187 wwarning(_("the following character sets are missing in %s:"), fname);
188 for (i = 0; i < nmissing; i++) {
189 wwarning(missing[i]);
191 XFreeStringList(missing);
192 if (defaultString)
193 wwarning(_("the string \"%s\" will be used in place of any characters from those sets."),
194 defaultString);
196 if (!font->font.set) {
197 wfree(font);
198 wfree(fname);
199 return NULL;
202 extents = XExtentsOfFontSet(font->font.set);
204 font->height = extents->max_logical_extent.height;
205 font->y = font->height - (font->height + extents->max_logical_extent.y);
207 font->refCount = 1;
209 font->name = fname;
211 assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL);
213 return font;
218 WMFont*
219 WMCreateNormalFont(WMScreen *scrPtr, char *fontName)
221 WMFont *font;
222 Display *display = scrPtr->display;
223 char *fname, *ptr;
225 fontName = xlfdFromFontName(fontName, False);
227 if ((ptr = strchr(fontName, ','))) {
228 fname = wmalloc(ptr - fontName + 1);
229 strncpy(fname, fontName, ptr - fontName);
230 fname[ptr - fontName] = 0;
231 } else {
232 fname = wstrdup(fontName);
235 wfree(fontName);
237 font = WMHashGet(scrPtr->fontCache, fname);
238 if (font) {
239 WMRetainFont(font);
240 wfree(fname);
241 return font;
244 font = wmalloc(sizeof(WMFont));
245 memset(font, 0, sizeof(WMFont));
247 font->notFontSet = 1;
248 font->antialiased = 0;
250 font->screen = scrPtr;
252 font->font.normal = XLoadQueryFont(display, fname);
253 if (!font->font.normal) {
254 wfree(font);
255 wfree(fname);
256 return NULL;
258 font->height = font->font.normal->ascent+font->font.normal->descent;
259 font->y = font->font.normal->ascent;
261 font->refCount = 1;
263 font->name = fname;
265 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
267 return font;
271 WMFont*
272 WMCreateAntialiasedFont(WMScreen *scrPtr, char *fontName)
274 #ifdef XFT
275 WMFont *font;
276 Display *display = scrPtr->display;
277 char *fname, *ptr;
279 if (!scrPtr->hasXftSupport)
280 return NULL;
282 fontName = xlfdFromFontName(fontName, True);
284 if ((ptr = strchr(fontName, ','))) {
285 fname = wmalloc(ptr - fontName + 1);
286 strncpy(fname, fontName, ptr - fontName);
287 fname[ptr - fontName] = 0;
288 } else {
289 fname = wstrdup(fontName);
292 wfree(fontName);
294 font = WMHashGet(scrPtr->xftFontCache, fname);
295 if (font) {
296 WMRetainFont(font);
297 wfree(fname);
298 return font;
301 font = wmalloc(sizeof(WMFont));
302 memset(font, 0, sizeof(WMFont));
304 font->notFontSet = 1;
305 font->antialiased = 1;
307 font->screen = scrPtr;
309 /* Xft sux. Loading a font with an invalid XLFD will give strange results
310 * sometimes without returning any warning or error.
311 * However Xft's idea of what font is invalid is quite strange:
312 * 1. If the XLFD doesn't have all its fields present will fail and
313 * return NULL.
314 * 2. If all fields are present, but hold invalid values then it will:
315 * a. If family is invalid, will load a default font without warning.
316 * b. If the font size is invalid (non-numerical) it will fail and
317 * return NULL.
318 * c. If other fields are invalid, will load the font specified by
319 * the valid family name, ignoring any invalid fields. It will
320 * use a default medium weight and a default roman slant if they
321 * are invalid.
323 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
324 if (!font->font.xft) {
325 wfree(font);
326 wfree(fname);
327 return NULL;
329 font->height = font->font.xft->ascent+font->font.xft->descent;
330 font->y = font->font.xft->ascent;
332 font->refCount = 1;
334 font->name = fname;
336 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
338 return font;
339 #else
340 return NULL;
341 #endif
345 WMFont*
346 WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName)
348 #ifdef XFT
349 WMFont *font;
350 Display *display = scrPtr->display;
351 char *fname, *ptr;
353 if (!scrPtr->hasXftSupport)
354 return NULL;
356 fontName = xlfdFromFontName(fontName, True);
358 if ((ptr = strchr(fontName, ','))) {
359 fname = wmalloc(ptr - fontName + 1);
360 strncpy(fname, fontName, ptr - fontName);
361 fname[ptr - fontName] = 0;
362 } else {
363 fname = wstrdup(fontName);
366 wfree(fontName);
368 font = WMHashGet(scrPtr->xftFontSetCache, fname);
369 if (font) {
370 WMRetainFont(font);
371 wfree(fname);
372 return font;
375 font = wmalloc(sizeof(WMFont));
376 memset(font, 0, sizeof(WMFont));
378 font->notFontSet = 0;
379 font->antialiased = 1;
381 font->screen = scrPtr;
383 /* Xft sux. Loading a font with an invalid XLFD will give strange results
384 * sometimes without returning any warning or error.
385 * However Xft's idea of what font is invalid is quite strange:
386 * 1. If the XLFD doesn't have all its fields present will fail and
387 * return NULL.
388 * 2. If all fields are present, but hold invalid values then it will:
389 * a. If family is invalid, will load a default font without warning.
390 * b. If the font size is invalid (non-numerical) it will fail and
391 * return NULL.
392 * c. If other fields are invalid, will load the font specified by
393 * the valid family name, ignoring any invalid fields. It will
394 * use a default medium weight and a default roman slant if they
395 * are invalid.
397 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
398 if (!font->font.xft) {
399 wfree(font);
400 wfree(fname);
401 return NULL;
403 font->height = font->font.xft->ascent+font->font.xft->descent;
404 font->y = font->font.xft->ascent;
406 font->refCount = 1;
408 font->name = fname;
410 assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL);
412 return font;
413 #else
414 return NULL;
415 #endif
419 WMFont*
420 WMCreateFont(WMScreen *scrPtr, char *fontName)
422 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
426 WMFont*
427 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
429 Bool multiByte = scrPtr->useMultiByte;
430 Bool antialiased = scrPtr->antialiasedText;
431 WMFont *font;
433 if (flags & WFFontSet) {
434 multiByte = True;
435 } else if (flags & WFNormalFont) {
436 multiByte = False;
438 if (flags & WFAntialiased) {
439 antialiased = True;
440 } else if (flags & WFNotAntialiased) {
441 antialiased = False;
444 if (antialiased && multiByte) {
445 font = WMCreateAntialiasedFontSet(scrPtr, fontName);
446 /* If we cannot create an antialiased font set and antialiasing is
447 * not explicitly requested in flags, fallback to standard font sets */
448 if (!font && (flags & WFAntialiased)==0) {
449 font = WMCreateFontSet(scrPtr, fontName);
451 } else if (antialiased) {
452 font = WMCreateAntialiasedFont(scrPtr, fontName);
453 /* If we cannot create an antialiased font and antialiasing is
454 * not explicitly requested in flags, fallback to normal font */
455 if (!font && (flags & WFAntialiased)==0) {
456 font = WMCreateNormalFont(scrPtr, fontName);
458 } else if (multiByte) {
459 font = WMCreateFontSet(scrPtr, fontName);
460 } else {
461 font = WMCreateNormalFont(scrPtr, fontName);
464 return font;
468 WMFont*
469 WMRetainFont(WMFont *font)
471 wassertrv(font!=NULL, NULL);
473 font->refCount++;
475 return font;
479 void
480 WMReleaseFont(WMFont *font)
482 wassertr(font!=NULL);
484 font->refCount--;
485 if (font->refCount < 1) {
486 if (font->antialiased) {
487 #ifdef XFT
488 XftFontClose(font->screen->display, font->font.xft);
489 #else
490 assert(False);
491 #endif
492 } else if (font->notFontSet) {
493 XFreeFont(font->screen->display, font->font.normal);
494 } else {
495 XFreeFontSet(font->screen->display, font->font.set);
498 if (font->name) {
499 if (font->antialiased && !font->notFontSet) {
500 WMHashRemove(font->screen->xftFontSetCache, font->name);
501 } else if (font->antialiased) {
502 WMHashRemove(font->screen->xftFontCache, font->name);
503 } else if (font->notFontSet) {
504 WMHashRemove(font->screen->fontCache, font->name);
505 } else {
506 WMHashRemove(font->screen->fontSetCache, font->name);
508 wfree(font->name);
510 wfree(font);
515 Bool
516 WMHasAntialiasingSupport(WMScreen *scrPtr)
518 return scrPtr->hasXftSupport;
522 Bool
523 WMIsAntialiasingEnabled(WMScreen *scrPtr)
525 return scrPtr->antialiasedText;
529 Bool
530 WMIsAntialiasedFont(WMFont *font)
532 wassertrv(font!=NULL, False);
534 return font->antialiased;
538 unsigned int
539 WMFontHeight(WMFont *font)
541 wassertrv(font!=NULL, 0);
543 return font->height;
547 char*
548 WMGetFontName(WMFont *font)
550 wassertrv(font!=NULL, NULL);
552 return font->name;
556 WMFont*
557 WMDefaultSystemFont(WMScreen *scrPtr)
559 return WMRetainFont(scrPtr->normalFont);
563 WMFont*
564 WMDefaultBoldSystemFont(WMScreen *scrPtr)
566 return WMRetainFont(scrPtr->boldFont);
570 static WMFont*
571 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
573 WMFont *font;
574 char *fontSpec, *xftFontSpec;
576 #define WConf WINGsConfiguration
577 if (bold) {
578 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
579 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
580 } else {
581 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
582 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
584 #undef WConf
586 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
587 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
588 } else if (scrPtr->antialiasedText) {
589 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
590 } else if (scrPtr->useMultiByte) {
591 font = WMCreateFontSet(scrPtr, fontSpec);
592 } else {
593 font = WMCreateNormalFont(scrPtr, fontSpec);
596 if (!font) {
597 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
598 // is arial a good fallback for multibyte?
599 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
600 if (bold) {
601 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
602 } else {
603 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
605 if (!font) {
606 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
607 font = WMCreateFontSet(scrPtr, fontSpec);
608 if (!font) {
609 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
610 font = WMCreateFontSet(scrPtr, "fixed");
613 } else if (scrPtr->antialiasedText) {
614 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
615 if (bold) {
616 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
617 } else {
618 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
620 if (!font) {
621 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
622 font = WMCreateNormalFont(scrPtr, fontSpec);
623 if (!font) {
624 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
625 font = WMCreateNormalFont(scrPtr, "fixed");
628 } else if (scrPtr->useMultiByte) {
629 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
630 font = WMCreateFontSet(scrPtr, "fixed");
631 if (!font) {
632 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
634 } else {
635 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
636 font = WMCreateNormalFont(scrPtr, "fixed");
638 if (!font) {
639 wwarning(_("could not load fixed font!"));
640 wfree(fontSpec);
641 wfree(xftFontSpec);
642 return NULL;
645 wfree(fontSpec);
646 wfree(xftFontSpec);
648 return font;
652 WMFont*
653 WMSystemFontOfSize(WMScreen *scrPtr, int size)
655 return makeSystemFontOfSize(scrPtr, size, False);
659 WMFont*
660 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
662 return makeSystemFontOfSize(scrPtr, size, True);
666 XFontSet
667 WMGetFontFontSet(WMFont *font)
669 wassertrv(font!=NULL, NULL);
671 if (!font->notFontSet && !font->antialiased)
672 return font->font.set;
674 return NULL;
679 WMWidthOfString(WMFont *font, char *text, int length)
681 wassertrv(font!=NULL, 0);
682 wassertrv(text!=NULL, 0);
684 if (font->antialiased) {
685 #ifdef XFT
686 XGlyphInfo extents;
688 if (!font->notFontSet) {
689 wchar_t *wtext;
690 char *mtext;
691 int len;
693 /* Use mtext instead of text, because mbstrtowcs() alters it */
694 mtext = text;
695 wtext = (wchar_t *)wmalloc(4*length+4);
696 /* pass a real ps instead of NULL below? for multithread safety
697 * as from manual page */
698 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
699 if (len>0) {
700 XftTextExtents32(font->screen->display, font->font.xft,
701 (XftChar32 *)wtext, len, &extents);
702 } else {
703 if (len==-1) {
704 wwarning(_("Conversion to widechar failed (possible "
705 "invalid multibyte sequence): '%s':(pos %d)\n"),
706 text, mtext-text+1);
708 extents.xOff = 0;
710 wfree(wtext);
711 } else {
712 XftTextExtents8(font->screen->display, font->font.xft,
713 (XftChar8 *)text, length, &extents);
716 return extents.xOff; /* don't ask :P */
717 #else
718 wassertrv(False, 0);
719 #endif
720 } else if (font->notFontSet) {
721 return XTextWidth(font->font.normal, text, length);
722 } else {
723 XRectangle rect;
724 XRectangle AIXsucks;
726 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
728 return rect.width;
734 void
735 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
736 int x, int y, char *text, int length)
738 wassertr(font!=NULL);
740 if (font->antialiased) {
741 #ifdef XFT
742 XftColor xftcolor;
744 xftcolor.color.red = color->color.red;
745 xftcolor.color.green = color->color.green;
746 xftcolor.color.blue = color->color.blue;
747 xftcolor.color.alpha = color->alpha;;
748 xftcolor.pixel = W_PIXEL(color);
750 XftDrawChange(scr->xftdraw, d);
752 if (!font->notFontSet) {
753 wchar_t *wtext;
754 char *mtext;
755 int len;
757 /* Use mtext instead of text, because mbstrtowcs() alters it */
758 mtext = text;
759 wtext = (wchar_t *)wmalloc(4*length+4);
760 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
761 if (len>0) {
762 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
763 x, y + font->y, (XftChar32*)wtext, len);
764 } else if (len==-1) {
765 wwarning(_("Conversion to widechar failed (possible invalid "
766 "multibyte sequence): '%s':(pos %d)\n"),
767 text, mtext-text+1);
768 /* we can draw normal text, or we can draw as much widechar
769 * text as was already converted until the error. go figure */
770 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
771 x, y + font->y, (XftChar8*)text, length);*/
773 wfree(wtext);
774 } else {
775 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
776 x, y + font->y, (XftChar8*)text, length);
778 #else
779 wassertr(False);
780 #endif
781 } else if (font->notFontSet) {
782 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
783 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
784 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
785 text, length);
786 } else {
787 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
788 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
789 x, y + font->y, text, length);
794 void
795 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
796 WMFont *font, int x, int y, char *text, int length)
798 wassertr(font!=NULL);
800 if (font->antialiased) {
801 #ifdef XFT
802 XftColor textColor;
803 XftColor bgColor;
805 textColor.color.red = color->color.red;
806 textColor.color.green = color->color.green;
807 textColor.color.blue = color->color.blue;
808 textColor.color.alpha = color->alpha;;
809 textColor.pixel = W_PIXEL(color);
811 bgColor.color.red = background->color.red;
812 bgColor.color.green = background->color.green;
813 bgColor.color.blue = background->color.blue;
814 bgColor.color.alpha = background->alpha;;
815 bgColor.pixel = W_PIXEL(background);
818 XftDrawChange(scr->xftdraw, d);
820 XftDrawRect(scr->xftdraw, &bgColor, x, y,
821 WMWidthOfString(font, text, length), font->height);
823 if (!font->notFontSet) {
824 wchar_t *wtext;
825 char *mtext;
826 int len;
828 /* Use mtext instead of text, because mbstrtowcs() alters it */
829 mtext = text;
830 wtext = (wchar_t *)wmalloc(4*length+4);
831 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
832 if (len>0) {
833 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
834 x, y + font->y, (XftChar32*)wtext, len);
835 } else if (len==-1) {
836 wwarning(_("Conversion to widechar failed (possible invalid "
837 "multibyte sequence): '%s':(pos %d)\n"),
838 text, mtext-text+1);
839 /* we can draw normal text, or we can draw as much widechar
840 * text as was already converted until the error. go figure */
841 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
842 x, y + font->y, (XftChar8*)text, length);*/
844 wfree(wtext);
845 } else {
846 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
847 x, y + font->y, (XftChar8*)text, length);
849 #else
850 wassertr(False);
851 #endif
852 } else if (font->notFontSet) {
853 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
854 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
855 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
856 XDrawImageString(scr->display, d, scr->drawImStringGC,
857 x, y + font->y, text, length);
858 } else {
859 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
860 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
861 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
862 x, y + font->y, text, length);
869 static char*
870 makeFontSetOfSize(char *fontset, int size)
872 char font[300], *f;
873 char *newfs = NULL;
874 char *ptr;
876 do {
877 char *tmp;
878 int end;
881 f = fontset;
882 ptr = strchr(fontset, ',');
883 if (ptr) {
884 int count = ptr-fontset;
886 if (count > 255) {
887 wwarning(_("font description %s is too large."), fontset);
888 } else {
889 memcpy(font, fontset, count);
890 font[count] = 0;
891 f = (char*)font;
895 if (newfs)
896 end = strlen(newfs);
897 else
898 end = 0;
900 tmp = wmalloc(end + strlen(f) + 8);
901 if (end != 0) {
902 sprintf(tmp, "%s,", newfs);
903 sprintf(tmp + end + 1, f, size);
904 } else {
905 sprintf(tmp + end, f, size);
908 if (newfs)
909 wfree(newfs);
910 newfs = tmp;
912 fontset = ptr+1;
913 } while (ptr!=NULL);
915 return newfs;
919 #define FONT_PROPS 14
921 typedef struct {
922 char *props[FONT_PROPS];
923 } W_FontAttributes;
926 static void
927 changeFontProp(char *buf, char *newprop, int position)
929 char buf2[512];
930 char *ptr, *pptr, *rptr;
931 int count;
933 if (buf[0]!='-') {
934 /* // remove warning later. or maybe not */
935 wwarning(_("Invalid font specification: '%s'\n"), buf);
936 return;
939 ptr = pptr = rptr = buf;
940 count = 0;
941 while (*ptr && *ptr!=',') {
942 if (*ptr == '-') {
943 count++;
944 if (count-1==position+1) {
945 rptr = ptr;
946 break;
948 if (count-1==position) {
949 pptr = ptr+1;
952 ptr++;
954 if (position==FONT_PROPS-1) {
955 rptr = ptr;
958 *pptr = 0;
959 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
960 strcpy(buf, buf2);
964 static WMArray*
965 getOptions(char *options)
967 char *ptr, *ptr2, *str;
968 WMArray *result;
969 int count;
971 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
973 ptr = options;
974 while (1) {
975 ptr2 = strchr(ptr, ',');
976 if (!ptr2) {
977 WMAddToArray(result, wstrdup(ptr));
978 break;
979 } else {
980 count = ptr2 - ptr;
981 str = wmalloc(count+1);
982 memcpy(str, ptr, count);
983 str[count] = 0;
984 WMAddToArray(result, str);
985 ptr = ptr2 + 1;
989 return result;
993 WMFont*
994 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
995 const WMFontAttributes *changes)
997 int index[FONT_PROPS], count[FONT_PROPS];
998 int totalProps, i, j, carry;
999 char fname[512];
1000 WMFontFlags fFlags;
1001 WMBag *props;
1002 WMArray *options;
1003 WMFont *result;
1004 char *prop;
1006 snprintf(fname, 512, "%s", font->name);
1008 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
1009 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
1011 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
1013 totalProps = 0;
1014 for (i=0; i<FONT_PROPS; i++) {
1015 prop = ((W_FontAttributes*)changes)->props[i];
1016 count[i] = index[i] = 0;
1017 if (!prop) {
1018 /* No change for this property */
1019 continue;
1020 } else if (strchr(prop, ',')==NULL) {
1021 /* Simple option */
1022 changeFontProp(fname, prop, i);
1023 } else {
1024 /* Option with fallback alternatives */
1025 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1026 font->antialiased && strcmp(prop, "o,i")==0) {
1027 options = getOptions("i,o");
1028 } else {
1029 options = getOptions(prop);
1031 WMInsertInBag(props, i, options);
1032 count[i] = WMGetArrayItemCount(options);
1033 if (totalProps==0)
1034 totalProps = 1;
1035 totalProps = totalProps * count[i];
1039 if (totalProps == 0) {
1040 /* No options with fallback alternatives at all */
1041 WMFreeBag(props);
1042 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1045 for (i=0; i<totalProps; i++) {
1046 for (j=0; j<FONT_PROPS; j++) {
1047 if (count[j]!=0) {
1048 options = WMGetFromBag(props, j);
1049 prop = WMGetFromArray(options, index[j]);
1050 if (prop) {
1051 changeFontProp(fname, prop, j);
1055 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1056 if (result) {
1057 WMFreeBag(props);
1058 return result;
1060 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1061 if (count[j]!=0) {
1062 index[j] += carry;
1063 carry = (index[j]==count[j]);
1064 index[j] %= count[j];
1069 WMFreeBag(props);
1071 return NULL;
1076 // should WFANormal also set "normal" or leave it alone?
1077 static const WMFontAttributes W_FANormal = {
1078 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1079 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1080 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1084 static const WMFontAttributes W_FABold = {
1085 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1086 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1087 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1091 static const WMFontAttributes W_FANotBold = {
1092 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1093 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1094 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1098 static const WMFontAttributes W_FAEmphasized = {
1099 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1100 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1101 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1105 static const WMFontAttributes W_FANotEmphasized = {
1106 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1107 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1108 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1112 static const WMFontAttributes W_FABoldEmphasized = {
1113 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1114 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1115 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1119 const WMFontAttributes *WFANormal = &W_FANormal;
1120 const WMFontAttributes *WFABold = &W_FABold;
1121 const WMFontAttributes *WFANotBold = &W_FANotBold;
1122 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1123 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1124 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;