1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

Unix PuTTY/pterm: Ctrl-< / Ctrl-> to change font size.

Each gtkfont back end now provides a routine that will return the name
of a similar font to the current one but one notch larger or smaller.
For Pango, this is just a matter of incrementing the font size field
in a standard way; for X11 server-side fonts, we have to go and do an
XListFonts query with a wildcard that requests fonts that vary only in
the size fields from the current one, and then iterate over the result
looking for the best one.

(I expect this will be more useful to Pango scalable-font users than
to X11 fonts, but it seemed a shame not to give the X11 side my best
shot while I was at it.)

Choice of hotkey: I know I'm being inconsistent with gnome-terminal's
use of Ctrl-plus and Ctrl-minus. I thought that was because I was
already using Ctrl-minus as a more convenient synonym for
Ctrl-underscore (which sends the actual control code 0x1F), but now I
actually try it, apparently I'm not. However, Ctrl-plus and Ctrl-minus
are quite horrible as a keystroke pair anyway (one has to be typed
with shift and one without!), and I feel as if the 'less' and
'greater' signs are more specific anyway, in that they specifically
indicate _size_ rather than just 'unspecified numerical value'.
This commit is contained in:
Simon Tatham 2016-11-13 13:53:42 +00:00
parent d9c68d236b
commit 1a51771720
4 changed files with 219 additions and 2 deletions

View File

@ -153,6 +153,8 @@
#define GDK_KEY_Right GDK_Right
#define GDK_KEY_Tab GDK_Tab
#define GDK_KEY_Up GDK_Up
#define GDK_KEY_greater GDK_greater
#define GDK_KEY_less GDK_less
#endif

View File

