feature: add resize-by-cells option to constrain window sizes...

...to multiples of the cell size, and preserve grid size when changing
fonts or display scales in floating windows.
This commit is contained in:
Andrew J. Hesford 2024-01-17 15:00:14 -05:00 committed by Daniel Eklöf
parent e0f3703ae6
commit 21a8d832ce
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 120 additions and 55 deletions

View file

@ -54,6 +54,8 @@
* Unicode input mode now accepts input from the numpad as well,
numlock is ignored.
* A new `resize-by-cells` option, enabled by default, allows the size
of floating windows to be constrained to multiples of the cell size.
### Changed
@ -68,6 +70,8 @@
* Kitty keyboard protocol: updated behavior of modifiers bits during
modifier key events, to match the (new [#6913][kitty-6913]) behavior
in kitty >= 0.32.0 ([#1561][1561]).
* When changing font sizes or display scales in floating windows, the
window will be resized as needed to preserve the same grid size.
[1526]: https://codeberg.org/dnkl/foot/issues/1526
[1528]: https://codeberg.org/dnkl/foot/issues/1528

View file

@ -921,6 +921,9 @@ parse_section_main(struct context *ctx)
else if (streq(key, "resize-delay-ms"))
return value_to_uint16(ctx, 10, &conf->resize_delay_ms);
else if (streq(key, "resize-by-cells"))
return value_to_bool(ctx, &conf->resize_by_cells);
else if (streq(key, "bold-text-in-bright")) {
if (streq(value, "palette-based")) {
conf->bold_in_bright.enabled = true;
@ -2990,6 +2993,7 @@ config_load(struct config *conf, const char *conf_path,
},
.pad_x = 0,
.pad_y = 0,
.resize_by_cells = true,
.resize_delay_ms = 100,
.bold_in_bright = {
.enabled = false,

View file

@ -128,6 +128,9 @@ struct config {
unsigned pad_x;
unsigned pad_y;
bool center;
bool resize_by_cells;
uint16_t resize_delay_ms;
struct {

View file

@ -252,6 +252,21 @@ empty string to be set, but it must be quoted: *KEY=""*)
Default: _100_.
*resize-by-cells*
Boolean.
When set to *yes*, the window size will be constrained to multiples
of the cell size (plus any configured padding). When set to *no*,
the window size will be unconstrained, and padding may be adjusted
as necessary to accommodate window sizes that are not multiples of
the cell size.
This option only applies to floating windows. Sizes of maxmized, tiled
or fullscreen windows will not be constrained to multiples of the cell
size.
Default: _yes_
*initial-window-size-pixels*
Initial window width and height in _pixels_ (subject to output
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the

View file

@ -3912,9 +3912,25 @@ send_dimensions_to_client(struct terminal *term)
}
}
static void
set_size_from_grid(struct terminal *term, int *width, int *height, int cols, int rows)
{
/* Nominal grid dimensions */
*width = cols * term->cell_width;
*height = rows * term->cell_height;
/* Include any configured padding */
*width += 2 * term->conf->pad_x * term->scale;
*height += 2 * term->conf->pad_y * term->scale;
/* Round to multiples of scale */
*width = round(term->scale * round(*width / term->scale));
*height = round(term->scale * round(*height / term->scale));
}
/* Move to terminal.c? */
static bool
maybe_resize(struct terminal *term, int width, int height, bool force)
bool
render_resize(struct terminal *term, int width, int height, uint8_t opts)
{
if (term->shutdown.in_progress)
return false;
@ -3925,21 +3941,29 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
if (term->cell_width == 0 && term->cell_height == 0)
return false;
const bool is_floating =
!term->window->is_maximized &&
!term->window->is_fullscreen &&
!term->window->is_tiled;
/* Convert logical size to physical size */
const float scale = term->scale;
width = round(width * scale);
height = round(height * scale);
/* If the grid should be kept, the size should be overridden */
if (is_floating && (opts & RESIZE_KEEP_GRID)) {
set_size_from_grid(term, &width, &height, term->cols, term->rows);
}
if (width == 0 && height == 0) {
/*
* The compositor is letting us choose the size
*
* If we have a "last" used size - use that. Otherwise, use
* the size from the user configuration.
*/
/* The compositor is letting us choose the size */
if (term->stashed_width != 0 && term->stashed_height != 0) {
/* If a default size is requested, prefer the "last used" size */
width = term->stashed_width;
height = term->stashed_height;
} else {
/* Otherwise, use a user-configured size */
switch (term->conf->size.type) {
case CONF_SIZE_PX:
width = term->conf->size.width;
@ -3959,15 +3983,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
break;
case CONF_SIZE_CELLS:
width = term->conf->size.width * term->cell_width;
height = term->conf->size.height * term->cell_height;
width += 2 * term->conf->pad_x * scale;
height += 2 * term->conf->pad_y * scale;
/* Ensure width/height is a valid multiple of scale */
width = roundf(scale * roundf(width / scale));
height = roundf(scale * roundf(height / scale));
set_size_from_grid(term, &width, &height,
term->conf->size.width, term->conf->size.height);
break;
}
}
@ -3990,8 +4007,25 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
const int pad_x = min(max_pad_x, scale * term->conf->pad_x);
const int pad_y = min(max_pad_y, scale * term->conf->pad_y);
if (!force && width == term->width && height == term->height && scale == term->scale)
if (is_floating &&
(opts & RESIZE_BY_CELLS) &&
term->conf->resize_by_cells)
{
/* If resizing in cell increments, restrict the width and height */
width = ((width - 2 * pad_x) / term->cell_width) * term->cell_width + 2 * pad_x;
width = max(min_width, roundf(scale * roundf(width / scale)));
height = ((height - 2 * pad_y) / term->cell_height) * term->cell_height + 2 * pad_y;
height = max(min_height, roundf(scale * roundf(height / scale)));
}
if (!(opts & RESIZE_FORCE) &&
width == term->width &&
height == term->height &&
scale == term->scale)
{
return false;
}
/* Cancel an application initiated "Synchronized Update" */
term_disable_app_sync_updates(term);
@ -4225,10 +4259,7 @@ damage_view:
/* Signal TIOCSWINSZ */
send_dimensions_to_client(term);
if (!term->window->is_maximized &&
!term->window->is_fullscreen &&
!term->window->is_tiled)
{
if (is_floating) {
/* Stash current size, to enable us to restore it when we're
* being un-maximized/fullscreened/tiled */
term->stashed_width = term->width;
@ -4291,18 +4322,6 @@ damage_view:
return true;
}
bool
render_resize(struct terminal *term, int width, int height)
{
return maybe_resize(term, width, height, false);
}
bool
render_resize_force(struct terminal *term, int width, int height)
{
return maybe_resize(term, width, height, true);
}
static void xcursor_callback(
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
static const struct wl_callback_listener xcursor_listener = {

View file

@ -10,8 +10,15 @@ struct renderer;
struct renderer *render_init(struct fdm *fdm, struct wayland *wayl);
void render_destroy(struct renderer *renderer);
bool render_resize(struct terminal *term, int width, int height);
bool render_resize_force(struct terminal *term, int width, int height);
enum resize_options {
RESIZE_NORMAL = 0,
RESIZE_FORCE = 1 << 0,
RESIZE_BY_CELLS = 1 << 1,
RESIZE_KEEP_GRID = 1 << 2,
};
bool render_resize(
struct terminal *term, int width, int height, uint8_t resize_options);
void render_refresh(struct terminal *term);
void render_refresh_csd(struct terminal *term);

View file

@ -784,10 +784,11 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4],
* render_resize() after this function */
if (resize_grid) {
/* Use force, since cell-width/height may have changed */
render_resize_force(
render_resize(
term,
(int)roundf(term->width / term->scale),
(int)roundf(term->height / term->scale));
(int)roundf(term->height / term->scale),
RESIZE_FORCE | RESIZE_KEEP_GRID);
}
return true;
}

View file

@ -392,8 +392,6 @@ static void
update_term_for_output_change(struct terminal *term)
{
const float old_scale = term->scale;
const float logical_width = term->width / term->scale;
const float logical_height = term->height / term->scale;
/* Note: order matters! term_update_scale() must come first */
bool scale_updated = term_update_scale(term);
@ -402,24 +400,37 @@ update_term_for_output_change(struct terminal *term)
csd_reload_font(term->window, old_scale);
uint8_t resize_opts = RESIZE_KEEP_GRID;
if (fonts_updated) {
/*
* If the fonts have been updated, the cell dimensions have
* changed. This requires a forced resize, since the surface
* buffer dimensions may not have been updated (in which case
* render_size() normally shortcuts and returns early).
* render_resize() normally shortcuts and returns early).
*/
render_resize_force(term, (int)roundf(logical_width), (int)roundf(logical_height));
resize_opts |= RESIZE_FORCE;
} else if (!scale_updated) {
/* No need to resize if neither scale nor fonts have changed */
return;
} else if (term->conf->dpi_aware) {
/*
* If fonts are sized according to DPI, it is possible for the cell
* size to remain the same when display scale changes. This will not
* change the surface buffer dimensions, but will change the logical
* size of the window. To ensure that the compositor is made aware of
* the proper logical size, force a resize rather than allowing
* render_resize() to shortcut the notification if the buffer
* dimensions remain the same.
*/
resize_opts |= RESIZE_FORCE;
}
else if (scale_updated) {
/*
* A scale update means the surface buffer dimensions have
* been updated, even though the window logical dimensions
* havent changed.
*/
render_resize(term, (int)roundf(logical_width), (int)roundf(logical_height));
}
render_resize(
term,
(int)roundf(term->width / term->scale),
(int)roundf(term->height / term->scale),
resize_opts);
}
static void
@ -976,6 +987,8 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
xdg_surface_ack_configure(xdg_surface, serial);
enum resize_options opts = RESIZE_BY_CELLS;
#if 1
/*
* TODO: decide if we should do the last forced call when ending
@ -989,13 +1002,12 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
* Note: if we also disable content centering while resizing, then
* the last, forced, resize *is* necessary.
*/
bool resized = was_resizing && !win->is_resizing
? render_resize_force(term, new_width, new_height)
: render_resize(term, new_width, new_height);
#else
bool resized = render_resize(term, new_width, new_height);
if (was_resizing && !win->is_resizing)
opts |= RESIZE_FORCE;
#endif
bool resized = render_resize(term, new_width, new_height, opts);
if (win->configure.is_activated)
term_visual_focus_in(term);
else