diff --git a/src/logic/Appearance.swift b/src/logic/Appearance.swift index 3558f0d1..0052897f 100644 --- a/src/logic/Appearance.swift +++ b/src/logic/Appearance.swift @@ -55,15 +55,14 @@ class Appearance { } private static func updateSize() { - let screen = NSScreen.preferred() - let isHorizontalScreen = screen.isHorizontal() - maxWidthOnScreen = AppearanceTestable.comfortableWidth(screen.physicalSize().map { $0.width }) + let isHorizontalScreen = NSScreen.preferred.isHorizontal() + maxWidthOnScreen = AppearanceTestable.comfortableWidth(NSScreen.preferred.physicalSize().map { $0.width }) if currentStyle == .appIcons { appIconsSize() } else if currentStyle == .titles { titlesSize(isHorizontalScreen) } else { - thumbnailsSize(isHorizontalScreen, screen) + thumbnailsSize(isHorizontalScreen) } } @@ -75,7 +74,7 @@ class Appearance { } } - private static func thumbnailsSize(_ isHorizontalScreen: Bool, _ screen: NSScreen) { + private static func thumbnailsSize(_ isHorizontalScreen: Bool) { hideThumbnails = false windowPadding = 18 cellCornerRadius = 10 @@ -95,7 +94,7 @@ class Appearance { iconSize = 32 fontHeight = 16 } - let thumbnailsPanelRatio = (screen.frame.width * maxWidthOnScreen) / (screen.frame.height * maxHeightOnScreen) + let thumbnailsPanelRatio = (NSScreen.preferred.frame.width * maxWidthOnScreen) / (NSScreen.preferred.frame.height * maxHeightOnScreen) (windowMinWidthInRow, windowMaxWidthInRow) = AppearanceTestable.goodValuesForThumbnailsWidthMinMax(thumbnailsPanelRatio, rowsCount) if currentVisibility == .highest { edgeInsetsSize = 10 diff --git a/src/logic/NSScreen.swift b/src/logic/NSScreen.swift index 87956fea..ea35ca24 100644 --- a/src/logic/NSScreen.swift +++ b/src/logic/NSScreen.swift @@ -1,6 +1,45 @@ import Cocoa extension NSScreen { + static var preferred: NSScreen = detectPreferred() ?? NSScreen.screens.first! + + static func updatePreferred() { + preferred = detectPreferred() ?? NSScreen.screens.first! + } + + private static func detectPreferred() -> NSScreen? { + switch Preferences.showOnScreen { + case .includingMouse: return withMouse() + case .active: return NSScreen.active() + case .includingMenubar: return NSScreen.screens.first + } + } + + /// NSScreen.main docs are incorrect. It stopped returning the screen with the key window in macOS 10.9 + /// see https://stackoverflow.com/a/56268826/2249756 + /// There are a few cases where .main doesn't return the screen with the key window: + /// * if the active screen shows a fullscreen app, it always returns screens[0] + /// * if NSScreen.screensHaveSeparateSpaces == false, and key window is on another screen than screens[0], it still returns screens[0] + /// we find the screen with the key window ourselves manually + static func active() -> NSScreen? { + if let app = Applications.find(NSWorkspace.shared.frontmostApplication?.processIdentifier) { + if let focusedWindow = app.focusedWindow { + return NSScreen.screens.first { focusedWindow.isOnScreen($0) } + } + return NSScreen.withActiveMenubar() + } + return nil + } + + /// there is only 1 active menubar. Other screens will show their menubar dimmed + static func withActiveMenubar() -> NSScreen? { + return NSScreen.screens.first { CGSCopyActiveMenuBarDisplayIdentifier(CGS_CONNECTION) == $0.uuid() } + } + + static func withMouse() -> NSScreen? { + return NSScreen.screens.first { NSMouseInRect(NSEvent.mouseLocation, $0.frame, false) } + } + func ratio() -> CGFloat { return frame.width / frame.height } @@ -41,43 +80,6 @@ extension NSScreen { return nil } - static func preferred() -> NSScreen { - preferred_() ?? NSScreen.screens.first! - } - - private static func preferred_() -> NSScreen? { - switch Preferences.showOnScreen { - case .includingMouse: return withMouse() - case .active: return NSScreen.active() - case .includingMenubar: return NSScreen.screens.first - } - } - - /// NSScreen.main docs are incorrect. It stopped returning the screen with the key window in macOS 10.9 - /// see https://stackoverflow.com/a/56268826/2249756 - /// There are a few cases where .main doesn't return the screen with the key window: - /// * if the active screen shows a fullscreen app, it always returns screens[0] - /// * if NSScreen.screensHaveSeparateSpaces == false, and key window is on another screen than screens[0], it still returns screens[0] - /// we find the screen with the key window ourselves manually - static func active() -> NSScreen? { - if let app = Applications.find(NSWorkspace.shared.frontmostApplication?.processIdentifier) { - if let focusedWindow = app.focusedWindow { - return NSScreen.screens.first { focusedWindow.isOnScreen($0) } - } - return NSScreen.withActiveMenubar() - } - return nil - } - - // there is only 1 active menubar. Other screens will show their menubar dimmed - static func withActiveMenubar() -> NSScreen? { - return NSScreen.screens.first { CGSCopyActiveMenuBarDisplayIdentifier(CGS_CONNECTION) == $0.uuid() } - } - - static func withMouse() -> NSScreen? { - return NSScreen.screens.first { NSMouseInRect(NSEvent.mouseLocation, $0.frame, false) } - } - func repositionPanel(_ window: NSWindow) { let screenFrame = visibleFrame let panelFrame = window.frame diff --git a/src/logic/Window.swift b/src/logic/Window.swift index f3186af1..eea22998 100644 --- a/src/logic/Window.swift +++ b/src/logic/Window.swift @@ -7,6 +7,7 @@ class Window { var creationOrder = Int.zero var title: String! var thumbnail: NSImage? + var thumbnailFullSize: NSSize? var icon: NSImage? { get { application.icon } } var shouldShowTheUser = true var isTabbed: Bool = false @@ -98,12 +99,13 @@ class Window { func refreshThumbnail(_ screenshot: NSImage?) { thumbnail = screenshot + thumbnailFullSize = screenshot?.size if App.app.appIsBeingUsed && shouldShowTheUser { if let index = (Windows.list.firstIndex { $0.cgWindowId == cgWindowId }) { let view = ThumbnailsView.recycledViews[index] if !view.thumbnail.isHidden { view.thumbnail.image = thumbnail - let thumbnailSize = ThumbnailView.thumbnailSize(thumbnail, NSScreen.preferred(), false) + let thumbnailSize = ThumbnailView.thumbnailSize(thumbnail, false) view.thumbnail.image?.size = thumbnailSize view.thumbnail.frame.size = thumbnailSize } diff --git a/src/logic/Windows.swift b/src/logic/Windows.swift index 3a8aa606..8745786d 100644 --- a/src/logic/Windows.swift +++ b/src/logic/Windows.swift @@ -262,7 +262,7 @@ class Windows { } } - static func updatesBeforeShowing(_ screen: NSScreen) -> Bool { + static func updatesBeforeShowing() -> Bool { if list.count == 0 || MissionControl.state() == .showAllWindows || MissionControl.state() == .showFrontWindows { return false } // TODO: find a way to update space info when spaces are changed, instead of on every trigger // workaround: when Preferences > Mission Control > "Displays have separate Spaces" is unchecked, @@ -275,9 +275,9 @@ class Windows { // TODO: can the CGS call inside detectTabbedWindows introduce latency when WindowServer is busy? detectTabbedWindows(window, cgsWindowIds, visibleCgsWindowIds) updatesWindowSpace(window) - refreshIfWindowShouldBeShownToTheUser(window, screen) + refreshIfWindowShouldBeShownToTheUser(window) } - refreshWhichWindowsToShowTheUser(screen) + refreshWhichWindowsToShowTheUser() sort() if (!list.contains { $0.shouldShowTheUser }) { return false } return true @@ -337,7 +337,7 @@ class Windows { } } - static func refreshWhichWindowsToShowTheUser(_ screen: NSScreen) { + static func refreshWhichWindowsToShowTheUser() { if Preferences.onlyShowApplications() { // Group windows by application and select the optimal main window let windowsGroupedByApp = Dictionary(grouping: list) { $0.application.pid } @@ -353,7 +353,7 @@ class Windows { } } - private static func refreshIfWindowShouldBeShownToTheUser(_ window: Window, _ screen: NSScreen) { + private static func refreshIfWindowShouldBeShownToTheUser(_ window: Window) { window.shouldShowTheUser = !(window.application.runningApplication.bundleIdentifier.flatMap { id in Preferences.blacklist.contains { @@ -368,7 +368,7 @@ class Windows { !(!(Preferences.showFullscreenWindows[App.app.shortcutIndex] != .hide) && window.isFullscreen) && !(!(Preferences.showMinimizedWindows[App.app.shortcutIndex] != .hide) && window.isMinimized) && !(Preferences.spacesToShow[App.app.shortcutIndex] == .visible && !Spaces.visibleSpaces.contains(window.spaceId)) && - !(Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab && !window.isOnScreen(screen)) && + !(Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab && !window.isOnScreen(NSScreen.preferred)) && (Preferences.showTabsAsWindows || !window.isTabbed)) } diff --git a/src/ui/App.swift b/src/ui/App.swift index 0573f42b..4fa2469a 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -145,7 +145,8 @@ class App: AppCenterApplication { func showSecondaryWindow(_ window: NSWindow?) { if let window = window { - NSScreen.preferred().repositionPanel(window) + NSScreen.updatePreferred() + NSScreen.preferred.repositionPanel(window) App.shared.activate(ignoringOtherApps: true) window.makeKeyAndOrderFront(nil) // Use the center function to continue to center, the `repositionPanel` function cannot center, it may be a system bug @@ -201,19 +202,19 @@ class App: AppCenterApplication { return } guard appIsBeingUsed else { return } - let currentScreen = NSScreen.preferred() // fix screen between steps since it could change (e.g. mouse moved to another screen) if !skipUpdatesBeforeShowing { - if !Windows.updatesBeforeShowing(currentScreen) { hideUi(); return } + if !Windows.updatesBeforeShowing() { hideUi(); return } } guard appIsBeingUsed else { return } Windows.updateFocusedWindowIndex() guard appIsBeingUsed else { return } - thumbnailsPanel.thumbnailsView.updateItemsAndLayout(currentScreen) + print("updateItemsAndLayout") + thumbnailsPanel.thumbnailsView.updateItemsAndLayout() guard appIsBeingUsed else { return } thumbnailsPanel.setContentSize(thumbnailsPanel.thumbnailsView.frame.size) thumbnailsPanel.display() guard appIsBeingUsed else { return } - currentScreen.repositionPanel(thumbnailsPanel) + NSScreen.preferred.repositionPanel(thumbnailsPanel) guard appIsBeingUsed else { return } Windows.voiceOverWindow() // at this point ThumbnailViews are assigned to the window, and ready guard appIsBeingUsed else { return } @@ -232,16 +233,16 @@ class App: AppCenterApplication { } isFirstSummon = false self.shortcutIndex = shortcutIndex - let screen = NSScreen.preferred() - if !Windows.updatesBeforeShowing(screen) { hideUi(); return } + NSScreen.updatePreferred() + if !Windows.updatesBeforeShowing() { hideUi(); return } Windows.setInitialFocusedAndHoveredWindowIndex() if Preferences.windowDisplayDelay == DispatchTimeInterval.milliseconds(0) { - buildUiAndShowPanel(screen) + buildUiAndShowPanel() } else { delayedDisplayScheduled += 1 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Preferences.windowDisplayDelay) { () -> () in if self.delayedDisplayScheduled == 1 { - self.buildUiAndShowPanel(screen) + self.buildUiAndShowPanel() } self.delayedDisplayScheduled -= 1 } @@ -252,7 +253,7 @@ class App: AppCenterApplication { } } - func buildUiAndShowPanel(_ screen: NSScreen = NSScreen.preferred()) { + func buildUiAndShowPanel() { guard appIsBeingUsed else { return } Appearance.update() guard appIsBeingUsed else { return } @@ -299,6 +300,7 @@ extension App: NSApplicationDelegate { SystemPermissions.ensurePermissionsAreGranted { [weak self] in guard let self = self else { return } BackgroundWork.start() + NSScreen.updatePreferred() Appearance.update() Menubar.initialize() self.loadMainMenuXib() diff --git a/src/ui/main-window/ThumbnailView.swift b/src/ui/main-window/ThumbnailView.swift index dd3cbea2..3c89755f 100644 --- a/src/ui/main-window/ThumbnailView.swift +++ b/src/ui/main-window/ThumbnailView.swift @@ -95,11 +95,11 @@ class ThumbnailView: FlippedView { observeDragAndDrop() } - func updateRecycledCellWithNewContent(_ element: Window, _ index: Int, _ newHeight: CGFloat, _ screen: NSScreen) { + func updateRecycledCellWithNewContent(_ element: Window, _ index: Int, _ newHeight: CGFloat) { window_ = element - updateValues(element, index, newHeight, screen) - updateSizes(newHeight, screen) - updatePositions(newHeight, screen) + updateValues(element, index, newHeight) + updateSizes(newHeight) + updatePositions(newHeight) label.toolTip = label.cell!.cellSize.width >= label.frame.size.width ? label.stringValue : nil } @@ -298,7 +298,36 @@ class ThumbnailView: FlippedView { view.label.toolTip = view.label.cell!.cellSize.width >= view.label.frame.size.width ? view.label.stringValue : nil } - private func updateValues(_ element: Window, _ index: Int, _ newHeight: CGFloat, _ screen: NSScreen) { + private func updateThumbnail(_ element: Window) { + // we need to reset the original size, otherwise it may be too small and not get resized + // this can happen when switching from one screen to another for example + if let screenshot = element.thumbnail, let thumbnailFullSize = element.thumbnailFullSize { + screenshot.size = thumbnailFullSize + } + if !thumbnail.isHidden && thumbnail != element.thumbnail { + if let screenshot = element.thumbnail { + thumbnail.image = screenshot + } else if let appIconFallback = element.icon { + // if no thumbnail, show appIcon instead + // .icon is always 32x32 by default. We scale it so it can be "thumbnail-ed" down + appIconFallback.size = NSSize(width: 1024, height: 1024) + thumbnail.image = appIconFallback + } + // for Accessibility > "speak items under the pointer" + thumbnail.setAccessibilityLabel(element.title) + } + } + + private func updateAppIcon(_ element: Window, _ title: String) -> Bool { + let appIconChanged = appIcon.image != element.icon + if appIconChanged { + appIcon.image = element.icon + appIcon.setAccessibilityLabel(title) + } + return appIconChanged + } + + private func updateValues(_ element: Window, _ index: Int, _ newHeight: CGFloat) { assignIfDifferent(&thumbnail.isHidden, Appearance.hideThumbnails || element.isWindowlessApp) assignIfDifferent(&windowlessIcon.isHidden, !element.isWindowlessApp || Appearance.hideThumbnails) assignIfDifferent(&windowlessAppIndicator.isHidden, !element.isWindowlessApp) @@ -310,11 +339,7 @@ class ThumbnailView: FlippedView { NSScreen.screens.count < 2 || Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab ) )) - if !thumbnail.isHidden { - thumbnail.image = element.thumbnail - // for Accessibility > "speak items under the pointer" - thumbnail.setAccessibilityLabel(element.title) - } + updateThumbnail(element) let title = getAppOrAndWindowTitle() let labelChanged = label.stringValue != title if labelChanged { @@ -331,11 +356,7 @@ class ThumbnailView: FlippedView { spaceIcon.toolTip = String(format: NSLocalizedString("Window is on Space %d", comment: ""), element.spaceIndex) } } - let appIconChanged = appIcon.image != element.icon - if appIconChanged { - appIcon.image = element.icon - appIcon.setAccessibilityLabel(title) - } + let appIconChanged = updateAppIcon(element, title) let dockLabelChanged = updateDockLabelIcon(element.dockLabel) if appIconChanged || dockLabelChanged { setAccessibilityHelp(getAccessibilityHelp(element.application.runningApplication.localizedName, element.dockLabel)) @@ -349,19 +370,19 @@ class ThumbnailView: FlippedView { mouseMovedCallback = { () -> Void in Windows.updateFocusedAndHoveredWindowIndex(index, true) } } - private func updateSizes(_ newHeight: CGFloat, _ screen: NSScreen) { + private func updateSizes(_ newHeight: CGFloat) { if Preferences.appearanceStyle == .thumbnails { if !thumbnail.isHidden { - let thumbnailSize = ThumbnailView.thumbnailSize(thumbnail.image, screen, false) + let thumbnailSize = ThumbnailView.thumbnailSize(thumbnail.image, false) thumbnail.setSize(thumbnailSize) } if !windowlessIcon.isHidden { - let windowlessIconSize = ThumbnailView.thumbnailSize(windowlessIcon.image, screen, true) + let windowlessIconSize = ThumbnailView.thumbnailSize(windowlessIcon.image, true) windowlessIcon.setSize(windowlessIconSize) } } - setFrameWidthHeight(screen, newHeight) - let appIconSize = ThumbnailView.iconSize(screen) + setFrameWidthHeight(newHeight) + let appIconSize = ThumbnailView.iconSize() appIcon.setSize(appIconSize) if Preferences.appearanceStyle == .appIcons { vStackView.frame.size = NSSize(width: frame.width, height: appIcon.frame.height + Appearance.edgeInsetsSize * 2) @@ -378,7 +399,7 @@ class ThumbnailView: FlippedView { } } - private func updatePositions(_ newHeight: CGFloat, _ screen: NSScreen) { + private func updatePositions(_ newHeight: CGFloat) { hStackView.frame.origin = NSPoint(x: Appearance.edgeInsetsSize, y: Appearance.edgeInsetsSize) if Preferences.appearanceStyle != .appIcons { appIcon.frame.origin.x = App.shared.userInterfaceLayoutDirection == .leftToRight @@ -426,7 +447,7 @@ class ThumbnailView: FlippedView { windowlessAppIndicator.frame.origin.y = windowlessAppIndicator.superview!.frame.height - windowlessAppIndicator.frame.height } if !dockLabelIcon.isHidden { - let iconSize = ThumbnailView.iconSize(screen) + let iconSize = ThumbnailView.iconSize() dockLabelIcon.frame.origin.x = ((iconSize.width * 0.8) - (dockLabelIcon.fittingSize.width / 2)).rounded() dockLabelIcon.frame.origin.y = ((iconSize.height * 0.8) - (dockLabelIcon.fittingSize.height / 2)).rounded() - (Preferences.appearanceSize == .small ? 2 : 0) @@ -449,18 +470,18 @@ class ThumbnailView: FlippedView { return windowTitle ?? "" } - private func setFrameWidthHeight(_ screen: NSScreen, _ newHeight: CGFloat) { + private func setFrameWidthHeight(_ newHeight: CGFloat) { var contentWidth = CGFloat(0) if Preferences.appearanceStyle == .thumbnails { // Preferred to the width of the image, and the minimum width may be set to be large. contentWidth = (!windowlessIcon.isHidden ? windowlessIcon : thumbnail).frame.size.width } else if Preferences.appearanceStyle == .titles { - contentWidth = ThumbnailView.maxThumbnailWidth(screen) - Appearance.edgeInsetsSize * 2 + contentWidth = ThumbnailView.maxThumbnailWidth() - Appearance.edgeInsetsSize * 2 } else { contentWidth = Appearance.iconSize } let frameWidth = (contentWidth + Appearance.edgeInsetsSize * 2).rounded() - let widthMin = ThumbnailView.minThumbnailWidth(screen) + let widthMin = ThumbnailView.minThumbnailWidth() let width = max(frameWidth, widthMin).rounded() assignIfDifferent(&frame.size.width, width) assignIfDifferent(&frame.size.height, newHeight) @@ -489,7 +510,7 @@ class ThumbnailView: FlippedView { } static func dockLabelLabelSize() -> CGFloat { - let size = (ThumbnailView.iconSize(NSScreen.preferred()).width * 0.43).rounded() + let size = (ThumbnailView.iconSize().width * 0.43).rounded() // label should have a minimum size for readability return max(size, 13) } @@ -505,33 +526,28 @@ class ThumbnailView: FlippedView { return shadow } - static func maxThumbnailWidth(_ screen: NSScreen) -> CGFloat { - return ThumbnailsPanel.maxThumbnailsWidth(screen) * Appearance.windowMaxWidthInRow - Appearance.interCellPadding * 2 + static func maxThumbnailWidth() -> CGFloat { + return ThumbnailsPanel.maxThumbnailsWidth() * Appearance.windowMaxWidthInRow - Appearance.interCellPadding * 2 } - static func minThumbnailWidth(_ screen: NSScreen) -> CGFloat { - return ThumbnailsPanel.maxThumbnailsWidth(screen) * Appearance.windowMinWidthInRow - Appearance.interCellPadding * 2 + static func minThumbnailWidth() -> CGFloat { + return ThumbnailsPanel.maxThumbnailsWidth() * Appearance.windowMinWidthInRow - Appearance.interCellPadding * 2 } /// The maximum height that a thumbnail can be drawn - /// /// maxThumbnailsHeight = maxThumbnailHeight * rowCount + interCellPadding * (rowCount - 1) - /// /// maxThumbnailHeight = (maxThumbnailsHeight - interCellPadding * (rowCount - 1)) / rowCount - /// - /// - Parameter screen: - /// - Returns: - static func maxThumbnailHeight(_ screen: NSScreen) -> CGFloat { - return (ThumbnailsPanel.maxThumbnailsHeight(screen) - Appearance.interCellPadding) / Appearance.rowsCount - Appearance.interCellPadding + static func maxThumbnailHeight() -> CGFloat { + return ((ThumbnailsPanel.maxThumbnailsHeight() - Appearance.interCellPadding) / Appearance.rowsCount - Appearance.interCellPadding).rounded() } - static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen, _ isWindowlessApp: Bool) -> NSSize { + static func thumbnailSize(_ image: NSImage?, _ isWindowlessApp: Bool) -> NSSize { guard let image = image else { return NSSize(width: 0, height: 0) } - let thumbnailHeightMax = ThumbnailView.maxThumbnailHeight(screen) + let thumbnailHeightMax = ThumbnailView.maxThumbnailHeight() - Appearance.edgeInsetsSize * 2 - Appearance.intraCellPadding - Appearance.iconSize - let thumbnailWidthMax = ThumbnailView.maxThumbnailWidth(screen) + let thumbnailWidthMax = ThumbnailView.maxThumbnailWidth() - Appearance.edgeInsetsSize * 2 // don't stretch very small windows; keep them 1:1 in the switcher if !isWindowlessApp && image.size.width < thumbnailWidthMax && image.size.height < thumbnailHeightMax { @@ -559,9 +575,9 @@ class ThumbnailView: FlippedView { return NSSize(width: width.rounded(), height: height.rounded()) } - static func iconSize(_ screen: NSScreen) -> NSSize { + static func iconSize() -> NSSize { if Preferences.appearanceStyle == .appIcons { - let widthMin = ThumbnailView.minThumbnailWidth(screen) + let widthMin = ThumbnailView.minThumbnailWidth() let contentWidth = Appearance.iconSize let frameWidth = contentWidth + Appearance.edgeInsetsSize * 2 let width = max(frameWidth, widthMin).rounded() @@ -573,12 +589,12 @@ class ThumbnailView: FlippedView { return NSSize(width: Appearance.iconSize, height: Appearance.iconSize) } - static func height(_ screen: NSScreen, _ labelHeight: CGFloat) -> CGFloat { + static func height(_ labelHeight: CGFloat) -> CGFloat { if Preferences.appearanceStyle == .titles { - return max(ThumbnailView.iconSize(screen).height, labelHeight) + Appearance.edgeInsetsSize * 2 + return max(ThumbnailView.iconSize().height, labelHeight) + Appearance.edgeInsetsSize * 2 } else if Preferences.appearanceStyle == .appIcons { - return ThumbnailView.iconSize(screen).height + Appearance.edgeInsetsSize * 2 + Appearance.intraCellPadding * 2 + labelHeight + return ThumbnailView.iconSize().height + Appearance.edgeInsetsSize * 2 + Appearance.intraCellPadding * 2 + labelHeight } - return ThumbnailView.maxThumbnailHeight(screen).rounded(.down) + return ThumbnailView.maxThumbnailHeight() } } diff --git a/src/ui/main-window/ThumbnailsPanel.swift b/src/ui/main-window/ThumbnailsPanel.swift index 18755e22..67d00158 100644 --- a/src/ui/main-window/ThumbnailsPanel.swift +++ b/src/ui/main-window/ThumbnailsPanel.swift @@ -44,12 +44,12 @@ class ThumbnailsPanel: NSPanel { thumbnailsView.scrollView.flashScrollers() } - static func maxThumbnailsWidth(_ screen: NSScreen) -> CGFloat { - return screen.frame.width * Appearance.maxWidthOnScreen - Appearance.windowPadding * 2 + static func maxThumbnailsWidth() -> CGFloat { + return (NSScreen.preferred.frame.width * Appearance.maxWidthOnScreen - Appearance.windowPadding * 2).rounded() } - static func maxThumbnailsHeight(_ screen: NSScreen) -> CGFloat { - return screen.frame.height * Appearance.maxHeightOnScreen - Appearance.windowPadding * 2 + static func maxThumbnailsHeight() -> CGFloat { + return (NSScreen.preferred.frame.height * Appearance.maxHeightOnScreen - Appearance.windowPadding * 2).rounded() } } diff --git a/src/ui/main-window/ThumbnailsView.swift b/src/ui/main-window/ThumbnailsView.swift index 39d447dd..8f92d8b7 100644 --- a/src/ui/main-window/ThumbnailsView.swift +++ b/src/ui/main-window/ThumbnailsView.swift @@ -22,6 +22,7 @@ class ThumbnailsView: NSVisualEffectView { func reset() { // it would be nicer to remove this whole "reset" logic, and instead update each component to check Appearance properties before showing // Maybe in some Appkit willDraw() function that triggers before drawing it + NSScreen.updatePreferred() Appearance.update() material = Appearance.material for i in 0.. (CGFloat, CGFloat, CGFloat)? { + private func layoutThumbnailViews(_ widthMax: CGFloat) -> (CGFloat, CGFloat, CGFloat)? { let labelHeight = ThumbnailsView.recycledViews.first!.label.cell!.cellSize.height - let height = ThumbnailView.height(screen, labelHeight) + let height = ThumbnailView.height(labelHeight) let isLeftToRight = App.shared.userInterfaceLayoutDirection == .leftToRight let startingX = isLeftToRight ? Appearance.interCellPadding : widthMax - Appearance.interCellPadding var currentX = startingX @@ -136,7 +137,7 @@ class ThumbnailsView: NSVisualEffectView { guard App.app.appIsBeingUsed else { return nil } guard window.shouldShowTheUser else { continue } let view = ThumbnailsView.recycledViews[index] - view.updateRecycledCellWithNewContent(window, index, height, screen) + view.updateRecycledCellWithNewContent(window, index, height) let width = view.frame.size.width let projectedX = projectedWidth(currentX, width).rounded(.down) if needNewLine(projectedX, widthMax) { @@ -177,8 +178,8 @@ class ThumbnailsView: NSVisualEffectView { App.shared.userInterfaceLayoutDirection == .leftToRight ? currentX : currentX - width } - private func layoutParentViews(_ screen: NSScreen, _ maxX: CGFloat, _ widthMax: CGFloat, _ maxY: CGFloat, _ labelHeight: CGFloat) { - let heightMax = ThumbnailsPanel.maxThumbnailsHeight(screen).rounded() + private func layoutParentViews(_ maxX: CGFloat, _ widthMax: CGFloat, _ maxY: CGFloat, _ labelHeight: CGFloat) { + let heightMax = ThumbnailsPanel.maxThumbnailsHeight() ThumbnailsView.thumbnailsWidth = min(maxX, widthMax) ThumbnailsView.thumbnailsHeight = min(maxY, heightMax) let frameWidth = ThumbnailsView.thumbnailsWidth + Appearance.windowPadding * 2