@ -91,6 +91,7 @@ struct unifont_vtable {
char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size,
int *flags, int resolve_aliases);
char *(*scale_fontname)(GtkWidget *widget, const char *name, int size);
char *(*size_increment)(unifont *font, int increment);
/*
* `Static data members' of the `class'.
@ -124,6 +125,7 @@ static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
int resolve_aliases);
static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
int size);
static char *x11font_size_increment(unifont *font, int increment);
#ifdef DRAW_TEXT_CAIRO
struct cairo_cached_glyph {
@ -216,6 +218,7 @@ static const struct unifont_vtable x11font_vtable = {
x11font_enum_fonts,
x11font_canonify_fontname,
x11font_scale_fontname,
x11font_size_increment,
"server",
};
@ -236,6 +239,9 @@ static const struct unifont_vtable x11font_vtable = {
S(charset_encoding) \
/* end of list */
/* Special value for int fields that xlfd_recompose will render as "*" */
#define XLFD_INT_WILDCARD INT_MIN
struct xlfd_decomposed {
#define STR_FIELD(f) const char *f;
#define INT_FIELD(f) int f;
@ -289,8 +295,11 @@ static char *xlfd_recompose(const struct xlfd_decomposed *dec)
{
#define FMT_STR(f) "-%s"
#define ARG_STR(f) , dec->f
#define FMT_INT(f) "-%d"
#define ARG_INT(f) , dec->f
#define FMT_INT(f) "%s%.*d"
#define ARG_INT(f) \
, dec->f == XLFD_INT_WILDCARD ? "-*" : "-" \
, dec->f == XLFD_INT_WILDCARD ? 0 : 1 \
, dec->f == XLFD_INT_WILDCARD ? 0 : dec->f
return dupprintf(XLFD_STRING_PARTS_LIST(FMT_STR, FMT_INT)
XLFD_STRING_PARTS_LIST(ARG_STR, ARG_INT));
#undef FMT_STR
@ -1177,6 +1186,89 @@ static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
return NULL; /* shan't */
}
static char *x11font_size_increment(unifont *font, int increment)
{
struct x11font *xfont = (struct x11font *)font;
Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
Atom fontprop = XInternAtom(disp, "FONT", False);
char *returned_name = NULL;
unsigned long ret;
if (XGetFontProperty(xfont->fonts[0].xfs, fontprop, &ret)) {
struct xlfd_decomposed *xlfd;
struct xlfd_decomposed *xlfd_best;
char *wc;
char **fontnames;
int nnames, i, max;
xlfd = xlfd_decompose(XGetAtomName(disp, (Atom)ret));
if (!xlfd)
return NULL;
/*
* Form a wildcard consisting of everything in the
* original XLFD except for the size-related fields.
*/
{
struct xlfd_decomposed xlfd_wc = *xlfd; /* structure copy */
xlfd_wc.pixel_size = XLFD_INT_WILDCARD;
xlfd_wc.point_size = XLFD_INT_WILDCARD;
xlfd_wc.average_width = XLFD_INT_WILDCARD;
wc = xlfd_recompose(&xlfd_wc);
}
/*
* Fetch all the font names matching that wildcard.
*/
max = 32768;
while (1) {
fontnames = XListFonts(disp, wc, max, &nnames);
if (nnames >= max) {
XFreeFontNames(fontnames);
max *= 2;
} else
break;
}
sfree(wc);
/*
* Iterate over those to find the one closest in size to the
* original font, in the correct direction.
*/
#define FLIPPED_SIZE(xlfd) \
(((xlfd)->pixel_size + (xlfd)->point_size) * \
(increment < 0 ? -1 : +1))
xlfd_best = NULL;
for (i = 0; i < nnames; i++) {
struct xlfd_decomposed *xlfd2 = xlfd_decompose(fontnames[i]);
if (!xlfd2)
continue;
if (xlfd2->pixel_size != 0 &&
FLIPPED_SIZE(xlfd2) > FLIPPED_SIZE(xlfd) &&
(!xlfd_best || FLIPPED_SIZE(xlfd2)<FLIPPED_SIZE(xlfd_best))) {
sfree(xlfd_best);
xlfd_best = xlfd2;
xlfd2 = NULL;
}
sfree(xlfd2);
}
#undef FLIPPED_SIZE
if (xlfd_best)
returned_name = xlfd_recompose(xlfd_best);
XFreeFontNames(fontnames);
sfree(xlfd);
sfree(xlfd_best);
}
return returned_name;
}
#endif /* NOT_X_WINDOWS */
#if GTK_CHECK_VERSION(2,0,0)
@ -1211,6 +1303,7 @@ static char *pangofont_canonify_fontname(GtkWidget *widget, const char *name,
int resolve_aliases);
static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
int size);
static char *pangofont_size_increment(unifont *font, int increment);
struct pangofont {
struct unifont u;
@ -1246,6 +1339,7 @@ static const struct unifont_vtable pangofont_vtable = {
pangofont_enum_fonts,
pangofont_canonify_fontname,
pangofont_scale_fontname,
pangofont_size_increment,
"client",
};
@ -1904,6 +1998,31 @@ static char *pangofont_scale_fontname(GtkWidget *widget, const char *name,
return retname;
}
static char *pangofont_size_increment(unifont *font, int increment)
{
struct pangofont *pfont = (struct pangofont *)font;
PangoFontDescription *desc;
int size;
char *newname, *retname;
desc = pango_font_description_copy_static(pfont->desc);
size = pango_font_description_get_size(desc);
size += PANGO_SCALE * increment;
if (size <= 0) {
retname = NULL;
} else {
pango_font_description_set_size(desc, size);
newname = pango_font_description_to_string(desc);
retname = dupstr(newname);
g_free(newname);
}
pango_font_description_free(desc);
return retname;
}
#endif /* GTK_CHECK_VERSION(2,0,0) */
/* ----------------------------------------------------------------------
@ -2010,6 +2129,11 @@ void unifont_draw_combining(unifont_drawctx *ctx, unifont *font,
cellwidth);
}
char *unifont_size_increment(unifont *font, int increment)
{
return font->vt->size_increment(font, increment);
}
/* ----------------------------------------------------------------------
* Multiple-font wrapper. This is a type of unifont which encapsulates
* up to two other unifonts, permitting missing glyphs in the main
@ -2031,6 +2155,7 @@ static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font,
int len, int wide, int bold,
int cellwidth);
static void multifont_destroy(unifont *font);
static char *multifont_size_increment(unifont *font, int increment);
struct multifont {
struct unifont u;
@ -2048,6 +2173,7 @@ static const struct unifont_vtable multifont_vtable = {
NULL,
NULL,
NULL,
multifont_size_increment,
"client",
};
@ -2159,6 +2285,12 @@ static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font,
cellwidth, 0, unifont_draw_combining);
}
static char *multifont_size_increment(unifont *font, int increment)
{
struct multifont *mfont = (struct multifont *)font;
return unifont_size_increment(mfont->main, increment);
}
#if GTK_CHECK_VERSION(2,0,0)
/* ----------------------------------------------------------------------

View File

@ -142,6 +142,9 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
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);
/* Return a name that will select a bigger/smaller font than this one,
* or NULL if no such name is available. */
char *unifont_size_increment(unifont *font, int increment);
/*
* This function behaves exactly like the low-level unifont_create,

View File

@ -638,6 +638,8 @@ char *dup_keyval_name(guint keyval)
}
#endif
static void change_font_size(struct gui_data *inst, int increment);
gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
@ -838,6 +840,23 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
}
}
if (event->keyval == GDK_KEY_greater &&
(event->state & GDK_CONTROL_MASK)) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Ctrl->: increase font size\n"));
#endif
change_font_size(inst, +1);
return TRUE;
}
if (event->keyval == GDK_KEY_less &&
(event->state & GDK_CONTROL_MASK)) {
#ifdef KEY_EVENT_DIAGNOSTICS
debug((" - Ctrl-<: increase font size\n"));
#endif
change_font_size(inst, -1);
return TRUE;
}
/*
* Shift-PgUp and Shift-PgDn don't even generate keystrokes
* at all.
@ -3972,6 +3991,67 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
inst->reconfiguring = FALSE;
}
static void change_font_size(struct gui_data *inst, int increment)
{
static const int conf_keys[lenof(inst->fonts)] = {
CONF_font, CONF_boldfont, CONF_widefont, CONF_wideboldfont,
};
FontSpec *oldfonts[lenof(inst->fonts)];
FontSpec *newfonts[lenof(inst->fonts)];
char *errmsg = NULL;
int i;
for (i = 0; i < lenof(newfonts); i++)
oldfonts[i] = newfonts[i] = NULL;
for (i = 0; i < lenof(inst->fonts); i++) {
if (inst->fonts[i]) {
char *newname = unifont_size_increment(inst->fonts[i], increment);
if (!newname)
goto cleanup;
newfonts[i] = fontspec_new(newname);
sfree(newname);
}
}
for (i = 0; i < lenof(newfonts); i++) {
if (newfonts[i]) {
oldfonts[i] = fontspec_copy(
conf_get_fontspec(inst->conf, conf_keys[i]));
conf_set_fontspec(inst->conf, conf_keys[i], newfonts[i]);
}
}
errmsg = setup_fonts_ucs(inst);
if (errmsg)
goto cleanup;
/* Success, so suppress putting everything back */
for (i = 0; i < lenof(newfonts); i++) {
if (oldfonts[i]) {
fontspec_free(oldfonts[i]);
oldfonts[i] = NULL;
}
}
set_geom_hints(inst);
request_resize(inst, conf_get_int(inst->conf, CONF_width),
conf_get_int(inst->conf, CONF_height));
term_invalidate(inst->term);
gtk_widget_queue_draw(inst->area);
cleanup:
for (i = 0; i < lenof(oldfonts); i++) {
if (oldfonts[i]) {
conf_set_fontspec(inst->conf, conf_keys[i], oldfonts[i]);
fontspec_free(oldfonts[i]);
}
if (newfonts[i])
fontspec_free(newfonts[i]);
}
sfree(errmsg);
}
void dup_session_menuitem(GtkMenuItem *item, gpointer gdata)
{
struct gui_data *inst = (struct gui_data *)gdata;