Implemented a Pango back end. GTK 2 PuTTY can now switch seamlessly

back and forth between X fonts and Pango fonts, provided you're
willing to type in the names of the former by hand.

[originally from svn r7937]
This commit is contained in:
Simon Tatham 2008-03-22 18:11:17 +00:00
Родитель 93c6e2c987
Коммит debbee0fe4
3 изменённых файлов: 191 добавлений и 28 удалений

Просмотреть файл

@ -25,10 +25,11 @@
/* /*
* To do: * To do:
* *
* - import flags to do VT100 double-width, and import the icky * - import flags to do VT100 double-width; import the icky
* pixmap stretch code for it. * pixmap stretch code on to the X11 side, and do something
* nicer in Pango.
* *
* - add the Pango back end! * - unified font selector dialog, arrgh!
*/ */
/* /*
@ -56,12 +57,12 @@ struct unifont_vtable {
/* /*
* `Methods' of the `class'. * `Methods' of the `class'.
*/ */
unifont *(*create)(char *name, int wide, int bold, unifont *(*create)(GtkWidget *widget, char *name, int wide, int bold,
int shadowoffset, int shadowalways); int shadowoffset, int shadowalways);
void (*destroy)(unifont *font); void (*destroy)(unifont *font);
void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font, void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int wide, int x, int y, const char *string, int len, int wide,
int bold); int bold, int cellwidth);
/* /*
* `Static data members' of the `class'. * `Static data members' of the `class'.
*/ */
@ -74,8 +75,9 @@ struct unifont_vtable {
static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int x, int y, const char *string, int len,
int wide, int bold); int wide, int bold, int cellwidth);
static unifont *x11font_create(char *name, int wide, int bold, static unifont *x11font_create(GtkWidget *widget, char *name,
int wide, int bold,
int shadowoffset, int shadowalways); int shadowoffset, int shadowalways);
static void x11font_destroy(unifont *font); static void x11font_destroy(unifont *font);
@ -99,11 +101,6 @@ struct x11font {
* whether we use gdk_draw_text_wc() or gdk_draw_text(). * whether we use gdk_draw_text_wc() or gdk_draw_text().
*/ */
int sixteen_bit; 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(). * Data passed in to unifont_create().
*/ */
@ -181,7 +178,8 @@ static int x11_font_width(GdkFont *font, int sixteen_bit)
} }
} }
static unifont *x11font_create(char *name, int wide, int bold, static unifont *x11font_create(GtkWidget *widget, char *name,
int wide, int bold,
int shadowoffset, int shadowalways) int shadowoffset, int shadowalways)
{ {
struct x11font *xfont; struct x11font *xfont;
@ -299,7 +297,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid)
static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int x, int y, const char *string, int len,
int wide, int bold) int wide, int bold, int cellwidth)
{ {
struct x11font *xfont = (struct x11font *)font; struct x11font *xfont = (struct x11font *)font;
int sfid; int sfid;
@ -374,6 +372,164 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
} }
} }
/* ----------------------------------------------------------------------
* Pango font implementation.
*/
static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len,
int wide, int bold, int cellwidth);
static unifont *pangofont_create(GtkWidget *widget, char *name,
int wide, int bold,
int shadowoffset, int shadowalways);
static void pangofont_destroy(unifont *font);
struct pangofont {
struct unifont u;
/*
* Pango objects.
*/
PangoFontDescription *desc;
PangoFontset *fset;
/*
* The containing widget.
*/
GtkWidget *widget;
/*
* Data passed in to unifont_create().
*/
int bold, shadowoffset, shadowalways;
};
static const struct unifont_vtable pangofont_vtable = {
pangofont_create,
pangofont_destroy,
pangofont_draw_text,
"pango"
};
static unifont *pangofont_create(GtkWidget *widget, char *name,
int wide, int bold,
int shadowoffset, int shadowalways)
{
struct pangofont *pfont;
PangoContext *ctx;
PangoFontMap *map;
PangoFontDescription *desc;
PangoFontset *fset;
PangoFontMetrics *metrics;
desc = pango_font_description_from_string(name);
if (!desc)
return NULL;
ctx = gtk_widget_get_pango_context(widget);
if (!ctx) {
pango_font_description_free(desc);
return NULL;
}
map = pango_context_get_font_map(ctx);
if (!map) {
pango_font_description_free(desc);
return NULL;
}
fset = pango_font_map_load_fontset(map, ctx, desc,
pango_context_get_language(ctx));
if (!fset) {
pango_font_description_free(desc);
return NULL;
}
metrics = pango_fontset_get_metrics(fset);
if (!metrics ||
pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
pango_font_description_free(desc);
g_object_unref(fset);
return NULL;
}
pfont = snew(struct pangofont);
pfont->u.vt = &pangofont_vtable;
pfont->u.width =
PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics));
pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
pfont->u.height = pfont->u.ascent + pfont->u.descent;
/* The Pango API is hardwired to UTF-8 */
pfont->u.public_charset = CS_UTF8;
pfont->u.real_charset = CS_UTF8;
pfont->desc = desc;
pfont->fset = fset;
pfont->widget = widget;
pfont->bold = bold;
pfont->shadowoffset = shadowoffset;
pfont->shadowalways = shadowalways;
return (unifont *)pfont;
}
static void pangofont_destroy(unifont *font)
{
struct pangofont *pfont = (struct pangofont *)font;
pfont = pfont; /* FIXME */
pango_font_description_free(pfont->desc);
g_object_unref(pfont->fset);
sfree(font);
}
static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len,
int wide, int bold, int cellwidth)
{
struct pangofont *pfont = (struct pangofont *)font;
PangoLayout *layout;
PangoRectangle rect;
int shadowbold = FALSE;
if (wide)
cellwidth *= 2;
y -= pfont->u.ascent;
layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget));
pango_layout_set_font_description(layout, pfont->desc);
if (bold > pfont->bold) {
if (pfont->shadowalways)
shadowbold = TRUE;
else {
PangoFontDescription *desc2 =
pango_font_description_copy_static(pfont->desc);
pango_font_description_set_weight(desc2, PANGO_WEIGHT_BOLD);
pango_layout_set_font_description(layout, desc2);
}
}
while (len > 0) {
int clen;
/*
* Extract a single UTF-8 character from the string.
*/
clen = 1;
while (clen < len &&
(unsigned char)string[clen] >= 0x80 &&
(unsigned char)string[clen] < 0xC0)
clen++;
pango_layout_set_text(layout, string, clen);
pango_layout_get_pixel_extents(layout, NULL, &rect);
gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2,
y + (pfont->u.height - rect.height)/2, layout);
if (shadowbold)
gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2 + pfont->shadowoffset,
y + (pfont->u.height - rect.height)/2, layout);
len -= clen;
string += clen;
x += cellwidth;
}
g_object_unref(layout);
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* Outermost functions which do the vtable dispatch. * Outermost functions which do the vtable dispatch.
*/ */
@ -385,9 +541,10 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
* the font name. * the font name.
*/ */
static const struct unifont_vtable *unifont_types[] = { static const struct unifont_vtable *unifont_types[] = {
&pangofont_vtable,
&x11font_vtable, &x11font_vtable,
}; };
unifont *unifont_create(char *name, int wide, int bold, unifont *unifont_create(GtkWidget *widget, char *name, int wide, int bold,
int shadowoffset, int shadowalways) int shadowoffset, int shadowalways)
{ {
int colonpos = strcspn(name, ":"); int colonpos = strcspn(name, ":");
@ -405,14 +562,14 @@ unifont *unifont_create(char *name, int wide, int bold,
} }
if (i == lenof(unifont_types)) if (i == lenof(unifont_types))
return NULL; /* prefix not recognised */ return NULL; /* prefix not recognised */
return unifont_types[i]->create(name+colonpos+1, wide, bold, return unifont_types[i]->create(widget, name+colonpos+1, wide, bold,
shadowoffset, shadowalways); shadowoffset, shadowalways);
} else { } else {
/* /*
* No colon prefix, so just go through all the subclasses. * No colon prefix, so just go through all the subclasses.
*/ */
for (i = 0; i < lenof(unifont_types); i++) { for (i = 0; i < lenof(unifont_types); i++) {
unifont *ret = unifont_types[i]->create(name, wide, bold, unifont *ret = unifont_types[i]->create(widget, name, wide, bold,
shadowoffset, shadowoffset,
shadowalways); shadowalways);
if (ret) if (ret)
@ -429,7 +586,8 @@ void unifont_destroy(unifont *font)
void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int x, int y, const char *string, int len,
int wide, int bold) int wide, int bold, int cellwidth)
{ {
font->vt->draw_text(target, gc, font, x, y, string, len, wide, bold); font->vt->draw_text(target, gc, font, x, y, string, len,
wide, bold, cellwidth);
} }

Просмотреть файл

@ -36,11 +36,11 @@ typedef struct unifont {
int width, height, ascent, descent; int width, height, ascent, descent;
} unifont; } unifont;
unifont *unifont_create(char *name, int wide, int bold, unifont *unifont_create(GtkWidget *widget, char *name, int wide, int bold,
int shadowoffset, int shadowalways); int shadowoffset, int shadowalways);
void unifont_destroy(unifont *font); void unifont_destroy(unifont *font);
void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int x, int y, const char *string, int len,
int wide, int bold); int wide, int bold, int cellwidth);
#endif /* PUTTY_GTKFONT_H */ #endif /* PUTTY_GTKFONT_H */

