diff --git a/Recipe b/Recipe index fab512bc..8854c402 100644 --- a/Recipe +++ b/Recipe @@ -245,7 +245,7 @@ GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint # Same thing on Unix. UXTERM = TERMINAL uxcfg sercfg uxucs uxprint timing -GTKTERM = UXTERM gtkwin gtkcfg gtkdlg gtkcols xkeysym +GTKTERM = UXTERM gtkwin gtkcfg gtkdlg gtkfont gtkcols xkeysym OSXTERM = UXTERM osxwin osxdlg osxctrls # Non-SSH back ends (putty, puttytel, plink). diff --git a/unix/gtkfont.c b/unix/gtkfont.c new file mode 100644 index 00000000..8fabdd23 --- /dev/null +++ b/unix/gtkfont.c @@ -0,0 +1,435 @@ +/* + * Unified font management for GTK. + * + * PuTTY is willing to use both old-style X server-side bitmap + * fonts _and_ GTK2/Pango client-side fonts. This requires us to + * do a bit of work to wrap the two wildly different APIs into + * forms the rest of the code can switch between seamlessly, and + * also requires a custom font selector capable of handling both + * types of font. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "putty.h" +#include "gtkfont.h" + +/* + * To do: + * + * - import flags to do VT100 double-width, and import the icky + * pixmap stretch code for it. + * + * - add the Pango back end! + */ + +/* + * Future work: + * + * - all the GDK font functions used in the x11font subclass are + * deprecated, so one day they may go away. When this happens - + * or before, if I'm feeling proactive - it oughtn't to be too + * difficult in principle to convert the whole thing to use + * actual Xlib font calls. + */ + +/* + * Ad-hoc vtable mechanism to allow font structures to be + * polymorphic. + * + * Any instance of `unifont' used in the vtable functions will + * actually be the first element of a larger structure containing + * data specific to the subtype. This is permitted by the ISO C + * provision that one may safely cast between a pointer to a + * structure and a pointer to its first element. + */ + +struct unifont_vtable { + /* + * `Methods' of the `class'. + */ + unifont *(*create)(char *name, int wide, int bold, + int shadowoffset, int shadowalways); + void (*destroy)(unifont *font); + void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font, + int x, int y, const char *string, int len, int wide, + int bold); + /* + * `Static data members' of the `class'. + */ + const char *prefix; +}; + +/* ---------------------------------------------------------------------- + * GDK-based X11 font implementation. + */ + +static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, + int x, int y, const char *string, int len, + int wide, int bold); +static unifont *x11font_create(char *name, int wide, int bold, + int shadowoffset, int shadowalways); +static void x11font_destroy(unifont *font); + +struct x11font { + struct unifont u; + /* + * Actual font objects. We store a number of these, for + * automatically guessed bold and wide variants. + * + * The parallel array `allocated' indicates whether we've + * tried to fetch a subfont already (thus distinguishing NULL + * because we haven't tried yet from NULL because we tried and + * failed, so that we don't keep trying and failing + * subsequently). + */ + GdkFont *fonts[4]; + int allocated[4]; + /* + * `sixteen_bit' is true iff the font object is indexed by + * values larger than a byte. That is, this flag tells us + * whether we use gdk_draw_text_wc() or gdk_draw_text(). + */ + int sixteen_bit; + /* + * Font charsets. public_charset and real_charset can differ + * for X11 fonts, because many X fonts use CS_ISO8859_1_X11. + */ + int public_charset, real_charset; + /* + * Data passed in to unifont_create(). + */ + int wide, bold, shadowoffset, shadowalways; +}; + +static const struct unifont_vtable x11font_vtable = { + x11font_create, + x11font_destroy, + x11font_draw_text, + "x11" +}; + +char *x11_guess_derived_font_name(GdkFont *font, int bold, int wide) +{ + XFontStruct *xfs = GDK_FONT_XFONT(font); + Display *disp = GDK_FONT_XDISPLAY(font); + Atom fontprop = XInternAtom(disp, "FONT", False); + unsigned long ret; + if (XGetFontProperty(xfs, fontprop, &ret)) { + char *name = XGetAtomName(disp, (Atom)ret); + if (name && name[0] == '-') { + char *strings[13]; + char *dupname, *extrafree = NULL, *ret; + char *p, *q; + int nstr; + + p = q = dupname = dupstr(name); /* skip initial minus */ + nstr = 0; + + while (*p && nstr < lenof(strings)) { + if (*p == '-') { + *p = '\0'; + strings[nstr++] = p+1; + } + p++; + } + + if (nstr < lenof(strings)) + return NULL; /* XLFD was malformed */ + + if (bold) + strings[2] = "bold"; + + if (wide) { + /* 4 is `wideness', which obviously may have changed. */ + /* 5 is additional style, which may be e.g. `ja' or `ko'. */ + strings[4] = strings[5] = "*"; + strings[11] = extrafree = dupprintf("%d", 2*atoi(strings[11])); + } + + ret = dupcat("-", strings[ 0], "-", strings[ 1], "-", strings[ 2], + "-", strings[ 3], "-", strings[ 4], "-", strings[ 5], + "-", strings[ 6], "-", strings[ 7], "-", strings[ 8], + "-", strings[ 9], "-", strings[10], "-", strings[11], + "-", strings[12], NULL); + sfree(extrafree); + sfree(dupname); + + return ret; + } + } + return NULL; +} + +static int x11_font_width(GdkFont *font, int sixteen_bit) +{ + if (sixteen_bit) { + XChar2b space; + space.byte1 = 0; + space.byte2 = ' '; + return gdk_text_width(font, (const gchar *)&space, 2); + } else { + return gdk_char_width(font, ' '); + } +} + +static unifont *x11font_create(char *name, int wide, int bold, + int shadowoffset, int shadowalways) +{ + struct x11font *xfont; + GdkFont *font; + XFontStruct *xfs; + Display *disp; + Atom charset_registry, charset_encoding; + unsigned long registry_ret, encoding_ret; + int pubcs, realcs, sixteen_bit; + int i; + + font = gdk_font_load(name); + if (!font) + return NULL; + + xfs = GDK_FONT_XFONT(font); + disp = GDK_FONT_XDISPLAY(font); + + charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False); + charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False); + + pubcs = realcs = CS_NONE; + sixteen_bit = FALSE; + + if (XGetFontProperty(xfs, charset_registry, ®istry_ret) && + XGetFontProperty(xfs, charset_encoding, &encoding_ret)) { + char *reg, *enc; + reg = XGetAtomName(disp, (Atom)registry_ret); + enc = XGetAtomName(disp, (Atom)encoding_ret); + if (reg && enc) { + char *encoding = dupcat(reg, "-", enc, NULL); + pubcs = realcs = charset_from_xenc(encoding); + + /* + * iso10646-1 is the only wide font encoding we + * support. In this case, we expect clients to give us + * UTF-8, which this module must internally convert + * into 16-bit Unicode. + */ + if (!strcasecmp(encoding, "iso10646-1")) { + sixteen_bit = TRUE; + pubcs = realcs = CS_UTF8; + } + + /* + * Hack for X line-drawing characters: if the primary + * font is encoded as ISO-8859-1, and has valid glyphs + * in the first 32 char positions, it is assumed that + * those glyphs are the VT100 line-drawing character + * set. + * + * Actually, we'll hack even harder by only checking + * position 0x19 (vertical line, VT100 linedrawing + * `x'). Then we can check it easily by seeing if the + * ascent and descent differ. + */ + if (pubcs == CS_ISO8859_1) { + int lb, rb, wid, asc, desc; + gchar text[2]; + + text[1] = '\0'; + text[0] = '\x12'; + gdk_string_extents(font, text, &lb, &rb, &wid, &asc, &desc); + if (asc != desc) + realcs = CS_ISO8859_1_X11; + } + + sfree(encoding); + } + } + + xfont = snew(struct x11font); + xfont->u.vt = &x11font_vtable; + xfont->u.width = x11_font_width(font, sixteen_bit); + xfont->u.ascent = font->ascent; + xfont->u.descent = font->descent; + xfont->u.height = xfont->u.ascent + xfont->u.descent; + xfont->u.public_charset = pubcs; + xfont->u.real_charset = realcs; + xfont->fonts[0] = font; + xfont->allocated[0] = TRUE; + xfont->sixteen_bit = sixteen_bit; + xfont->wide = wide; + xfont->bold = bold; + xfont->shadowoffset = shadowoffset; + xfont->shadowalways = shadowalways; + + for (i = 1; i < lenof(xfont->fonts); i++) { + xfont->fonts[i] = NULL; + xfont->allocated[i] = FALSE; + } + + return (unifont *)xfont; +} + +static void x11font_destroy(unifont *font) +{ + struct x11font *xfont = (struct x11font *)font; + int i; + + for (i = 0; i < lenof(xfont->fonts); i++) + if (xfont->fonts[i]) + gdk_font_unref(xfont->fonts[i]); + sfree(font); +} + +static void x11_alloc_subfont(struct x11font *xfont, int sfid) +{ + char *derived_name = x11_guess_derived_font_name + (xfont->fonts[0], sfid & 1, !!(sfid & 2)); + xfont->fonts[sfid] = gdk_font_load(derived_name); /* may be NULL */ + xfont->allocated[sfid] = TRUE; + sfree(derived_name); +} + +static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, + int x, int y, const char *string, int len, + int wide, int bold) +{ + struct x11font *xfont = (struct x11font *)font; + int sfid; + int shadowbold = FALSE; + + wide -= xfont->wide; + bold -= xfont->bold; + + /* + * Decide which subfont we're using, and whether we have to + * use shadow bold. + */ + if (xfont->shadowalways && bold) { + shadowbold = TRUE; + bold = 0; + } + sfid = 2 * wide + bold; + if (!xfont->allocated[sfid]) + x11_alloc_subfont(xfont, sfid); + if (bold && !xfont->fonts[sfid]) { + bold = 0; + shadowbold = TRUE; + sfid = 2 * wide + bold; + if (!xfont->allocated[sfid]) + x11_alloc_subfont(xfont, sfid); + } + + if (!xfont->fonts[sfid]) + return; /* we've tried our best, but no luck */ + + if (xfont->sixteen_bit) { + /* + * This X font has 16-bit character indices, which means + * we expect our string to have been passed in UTF-8. + */ + XChar2b *xcs; + wchar_t *wcs; + int nchars, maxchars, i; + + /* + * Convert the input string to wide-character Unicode. + */ + maxchars = 0; + for (i = 0; i < len; i++) + if ((unsigned char)string[i] <= 0x7F || + (unsigned char)string[i] >= 0xC0) + maxchars++; + wcs = snewn(maxchars+1, wchar_t); + nchars = charset_to_unicode((char **)&string, &len, wcs, maxchars, + CS_UTF8, NULL, NULL, 0); + assert(nchars <= maxchars); + wcs[nchars] = L'\0'; + + xcs = snewn(nchars, XChar2b); + for (i = 0; i < nchars; i++) { + xcs[i].byte1 = wcs[i] >> 8; + xcs[i].byte2 = wcs[i]; + } + + gdk_draw_text(target, xfont->fonts[sfid], gc, + x, y, (gchar *)xcs, nchars*2); + if (shadowbold) + gdk_draw_text(target, xfont->fonts[sfid], gc, + x + xfont->shadowoffset, y, (gchar *)xcs, nchars*2); + sfree(xcs); + sfree(wcs); + } else { + gdk_draw_text(target, xfont->fonts[sfid], gc, x, y, string, len); + if (shadowbold) + gdk_draw_text(target, xfont->fonts[sfid], gc, + x + xfont->shadowoffset, y, string, len); + } +} + +/* ---------------------------------------------------------------------- + * Outermost functions which do the vtable dispatch. + */ + +/* + * This function is the only one which needs to know the full set + * of font implementations available, because it has to try each + * in turn until one works, or condition on an override prefix in + * the font name. + */ +static const struct unifont_vtable *unifont_types[] = { + &x11font_vtable, +}; +unifont *unifont_create(char *name, int wide, int bold, + int shadowoffset, int shadowalways) +{ + int colonpos = strcspn(name, ":"); + int i; + + if (name[colonpos]) { + /* + * There's a colon prefix on the font name. Use it to work + * out which subclass to try to create. + */ + for (i = 0; i < lenof(unifont_types); i++) { + if (strlen(unifont_types[i]->prefix) == colonpos && + !strncmp(unifont_types[i]->prefix, name, colonpos)) + break; + } + if (i == lenof(unifont_types)) + return NULL; /* prefix not recognised */ + return unifont_types[i]->create(name+colonpos+1, wide, bold, + shadowoffset, shadowalways); + } else { + /* + * No colon prefix, so just go through all the subclasses. + */ + for (i = 0; i < lenof(unifont_types); i++) { + unifont *ret = unifont_types[i]->create(name, wide, bold, + shadowoffset, + shadowalways); + if (ret) + return ret; + } + return NULL; /* font not found in any scheme */ + } +} + +void unifont_destroy(unifont *font) +{ + font->vt->destroy(font); +} + +void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, + int x, int y, const char *string, int len, + int wide, int bold) +{ + font->vt->draw_text(target, gc, font, x, y, string, len, wide, bold); +} diff --git a/unix/gtkfont.h b/unix/gtkfont.h new file mode 100644 index 00000000..9cb66783 --- /dev/null +++ b/unix/gtkfont.h @@ -0,0 +1,46 @@ +/* + * Header file for gtkfont.c. Has to be separate from unix.h + * because it depends on GTK data types, hence can't be included + * from cross-platform code (which doesn't go near GTK). + */ + +#ifndef PUTTY_GTKFONT_H +#define PUTTY_GTKFONT_H + +/* + * Exports from gtkfont.c. + */ +struct unifont_vtable; /* contents internal to gtkfont.c */ +typedef struct unifont { + const struct unifont_vtable *vt; + /* + * `Non-static data members' of the `class', accessible to + * external code. + */ + + /* + * public_charset is the charset used when the user asks for + * `Use font encoding'. + * + * real_charset is the charset used when translating text into + * a form suitable for sending to unifont_draw_text(). + * + * They can differ. For example, public_charset might be + * CS_ISO8859_1 while real_charset is CS_ISO8859_1_X11. + */ + int public_charset, real_charset; + + /* + * Font dimensions needed by clients. + */ + int width, height, ascent, descent; +} unifont; + +unifont *unifont_create(char *name, int wide, int bold, + int shadowoffset, int shadowalways); +void unifont_destroy(unifont *font); +void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, + int x, int y, const char *string, int len, + int wide, int bold); + +#endif /* PUTTY_GTKFONT_H */ diff --git a/unix/gtkwin.c b/unix/gtkwin.c index e6ff13c3..2972dba1 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -28,6 +28,7 @@ #include "putty.h" #include "terminal.h" +#include "gtkfont.h" #define CAT2(x,y) x ## y #define CAT(x,y) CAT2(x,y) @@ -58,11 +59,7 @@ struct gui_data { *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; - GdkFont *fonts[4]; /* normal, bold, wide, widebold */ - struct { - int charset; - int is_wide; - } fontinfo[4]; + unifont *fonts[4]; /* normal, bold, wide, widebold */ int xpos, ypos, gotpos, gravity; GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; @@ -1880,6 +1877,8 @@ int char_width(Context ctx, int uc) * Under X, any fixed-width font really _is_ fixed-width. * Double-width characters will be dealt with using a separate * font. For the moment we can simply return 1. + * + * FIXME: but is that also true of Pango? */ return 1; } @@ -1920,7 +1919,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, struct gui_data *inst = dctx->inst; GdkGC *gc = dctx->gc; int ncombining, combining; - int nfg, nbg, t, fontid, shadow, rlen, widefactor; + int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; int monochrome = gtk_widget_get_visual(inst->area)->depth == 1; if (attr & TATTR_COMBINING) { @@ -1959,10 +1958,27 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } if ((attr & ATTR_BOLD) && !inst->cfg.bold_colour) { - if (inst->fonts[fontid | 1]) - fontid |= 1; - else - shadow = 1; + bold = 1; + fontid |= 1; + } else { + bold = 0; + } + + if (!inst->fonts[fontid]) { + int i; + /* + * Fall back through font ids with subsets of this one's + * set bits, in order. + */ + for (i = fontid; i-- > 0 ;) { + if (i & ~fontid) + continue; /* some other bit is set */ + if (inst->fonts[i]) { + fontid = i; + break; + } + } + assert(inst->fonts[fontid]); /* we should at least have hit zero */ } if ((lattr & LATTR_MODE) != LATTR_NORM) { @@ -1993,82 +2009,27 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, gdk_gc_set_foreground(gc, &inst->cols[nfg]); { - GdkWChar *gwcs; gchar *gcs; - wchar_t *wcs; - int i; - wcs = snewn(len*ncombining+1, wchar_t); - for (i = 0; i < len*ncombining; i++) { - wcs[i] = text[i]; - } + /* + * FIXME: this length is hardwired on the assumption that + * conversions from wide to multibyte characters will + * never generate more than 10 bytes for a single wide + * character. + */ + gcs = snewn(len*10+1, gchar); - if (inst->fonts[fontid] == NULL && (fontid & 2)) { - /* - * We've been given ATTR_WIDE, but have no wide font. - * Fall back to the non-wide font. - */ - fontid &= ~2; - } - - if (inst->fonts[fontid] == NULL) { - /* - * The font for this contingency does not exist. So we - * display nothing at all; such is life. - */ - } else if (inst->fontinfo[fontid].is_wide) { - /* - * At least one version of gdk_draw_text_wc() has a - * weird bug whereby it reads `len' elements of the - * input string, but only draws `len/2'. Hence I'm - * going to make its input array twice as long as it - * theoretically needs to be, and pass in twice the - * actual number of characters. If a fixed gdk actually - * takes the doubled length seriously, then (a) the - * array will stand scrutiny up to the full length, (b) - * the spare elements of the array are full of zeroes - * which will probably be an empty glyph in the font, - * and (c) the clip rectangle should prevent it causing - * trouble anyway. - */ - gwcs = snewn(len*2+1, GdkWChar); - memset(gwcs, 0, sizeof(GdkWChar) * (len*2+1)); - /* - * FIXME: when we have a wide-char equivalent of - * from_unicode, use it instead of this. - */ - for (combining = 0; combining < ncombining; combining++) { - for (i = 0; i <= len; i++) - gwcs[i] = wcs[i + combining]; - gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gwcs, len*2); - if (shadow) - gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gwcs, len*2); - } - sfree(gwcs); - } else { - gcs = snewn(len+1, gchar); - for (combining = 0; combining < ncombining; combining++) { - wc_to_mb(inst->fontinfo[fontid].charset, 0, - wcs + combining, len, gcs, len, ".", NULL, NULL); - gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, + for (combining = 0; combining < ncombining; combining++) { + int mblen = wc_to_mb(inst->fonts[fontid]->real_charset, 0, + text + combining, len, gcs, len*10+1, ".", + NULL, NULL); + unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid], x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gcs, len); - if (shadow) - gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gcs, len); - } - sfree(gcs); + gcs, mblen, widefactor > 1, bold); } - sfree(wcs); + + sfree(gcs); } if (attr & ATTR_UNDER) { @@ -2633,70 +2594,6 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, return err; } -/* - * This function retrieves the character set encoding of a font. It - * returns the character set without the X11 hack (in case the user - * asks to use the font's own encoding). - */ -static int set_font_info(struct gui_data *inst, int fontid) -{ - GdkFont *font = inst->fonts[fontid]; - XFontStruct *xfs = GDK_FONT_XFONT(font); - Display *disp = GDK_FONT_XDISPLAY(font); - Atom charset_registry, charset_encoding; - unsigned long registry_ret, encoding_ret; - int retval = CS_NONE; - - charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False); - charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False); - inst->fontinfo[fontid].charset = CS_NONE; - inst->fontinfo[fontid].is_wide = 0; - if (XGetFontProperty(xfs, charset_registry, ®istry_ret) && - XGetFontProperty(xfs, charset_encoding, &encoding_ret)) { - char *reg, *enc; - reg = XGetAtomName(disp, (Atom)registry_ret); - enc = XGetAtomName(disp, (Atom)encoding_ret); - if (reg && enc) { - char *encoding = dupcat(reg, "-", enc, NULL); - retval = inst->fontinfo[fontid].charset = - charset_from_xenc(encoding); - /* FIXME: when libcharset supports wide encodings fix this. */ - if (!strcasecmp(encoding, "iso10646-1")) { - inst->fontinfo[fontid].is_wide = 1; - retval = CS_UTF8; - } - - /* - * Hack for X line-drawing characters: if the primary - * font is encoded as ISO-8859-anything, and has valid - * glyphs in the first 32 char positions, it is assumed - * that those glyphs are the VT100 line-drawing - * character set. - * - * Actually, we'll hack even harder by only checking - * position 0x19 (vertical line, VT100 linedrawing - * `x'). Then we can check it easily by seeing if the - * ascent and descent differ. - */ - if (inst->fontinfo[fontid].charset == CS_ISO8859_1) { - int lb, rb, wid, asc, desc; - gchar text[2]; - - text[1] = '\0'; - text[0] = '\x12'; - gdk_string_extents(inst->fonts[fontid], text, - &lb, &rb, &wid, &asc, &desc); - if (asc != desc) - inst->fontinfo[fontid].charset = CS_ISO8859_1_X11; - } - - sfree(encoding); - } - } - - return retval; -} - int uxsel_input_add(int fd, int rwx) { int flags = 0; if (rwx & 1) flags |= GDK_INPUT_READ; @@ -2710,173 +2607,71 @@ void uxsel_input_remove(int id) { gdk_input_remove(id); } -char *guess_derived_font_name(GdkFont *font, int bold, int wide) -{ - XFontStruct *xfs = GDK_FONT_XFONT(font); - Display *disp = GDK_FONT_XDISPLAY(font); - Atom fontprop = XInternAtom(disp, "FONT", False); - unsigned long ret; - if (XGetFontProperty(xfs, fontprop, &ret)) { - char *name = XGetAtomName(disp, (Atom)ret); - if (name && name[0] == '-') { - char *strings[13]; - char *dupname, *extrafree = NULL, *ret; - char *p, *q; - int nstr; - - p = q = dupname = dupstr(name); /* skip initial minus */ - nstr = 0; - - while (*p && nstr < lenof(strings)) { - if (*p == '-') { - *p = '\0'; - strings[nstr++] = p+1; - } - p++; - } - - if (nstr < lenof(strings)) - return NULL; /* XLFD was malformed */ - - if (bold) - strings[2] = "bold"; - - if (wide) { - /* 4 is `wideness', which obviously may have changed. */ - /* 5 is additional style, which may be e.g. `ja' or `ko'. */ - strings[4] = strings[5] = "*"; - strings[11] = extrafree = dupprintf("%d", 2*atoi(strings[11])); - } - - ret = dupcat("-", strings[ 0], "-", strings[ 1], "-", strings[ 2], - "-", strings[ 3], "-", strings[ 4], "-", strings[ 5], - "-", strings[ 6], "-", strings[ 7], "-", strings[ 8], - "-", strings[ 9], "-", strings[10], "-", strings[11], - "-", strings[12], NULL); - sfree(extrafree); - sfree(dupname); - - return ret; - } - } - return NULL; -} - void setup_fonts_ucs(struct gui_data *inst) { - int font_charset; - char *name; - int guessed; - if (inst->fonts[0]) - gdk_font_unref(inst->fonts[0]); + unifont_destroy(inst->fonts[0]); if (inst->fonts[1]) - gdk_font_unref(inst->fonts[1]); + unifont_destroy(inst->fonts[1]); if (inst->fonts[2]) - gdk_font_unref(inst->fonts[2]); + unifont_destroy(inst->fonts[2]); if (inst->fonts[3]) - gdk_font_unref(inst->fonts[3]); + unifont_destroy(inst->fonts[3]); - inst->fonts[0] = gdk_font_load(inst->cfg.font.name); + inst->fonts[0] = unifont_create(inst->cfg.font.name, FALSE, FALSE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); if (!inst->fonts[0]) { fprintf(stderr, "%s: unable to load font \"%s\"\n", appname, inst->cfg.font.name); exit(1); } - gdk_font_ref(inst->fonts[0]); - font_charset = set_font_info(inst, 0); - if (inst->cfg.shadowbold) { + if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) { inst->fonts[1] = NULL; } else { - if (inst->cfg.boldfont.name[0]) { - name = inst->cfg.boldfont.name; - guessed = FALSE; - } else { - name = guess_derived_font_name(inst->fonts[0], TRUE, FALSE); - guessed = TRUE; - } - inst->fonts[1] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[1]) { - gdk_font_ref(inst->fonts[1]); - set_font_info(inst, 1); - } else if (!guessed) { + inst->fonts[1] = unifont_create(inst->cfg.boldfont.name, FALSE, TRUE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[1]) { fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, inst->cfg.boldfont.name); exit(1); } - if (guessed) - sfree(name); } if (inst->cfg.widefont.name[0]) { - name = inst->cfg.widefont.name; - guessed = FALSE; - } else { - name = guess_derived_font_name(inst->fonts[0], FALSE, TRUE); - guessed = TRUE; - } - inst->fonts[2] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[2]) { - gdk_font_ref(inst->fonts[2]); - set_font_info(inst, 2); - } else if (!guessed) { - fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, - inst->cfg.widefont.name); - exit(1); - } - if (guessed) - sfree(name); - - if (inst->cfg.shadowbold) { - inst->fonts[3] = NULL; - } else { - if (inst->cfg.wideboldfont.name[0]) { - name = inst->cfg.wideboldfont.name; - guessed = FALSE; - } else { - /* - * Here we have some choices. We can widen the bold font, - * bolden the wide font, or widen and bolden the standard - * font. Try them all, in that order! - */ - if (inst->cfg.widefont.name[0]) - name = guess_derived_font_name(inst->fonts[2], TRUE, FALSE); - else if (inst->cfg.boldfont.name[0]) - name = guess_derived_font_name(inst->fonts[1], FALSE, TRUE); - else - name = guess_derived_font_name(inst->fonts[0], TRUE, TRUE); - guessed = TRUE; - } - inst->fonts[3] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[3]) { - gdk_font_ref(inst->fonts[3]); - set_font_info(inst, 3); - } else if (!guessed) { - fprintf(stderr, "%s: unable to load wide/bold font \"%s\"\n", appname, - inst->cfg.wideboldfont.name); + inst->fonts[2] = unifont_create(inst->cfg.widefont.name, TRUE, FALSE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[2]) { + fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, + inst->cfg.widefont.name); exit(1); } - if (guessed) - sfree(name); + } else { + inst->fonts[2] = NULL; } - inst->font_width = gdk_char_width(inst->fonts[0], ' '); - if (!inst->font_width) { - /* Maybe this is a 16-bit font? If so, GDK 2 actually expects a - * pointer to an XChar2b. This is pretty revolting. Can Pango do - * this more neatly even for server-side fonts? - */ - XChar2b space; - space.byte1 = 0; - space.byte2 = ' '; - inst->font_width = gdk_text_width(inst->fonts[0], - (const gchar *)&space, 2); + if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) { + inst->fonts[3] = NULL; + } else { + inst->fonts[3] = unifont_create(inst->cfg.wideboldfont.name, TRUE, + TRUE, inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[3]) { + fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname, + inst->cfg.boldfont.name); + exit(1); + } } - inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; + + inst->font_width = inst->fonts[0]->width; + inst->font_height = inst->fonts[0]->height; inst->direct_to_font = init_ucs(&inst->ucsdata, inst->cfg.line_codepage, - inst->cfg.utf8_override, font_charset, + inst->cfg.utf8_override, + inst->fonts[0]->public_charset, inst->cfg.vtmode); }