GUACAMOLE-630: Separate setting of font family/size from terminal display initialization.

This commit is contained in:
Michael Jumper 2018-10-07 23:38:03 -07:00
parent 0cf24219d8
commit 9e28de70ec
4 changed files with 190 additions and 37 deletions

View File

@ -206,15 +206,15 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
guac_terminal_color* foreground, guac_terminal_color* background, guac_terminal_color* foreground, guac_terminal_color* background,
guac_terminal_color (*palette)[256]) { guac_terminal_color (*palette)[256]) {
PangoFontMap* font_map;
PangoFont* font;
PangoFontMetrics* metrics;
PangoContext* context;
/* Allocate display */ /* Allocate display */
guac_terminal_display* display = malloc(sizeof(guac_terminal_display)); guac_terminal_display* display = malloc(sizeof(guac_terminal_display));
display->client = client; display->client = client;
/* Initially no font loaded */
display->font_desc = NULL;
display->char_width = 0;
display->char_height = 0;
/* Create default surface */ /* Create default surface */
display->display_layer = guac_client_alloc_layer(client); display->display_layer = guac_client_alloc_layer(client);
display->select_layer = guac_client_alloc_layer(client); display->select_layer = guac_client_alloc_layer(client);
@ -225,42 +225,10 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
guac_protocol_send_move(client->socket, display->select_layer, guac_protocol_send_move(client->socket, display->select_layer,
display->display_layer, 0, 0, 0); display->display_layer, 0, 0, 0);
/* Get font */
display->font_desc = pango_font_description_new();
pango_font_description_set_family(display->font_desc, font_name);
pango_font_description_set_weight(display->font_desc, PANGO_WEIGHT_NORMAL);
pango_font_description_set_size(display->font_desc,
font_size * PANGO_SCALE * dpi / 96);
font_map = pango_cairo_font_map_get_default();
context = pango_font_map_create_context(font_map);
font = pango_font_map_load_font(font_map, context, display->font_desc);
if (font == NULL) {
guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to get font \"%s\"", font_name);
free(display);
return NULL;
}
metrics = pango_font_get_metrics(font, NULL);
if (metrics == NULL) {
guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to get font metrics for font \"%s\"", font_name);
free(display);
return NULL;
}
display->default_foreground = display->glyph_foreground = *foreground; display->default_foreground = display->glyph_foreground = *foreground;
display->default_background = display->glyph_background = *background; display->default_background = display->glyph_background = *background;
display->default_palette = palette; display->default_palette = palette;
/* Calculate character dimensions */
display->char_width =
pango_font_metrics_get_approximate_digit_width(metrics) / PANGO_SCALE;
display->char_height =
(pango_font_metrics_get_descent(metrics)
+ pango_font_metrics_get_ascent(metrics)) / PANGO_SCALE;
/* Initially empty */ /* Initially empty */
display->width = 0; display->width = 0;
display->height = 0; display->height = 0;
@ -269,12 +237,23 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
/* Initially nothing selected */ /* Initially nothing selected */
display->text_selected = false; display->text_selected = false;
/* Attempt to load font */
if (guac_terminal_display_set_font(display, font_name, font_size, dpi)) {
guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to set initial font \"%s\"", font_name);
free(display);
return NULL;
}
return display; return display;
} }
void guac_terminal_display_free(guac_terminal_display* display) { void guac_terminal_display_free(guac_terminal_display* display) {
/* Free font description */
pango_font_description_free(display->font_desc);
/* Free default palette. */ /* Free default palette. */
free(display->default_palette); free(display->default_palette);
@ -966,4 +945,78 @@ void guac_terminal_display_clear_select(guac_terminal_display* display) {
} }
int guac_terminal_display_set_font(guac_terminal_display* display,
const char* font_name, int font_size, int dpi) {
PangoFontDescription* font_desc;
/* Build off existing font description if possible */
if (display->font_desc != NULL)
font_desc = pango_font_description_copy(display->font_desc);
/* Create new font description if there is nothing to copy */
else {
font_desc = pango_font_description_new();
pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
}
/* Optionally update font name */
if (font_name != NULL)
pango_font_description_set_family(font_desc, font_name);
/* Optionally update size */
if (font_size != -1) {
pango_font_description_set_size(font_desc,
font_size * PANGO_SCALE * dpi / 96);
}
PangoFontMap* font_map = pango_cairo_font_map_get_default();
PangoContext* context = pango_font_map_create_context(font_map);
/* Load font from font map */
PangoFont* font = pango_font_map_load_font(font_map, context, font_desc);
if (font == NULL) {
guac_client_log(display->client, GUAC_LOG_INFO, "Unable to load "
"font \"%s\"", pango_font_description_get_family(font_desc));
pango_font_description_free(font_desc);
return 1;
}
/* Get metrics from loaded font */
PangoFontMetrics* metrics = pango_font_get_metrics(font, NULL);
if (metrics == NULL) {
guac_client_log(display->client, GUAC_LOG_INFO, "Unable to get font "
"metrics for font \"%s\"",
pango_font_description_get_family(font_desc));
pango_font_description_free(font_desc);
return 1;
}
/* Save effective size of current display */
int pixel_width = display->width * display->char_width;
int pixel_height = display->height * display->char_height;
/* Calculate character dimensions using metrics */
display->char_width =
pango_font_metrics_get_approximate_digit_width(metrics) / PANGO_SCALE;
display->char_height =
(pango_font_metrics_get_descent(metrics)
+ pango_font_metrics_get_ascent(metrics)) / PANGO_SCALE;
/* Atomically replace old font description */
PangoFontDescription* old_font_desc = display->font_desc;
display->font_desc = font_desc;
pango_font_description_free(old_font_desc);
/* Recalculate dimensions which will fit within current surface */
int new_width = pixel_width / display->char_width;
int new_height = pixel_height / display->char_height;
/* Resize display if dimensions have changed */
if (new_width != display->width || new_height != display->height)
guac_terminal_display_resize(display, new_width, new_height);
return 0;
}

View File

@ -360,6 +360,10 @@ guac_terminal* guac_terminal_create(guac_client* client,
term->upload_path_handler = NULL; term->upload_path_handler = NULL;
term->file_download_handler = NULL; term->file_download_handler = NULL;
/* Set size of available screen area */
term->outer_width = width;
term->outer_height = height;
/* Init modified flag and conditional */ /* Init modified flag and conditional */
term->modified = 0; term->modified = 0;
pthread_cond_init(&(term->modified_cond), NULL); pthread_cond_init(&(term->modified_cond), NULL);
@ -1338,6 +1342,10 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) {
/* Acquire exclusive access to terminal */ /* Acquire exclusive access to terminal */
guac_terminal_lock(terminal); guac_terminal_lock(terminal);
/* Set size of available screen area */
terminal->outer_width = width;
terminal->outer_height = height;
/* Calculate available display area */ /* Calculate available display area */
int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH; int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH;
if (available_width < 0) if (available_width < 0)
@ -1968,3 +1976,27 @@ void guac_terminal_apply_color_scheme(guac_terminal* terminal,
} }
void guac_terminal_apply_font(guac_terminal* terminal, const char* font_name,
int font_size, int dpi) {
guac_client* client = terminal->client;
guac_terminal_display* display = terminal->display;
if (guac_terminal_display_set_font(display, font_name, font_size, dpi))
return;
/* Resize terminal to fit available region, now that font metrics may be
* different */
guac_terminal_resize(terminal, terminal->outer_width,
terminal->outer_height);
/* Redraw terminal text and background */
guac_terminal_repaint_default_layer(terminal, client->socket);
__guac_terminal_redraw_rect(terminal, 0, 0,
terminal->term_height - 1,
terminal->term_width - 1);
guac_terminal_notify(terminal);
}

View File

@ -334,5 +334,35 @@ void guac_terminal_display_select(guac_terminal_display* display,
*/ */
void guac_terminal_display_clear_select(guac_terminal_display* display); void guac_terminal_display_clear_select(guac_terminal_display* display);
/**
* Alters the font of the terminal display. The available display area and the
* regular grid of character cells will be resized as necessary to compensate
* for any changes in font metrics.
*
* If successful, the terminal itself MUST be manually resized to take into
* account the new character dimensions, and MUST be manually redrawn. Failing
* to do so will result in graphical artifacts.
*
* @param display
* The display whose font family and/or size are being changed.
*
* @param font_name
* The name of the new font family, or NULL if the font family should
* remain unchanged.
*
* @param font_size
* The new font size, in points, or -1 if the font size should remain
* unchanged.
*
* @param dpi
* The resolution of the display in DPI. If the font size will not be
* changed (the font size given is -1), this value is ignored.
*
* @return
* Zero if the font was successfully changed, non-zero otherwise.
*/
int guac_terminal_display_set_font(guac_terminal_display* display,
const char* font_name, int font_size, int dpi);
#endif #endif

View File

@ -277,6 +277,20 @@ struct guac_terminal {
*/ */
int requested_scrollback; int requested_scrollback;
/**
* The width of the space available to all components of the terminal, in
* pixels. This may include space which will not actually be used for
* character rendering.
*/
int outer_width;
/**
* The height of the space available to all components of the terminal, in
* pixels. This may include space which will not actually be used for
* character rendering.
*/
int outer_height;
/** /**
* The width of the terminal, in pixels. * The width of the terminal, in pixels.
*/ */
@ -1086,5 +1100,29 @@ int guac_terminal_available_scroll(guac_terminal* term);
void guac_terminal_apply_color_scheme(guac_terminal* terminal, void guac_terminal_apply_color_scheme(guac_terminal* terminal,
const char* color_scheme); const char* color_scheme);
/**
* Alters the font of the terminal. The terminal will automatically be redrawn
* and resized as necessary. If the terminal size changes, the remote side of
* the terminal session must be manually informed of that change or graphical
* artifacts may result.
*
* @param terminal
* The terminal whose font family and/or size are being changed.
*
* @param font_name
* The name of the new font family, or NULL if the font family should
* remain unchanged.
*
* @param font_size
* The new font size, in points, or -1 if the font size should remain
* unchanged.
*
* @param dpi
* The resolution of the display in DPI. If the font size will not be
* changed (the font size given is -1), this value is ignored.
*/
void guac_terminal_apply_font(guac_terminal* terminal, const char* font_name,
int font_size, int dpi);
#endif #endif