- enabled the use of SHAPE extension in the color panel. without it the
[wmaker-crm.git] / WINGs / wfont.c
blobd7d728248a1648e3ed0c37ab4546fa830b99554c
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 return font->antialiased;
536 unsigned int
537 WMFontHeight(WMFont *font)
539 wassertrv(font!=NULL, 0);
541 return font->height;
545 WMFont*
546 WMDefaultSystemFont(WMScreen *scrPtr)
548 return WMRetainFont(scrPtr->normalFont);
552 WMFont*
553 WMDefaultBoldSystemFont(WMScreen *scrPtr)
555 return WMRetainFont(scrPtr->boldFont);
559 static WMFont*
560 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
562 WMFont *font;
563 char *fontSpec, *xftFontSpec;
565 #define WConf WINGsConfiguration
566 if (bold) {
567 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
568 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
569 } else {
570 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
571 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
573 #undef WConf
575 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
576 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
577 } else if (scrPtr->antialiasedText) {
578 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
579 } else if (scrPtr->useMultiByte) {
580 font = WMCreateFontSet(scrPtr, fontSpec);
581 } else {
582 font = WMCreateNormalFont(scrPtr, fontSpec);
585 if (!font) {
586 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
587 // is arial a good fallback for multibyte?
588 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
589 if (bold) {
590 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
591 } else {
592 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
594 if (!font) {
595 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
596 font = WMCreateFontSet(scrPtr, fontSpec);
597 if (!font) {
598 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
599 font = WMCreateFontSet(scrPtr, "fixed");
602 } else if (scrPtr->antialiasedText) {
603 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
604 if (bold) {
605 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
606 } else {
607 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
609 if (!font) {
610 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
611 font = WMCreateNormalFont(scrPtr, fontSpec);
612 if (!font) {
613 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
614 font = WMCreateNormalFont(scrPtr, "fixed");
617 } else if (scrPtr->useMultiByte) {
618 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
619 font = WMCreateFontSet(scrPtr, "fixed");
620 if (!font) {
621 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
623 } else {
624 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
625 font = WMCreateNormalFont(scrPtr, "fixed");
627 if (!font) {
628 wwarning(_("could not load fixed font!"));
629 wfree(fontSpec);
630 wfree(xftFontSpec);
631 return NULL;
634 wfree(fontSpec);
635 wfree(xftFontSpec);
637 return font;
641 WMFont*
642 WMSystemFontOfSize(WMScreen *scrPtr, int size)
644 return makeSystemFontOfSize(scrPtr, size, False);
648 WMFont*
649 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
651 return makeSystemFontOfSize(scrPtr, size, True);
655 XFontSet
656 WMGetFontFontSet(WMFont *font)
658 wassertrv(font!=NULL, NULL);
660 if (!font->notFontSet && !font->antialiased)
661 return font->font.set;
663 return NULL;
668 WMWidthOfString(WMFont *font, char *text, int length)
670 wassertrv(font!=NULL, 0);
671 wassertrv(text!=NULL, 0);
673 if (font->antialiased) {
674 #ifdef XFT
675 XGlyphInfo extents;
677 if (!font->notFontSet) {
678 wchar_t *wtext;
679 char *mtext;
680 int len;
682 /* Use mtext instead of text, because mbstrtowcs() alters it */
683 mtext = text;
684 wtext = (wchar_t *)wmalloc(4*length+4);
685 /* pass a real ps instead of NULL below? for multithread safety
686 * as from manual page */
687 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
688 if (len>0) {
689 XftTextExtents32(font->screen->display, font->font.xft,
690 (XftChar32 *)wtext, len, &extents);
691 } else {
692 if (len==-1) {
693 wwarning(_("Conversion to widechar failed (possible "
694 "invalid multibyte sequence): '%s':(pos %d)\n"),
695 text, mtext-text+1);
697 extents.xOff = 0;
699 wfree(wtext);
700 } else {
701 XftTextExtents8(font->screen->display, font->font.xft,
702 (XftChar8 *)text, length, &extents);
705 return extents.xOff; /* don't ask :P */
706 #else
707 wassertrv(False, 0);
708 #endif
709 } else if (font->notFontSet) {
710 return XTextWidth(font->font.normal, text, length);
711 } else {
712 XRectangle rect;
713 XRectangle AIXsucks;
715 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
717 return rect.width;
723 void
724 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
725 int x, int y, char *text, int length)
727 wassertr(font!=NULL);
729 if (font->antialiased) {
730 #ifdef XFT
731 XftColor xftcolor;
733 xftcolor.color.red = color->color.red;
734 xftcolor.color.green = color->color.green;
735 xftcolor.color.blue = color->color.blue;
736 xftcolor.color.alpha = color->alpha;;
737 xftcolor.pixel = W_PIXEL(color);
739 XftDrawChange(scr->xftdraw, d);
741 if (!font->notFontSet) {
742 wchar_t *wtext;
743 char *mtext;
744 int len;
746 /* Use mtext instead of text, because mbstrtowcs() alters it */
747 mtext = text;
748 wtext = (wchar_t *)wmalloc(4*length+4);
749 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
750 if (len>0) {
751 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
752 x, y + font->y, (XftChar32*)wtext, len);
753 } else if (len==-1) {
754 wwarning(_("Conversion to widechar failed (possible invalid "
755 "multibyte sequence): '%s':(pos %d)\n"),
756 text, mtext-text+1);
757 /* we can draw normal text, or we can draw as much widechar
758 * text as was already converted until the error. go figure */
759 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
760 x, y + font->y, (XftChar8*)text, length);*/
762 wfree(wtext);
763 } else {
764 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
765 x, y + font->y, (XftChar8*)text, length);
767 #else
768 wassertr(False);
769 #endif
770 } else if (font->notFontSet) {
771 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
772 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
773 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
774 text, length);
775 } else {
776 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
777 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
778 x, y + font->y, text, length);
783 void
784 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
785 WMFont *font, int x, int y, char *text, int length)
787 wassertr(font!=NULL);
789 if (font->antialiased) {
790 #ifdef XFT
791 XftColor textColor;
792 XftColor bgColor;
794 textColor.color.red = color->color.red;
795 textColor.color.green = color->color.green;
796 textColor.color.blue = color->color.blue;
797 textColor.color.alpha = color->alpha;;
798 textColor.pixel = W_PIXEL(color);
800 bgColor.color.red = background->color.red;
801 bgColor.color.green = background->color.green;
802 bgColor.color.blue = background->color.blue;
803 bgColor.color.alpha = background->alpha;;
804 bgColor.pixel = W_PIXEL(background);
807 XftDrawChange(scr->xftdraw, d);
809 XftDrawRect(scr->xftdraw, &bgColor, x, y,
810 WMWidthOfString(font, text, length), font->height);
812 if (!font->notFontSet) {
813 wchar_t *wtext;
814 char *mtext;
815 int len;
817 /* Use mtext instead of text, because mbstrtowcs() alters it */
818 mtext = text;
819 wtext = (wchar_t *)wmalloc(4*length+4);
820 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
821 if (len>0) {
822 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
823 x, y + font->y, (XftChar32*)wtext, len);
824 } else if (len==-1) {
825 wwarning(_("Conversion to widechar failed (possible invalid "
826 "multibyte sequence): '%s':(pos %d)\n"),
827 text, mtext-text+1);
828 /* we can draw normal text, or we can draw as much widechar
829 * text as was already converted until the error. go figure */
830 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
831 x, y + font->y, (XftChar8*)text, length);*/
833 wfree(wtext);
834 } else {
835 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
836 x, y + font->y, (XftChar8*)text, length);
838 #else
839 wassertr(False);
840 #endif
841 } else if (font->notFontSet) {
842 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
843 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
844 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
845 XDrawImageString(scr->display, d, scr->drawImStringGC,
846 x, y + font->y, text, length);
847 } else {
848 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
849 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
850 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
851 x, y + font->y, text, length);
858 static char*
859 makeFontSetOfSize(char *fontset, int size)
861 char font[300], *f;
862 char *newfs = NULL;
863 char *ptr;
865 do {
866 char *tmp;
867 int end;
870 f = fontset;
871 ptr = strchr(fontset, ',');
872 if (ptr) {
873 int count = ptr-fontset;
875 if (count > 255) {
876 wwarning(_("font description %s is too large."), fontset);
877 } else {
878 memcpy(font, fontset, count);
879 font[count] = 0;
880 f = (char*)font;
884 if (newfs)
885 end = strlen(newfs);
886 else
887 end = 0;
889 tmp = wmalloc(end + strlen(f) + 8);
890 if (end != 0) {
891 sprintf(tmp, "%s,", newfs);
892 sprintf(tmp + end + 1, f, size);
893 } else {
894 sprintf(tmp + end, f, size);
897 if (newfs)
898 wfree(newfs);
899 newfs = tmp;
901 fontset = ptr+1;
902 } while (ptr!=NULL);
904 return newfs;
908 #define FONT_PROPS 14
910 typedef struct {
911 char *props[FONT_PROPS];
912 } W_FontAttributes;
915 static void
916 changeFontProp(char *buf, char *newprop, int position)
918 char buf2[512];
919 char *ptr, *pptr, *rptr;
920 int count;
922 if (buf[0]!='-') {
923 /* // remove warning later. or maybe not */
924 wwarning(_("Invalid font specification: '%s'\n"), buf);
925 return;
928 ptr = pptr = rptr = buf;
929 count = 0;
930 while (*ptr && *ptr!=',') {
931 if (*ptr == '-') {
932 count++;
933 if (count-1==position+1) {
934 rptr = ptr;
935 break;
937 if (count-1==position) {
938 pptr = ptr+1;
941 ptr++;
943 if (position==FONT_PROPS-1) {
944 rptr = ptr;
947 *pptr = 0;
948 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
949 strcpy(buf, buf2);
953 static WMArray*
954 getOptions(char *options)
956 char *ptr, *ptr2, *str;
957 WMArray *result;
958 int count;
960 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
962 ptr = options;
963 while (1) {
964 ptr2 = strchr(ptr, ',');
965 if (!ptr2) {
966 WMAddToArray(result, wstrdup(ptr));
967 break;
968 } else {
969 count = ptr2 - ptr;
970 str = wmalloc(count+1);
971 memcpy(str, ptr, count);
972 str[count] = 0;
973 WMAddToArray(result, str);
974 ptr = ptr2 + 1;
978 return result;
982 WMFont*
983 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
984 const WMFontAttributes *changes)
986 int index[FONT_PROPS], count[FONT_PROPS];
987 int totalProps, i, j, carry;
988 char fname[512];
989 WMFontFlags fFlags;
990 WMBag *props;
991 WMArray *options;
992 WMFont *result;
993 char *prop;
995 snprintf(fname, 512, "%s", font->name);
997 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
998 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
1000 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
1002 totalProps = 0;
1003 for (i=0; i<FONT_PROPS; i++) {
1004 prop = ((W_FontAttributes*)changes)->props[i];
1005 count[i] = index[i] = 0;
1006 if (!prop) {
1007 /* No change for this property */
1008 continue;
1009 } else if (strchr(prop, ',')==NULL) {
1010 /* Simple option */
1011 changeFontProp(fname, prop, i);
1012 } else {
1013 /* Option with fallback alternatives */
1014 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1015 font->antialiased && strcmp(prop, "o,i")==0) {
1016 options = getOptions("i,o");
1017 } else {
1018 options = getOptions(prop);
1020 WMInsertInBag(props, i, options);
1021 count[i] = WMGetArrayItemCount(options);
1022 if (totalProps==0)
1023 totalProps = 1;
1024 totalProps = totalProps * count[i];
1028 if (totalProps == 0) {
1029 /* No options with fallback alternatives at all */
1030 WMFreeBag(props);
1031 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1034 for (i=0; i<totalProps; i++) {
1035 for (j=0; j<FONT_PROPS; j++) {
1036 if (count[j]!=0) {
1037 options = WMGetFromBag(props, j);
1038 prop = WMGetFromArray(options, index[j]);
1039 if (prop) {
1040 changeFontProp(fname, prop, j);
1044 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1045 if (result) {
1046 WMFreeBag(props);
1047 return result;
1049 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1050 if (count[j]!=0) {
1051 index[j] += carry;
1052 carry = (index[j]==count[j]);
1053 index[j] %= count[j];
1058 WMFreeBag(props);
1060 return NULL;
1065 // should WFANormal also set "normal" or leave it alone?
1066 static const WMFontAttributes W_FANormal = {
1067 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1068 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1069 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1073 static const WMFontAttributes W_FABold = {
1074 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1075 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1076 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1080 static const WMFontAttributes W_FANotBold = {
1081 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1082 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1083 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1087 static const WMFontAttributes W_FAEmphasized = {
1088 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1089 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1090 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1094 static const WMFontAttributes W_FANotEmphasized = {
1095 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1096 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1097 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1101 static const WMFontAttributes W_FABoldEmphasized = {
1102 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1103 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1104 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1108 const WMFontAttributes *WFANormal = &W_FANormal;
1109 const WMFontAttributes *WFABold = &W_FABold;
1110 const WMFontAttributes *WFANotBold = &W_FANotBold;
1111 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1112 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1113 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;