feat: improve responsiveness of showing the switcher
This commit is contained in:
1 parent
fab9d7c0ab
commit
689adc0a30
4 files changed
+40
-17
No files matched your search
@@ -314,7 +314,7 @@ class Windows {
|
||||
}
|
||||
|
||||
// dispatch screenshot requests off the main-thread, then wait for completion
|
||||
static func refreshThumbnails(_ windows: [Window], _ source: RefreshCausedBy) {
|
||||
static func refreshThumbnailsAsync(_ windows: [Window], _ source: RefreshCausedBy) {
|
||||
var eligibleWindows = [Window]()
|
||||
for window in windows {
|
||||
if !window.isWindowlessApp, let cgWindowId = window.cgWindowId, cgWindowId != CGWindowID(bitPattern: -1) {
|
||||
@@ -322,10 +322,10 @@ class Windows {
|
||||
}
|
||||
}
|
||||
if eligibleWindows.isEmpty { return }
|
||||
screenshotEligibleWindowsAndRefreshUi(eligibleWindows, source)
|
||||
screenshotEligibleWindowsAndUpdateUi(eligibleWindows, source)
|
||||
}
|
||||
|
||||
private static func screenshotEligibleWindowsAndRefreshUi(_ eligibleWindows: [Window], _ source: RefreshCausedBy) {
|
||||
private static func screenshotEligibleWindowsAndUpdateUi(_ eligibleWindows: [Window], _ source: RefreshCausedBy) {
|
||||
for window in eligibleWindows {
|
||||
BackgroundWork.screenshotsQueue.addOperation { [weak window] in
|
||||
if source == .refreshOnlyThumbnailsAfterShowUi && !App.app.appIsBeingUsed { return }
|
||||
|
||||
+3
-10
@@ -206,7 +206,7 @@ class App: AppCenterApplication {
|
||||
if !windowsToScreenshot.isEmpty && SystemPermissions.screenRecordingPermission == .granted
|
||||
&& !Preferences.onlyShowApplications()
|
||||
&& (!Appearance.hideThumbnails || Preferences.previewFocusedWindow) {
|
||||
Windows.refreshThumbnails(windowsToScreenshot, source)
|
||||
Windows.refreshThumbnailsAsync(windowsToScreenshot, source)
|
||||
if source == .refreshOnlyThumbnailsAfterShowUi { return }
|
||||
}
|
||||
guard appIsBeingUsed else { return }
|
||||
@@ -216,12 +216,7 @@ class App: AppCenterApplication {
|
||||
guard appIsBeingUsed else { return }
|
||||
Windows.updateFocusedWindowIndex()
|
||||
guard appIsBeingUsed else { return }
|
||||
thumbnailsPanel.thumbnailsView.updateItemsAndLayout()
|
||||
guard appIsBeingUsed else { return }
|
||||
thumbnailsPanel.setContentSize(thumbnailsPanel.thumbnailsView.contentView.frame.size)
|
||||
thumbnailsPanel.display()
|
||||
guard appIsBeingUsed else { return }
|
||||
NSScreen.preferred.repositionPanel(thumbnailsPanel)
|
||||
thumbnailsPanel.updateContents()
|
||||
guard appIsBeingUsed else { return }
|
||||
Windows.voiceOverWindow() // at this point ThumbnailViews are assigned to the window, and ready
|
||||
guard appIsBeingUsed else { return }
|
||||
@@ -267,12 +262,10 @@ class App: AppCenterApplication {
|
||||
guard appIsBeingUsed else { return }
|
||||
Appearance.update()
|
||||
guard appIsBeingUsed else { return }
|
||||
thumbnailsPanel.makeKeyAndOrderFront(nil) // workaround: without this, switching between 2 screens make thumbnailPanel invisible
|
||||
KeyRepeatTimer.toggleRepeatingKeyNextWindow()
|
||||
guard appIsBeingUsed else { return }
|
||||
refreshOpenUi([], .showUi)
|
||||
guard appIsBeingUsed else { return }
|
||||
thumbnailsPanel.show()
|
||||
KeyRepeatTimer.toggleRepeatingKeyNextWindow()
|
||||
refreshOpenUi(Windows.list, .refreshOnlyThumbnailsAfterShowUi)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,27 +13,46 @@ class LightImageView: NSView {
|
||||
super.init(frame: frameRect)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
wantsLayer = true
|
||||
// configure the layer for efficient GPU-scaling
|
||||
layer!.contentsGravity = .resize
|
||||
layer!.magnificationFilter = .trilinear
|
||||
layer!.minificationFilter = .trilinear
|
||||
layer!.minificationFilterBias = 0.0
|
||||
layer!.shouldRasterize = false
|
||||
// disable implicit animations
|
||||
layer!.actions = [
|
||||
"contents": NSNull(),
|
||||
"bounds": NSNull(),
|
||||
"position": NSNull(),
|
||||
"contentsScale": NSNull()
|
||||
]
|
||||
}
|
||||
|
||||
func updateWithResizedCopy(_ image: CGImage?, _ size: NSSize) {
|
||||
let scaleFactor = NSScreen.preferred.backingScaleFactor
|
||||
if let image {
|
||||
CATransaction.begin()
|
||||
// disable implicit fade-in animation from CALayer
|
||||
CATransaction.setDisableActions(true)
|
||||
// alternatively, we could set layer!.contentsGravity to .center, and use the lines bellow to resize ourselves
|
||||
// let scaledSize = NSSize(width: size.width * scaleFactor, height: size.height * scaleFactor)
|
||||
// layer!.contents = image.resizedCopyWithCoreGraphics(scaledSize, fixBitmapInfo)
|
||||
// it would produce subjectively better quality, but the resizing would be done on the CPU so poor performance
|
||||
layer!.contents = image
|
||||
layer!.contentsScale = scaleFactor
|
||||
CATransaction.commit()
|
||||
}
|
||||
frame.size = size
|
||||
}
|
||||
|
||||
/// this schedules the image update for the next cycle
|
||||
/// The Panel will show with previous pictures, then they each will get updated quickly. It's a trade-off of getting AltTab interactive faster at the price of wrong data being shown
|
||||
/// I feel the UX is better without it. I may reconsider
|
||||
func updateWithResizedCopyAsync(_ image: CGImage?, _ size: NSSize) {
|
||||
layer!.contentsScale = NSScreen.preferred.backingScaleFactor
|
||||
frame.size = size
|
||||
if let image {
|
||||
// set image on another cycle so it doesn't block initial rendering
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
self.layer!.contents = image
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,17 @@ class ThumbnailsPanel: NSPanel {
|
||||
appearance = NSAppearance(named: Appearance.currentTheme == .dark ? .vibrantDark : .vibrantLight)
|
||||
}
|
||||
|
||||
func updateContents() {
|
||||
CATransaction.begin()
|
||||
defer { CATransaction.commit() }
|
||||
CATransaction.setDisableActions(true)
|
||||
thumbnailsView.updateItemsAndLayout()
|
||||
guard App.app.appIsBeingUsed else { return }
|
||||
setContentSize(thumbnailsView.contentView.frame.size)
|
||||
guard App.app.appIsBeingUsed else { return }
|
||||
NSScreen.preferred.repositionPanel(self)
|
||||
}
|
||||
|
||||
override func orderOut(_ sender: Any?) {
|
||||
if Preferences.fadeOutAnimation {
|
||||
NSAnimationContext.runAnimationGroup(
|
||||
|
||||
Reference in new issue
Block a user