diff --git a/terminal.c b/terminal.c index bec0ce7b..89c18c75 100644 --- a/terminal.c +++ b/terminal.c @@ -507,8 +507,54 @@ initialize_render_workers(struct terminal *term) } static bool -initialize_fonts(const struct terminal *term, const struct config *conf, - struct font *fonts[static 4]) +term_set_fonts(struct terminal *term, struct font *fonts[static 4]) +{ + for (size_t i = 0; i < 4; i++) { + assert(fonts[i] != NULL); + + font_destroy(term->fonts[i]); + term->fonts[i] = fonts[i]; + } + + term->cell_width = term->fonts[0]->space_x_advance > 0 + ? term->fonts[0]->space_x_advance : term->fonts[0]->max_x_advance; + term->cell_height = term->fonts[0]->height; + LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height); + + render_resize_force(term, term->width, term->height); + return true; +} + +static unsigned +get_font_dpi(const struct terminal *term) +{ + /* Use highest DPI from outputs we're mapped on */ + unsigned dpi = 0; + assert(term->window != NULL); + tll_foreach(term->window->on_outputs, it) { + if (it->item->y_ppi > dpi) + dpi = it->item->y_ppi; + } + + /* If we're not mapped, use DPI from first monitor. Hopefully this is where we'll get mapped later... */ + if (dpi == 0) { + tll_foreach(term->wl->monitors, it) { + dpi = it->item.y_ppi; + break; + } + } + + if (dpi == 0) { + /* No monitors? */ + dpi = 96; + } + + return dpi; +} + +static bool +load_fonts_from_conf(const struct terminal *term, const struct config *conf, + struct font *fonts[static 4]) { const size_t count = tll_length(conf->fonts); const char *names[count]; @@ -517,18 +563,11 @@ initialize_fonts(const struct terminal *term, const struct config *conf, tll_foreach(conf->fonts, it) names[i++] = it->item; - /* Use highest DPI available */ - unsigned dpi = 96; - tll_foreach(term->wl->monitors, it) { - if (it->item.y_ppi > dpi) - dpi = it->item.y_ppi; - } - char attrs0[64], attrs1[64], attrs2[64], attrs3[64]; - snprintf(attrs0, sizeof(attrs0), "dpi=%u", dpi); - snprintf(attrs1, sizeof(attrs1), "dpi=%u:weight=bold", dpi); - snprintf(attrs2, sizeof(attrs2), "dpi=%u:slant=italic", dpi); - snprintf(attrs3, sizeof(attrs3), "dpi=%u:weight=bold:slant=italic", dpi); + snprintf(attrs0, sizeof(attrs0), "dpi=%u", term->font_dpi); + snprintf(attrs1, sizeof(attrs1), "dpi=%u:weight=bold", term->font_dpi); + snprintf(attrs2, sizeof(attrs2), "dpi=%u:slant=italic", term->font_dpi); + snprintf(attrs3, sizeof(attrs3), "dpi=%u:weight=bold:slant=italic", term->font_dpi); fonts[0] = fonts[1] = fonts[2] = fonts[3] = NULL; bool ret = @@ -619,6 +658,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .quit = false, .ptmx = ptmx, .ptmx_buffer = tll_init(), + .font_dpi = 0, + .font_adjustments = 0, .cursor_keys_mode = CURSOR_KEYS_NORMAL, .keypad_keys_mode = KEYPAD_NUMERICAL, .auto_margin = true, @@ -706,21 +747,16 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .cwd = strdup(cwd), }; + /* Guess scale; we're not mapped yet, so we don't know on which + * output we'll be. Pick highest scale we find for now */ + tll_foreach(term->wl->monitors, it) { + if (it->item.scale > term->scale) + term->scale = it->item.scale; + } + initialize_color_cube(term); if (!initialize_render_workers(term)) goto err; - if (!initialize_fonts(term, conf, term->fonts)) - goto err; - - /* Cell dimensions are based on the font metrics. Obviously */ - term->cell_width = term->fonts[0]->space_x_advance > 0 - ? term->fonts[0]->space_x_advance : term->fonts[0]->max_x_advance; - term->cell_height = term->fonts[0]->height; - LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height); - - /* Start the slave/client */ - if ((term->slave = slave_spawn(term->ptmx, argc, term->cwd, argv, term_env, conf->shell)) == -1) - goto err; /* Initialize the Wayland window backend */ if ((term->window = wayl_win_init(term)) == NULL) @@ -729,9 +765,21 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, /* Let the Wayland backend know we exist */ tll_push_back(wayl->terms, term); wayl_roundtrip(term->wl); - term_set_window_title(term, "foot"); + /* Load fonts */ +#if 0 + struct font *fonts[4]; + if (!load_fonts_from_conf(term, conf, fonts)) + goto err; + term_set_fonts(term, fonts); +#endif + term_font_dpi_changed(term); + + /* Start the slave/client */ + if ((term->slave = slave_spawn(term->ptmx, argc, term->cwd, argv, term_env, conf->shell)) == -1) + goto err; + if (term->width == 0 && term->height == 0) { /* Try to use user-configured window dimentions */ @@ -1112,25 +1160,7 @@ term_reset(struct terminal *term, bool hard) term_damage_all(term); } -static void -term_set_fonts(struct terminal *term, struct font *fonts[static 4]) -{ - for (size_t i = 0; i < 4; i++) { - assert(fonts[i] != NULL); - - font_destroy(term->fonts[i]); - term->fonts[i] = fonts[i]; - } - - term->cell_width = term->fonts[0]->space_x_advance > 0 - ? term->fonts[0]->space_x_advance : term->fonts[0]->max_x_advance; - term->cell_height = term->fonts[0]->height; - LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height); - - render_resize_force(term, term->width, term->height); -} - -static void +static bool term_font_size_adjust(struct terminal *term, double amount) { struct font *fonts[4] = { @@ -1145,32 +1175,90 @@ term_font_size_adjust(struct terminal *term, double amount) { for (size_t i = 0; i < 4; i++) font_destroy(fonts[i]); - return; + return false; } term_set_fonts(term, fonts); + return true; } -void +bool term_font_size_increase(struct terminal *term) { - term_font_size_adjust(term, 0.5); + if (!term_font_size_adjust(term, 0.5)) + return false; + + term->font_adjustments++; + return true; } -void +bool term_font_size_decrease(struct terminal *term) { - term_font_size_adjust(term, -0.5); + if (!term_font_size_adjust(term, -0.5)) + return false; + + term->font_adjustments--; + return true; } -void +bool term_font_size_reset(struct terminal *term) { struct font *fonts[4]; - if (!initialize_fonts(term, term->conf, fonts)) - return; + if (!load_fonts_from_conf(term, term->conf, fonts)) + return false; term_set_fonts(term, fonts); + term->font_adjustments = 0; + return true; +} + +bool +term_font_dpi_changed(struct terminal *term) +{ + unsigned dpi = get_font_dpi(term); + if (dpi == term->font_dpi) + return true; + + LOG_DBG("DPI changed (%u -> %u): reloading fonts", term->font_dpi, dpi); + term->font_dpi = dpi; + + struct font *fonts[4]; + if (!load_fonts_from_conf(term, term->conf, fonts)) + return false; + + if (term->font_adjustments == 0) + return term_set_fonts(term, fonts); + + /* User has adjusted the font size run-time, re-apply */ + + double amount = term->font_adjustments * 0.5; + + struct font *adjusted_fonts[4] = { + font_size_adjust(fonts[0], amount), + font_size_adjust(fonts[1], amount), + font_size_adjust(fonts[2], amount), + font_size_adjust(fonts[3], amount), + }; + + if (adjusted_fonts[0] == NULL || adjusted_fonts[1] == NULL || + adjusted_fonts[2] == NULL || adjusted_fonts[3] == NULL) + { + for (size_t i = 0; i < 4; i++) + font_destroy(adjusted_fonts[i]); + + /* At least use the newly re-loaded default fonts */ + term->font_adjustments = 0; + return term_set_fonts(term, fonts); + } else { + for (size_t i = 0; i < 4; i++) + font_destroy(fonts[i]); + return term_set_fonts(term, adjusted_fonts); + } + + assert(false); + return false; } void diff --git a/terminal.h b/terminal.h index 1d19c9d7..d400dca5 100644 --- a/terminal.h +++ b/terminal.h @@ -187,6 +187,8 @@ struct terminal { struct grid *grid; struct font *fonts[4]; + int font_dpi; + int font_adjustments; tll(struct ptmx_buffer) ptmx_buffer; @@ -364,9 +366,10 @@ int term_destroy(struct terminal *term); void term_reset(struct terminal *term, bool hard); bool term_to_slave(struct terminal *term, const void *data, size_t len); -void term_font_size_increase(struct terminal *term); -void term_font_size_decrease(struct terminal *term); -void term_font_size_reset(struct terminal *term); +bool term_font_size_increase(struct terminal *term); +bool term_font_size_decrease(struct terminal *term); +bool term_font_size_reset(struct terminal *term); +bool term_font_dpi_changed(struct terminal *term); void term_damage_rows(struct terminal *term, int start, int end); void term_damage_rows_in_view(struct terminal *term, int start, int end); diff --git a/wayland.c b/wayland.c index 8a9b8012..8528f987 100644 --- a/wayland.c +++ b/wayland.c @@ -95,6 +95,31 @@ static const struct wl_seat_listener seat_listener = { .name = seat_handle_name, }; +static void +update_term_for_output_change(struct terminal *term) +{ + render_resize(term, term->width / term->scale, term->height / term->scale); + term_font_dpi_changed(term); + wayl_reload_cursor_theme(term->wl, term); +} + +static void +update_terms_on_monitor(struct monitor *mon) +{ + struct wayland *wayl = mon->wayl; + + tll_foreach(wayl->terms, it) { + struct terminal *term = it->item; + + tll_foreach(term->window->on_outputs, it2) { + if (it2->item == mon) { + update_term_for_output_change(term); + break; + } + } + } +} + static void output_update_ppi(struct monitor *mon) { @@ -128,27 +153,22 @@ output_mode(void *data, struct wl_output *wl_output, uint32_t flags, struct monitor *mon = data; mon->refresh = (float)refresh / 1000; + mon->width_px = width; + mon->height_px = height; } static void output_done(void *data, struct wl_output *wl_output) { + struct monitor *mon = data; + update_terms_on_monitor(mon); } static void output_scale(void *data, struct wl_output *wl_output, int32_t factor) { struct monitor *mon = data; - mon->scale = factor; - - tll_foreach(mon->wayl->terms, it) { - struct terminal *term = it->item; - int scale = term->scale; - - render_resize(term, term->width / scale, term->height / scale); - wayl_reload_cursor_theme(mon->wayl, term); - } } static const struct wl_output_listener output_listener = { @@ -171,10 +191,6 @@ static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) { - struct monitor *mon = data; - mon->width_px = width; - mon->height_px = height; - output_update_ppi(mon); } static void @@ -370,11 +386,7 @@ surface_enter(void *data, struct wl_surface *wl_surface, if (it->item.output == wl_output) { LOG_DBG("mapped on %s", it->item.name); tll_push_back(term->window->on_outputs, &it->item); - - /* Resize, since scale-to-use may have changed */ - int scale = term->scale; - render_resize(term, term->width / scale, term->height / scale); - wayl_reload_cursor_theme(term->wl, term); + update_term_for_output_change(term); return; } } @@ -395,11 +407,7 @@ surface_leave(void *data, struct wl_surface *wl_surface, LOG_DBG("unmapped from %s", it->item->name); tll_remove(term->window->on_outputs, it); - - /* Resize, since scale-to-use may have changed */ - int scale = term->scale; - render_resize(term, term->width / scale, term->height / scale); - wayl_reload_cursor_theme(term->wl, term); + update_term_for_output_change(term); return; }