- Fixed userdefaults in WINGs not to synchronize on exit a domain that is
[wmaker-crm.git] / WINGs / wfont.c
blob098803c0a1cb56b26fd7cc55b9c1c57ab72253f6
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 static char*
108 xlfdFromFontName(char *fontName, Bool antialiased)
110 char *systemFont, *boldSystemFont;
111 char *font;
112 int size;
114 if (antialiased) {
115 systemFont = WINGsConfiguration.antialiasedSystemFont;
116 boldSystemFont = WINGsConfiguration.antialiasedBoldSystemFont;
117 } else {
118 systemFont = WINGsConfiguration.systemFont;
119 boldSystemFont = WINGsConfiguration.boldSystemFont;
122 size = WINGsConfiguration.defaultFontSize;
124 if (strcmp(fontName, "SystemFont")==0) {
125 font = systemFont;
126 size = WINGsConfiguration.defaultFontSize;
127 } else if (strncmp(fontName, "SystemFont-", 11)==0) {
128 font = systemFont;
129 if (sscanf(&fontName[11], "%i", &size)!=1) {
130 size = WINGsConfiguration.defaultFontSize;
131 wwarning(_("Invalid size specification '%s' in %s. "
132 "Using default %d\n"), &fontName[11], fontName, size);
134 } else if (strcmp(fontName, "BoldSystemFont")==0) {
135 font = boldSystemFont;
136 size = WINGsConfiguration.defaultFontSize;
137 } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) {
138 font = boldSystemFont;
139 if (sscanf(&fontName[15], "%i", &size)!=1) {
140 size = WINGsConfiguration.defaultFontSize;
141 wwarning(_("Invalid size specification '%s' in %s. "
142 "Using default %d\n"), &fontName[15], fontName, size);
144 } else {
145 font = NULL;
148 return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName));
152 WMFont*
153 WMCreateFontSet(WMScreen *scrPtr, char *fontName)
155 WMFont *font;
156 Display *display = scrPtr->display;
157 char **missing;
158 int nmissing = 0;
159 char *defaultString;
160 char *fname;
161 XFontSetExtents *extents;
163 fname = xlfdFromFontName(fontName, False);
165 font = WMHashGet(scrPtr->fontSetCache, fname);
166 if (font) {
167 WMRetainFont(font);
168 wfree(fname);
169 return font;
172 font = wmalloc(sizeof(WMFont));
173 memset(font, 0, sizeof(WMFont));
175 font->notFontSet = 0;
176 font->antialiased = 0;
178 font->screen = scrPtr;
180 font->font.set = W_CreateFontSetWithGuess(display, fname, &missing,
181 &nmissing, &defaultString);
182 if (nmissing > 0 && font->font.set) {
183 int i;
185 wwarning(_("the following character sets are missing in %s:"), fname);
186 for (i = 0; i < nmissing; i++) {
187 wwarning(missing[i]);
189 XFreeStringList(missing);
190 if (defaultString)
191 wwarning(_("the string \"%s\" will be used in place of any characters from those sets."),
192 defaultString);
194 if (!font->font.set) {
195 wfree(font);
196 wfree(fname);
197 return NULL;
200 extents = XExtentsOfFontSet(font->font.set);
202 font->height = extents->max_logical_extent.height;
203 font->y = font->height - (font->height + extents->max_logical_extent.y);
205 font->refCount = 1;
207 font->name = fname;
209 assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL);
211 return font;
216 WMFont*
217 WMCreateNormalFont(WMScreen *scrPtr, char *fontName)
219 WMFont *font;
220 Display *display = scrPtr->display;
221 char *fname, *ptr;
223 fontName = xlfdFromFontName(fontName, False);
225 if ((ptr = strchr(fontName, ','))) {
226 fname = wmalloc(ptr - fontName + 1);
227 strncpy(fname, fontName, ptr - fontName);
228 fname[ptr - fontName] = 0;
229 } else {
230 fname = wstrdup(fontName);
233 wfree(fontName);
235 font = WMHashGet(scrPtr->fontCache, fname);
236 if (font) {
237 WMRetainFont(font);
238 wfree(fname);
239 return font;
242 font = wmalloc(sizeof(WMFont));
243 memset(font, 0, sizeof(WMFont));
245 font->notFontSet = 1;
246 font->antialiased = 0;
248 font->screen = scrPtr;
250 font->font.normal = XLoadQueryFont(display, fname);
251 if (!font->font.normal) {
252 wfree(font);
253 wfree(fname);
254 return NULL;
256 font->height = font->font.normal->ascent+font->font.normal->descent;
257 font->y = font->font.normal->ascent;
259 font->refCount = 1;
261 font->name = fname;
263 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
265 return font;
269 WMFont*
270 WMCreateAntialiasedFont(WMScreen *scrPtr, char *fontName)
272 #ifdef XFT
273 WMFont *font;
274 Display *display = scrPtr->display;
275 char *fname, *ptr;
277 if (!scrPtr->hasXftSupport)
278 return NULL;
280 fontName = xlfdFromFontName(fontName, True);
282 if ((ptr = strchr(fontName, ','))) {
283 fname = wmalloc(ptr - fontName + 1);
284 strncpy(fname, fontName, ptr - fontName);
285 fname[ptr - fontName] = 0;
286 } else {
287 fname = wstrdup(fontName);
290 wfree(fontName);
292 font = WMHashGet(scrPtr->xftFontCache, fname);
293 if (font) {
294 WMRetainFont(font);
295 wfree(fname);
296 return font;
299 font = wmalloc(sizeof(WMFont));
300 memset(font, 0, sizeof(WMFont));
302 font->notFontSet = 1;
303 font->antialiased = 1;
305 font->screen = scrPtr;
307 #if 0
308 /* // Xft sux. Loading a font that doesn't exist will load the default
309 * defined in XftConfig without any warning or error */
310 font->font.normal = XLoadQueryFont(display, fname);
311 if (!font->font.normal) {
312 wfree(font);
313 wfree(fname);
314 return NULL;
316 XFreeFont(display, font->font.normal);
317 #endif
319 font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname);
320 if (!font->font.xft) {
321 wfree(font);
322 wfree(fname);
323 return NULL;
325 font->height = font->font.xft->ascent+font->font.xft->descent;
326 font->y = font->font.xft->ascent;
328 font->refCount = 1;
330 font->name = fname;
332 assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL);
334 return font;
335 #else
336 return NULL;
337 #endif
341 WMFont*
342 WMCreateFont(WMScreen *scrPtr, char *fontName)
344 return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont);
348 WMFont*
349 WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags)
351 Bool multiByte = scrPtr->useMultiByte;
352 Bool antialiased = scrPtr->antialiasedText;
353 WMFont *font;
355 if (flags & WFFontSet) {
356 multiByte = True;
357 } else if (flags & WFNormalFont) {
358 multiByte = False;
360 if (flags & WFAntialiased) {
361 antialiased = True;
362 } else if (flags & WFNotAntialiased) {
363 antialiased = False;
366 /* Multibyte with antialiasing is not implemented. To avoid problems,
367 * if both multiByte and antialiasing are enabled, ignore antialiasing
368 * and return a FontSet.
370 if (multiByte) {
371 font = WMCreateFontSet(scrPtr, fontName);
372 } else if (antialiased) {
373 font = WMCreateAntialiasedFont(scrPtr, fontName);
374 /* If we cannot create an antialiased font and antialiasing is
375 * not explicitly requested in flags, fallback to normal font */
376 if (!font && (flags & WFAntialiased)==0) {
377 font = WMCreateNormalFont(scrPtr, fontName);
379 } else {
380 font = WMCreateNormalFont(scrPtr, fontName);
383 return font;
387 WMFont*
388 WMRetainFont(WMFont *font)
390 wassertrv(font!=NULL, NULL);
392 font->refCount++;
394 return font;
398 void
399 WMReleaseFont(WMFont *font)
401 wassertr(font!=NULL);
403 font->refCount--;
404 if (font->refCount < 1) {
405 if (font->notFontSet) {
406 if (font->antialiased) {
407 #ifdef XFT
408 XftFontClose(font->screen->display, font->font.xft);
409 #else
410 assert(False);
411 #endif
412 } else {
413 XFreeFont(font->screen->display, font->font.normal);
415 } else {
416 XFreeFontSet(font->screen->display, font->font.set);
418 if (font->name) {
419 if (font->antialiased) {
420 WMHashRemove(font->screen->xftFontCache, font->name);
421 } else if (font->notFontSet) {
422 WMHashRemove(font->screen->fontCache, font->name);
423 } else {
424 WMHashRemove(font->screen->fontSetCache, font->name);
426 wfree(font->name);
428 wfree(font);
433 Bool
434 WMHasAntialiasingSupport(WMScreen *scrPtr)
436 return scrPtr->hasXftSupport;
440 Bool
441 WMIsAntialiasingEnabled(WMScreen *scrPtr)
443 return scrPtr->antialiasedText;
447 Bool
448 WMIsAntialiasedFont(WMFont *font)
450 return font->antialiased;
454 unsigned int
455 WMFontHeight(WMFont *font)
457 wassertrv(font!=NULL, 0);
459 return font->height;
463 WMFont*
464 WMDefaultSystemFont(WMScreen *scrPtr)
466 return WMRetainFont(scrPtr->normalFont);
470 WMFont*
471 WMDefaultBoldSystemFont(WMScreen *scrPtr)
473 return WMRetainFont(scrPtr->boldFont);
477 static WMFont*
478 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
480 WMFont *font;
481 char *fontSpec, *xftFontSpec;
483 #define WConf WINGsConfiguration
484 if (bold) {
485 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
486 xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
487 } else {
488 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
489 xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
491 #undef WConf
493 if (scrPtr->useMultiByte) {
494 font = WMCreateFontSet(scrPtr, fontSpec);
495 } else if (scrPtr->antialiasedText) {
496 font = WMCreateAntialiasedFont(scrPtr, xftFontSpec);
497 } else {
498 font = WMCreateNormalFont(scrPtr, fontSpec);
501 if (!font) {
502 if (scrPtr->useMultiByte) {
503 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
504 font = WMCreateFontSet(scrPtr, "fixed");
505 if (!font) {
506 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
508 } else if (scrPtr->antialiasedText) {
509 wwarning(_("could not load font %s. Trying arial."), xftFontSpec);
510 if (bold) {
511 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
512 } else {
513 font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
515 if (!font) {
516 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
517 font = WMCreateNormalFont(scrPtr, fontSpec);
518 if (!font) {
519 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
520 font = WMCreateNormalFont(scrPtr, "fixed");
523 } else {
524 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
525 font = WMCreateNormalFont(scrPtr, "fixed");
527 if (!font) {
528 wwarning(_("could not load fixed font!"));
529 wfree(fontSpec);
530 wfree(xftFontSpec);
531 return NULL;
534 wfree(fontSpec);
535 wfree(xftFontSpec);
537 return font;
541 WMFont*
542 WMSystemFontOfSize(WMScreen *scrPtr, int size)
544 return makeSystemFontOfSize(scrPtr, size, False);
548 WMFont*
549 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
551 return makeSystemFontOfSize(scrPtr, size, True);
555 XFontSet
556 WMGetFontFontSet(WMFont *font)
558 wassertrv(font!=NULL, NULL);
560 if (font->notFontSet)
561 return NULL;
562 else
563 return font->font.set;
568 WMWidthOfString(WMFont *font, char *text, int length)
570 wassertrv(font!=NULL, 0);
571 wassertrv(text!=NULL, 0);
573 if (font->notFontSet) {
574 if (font->antialiased) {
575 #ifdef XFT
576 XGlyphInfo extents;
578 XftTextExtents8(font->screen->display, font->font.xft,
579 (XftChar8 *)text, length, &extents);
580 return extents.xOff; /* don't ask :P */
581 #else
582 assert(False);
583 #endif
584 } else {
585 return XTextWidth(font->font.normal, text, length);
587 } else {
588 XRectangle rect;
589 XRectangle AIXsucks;
591 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
593 return rect.width;
599 void
600 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
601 int x, int y, char *text, int length)
603 wassertr(font!=NULL);
605 if (font->notFontSet) {
606 if (font->antialiased) {
607 #ifdef XFT
608 XftColor xftcolor;
610 xftcolor.color.red = color->color.red;
611 xftcolor.color.green = color->color.green;
612 xftcolor.color.blue = color->color.blue;
613 xftcolor.color.alpha = color->alpha;;
614 xftcolor.pixel = W_PIXEL(color);
616 XftDrawChange(scr->xftdraw, d);
618 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
619 x, y + font->y, text, length);
620 #else
621 assert(False);
622 #endif
623 } else {
624 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
625 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
626 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
627 text, length);
629 } else {
630 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
631 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
632 x, y + font->y, text, length);
637 void
638 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
639 WMFont *font, int x, int y, char *text, int length)
641 wassertr(font != NULL);
643 if (font->notFontSet) {
644 if (font->antialiased) {
645 #ifdef XFT
646 XftColor textColor;
647 XftColor bgColor;
649 textColor.color.red = color->color.red;
650 textColor.color.green = color->color.green;
651 textColor.color.blue = color->color.blue;
652 textColor.color.alpha = color->alpha;;
653 textColor.pixel = W_PIXEL(color);
655 bgColor.color.red = background->color.red;
656 bgColor.color.green = background->color.green;
657 bgColor.color.blue = background->color.blue;
658 bgColor.color.alpha = background->alpha;;
659 bgColor.pixel = W_PIXEL(background);
662 XftDrawChange(scr->xftdraw, d);
664 XftDrawRect(scr->xftdraw, &bgColor, x, y,
665 WMWidthOfString(font, text, length), font->height);
667 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
668 x, y + font->y, text, length);
669 #else
670 assert(False);
671 #endif
672 } else {
673 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
674 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
675 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
676 XDrawImageString(scr->display, d, scr->drawImStringGC,
677 x, y + font->y, text, length);
679 } else {
680 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
681 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
682 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
683 x, y + font->y, text, length);
690 static char*
691 makeFontSetOfSize(char *fontset, int size)
693 char font[300], *f;
694 char *newfs = NULL;
695 char *ptr;
697 do {
698 char *tmp;
699 int end;
702 f = fontset;
703 ptr = strchr(fontset, ',');
704 if (ptr) {
705 int count = ptr-fontset;
707 if (count > 255) {
708 wwarning(_("font description %s is too large."), fontset);
709 } else {
710 memcpy(font, fontset, count);
711 font[count] = 0;
712 f = (char*)font;
716 if (newfs)
717 end = strlen(newfs);
718 else
719 end = 0;
721 tmp = wmalloc(end + strlen(f) + 8);
722 if (end != 0) {
723 sprintf(tmp, "%s,", newfs);
724 sprintf(tmp + end + 1, f, size);
725 } else {
726 sprintf(tmp + end, f, size);
729 if (newfs)
730 wfree(newfs);
731 newfs = tmp;
733 fontset = ptr+1;
734 } while (ptr!=NULL);
736 return newfs;
740 static void
741 changeFontProp(char *fname, char *newprop, int which)
743 char before[128], prop[128], after[128];
744 char *ptr, *bptr;
745 int part=0;
747 if (!fname || !prop)
748 return;
750 ptr = fname;
751 bptr = before;
752 while (*ptr) {
753 if(*ptr == '-') {
754 *bptr = 0;
755 if (part==which)
756 bptr = prop;
757 else if (part==which+1)
758 bptr = after;
759 *bptr++ = *ptr;
760 part++;
761 } else {
762 *bptr++ = *ptr;
764 ptr++;
766 *bptr = 0;
767 snprintf(fname, 255, "%s-%s%s", before, newprop, after);
771 WMFont*
772 WMNormalizeFont(WMScreen *scr, WMFont *font)
774 char fname[256];
775 WMFontFlags flag;
777 if (!scr || !font)
778 return NULL;
780 snprintf(fname, 255, "%s", font->name);
781 changeFontProp(fname, "medium", 2);
782 changeFontProp(fname, "r", 3);
783 flag = (font->antialiased ? WFAntialiased : WFNotAntialiased);
784 return WMCreateFontWithFlags(scr, fname, flag);
788 WMFont*
789 WMStrengthenFont(WMScreen *scr, WMFont *font)
791 char fname[256];
792 WMFontFlags flag;
794 if (!scr || !font)
795 return NULL;
797 snprintf(fname, 255, "%s", font->name);
798 changeFontProp(fname, "bold", 2);
799 flag = (font->antialiased ? WFAntialiased : WFNotAntialiased);
800 return WMCreateFontWithFlags(scr, fname, flag);
804 WMFont*
805 WMUnstrengthenFont(WMScreen *scr, WMFont *font)
807 char fname[256];
808 WMFontFlags flag;
810 if (!scr || !font)
811 return NULL;
813 snprintf(fname, 255, "%s", font->name);
814 changeFontProp(fname, "medium", 2);
815 flag = (font->antialiased ? WFAntialiased : WFNotAntialiased);
816 return WMCreateFontWithFlags(scr, fname, flag);
820 WMFont*
821 WMEmphasizeFont(WMScreen *scr, WMFont *font)
823 char fname[256];
824 WMFontFlags flag;
826 if (!scr || !font)
827 return NULL;
829 snprintf(fname, 255, "%s", font->name);
830 if (font->antialiased)
831 changeFontProp(fname, "i", 3);
832 else
833 changeFontProp(fname, "o", 3);
835 flag = (font->antialiased ? WFAntialiased : WFNotAntialiased);
836 return WMCreateFontWithFlags(scr, fname, flag);
840 WMFont*
841 WMUnemphasizeFont(WMScreen *scr, WMFont *font)
843 char fname[256];
844 WMFontFlags flag;
846 if (!scr || !font)
847 return NULL;
849 snprintf(fname, 255, "%s", font->name);
850 changeFontProp(fname, "r", 3);
851 flag = (font->antialiased ? WFAntialiased : WFNotAntialiased);
852 return WMCreateFontWithFlags(scr, fname, flag);