Fix multi cursor drawing

This commit is contained in:
1024jp 2024-03-11 12:44:29 +09:00
parent a5e3872f20
commit 0354f9cb29
3 changed files with 32 additions and 24 deletions

View File

@ -3,6 +3,10 @@
4.8.0-beta.3 (unreleased)
--------------------------
### Fixes
- [beta] Fix an issue on macOS 14 that multiple cursors in editors were not drawn when the editor becomes active again.
4.8.0-beta.2 (635)

View File

@ -230,16 +230,6 @@ class EditorTextView: NSTextView, Themable, CurrentLineHighlighting, MultiCursor
.filter { !$0 }
.sink { [unowned self] _ in self.layoutManager?.removeTemporaryAttribute(.roundedBackgroundColor, forCharacterRange: self.string.nsRange) },
]
// workaround the issue that indicators display even the application is inactive
// (2023-08 macOS 14 beta 5, FB12968177)
if #available(macOS 14, *) {
self.keyStateObserver = Publishers.Merge3(
NotificationCenter.default.publisher(for: NSApplication.didResignActiveNotification, object: NSApp),
NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification, object: NSApp),
NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification))
.sink { [unowned self] _ in self.invalidateInsertionPointDisplayMode(isFirstResponder: self.window?.firstResponder == self) }
}
}
@ -320,8 +310,8 @@ class EditorTextView: NSTextView, Themable, CurrentLineHighlighting, MultiCursor
// post notification about becoming the first responder
NotificationCenter.default.post(name: EditorTextView.didBecomeFirstResponderNotification, object: self)
if #available(macOS 14, *) {
self.invalidateInsertionPointDisplayMode(isFirstResponder: true)
defer {
self.invalidateInsertionIndicatorDisplayMode()
}
return true
@ -332,8 +322,8 @@ class EditorTextView: NSTextView, Themable, CurrentLineHighlighting, MultiCursor
guard super.resignFirstResponder() else { return false }
if #available(macOS 14, *) {
self.invalidateInsertionPointDisplayMode(isFirstResponder: false)
defer {
self.invalidateInsertionIndicatorDisplayMode()
}
return true
@ -356,6 +346,16 @@ class EditorTextView: NSTextView, Themable, CurrentLineHighlighting, MultiCursor
self?.enclosingScrollView?.drawsBackground = $0
self?.lineHighlightColor = self?.theme?.lineHighlightColor(forOpaqueBackground: $0)
}
// observe key window state for insertion points drawing
if #available(macOS 14, *), let window {
self.keyStateObserver = Publishers.Merge(
NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification, object: window),
NotificationCenter.default.publisher(for: NSWindow.didResignKeyNotification, object: window)
)
.sink { [unowned self] _ in self.invalidateInsertionIndicatorDisplayMode() }
}
}

View File

@ -397,7 +397,7 @@ extension MultiCursorEditing {
// reuse existing indicators
var indicators = ArraySlice(self.insertionIndicators) // slice for popFirst()
let isActive = (self.window?.firstResponder == self && NSApp.isActive)
let shouldDraw = self.shouldDrawInsertionPoints
self.insertionIndicators = insertionLocations
.compactMap { layoutManager.insertionPointRect(at: $0) } // ignore split cursors
@ -409,7 +409,7 @@ extension MultiCursorEditing {
} else {
let indicator = NSTextInsertionIndicator(frame: rect)
indicator.color = self.insertionPointColor
indicator.displayMode = isActive ? .automatic : .hidden
indicator.displayMode = shouldDraw ? .automatic : .hidden
self.addSubview(indicator)
return indicator
}
@ -422,17 +422,14 @@ extension MultiCursorEditing {
/// Workarounds the issue that indicators display even the editor is inactive (2023-08 macOS 14, FB12964703 and FB12968177)
///
/// This method should be Invoked when the receiver is changed whether it is the key editor receiving text input in the system.
///
/// - Parameter isFirstResponder: Whether the receiver is the first responder in the window.
@available(macOS 14, *)
func invalidateInsertionPointDisplayMode(isFirstResponder: Bool) {
/// This method should be Invoked when changing the state whether the receiver is the key editor receiving text input in the system.
func invalidateInsertionIndicatorDisplayMode() {
guard !self.insertionIndicators.isEmpty else { return }
guard #available(macOS 14, *), !self.insertionIndicators.isEmpty else { return }
let isActive = NSApp.isActive && self.window == NSApp.keyWindow && isFirstResponder
let shouldDraw = self.shouldDrawInsertionPoints
for indicator in self.insertionIndicators {
indicator.displayMode = isActive ? .automatic : .hidden
indicator.displayMode = shouldDraw ? .automatic : .hidden
}
}
}
@ -440,6 +437,13 @@ extension MultiCursorEditing {
extension NSTextView {
/// Whether the editor should draw insertion points.
fileprivate final var shouldDrawInsertionPoints: Bool {
NSApp.isActive && self.window?.isKeyWindow == true && self.window?.firstResponder == self && self.isEditable
}
/// Finds the location for the insertion point where one (visual) line above to the given insertion point location.
///
/// - Parameter index: The character index of the reference insertion point.