Просмотреть файл

@ -1455,7 +1455,7 @@ void palette_reset(void *frontend)
/* Since Default Background may have changed, ensure that space /* Since Default Background may have changed, ensure that space
* between text area and window border is refreshed. */ * between text area and window border is refreshed. */
set_window_background(inst); set_window_background(inst);
if (inst->area) { if (inst->area && inst->area->window) {
draw_backing_rect(inst); draw_backing_rect(inst);
gtk_widget_queue_draw(inst->area); gtk_widget_queue_draw(inst->area);
} }
@ -2026,7 +2026,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid], unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],
x*inst->font_width+inst->cfg.window_border, x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
gcs, mblen, widefactor > 1, bold); gcs, mblen, widefactor > 1, bold, inst->font_width);
} }
sfree(gcs); sfree(gcs);
@ -2618,7 +2618,8 @@ void setup_fonts_ucs(struct gui_data *inst)
if (inst->fonts[3]) if (inst->fonts[3])
unifont_destroy(inst->fonts[3]); unifont_destroy(inst->fonts[3]);
inst->fonts[0] = unifont_create(inst->cfg.font.name, FALSE, FALSE, inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name,
FALSE, FALSE,
inst->cfg.shadowboldoffset, inst->cfg.shadowboldoffset,
inst->cfg.shadowbold); inst->cfg.shadowbold);
if (!inst->fonts[0]) { if (!inst->fonts[0]) {
@ -2630,7 +2631,8 @@ void setup_fonts_ucs(struct gui_data *inst)
if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) { if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) {
inst->fonts[1] = NULL; inst->fonts[1] = NULL;
} else { } else {
inst->fonts[1] = unifont_create(inst->cfg.boldfont.name, FALSE, TRUE, inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name,
FALSE, TRUE,
inst->cfg.shadowboldoffset, inst->cfg.shadowboldoffset,
inst->cfg.shadowbold); inst->cfg.shadowbold);
if (!inst->fonts[1]) { if (!inst->fonts[1]) {
@ -2641,7 +2643,8 @@ void setup_fonts_ucs(struct gui_data *inst)
} }
if (inst->cfg.widefont.name[0]) { if (inst->cfg.widefont.name[0]) {
inst->fonts[2] = unifont_create(inst->cfg.widefont.name, TRUE, FALSE, inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name,
TRUE, FALSE,
inst->cfg.shadowboldoffset, inst->cfg.shadowboldoffset,
inst->cfg.shadowbold); inst->cfg.shadowbold);
if (!inst->fonts[2]) { if (!inst->fonts[2]) {
@ -2656,7 +2659,8 @@ void setup_fonts_ucs(struct gui_data *inst)
if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) { if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) {
inst->fonts[3] = NULL; inst->fonts[3] = NULL;
} else { } else {
inst->fonts[3] = unifont_create(inst->cfg.wideboldfont.name, TRUE, inst->fonts[3] = unifont_create(inst->area,
inst->cfg.wideboldfont.name, TRUE,
TRUE, inst->cfg.shadowboldoffset, TRUE, inst->cfg.shadowboldoffset,
inst->cfg.shadowbold); inst->cfg.shadowbold);
if (!inst->fonts[3]) { if (!inst->fonts[3]) {
@ -3320,6 +3324,8 @@ int pt_main(int argc, char **argv)
if (!utf8_string_atom) if (!utf8_string_atom)
utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
inst->area = gtk_drawing_area_new();
setup_fonts_ucs(inst); setup_fonts_ucs(inst);
init_cutbuffers(); init_cutbuffers();
@ -3333,7 +3339,6 @@ int pt_main(int argc, char **argv)
inst->width = inst->cfg.width; inst->width = inst->cfg.width;
inst->height = inst->cfg.height; inst->height = inst->cfg.height;
inst->area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area),
inst->font_width * inst->cfg.width + 2*inst->cfg.window_border, inst->font_width * inst->cfg.width + 2*inst->cfg.window_border,
inst->font_height * inst->cfg.height + 2*inst->cfg.window_border); inst->font_height * inst->cfg.height + 2*inst->cfg.window_border);