From cce6a5e2ec53542c3f4dca4035cdee4ec243fca5 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 29 Mar 2008 10:48:16 +0000 Subject: [PATCH] Detect non-monospaced X fonts, and respond by drawing text one character at a time centred in its character cell, as we do for Pango. Gives much better results for those non-monospaced fonts which are usable as terminal fonts, and shows up the problems with the others more readily. (In particular, this means the preview pane in the font selector now warns you there will be trouble if you select such a font.) [originally from svn r7949] --- unix/gtkfont.c | 81 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/unix/gtkfont.c b/unix/gtkfont.c index d236c6f4..f5b7ec8c 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -27,10 +27,6 @@ * TODO on fontsel * --------------- * - * - start drawing X fonts one character at a time, at least if - * they're not fixed-width? Now we have that helpful pangram, - * we should make it work for everyone. - * * - think about points versus pixels, harder than I already have * * - generalised style and padding polish @@ -145,6 +141,12 @@ struct x11font { * whether we use gdk_draw_text_wc() or gdk_draw_text(). */ int sixteen_bit; + /* + * `variable' is true iff the font is non-fixed-pitch. This + * enables some code which takes greater care over character + * positioning during text drawing. + */ + int variable; /* * Data passed in to unifont_create(). */ @@ -218,10 +220,10 @@ static int x11_font_width(GdkFont *font, int sixteen_bit) if (sixteen_bit) { XChar2b space; space.byte1 = 0; - space.byte2 = ' '; + space.byte2 = '0'; return gdk_text_width(font, (const gchar *)&space, 2); } else { - return gdk_char_width(font, ' '); + return gdk_char_width(font, '0'); } } @@ -233,9 +235,9 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, GdkFont *font; XFontStruct *xfs; Display *disp; - Atom charset_registry, charset_encoding; - unsigned long registry_ret, encoding_ret; - int pubcs, realcs, sixteen_bit; + Atom charset_registry, charset_encoding, spacing; + unsigned long registry_ret, encoding_ret, spacing_ret; + int pubcs, realcs, sixteen_bit, variable; int i; font = gdk_font_load(name); @@ -250,6 +252,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, pubcs = realcs = CS_NONE; sixteen_bit = FALSE; + variable = TRUE; if (XGetFontProperty(xfs, charset_registry, ®istry_ret) && XGetFontProperty(xfs, charset_encoding, &encoding_ret)) { @@ -298,6 +301,15 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, } } + spacing = XInternAtom(disp, "SPACING", False); + if (XGetFontProperty(xfs, spacing, &spacing_ret)) { + char *spc; + spc = XGetAtomName(disp, (Atom)spacing_ret); + + if (spc && strchr("CcMm", spc[0])) + variable = FALSE; + } + xfont = snew(struct x11font); xfont->u.vt = &x11font_vtable; xfont->u.width = x11_font_width(font, sixteen_bit); @@ -309,6 +321,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name, xfont->fonts[0] = font; xfont->allocated[0] = TRUE; xfont->sixteen_bit = sixteen_bit; + xfont->variable = variable; xfont->wide = wide; xfont->bold = bold; xfont->shadowoffset = shadowoffset; @@ -342,6 +355,38 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid) sfree(derived_name); } +static void x11font_really_draw_text(GdkDrawable *target, GdkFont *font, + GdkGC *gc, int x, int y, + const gchar *string, int clen, int nchars, + int shadowbold, int shadowoffset, + int fontvariable, int cellwidth) +{ + int step = clen * nchars, nsteps = 1, centre = FALSE; + + if (fontvariable) { + /* + * In a variable-pitch font, we draw one character at a + * time, and centre it in the character cell. + */ + step = clen; + nsteps = nchars; + centre = TRUE; + } + + while (nsteps-- > 0) { + int X = x; + if (centre) + X += (cellwidth - gdk_text_width(font, string, step)) / 2; + + gdk_draw_text(target, font, gc, X, y, string, step); + if (shadowbold) + gdk_draw_text(target, font, gc, X + shadowoffset, y, string, step); + + x += cellwidth; + string += step; + } +} + static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, int x, int y, const char *string, int len, int wide, int bold, int cellwidth) @@ -349,6 +394,7 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, struct x11font *xfont = (struct x11font *)font; int sfid; int shadowbold = FALSE; + int mult = (wide ? 2 : 1); wide -= xfont->wide; bold -= xfont->bold; @@ -404,18 +450,17 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, 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); + x11font_really_draw_text(target, xfont->fonts[sfid], gc, x, y, + (gchar *)xcs, 2, nchars, + shadowbold, xfont->shadowoffset, + xfont->variable, cellwidth * mult); 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); + x11font_really_draw_text(target, xfont->fonts[sfid], gc, x, y, + string, 1, len, + shadowbold, xfont->shadowoffset, + xfont->variable, cellwidth * mult); } } -- 2.45.2