macOS: Don't clip surfaceView to contentView, fix transparent scrollbar background (#9517)

Here's a much simpler approach to fixing #9248 that doesn't involve
changes to the core or libghostty (the apprt one) at all. No safe area
API needed. All that's needed is for the content view to not clip its
subviews, such that the surface view can draw behind the scrollbar even
though it's a subview of the content view.

I haven't looked at the details on the renderer side, but since this
works it must be that it always renders background all the way to the
edges of the framebuffer, regardless of what the terminal screen size
(including window padding) happens to be. (This was already evident in
that we were able to avoid a transparent slot when the scrollbar was
hidden.) So I guess we kind of already have a safe area API through this
ability to set a screen size that's different from the framebuffer size?
_EDIT:_ I guess what's missing is the ability to shift the origin of the
screen within the framebuffer.

Fixes #9248, supersedes #9291.
pull/9518/head
Lukas 2025-11-08 19:29:28 +01:00 committed by GitHub
commit 0d5ecc7713
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 10 additions and 9 deletions

View File

@ -36,6 +36,9 @@ class SurfaceScrollView: NSView {
scrollView.usesPredominantAxisScrolling = true
// hide default background to show blur effect properly
scrollView.drawsBackground = false
// don't let the content view clip it's subviews, to enable the
// surface to draw the background behind non-overlay scrollers
scrollView.contentView.clipsToBounds = false
// The document view is what the scrollview is actually going
// to be directly scrolling. We set it up to a "blank" NSView
@ -142,6 +145,11 @@ class SurfaceScrollView: NSView {
// Fill entire bounds with scroll view
scrollView.frame = bounds
surfaceView.frame.size = scrollView.bounds.size
// We only set the width of the documentView here, as the height depends
// on the scrollbar state and is updated in synchronizeScrollView
documentView.frame.size.width = scrollView.bounds.width
// When our scrollview changes make sure our scroller and surface views are synchronized
synchronizeScrollView()
@ -175,20 +183,13 @@ class SurfaceScrollView: NSView {
/// so the renderer only needs to render what's currently on screen.
private func synchronizeSurfaceView() {
let visibleRect = scrollView.contentView.documentVisibleRect
surfaceView.frame = visibleRect
surfaceView.frame.origin = visibleRect.origin
}
/// Sizes the document view and scrolls the content view according to the scrollbar state
private func synchronizeScrollView() {
// We adjust the document height first, as the content width may depend on it.
// Update the document height to give our scroller the correct proportions
documentView.frame.size.height = documentHeight()
// Our width should be the content width to account for visible scrollers.
// We don't do horizontal scrolling in terminals. The surfaceView width is
// yoked to the document width (this is distinct from the content width
// passed to surfaceView.sizeDidChange, which is only updated on layout).
documentView.frame.size.width = scrollView.contentSize.width
surfaceView.frame.size.width = scrollView.contentSize.width
// Only update our actual scroll position if we're not actively scrolling.
if !isLiveScrolling {