2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2009 Kim Woelders
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 static Visual *last_vis = NULL;
36 vis = WinGetVisual(win);
46 gc = EXCreateGC(WinGetXwin(win), 0, NULL);
52 TextDrawRotTo(Win win, Drawable src, Drawable dst, int x, int y,
53 int w, int h, TextState * ts)
58 switch (ts->style.orientation)
61 im = EImageGrabDrawable(src, 0, y, x, h, w, 0);
62 EImageOrientate(im, 1);
63 EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
67 EXGetGeometry(src, NULL, NULL, NULL, &win_w, NULL, NULL, NULL);
68 im = EImageGrabDrawable(src, None, win_w - y - h, x, h, w, 0);
69 EImageOrientate(im, 3);
70 EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
73 case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */
74 im = EImageGrabDrawable(src, None, x, y, w, h, 0);
75 EImageOrientate(im, 2);
76 EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
85 TextDrawRotBack(Win win, Drawable dst, Drawable src, int x, int y,
86 int w, int h, TextState * ts)
91 switch (ts->style.orientation)
94 im = EImageGrabDrawable(src, None, 0, 0, w, h, 0);
95 EImageOrientate(im, 3);
96 EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w);
100 EXGetGeometry(dst, NULL, NULL, NULL, &win_w, NULL, NULL, NULL);
101 im = EImageGrabDrawable(src, None, 0, 0, w, h, 0);
102 EImageOrientate(im, 1);
103 EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w);
106 case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */
107 im = EImageGrabDrawable(src, None, 0, 0, w, h, 0);
108 EImageOrientate(im, 2);
109 EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
119 TextImageGet(Win win __UNUSED__, Drawable src, int x, int y, int w, int h,
125 switch (ts->style.orientation)
129 im = EImageGrabDrawable(src, None, x, y, w, h, 0);
132 im = EImageGrabDrawable(src, None, x, y, w, h, 0);
133 EImageOrientate(im, 2);
136 im = EImageGrabDrawable(src, 0, y, x, h, w, 0);
137 EImageOrientate(im, 1);
140 EXGetGeometry(src, NULL, NULL, NULL, &win_w, NULL, NULL, NULL);
141 im = EImageGrabDrawable(src, None, win_w - y - h, x, h, w, 0);
142 EImageOrientate(im, 3);
150 TextImagePut(EImage * im, Win win, Drawable dst, int x, int y,
151 int w, int h, TextState * ts)
155 switch (ts->style.orientation)
159 EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
162 EImageOrientate(im, 2);
163 EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
166 EImageOrientate(im, 3);
167 EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w);
170 EXGetGeometry(dst, NULL, NULL, NULL, &win_w, NULL, NULL, NULL);
171 EImageOrientate(im, 1);
172 EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w);
177 #endif /* FONT_TYPE_IFT */
180 TextclassGetTextState(TextClass * tclass, int state, int active, int sticky)
192 return tclass->active.normal;
194 return tclass->active.hilited;
196 return tclass->active.clicked;
198 return tclass->active.disabled;
208 return tclass->sticky_active.normal;
210 return tclass->sticky_active.hilited;
212 return tclass->sticky_active.clicked;
214 return tclass->sticky_active.disabled;
226 return tclass->sticky.normal;
228 return tclass->sticky.hilited;
230 return tclass->sticky.clicked;
232 return tclass->sticky.disabled;
242 return tclass->norm.normal;
244 return tclass->norm.hilited;
246 return tclass->norm.clicked;
248 return tclass->norm.disabled;
257 TextstateTextFit1(TextState * ts, char **ptext, int *pw, int textwidth_limit)
262 int nuke_count = 0, nc2;
268 new_line = EMALLOC(char, len + 10);
272 while (*pw > textwidth_limit)
276 if (nuke_count >= len - 1)
278 new_line[0] = text[0];
279 memcpy(new_line + 1, "...", 4);
283 nc2 = (len - nuke_count) / 2;
284 memcpy(new_line, text, nc2);
285 memcpy(new_line + nc2, "...", 3);
286 strcpy(new_line + nc2 + 3, text + nc2 + nuke_count);
288 ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
297 TextstateTextFit2(TextState * ts, char **ptext, int *pw, int textwidth_limit)
306 new_line = EMALLOC(char, len + 20);
311 while (*pw > textwidth_limit)
315 if (nuke_count > len)
317 memcpy(new_line, text, 2);
318 memcpy(new_line + 2, ". . . ", 7);
323 strncat(new_line, text, (len - nuke_count) / 4);
324 strcat(new_line, ". . . ");
325 strcat(new_line, text + ((len - nuke_count) / 4) + nuke_count);
327 ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
333 #endif /* FONT_TYPE_XFONT */
336 TextstateTextFitMB(TextState * ts, char **ptext, int *pw, int textwidth_limit)
341 int nuke_count = 0, nc2;
343 wchar_t *wc_line = NULL;
346 if (EwcOpen(ts->need_utf8 || Mode.locale.utf8_int))
350 wc_len = EwcStrToWcs(text, len, NULL, 0);
354 wc_line = EMALLOC(wchar_t, wc_len + 1);
358 if (EwcStrToWcs(text, len, wc_line, wc_len) <= 0)
361 new_line = EMALLOC(char, len + 10);
366 while (*pw > textwidth_limit)
371 if (nuke_count >= wc_len - 1)
375 mlen = EwcWcsToStr(wc_line, 1, new_line, MB_CUR_MAX);
379 strcpy(new_line + mlen, "...");
383 nc2 = (wc_len - nuke_count) / 2;
384 len_mb = EwcWcsToStr(wc_line, nc2, new_line, len + 10);
385 memcpy(new_line + len_mb, "...", 3);
387 len_mb += EwcWcsToStr(wc_line + nc2 + nuke_count,
388 wc_len - nc2 - nuke_count,
389 new_line + len_mb, len + 10 - len_mb);
390 new_line[len_mb] = '\0';
392 ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
403 * XFontSet - XCreateFontSet
405 extern const FontOps FontOpsXfs;
416 _xfs_Load(TextState * ts, const char *name)
420 int i, missing_cnt, font_cnt;
421 char **missing_list, *def_str, **fnlr;
424 font = XCreateFontSet(disp, name, &missing_list, &missing_cnt, &def_str);
426 XFreeStringList(missing_list);
430 if (EDebug(EDBUG_TYPE_FONTS) >= 2)
432 Eprintf("- XBaseFontNameListOfFontSet %s\n",
433 XBaseFontNameListOfFontSet(font));
434 font_cnt = XFontsOfFontSet(font, &fs, &fnlr);
435 for (i = 0; i < font_cnt; i++)
436 Eprintf("- XFontsOfFontSet %d: %s\n", i, fnlr[i]);
439 fdc = EMALLOC(FontCtxXfs, 1);
445 font_cnt = XFontsOfFontSet(font, &fs, &fnlr);
446 for (i = 0; i < font_cnt; i++)
447 fdc->ascent = MAX(fs[i]->ascent, fdc->ascent);
448 ts->type = FONT_TYPE_XFS;
449 ts->ops = &FontOpsXfs;
454 _xfs_Unload(TextState * ts)
456 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
458 XFreeFontSet(disp, fdc->font);
462 _xfs_TextSize(TextState * ts, const char *text, int len,
463 int *width, int *height, int *ascent)
465 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
470 XmbTextExtents(fdc->font, text, len, NULL, &ret2);
471 *height = ret2.height;
473 *ascent = fdc->ascent;
477 _xfs_TextDraw(TextState * ts, int x, int y, const char *text, int len)
479 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
481 XmbDrawString(disp, fdc->draw, fdc->font, fdc->gc, x, y, text, len);
485 _xfs_FdcInit(TextState * ts, Win win, Drawable draw)
487 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
491 fdc->gc = _get_gc(win);
496 _xfs_FdcSetDrawable(TextState * ts, unsigned long draw)
498 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
504 _xfs_FdcSetColor(TextState * ts, EColor * xc)
506 FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
508 EAllocColor(WinGetCmap(fdc->win), xc);
509 XSetForeground(disp, fdc->gc, xc->pixel);
512 const FontOps FontOpsXfs = {
513 _xfs_Load, _xfs_Unload, _xfs_TextSize, TextstateTextFit, _xfs_TextDraw,
514 _xfs_FdcInit, NULL, _xfs_FdcSetDrawable, _xfs_FdcSetColor
516 #endif /* FONT_TYPE_XFS */
520 * XFontStruct - XLoadQueryFont
522 extern const FontOps FontOpsXfont;
532 _xfont_Load(TextState * ts, const char *name)
537 font = XLoadQueryFont(disp, name);
541 fdc = EMALLOC(FontCtxXfont, 1);
546 ts->type = FONT_TYPE_XFONT;
547 ts->ops = &FontOpsXfont;
552 _xfont_Unload(TextState * ts __UNUSED__)
554 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
556 XFreeFont(disp, fdc->font);
560 _xfont_TextSize(TextState * ts, const char *text, int len,
561 int *width, int *height, int *ascent)
563 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
567 if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
568 *width = XTextWidth(fdc->font, text, len);
570 *width = XTextWidth16(fdc->font, (XChar2b *) text, len / 2);
571 *height = fdc->font->ascent + fdc->font->descent;
572 *ascent = fdc->font->ascent;
576 _xfont_TextDraw(TextState * ts, int x, int y, const char *text, int len)
578 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
580 if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
581 XDrawString(disp, fdc->draw, fdc->gc, x, y, text, len);
583 XDrawString16(disp, fdc->draw, fdc->gc, x, y, (XChar2b *) text, len);
587 _xfont_FdcInit(TextState * ts, Win win, Drawable draw)
589 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
593 fdc->gc = _get_gc(win);
595 XSetFont(disp, fdc->gc, fdc->font->fid);
600 _xfont_FdcSetDrawable(TextState * ts, unsigned long draw)
602 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
608 _xfont_FdcSetColor(TextState * ts, EColor * xc)
610 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
612 EAllocColor(WinGetCmap(fdc->win), xc);
613 XSetForeground(disp, fdc->gc, xc->pixel);
617 _xfont_TextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit)
619 FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
621 if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
622 TextstateTextFit1(ts, ptext, pw, textwidth_limit);
624 TextstateTextFit2(ts, ptext, pw, textwidth_limit);
627 const FontOps FontOpsXfont = {
628 _xfont_Load, _xfont_Unload, _xfont_TextSize, _xfont_TextFit, _xfont_TextDraw,
629 _xfont_FdcInit, NULL, _xfont_FdcSetDrawable, _xfont_FdcSetColor
631 #endif /* FONT_TYPE_XFONT */
634 TsTextDraw(TextState * ts, int x, int y, const char *text, int len)
636 if (ts->style.effect == 1)
638 ts->ops->FdcSetColor(ts, &(ts->bg_col));
639 ts->ops->TextDraw(ts, x + 1, y + 1, text, len);
641 else if (ts->style.effect == 2)
643 ts->ops->FdcSetColor(ts, &(ts->bg_col));
644 ts->ops->TextDraw(ts, x - 1, y, text, len);
645 ts->ops->TextDraw(ts, x + 1, y, text, len);
646 ts->ops->TextDraw(ts, x, y - 1, text, len);
647 ts->ops->TextDraw(ts, x, y + 1, text, len);
649 ts->ops->FdcSetColor(ts, &(ts->fg_col));
650 ts->ops->TextDraw(ts, x, y, text, len);
661 #define FONT(type, ops, opsm) { type, opsm, 0 }
665 #define FONT(type, ops, opsm) { type, ops, 0 }
668 extern const FontOps FontOps_ift;
671 extern const FontOps FontOps_xft;
673 #if FONT_TYPE_PANGO_XFT
674 extern const FontOps FontOps_pango;
677 #endif /* USE_MODULES */
679 static FontHandler fhs[] = {
681 FONT("xfont", &FontOpsXfont, &FontOpsXfont), /* XFontStruct - XLoadQueryFont */
684 FONT("xfs", &FontOpsXfs, &FontOpsXfs), /* XFontSet - XCreateFontSet */
687 FONT("ift", &FontOps_ift, NULL), /* Imlib2/FreeType */
690 FONT("xft", &FontOps_xft, NULL), /* Xft */
692 #if FONT_TYPE_PANGO_XFT
693 FONT("pango", &FontOps_pango, NULL), /* Pango-Xft */
699 TextStateLoadFont(TextState * ts)
701 const char *s, *type, *name;
703 FontHandler *fhp = fhs;
708 /* Quit if already done */
712 ts->need_utf8 = Mode.locale.utf8_int;
717 if (strchr(ts->fontname, '/'))
724 if (ts->fontname[0] == '-')
730 s = strchr(ts->fontname, ':');
731 if (!s || s == ts->fontname)
733 if (s - ts->fontname > 16)
735 memcpy(buf, ts->fontname, s - ts->fontname);
736 buf[s - ts->fontname] = '\0';
741 for (fhp = fhs; fhp->type; fhp++)
743 if (strcmp(fhp->type, type))
751 fhp->ops = ModLoadSym("font", "FontOps", type);
756 if (fhp->ops->Load(ts, name) == 0)
761 if (!FontOpsXfs.Load(ts, "fixed")) /* XFontSet - XCreateFontSet */
765 if (!FontOpsXfont.Load(ts, "fixed")) /* XFontStruct - XLoadQueryFont */
771 Eprintf("*** Unable to load font \"%s\"\n", ts->fontname);
772 else if (EDebug(EDBUG_TYPE_FONTS))
773 Eprintf("TextStateLoadFont %s: type=%d\n", ts->fontname, ts->type);
778 TextSize(TextClass * tclass, int active, int sticky, int state,
779 const char *text, int *width, int *height, int fsize __UNUSED__)
783 int i, num_lines, ww, hh, asc;
792 ts = TextclassGetTextState(tclass, state, active, sticky);
796 TextStateLoadFont(ts);
800 /* Do encoding conversion, if necessary */
801 str = EstrInt2Enc(text, ts->need_utf8);
802 lines = StrlistFromString(str, '\n', &num_lines);
803 EstrInt2EncFree(str, ts->need_utf8);
807 for (i = 0; i < num_lines; i++)
809 ts->ops->TextSize(ts, lines[i], strlen(lines[i]), &ww, &hh, &asc);
815 StrlistFree(lines, num_lines);
819 TextstateTextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit)
821 if (ts->need_utf8 || MB_CUR_MAX > 1)
822 TextstateTextFitMB(ts, ptext, pw, textwidth_limit);
824 TextstateTextFit1(ts, ptext, pw, textwidth_limit);
828 TextstateTextDraw(TextState * ts, Win win, Drawable draw, const char *text,
829 int x, int y, int w, int h, const EImageBorder * pad,
830 int fsize __UNUSED__, int justh, int justv)
835 int textwidth_limit, textheight_limit, offset_x, offset_y;
836 int xx, yy, ww, hh, ascent;
839 if (w <= 0 || h <= 0)
842 TextStateLoadFont(ts);
846 /* Do encoding conversion, if necessary */
847 str = EstrInt2Enc(text, ts->need_utf8);
848 lines = StrlistFromString(str, '\n', &num_lines);
849 EstrInt2EncFree(str, ts->need_utf8);
854 draw = WinGetXwin(win);
856 if (ts->style.orientation == FONT_TO_RIGHT ||
857 ts->style.orientation == FONT_TO_LEFT)
862 w -= pad->left + pad->right;
864 h -= pad->top + pad->bottom;
867 textheight_limit = h;
874 h -= pad->left + pad->right;
876 w -= pad->top + pad->bottom;
879 textheight_limit = w;
883 Eprintf("TextstateTextDraw %d,%d %dx%d(%dx%d): %s\n", x, y, w, h,
884 textwidth_limit, textheight_limit, text);
890 if (ts->ops->FdcInit(ts, win, draw))
894 if (ts->type == FONT_TYPE_IFT)
896 for (i = 0; i < num_lines; i++)
900 ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent);
901 if (ww > textwidth_limit)
902 ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit);
904 if (justv && num_lines == 1 && textheight_limit > 0)
905 yy += (textheight_limit - hh) / 2;
908 xx = x + (((textwidth_limit - ww) * justh) >> 10);
910 im = TextImageGet(win, draw, xx - 1, yy - 1 - ascent,
916 offset_y = ascent + 1;
918 ts->ops->FdcSetDrawable(ts, (unsigned long)im);
920 TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i]));
922 TextImagePut(im, win, draw, xx - 1, yy - 1 - ascent,
929 #endif /* FONT_TYPE_IFT */
931 for (i = 0; i < num_lines; i++)
933 ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent);
934 if (ww > textwidth_limit)
935 ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit);
937 if (justv && num_lines == 1 && textheight_limit > 0)
938 yy += (textheight_limit - hh) / 2;
941 xx = x + (((textwidth_limit - ww) * justh) >> 10);
943 if (ts->style.orientation != FONT_TO_RIGHT)
944 drawable = ECreatePixmap(win, ww + 2, hh + 2, 0);
947 TextDrawRotTo(win, draw, drawable, xx - 1, yy - 1 - ascent,
950 if (ts->style.orientation == FONT_TO_RIGHT)
958 offset_y = ascent + 1;
961 if (drawable != draw)
962 ts->ops->FdcSetDrawable(ts, drawable);
964 TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i]));
966 TextDrawRotBack(win, draw, drawable, xx - 1, yy - 1 - ascent,
968 if (drawable != draw)
969 EFreePixmap(drawable);
975 if (ts->ops->FdcFini)
976 ts->ops->FdcFini(ts);
978 StrlistFree(lines, num_lines);
982 TextDraw(TextClass * tclass, Win win, Drawable draw, int active, int sticky,
983 int state, const char *text, int x, int y, int w, int h, int fsize,
988 if (!tclass || !text)
991 ts = TextclassGetTextState(tclass, state, active, sticky);
995 TextstateTextDraw(ts, win, draw, text, x, y, w, h, NULL, fsize, justh, 0);