_ fixed bug in resizing a scrollview
[wmaker-crm.git] / WINGs / wfont.c
blobf4ae2722f5396de9e5cb8b07527210f6eec5b84b
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 printf("%s\n", fname);
324 if (fname[0] == '-') {
325 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
326 } else {
327 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
329 if (!font->font.xft) {
330 wfree(font);
331 wfree(fname);
332 return NULL;
334 font->height = font->font.xft->ascent+font->font.xft->descent;
335 font->y = font->font.xft->ascent;
337 font->refCount = 1;
339 font->name = fname;
341 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
343 return font;
344 #else
345 return NULL;
346 #endif
350 WMFont*
351 WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName)
353 #ifdef XFT
354 WMFont *font;
355 Display *display = scrPtr->display;
356 char *fname, *ptr;
358 if (!scrPtr->hasXftSupport)
359 return NULL;
361 fontName = xlfdFromFontName(fontName, True);
363 if ((ptr = strchr(fontName, ','))) {
364 fname = wmalloc(ptr - fontName + 1);
365 strncpy(fname, fontName, ptr - fontName);
366 fname[ptr - fontName] = 0;
367 } else {
368 fname = wstrdup(fontName);
371 wfree(fontName);
373 font = WMHashGet(scrPtr->xftFontSetCache, fname);
374 if (font) {
375 WMRetainFont(font);
376 wfree(fname);
377 return font;
380 font = wmalloc(sizeof(WMFont));
381 memset(font, 0, sizeof(WMFont));
383 font->notFontSet = 0;
384 font->antialiased = 1;
386 font->screen = scrPtr;
388 /* Xft sux. Loading a font with an invalid XLFD will give strange results
389 * sometimes without returning any warning or error.
390 * However Xft's idea of what font is invalid is quite strange:
391 * 1. If the XLFD doesn't have all its fields present will fail and
392 * return NULL.
393 * 2. If all fields are present, but hold invalid values then it will:
394 * a. If family is invalid, will load a default font without warning.
395 * b. If the font size is invalid (non-numerical) it will fail and
396 * return NULL.
397 * c. If other fields are invalid, will load the font specified by
398 * the valid family name, ignoring any invalid fields. It will
399 * use a default medium weight and a default roman slant if they
400 * are invalid.
402 if (fname[0] == '-') {
403 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
404 } else {
405 font->font.xft = XftFontOpenName(display, scrPtr->screen, fname);
407 if (!font->font.xft) {
408 wfree(font);
409 wfree(fname);
410 return NULL;
412 font->height = font->font.xft->ascent+font->font.xft->descent;
413 font->y = font->font.xft->ascent;
415 font->refCount = 1;
417 font->name = fname;
419 assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL);
421 return font;
422 #else
423 return NULL;
424 #endif
428 WMFont*
429 WMCreateFont(WMScreen *scrPtr, char *fontName)
431 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
435 WMFont*
436 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
438 Bool multiByte = scrPtr->useMultiByte;
439 Bool antialiased = scrPtr->antialiasedText;
440 WMFont *font;
442 if (flags & WFFontSet) {
443 multiByte = True;
444 } else if (flags & WFNormalFont) {
445 multiByte = False;
447 if (flags & WFAntialiased) {
448 antialiased = True;
449 } else if (flags & WFNotAntialiased) {
450 antialiased = False;
453 if (antialiased && multiByte) {
454 font = WMCreateAntialiasedFontSet(scrPtr, fontName);
455 /* If we cannot create an antialiased font set and antialiasing is
456 * not explicitly requested in flags, fallback to standard font sets */
457 if (!font && (flags & WFAntialiased)==0) {
458 font = WMCreateFontSet(scrPtr, fontName);
460 } else if (antialiased) {
461 font = WMCreateAntialiasedFont(scrPtr, fontName);
462 /* If we cannot create an antialiased font and antialiasing is
463 * not explicitly requested in flags, fallback to normal font */
464 if (!font && (flags & WFAntialiased)==0) {
465 font = WMCreateNormalFont(scrPtr, fontName);
467 } else if (multiByte) {
468 font = WMCreateFontSet(scrPtr, fontName);
469 } else {
470 font = WMCreateNormalFont(scrPtr, fontName);
473 return font;
477 WMFont*
478 WMRetainFont(WMFont *font)
480 wassertrv(font!=NULL, NULL);
482 font->refCount++;
484 return font;
488 void
489 WMReleaseFont(WMFont *font)
491 wassertr(font!=NULL);
493 font->refCount--;
494 if (font->refCount < 1) {
495 if (font->antialiased) {
496 #ifdef XFT
497 XftFontClose(font->screen->display, font->font.xft);
498 #else
499 assert(False);
500 #endif
501 } else if (font->notFontSet) {
502 XFreeFont(font->screen->display, font->font.normal);
503 } else {
504 XFreeFontSet(font->screen->display, font->font.set);
507 if (font->name) {
508 if (font->antialiased && !font->notFontSet) {
509 WMHashRemove(font->screen->xftFontSetCache, font->name);
510 } else if (font->antialiased) {
511 WMHashRemove(font->screen->xftFontCache, font->name);
512 } else if (font->notFontSet) {
513 WMHashRemove(font->screen->fontCache, font->name);
514 } else {
515 WMHashRemove(font->screen->fontSetCache, font->name);
517 wfree(font->name);
519 wfree(font);
524 Bool
525 WMHasAntialiasingSupport(WMScreen *scrPtr)
527 return scrPtr->hasXftSupport;
531 Bool
532 WMIsAntialiasingEnabled(WMScreen *scrPtr)
534 return scrPtr->antialiasedText;
538 Bool
539 WMIsAntialiasedFont(WMFont *font)
541 wassertrv(font!=NULL, False);
543 return font->antialiased;
547 unsigned int
548 WMFontHeight(WMFont *font)
550 wassertrv(font!=NULL, 0);
552 return font->height;
556 char*
557 WMGetFontName(WMFont *font)
559 wassertrv(font!=NULL, NULL);
561 return font->name;
565 WMFont*
566 WMDefaultSystemFont(WMScreen *scrPtr)
568 return WMRetainFont(scrPtr->normalFont);
572 WMFont*
573 WMDefaultBoldSystemFont(WMScreen *scrPtr)
575 return WMRetainFont(scrPtr->boldFont);
579 static WMFont*
580 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
582 WMFont *font;
583 char *fontSpec, *xftFontSpec;
585 #define WConf WINGsConfiguration
586 if (bold) {
587 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
588 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
589 } else {
590 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
591 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
593 #undef WConf
595 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
596 font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec);
597 } else if (scrPtr->antialiasedText) {
598 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
599 } else if (scrPtr->useMultiByte) {
600 font = WMCreateFontSet(scrPtr, fontSpec);
601 } else {
602 font = WMCreateNormalFont(scrPtr, fontSpec);
605 if (!font) {
606 if (scrPtr->antialiasedText && scrPtr->useMultiByte) {
607 // is arial a good fallback for multibyte?
608 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
609 if (bold) {
610 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
611 } else {
612 font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
614 if (!font) {
615 wwarning(_("could not load antialiased font set. Reverting to standard font sets."));
616 font = WMCreateFontSet(scrPtr, fontSpec);
617 if (!font) {
618 wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec);
619 font = WMCreateFontSet(scrPtr, "fixed");
622 } else if (scrPtr->antialiasedText) {
623 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
624 if (bold) {
625 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
626 } else {
627 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
629 if (!font) {
630 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
631 font = WMCreateNormalFont(scrPtr, fontSpec);
632 if (!font) {
633 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
634 font = WMCreateNormalFont(scrPtr, "fixed");
637 } else if (scrPtr->useMultiByte) {
638 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
639 font = WMCreateFontSet(scrPtr, "fixed");
640 if (!font) {
641 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
643 } else {
644 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
645 font = WMCreateNormalFont(scrPtr, "fixed");
647 if (!font) {
648 wwarning(_("could not load fixed font!"));
649 wfree(fontSpec);
650 wfree(xftFontSpec);
651 return NULL;
654 wfree(fontSpec);
655 wfree(xftFontSpec);
657 return font;
661 WMFont*
662 WMSystemFontOfSize(WMScreen *scrPtr, int size)
664 return makeSystemFontOfSize(scrPtr, size, False);
668 WMFont*
669 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
671 return makeSystemFontOfSize(scrPtr, size, True);
675 XFontSet
676 WMGetFontFontSet(WMFont *font)
678 wassertrv(font!=NULL, NULL);
680 if (!font->notFontSet && !font->antialiased)
681 return font->font.set;
683 return NULL;
688 WMWidthOfString(WMFont *font, char *text, int length)
690 wassertrv(font!=NULL, 0);
691 wassertrv(text!=NULL, 0);
693 if (font->antialiased) {
694 #ifdef XFT
695 XGlyphInfo extents;
697 if (!font->notFontSet) {
698 wchar_t *wtext;
699 char *mtext;
700 int len;
702 /* Use mtext instead of text, because mbstrtowcs() alters it */
703 mtext = text;
704 wtext = (wchar_t *)wmalloc(4*length+4);
705 /* pass a real ps instead of NULL below? for multithread safety
706 * as from manual page */
707 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
708 if (len>0) {
709 XftTextExtents32(font->screen->display, font->font.xft,
710 (XftChar32 *)wtext, len, &extents);
711 } else {
712 if (len==-1) {
713 wwarning(_("Conversion to widechar failed (possible "
714 "invalid multibyte sequence): '%s':(pos %d)\n"),
715 text, mtext-text+1);
717 extents.xOff = 0;
719 wfree(wtext);
720 } else {
721 XftTextExtents8(font->screen->display, font->font.xft,
722 (XftChar8 *)text, length, &extents);
725 return extents.xOff; /* don't ask :P */
726 #else
727 wassertrv(False, 0);
728 #endif
729 } else if (font->notFontSet) {
730 return XTextWidth(font->font.normal, text, length);
731 } else {
732 XRectangle rect;
733 XRectangle AIXsucks;
735 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
737 return rect.width;
743 void
744 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
745 int x, int y, char *text, int length)
747 wassertr(font!=NULL);
749 if (font->antialiased) {
750 #ifdef XFT
751 XftColor xftcolor;
753 xftcolor.color.red = color->color.red;
754 xftcolor.color.green = color->color.green;
755 xftcolor.color.blue = color->color.blue;
756 xftcolor.color.alpha = color->alpha;;
757 xftcolor.pixel = W_PIXEL(color);
759 XftDrawChange(scr->xftdraw, d);
761 if (!font->notFontSet) {
762 wchar_t *wtext;
763 char *mtext;
764 int len;
766 /* Use mtext instead of text, because mbstrtowcs() alters it */
767 mtext = text;
768 wtext = (wchar_t *)wmalloc(4*length+4);
769 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
770 if (len>0) {
771 XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft,
772 x, y + font->y, (XftChar32*)wtext, len);
773 } else if (len==-1) {
774 wwarning(_("Conversion to widechar failed (possible invalid "
775 "multibyte sequence): '%s':(pos %d)\n"),
776 text, mtext-text+1);
777 /* we can draw normal text, or we can draw as much widechar
778 * text as was already converted until the error. go figure */
779 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
780 x, y + font->y, (XftChar8*)text, length);*/
782 wfree(wtext);
783 } else {
784 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
785 x, y + font->y, (XftChar8*)text, length);
787 #else
788 wassertr(False);
789 #endif
790 } else if (font->notFontSet) {
791 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
792 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
793 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
794 text, length);
795 } else {
796 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
797 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
798 x, y + font->y, text, length);
803 void
804 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
805 WMFont *font, int x, int y, char *text, int length)
807 wassertr(font!=NULL);
809 if (font->antialiased) {
810 #ifdef XFT
811 XftColor textColor;
812 XftColor bgColor;
814 textColor.color.red = color->color.red;
815 textColor.color.green = color->color.green;
816 textColor.color.blue = color->color.blue;
817 textColor.color.alpha = color->alpha;;
818 textColor.pixel = W_PIXEL(color);
820 bgColor.color.red = background->color.red;
821 bgColor.color.green = background->color.green;
822 bgColor.color.blue = background->color.blue;
823 bgColor.color.alpha = background->alpha;;
824 bgColor.pixel = W_PIXEL(background);
827 XftDrawChange(scr->xftdraw, d);
829 XftDrawRect(scr->xftdraw, &bgColor, x, y,
830 WMWidthOfString(font, text, length), font->height);
832 if (!font->notFontSet) {
833 wchar_t *wtext;
834 char *mtext;
835 int len;
837 /* Use mtext instead of text, because mbstrtowcs() alters it */
838 mtext = text;
839 wtext = (wchar_t *)wmalloc(4*length+4);
840 len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL);
841 if (len>0) {
842 XftDrawString32(scr->xftdraw, &textColor, font->font.xft,
843 x, y + font->y, (XftChar32*)wtext, len);
844 } else if (len==-1) {
845 wwarning(_("Conversion to widechar failed (possible invalid "
846 "multibyte sequence): '%s':(pos %d)\n"),
847 text, mtext-text+1);
848 /* we can draw normal text, or we can draw as much widechar
849 * text as was already converted until the error. go figure */
850 /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
851 x, y + font->y, (XftChar8*)text, length);*/
853 wfree(wtext);
854 } else {
855 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
856 x, y + font->y, (XftChar8*)text, length);
858 #else
859 wassertr(False);
860 #endif
861 } else if (font->notFontSet) {
862 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
863 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
864 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
865 XDrawImageString(scr->display, d, scr->drawImStringGC,
866 x, y + font->y, text, length);
867 } else {
868 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
869 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
870 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
871 x, y + font->y, text, length);
878 static char*
879 makeFontSetOfSize(char *fontset, int size)
881 char font[300], *f;
882 char *newfs = NULL;
883 char *ptr;
885 do {
886 char *tmp;
887 int end;
890 f = fontset;
891 ptr = strchr(fontset, ',');
892 if (ptr) {
893 int count = ptr-fontset;
895 if (count > 255) {
896 wwarning(_("font description %s is too large."), fontset);
897 } else {
898 memcpy(font, fontset, count);
899 font[count] = 0;
900 f = (char*)font;
904 if (newfs)
905 end = strlen(newfs);
906 else
907 end = 0;
909 tmp = wmalloc(end + strlen(f) + 8);
910 if (end != 0) {
911 sprintf(tmp, "%s,", newfs);
912 sprintf(tmp + end + 1, f, size);
913 } else {
914 sprintf(tmp + end, f, size);
917 if (newfs)
918 wfree(newfs);
919 newfs = tmp;
921 fontset = ptr+1;
922 } while (ptr!=NULL);
924 return newfs;
928 #define FONT_PROPS 14
930 typedef struct {
931 char *props[FONT_PROPS];
932 } W_FontAttributes;
935 static void
936 changeFontProp(char *buf, char *newprop, int position)
938 char buf2[512];
939 char *ptr, *pptr, *rptr;
940 int count;
942 if (buf[0]!='-') {
943 /* // remove warning later. or maybe not */
944 wwarning(_("Invalid font specification: '%s'\n"), buf);
945 return;
948 ptr = pptr = rptr = buf;
949 count = 0;
950 while (*ptr && *ptr!=',') {
951 if (*ptr == '-') {
952 count++;
953 if (count-1==position+1) {
954 rptr = ptr;
955 break;
957 if (count-1==position) {
958 pptr = ptr+1;
961 ptr++;
963 if (position==FONT_PROPS-1) {
964 rptr = ptr;
967 *pptr = 0;
968 snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr);
969 strcpy(buf, buf2);
973 static WMArray*
974 getOptions(char *options)
976 char *ptr, *ptr2, *str;
977 WMArray *result;
978 int count;
980 result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree);
982 ptr = options;
983 while (1) {
984 ptr2 = strchr(ptr, ',');
985 if (!ptr2) {
986 WMAddToArray(result, wstrdup(ptr));
987 break;
988 } else {
989 count = ptr2 - ptr;
990 str = wmalloc(count+1);
991 memcpy(str, ptr, count);
992 str[count] = 0;
993 WMAddToArray(result, str);
994 ptr = ptr2 + 1;
998 return result;
1002 WMFont*
1003 WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font,
1004 const WMFontAttributes *changes)
1006 int index[FONT_PROPS], count[FONT_PROPS];
1007 int totalProps, i, j, carry;
1008 char fname[512];
1009 WMFontFlags fFlags;
1010 WMBag *props;
1011 WMArray *options;
1012 WMFont *result;
1013 char *prop;
1015 snprintf(fname, 512, "%s", font->name);
1017 fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased);
1018 fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet);
1020 props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray);
1022 totalProps = 0;
1023 for (i=0; i<FONT_PROPS; i++) {
1024 prop = ((W_FontAttributes*)changes)->props[i];
1025 count[i] = index[i] = 0;
1026 if (!prop) {
1027 /* No change for this property */
1028 continue;
1029 } else if (strchr(prop, ',')==NULL) {
1030 /* Simple option */
1031 changeFontProp(fname, prop, i);
1032 } else {
1033 /* Option with fallback alternatives */
1034 if ((changes==WFAEmphasized || changes==WFABoldEmphasized) &&
1035 font->antialiased && strcmp(prop, "o,i")==0) {
1036 options = getOptions("i,o");
1037 } else {
1038 options = getOptions(prop);
1040 WMInsertInBag(props, i, options);
1041 count[i] = WMGetArrayItemCount(options);
1042 if (totalProps==0)
1043 totalProps = 1;
1044 totalProps = totalProps * count[i];
1048 if (totalProps == 0) {
1049 /* No options with fallback alternatives at all */
1050 WMFreeBag(props);
1051 return WMCreateFontWithFlags(scrPtr, fname, fFlags);
1054 for (i=0; i<totalProps; i++) {
1055 for (j=0; j<FONT_PROPS; j++) {
1056 if (count[j]!=0) {
1057 options = WMGetFromBag(props, j);
1058 prop = WMGetFromArray(options, index[j]);
1059 if (prop) {
1060 changeFontProp(fname, prop, j);
1064 result = WMCreateFontWithFlags(scrPtr, fname, fFlags);
1065 if (result) {
1066 WMFreeBag(props);
1067 return result;
1069 for (j=FONT_PROPS-1, carry=1; j>=0; j--) {
1070 if (count[j]!=0) {
1071 index[j] += carry;
1072 carry = (index[j]==count[j]);
1073 index[j] %= count[j];
1078 WMFreeBag(props);
1080 return NULL;
1085 // should WFANormal also set "normal" or leave it alone?
1086 static const WMFontAttributes W_FANormal = {
1087 WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal",
1088 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1089 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1093 static const WMFontAttributes W_FABold = {
1094 WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged,
1095 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1096 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1100 static const WMFontAttributes W_FANotBold = {
1101 WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged,
1102 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1103 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1107 static const WMFontAttributes W_FAEmphasized = {
1108 WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i",
1109 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1110 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1114 static const WMFontAttributes W_FANotEmphasized = {
1115 WFAUnchanged, WFAUnchanged, WFAUnchanged, "r",
1116 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1117 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1121 static const WMFontAttributes W_FABoldEmphasized = {
1122 WFAUnchanged, WFAUnchanged, "bold", "o,i",
1123 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged,
1124 WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged
1128 const WMFontAttributes *WFANormal = &W_FANormal;
1129 const WMFontAttributes *WFABold = &W_FABold;
1130 const WMFontAttributes *WFANotBold = &W_FANotBold;
1131 const WMFontAttributes *WFAEmphasized = &W_FAEmphasized;
1132 const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized;
1133 const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized;