fix: app icons could sometimes be invisible (closes #5226)
This commit is contained in:
1 parent
56546571b6
commit
23fbc01a0e
4 files changed
+24
-11
No files matched your search
@@ -188,7 +188,7 @@
|
||||
"Show standard tabs as windows" = "표준 탭을 윈도우로 보이기";
|
||||
"Show standard tabs as windows:" = "표준 탭을 윈도우로 보여주기:";
|
||||
"Show titles" = "제목 표시";
|
||||
"Show windows from applications" = "윈도우을 표시할 앱";
|
||||
"Show windows from applications" = "윈도우를 표시할 앱";
|
||||
"Show windows from screens" = "윈도우를 표시할 화면";
|
||||
"Show windows from Spaces" = "윈도우를 표시할 Space";
|
||||
"Show windows from:" = "창을 표시할 항목:";
|
||||
|
||||
@@ -45,18 +45,29 @@ class Application: NSObject {
|
||||
return 0
|
||||
}()
|
||||
|
||||
/// Converting NSImage to CGImage may seem simple, but it's actually very tricky. Lots of time has been put to make it work robustly
|
||||
/// The RunningApplication.icon can have store bitmaps or vectors. We have to rasterize into pixels. This is not easy as there are many APIs:
|
||||
/// * icon.cgImage(forProposedRect:) > context.draw -> only API which works
|
||||
/// * icon.cgImage(forProposedRect:) > cgImage.draw -> returns nil for some users (could never reproduce it locally)
|
||||
/// * icon.draw() -> returns nil for some users (could never reproduce it locally)
|
||||
/// * icon.bestRepresentation() > bestRep.draw(in:) -> returns nil for some users (could never reproduce it locally)
|
||||
/// MacOS Big Sur also introduced a constant padding around app icons. It was later increased with Tahoe. We have to crop it
|
||||
static func appIconWithoutPadding(_ icon: NSImage?) -> CGImage? {
|
||||
guard let icon else { return nil }
|
||||
let finalWidth = max(ThumbnailsPanel.maxPossibleAppIconSize.width, ThumbnailsPanel.maxPossibleAppIconSize.height)
|
||||
// we hardcode cropping values based on a reference 1024 icon, and depending on the macOS version
|
||||
let padding = appIconPadding * (finalWidth / (1024 - appIconPadding * 2))
|
||||
// we need a bigger image size, since we'll crop to reach finalWidth
|
||||
let sourceWidth = finalWidth + padding * 2
|
||||
guard let context = CGContext(data: nil, width: Int(finalWidth), height: Int(finalWidth), bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return nil }
|
||||
// we ask the NSImage for the closest image it has to our desired size. It's likely to return a 1024x1024 or 512x512 image; whichever is closest
|
||||
var proposedRect = CGRect(origin: .zero, size: NSSize(width: sourceWidth, height: sourceWidth))
|
||||
guard let cgImage = icon.cgImage(forProposedRect: &proposedRect, context: nil, hints: [.interpolation: NSImageInterpolation.high]) else { return nil }
|
||||
// we have to crop this image; let's scale our intended padding, given the image size we got
|
||||
let paddingScaled = padding * (CGFloat(cgImage.width) / sourceWidth)
|
||||
guard let image = cgImage.cropping(to: CGRect(x: paddingScaled, y: paddingScaled, width: CGFloat(cgImage.width) - paddingScaled * 2, height: CGFloat(cgImage.height) - paddingScaled * 2).integral),
|
||||
let context = CGContext(data: nil, width: Int(finalWidth), height: Int(finalWidth), bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue).union(.byteOrder32Little).rawValue) else { return nil }
|
||||
context.interpolationQuality = .high
|
||||
let drawRect = CGRect(x: -padding, y: -padding, width: sourceWidth, height: sourceWidth)
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
NSGraphicsContext.current = NSGraphicsContext(cgContext: context, flipped: false)
|
||||
icon.draw(in: drawRect, from: .zero, operation: .copy, fraction: 1.0, respectFlipped: false, hints: nil)
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
context.draw(image, in: CGRect(origin: .zero, size: NSSize(width: finalWidth, height: finalWidth)))
|
||||
return context.makeImage()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class Screens {
|
||||
}
|
||||
|
||||
extension NSScreen {
|
||||
static var preferred: NSScreen = detectPreferred() ?? NSScreen.screens.first!
|
||||
static var preferred = NSScreen.screens.first!
|
||||
|
||||
static func updatePreferred() {
|
||||
preferred = detectPreferred() ?? NSScreen.screens.first!
|
||||
@@ -35,7 +35,9 @@ extension NSScreen {
|
||||
/// we find the screen with the key window ourselves manually
|
||||
static func active() -> NSScreen? {
|
||||
guard let frontmostPid = NSWorkspace.shared.frontmostApplication?.processIdentifier,
|
||||
let frontmostApp = Applications.findOrCreate(frontmostPid) else { return nil }
|
||||
// we avoid Applications.findOrCreate() here, because it active() is called very early during launch
|
||||
// we are not ready to create applications yet
|
||||
let frontmostApp = (Applications.list.first { $0.pid == frontmostPid }) else { return nil }
|
||||
guard let focusedWindow = frontmostApp.focusedWindow else { return NSScreen.withActiveMenubar() }
|
||||
// on the very first summon, this window may not have its spaces updated, which may land the wrong active screen
|
||||
focusedWindow.updateSpacesAndScreen()
|
||||
|
||||
+2
-2
@@ -299,6 +299,8 @@ extension App: NSApplicationDelegate {
|
||||
BackgroundWork.start()
|
||||
NSScreen.updatePreferred()
|
||||
Appearance.update()
|
||||
ThumbnailsPanel.updateMaxPossibleThumbnailSize()
|
||||
ThumbnailsPanel.updateMaxPossibleAppIconSize()
|
||||
Menubar.initialize()
|
||||
MainMenu.loadFromXib()
|
||||
self.thumbnailsPanel = ThumbnailsPanel()
|
||||
@@ -307,8 +309,6 @@ extension App: NSApplicationDelegate {
|
||||
Screens.refresh()
|
||||
SpacesEvents.observe()
|
||||
ScreensEvents.observe()
|
||||
ThumbnailsPanel.updateMaxPossibleThumbnailSize()
|
||||
ThumbnailsPanel.updateMaxPossibleAppIconSize()
|
||||
SystemAppearanceEvents.observe()
|
||||
SystemScrollerStyleEvents.observe()
|
||||
Applications.initialDiscovery()
|
||||
|
||||
Reference in new issue
Block a user