fix: app-icons wouldn't show when permissions were skipped

also cached NSScreen.preferred for performance
This commit is contained in:
lwouis committed 2025-01-03 23:40:01 +01:00
1 parent f027b4795f
commit 837fa03f64
8 files changed
+141 -119

No files matched your search

+5 -6
View File
@@ -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
+39 -37
View File
@@ -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
+3 -1
View File
@@ -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
}
+6 -6
View File
@@ -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))
}
+12 -10
View File
@@ -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()
+62 -46
View File
@@ -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()
}
}
+4 -4
View File
@@ -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()
}
}
+10 -9
View File
@@ -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..<ThumbnailsView.recycledViews.count {
@@ -101,10 +102,10 @@ class ThumbnailsView: NSVisualEffectView {
}
}
func updateItemsAndLayout(_ screen: NSScreen) {
let widthMax = ThumbnailsPanel.maxThumbnailsWidth(screen).rounded()
if let (maxX, maxY, labelHeight) = layoutThumbnailViews(screen, widthMax) {
layoutParentViews(screen, maxX, widthMax, maxY, labelHeight)
func updateItemsAndLayout() {
let widthMax = ThumbnailsPanel.maxThumbnailsWidth().rounded()
if let (maxX, maxY, labelHeight) = layoutThumbnailViews(widthMax) {
layoutParentViews(maxX, widthMax, maxY, labelHeight)
if Preferences.alignThumbnails == .center {
centerRows(maxX)
}
@@ -120,9 +121,9 @@ class ThumbnailsView: NSVisualEffectView {
}
}
private func layoutThumbnailViews(_ screen: NSScreen, _ widthMax: CGFloat) -> (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