зеркало из https://github.com/github/putty.git
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:
Родитель
93c6e2c987
Коммит
debbee0fe4
196
unix/gtkfont.c
196
unix/gtkfont.c
|
@ -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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче