mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
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:
parent
e0f3703ae6
commit
21a8d832ce
8 changed files with 120 additions and 55 deletions
|
|
@ -54,6 +54,8 @@
|
||||||
|
|
||||||
* Unicode input mode now accepts input from the numpad as well,
|
* Unicode input mode now accepts input from the numpad as well,
|
||||||
numlock is ignored.
|
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
|
### Changed
|
||||||
|
|
@ -68,6 +70,8 @@
|
||||||
* Kitty keyboard protocol: updated behavior of modifiers bits during
|
* Kitty keyboard protocol: updated behavior of modifiers bits during
|
||||||
modifier key events, to match the (new [#6913][kitty-6913]) behavior
|
modifier key events, to match the (new [#6913][kitty-6913]) behavior
|
||||||
in kitty >= 0.32.0 ([#1561][1561]).
|
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
|
[1526]: https://codeberg.org/dnkl/foot/issues/1526
|
||||||
[1528]: https://codeberg.org/dnkl/foot/issues/1528
|
[1528]: https://codeberg.org/dnkl/foot/issues/1528
|
||||||
|
|
|
||||||
4
config.c
4
config.c
|
|
@ -921,6 +921,9 @@ parse_section_main(struct context *ctx)
|
||||||
else if (streq(key, "resize-delay-ms"))
|
else if (streq(key, "resize-delay-ms"))
|
||||||
return value_to_uint16(ctx, 10, &conf->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")) {
|
else if (streq(key, "bold-text-in-bright")) {
|
||||||
if (streq(value, "palette-based")) {
|
if (streq(value, "palette-based")) {
|
||||||
conf->bold_in_bright.enabled = true;
|
conf->bold_in_bright.enabled = true;
|
||||||
|
|
@ -2990,6 +2993,7 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
},
|
},
|
||||||
.pad_x = 0,
|
.pad_x = 0,
|
||||||
.pad_y = 0,
|
.pad_y = 0,
|
||||||
|
.resize_by_cells = true,
|
||||||
.resize_delay_ms = 100,
|
.resize_delay_ms = 100,
|
||||||
.bold_in_bright = {
|
.bold_in_bright = {
|
||||||
.enabled = false,
|
.enabled = false,
|
||||||
|
|
|
||||||
3
config.h
3
config.h
|
|
@ -128,6 +128,9 @@ struct config {
|
||||||
unsigned pad_x;
|
unsigned pad_x;
|
||||||
unsigned pad_y;
|
unsigned pad_y;
|
||||||
bool center;
|
bool center;
|
||||||
|
|
||||||
|
bool resize_by_cells;
|
||||||
|
|
||||||
uint16_t resize_delay_ms;
|
uint16_t resize_delay_ms;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,21 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
||||||
|
|
||||||
Default: _100_.
|
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-size-pixels*
|
||||||
Initial window width and height in _pixels_ (subject to output
|
Initial window width and height in _pixels_ (subject to output
|
||||||
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the
|
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the
|
||||||
|
|
|
||||||
87
render.c
87
render.c
|
|
@ -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? */
|
/* Move to terminal.c? */
|
||||||
static bool
|
bool
|
||||||
maybe_resize(struct terminal *term, int width, int height, bool force)
|
render_resize(struct terminal *term, int width, int height, uint8_t opts)
|
||||||
{
|
{
|
||||||
if (term->shutdown.in_progress)
|
if (term->shutdown.in_progress)
|
||||||
return false;
|
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)
|
if (term->cell_width == 0 && term->cell_height == 0)
|
||||||
return false;
|
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;
|
const float scale = term->scale;
|
||||||
width = round(width * scale);
|
width = round(width * scale);
|
||||||
height = round(height * 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) {
|
if (width == 0 && height == 0) {
|
||||||
/*
|
/* The compositor is letting us choose the size */
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
if (term->stashed_width != 0 && term->stashed_height != 0) {
|
if (term->stashed_width != 0 && term->stashed_height != 0) {
|
||||||
|
/* If a default size is requested, prefer the "last used" size */
|
||||||
width = term->stashed_width;
|
width = term->stashed_width;
|
||||||
height = term->stashed_height;
|
height = term->stashed_height;
|
||||||
} else {
|
} else {
|
||||||
|
/* Otherwise, use a user-configured size */
|
||||||
switch (term->conf->size.type) {
|
switch (term->conf->size.type) {
|
||||||
case CONF_SIZE_PX:
|
case CONF_SIZE_PX:
|
||||||
width = term->conf->size.width;
|
width = term->conf->size.width;
|
||||||
|
|
@ -3959,15 +3983,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONF_SIZE_CELLS:
|
case CONF_SIZE_CELLS:
|
||||||
width = term->conf->size.width * term->cell_width;
|
set_size_from_grid(term, &width, &height,
|
||||||
height = term->conf->size.height * term->cell_height;
|
term->conf->size.width, term->conf->size.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));
|
|
||||||
break;
|
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_x = min(max_pad_x, scale * term->conf->pad_x);
|
||||||
const int pad_y = min(max_pad_y, scale * term->conf->pad_y);
|
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;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cancel an application initiated "Synchronized Update" */
|
/* Cancel an application initiated "Synchronized Update" */
|
||||||
term_disable_app_sync_updates(term);
|
term_disable_app_sync_updates(term);
|
||||||
|
|
@ -4225,10 +4259,7 @@ damage_view:
|
||||||
/* Signal TIOCSWINSZ */
|
/* Signal TIOCSWINSZ */
|
||||||
send_dimensions_to_client(term);
|
send_dimensions_to_client(term);
|
||||||
|
|
||||||
if (!term->window->is_maximized &&
|
if (is_floating) {
|
||||||
!term->window->is_fullscreen &&
|
|
||||||
!term->window->is_tiled)
|
|
||||||
{
|
|
||||||
/* Stash current size, to enable us to restore it when we're
|
/* Stash current size, to enable us to restore it when we're
|
||||||
* being un-maximized/fullscreened/tiled */
|
* being un-maximized/fullscreened/tiled */
|
||||||
term->stashed_width = term->width;
|
term->stashed_width = term->width;
|
||||||
|
|
@ -4291,18 +4322,6 @@ damage_view:
|
||||||
return true;
|
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(
|
static void xcursor_callback(
|
||||||
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
|
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
|
||||||
static const struct wl_callback_listener xcursor_listener = {
|
static const struct wl_callback_listener xcursor_listener = {
|
||||||
|
|
|
||||||
11
render.h
11
render.h
|
|
@ -10,8 +10,15 @@ struct renderer;
|
||||||
struct renderer *render_init(struct fdm *fdm, struct wayland *wayl);
|
struct renderer *render_init(struct fdm *fdm, struct wayland *wayl);
|
||||||
void render_destroy(struct renderer *renderer);
|
void render_destroy(struct renderer *renderer);
|
||||||
|
|
||||||
bool render_resize(struct terminal *term, int width, int height);
|
enum resize_options {
|
||||||
bool render_resize_force(struct terminal *term, int width, int height);
|
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(struct terminal *term);
|
||||||
void render_refresh_csd(struct terminal *term);
|
void render_refresh_csd(struct terminal *term);
|
||||||
|
|
|
||||||
|
|
@ -784,10 +784,11 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4],
|
||||||
* render_resize() after this function */
|
* render_resize() after this function */
|
||||||
if (resize_grid) {
|
if (resize_grid) {
|
||||||
/* Use force, since cell-width/height may have changed */
|
/* Use force, since cell-width/height may have changed */
|
||||||
render_resize_force(
|
render_resize(
|
||||||
term,
|
term,
|
||||||
(int)roundf(term->width / term->scale),
|
(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
wayland.c
46
wayland.c
|
|
@ -392,8 +392,6 @@ static void
|
||||||
update_term_for_output_change(struct terminal *term)
|
update_term_for_output_change(struct terminal *term)
|
||||||
{
|
{
|
||||||
const float old_scale = term->scale;
|
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 */
|
/* Note: order matters! term_update_scale() must come first */
|
||||||
bool scale_updated = term_update_scale(term);
|
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);
|
csd_reload_font(term->window, old_scale);
|
||||||
|
|
||||||
|
uint8_t resize_opts = RESIZE_KEEP_GRID;
|
||||||
|
|
||||||
if (fonts_updated) {
|
if (fonts_updated) {
|
||||||
/*
|
/*
|
||||||
* If the fonts have been updated, the cell dimensions have
|
* If the fonts have been updated, the cell dimensions have
|
||||||
* changed. This requires a “forced” resize, since the surface
|
* changed. This requires a “forced” resize, since the surface
|
||||||
* buffer dimensions may not have been updated (in which case
|
* 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) {
|
render_resize(
|
||||||
/*
|
term,
|
||||||
* A scale update means the surface buffer dimensions have
|
(int)roundf(term->width / term->scale),
|
||||||
* been updated, even though the window logical dimensions
|
(int)roundf(term->height / term->scale),
|
||||||
* haven’t changed.
|
resize_opts);
|
||||||
*/
|
|
||||||
render_resize(term, (int)roundf(logical_width), (int)roundf(logical_height));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -976,6 +987,8 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
||||||
|
|
||||||
xdg_surface_ack_configure(xdg_surface, serial);
|
xdg_surface_ack_configure(xdg_surface, serial);
|
||||||
|
|
||||||
|
enum resize_options opts = RESIZE_BY_CELLS;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
/*
|
/*
|
||||||
* TODO: decide if we should do the last “forced” call when ending
|
* 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
|
* Note: if we also disable content centering while resizing, then
|
||||||
* the last, forced, resize *is* necessary.
|
* the last, forced, resize *is* necessary.
|
||||||
*/
|
*/
|
||||||
bool resized = was_resizing && !win->is_resizing
|
if (was_resizing && !win->is_resizing)
|
||||||
? render_resize_force(term, new_width, new_height)
|
opts |= RESIZE_FORCE;
|
||||||
: render_resize(term, new_width, new_height);
|
|
||||||
#else
|
|
||||||
bool resized = render_resize(term, new_width, new_height);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool resized = render_resize(term, new_width, new_height, opts);
|
||||||
|
|
||||||
if (win->configure.is_activated)
|
if (win->configure.is_activated)
|
||||||
term_visual_focus_in(term);
|
term_visual_focus_in(term);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue