Added Xft support in WINGs (for drawing antialiased fonts with transparency)
[wmaker-crm.git] / WINGs / wfont.c
blobc9d94f9b3e0d936722f1d23e430087a157795100
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>
16 static char *makeFontSetOfSize(char *fontset, int size);
20 /* XLFD pattern matching */
21 static char*
22 getElementFromXLFD(const char *xlfd, int index)
24 const char *p = xlfd;
25 while (*p != 0) {
26 if (*p == '-' && --index == 0) {
27 const char *end = strchr(p + 1, '-');
28 char *buf;
29 size_t len;
30 if (end == 0) end = p + strlen(p);
31 len = end - (p + 1);
32 buf = wmalloc(len);
33 memcpy(buf, p + 1, len);
34 buf[len] = 0;
35 return buf;
37 p++;
39 return strdup("*");
43 /* XLFD pattern matching */
44 static char*
45 generalizeXLFD(const char *xlfd)
47 char *buf;
48 int len;
49 char *weight = getElementFromXLFD(xlfd, 3);
50 char *slant = getElementFromXLFD(xlfd, 4);
51 char *pxlsz = getElementFromXLFD(xlfd, 7);
53 #define Xstrlen(A) ((A)?strlen(A):0)
54 len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60;
55 #undef Xstrlen
57 buf = wmalloc(len + 1);
58 snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*,"
59 "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*",
60 xlfd, weight, slant, pxlsz, pxlsz);
62 wfree(pxlsz);
63 wfree(slant);
64 wfree(weight);
66 return buf;
69 /* XLFD pattern matching */
70 static XFontSet
71 W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing,
72 int *nmissing, char **def_string)
74 XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
76 if (fs != NULL && *nmissing == 0) return fs;
78 /* for non-iso8859-1 language and iso8859-1 specification
79 (this fontset is only for pattern analysis) */
80 if (fs == NULL) {
81 if (*nmissing != 0) XFreeStringList(*missing);
82 setlocale(LC_CTYPE, "C");
83 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
84 setlocale(LC_CTYPE, "");
87 /* make XLFD font name for pattern analysis */
88 if (fs != NULL) {
89 XFontStruct **fontstructs;
90 char **fontnames;
91 if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0)
92 xlfd = fontnames[0];
95 xlfd = generalizeXLFD(xlfd);
97 if (*nmissing != 0) XFreeStringList(*missing);
98 if (fs != NULL) XFreeFontSet(dpy, fs);
100 fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string);
102 wfree(xlfd);
103 return fs;
107 WMFont*
108 WMCreateFontSet(WMScreen *scrPtr, char *fontName)
110 WMFont *font;
111 Display *display = scrPtr->display;
112 char **missing;
113 int nmissing = 0;
114 char *defaultString;
115 XFontSetExtents *extents;
117 font = WMHashGet(scrPtr->fontSetCache, fontName);
118 if (font) {
119 WMRetainFont(font);
120 return font;
123 font = malloc(sizeof(WMFont));
124 if (!font)
125 return NULL;
126 memset(font, 0, sizeof(WMFont));
128 font->notFontSet = 0;
129 font->antialiased = 0;
131 font->screen = scrPtr;
133 font->font.set = W_CreateFontSetWithGuess(display, fontName, &missing,
134 &nmissing, &defaultString);
135 if (nmissing > 0 && font->font.set) {
136 int i;
138 wwarning(_("the following character sets are missing in %s:"),
139 fontName);
140 for (i = 0; i < nmissing; i++) {
141 wwarning(missing[i]);
143 XFreeStringList(missing);
144 if (defaultString)
145 wwarning(_("the string \"%s\" will be used in place of any characters from those sets."),
146 defaultString);
148 if (!font->font.set) {
149 wfree(font);
150 return NULL;
153 extents = XExtentsOfFontSet(font->font.set);
155 font->height = extents->max_logical_extent.height;
156 font->y = font->height - (font->height + extents->max_logical_extent.y);
158 font->refCount = 1;
160 font->name = wstrdup(fontName);
162 assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL);
164 return font;
169 WMFont*
170 WMCreateNormalFont(WMScreen *scrPtr, char *fontName)
172 WMFont *font;
173 Display *display = scrPtr->display;
174 char *fname, *ptr;
176 if ((ptr = strchr(fontName, ','))) {
177 fname = wmalloc(ptr - fontName + 1);
178 strncpy(fname, fontName, ptr - fontName);
179 fname[ptr - fontName] = 0;
180 } else {
181 fname = wstrdup(fontName);
184 font = WMHashGet(scrPtr->fontCache, fname);
185 if (font) {
186 WMRetainFont(font);
187 wfree(fname);
188 return font;
191 font = malloc(sizeof(WMFont));
192 if (!font) {
193 wfree(fname);
194 return NULL;
196 memset(font, 0, sizeof(WMFont));
198 font->notFontSet = 1;
199 font->antialiased = 0;
201 font->screen = scrPtr;
203 font->font.normal = XLoadQueryFont(display, fname);
204 if (!font->font.normal) {
205 wfree(font);
206 wfree(fname);
207 return NULL;
209 font->height = font->font.normal->ascent+font->font.normal->descent;
210 font->y = font->font.normal->ascent;
212 font->refCount = 1;
214 font->name = fname;
216 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
218 return font;
222 WMFont*
223 WMCreateAAFont(WMScreen *scrPtr, char *fontName)
225 #ifdef XFT
226 WMFont *font;
227 Display *display = scrPtr->display;
228 char *fname, *ptr;
230 if ((ptr = strchr(fontName, ','))) {
231 fname = wmalloc(ptr - fontName + 1);
232 strncpy(fname, fontName, ptr - fontName);
233 fname[ptr - fontName] = 0;
234 } else {
235 fname = wstrdup(fontName);
238 font = WMHashGet(scrPtr->fontCache, fname);
239 if (font) {
240 WMRetainFont(font);
241 wfree(fname);
242 return font;
245 font = malloc(sizeof(WMFont));
246 if (!font) {
247 wfree(fname);
248 return NULL;
250 memset(font, 0, sizeof(WMFont));
252 font->notFontSet = 1;
253 font->antialiased = 1;
255 font->screen = scrPtr;
257 /* // Xft sux */
258 font->font.normal = XLoadQueryFont(display, fname);
259 if (!font->font.normal) {
260 wfree(font);
261 wfree(fname);
262 return NULL;
264 XFreeFont(display, font->font.normal);
266 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
267 if (!font->font.xft) {
268 wfree(font);
269 wfree(fname);
270 return NULL;
272 font->height = font->font.xft->ascent+font->font.xft->descent;
273 font->y = font->font.xft->ascent;
275 font->refCount = 1;
277 font->name = fname;
279 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
281 return font;
282 #else
283 return NULL;
284 #endif
288 WMFont*
289 WMCreateFont(WMScreen *scrPtr, char *fontName)
291 if (scrPtr->useMultiByte) {
292 return WMCreateFontSet(scrPtr, fontName);
293 } else if (scrPtr->antialiasedText) {
294 /*// should revert to normal if this fails? */
295 return WMCreateAAFont(scrPtr, fontName);
296 } else {
297 return WMCreateNormalFont(scrPtr, fontName);
302 WMFont*
303 WMRetainFont(WMFont *font)
305 wassertrv(font!=NULL, NULL);
307 font->refCount++;
309 return font;
313 void
314 WMReleaseFont(WMFont *font)
316 wassertr(font!=NULL);
318 font->refCount--;
319 if (font->refCount < 1) {
320 if (font->notFontSet) {
321 if (font->antialiased) {
322 #ifdef XFT
323 XftFontClose(font->screen->display, font->font.xft);
324 #else
325 assert(False);
326 #endif
327 } else {
328 XFreeFont(font->screen->display, font->font.normal);
330 } else {
331 XFreeFontSet(font->screen->display, font->font.set);
333 if (font->name) {
334 if (font->notFontSet) {
335 WMHashRemove(font->screen->fontCache, font->name);
336 } else {
337 WMHashRemove(font->screen->fontSetCache, font->name);
339 wfree(font->name);
341 wfree(font);
347 unsigned int
348 WMFontHeight(WMFont *font)
350 wassertrv(font!=NULL, 0);
352 return font->height;
356 WMFont*
357 WMDefaultSystemFont(WMScreen *scrPtr)
359 return WMRetainFont(scrPtr->normalFont);
363 WMFont*
364 WMDefaultBoldSystemFont(WMScreen *scrPtr)
366 return WMRetainFont(scrPtr->boldFont);
370 static WMFont*
371 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
373 WMFont *font;
374 char *fontSpec, *aaFontSpec;
376 if (bold) {
377 fontSpec = makeFontSetOfSize(WINGsConfiguration.boldSystemFont, size);
378 aaFontSpec = makeFontSetOfSize(WINGsConfiguration.aaBoldSystemFont, size);
379 } else {
380 fontSpec = makeFontSetOfSize(WINGsConfiguration.systemFont, size);
381 aaFontSpec = makeFontSetOfSize(WINGsConfiguration.aaSystemFont, size);
384 if (scrPtr->useMultiByte) {
385 font = WMCreateFontSet(scrPtr, fontSpec);
386 } else if (scrPtr->antialiasedText) {
387 font = WMCreateAAFont(scrPtr, aaFontSpec);
388 } else {
389 font = WMCreateNormalFont(scrPtr, fontSpec);
392 if (!font) {
393 if (scrPtr->useMultiByte) {
394 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
395 font = WMCreateFontSet(scrPtr, "fixed");
396 if (!font) {
397 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
399 } else if (scrPtr->antialiasedText) {
400 wwarning(_("could not load font %s. Trying arial."), aaFontSpec);
401 if (bold) {
402 font = WMCreateAAFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
403 } else {
404 font = WMCreateAAFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
406 if (!font) {
407 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
408 font = WMCreateNormalFont(scrPtr, fontSpec);
409 if (!font) {
410 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
411 font = WMCreateNormalFont(scrPtr, "fixed");
414 } else {
415 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
416 font = WMCreateNormalFont(scrPtr, "fixed");
418 if (!font) {
419 wwarning(_("could not load fixed font!"));
420 wfree(fontSpec);
421 wfree(aaFontSpec);
422 return NULL;
425 wfree(fontSpec);
426 wfree(aaFontSpec);
428 return font;
432 WMFont*
433 WMSystemFontOfSize(WMScreen *scrPtr, int size)
435 return makeSystemFontOfSize(scrPtr, size, False);
439 WMFont*
440 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
442 return makeSystemFontOfSize(scrPtr, size, True);
446 XFontSet
447 WMGetFontFontSet(WMFont *font)
449 wassertrv(font!=NULL, NULL);
451 if (font->notFontSet)
452 return NULL;
453 else
454 return font->font.set;
459 WMWidthOfString(WMFont *font, char *text, int length)
461 wassertrv(font!=NULL, 0);
462 wassertrv(text!=NULL, 0);
464 if (font->notFontSet) {
465 if (font->antialiased) {
466 #ifdef XFT
467 XGlyphInfo extents;
469 XftTextExtents8(font->screen->display, font->font.xft,
470 (XftChar8 *)text, length, &extents);
471 return extents.xOff; /* don't ask :P */
472 #else
473 assert(False);
474 #endif
475 } else {
476 return XTextWidth(font->font.normal, text, length);
478 } else {
479 XRectangle rect;
480 XRectangle AIXsucks;
482 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
484 return rect.width;
490 void
491 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
492 int x, int y, char *text, int length)
494 wassertr(font!=NULL);
496 if (font->notFontSet) {
497 if (font->antialiased) {
498 #ifdef XFT
499 XftColor xftcolor;
500 XftDraw *xftdraw;
502 xftcolor.color.red = color->color.red;
503 xftcolor.color.green = color->color.green;
504 xftcolor.color.blue = color->color.blue;
505 xftcolor.color.alpha = color->alpha;;
506 xftcolor.pixel = W_PIXEL(color);
508 /* //share if possible */
509 xftdraw = XftDrawCreate(scr->display, d, scr->visual, scr->colormap);
511 XftDrawString8(xftdraw, &xftcolor, font->font.xft,
512 x, y + font->y, text, length);
514 XftDrawDestroy(xftdraw);
515 #else
516 assert(False);
517 #endif
518 } else {
519 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
520 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
521 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
522 text, length);
524 } else {
525 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
526 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
527 x, y + font->y, text, length);
532 void
533 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
534 WMFont *font, int x, int y, char *text, int length)
536 wassertr(font != NULL);
538 if (font->notFontSet) {
539 if (font->antialiased) {
540 #ifdef XFT
541 XftColor textColor;
542 XftColor bgColor;
543 XftDraw *xftdraw;
545 textColor.color.red = color->color.red;
546 textColor.color.green = color->color.green;
547 textColor.color.blue = color->color.blue;
548 textColor.color.alpha = color->alpha;;
549 textColor.pixel = W_PIXEL(color);
551 bgColor.color.red = background->color.red;
552 bgColor.color.green = background->color.green;
553 bgColor.color.blue = background->color.blue;
554 bgColor.color.alpha = background->alpha;;
555 bgColor.pixel = W_PIXEL(background);
557 /* //share if possible */
558 xftdraw = XftDrawCreate(scr->display, d, scr->visual, scr->colormap);
560 XftDrawRect(xftdraw, &bgColor, x, y,
561 WMWidthOfString(font, text, length), font->height);
563 XftDrawString8(xftdraw, &textColor, font->font.xft, x, y + font->y,
564 text, length);
566 XftDrawDestroy(xftdraw);
567 #else
568 assert(False);
569 #endif
570 } else {
571 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
572 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
573 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
574 XDrawImageString(scr->display, d, scr->drawImStringGC,
575 x, y + font->y, text, length);
577 } else {
578 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
579 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
580 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
581 x, y + font->y, text, length);
588 static char*
589 makeFontSetOfSize(char *fontset, int size)
591 char font[300], *f;
592 char *newfs = NULL;
593 char *ptr;
595 do {
596 char *tmp;
597 int end;
600 f = fontset;
601 ptr = strchr(fontset, ',');
602 if (ptr) {
603 int count = ptr-fontset;
605 if (count > 255) {
606 wwarning(_("font description %s is too large."), fontset);
607 } else {
608 memcpy(font, fontset, count);
609 font[count] = 0;
610 f = (char*)font;
614 if (newfs)
615 end = strlen(newfs);
616 else
617 end = 0;
619 tmp = wmalloc(end + strlen(f) + 8);
620 if (end != 0) {
621 sprintf(tmp, "%s,", newfs);
622 sprintf(tmp + end + 1, f, size);
623 } else {
624 sprintf(tmp + end, f, size);
627 if (newfs)
628 wfree(newfs);
629 newfs = tmp;
631 fontset = ptr+1;
632 } while (ptr!=NULL);
634 return newfs;
638 static void
639 changeFontProp(char *fname, char *newprop, int which)
641 char before[128], prop[128], after[128];
642 char *ptr, *bptr;
643 int part=0;
645 if (!fname || !prop)
646 return;
648 ptr = fname;
649 bptr = before;
650 while (*ptr) {
651 if(*ptr == '-') {
652 *bptr = 0;
653 if (part==which)
654 bptr = prop;
655 else if (part==which+1)
656 bptr = after;
657 *bptr++ = *ptr;
658 part++;
659 } else {
660 *bptr++ = *ptr;
662 ptr++;
664 *bptr = 0;
665 snprintf(fname, 255, "%s-%s%s", before, newprop, after);
669 WMFont*
670 WMNormalizeFont(WMScreen *scr, WMFont *font)
672 WMFont *newfont=NULL;
673 char fname[256];
675 if (!scr || !font)
676 return NULL;
678 snprintf(fname, 255, "%s", font->name);
679 changeFontProp(fname, "medium", 2);
680 changeFontProp(fname, "r", 3);
681 newfont = WMCreateNormalFont(scr, fname);
683 if (!newfont)
684 return NULL;
686 return newfont;
690 WMFont*
691 WMStrengthenFont(WMScreen *scr, WMFont *font)
693 WMFont *newfont=NULL;
694 char fname[256];
696 if (!scr || !font)
697 return NULL;
699 snprintf(fname, 255, "%s", font->name);
700 changeFontProp(fname, "bold", 2);
701 newfont = WMCreateNormalFont(scr, fname);
703 if (!newfont)
704 return NULL;
706 return newfont;
710 WMFont*
711 WMUnstrengthenFont(WMScreen *scr, WMFont *font)
713 WMFont *newfont=NULL;
714 char fname[256];
716 if (!scr || !font)
717 return NULL;
719 snprintf(fname, 255, "%s", font->name);
720 changeFontProp(fname, "medium", 2);
721 newfont = WMCreateNormalFont(scr, fname);
723 if (!newfont)
724 return NULL;
726 return newfont;
730 WMFont*
731 WMEmphasizeFont(WMScreen *scr, WMFont *font)
733 WMFont *newfont=NULL;
734 char fname[256];
736 if (!scr || !font)
737 return NULL;
739 snprintf(fname, 255, "%s", font->name);
740 changeFontProp(fname, "o", 3);
741 newfont = WMCreateNormalFont(scr, fname);
743 if (!newfont)
744 return NULL;
746 return newfont;
750 WMFont*
751 WMUnemphasizeFont(WMScreen *scr, WMFont *font)
753 WMFont *newfont=NULL;
754 char fname[256];
756 if (!scr || !font)
757 return NULL;
759 snprintf(fname, 255, "%s", font->name);
760 changeFontProp(fname, "r", 3);
761 newfont = WMCreateNormalFont(scr, fname);
763 if (!newfont)
764 return NULL;
766 return newfont;
770 WMFont*
771 WMGetFontOfSize(WMScreen *scr, WMFont *font, int size)
773 if(!scr || !font || size<1)
774 return NULL;
776 return font;