- Fixed a bug with empty frame titles (Alexey Voinov <voins@voins.program.ru>)
[wmaker-crm.git] / WINGs / wfont.c
blob9d51b5794cf65b7d28c73bc99962dcfec7ddff78
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 #if 0
310 /* // Xft sux. Loading a font that doesn't exist will load the default
311 * defined in XftConfig without any warning or error */
312 font->font.normal = XLoadQueryFont(display, fname);
313 if (!font->font.normal) {
314 wfree(font);
315 wfree(fname);
316 return NULL;
318 XFreeFont(display, font->font.normal);
319 #endif
321 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
322 if (!font->font.xft) {
323 wfree(font);
324 wfree(fname);
325 return NULL;
327 font->height = font->font.xft->ascent+font->font.xft->descent;
328 font->y = font->font.xft->ascent;
330 font->refCount = 1;
332 font->name = fname;
334 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
336 return font;
337 #else
338 return NULL;
339 #endif
343 WMFont*
344 WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName)
346 #ifdef XFT
347 WMFont *font;
348 Display *display = scrPtr->display;
349 char *fname, *ptr;
351 if (!scrPtr->hasXftSupport)
352 return NULL;
354 fontName = xlfdFromFontName(fontName, True);
356 // use the second in list if available, instead of first?
357 if ((ptr = strchr(fontName, ','))) {
358 fname = wmalloc(ptr - fontName + 1);
359 strncpy(fname, fontName, ptr - fontName);
360 fname[ptr - fontName] = 0;
361 } else {
362 fname = wstrdup(fontName);
365 wfree(fontName);
367 font = WMHashGet(scrPtr->xftFontSetCache, fname);
368 if (font) {
369 WMRetainFont(font);
370 wfree(fname);
371 return font;
374 font = wmalloc(sizeof(WMFont));
375 memset(font, 0, sizeof(WMFont));
377 font->notFontSet = 0;
378 font->antialiased = 1;
380 font->screen = scrPtr;
382 #if 0
383 /* // Xft sux. Loading a font that doesn't exist will load the default
384 * defined in XftConfig without any warning or error */
385 font->font.normal = XLoadQueryFont(display, fname);
386 if (!font->font.normal) {
387 wfree(font);
388 wfree(fname);
389 return NULL;
391 XFreeFont(display, font->font.normal);
392 #endif
394 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
395 if (!font->font.xft) {
396 wfree(font);
397 wfree(fname);
398 return NULL;
400 font->height = font->font.xft->ascent+font->font.xft->descent;
401 font->y = font->font.xft->ascent;
403 font->refCount = 1;
405 font->name = fname;
407 assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL);
409 return font;
410 #else
411 return NULL;
412 #endif
416 WMFont*
417 WMCreateFont(WMScreen *scrPtr, char *fontName)
419 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
423 WMFont*
424 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
426 Bool multiByte = scrPtr->useMultiByte;
427 Bool antialiased = scrPtr->antialiasedText;
428 WMFont *font;
430 if (flags & WFFontSet) {
431 multiByte = True;
432 } else if (flags & WFNormalFont) {
433 multiByte = False;
435 if (flags & WFAntialiased) {
436 antialiased = True;
437 } else if (flags & WFNotAntialiased) {
438 antialiased = False;
441 if (antialiased && multiByte) {
442 font = WMCreateAntialiasedFontSet(scrPtr, fontName);
443 /* If we cannot create an antialiased font set and antialiasing is
444 * not explicitly requested in flags, fallback to standard font sets */
445 if (!font && (flags & WFAntialiased)==0) {
446 font = WMCreateFontSet(scrPtr, fontName);
448 } else if (antialiased) {
449 font = WMCreateAntialiasedFont(scrPtr, fontName);
450 /* If we cannot create an antialiased font and antialiasing is
451 * not explicitly requested in flags, fallback to normal font */
452 if (!font && (flags & WFAntialiased)==0) {
453 font = WMCreateNormalFont(scrPtr, fontName);
455 } else if (multiByte) {
456 font = WMCreateFontSet(scrPtr, fontName);
457 } else {
458 font = WMCreateNormalFont(scrPtr, fontName);
461 return font;
465 WMFont*
466 WMRetainFont(WMFont *font)
468 wassertrv(font!=NULL, NULL);
470 font->refCount++;
472 return font;
476 void
477 WMReleaseFont(WMFont *font)
479 wassertr(font!=NULL);
481 font->refCount--;
482 if (font->refCount < 1) {
483 if (font->antialiased) {
484 #ifdef XFT
485 XftFontClose(font->screen->display, font->font.xft);
486 #else
487 assert(False);
488 #endif
489 } else if (font->notFontSet) {
490 XFreeFont(font->screen->display, font->font.normal);
491 } else {
492 XFreeFontSet(font->screen->display, font->font.set);
495 if (font->name) {
496 if (font->antialiased && !font->notFontSet) {
497 WMHashRemove(font->screen->xftFontSetCache, font->name);
498 } else if (font->antialiased) {
499 WMHashRemove(font->screen->xftFontCache, font->name);
500 } else if (font->notFontSet) {
501 WMHashRemove(font->screen->fontCache, font->name);
502 } else {
503 WMHashRemove(font->screen->fontSetCache, font->name);
505 wfree(font->name);
507 wfree(font);
512 Bool
513 WMHasAntialiasingSupport(WMScreen *scrPtr)
515 return scrPtr->hasXftSupport;
519 Bool
520 WMIsAntialiasingEnabled(WMScreen *scrPtr)
522 return scrPtr->antialiasedText;
526 Bool
527 WMIsAntialiasedFont(WMFont *font)
529 return font->antialiased;
533 unsigned int
534 WMFontHeight(WMFont *font)
536 wassertrv(font!=NULL, 0);
538 return font->height;
542 WMFont*
543 WMDefaultSystemFont(WMScreen *scrPtr)
545 return WMRetainFont(scrPtr->normalFont);
549 WMFont*
550 WMDefaultBoldSystemFont(WMScreen *scrPtr)
552 return WMRetainFont(scrPtr->boldFont);
556 static WMFont*
557 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
559 WMFont *font;
560 char *fontSpec, *xftFontSpec;
562 #define WConf WINGsConfiguration
563 if (bold) {
564 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
565 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
566 } else {
567 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
568 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
570 #undef WConf
572 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
573 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
574 } else if (scrPtr->antialiasedText) {
575 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
576 } else if (scrPtr->useMultiByte) {
577 font = WMCreateFontSet(scrPtr, fontSpec);
578 } else {
579 font = WMCreateNormalFont(scrPtr, fontSpec);
582 if (!font) {
583 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
584 // is arial a good fallback for multibyte?
585 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
586 if (bold) {
587 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
588 } else {
589 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
591 if (!font) {
592 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
593 font = WMCreateFontSet(scrPtr, fontSpec);
594 if (!font) {
595 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
596 font = WMCreateFontSet(scrPtr, "fixed");
599 } else if (scrPtr->antialiasedText) {
600 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
601 if (bold) {
602 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
603 } else {
604 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
606 if (!font) {
607 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
608 font = WMCreateNormalFont(scrPtr, fontSpec);
609 if (!font) {
610 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
611 font = WMCreateNormalFont(scrPtr, "fixed");
614 } else if (scrPtr->useMultiByte) {
615 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
616 font = WMCreateFontSet(scrPtr, "fixed");
617 if (!font) {
618 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
620 } else {
621 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
622 font = WMCreateNormalFont(scrPtr, "fixed");
624 if (!font) {
625 wwarning(_("could not load fixed font!"));
626 wfree(fontSpec);
627 wfree(xftFontSpec);
628 return NULL;
631 wfree(fontSpec);
632 wfree(xftFontSpec);
634 return font;
638 WMFont*
639 WMSystemFontOfSize(WMScreen *scrPtr, int size)
641 return makeSystemFontOfSize(scrPtr, size, False);
645 WMFont*
646 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
648 return makeSystemFontOfSize(scrPtr, size, True);
652 XFontSet
653 WMGetFontFontSet(WMFont *font)
655 wassertrv(font!=NULL, NULL);
657 if (!font->notFontSet && !font->antialiased)
658 return font->font.set;
660 return NULL;
665 WMWidthOfString(WMFont *font, char *text, int length)
667 wassertrv(font!=NULL, 0);
668 wassertrv(text!=NULL, 0);
670 if (font->antialiased) {
671 #ifdef XFT
672 XGlyphInfo extents;
674 if (!font->notFontSet) {
675 wchar_t *wtext;
676 char *mtext;
677 int len;
679 /* Use mtext instead of text, because mbstrtowcs() alters it */
680 mtext = text;
681 wtext = (wchar_t *)wmalloc(4*length+4);
682 /* pass a real ps instead of NULL below? for multithread safety
683 * as from manual page */
684 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
685 if (len>0) {
686 XftTextExtents32(font->screen->display, font->font.xft,
687 (XftChar32 *)wtext, len, &extents);
688 } else {
689 if (len==-1) {
690 wwarning(_("Conversion to widechar failed (possible "
691 "invalid multibyte sequence): '%s':(pos %d)\n"),
692 text, mtext-text+1);
694 extents.xOff = 0;
696 wfree(wtext);
697 } else {
698 XftTextExtents8(font->screen->display, font->font.xft,
699 (XftChar8 *)text, length, &extents);
702 return extents.xOff; /* don't ask :P */
703 #else
704 wassertrv(False, 0);
705 #endif
706 } else if (font->notFontSet) {
707 return XTextWidth(font->font.normal, text, length);
708 } else {
709 XRectangle rect;
710 XRectangle AIXsucks;
712 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
714 return rect.width;
720 void
721 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
722 int x, int y, char *text, int length)
724 wassertr(font!=NULL);
726 if (font->antialiased) {
727 #ifdef XFT
728 XftColor xftcolor;
730 xftcolor.color.red = color->color.red;
731 xftcolor.color.green = color->color.green;
732 xftcolor.color.blue = color->color.blue;
733 xftcolor.color.alpha = color->alpha;;
734 xftcolor.pixel = W_PIXEL(color);
736 XftDrawChange(scr->xftdraw, d);
738 if (!font->notFontSet) {
739 wchar_t *wtext;
740 char *mtext;
741 int len;
743 /* Use mtext instead of text, because mbstrtowcs() alters it */
744 mtext = text;
745 wtext = (wchar_t *)wmalloc(4*length+4);
746 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
747 if (len>0) {
748 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
749 x, y + font->y, (XftChar32*)wtext, len);
750 } else if (len==-1) {
751 wwarning(_("Conversion to widechar failed (possible invalid "
752 "multibyte sequence): '%s':(pos %d)\n"),
753 text, mtext-text+1);
754 /* we can draw normal text, or we can draw as much widechar
755 * text as was already converted until the error. go figure */
756 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
757 x, y + font->y, (XftChar8*)text, length);*/
759 wfree(wtext);
760 } else {
761 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
762 x, y + font->y, (XftChar8*)text, length);
764 #else
765 wassertr(False);
766 #endif
767 } else if (font->notFontSet) {
768 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
769 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
770 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
771 text, length);
772 } else {
773 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
774 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
775 x, y + font->y, text, length);
780 void
781 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
782 WMFont *font, int x, int y, char *text, int length)
784 wassertr(font!=NULL);
786 if (font->antialiased) {
787 #ifdef XFT
788 XftColor textColor;
789 XftColor bgColor;
791 textColor.color.red = color->color.red;
792 textColor.color.green = color->color.green;
793 textColor.color.blue = color->color.blue;
794 textColor.color.alpha = color->alpha;;
795 textColor.pixel = W_PIXEL(color);
797 bgColor.color.red = background->color.red;
798 bgColor.color.green = background->color.green;
799 bgColor.color.blue = background->color.blue;
800 bgColor.color.alpha = background->alpha;;
801 bgColor.pixel = W_PIXEL(background);
804 XftDrawChange(scr->xftdraw, d);
806 XftDrawRect(scr->xftdraw, &bgColor, x, y,
807 WMWidthOfString(font, text, length), font->height);
809 if (!font->notFontSet) {
810 wchar_t *wtext;
811 char *mtext;
812 int len;
814 /* Use mtext instead of text, because mbstrtowcs() alters it */
815 mtext = text;
816 wtext = (wchar_t *)wmalloc(4*length+4);
817 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
818 if (len>0) {
819 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
820 x, y + font->y, (XftChar32*)wtext, len);
821 } else if (len==-1) {
822 wwarning(_("Conversion to widechar failed (possible invalid "
823 "multibyte sequence): '%s':(pos %d)\n"),
824 text, mtext-text+1);
825 /* we can draw normal text, or we can draw as much widechar
826 * text as was already converted until the error. go figure */
827 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
828 x, y + font->y, (XftChar8*)text, length);*/
830 wfree(wtext);
831 } else {
832 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
833 x, y + font->y, (XftChar8*)text, length);
835 #else
836 wassertr(False);
837 #endif
838 } else if (font->notFontSet) {
839 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
840 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
841 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
842 XDrawImageString(scr->display, d, scr->drawImStringGC,
843 x, y + font->y, text, length);
844 } else {
845 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
846 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
847 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
848 x, y + font->y, text, length);
855 static char*
856 makeFontSetOfSize(char *fontset, int size)
858 char font[300], *f;
859 char *newfs = NULL;
860 char *ptr;
862 do {
863 char *tmp;
864 int end;
867 f = fontset;
868 ptr = strchr(fontset, ',');
869 if (ptr) {
870 int count = ptr-fontset;
872 if (count > 255) {
873 wwarning(_("font description %s is too large."), fontset);
874 } else {
875 memcpy(font, fontset, count);
876 font[count] = 0;
877 f = (char*)font;
881 if (newfs)
882 end = strlen(newfs);
883 else
884 end = 0;
886 tmp = wmalloc(end + strlen(f) + 8);
887 if (end != 0) {
888 sprintf(tmp, "%s,", newfs);
889 sprintf(tmp + end + 1, f, size);
890 } else {
891 sprintf(tmp + end, f, size);
894 if (newfs)
895 wfree(newfs);
896 newfs = tmp;
898 fontset = ptr+1;
899 } while (ptr!=NULL);
901 return newfs;
905 #define FONT_PROPS 14
907 typedef struct {
908 char *props[FONT_PROPS];
909 } W_FontAttributes;
912 static void
913 changeFontProp(char *buf, char *newprop, int position)
915 char buf2[512];
916 char *ptr, *pptr, *rptr;
917 int count;
919 if (buf[0]!='-') {
920 // remove warning later. or maybe not
921 wwarning(_("Invalid font specification: '%s'\n"), buf);
922 return;
925 ptr = pptr = rptr = buf;
926 count = 0;
927 while (*ptr && *ptr!=',') {
928 if (*ptr == '-') {
929 count++;
930 if (count-1==position+1) {
931 rptr = ptr;
932 break;
934 if (count-1==position) {
935 pptr = ptr+1;
938 ptr++;
940 if (position==FONT_PROPS-1) {
941 rptr = ptr;
944 *pptr = 0;
945 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
946 strcpy(buf, buf2);
950 static WMArray*
951 getOptions(char *options)
953 char *ptr, *ptr2, *str;
954 WMArray *result;
955 int count;
957 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
959 ptr = options;
960 while (1) {
961 ptr2 = strchr(ptr, ',');
962 if (!ptr2) {
963 WMAddToArray(result, wstrdup(ptr));
964 break;
965 } else {
966 count = ptr2 - ptr;
967 str = wmalloc(count+1);
968 memcpy(str, ptr, count);
969 str[count] = 0;
970 WMAddToArray(result, str);
971 ptr = ptr2 + 1;
975 return result;
979 WMFont*
980 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
981 const WMFontAttributes *changes)
983 int index[FONT_PROPS], count[FONT_PROPS];
984 int totalProps, i, j, carry;
985 char fname[512];
986 WMFontFlags fFlags;
987 WMBag *props;
988 WMArray *options;
989 WMFont *result;
990 char *prop;
992 snprintf(fname, 512, "%s", font->name);
994 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
995 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
997 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
999 totalProps = 0;
1000 for (i=0; i<FONT_PROPS; i++) {
1001 prop = ((W_FontAttributes*)changes)->props[i];
1002 count[i] = index[i] = 0;
1003 if (!prop) {
1004 /* No change for this property */
1005 continue;
1006 } else if (strchr(prop, ',')==NULL) {
1007 /* Simple option */
1008 changeFontProp(fname, prop, i);
1009 } else {
1010 /* Option with fallback alternatives */
1011 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1012 font->antialiased && strcmp(prop, "o,i")==0) {
1013 options = getOptions("i,o");
1014 } else {
1015 options = getOptions(prop);
1017 WMInsertInBag(props, i, options);
1018 count[i] = WMGetArrayItemCount(options);
1019 if (totalProps==0)
1020 totalProps = 1;
1021 totalProps = totalProps * count[i];
1025 if (totalProps == 0) {
1026 /* No options with fallback alternatives at all */
1027 WMFreeBag(props);
1028 //printf("try: '%s'\n '%s'\n", font->name, fname);
1029 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1032 for (i=0; i<totalProps; i++) {
1033 for (j=0; j<FONT_PROPS; j++) {
1034 if (count[j]!=0) {
1035 options = WMGetFromBag(props, j);
1036 prop = WMGetFromArray(options, index[j]);
1037 if (prop) {
1038 changeFontProp(fname, prop, j);
1042 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1043 //printf("try: '%s'\n '%s'\n", font->name, fname);
1044 if (result) {
1045 WMFreeBag(props);
1046 return result;
1048 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1049 if (count[j]!=0) {
1050 index[j] += carry;
1051 carry = (index[j]==count[j]);
1052 index[j] %= count[j];
1057 WMFreeBag(props);
1059 return NULL;
1064 // should WFANormal also set "normal" or leave it alone?
1065 static const WMFontAttributes W_FANormal = {
1066 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1067 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1068 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1072 static const WMFontAttributes W_FABold = {
1073 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1074 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1075 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1079 static const WMFontAttributes W_FANotBold = {
1080 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1081 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1082 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1086 static const WMFontAttributes W_FAEmphasized = {
1087 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1088 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1089 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1093 static const WMFontAttributes W_FANotEmphasized = {
1094 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1095 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1096 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1100 static const WMFontAttributes W_FABoldEmphasized = {
1101 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1102 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1103 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1107 const WMFontAttributes *WFANormal = &W_FANormal;
1108 const WMFontAttributes *WFABold = &W_FABold;
1109 const WMFontAttributes *WFANotBold = &W_FANotBold;
1110 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1111 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1112 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;