From 09e10fea85e35047130b4e7ae87844e475af4643 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 03:13:25 +0000 Subject: [PATCH] Fix stale is_selected buffer after screen buffer toggle (#9725) When toggling between alt and main screen buffers, the selection buffer (is_selected) was not always re-uploaded to the GPU. This caused a size mismatch because render_lines_for_screen depends on pixel_scroll_enabled, which depends on linebuf == main_linebuf. On alt screen, pixel_scroll is disabled so render_lines = screen->lines. On main screen, pixel_scroll is enabled so render_lines = screen->lines + 1. After switching from alt to main, the cell data buffer was re-uploaded with the larger size (is_dirty = true), but the selection buffer was not (screen_is_selection_dirty could return false if no selections/urls/extra cursors were active). The extra row of cells then read out-of-bounds from the selection buffer, getting garbage data that the shader interpreted as extra cursor shapes, producing blinking cursor-colored artifacts. Fix by unconditionally setting extra_cursors.dirty = true after screen toggle, ensuring the selection buffer is always re-uploaded with the correct size matching the cell data buffer. Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/daa73124-4795-4389-aea5-bb5593a26d9f Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com> --- kitty/screen.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kitty/screen.c b/kitty/screen.c index e82d6ea55..9a184f497 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1622,10 +1622,13 @@ screen_toggle_screen_buffer(Screen *self, bool save_cursor, bool clear_alt_scree self->is_dirty = true; grman_mark_layers_dirty(self->grman); clear_all_selections(self); - if (self->extra_cursors.count) { - self->extra_cursors.count = 0; - self->extra_cursors.dirty = true; - } + self->extra_cursors.count = 0; + // Force re-upload of the selection buffer as the number of render lines + // changes when pixel_scroll_enabled changes (which depends on which + // linebuf is active). Without this, the selection buffer can be smaller + // than the cell data buffer, causing OOB reads that produce cursor + // artifacts (see #9725). + self->extra_cursors.dirty = true; global_state.check_for_active_animated_images = true; }