macos: always use overlay scroller (#9865)
With this PR, the macos scrollbar always uses the overlay style. If the OS preferred style is `.legacy`, we flash the scroller when the mouse is moved over it, such that users can still click and drag without relying on scroll wheels or gestures. Implements #9610. There are a few lines of code that could technically be removed after this change as they're only needed to make surfaces work correctly with the legacy scrollbar, but I decided to leave them in since they do no harm (see code comments). This ensures correct behavior if, for whatever reason, some corner case brings back the legacy scrollbar, or if someone decides to experiment with scrollbar styles in the future.pull/9831/head
commit
4a173052fb
|
|
@ -34,10 +34,15 @@ class SurfaceScrollView: NSView {
|
|||
scrollView.hasHorizontalScroller = false
|
||||
scrollView.autohidesScrollers = false
|
||||
scrollView.usesPredominantAxisScrolling = true
|
||||
// Always use the overlay style. See mouseMoved for how we make
|
||||
// it usable without a scroll wheel or gestures.
|
||||
scrollView.scrollerStyle = .overlay
|
||||
// hide default background to show blur effect properly
|
||||
scrollView.drawsBackground = false
|
||||
// don't let the content view clip it's subviews, to enable the
|
||||
// don't let the content view clip its subviews, to enable the
|
||||
// surface to draw the background behind non-overlay scrollers
|
||||
// (we currently only use overlay scrollers, but might as well
|
||||
// configure the views correctly in case we change our mind)
|
||||
scrollView.contentView.clipsToBounds = false
|
||||
|
||||
// The document view is what the scrollview is actually going
|
||||
|
|
@ -107,7 +112,10 @@ class SurfaceScrollView: NSView {
|
|||
observers.append(NotificationCenter.default.addObserver(
|
||||
forName: NSScroller.preferredScrollerStyleDidChangeNotification,
|
||||
object: nil,
|
||||
queue: .main
|
||||
// Since this observer is used to immediately override the event
|
||||
// that produced the notification, we let it run synchronously on
|
||||
// the posting thread.
|
||||
queue: nil
|
||||
) { [weak self] _ in
|
||||
self?.handleScrollerStyleChange()
|
||||
})
|
||||
|
|
@ -176,10 +184,10 @@ class SurfaceScrollView: NSView {
|
|||
private func synchronizeAppearance() {
|
||||
let scrollbarConfig = surfaceView.derivedConfig.scrollbar
|
||||
scrollView.hasVerticalScroller = scrollbarConfig != .never
|
||||
scrollView.verticalScroller?.controlSize = .small
|
||||
let hasLightBackground = OSColor(surfaceView.derivedConfig.backgroundColor).isLightColor
|
||||
// Make sure the scroller’s appearance matches the surface's background color.
|
||||
scrollView.appearance = NSAppearance(named: hasLightBackground ? .aqua : .darkAqua)
|
||||
updateTrackingAreas()
|
||||
}
|
||||
|
||||
/// Positions the surface view to fill the currently visible rectangle.
|
||||
|
|
@ -240,6 +248,7 @@ class SurfaceScrollView: NSView {
|
|||
|
||||
/// Handles scrollbar style changes
|
||||
private func handleScrollerStyleChange() {
|
||||
scrollView.scrollerStyle = .overlay
|
||||
synchronizeCoreSurface()
|
||||
}
|
||||
|
||||
|
|
@ -350,4 +359,32 @@ class SurfaceScrollView: NSView {
|
|||
}
|
||||
return contentHeight
|
||||
}
|
||||
|
||||
// MARK: Mouse events
|
||||
|
||||
override func mouseMoved(with: NSEvent) {
|
||||
// When the OS preferred style is .legacy, the user should be able to
|
||||
// click and drag the scroller without using scroll wheels or gestures,
|
||||
// so we flash it when the mouse is moved over the scrollbar area.
|
||||
guard NSScroller.preferredScrollerStyle == .legacy else { return }
|
||||
scrollView.flashScrollers()
|
||||
}
|
||||
|
||||
override func updateTrackingAreas() {
|
||||
// To update our tracking area we just recreate it all.
|
||||
trackingAreas.forEach { removeTrackingArea($0) }
|
||||
|
||||
super.updateTrackingAreas()
|
||||
|
||||
// Our tracking area is the scroller frame
|
||||
guard let scroller = scrollView.verticalScroller else { return }
|
||||
addTrackingArea(NSTrackingArea(
|
||||
rect: convert(scroller.bounds, from: scroller),
|
||||
options: [
|
||||
.mouseMoved,
|
||||
.activeInKeyWindow,
|
||||
],
|
||||
owner: self,
|
||||
userInfo: nil))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue