diff --git a/src/ui/generic-components/LightImageView.swift b/src/ui/generic-components/LightImageView.swift index 4c431b9d..5c92b5cc 100644 --- a/src/ui/generic-components/LightImageView.swift +++ b/src/ui/generic-components/LightImageView.swift @@ -26,6 +26,7 @@ class LightImageView: NSView { "position": NSNull(), "contentsScale": NSNull() ] + layerContentsRedrawPolicy = .never } func updateWithResizedCopy(_ image: CGImage?, _ size: NSSize) { @@ -38,7 +39,9 @@ class LightImageView: NSView { layer!.contents = image layer!.contentsScale = scaleFactor } - frame.size = size + if frame.size != size { + frame.size = size + } } /// this schedules the image update for the next cycle diff --git a/src/ui/main-window/ThumbnailView.swift b/src/ui/main-window/ThumbnailView.swift index 8aca6e7a..b93cbf58 100644 --- a/src/ui/main-window/ThumbnailView.swift +++ b/src/ui/main-window/ThumbnailView.swift @@ -143,21 +143,27 @@ class ThumbnailView: FlippedView { } func showOrHideWindowControls(_ shouldShowWindowControls: Bool) { + guard Preferences.appearanceStyle == .thumbnails else { return } let shouldShow = shouldShowWindowControls && !Preferences.hideColoredCircles && !Appearance.hideThumbnails - if Preferences.appearanceStyle == .thumbnails { - isShowingWindowControls = shouldShow - for icon in windowControlIcons { - icon.isHidden = !shouldShow - || (icon.type == .quit && !(window_?.application.canBeQuit() ?? true)) - || (icon.type == .close && !(window_?.canBeClosed() ?? true)) - || ((icon.type == .miniaturize || icon.type == .fullscreen) && !(window_?.canBeMinDeminOrFullscreened() ?? true)) - // Force the icons to redraw; otherwise after clicking the fullscreen button, - // it will still appear to be in fullscreen mode. - icon.display() + guard isShowingWindowControls != shouldShow else { return } + isShowingWindowControls = shouldShow + CATransaction.begin() + CATransaction.setDisableActions(true) + for icon in windowControlIcons { + let shouldHide = !shouldShow + || (icon.type == .quit && !(window_?.application.canBeQuit() ?? true)) + || (icon.type == .close && !(window_?.canBeClosed() ?? true)) + || ((icon.type == .miniaturize || icon.type == .fullscreen) && !(window_?.canBeMinDeminOrFullscreened() ?? true)) + + if icon.isHidden != shouldHide { + icon.isHidden = shouldHide + icon.needsDisplay = true } } + CATransaction.commit() } + func updateDockLabelIcon(_ dockLabel: String?) { assignIfDifferent(&dockLabelIcon.isHidden, dockLabel == nil || Preferences.hideAppBadges || Appearance.iconSize == 0) if !dockLabelIcon.isHidden, let dockLabel { diff --git a/src/ui/main-window/ThumbnailsView.swift b/src/ui/main-window/ThumbnailsView.swift index b7cdb2b7..a2142a77 100644 --- a/src/ui/main-window/ThumbnailsView.swift +++ b/src/ui/main-window/ThumbnailsView.swift @@ -277,33 +277,38 @@ class ScrollView: NSScrollView { } } + override func mouseExited(with event: NSEvent) { + previousTarget = nil + resetHoveredWindow() + } + override func mouseMoved(with event: NSEvent) { - // disable mouse hover during scrolling as it creates jank during elastic bounces at the start/end of the scrollview - // also disable it when ScrollwheelEvents is enabled, as it indicates that a multi-finder gesture is in progress - if isCurrentlyScrolling || ScrollwheelEvents.shouldBeEnabled { return } - if let hit = hitTest(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream) { - var target: NSView? = hit - while !(target is ThumbnailView) && target != nil { - target = target!.superview - } - if let target = target as? ThumbnailView { - if previousTarget != target { - previousTarget?.showOrHideWindowControls(false) - previousTarget = target - } - target.mouseMoved() - } else { - if !checkIfWithinInterPadding() { - resetHoveredWindow() - } - } + guard let documentView, !isCurrentlyScrolling && !ScrollwheelEvents.shouldBeEnabled else { return } + let location = documentView.convert(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream, from: nil) + let newTarget = findTarget(location) + guard newTarget !== previousTarget else { return } + CATransaction.begin() + CATransaction.setDisableActions(true) + if let newTarget { + previousTarget?.showOrHideWindowControls(false) + newTarget.mouseMoved() } else { resetHoveredWindow() } + previousTarget = newTarget + CATransaction.commit() } - override func mouseExited(with event: NSEvent) { - resetHoveredWindow() + private func findTarget(_ location: NSPoint) -> ThumbnailView? { + for i in 0..