diff --git a/src/logic/DebugProfile.swift b/src/logic/DebugProfile.swift index 87a34673..4c731e6d 100644 --- a/src/logic/DebugProfile.swift +++ b/src/logic/DebugProfile.swift @@ -85,8 +85,8 @@ class DebugProfile { ("isTabbed", String(window.isTabbed)), ("isOnAllSpaces", String(window.isOnAllSpaces)), ("shouldShowTheUser", String(window.shouldShowTheUser)), - ("spaceId", String(window.spaceId)), - ("spaceIndex", String(window.spaceIndex)), + ("spaceIds", window.spaceIds.map(String.init).joined(separator: interSeparator)), + ("spaceIndexes", window.spaceIndexes.map(String.init).joined(separator: interSeparator)), ]) } diff --git a/src/logic/NSScreen.swift b/src/logic/NSScreen.swift index ea35ca24..1d1268b9 100644 --- a/src/logic/NSScreen.swift +++ b/src/logic/NSScreen.swift @@ -24,6 +24,8 @@ extension NSScreen { static func active() -> NSScreen? { if let app = Applications.find(NSWorkspace.shared.frontmostApplication?.processIdentifier) { if let focusedWindow = app.focusedWindow { + // on the very first summon, this window may not have its spaces updated, which may land the wrong active screen + Windows.updatesWindowSpace(focusedWindow) return NSScreen.screens.first { focusedWindow.isOnScreen($0) } } return NSScreen.withActiveMenubar() diff --git a/src/logic/Window.swift b/src/logic/Window.swift index bac18313..3ea23104 100644 --- a/src/logic/Window.swift +++ b/src/logic/Window.swift @@ -19,8 +19,8 @@ class Window { var isWindowlessApp = false var position: CGPoint? var size: CGSize? - var spaceId = CGSSpaceID.max - var spaceIndex = SpaceIndex.max + var spaceIds = [CGSSpaceID.max] + var spaceIndexes = [SpaceIndex.max] var axUiElement: AXUIElement! var application: Application var axObserver: AXObserver? @@ -40,8 +40,7 @@ class Window { self.axUiElement = axUiElement self.application = application cgWindowId = wid - spaceId = Spaces.currentSpaceId - spaceIndex = Spaces.currentSpaceIndex + Windows.updatesWindowSpace(self) self.isFullscreen = isFullscreen self.isMinimized = isMinimized self.position = position @@ -232,10 +231,11 @@ class Window { return application.localizedName ?? "" } + /// window may not be visible on that screen (e.g. the window is not on the current Space) func isOnScreen(_ screen: NSScreen) -> Bool { if NSScreen.screensHaveSeparateSpaces { if let screenUuid = screen.uuid(), let screenSpaces = Spaces.screenSpacesMap[screenUuid] { - return screenSpaces.contains { $0 == spaceId } + return screenSpaces.contains { screenSpace in spaceIds.contains { $0 == screenSpace } } } } else { let referenceWindow = referenceWindowForTabbedWindow() diff --git a/src/logic/Windows.swift b/src/logic/Windows.swift index 64a1cc76..7d5a5825 100644 --- a/src/logic/Windows.swift +++ b/src/logic/Windows.swift @@ -51,7 +51,15 @@ class Windows { order = compareByAppNameThenWindowTitle($0, $1) } if sortType == .space { - order = $0.spaceIndex.compare($1.spaceIndex) + if $0.isOnAllSpaces && $1.isOnAllSpaces { + order = .orderedSame + } else if $0.isOnAllSpaces { + order = .orderedAscending + } else if $1.isOnAllSpaces { + order = .orderedDescending + } else if let spaceIndex0 = $0.spaceIndexes.first, let spaceIndex1 = $1.spaceIndexes.first { + order = spaceIndex0.compare(spaceIndex1) + } if order == .orderedSame { order = compareByAppNameThenWindowTitle($0, $1) } @@ -283,21 +291,15 @@ class Windows { return true } - private static func updatesWindowSpace(_ window: Window) { + static func updatesWindowSpace(_ window: Window) { // macOS bug: if you tab a window, then move the tab group to another space, other tabs from the tab group will stay on the current space // you can use the Dock to focus one of the other tabs and it will teleport that tab in the current space, proving that it's a macOS bug // note: for some reason, it behaves differently if you minimize the tab group after moving it to another space if let cgWindowId = window.cgWindowId { let spaceIds = cgWindowId.spaces() - if spaceIds.count == 1 { - window.spaceId = spaceIds.first! - window.spaceIndex = Spaces.idsAndIndexes.first { $0.0 == spaceIds.first! }!.1 - window.isOnAllSpaces = false - } else if spaceIds.count > 1 { - window.spaceId = Spaces.currentSpaceId - window.spaceIndex = Spaces.currentSpaceIndex - window.isOnAllSpaces = true - } + window.spaceIds = spaceIds + window.spaceIndexes = spaceIds.map { spaceId in Spaces.idsAndIndexes.first { $0.0 == spaceId }!.1 } + window.isOnAllSpaces = spaceIds.count > 1 } } @@ -358,7 +360,7 @@ class Windows { !window.isWindowlessApp && !(!(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.spacesToShow[App.app.shortcutIndex] == .visible && !Spaces.visibleSpaces.contains { visibleSpace in window.spaceIds.contains { $0 == visibleSpace } }) && !(Preferences.screensToShow[App.app.shortcutIndex] == .showingAltTab && !window.isOnScreen(NSScreen.preferred)) && (Preferences.showTabsAsWindows || !window.isTabbed)) } diff --git a/src/ui/main-window/ThumbnailView.swift b/src/ui/main-window/ThumbnailView.swift index ed0782e0..50b4949b 100644 --- a/src/ui/main-window/ThumbnailView.swift +++ b/src/ui/main-window/ThumbnailView.swift @@ -351,12 +351,13 @@ class ThumbnailView: FlippedView { } label.updateTruncationModeIfNeeded() if !spaceIcon.isHidden { - if element.spaceIndex > 30 || element.isOnAllSpaces { + let spaceIndex = element.spaceIndexes.first + if element.isOnAllSpaces || (spaceIndex != nil && spaceIndex! > 30) { spaceIcon.setStar() spaceIcon.toolTip = NSLocalizedString("Window is on every Space", comment: "") - } else { - spaceIcon.setNumber(element.spaceIndex, false) - spaceIcon.toolTip = String(format: NSLocalizedString("Window is on Space %d", comment: ""), element.spaceIndex) + } else if let spaceIndex { + spaceIcon.setNumber(spaceIndex, false) + spaceIcon.toolTip = String(format: NSLocalizedString("Window is on Space %d", comment: ""), spaceIndex) } } let appIconChanged = updateAppIcon(element, title)