/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2015 Kim Woelders * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software, its documentation and marketing & publicity * materials, and acknowledgment shall be given in the documentation, materials * and software packages that this Software was used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "E.h" #include "eimage.h" #include "tclass.h" #include "xwin.h" static GC _get_gc(Win win) { static GC gc = NULL; static Visual *last_vis = NULL; Visual *vis; vis = WinGetVisual(win); if (vis != last_vis) { if (gc) EXFreeGC(gc); gc = NULL; last_vis = vis; } if (!gc) gc = EXCreateGC(WinGetXwin(win), 0, NULL); return gc; } static void TextDrawRotTo(Win win, EX_Drawable src, EX_Drawable dst, int x, int y, int w, int h, TextState * ts) { EImage *im; int win_w; switch (ts->style.orientation) { case FONT_TO_UP: im = EImageGrabDrawable(src, 0, y, x, h, w, 0); EImageOrientate(im, 1); EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h); EImageFree(im); break; case FONT_TO_DOWN: EXGetGeometry(src, NULL, NULL, NULL, &win_w, NULL, NULL, NULL); im = EImageGrabDrawable(src, NoXID, win_w - y - h, x, h, w, 0); EImageOrientate(im, 3); EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h); EImageFree(im); break; case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */ im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0); EImageOrientate(im, 2); EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h); EImageFree(im); break; default: break; } } static void TextDrawRotBack(Win win, EX_Drawable dst, EX_Drawable src, int x, int y, int w, int h, TextState * ts) { EImage *im; int win_w; switch (ts->style.orientation) { case FONT_TO_UP: im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0); EImageOrientate(im, 3); EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w); EImageFree(im); break; case FONT_TO_DOWN: EXGetGeometry(dst, NULL, NULL, NULL, &win_w, NULL, NULL, NULL); im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0); EImageOrientate(im, 1); EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w); EImageFree(im); break; case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */ im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0); EImageOrientate(im, 2); EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h); EImageFree(im); break; default: break; } } #if FONT_TYPE_IFT static EImage * TextImageGet(Win win __UNUSED__, EX_Drawable src, int x, int y, int w, int h, TextState * ts) { EImage *im; int win_w; switch (ts->style.orientation) { default: case FONT_TO_RIGHT: im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0); break; case FONT_TO_LEFT: im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0); EImageOrientate(im, 2); break; case FONT_TO_UP: im = EImageGrabDrawable(src, 0, y, x, h, w, 0); EImageOrientate(im, 1); break; case FONT_TO_DOWN: EXGetGeometry(src, NULL, NULL, NULL, &win_w, NULL, NULL, NULL); im = EImageGrabDrawable(src, NoXID, win_w - y - h, x, h, w, 0); EImageOrientate(im, 3); break; } return im; } static void TextImagePut(EImage * im, Win win, EX_Drawable dst, int x, int y, int w, int h, TextState * ts) { int win_w; switch (ts->style.orientation) { default: case FONT_TO_RIGHT: EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h); break; case FONT_TO_LEFT: EImageOrientate(im, 2); EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h); break; case FONT_TO_UP: EImageOrientate(im, 3); EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w); break; case FONT_TO_DOWN: EXGetGeometry(dst, NULL, NULL, NULL, &win_w, NULL, NULL, NULL); EImageOrientate(im, 1); EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w); break; } EImageFree(im); } #endif /* FONT_TYPE_IFT */ TextState * TextclassGetTextState(TextClass * tclass, int state, int active, int sticky) { if (!tclass) return NULL; if (active) { if (!sticky) { switch (state) { case STATE_NORMAL: return tclass->active.normal; case STATE_HILITED: return tclass->active.hilited; case STATE_CLICKED: return tclass->active.clicked; case STATE_DISABLED: return tclass->active.disabled; default: break; } } else { switch (state) { case STATE_NORMAL: return tclass->sticky_active.normal; case STATE_HILITED: return tclass->sticky_active.hilited; case STATE_CLICKED: return tclass->sticky_active.clicked; case STATE_DISABLED: return tclass->sticky_active.disabled; default: break; } } } else if (sticky) { switch (state) { case STATE_NORMAL: return tclass->sticky.normal; case STATE_HILITED: return tclass->sticky.hilited; case STATE_CLICKED: return tclass->sticky.clicked; case STATE_DISABLED: return tclass->sticky.disabled; default: break; } } else { switch (state) { case STATE_NORMAL: return tclass->norm.normal; case STATE_HILITED: return tclass->norm.hilited; case STATE_CLICKED: return tclass->norm.clicked; case STATE_DISABLED: return tclass->norm.disabled; default: break; } } return NULL; } static void TextstateTextFit1(TextState * ts, char **ptext, int *pw, int textwidth_limit) { char *text = *ptext; int hh, ascent; char *new_line; int nuke_count = 0, nc2; int len; len = strlen(text); if (len <= 1) return; new_line = EMALLOC(char, len + 10); if (!new_line) return; while (*pw > textwidth_limit) { nuke_count++; if (nuke_count >= len - 1) { new_line[0] = text[0]; memcpy(new_line + 1, "...", 4); break; } nc2 = (len - nuke_count) / 2; memcpy(new_line, text, nc2); memcpy(new_line + nc2, "...", 3); strcpy(new_line + nc2 + 3, text + nc2 + nuke_count); ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent); } Efree(text); *ptext = new_line; } #if FONT_TYPE_XFONT static void TextstateTextFit2(TextState * ts, char **ptext, int *pw, int textwidth_limit) { char *text = *ptext; int hh, ascent; char *new_line; int nuke_count = 0; int len; len = strlen(text); new_line = EMALLOC(char, len + 20); if (!new_line) return; while (*pw > textwidth_limit) { nuke_count += 2; if (nuke_count > len) { memcpy(new_line, text, 2); memcpy(new_line + 2, ". . . ", 7); break; } new_line[0] = 0; strncat(new_line, text, (len - nuke_count) / 4); strcat(new_line, ". . . "); strcat(new_line, text + ((len - nuke_count) / 4) + nuke_count); ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent); } Efree(text); *ptext = new_line; } #endif /* FONT_TYPE_XFONT */ static void TextstateTextFitMB(TextState * ts, char **ptext, int *pw, int textwidth_limit) { char *text = *ptext; int hh, ascent; char *new_line; int nuke_count = 0, nc2; int len; wchar_t *wc_line = NULL; int wc_len; if (EwcOpen(ts->need_utf8 || Mode.locale.utf8_int)) return; len = strlen(text); wc_len = EwcStrToWcs(text, len, NULL, 0); if (wc_len <= 1) goto done; wc_line = EMALLOC(wchar_t, wc_len + 1); if (!wc_line) goto done; if (EwcStrToWcs(text, len, wc_line, wc_len) <= 0) goto done; new_line = EMALLOC(char, len + 10); if (!new_line) goto done; while (*pw > textwidth_limit) { int len_mb; nuke_count++; if (nuke_count >= wc_len - 1) { int mlen; mlen = EwcWcsToStr(wc_line, 1, new_line, MB_CUR_MAX); if (mlen < 0) mlen = 1; strcpy(new_line + mlen, "..."); break; } nc2 = (wc_len - nuke_count) / 2; len_mb = EwcWcsToStr(wc_line, nc2, new_line, len + 10); memcpy(new_line + len_mb, "...", 3); len_mb += 3; len_mb += EwcWcsToStr(wc_line + nc2 + nuke_count, wc_len - nc2 - nuke_count, new_line + len_mb, len + 10 - len_mb); new_line[len_mb] = '\0'; ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent); } Efree(text); *ptext = new_line; done: Efree(wc_line); EwcClose(); } #if FONT_TYPE_XFS /* * XFontSet - XCreateFontSet */ extern const FontOps FontOpsXfs; typedef struct { XFontSet font; int ascent; Win win; EX_Drawable draw; GC gc; } FontCtxXfs; static int _xfs_Load(TextState * ts, const char *name) { XFontSet font; FontCtxXfs *fdc; int i, missing_cnt, font_cnt; char **missing_list, *def_str, **fnlr; XFontStruct **fs; font = XCreateFontSet(disp, name, &missing_list, &missing_cnt, &def_str); if (missing_cnt) XFreeStringList(missing_list); if (!font) return -1; if (EDebug(EDBUG_TYPE_FONTS) >= 2) { Eprintf("- XBaseFontNameListOfFontSet %s\n", XBaseFontNameListOfFontSet(font)); font_cnt = XFontsOfFontSet(font, &fs, &fnlr); for (i = 0; i < font_cnt; i++) Eprintf("- XFontsOfFontSet %d: %s\n", i, fnlr[i]); } fdc = EMALLOC(FontCtxXfs, 1); if (!fdc) return -1; fdc->font = font; ts->fdc = fdc; fdc->ascent = 0; font_cnt = XFontsOfFontSet(font, &fs, &fnlr); for (i = 0; i < font_cnt; i++) fdc->ascent = MAX(fs[i]->ascent, fdc->ascent); ts->type = FONT_TYPE_XFS; ts->ops = &FontOpsXfs; return 0; } static void _xfs_Unload(TextState * ts) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; XFreeFontSet(disp, fdc->font); } static void _xfs_TextSize(TextState * ts, const char *text, int len, int *width, int *height, int *ascent) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; XRectangle ret2; if (len == 0) len = strlen(text); XmbTextExtents(fdc->font, text, len, NULL, &ret2); *height = ret2.height; *width = ret2.width; *ascent = fdc->ascent; } static void _xfs_TextDraw(TextState * ts, int x, int y, const char *text, int len) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; XmbDrawString(disp, fdc->draw, fdc->font, fdc->gc, x, y, text, len); } static int _xfs_FdcInit(TextState * ts, Win win, EX_Drawable draw) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; fdc->win = win; fdc->draw = draw; fdc->gc = _get_gc(win); return 0; } static void _xfs_FdcSetDrawable(TextState * ts, unsigned long draw) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; fdc->draw = draw; } static void _xfs_FdcSetColor(TextState * ts, unsigned int color) { FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc; unsigned int pixel; pixel = EAllocColor(WinGetCmap(fdc->win), color); XSetForeground(disp, fdc->gc, pixel); } const FontOps FontOpsXfs = { _xfs_Load, _xfs_Unload, _xfs_TextSize, TextstateTextFit, _xfs_TextDraw, _xfs_FdcInit, NULL, _xfs_FdcSetDrawable, _xfs_FdcSetColor }; #endif /* FONT_TYPE_XFS */ #if FONT_TYPE_XFONT /* * XFontStruct - XLoadQueryFont */ extern const FontOps FontOpsXfont; typedef struct { XFontStruct *font; Win win; EX_Drawable draw; GC gc; } FontCtxXfont; static int _xfont_Load(TextState * ts, const char *name) { XFontStruct *font; FontCtxXfont *fdc; font = XLoadQueryFont(disp, name); if (!font) return -1; fdc = EMALLOC(FontCtxXfont, 1); if (!fdc) return -1; fdc->font = font; ts->fdc = fdc; ts->type = FONT_TYPE_XFONT; ts->ops = &FontOpsXfont; return 0; } static void _xfont_Unload(TextState * ts __UNUSED__) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; XFreeFont(disp, fdc->font); } static void _xfont_TextSize(TextState * ts, const char *text, int len, int *width, int *height, int *ascent) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; if (len == 0) len = strlen(text); if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0) *width = XTextWidth(fdc->font, text, len); else *width = XTextWidth16(fdc->font, (XChar2b *) text, len / 2); *height = fdc->font->ascent + fdc->font->descent; *ascent = fdc->font->ascent; } static void _xfont_TextDraw(TextState * ts, int x, int y, const char *text, int len) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0) XDrawString(disp, fdc->draw, fdc->gc, x, y, text, len); else XDrawString16(disp, fdc->draw, fdc->gc, x, y, (XChar2b *) text, len); } static int _xfont_FdcInit(TextState * ts, Win win, EX_Drawable draw) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; fdc->win = win; fdc->draw = draw; fdc->gc = _get_gc(win); XSetFont(disp, fdc->gc, fdc->font->fid); return 0; } static void _xfont_FdcSetDrawable(TextState * ts, unsigned long draw) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; fdc->draw = draw; } static void _xfont_FdcSetColor(TextState * ts, unsigned int color) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; unsigned int pixel; pixel = EAllocColor(WinGetCmap(fdc->win), color); XSetForeground(disp, fdc->gc, pixel); } static void _xfont_TextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit) { FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc; if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0) TextstateTextFit1(ts, ptext, pw, textwidth_limit); else TextstateTextFit2(ts, ptext, pw, textwidth_limit); } const FontOps FontOpsXfont = { _xfont_Load, _xfont_Unload, _xfont_TextSize, _xfont_TextFit, _xfont_TextDraw, _xfont_FdcInit, NULL, _xfont_FdcSetDrawable, _xfont_FdcSetColor }; #endif /* FONT_TYPE_XFONT */ static void TsTextDraw(TextState * ts, int x, int y, const char *text, int len) { if (ts->style.effect == 1) { ts->ops->FdcSetColor(ts, ts->bg_col); ts->ops->TextDraw(ts, x + 1, y + 1, text, len); } else if (ts->style.effect == 2) { ts->ops->FdcSetColor(ts, ts->bg_col); ts->ops->TextDraw(ts, x - 1, y, text, len); ts->ops->TextDraw(ts, x + 1, y, text, len); ts->ops->TextDraw(ts, x, y - 1, text, len); ts->ops->TextDraw(ts, x, y + 1, text, len); } ts->ops->FdcSetColor(ts, ts->fg_col); ts->ops->TextDraw(ts, x, y, text, len); } typedef struct { const char *type; const FontOps *ops; #if USE_MODULES char checked; #endif } FontHandler; #if USE_MODULES #define FONT(type, ops, opsm) { type, opsm, 0 } #else #define FONT(type, ops, opsm) { type, ops } #if FONT_TYPE_IFT extern const FontOps FontOps_ift; #endif #if FONT_TYPE_XFT extern const FontOps FontOps_xft; #endif #if FONT_TYPE_PANGO_XFT extern const FontOps FontOps_pango; #endif #endif /* USE_MODULES */ static FontHandler fhs[] = { #if FONT_TYPE_XFONT FONT("xfont", &FontOpsXfont, &FontOpsXfont), /* XFontStruct - XLoadQueryFont */ #endif #if FONT_TYPE_XFS FONT("xfs", &FontOpsXfs, &FontOpsXfs), /* XFontSet - XCreateFontSet */ #endif #if FONT_TYPE_IFT FONT("ift", &FontOps_ift, NULL), /* Imlib2/FreeType */ #endif #if FONT_TYPE_XFT FONT("xft", &FontOps_xft, NULL), /* Xft */ #endif #if FONT_TYPE_PANGO_XFT FONT("pango", &FontOps_pango, NULL), /* Pango-Xft */ #endif FONT(NULL, NULL, NULL) }; static void TextStateLoadFont(TextState * ts) { const char *s, *type, *name; char buf[1024]; FontHandler *fhp = fhs; if (!ts->fontname) return; /* Quit if already done */ if (ts->type) return; ts->need_utf8 = Mode.locale.utf8_int; type = NULL; name = ts->fontname; #if FONT_TYPE_IFT if (strchr(ts->fontname, '/')) { type = "ift"; goto check; } #endif #if FONT_TYPE_XFS if (ts->fontname[0] == '-') { type = "xfs"; goto check; } #endif s = strchr(ts->fontname, ':'); if (!s || s == ts->fontname) goto fallback; if (s - ts->fontname > 16) goto fallback; memcpy(buf, ts->fontname, s - ts->fontname); buf[s - ts->fontname] = '\0'; type = buf; name = s + 1; check: for (fhp = fhs; fhp->type; fhp++) { if (strcmp(fhp->type, type)) continue; #if USE_MODULES if (!fhp->ops) { if (fhp->checked) goto fallback; fhp->checked = 1; fhp->ops = ModLoadSym("font", "FontOps", type); if (!fhp->ops) goto fallback; } #endif if (fhp->ops->Load(ts, name) == 0) goto done; } fallback: #if FONT_TYPE_XFS if (!FontOpsXfs.Load(ts, "fixed")) /* XFontSet - XCreateFontSet */ goto done; #endif #if FONT_TYPE_XFONT if (!FontOpsXfont.Load(ts, "fixed")) /* XFontStruct - XLoadQueryFont */ goto done; #endif done: if (!ts->ops) Eprintf("*** Unable to load font \"%s\"\n", ts->fontname); else if (EDebug(EDBUG_TYPE_FONTS)) Eprintf("%s: %s: type=%d\n", __func__, ts->fontname, ts->type); return; } void TextSize(TextClass * tclass, int active, int sticky, int state, const char *text, int *width, int *height, int fsize __UNUSED__) { const char *str; char **lines; int i, num_lines, ww, hh, asc; TextState *ts; *width = 0; *height = 0; if (!text) return; ts = TextclassGetTextState(tclass, state, active, sticky); if (!ts) return; TextStateLoadFont(ts); if (!ts->ops) return; /* Do encoding conversion, if necessary */ str = EstrInt2Enc(text, ts->need_utf8); lines = StrlistFromString(str, '\n', &num_lines); EstrInt2EncFree(str, ts->need_utf8); if (!lines) return; for (i = 0; i < num_lines; i++) { ts->ops->TextSize(ts, lines[i], strlen(lines[i]), &ww, &hh, &asc); *height += hh; if (ww > *width) *width = ww; } StrlistFree(lines, num_lines); } void TextstateTextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit) { if (ts->need_utf8 || MB_CUR_MAX > 1) TextstateTextFitMB(ts, ptext, pw, textwidth_limit); else TextstateTextFit1(ts, ptext, pw, textwidth_limit); } void TextstateTextDraw(TextState * ts, Win win, EX_Drawable draw, const char *text, int x, int y, int w, int h, const EImageBorder * pad, int fsize __UNUSED__, int justh, int justv) { const char *str; char **lines; int i, num_lines; int textwidth_limit, textheight_limit, offset_x, offset_y; int xx, yy, ww, hh, ascent; EX_Pixmap drawable; if (w <= 0 || h <= 0) return; TextStateLoadFont(ts); if (!ts->ops) return; /* Do encoding conversion, if necessary */ str = EstrInt2Enc(text, ts->need_utf8); lines = StrlistFromString(str, '\n', &num_lines); EstrInt2EncFree(str, ts->need_utf8); if (!lines) return; if (draw == NoXID) draw = WinGetXwin(win); if (ts->style.orientation == FONT_TO_RIGHT || ts->style.orientation == FONT_TO_LEFT) { if (pad) { x += pad->left; w -= pad->left + pad->right; y += pad->top; h -= pad->top + pad->bottom; } textwidth_limit = w; textheight_limit = h; } else { if (pad) { x += pad->left; h -= pad->left + pad->right; y += pad->top; w -= pad->top + pad->bottom; } textwidth_limit = h; textheight_limit = w; } #if 0 Eprintf("%s: %d,%d %dx%d(%dx%d): %s\n", __func__, x, y, w, h, textwidth_limit, textheight_limit, text); #endif yy = y; if (ts->ops->FdcInit(ts, win, draw)) return; #if FONT_TYPE_IFT if (ts->type == FONT_TYPE_IFT) { for (i = 0; i < num_lines; i++) { EImage *im; ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent); if (ww > textwidth_limit) ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit); if (justv && num_lines == 1 && textheight_limit > 0) yy += (textheight_limit - hh) / 2; if (i == 0) yy += ascent; xx = x + (((textwidth_limit - ww) * justh) >> 10); im = TextImageGet(win, draw, xx - 1, yy - 1 - ascent, ww + 2, hh + 2, ts); if (!im) break; offset_x = 1; offset_y = ascent + 1; ts->ops->FdcSetDrawable(ts, (unsigned long)im); TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i])); TextImagePut(im, win, draw, xx - 1, yy - 1 - ascent, ww + 2, hh + 2, ts); yy += hh; } } else #endif /* FONT_TYPE_IFT */ { for (i = 0; i < num_lines; i++) { ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent); if (ww > textwidth_limit) ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit); if (justv && num_lines == 1 && textheight_limit > 0) yy += (textheight_limit - hh) / 2; if (i == 0) yy += ascent; xx = x + (((textwidth_limit - ww) * justh) >> 10); if (ts->style.orientation != FONT_TO_RIGHT) drawable = ECreatePixmap(win, ww + 2, hh + 2, 0); else drawable = draw; TextDrawRotTo(win, draw, drawable, xx - 1, yy - 1 - ascent, ww + 2, hh + 2, ts); if (ts->style.orientation == FONT_TO_RIGHT) { offset_x = xx; offset_y = yy; } else { offset_x = 1; offset_y = ascent + 1; } if (drawable != draw) ts->ops->FdcSetDrawable(ts, drawable); TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i])); TextDrawRotBack(win, draw, drawable, xx - 1, yy - 1 - ascent, ww + 2, hh + 2, ts); if (drawable != draw) EFreePixmap(drawable); yy += hh; } } if (ts->ops->FdcFini) ts->ops->FdcFini(ts); StrlistFree(lines, num_lines); } void TextDraw(TextClass * tclass, Win win, EX_Drawable draw, int active, int sticky, int state, const char *text, int x, int y, int w, int h, int fsize, int justh) { TextState *ts; if (!tclass || !text) return; ts = TextclassGetTextState(tclass, state, active, sticky); if (!ts) return; TextstateTextDraw(ts, win, draw, text, x, y, w, h, NULL, fsize, justh, 0); }