render: delay TIOCSWINSZ while doing an interactive resize

Instead of disabling content centering, delay the TIOCSWINSZ (a.k.a
delay sending the new dimensions to the client) by a small amount
while doing an interactive resize.

Non-interactive resizes are still immediate.

For now, force a resize when the user stops the interactive
resize. This ensures the client application receives the new
dimensions immediately.

It still works without the last, forced, resize, but there typically
be a small delay until the client application receives the final
dimensions.

Closes #301
Closes #283
This commit is contained in:
Daniel Eklöf 2021-01-17 16:12:54 +01:00
parent 6876ab6bc2
commit 9a1df7bb03
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 126 additions and 12 deletions

View file

@ -1745,6 +1745,19 @@ parse_section_tweak(
conf->tweak.box_drawing_base_thickness);
}
else if (strcmp(key, "resize-delay-ms") == 0) {
unsigned long ms;
if (!str_to_ulong(value, 10, &ms)) {
LOG_AND_NOTIFY_ERR(
"%s:%d: [tweak]: resize-delay-ms: expected an integer, got '%s'",
path, lineno, value);
return false;
}
conf->tweak.resize_delay_ms = ms;
LOG_WARN("tweak: resize-delay-ms=%hu", conf->tweak.resize_delay_ms);
}
else {
LOG_AND_NOTIFY_ERR("%s:%u: [tweak]: %s: invalid key", path, lineno, key);
return false;
@ -2166,6 +2179,7 @@ config_load(struct config *conf, const char *conf_path,
.render_timer_log = false,
.damage_whole_window = false,
.box_drawing_base_thickness = 0.04,
.resize_delay_ms = 100,
},
.notifications = tll_init(),

View file

@ -203,6 +203,7 @@ struct config {
uint64_t delayed_render_upper_ns;
off_t max_shm_pool_size;
float box_drawing_base_thickness;
uint16_t resize_delay_ms;
} tweak;
user_notifications_t notifications;

104
render.c
View file

@ -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,92 @@ 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);
LOG_WARN("DELAYED");
}
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->tweak.resize_delay_ms == 0) {
/* Send new dimensions to client immediately */
tiocswinsz(term);
LOG_ERR("IMMEDIATELY");
/* 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->tweak.resize_delay_ms > 0);
int fd = win->resize_timeout_fd;
uint16_t delay_ms = term->conf->tweak.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 tiemout */
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 +2759,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 && !term->window->is_resizing) {
if (term->conf->center) {
term->margins.left = total_x_pad / 2;
term->margins.top = total_y_pad / 2;
} else {
@ -2723,17 +2811,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 +2820,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)

View file

@ -677,9 +677,22 @@ xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
term->window->frame_callback = NULL;
}
#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.
*/
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);
@ -1278,6 +1291,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) {
@ -1430,6 +1444,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);
}

View file

@ -390,6 +390,8 @@ struct wl_window {
bool is_tiled_left:1;
bool is_tiled_right:1;
} configure;
int resize_timeout_fd;
};
struct config;