Fix jerky behavior when live resizing an OS window on platforms that report live resize being and end events

Also disable live resize begin/end events on Wayland since they are not
reliable.

On platforms that support live resize begin/end use a separately
configurable pause time before the screen is redrawn.

Fixes #6341
This commit is contained in:
Kovid Goyal 2023-06-07 14:31:39 +05:30
parent af389d6860
commit 89875af5e6
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
9 changed files with 54 additions and 19 deletions

10
glfw/wl_window.c vendored
View file

@ -504,6 +504,12 @@ _glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
return !already_fullscreen;
}
static void
report_live_resize(_GLFWwindow *w, bool started) {
// disabled as mutter, for instance, does not send a configure event when the user stops resizing (aka releases the mouse button)
if (false) _glfwInputLiveResize(w, started);
}
static void
xdgToplevelHandleConfigure(void* data,
struct xdg_toplevel* toplevel UNUSED,
@ -536,7 +542,7 @@ xdgToplevelHandleConfigure(void* data,
if (new_states & TOPLEVEL_STATE_RESIZING) {
if (width) window->wl.user_requested_content_size.width = width;
if (height) window->wl.user_requested_content_size.height = height;
if (!(window->wl.current.toplevel_states & TOPLEVEL_STATE_RESIZING)) _glfwInputLiveResize(window, true);
if (!(window->wl.current.toplevel_states & TOPLEVEL_STATE_RESIZING)) report_live_resize(window, true);
}
if (width != 0 && height != 0)
{
@ -606,7 +612,7 @@ static void xdgSurfaceHandleConfigure(void* data,
window->wl.current.width = width;
window->wl.current.height = height;
_glfwInputWindowFocus(window, window->wl.current.toplevel_states & TOPLEVEL_STATE_ACTIVATED);
if (live_resize_done) _glfwInputLiveResize(window, false);
if (live_resize_done) report_live_resize(window, false);
}
}

View file

@ -1004,9 +1004,19 @@ process_pending_resizes(monotonic_t now) {
if (w->live_resize.in_progress) {
bool update_viewport = false;
if (w->live_resize.from_os_notification) {
if (w->live_resize.os_says_resize_complete || (now - w->live_resize.last_resize_event_at) > 1) update_viewport = true;
if (w->live_resize.os_says_resize_complete) update_viewport = true;
else {
// prevent a "hang" if the OS never sends a resize complete event
// also reflow the screen when the user pauses resizing so the user can see what the resized
// screen will look like.
if ((now - w->live_resize.last_resize_event_at) > OPT(resize_debounce_time).on_pause) update_viewport = true;
else {
global_state.has_pending_resizes = true;
set_maximum_wait(s_double_to_monotonic_t(0.05));
}
}
} else {
monotonic_t debounce_time = OPT(resize_debounce_time);
monotonic_t debounce_time = OPT(resize_debounce_time).on_end;
// if more than one resize event has occurred, wait at least 0.2 secs
// before repainting, to avoid rapid transitions between the cells banner
// and the normal screen

View file

@ -1065,12 +1065,18 @@ faded and one being fully opaque.
)
opt('resize_debounce_time', '0.1',
option_type='positive_float', ctype='time',
opt('resize_debounce_time', '0.1 0.5',
option_type='resize_debounce_time', ctype='!resize_debounce_time',
long_text='''
The time to wait before redrawing the screen when a resize event is received (in
seconds). On platforms such as macOS, where the operating system sends events
corresponding to the start and end of a resize, this number is ignored.
The time to wait before redrawing the screen during a live resize of the OS
window, when no new resize events have been received, i.e. when resizing is
either paused or finished. On platforms such as macOS, where the operating
system sends events corresponding to the start and end of a live resize, the
second number is used for redraw-after-pause since kitty can distinguish
between a pause and end of resizing. On such systems the first number is
ignored and redraw is immediate after end of resize. On other systems the
first number is used so that kitty is "ready" quickly after the end of
resizing, while not also continuously redrawing, to save energy.
'''
)

14
kitty/options/parse.py generated
View file

@ -13,12 +13,12 @@ from kitty.options.utils import (
deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias,
deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations,
macos_option_as_alt, macos_titlebar_color, modify_font, narrow_symbols, optional_edge_width,
parse_map, parse_mouse_map, paste_actions, remote_control_password, resize_draw_strategy,
scrollback_lines, scrollback_pager_history_size, shell_integration, store_multiple, symbol_map,
tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade,
tab_font_style, tab_separator, tab_title_template, titlebar_color, to_cursor_shape, to_font_size,
to_layout_names, to_modifiers, url_prefixes, url_style, visual_window_select_characters,
window_border_width, window_size
parse_map, parse_mouse_map, paste_actions, remote_control_password, resize_debounce_time,
resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, shell_integration,
store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height,
tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, titlebar_color,
to_cursor_shape, to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style,
visual_window_select_characters, window_border_width, window_size
)
@ -1151,7 +1151,7 @@ class Parser:
ans['repaint_delay'] = positive_int(val)
def resize_debounce_time(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['resize_debounce_time'] = positive_float(val)
ans['resize_debounce_time'] = resize_debounce_time(val)
def resize_draw_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['resize_draw_strategy'] = resize_draw_strategy(val)

View file

@ -592,7 +592,7 @@ convert_from_opts_window_logo_alpha(PyObject *py_opts, Options *opts) {
static void
convert_from_python_resize_debounce_time(PyObject *val, Options *opts) {
opts->resize_debounce_time = parse_s_double_to_monotonic_t(val);
resize_debounce_time(val, opts);
}
static void

View file

@ -255,3 +255,9 @@ tab_bar_margin_height(PyObject *val, Options *opts) {
opts->tab_bar_margin_height.outer = PyFloat_AsDouble(PyTuple_GET_ITEM(val, 0));
opts->tab_bar_margin_height.inner = PyFloat_AsDouble(PyTuple_GET_ITEM(val, 1));
}
static void
resize_debounce_time(PyObject *src, Options *opts) {
opts->resize_debounce_time.on_end = s_double_to_monotonic_t(PyFloat_AsDouble(PyTuple_GET_ITEM(src, 0)));
opts->resize_debounce_time.on_pause = s_double_to_monotonic_t(PyFloat_AsDouble(PyTuple_GET_ITEM(src, 1)));
}

View file

@ -564,7 +564,7 @@ class Options:
pointer_shape_when_grabbed: choices_for_pointer_shape_when_grabbed = 'arrow'
remember_window_size: bool = True
repaint_delay: int = 10
resize_debounce_time: float = 0.1
resize_debounce_time: typing.Tuple[float, float] = (0.1, 0.5)
resize_draw_strategy: int = 0
resize_in_steps: bool = False
scrollback_fill_enlarged_window: bool = False

View file

@ -604,6 +604,13 @@ def resize_draw_strategy(x: str) -> int:
return cmap.get(x.lower(), 0)
def resize_debounce_time(x: str) -> Tuple[float, float]:
parts = x.split(maxsplit=1)
if len(parts) == 1:
return positive_float(parts[0]), 0.5
return positive_float(parts[0]), positive_float(parts[1])
def visual_window_select_characters(x: str) -> str:
import string
valid_characters = string.digits + string.ascii_uppercase

View file

@ -70,7 +70,7 @@ typedef struct {
bool window_alert_on_bell;
bool debug_keyboard;
bool allow_hyperlinks;
monotonic_t resize_debounce_time;
struct { monotonic_t on_end, on_pause; } resize_debounce_time;
MouseShape pointer_shape_when_grabbed;
MouseShape default_pointer_shape;
MouseShape pointer_shape_when_dragging;