Added (forgotten) release for notifications when destroying a WMList.
[wmaker-crm.git] / WINGs / wfont.c
blob840af4ec0afbb8a1fecf15079207eb0b94455b18
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 WMCreateNonAAFont(WMScreen *scrPtr, char *fontName)
291 if (scrPtr->useMultiByte) {
292 return WMCreateFontSet(scrPtr, fontName);
293 } else {
294 return WMCreateNormalFont(scrPtr, fontName);
299 WMFont*
300 WMCreateFont(WMScreen *scrPtr, char *fontName)
302 if (scrPtr->useMultiByte) {
303 return WMCreateFontSet(scrPtr, fontName);
304 } else if (scrPtr->antialiasedText) {
305 WMFont *font = WMCreateAAFont(scrPtr, fontName);
306 return font ? font : WMCreateNormalFont(scrPtr, fontName);
307 } else {
308 return WMCreateNormalFont(scrPtr, fontName);
313 WMFont*
314 WMRetainFont(WMFont *font)
316 wassertrv(font!=NULL, NULL);
318 font->refCount++;
320 return font;
324 void
325 WMReleaseFont(WMFont *font)
327 wassertr(font!=NULL);
329 font->refCount--;
330 if (font->refCount < 1) {
331 if (font->notFontSet) {
332 if (font->antialiased) {
333 #ifdef XFT
334 XftFontClose(font->screen->display, font->font.xft);
335 #else
336 assert(False);
337 #endif
338 } else {
339 XFreeFont(font->screen->display, font->font.normal);
341 } else {
342 XFreeFontSet(font->screen->display, font->font.set);
344 if (font->name) {
345 if (font->notFontSet) {
346 WMHashRemove(font->screen->fontCache, font->name);
347 } else {
348 WMHashRemove(font->screen->fontSetCache, font->name);
350 wfree(font->name);
352 wfree(font);
357 Bool
358 WMIsAAFont(WMFont *font)
360 return font->antialiased;
364 unsigned int
365 WMFontHeight(WMFont *font)
367 wassertrv(font!=NULL, 0);
369 return font->height;
373 WMFont*
374 WMDefaultSystemFont(WMScreen *scrPtr)
376 return WMRetainFont(scrPtr->normalFont);
380 WMFont*
381 WMDefaultBoldSystemFont(WMScreen *scrPtr)
383 return WMRetainFont(scrPtr->boldFont);
387 static WMFont*
388 makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold)
390 WMFont *font;
391 char *fontSpec, *aaFontSpec;
393 #define WConf WINGsConfiguration
394 if (bold) {
395 fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size);
396 aaFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size);
397 } else {
398 fontSpec = makeFontSetOfSize(WConf.systemFont, size);
399 aaFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size);
401 #undef WConf
403 if (scrPtr->useMultiByte) {
404 font = WMCreateFontSet(scrPtr, fontSpec);
405 } else if (scrPtr->antialiasedText) {
406 font = WMCreateAAFont(scrPtr, aaFontSpec);
407 } else {
408 font = WMCreateNormalFont(scrPtr, fontSpec);
411 if (!font) {
412 if (scrPtr->useMultiByte) {
413 wwarning(_("could not load font set %s. Trying fixed."), fontSpec);
414 font = WMCreateFontSet(scrPtr, "fixed");
415 if (!font) {
416 font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*");
418 } else if (scrPtr->antialiasedText) {
419 wwarning(_("could not load font %s. Trying arial."), aaFontSpec);
420 if (bold) {
421 font = WMCreateAAFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*");
422 } else {
423 font = WMCreateAAFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*");
425 if (!font) {
426 wwarning(_("could not load antialiased fonts. Reverting to normal fonts."));
427 font = WMCreateNormalFont(scrPtr, fontSpec);
428 if (!font) {
429 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
430 font = WMCreateNormalFont(scrPtr, "fixed");
433 } else {
434 wwarning(_("could not load font %s. Trying fixed."), fontSpec);
435 font = WMCreateNormalFont(scrPtr, "fixed");
437 if (!font) {
438 wwarning(_("could not load fixed font!"));
439 wfree(fontSpec);
440 wfree(aaFontSpec);
441 return NULL;
444 wfree(fontSpec);
445 wfree(aaFontSpec);
447 return font;
451 WMFont*
452 WMSystemFontOfSize(WMScreen *scrPtr, int size)
454 return makeSystemFontOfSize(scrPtr, size, False);
458 WMFont*
459 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
461 return makeSystemFontOfSize(scrPtr, size, True);
465 XFontSet
466 WMGetFontFontSet(WMFont *font)
468 wassertrv(font!=NULL, NULL);
470 if (font->notFontSet)
471 return NULL;
472 else
473 return font->font.set;
478 WMWidthOfString(WMFont *font, char *text, int length)
480 wassertrv(font!=NULL, 0);
481 wassertrv(text!=NULL, 0);
483 if (font->notFontSet) {
484 if (font->antialiased) {
485 #ifdef XFT
486 XGlyphInfo extents;
488 XftTextExtents8(font->screen->display, font->font.xft,
489 (XftChar8 *)text, length, &extents);
490 return extents.xOff; /* don't ask :P */
491 #else
492 assert(False);
493 #endif
494 } else {
495 return XTextWidth(font->font.normal, text, length);
497 } else {
498 XRectangle rect;
499 XRectangle AIXsucks;
501 XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect);
503 return rect.width;
509 void
510 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
511 int x, int y, char *text, int length)
513 wassertr(font!=NULL);
515 if (font->notFontSet) {
516 if (font->antialiased) {
517 #ifdef XFT
518 XftColor xftcolor;
520 xftcolor.color.red = color->color.red;
521 xftcolor.color.green = color->color.green;
522 xftcolor.color.blue = color->color.blue;
523 xftcolor.color.alpha = color->alpha;;
524 xftcolor.pixel = W_PIXEL(color);
526 XftDrawChange(scr->xftdraw, d);
528 XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft,
529 x, y + font->y, text, length);
530 #else
531 assert(False);
532 #endif
533 } else {
534 XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid);
535 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
536 XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y,
537 text, length);
539 } else {
540 XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color));
541 XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC,
542 x, y + font->y, text, length);
547 void
548 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
549 WMFont *font, int x, int y, char *text, int length)
551 wassertr(font != NULL);
553 if (font->notFontSet) {
554 if (font->antialiased) {
555 #ifdef XFT
556 XftColor textColor;
557 XftColor bgColor;
559 textColor.color.red = color->color.red;
560 textColor.color.green = color->color.green;
561 textColor.color.blue = color->color.blue;
562 textColor.color.alpha = color->alpha;;
563 textColor.pixel = W_PIXEL(color);
565 bgColor.color.red = background->color.red;
566 bgColor.color.green = background->color.green;
567 bgColor.color.blue = background->color.blue;
568 bgColor.color.alpha = background->alpha;;
569 bgColor.pixel = W_PIXEL(background);
572 XftDrawChange(scr->xftdraw, d);
574 XftDrawRect(scr->xftdraw, &bgColor, x, y,
575 WMWidthOfString(font, text, length), font->height);
577 XftDrawString8(scr->xftdraw, &textColor, font->font.xft,
578 x, y + font->y, text, length);
579 #else
580 assert(False);
581 #endif
582 } else {
583 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
584 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
585 XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid);
586 XDrawImageString(scr->display, d, scr->drawImStringGC,
587 x, y + font->y, text, length);
589 } else {
590 XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color));
591 XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background));
592 XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC,
593 x, y + font->y, text, length);
600 static char*
601 makeFontSetOfSize(char *fontset, int size)
603 char font[300], *f;
604 char *newfs = NULL;
605 char *ptr;
607 do {
608 char *tmp;
609 int end;
612 f = fontset;
613 ptr = strchr(fontset, ',');
614 if (ptr) {
615 int count = ptr-fontset;
617 if (count > 255) {
618 wwarning(_("font description %s is too large."), fontset);
619 } else {
620 memcpy(font, fontset, count);
621 font[count] = 0;
622 f = (char*)font;
626 if (newfs)
627 end = strlen(newfs);
628 else
629 end = 0;
631 tmp = wmalloc(end + strlen(f) + 8);
632 if (end != 0) {
633 sprintf(tmp, "%s,", newfs);
634 sprintf(tmp + end + 1, f, size);
635 } else {
636 sprintf(tmp + end, f, size);
639 if (newfs)
640 wfree(newfs);
641 newfs = tmp;
643 fontset = ptr+1;
644 } while (ptr!=NULL);
646 return newfs;
650 static void
651 changeFontProp(char *fname, char *newprop, int which)
653 char before[128], prop[128], after[128];
654 char *ptr, *bptr;
655 int part=0;
657 if (!fname || !prop)
658 return;
660 ptr = fname;
661 bptr = before;
662 while (*ptr) {
663 if(*ptr == '-') {
664 *bptr = 0;
665 if (part==which)
666 bptr = prop;
667 else if (part==which+1)
668 bptr = after;
669 *bptr++ = *ptr;
670 part++;
671 } else {
672 *bptr++ = *ptr;
674 ptr++;
676 *bptr = 0;
677 snprintf(fname, 255, "%s-%s%s", before, newprop, after);
681 WMFont*
682 WMNormalizeFont(WMScreen *scr, WMFont *font)
684 char fname[256];
686 if (!scr || !font)
687 return NULL;
689 snprintf(fname, 255, "%s", font->name);
690 changeFontProp(fname, "medium", 2);
691 changeFontProp(fname, "r", 3);
692 if (font->antialiased)
693 return WMCreateAAFont(scr, fname);
694 else
695 return WMCreateNonAAFont(scr, fname);
699 WMFont*
700 WMStrengthenFont(WMScreen *scr, WMFont *font)
702 char fname[256];
704 if (!scr || !font)
705 return NULL;
707 snprintf(fname, 255, "%s", font->name);
708 changeFontProp(fname, "bold", 2);
709 if (font->antialiased)
710 return WMCreateAAFont(scr, fname);
711 else
712 return WMCreateNonAAFont(scr, fname);
716 WMFont*
717 WMUnstrengthenFont(WMScreen *scr, WMFont *font)
719 char fname[256];
721 if (!scr || !font)
722 return NULL;
724 snprintf(fname, 255, "%s", font->name);
725 changeFontProp(fname, "medium", 2);
726 if (font->antialiased)
727 return WMCreateAAFont(scr, fname);
728 else
729 return WMCreateNonAAFont(scr, fname);
733 WMFont*
734 WMEmphasizeFont(WMScreen *scr, WMFont *font)
736 char fname[256];
738 if (!scr || !font)
739 return NULL;
741 snprintf(fname, 255, "%s", font->name);
742 if (font->antialiased)
743 changeFontProp(fname, "i", 3);
744 else
745 changeFontProp(fname, "o", 3);
747 if (font->antialiased)
748 return WMCreateAAFont(scr, fname);
749 else
750 return WMCreateNonAAFont(scr, fname);
754 WMFont*
755 WMUnemphasizeFont(WMScreen *scr, WMFont *font)
757 char fname[256];
759 if (!scr || !font)
760 return NULL;
762 snprintf(fname, 255, "%s", font->name);
763 changeFontProp(fname, "r", 3);
764 if (font->antialiased)
765 return WMCreateAAFont(scr, fname);
766 else
767 return WMCreateNonAAFont(scr, fname);