- added WMCopyFontWithChanges() a more generic and powerful function, meant
[wmaker-crm.git] / WINGs / wfont.c
blob8a2da6596a76d06945c929cc6ab3788cbeb57eea
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 static const WMFontAttributes W_FANormal = {
1065 WFAUnchanged,
1066 WFAUnchanged,
1067 "medium,normal,regular",
1068 "r",
1069 "normal", /* not sure about this */
1070 WFAUnchanged,
1071 WFAUnchanged,
1072 WFAUnchanged,
1073 WFAUnchanged,
1074 WFAUnchanged,
1075 WFAUnchanged,
1076 WFAUnchanged,
1077 WFAUnchanged,
1078 WFAUnchanged
1082 static const WMFontAttributes W_FABold = {
1083 WFAUnchanged,
1084 WFAUnchanged,
1085 "bold",
1086 WFAUnchanged,
1087 WFAUnchanged,
1088 WFAUnchanged,
1089 WFAUnchanged,
1090 WFAUnchanged,
1091 WFAUnchanged,
1092 WFAUnchanged,
1093 WFAUnchanged,
1094 WFAUnchanged,
1095 WFAUnchanged,
1096 WFAUnchanged
1100 static const WMFontAttributes W_FANonBold = {
1101 WFAUnchanged,
1102 WFAUnchanged,
1103 "medium,normal,regular",
1104 WFAUnchanged,
1105 WFAUnchanged,
1106 WFAUnchanged,
1107 WFAUnchanged,
1108 WFAUnchanged,
1109 WFAUnchanged,
1110 WFAUnchanged,
1111 WFAUnchanged,
1112 WFAUnchanged,
1113 WFAUnchanged,
1114 WFAUnchanged
1118 static const WMFontAttributes W_FAEmphasized = {
1119 WFAUnchanged,
1120 WFAUnchanged,
1121 WFAUnchanged,
1122 "o,i",
1123 WFAUnchanged,
1124 WFAUnchanged,
1125 WFAUnchanged,
1126 WFAUnchanged,
1127 WFAUnchanged,
1128 WFAUnchanged,
1129 WFAUnchanged,
1130 WFAUnchanged,
1131 WFAUnchanged,
1132 WFAUnchanged
1136 static const WMFontAttributes W_FANonEmphasized = {
1137 WFAUnchanged,
1138 WFAUnchanged,
1139 WFAUnchanged,
1140 "r",
1141 WFAUnchanged,
1142 WFAUnchanged,
1143 WFAUnchanged,
1144 WFAUnchanged,
1145 WFAUnchanged,
1146 WFAUnchanged,
1147 WFAUnchanged,
1148 WFAUnchanged,
1149 WFAUnchanged,
1150 WFAUnchanged
1154 static const WMFontAttributes W_FABoldEmphasized = {
1155 WFAUnchanged,
1156 WFAUnchanged,
1157 "bold",
1158 "o,i",
1159 WFAUnchanged,
1160 WFAUnchanged,
1161 WFAUnchanged,
1162 WFAUnchanged,
1163 WFAUnchanged,
1164 WFAUnchanged,
1165 WFAUnchanged,
1166 WFAUnchanged,
1167 WFAUnchanged,
1168 WFAUnchanged
1172 // by exposing a ptr to them we can allow one to alter their content
1173 // const doesn't prevent this effectively.
1174 // altering the content doesn't effectively work because it will core dump
1175 // if one tries, but still is not clean.
1176 // however passing the whole struct to the function instead of just the
1177 // pointer means passing a strcut with 14 pointers to char*
1179 const WMFontAttributes *WFANormal = &W_FANormal;
1180 const WMFontAttributes *WFABold = &W_FABold;
1181 const WMFontAttributes *WFANonBold = &W_FANonBold;
1182 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1183 const WMFontAttributes *WFANonEmphasized = &W_FANonEmphasized;
1184 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;