From 5b7f1456407824b624afd2b53438db126fbee90b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 17 Oct 2025 19:48:59 -0700 Subject: [PATCH] macos: make terminal smaller to account for legacy scrollbar When the preferred scrollbar style is "legacy", the scrollbar takes up space that offsets the actual terminal. To prevent reflow, we detect this before the scrollbar becomes visible and shrink our terminal width to prepare for it. This doesn't account for the style changing at runtime, yet. --- macos/Sources/Ghostty/SurfaceScrollView.swift | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceScrollView.swift b/macos/Sources/Ghostty/SurfaceScrollView.swift index 714227cd1..b1e1b9baf 100644 --- a/macos/Sources/Ghostty/SurfaceScrollView.swift +++ b/macos/Sources/Ghostty/SurfaceScrollView.swift @@ -142,18 +142,35 @@ class SurfaceScrollView: NSView { // Only update sizes if we have a valid (non-zero) content size. The content size // can be zero when this is added early to a view, or to an invisible hierarchy. // Practically, this happened in the quick terminal. - let contentSize = scrollView.contentSize - if contentSize.width > 0 && contentSize.height > 0 { - // Keep document width synchronized with content width - documentView.setFrameSize(CGSize( - width: contentSize.width, - height: documentView.frame.height - )) - - // Inform the actual pty of our size change - surfaceView.sizeDidChange(contentSize) + var contentSize = scrollView.contentSize + guard contentSize.width > 0 && contentSize.height > 0 else { + synchronizeSurfaceView() + return } + // If we have a legacy scrollbar and its not visible, then we account for that + // in advance, because legacy scrollbars change our contentSize and force reflow + // of our terminal which is not desirable. + // See: https://github.com/ghostty-org/ghostty/discussions/9254 + let style = scrollView.verticalScroller?.scrollerStyle ?? NSScroller.preferredScrollerStyle + if style == .legacy { + if (scrollView.verticalScroller?.isHidden ?? true) { + let scrollerWidth = NSScroller.scrollerWidth(for: .regular, scrollerStyle: .legacy) + contentSize.width -= scrollerWidth + } + } + + // Keep document width synchronized with content width + documentView.setFrameSize(CGSize( + width: contentSize.width, + height: documentView.frame.height + )) + + // Inform the actual pty of our size change. This doesn't change the actual view + // frame because we do want to render the whole thing, but it will prevent our + // rows/cols from going into the non-content area. + surfaceView.sizeDidChange(contentSize) + // When our scrollview changes make sure our surface view is synchronized synchronizeSurfaceView() }