fix(tui): do not remove SIGWINCH handler when resize events are enabled (#35221) (#35238)

When Nvim is started in one terminal emulator,
suspended, and later resumed in a different terminal emulator (as can
happen when using e.g. a multiplexer), the new terminal emulator will
not have all of the same modes enabled that the original terminal
emulator had. This is a problem in particular for in-band resize events
because we were disabling the SIGWINCH signal handler when we determined
that the terminal supported this mode.

However, if the new terminal does not support this mode then the
SIGWINCH handler remains disabled, and Neovim no longer properly
resizes. Instead of disabling the SIGWINCH handler, we track the state
of the resize events mode internally. If the mode is enabled then we
return early from the SIGWINCH handler before performing any ioctls or
other system calls. But if the mode is not enabled we proceed as normal.

(cherry picked from commit b1679f0ab6)
This commit is contained in:
Gregory Anders
2025-08-08 08:50:02 -05:00
committed by GitHub
parent 53a0d99702
commit e299430ff5

View File

@@ -113,7 +113,15 @@ struct TUIData {
bool set_cursor_color_as_str;
bool cursor_has_color;
bool is_starting;
bool did_set_grapheme_cluster_mode;
bool resize_events_enabled;
// Terminal modes that Nvim enabled that it must disable on exit
struct {
bool grapheme_clusters : 1;
bool theme_updates : 1;
bool resize_events : 1;
} modes;
FILE *screenshot;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
@@ -246,15 +254,25 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state)
case kTermModeGraphemeClusters:
if (!is_set) {
tui_set_term_mode(tui, mode, true);
tui->did_set_grapheme_cluster_mode = true;
tui->modes.grapheme_clusters = true;
}
break;
case kTermModeThemeUpdates:
tui_set_term_mode(tui, mode, true);
if (!is_set) {
tui_set_term_mode(tui, mode, true);
tui->modes.theme_updates = true;
}
break;
case kTermModeResizeEvents:
signal_watcher_stop(&tui->winch_handle);
tui_set_term_mode(tui, mode, true);
if (!is_set) {
tui_set_term_mode(tui, mode, true);
tui->modes.resize_events = true;
}
// We track both whether the mode is enabled AND if Nvim was the one to enable it
tui->resize_events_enabled = true;
break;
default:
break;
}
}
@@ -358,7 +376,10 @@ static void terminfo_start(TUIData *tui)
tui->overflow = false;
tui->set_cursor_color_as_str = false;
tui->cursor_has_color = false;
tui->did_set_grapheme_cluster_mode = false;
tui->resize_events_enabled = false;
tui->modes.grapheme_clusters = false;
tui->modes.resize_events = false;
tui->modes.theme_updates = false;
tui->showing_mode = SHAPE_IDX_N;
tui->unibi_ext.enable_mouse = -1;
tui->unibi_ext.disable_mouse = -1;
@@ -519,7 +540,9 @@ static void terminfo_disable(TUIData *tui)
{
// Disable theme update notifications. We do this first to avoid getting any
// more notifications after we reset the cursor and any color palette changes.
tui_set_term_mode(tui, kTermModeThemeUpdates, false);
if (tui->modes.theme_updates) {
tui_set_term_mode(tui, kTermModeThemeUpdates, false);
}
// Destroy output stuff
tui_mode_change(tui, NULL_STRING, SHAPE_IDX_N);
@@ -532,9 +555,12 @@ static void terminfo_disable(TUIData *tui)
// Reset the key encoding
tui_reset_key_encoding(tui);
// Disable resize events
tui_set_term_mode(tui, kTermModeResizeEvents, false);
if (tui->did_set_grapheme_cluster_mode) {
// Disable terminal modes that we enabled
if (tui->modes.resize_events) {
tui_set_term_mode(tui, kTermModeResizeEvents, false);
}
if (tui->modes.grapheme_clusters) {
tui_set_term_mode(tui, kTermModeGraphemeClusters, false);
}
@@ -680,7 +706,7 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *cbdata)
{
got_winch++;
TUIData *tui = cbdata;
if (tui_is_stopped(tui)) {
if (tui_is_stopped(tui) || tui->resize_events_enabled) {
return;
}