From 56896311a62b07e2b76cc209f1b7f9a169036824 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 15 Oct 2025 15:47:08 -0700 Subject: [PATCH] Selection dragging should not process when terminal screen changes (#9223) This hasn't caused any known bugs but leads to selection memory corruption and assertion failures in runtime safe modes. When the terminal screen changes (primary to secondary) and we have an active dragging mode going either by moving the mouse or our selection tick timer, we should halt. We still keep the mouse state active which lets selection continue once the screen switches back. --- src/Surface.zig | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Surface.zig b/src/Surface.zig index 03974dfc6..2df720fcb 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1004,6 +1004,16 @@ fn selectionScrollTick(self: *Surface) !void { defer self.renderer_state.mutex.unlock(); const t: *terminal.Terminal = self.renderer_state.terminal; + // If our screen changed while this is happening, we stop our + // selection scroll. + if (self.mouse.left_click_screen != t.active_screen) { + self.io.queueMessage( + .{ .selection_scroll = false }, + .locked, + ); + return; + } + // Scroll the viewport as required try t.scrollViewport(.{ .delta = delta }); @@ -4091,6 +4101,12 @@ pub fn cursorPosCallback( // count because we don't want to handle selection. if (self.mouse.left_click_count == 0) break :select; + // If our terminal screen changed then we don't process this. We don't + // invalidate our pin or mouse state because if the screen switches + // back then we can continue our selection. + const t: *terminal.Terminal = self.renderer_state.terminal; + if (self.mouse.left_click_screen != t.active_screen) break :select; + // All roads lead to requiring a re-render at this point. try self.queueRender(); @@ -4114,7 +4130,7 @@ pub fn cursorPosCallback( } // Convert to points - const screen = &self.renderer_state.terminal.screen; + const screen = &t.screen; const pin = screen.pages.pin(.{ .viewport = .{ .x = pos_vp.x,