Skip to content

Commit c1c028e

Browse files
committed
Preserve explicit wheel scrollback against passive follow
1 parent 7634abe commit c1c028e

1 file changed

Lines changed: 23 additions & 11 deletions

File tree

Sources/GhosttyTerminalView.swift

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6052,6 +6052,7 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
60526052
}
60536053

60546054
override func scrollWheel(with event: NSEvent) {
6055+
NotificationCenter.default.post(name: .ghosttyDidReceiveWheelScroll, object: self)
60556056
guard let surface = surface else { return }
60566057
lastScrollEventTime = CACurrentMediaTime()
60576058
Self.focusLog("scrollWheel: surface=\(terminalSurface?.id.uuidString ?? "nil") firstResponder=\(String(describing: window?.firstResponder))")
@@ -6453,6 +6454,7 @@ enum GhosttyNotificationKey {
64536454
extension Notification.Name {
64546455
static let ghosttyDidUpdateScrollbar = Notification.Name("ghosttyDidUpdateScrollbar")
64556456
static let ghosttyDidUpdateCellSize = Notification.Name("ghosttyDidUpdateCellSize")
6457+
static let ghosttyDidReceiveWheelScroll = Notification.Name("ghosttyDidReceiveWheelScroll")
64566458
static let ghosttySearchFocus = Notification.Name("ghosttySearchFocus")
64576459
static let ghosttyConfigDidReload = Notification.Name("ghosttyConfigDidReload")
64586460
static let ghosttyDefaultBackgroundDidChange = Notification.Name("ghosttyDefaultBackgroundDidChange")
@@ -6586,6 +6588,8 @@ final class GhosttySurfaceScrollView: NSView {
65866588
/// When true, auto-scroll should be suspended to prevent the "doomscroll" bug
65876589
/// where the terminal fights the user's scroll position.
65886590
private var userScrolledAwayFromBottom = false
6591+
private var pendingExplicitWheelScroll = false
6592+
private var allowExplicitScrollbarSync = false
65896593
/// Threshold in points from bottom to consider "at bottom" (allows for minor float drift)
65906594
private static let scrollToBottomThreshold: CGFloat = 5.0
65916595
private var isActive = true
@@ -7011,6 +7015,14 @@ final class GhosttySurfaceScrollView: NSView {
70117015
self?.handleScrollbarUpdate(notification)
70127016
})
70137017

7018+
observers.append(NotificationCenter.default.addObserver(
7019+
forName: .ghosttyDidReceiveWheelScroll,
7020+
object: surfaceView,
7021+
queue: .main
7022+
) { [weak self] _ in
7023+
self?.pendingExplicitWheelScroll = true
7024+
})
7025+
70147026
observers.append(NotificationCenter.default.addObserver(
70157027
forName: .ghosttySearchFocus,
70167028
object: nil,
@@ -9013,26 +9025,21 @@ final class GhosttySurfaceScrollView: NSView {
90139025
userScrolledAwayFromBottom = false
90149026
}
90159027

9016-
// Only auto-scroll if user hasn't manually scrolled away from bottom
9017-
// or if we're following terminal output (scrollbar shows we're at bottom)
9018-
let shouldAutoScroll = !userScrolledAwayFromBottom ||
9019-
(scrollbar.offset + scrollbar.len >= scrollbar.total)
9028+
// Passive bottom packets should not override an explicit scrollback review,
9029+
// but the first scrollbar packet caused by the user's own wheel input should
9030+
// still move the viewport to the requested scrollback position.
9031+
let shouldAutoScroll = !userScrolledAwayFromBottom || allowExplicitScrollbarSync
90209032

90219033
if shouldAutoScroll && !pointApproximatelyEqual(currentOrigin, targetOrigin) {
9022-
#if DEBUG
9023-
logDragGeometryChange(
9024-
event: "scrollOrigin",
9025-
old: currentOrigin,
9026-
new: targetOrigin
9027-
)
9028-
#endif
90299034
scrollView.contentView.scroll(to: targetOrigin)
90309035
didChangeGeometry = true
90319036
}
90329037
lastSentRow = Int(scrollbar.offset)
90339038
}
90349039
}
90359040

9041+
allowExplicitScrollbarSync = false
9042+
90369043
if didChangeGeometry {
90379044
scrollView.reflectScrolledClipView(scrollView.contentView)
90389045
}
@@ -9068,6 +9075,11 @@ final class GhosttySurfaceScrollView: NSView {
90689075
guard let scrollbar = notification.userInfo?[GhosttyNotificationKey.scrollbar] as? GhosttyScrollbar else {
90699076
return
90709077
}
9078+
if pendingExplicitWheelScroll {
9079+
userScrolledAwayFromBottom = scrollbar.offset + scrollbar.len < scrollbar.total
9080+
allowExplicitScrollbarSync = true
9081+
pendingExplicitWheelScroll = false
9082+
}
90719083
surfaceView.scrollbar = scrollbar
90729084
synchronizeScrollView()
90739085
}

0 commit comments

Comments
 (0)