mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Merge branch 'delay-tiocswinsz-on-interactive-resize'
Closes #283 Closes #301
This commit is contained in:
commit
c1675af103
8 changed files with 169 additions and 26 deletions
|
|
@ -63,6 +63,11 @@
|
|||
* The scrollback search box no longer accepts non-printable characters.
|
||||
* Non-formatting C0 control characters, `BS`, `HT` and `DEL` are now
|
||||
stripped from pasted text.
|
||||
* While doing an interactive resize of a foot window, foot now
|
||||
requires 100ms of idle time (where the window size does not change)
|
||||
before sending the new dimensions to the client application. The
|
||||
timing can be tweaked, or completely disabled, by setting
|
||||
`resize-delay-ms` (https://codeberg.org/dnkl/foot/issues/301).
|
||||
|
||||
|
||||
### Deprecated
|
||||
|
|
|
|||
14
config.c
14
config.c
|
|
@ -523,6 +523,19 @@ parse_section_main(const char *key, const char *value, struct config *conf,
|
|||
conf->center = center;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "resize-delay-ms") == 0) {
|
||||
unsigned long ms;
|
||||
if (!str_to_ulong(value, 10, &ms)) {
|
||||
LOG_AND_NOTIFY_ERR(
|
||||
"%s:%d: [default]: resize-delay-ms: "
|
||||
"expected an integer, got '%s'",
|
||||
path, lineno, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->resize_delay_ms = ms;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "bold-text-in-bright") == 0)
|
||||
conf->bold_in_bright = str_to_bool(value);
|
||||
|
||||
|
|
@ -2080,6 +2093,7 @@ config_load(struct config *conf, const char *conf_path,
|
|||
},
|
||||
.pad_x = 2,
|
||||
.pad_y = 2,
|
||||
.resize_delay_ms = 100,
|
||||
.bold_in_bright = false,
|
||||
.bell_action = BELL_ACTION_NONE,
|
||||
.startup_mode = STARTUP_WINDOWED,
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -77,6 +77,7 @@ struct config {
|
|||
unsigned pad_x;
|
||||
unsigned pad_y;
|
||||
bool center;
|
||||
uint16_t resize_delay_ms;
|
||||
|
||||
bool bold_in_bright;
|
||||
enum {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,25 @@ in this order:
|
|||
|
||||
Default: _2x2_.
|
||||
|
||||
*resize-delay-ms*
|
||||
Time, in milliseconds, of "idle time" "before foot sends the new
|
||||
window dimensions to the client application while doing an
|
||||
interactive resize of a foot window. Idle time in this context is
|
||||
a period of time where the window size is not changing.
|
||||
|
||||
In other words, while you are fiddling with the window size, foot
|
||||
does not send the updated dimensions to the client. Only when you
|
||||
pause the fiddling for *relay-size-ms* milliseconds is the client
|
||||
updated.
|
||||
|
||||
Emphasis is on _while_ here; as soon as the interactive resize
|
||||
ends (i.e. when you let go of the window border), the final
|
||||
dimensions is sent to the client, without any delays.
|
||||
|
||||
Setting it to 0 disables the delay completely.
|
||||
|
||||
Default: _100_.
|
||||
|
||||
*initial-window-size-pixels*
|
||||
Initial window width and height in _pixels_ (subject to output
|
||||
scaling), on the form _WIDTHxHEIGHT_. The height _includes_ the
|
||||
|
|
|
|||
1
foot.ini
1
foot.ini
|
|
@ -18,6 +18,7 @@
|
|||
# initial-window-size-chars=<COLSxROWS>
|
||||
# initial-window-mode=windowed
|
||||
# pad=2x2 # optionally append 'center'
|
||||
# resize-delay-ms=100
|
||||
|
||||
# bold-text-in-bright=no
|
||||
# bell=none
|
||||
|
|
|
|||
101
render.c
101
render.c
|
|
@ -1,10 +1,12 @@
|
|||
#include "render.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <pthread.h>
|
||||
#if __has_include(<pthread_np.h>)
|
||||
#include <pthread_np.h>
|
||||
|
|
@ -2545,6 +2547,89 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da
|
|||
grid_render(term);
|
||||
}
|
||||
|
||||
static void
|
||||
tiocswinsz(struct terminal *term)
|
||||
{
|
||||
if (term->ptmx >= 0) {
|
||||
if (ioctl(term->ptmx, (unsigned int)TIOCSWINSZ,
|
||||
&(struct winsize){
|
||||
.ws_row = term->rows,
|
||||
.ws_col = term->cols,
|
||||
.ws_xpixel = term->cols * term->cell_width,
|
||||
.ws_ypixel = term->rows * term->cell_height}) < 0)
|
||||
{
|
||||
LOG_ERRNO("TIOCSWINSZ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
fdm_tiocswinsz(struct fdm *fdm, int fd, int events, void *data)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
|
||||
if (events & EPOLLIN)
|
||||
tiocswinsz(term);
|
||||
|
||||
fdm_del(fdm, fd);
|
||||
term->window->resize_timeout_fd = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
send_dimensions_to_client(struct terminal *term)
|
||||
{
|
||||
struct wl_window *win = term->window;
|
||||
|
||||
if (!win->is_resizing || term->conf->resize_delay_ms == 0) {
|
||||
/* Send new dimensions to client immediately */
|
||||
tiocswinsz(term);
|
||||
|
||||
/* And make sure to reset and deallocate a lingering timer */
|
||||
if (win->resize_timeout_fd >= 0) {
|
||||
fdm_del(term->fdm, win->resize_timeout_fd);
|
||||
win->resize_timeout_fd = -1;
|
||||
}
|
||||
} else {
|
||||
/* Send new dimensions to client “in a while” */
|
||||
assert(win->is_resizing && term->conf->resize_delay_ms > 0);
|
||||
|
||||
int fd = win->resize_timeout_fd;
|
||||
uint16_t delay_ms = term->conf->resize_delay_ms;
|
||||
bool successfully_scheduled = false;
|
||||
|
||||
if (fd < 0) {
|
||||
/* Lazy create timer fd */
|
||||
fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
if (fd < 0)
|
||||
LOG_ERRNO("failed to create TIOCSWINSZ timer");
|
||||
else if (!fdm_add(term->fdm, fd, EPOLLIN, &fdm_tiocswinsz, term)) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
win->resize_timeout_fd = fd;
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
/* Reset timeout */
|
||||
const struct itimerspec timeout = {
|
||||
.it_value = {.tv_sec = 0, .tv_nsec = delay_ms * 1000000},
|
||||
};
|
||||
|
||||
if (timerfd_settime(fd, 0, &timeout, NULL) < 0) {
|
||||
LOG_ERRNO("failed to arm TIOCSWINSZ timer");
|
||||
fdm_del(term->fdm, fd);
|
||||
win->resize_timeout_fd = -1;
|
||||
} else
|
||||
successfully_scheduled = true;
|
||||
}
|
||||
|
||||
if (!successfully_scheduled)
|
||||
tiocswinsz(term);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move to terminal.c? */
|
||||
static bool
|
||||
maybe_resize(struct terminal *term, int width, int height, bool force)
|
||||
|
|
@ -2671,7 +2756,7 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
const int total_x_pad = term->width - grid_width;
|
||||
const int total_y_pad = term->height - grid_height;
|
||||
|
||||
if (term->conf->center) {
|
||||
if (term->conf->center && !term->window->is_resizing) {
|
||||
term->margins.left = total_x_pad / 2;
|
||||
term->margins.top = total_y_pad / 2;
|
||||
} else {
|
||||
|
|
@ -2723,17 +2808,6 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
term->width, term->height, term->cols, term->rows,
|
||||
term->margins.left, term->margins.right, term->margins.top, term->margins.bottom);
|
||||
|
||||
/* Signal TIOCSWINSZ */
|
||||
if (term->ptmx >= 0 && ioctl(term->ptmx, (unsigned int)TIOCSWINSZ,
|
||||
&(struct winsize){
|
||||
.ws_row = term->rows,
|
||||
.ws_col = term->cols,
|
||||
.ws_xpixel = term->cols * term->cell_width,
|
||||
.ws_ypixel = term->rows * term->cell_height}) == -1)
|
||||
{
|
||||
LOG_ERRNO("TIOCSWINSZ");
|
||||
}
|
||||
|
||||
if (term->scroll_region.start >= term->rows)
|
||||
term->scroll_region.start = 0;
|
||||
|
||||
|
|
@ -2743,6 +2817,9 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
|
|||
term->render.last_cursor.row = NULL;
|
||||
|
||||
damage_view:
|
||||
/* Signal TIOCSWINSZ */
|
||||
send_dimensions_to_client(term);
|
||||
|
||||
if (!term->window->is_maximized &&
|
||||
!term->window->is_fullscreen &&
|
||||
!term->window->is_tiled)
|
||||
|
|
|
|||
36
wayland.c
36
wayland.c
|
|
@ -535,6 +535,7 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
|||
bool is_activated = false;
|
||||
bool is_fullscreen = false;
|
||||
bool is_maximized = false;
|
||||
bool is_resizing = false;
|
||||
bool is_tiled_top = false;
|
||||
bool is_tiled_bottom = false;
|
||||
bool is_tiled_left = false;
|
||||
|
|
@ -566,11 +567,7 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
|||
case XDG_TOPLEVEL_STATE_TILED_RIGHT: is_tiled_right = true; break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP: is_tiled_top = true; break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM: is_tiled_bottom = true; break;
|
||||
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
/* Ignored */
|
||||
/* TODO: throttle? */
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING: is_resizing = true; break;
|
||||
}
|
||||
|
||||
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
||||
|
|
@ -614,6 +611,7 @@ xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
|||
win->configure.is_activated = is_activated;
|
||||
win->configure.is_fullscreen = is_fullscreen;
|
||||
win->configure.is_maximized = is_maximized;
|
||||
win->configure.is_resizing = is_resizing;
|
||||
win->configure.is_tiled_top = is_tiled_top;
|
||||
win->configure.is_tiled_bottom = is_tiled_bottom;
|
||||
win->configure.is_tiled_left = is_tiled_left;
|
||||
|
|
@ -646,8 +644,11 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
|||
struct terminal *term = win->term;
|
||||
|
||||
bool wasnt_configured = !win->is_configured;
|
||||
bool was_resizing = win->is_resizing;
|
||||
|
||||
win->is_configured = true;
|
||||
win->is_maximized = win->configure.is_maximized;
|
||||
win->is_resizing = win->configure.is_resizing;
|
||||
win->is_tiled_top = win->configure.is_tiled_top;
|
||||
win->is_tiled_bottom = win->configure.is_tiled_bottom;
|
||||
win->is_tiled_left = win->configure.is_tiled_left;
|
||||
|
|
@ -676,8 +677,25 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
|||
term->window->frame_callback = NULL;
|
||||
}
|
||||
|
||||
bool resized = render_resize(
|
||||
term, win->configure.width, win->configure.height);
|
||||
#if 1
|
||||
/*
|
||||
* TODO: decide if we should to the last “forced” call when ending
|
||||
* an interactive resize.
|
||||
*
|
||||
* Without it, the last TIOCSWINSZ sent to the client will be a
|
||||
* scheduled one. I.e. there will be a small delay after the user
|
||||
* has *stopped* resizing, and the client application receives the
|
||||
* final size.
|
||||
*
|
||||
* 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, win->configure.width, win->configure.height)
|
||||
: render_resize(term, win->configure.width, win->configure.height);
|
||||
#else
|
||||
bool resized = render_resize(term, win->configure.width, win->configure.height);
|
||||
#endif
|
||||
|
||||
if (win->configure.is_activated)
|
||||
term_visual_focus_in(term);
|
||||
|
|
@ -1276,6 +1294,7 @@ wayl_win_init(struct terminal *term)
|
|||
win->term = term;
|
||||
win->use_csd = CSD_UNKNOWN;
|
||||
win->csd.move_timeout_fd = -1;
|
||||
win->resize_timeout_fd = -1;
|
||||
|
||||
win->surface = wl_compositor_create_surface(wayl->compositor);
|
||||
if (win->surface == NULL) {
|
||||
|
|
@ -1428,6 +1447,9 @@ wayl_win_destroy(struct wl_window *win)
|
|||
wl_surface_destroy(win->surface);
|
||||
|
||||
wayl_roundtrip(win->term->wl);
|
||||
|
||||
if (win->resize_timeout_fd >= 0)
|
||||
fdm_del(win->term->wl->fdm, win->resize_timeout_fd);
|
||||
free(win);
|
||||
}
|
||||
|
||||
|
|
|
|||
18
wayland.h
18
wayland.h
|
|
@ -372,22 +372,26 @@ struct wl_window {
|
|||
bool is_configured;
|
||||
bool is_fullscreen;
|
||||
bool is_maximized;
|
||||
bool is_resizing;
|
||||
bool is_tiled_top;
|
||||
bool is_tiled_bottom;
|
||||
bool is_tiled_left;
|
||||
bool is_tiled_right;
|
||||
bool is_tiled; /* At least one of is_tiled_{top,bottom,left,right} is true */
|
||||
struct {
|
||||
bool is_activated;
|
||||
bool is_fullscreen;
|
||||
bool is_maximized;
|
||||
bool is_tiled_top;
|
||||
bool is_tiled_bottom;
|
||||
bool is_tiled_left;
|
||||
bool is_tiled_right;
|
||||
int width;
|
||||
int height;
|
||||
bool is_activated:1;
|
||||
bool is_fullscreen:1;
|
||||
bool is_maximized:1;
|
||||
bool is_resizing:1;
|
||||
bool is_tiled_top:1;
|
||||
bool is_tiled_bottom:1;
|
||||
bool is_tiled_left:1;
|
||||
bool is_tiled_right:1;
|
||||
} configure;
|
||||
|
||||
int resize_timeout_fd;
|
||||
};
|
||||
|
||||
struct config;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue