X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkfont.c;h=2f7e4a6172e96eb2b87cd6b92777befcd3732716;hb=af1460d6e5044a3344aaacd15c91cfdcb58578e7;hp=82c0dafaf7d942b6c6ee668de30ee7b841d35381;hpb=5de838a979f75380c5fc4bec39646b81b44bd9b6;p=PuTTY.git diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 82c0dafa..2f7e4a61 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -18,9 +18,12 @@ #include #endif +#define MAY_REFER_TO_GTK_IN_HEADERS + #include "putty.h" #include "gtkfont.h" #include "gtkcompat.h" +#include "gtkmisc.h" #include "tree234.h" #ifndef NOT_X_WINDOWS @@ -80,6 +83,9 @@ struct unifont_vtable { void (*draw_text)(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); + void (*draw_combining)(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth); void (*enum_fonts)(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size, @@ -104,6 +110,9 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph); static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth); static unifont *x11font_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); @@ -203,6 +212,7 @@ static const struct unifont_vtable x11font_vtable = { x11font_destroy, x11font_has_glyph, x11font_draw_text, + x11font_draw_combining, x11font_enum_fonts, x11font_canonify_fontname, x11font_scale_fontname, @@ -865,6 +875,20 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, } } +static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth) +{ + /* + * For server-side fonts, there's no sophisticated system for + * combining characters intelligently, so the best we can do is to + * overprint them on each other in the obvious way. + */ + int i; + for (i = 0; i < len; i++) + x11font_draw_text(ctx, font, x, y, string+i, 1, wide, bold, cellwidth); +} + static void x11font_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx) { @@ -1109,6 +1133,10 @@ static int pangofont_has_glyph(unifont *font, wchar_t glyph); static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); static unifont *pangofont_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); @@ -1154,6 +1182,7 @@ static const struct unifont_vtable pangofont_vtable = { pangofont_destroy, pangofont_has_glyph, pangofont_draw_text, + pangofont_draw_combining, pangofont_enum_fonts, pangofont_canonify_fontname, pangofont_scale_fontname, @@ -1335,10 +1364,10 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, /* * Here we check whether a character has the same width as the * character cell it'll be drawn in. Because profiling showed that - * pango_layout_get_pixel_extents() was a huge bottleneck when we - * were calling it every time we needed to know this, we instead - * call it only on characters we don't already know about, and - * cache the results. + * asking Pango for text sizes was a huge bottleneck when we were + * calling it every time we needed to know this, we instead call + * it only on characters we don't already know about, and cache + * the results. */ if ((unsigned)uchr >= pfont->nwidthcache) { @@ -1351,7 +1380,7 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, if (pfont->widthcache[uchr] < 0) { PangoRectangle rect; pango_layout_set_text(layout, utfchr, utflen); - pango_layout_get_pixel_extents(layout, NULL, &rect); + pango_layout_get_extents(layout, NULL, &rect); pfont->widthcache[uchr] = rect.width; } @@ -1381,9 +1410,10 @@ static void pango_cairo_draw_layout(unifont_drawctx *ctx, } #endif -static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, - int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) +static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth, + int combining) { struct pangofont *pfont = (struct pangofont *)font; PangoLayout *layout; @@ -1434,6 +1464,7 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, utfptr = utfstring; while (utflen > 0) { int clen, n; + int desired = cellwidth * PANGO_SCALE; /* * We want to display every character from this string in @@ -1459,45 +1490,55 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, * them to do that. */ - /* - * Start by extracting a single UTF-8 character from the - * string. - */ - clen = 1; - while (clen < utflen && - (unsigned char)utfptr[clen] >= 0x80 && - (unsigned char)utfptr[clen] < 0xC0) - clen++; - n = 1; - - if (is_rtl(string[0]) || - pangofont_char_width(layout, pfont, string[n-1], - utfptr, clen) != cellwidth) { + if (combining) { /* - * If this character is a right-to-left one, or has an - * unusual width, then we must display it on its own. + * For a character with combining stuff, we just dump the + * whole lot in one go, and expect it to take up just one + * character cell. */ + clen = utflen; + n = 1; } else { /* - * Try to amalgamate a contiguous string of characters - * with the expected sensible width, for the common case - * in which we're using a monospaced font and everything - * works as expected. + * Start by extracting a single UTF-8 character from the + * string. */ - while (clen < utflen) { - int oldclen = clen; - clen++; /* skip UTF-8 introducer byte */ - while (clen < utflen && - (unsigned char)utfptr[clen] >= 0x80 && - (unsigned char)utfptr[clen] < 0xC0) - clen++; - n++; - if (pangofont_char_width(layout, pfont, - string[n-1], utfptr + oldclen, - clen - oldclen) != cellwidth) { - clen = oldclen; - n--; - break; + clen = 1; + while (clen < utflen && + (unsigned char)utfptr[clen] >= 0x80 && + (unsigned char)utfptr[clen] < 0xC0) + clen++; + n = 1; + + if (is_rtl(string[0]) || + pangofont_char_width(layout, pfont, string[n-1], + utfptr, clen) != desired) { + /* + * If this character is a right-to-left one, or has an + * unusual width, then we must display it on its own. + */ + } else { + /* + * Try to amalgamate a contiguous string of characters + * with the expected sensible width, for the common case + * in which we're using a monospaced font and everything + * works as expected. + */ + while (clen < utflen) { + int oldclen = clen; + clen++; /* skip UTF-8 introducer byte */ + while (clen < utflen && + (unsigned char)utfptr[clen] >= 0x80 && + (unsigned char)utfptr[clen] < 0xC0) + clen++; + n++; + if (pangofont_char_width(layout, pfont, + string[n-1], utfptr + oldclen, + clen - oldclen) != desired) { + clen = oldclen; + n--; + break; + } } } } @@ -1524,6 +1565,37 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, g_object_unref(layout); } +static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) +{ + pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, + cellwidth, FALSE); +} + +static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth) +{ + wchar_t *tmpstring = NULL; + if (mk_wcwidth(string[0]) == 0) { + /* + * If we've been told to draw a sequence of _only_ combining + * characters, prefix a space so that they have something to + * combine with. + */ + tmpstring = snewn(len+1, wchar_t); + memcpy(tmpstring+1, string, len * sizeof(wchar_t)); + tmpstring[0] = L' '; + string = tmpstring; + len++; + } + pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, + cellwidth, TRUE); + sfree(tmpstring); +} + /* * Dummy size value to be used when converting a * PangoFontDescription of a scalable font to a string for @@ -1869,6 +1941,14 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font, font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth); } +void unifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) +{ + font->vt->draw_combining(ctx, font, x, y, string, len, wide, bold, + cellwidth); +} + /* ---------------------------------------------------------------------- * Multiple-font wrapper. This is a type of unifont which encapsulates * up to two other unifonts, permitting missing glyphs in the main @@ -1885,6 +1965,10 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font, static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); static void multifont_destroy(unifont *font); struct multifont { @@ -1899,6 +1983,7 @@ static const struct unifont_vtable multifont_vtable = { multifont_destroy, NULL, multifont_draw_text, + multifont_draw_combining, NULL, NULL, NULL, @@ -1959,9 +2044,15 @@ static void multifont_destroy(unifont *font) sfree(font); } -static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, +typedef void (*unifont_draw_func_t)(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); + +static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + int wide, int bold, int cellwidth, + int cellinc, unifont_draw_func_t draw) { struct multifont *mfont = (struct multifont *)font; unifont *f; @@ -1983,51 +2074,28 @@ static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, */ f = ok ? mfont->main : mfont->fallback; if (f) - unifont_draw_text(ctx, f, x, y, string, i, wide, bold, cellwidth); + draw(ctx, f, x, y, string, i, wide, bold, cellwidth); string += i; len -= i; - x += i * cellwidth; + x += i * cellinc; } } -/* ---------------------------------------------------------------------- - * Utility routine used by the code below, and also gtkdlg.c. - */ - -void get_label_text_dimensions(const char *text, int *width, int *height) +static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, + int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) { - /* - * Determine the dimensions of a piece of text in the standard - * font used in GTK interface elements like labels. We do this by - * instantiating an actual GtkLabel, and then querying its size. - * - * But GTK2 and GTK3 require us to query the size completely - * differently. I'm sure there ought to be an easier approach than - * the way I'm doing this in GTK3, too! - */ - GtkWidget *label = gtk_label_new(text); - -#if GTK_CHECK_VERSION(3,0,0) - PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(label)); - PangoRectangle logrect; - pango_layout_get_extents(layout, NULL, &logrect); - if (width) - *width = logrect.width / PANGO_SCALE; - if (height) - *height = logrect.height / PANGO_SCALE; -#else - GtkRequisition req; - gtk_widget_size_request(label, &req); - if (width) - *width = req.width; - if (height) - *height = req.height; -#endif + multifont_draw_main(ctx, font, x, y, string, len, wide, bold, + cellwidth, cellwidth, unifont_draw_text); +} - g_object_ref_sink(G_OBJECT(label)); -#if GTK_CHECK_VERSION(2,10,0) - g_object_unref(label); -#endif +static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth) +{ + multifont_draw_main(ctx, font, x, y, string, len, wide, bold, + cellwidth, 0, unifont_draw_combining); } #if GTK_CHECK_VERSION(2,0,0) @@ -2287,7 +2355,7 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, currstyle, 1, minpos, 2, maxpos+1, - 3, TRUE, -1); + 3, TRUE, 4, PANGO_WEIGHT_NORMAL, -1); listindex++; } if (info) { @@ -2296,7 +2364,7 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, info->charset, 1, -1, 2, -1, - 3, FALSE, -1); + 3, FALSE, 4, PANGO_WEIGHT_BOLD, -1); listindex++; } currcs = info->charset; @@ -3056,22 +3124,30 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_table_set_col_spacings(GTK_TABLE(table), 8); #endif gtk_widget_show(table); -#if GTK_CHECK_VERSION(2,4,0) + +#if GTK_CHECK_VERSION(3,0,0) + /* GtkAlignment has become deprecated and we use the "margin" + * property */ + w = table; + g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL); +#elif GTK_CHECK_VERSION(2,4,0) /* GtkAlignment seems to be the simplest way to put padding round things */ w = gtk_alignment_new(0, 0, 1, 1); gtk_alignment_set_padding(GTK_ALIGNMENT(w), 8, 8, 8, 8); gtk_container_add(GTK_CONTAINER(w), table); gtk_widget_show(w); #else + /* In GTK < 2.4, even that isn't available */ w = table; #endif + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area (GTK_DIALOG(fs->u.window))), w, TRUE, TRUE, 0); label = gtk_label_new_with_mnemonic("_Font:"); gtk_widget_show(label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1); g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); @@ -3119,7 +3195,7 @@ unifontsel *unifontsel_new(const char *wintitle) label = gtk_label_new_with_mnemonic("_Style:"); gtk_widget_show(label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1); g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); @@ -3128,19 +3204,21 @@ unifontsel *unifontsel_new(const char *wintitle) #endif /* - * The Style list box can contain insensitive elements - * (character set headings for server-side fonts), so we add - * an extra column to the list store to hold that information. + * The Style list box can contain insensitive elements (character + * set headings for server-side fonts), so we add an extra column + * to the list store to hold that information. Also, since GTK3 at + * least doesn't seem to display insensitive elements differently + * by default, we add a further column to change their style. */ - model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, - G_TYPE_BOOLEAN); + model = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, + G_TYPE_BOOLEAN, G_TYPE_INT); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); gtk_label_set_mnemonic_widget(GTK_LABEL(label), w); gtk_widget_show(w); column = gtk_tree_view_column_new_with_attributes ("Style", gtk_cell_renderer_text_new(), - "text", 0, "sensitive", 3, (char *)NULL); + "text", 0, "sensitive", 3, "weight", 4, (char *)NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column(GTK_TREE_VIEW(w), column); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))), @@ -3166,7 +3244,7 @@ unifontsel *unifontsel_new(const char *wintitle) label = gtk_label_new_with_mnemonic("Si_ze:"); gtk_widget_show(label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + align_label_left(GTK_LABEL(label)); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), label, 2, 0, 1, 1); g_object_set(G_OBJECT(label), "hexpand", TRUE, (const char *)NULL); @@ -3254,7 +3332,12 @@ unifontsel *unifontsel_new(const char *wintitle) w = gtk_frame_new(NULL); gtk_container_add(GTK_CONTAINER(w), ww); gtk_widget_show(w); -#if GTK_CHECK_VERSION(2,4,0) + +#if GTK_CHECK_VERSION(3,0,0) + /* GtkAlignment has become deprecated and we use the "margin" + * property */ + g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL); +#elif GTK_CHECK_VERSION(2,4,0) ww = w; /* GtkAlignment seems to be the simplest way to put padding round things */ w = gtk_alignment_new(0, 0, 1, 1); @@ -3262,6 +3345,7 @@ unifontsel *unifontsel_new(const char *wintitle) gtk_container_add(GTK_CONTAINER(w), ww); gtk_widget_show(w); #endif + ww = w; w = gtk_frame_new("Preview of font"); gtk_container_add(GTK_CONTAINER(w), ww);