Ariver
2026-05-24 3b4a0887d287c890092fc0845eeb57e9a5b03bcd
Fix Split View fullscreen overlay detection
2 files modified
5 files renamed
198 ■■■■■ changed files
Apptag/ApptagApp.swift 88 ●●●● patch | view | raw | blame | history
Release/AppStore-7.6.0-20260524.1652/APP_STORE_CONNECT_METADATA.md patch | view | raw | blame | history
Release/AppStore-7.6.0-20260524.1652/BUILD_SIGN_UPLOAD.md 2 ●●● patch | view | raw | blame | history
Release/AppStore-7.6.0-20260524.1652/FIRST_TIME_MAC_APP_STORE_TODO.md patch | view | raw | blame | history
Release/AppStore-7.6.0-20260524.1652/QA_RELEASE_EVIDENCE.md 7 ●●●●● patch | view | raw | blame | history
Release/AppStore-7.6.0-20260524.1652/README.md 5 ●●●●● patch | view | raw | blame | history
Scripts/window_logic_qa.sh 96 ●●●●● patch | view | raw | blame | history
Apptag/ApptagApp.swift
@@ -74,6 +74,11 @@
        let frame: NSRect
    }
    private struct ForeignWindowFrame {
        let owner: String
        let frame: NSRect
    }
    private var isOverlayVisible: Bool {
        overlayWindow?.isVisible == true
    }
@@ -882,8 +887,18 @@
    private func hasFullscreenWindowOnScreen(_ screen: NSScreen) -> Bool {
        let screenFrame = screen.frame
        let windowFrames = foreignLayerZeroWindows(on: screenFrame)
        if windowFrames.contains(where: { isSingleFullscreenWindow($0.frame, on: screenFrame) }) {
            return true
        }
        return hasSplitViewFullscreenWindows(windowFrames, on: screenFrame)
    }
    private func foreignLayerZeroWindows(on screenFrame: NSRect) -> [ForeignWindowFrame] {
        let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? []
        return windows.contains { info in
        return windows.compactMap { info in
            guard let owner = info[kCGWindowOwnerName as String] as? String,
                  owner != AppIdentity.displayName,
                  owner != "Window Server",
@@ -892,20 +907,71 @@
                  let layer = info[kCGWindowLayer as String] as? Int,
                  layer == 0,
                  let bounds = info[kCGWindowBounds as String] as? NSDictionary
            else { return false }
            else { return nil }
            let x = cgWindowDimension(bounds, "X")
            let y = cgWindowDimension(bounds, "Y")
            let width = cgWindowDimension(bounds, "Width")
            let height = cgWindowDimension(bounds, "Height")
            let windowFrame = NSRect(x: x, y: y, width: width, height: height)
            let widthMatches = abs(windowFrame.width - screenFrame.width) <= 12
            let heightMatches = windowFrame.height >= screenFrame.height * 0.88
            let horizontallyAligned = abs(windowFrame.midX - screenFrame.midX) <= 12
            return widthMatches && heightMatches && horizontallyAligned
            let frame = NSRect(
                x: cgWindowDimension(bounds, "X"),
                y: cgWindowDimension(bounds, "Y"),
                width: cgWindowDimension(bounds, "Width"),
                height: cgWindowDimension(bounds, "Height")
            )
            guard frame.intersects(screenFrame) else { return nil }
            return ForeignWindowFrame(owner: owner, frame: frame)
        }
    }
    private func isSingleFullscreenWindow(_ windowFrame: NSRect, on screenFrame: NSRect) -> Bool {
        let widthMatches = abs(windowFrame.width - screenFrame.width) <= 12
        let heightMatches = windowFrame.height >= screenFrame.height * 0.88
        let horizontallyAligned = abs(windowFrame.midX - screenFrame.midX) <= 12
        let verticallyAligned = abs(windowFrame.maxY - screenFrame.maxY) <= 32
        return widthMatches && heightMatches && horizontallyAligned && verticallyAligned
    }
    private func hasSplitViewFullscreenWindows(_ windows: [ForeignWindowFrame], on screenFrame: NSRect) -> Bool {
        let clippedWindows = windows.map {
            ForeignWindowFrame(owner: $0.owner, frame: $0.frame.intersection(screenFrame))
        }
        let tallWindows = clippedWindows
            .filter { window in
                let frame = window.frame
                return frame.height >= screenFrame.height * 0.86
                    && frame.width >= screenFrame.width * 0.20
                    && frame.width <= screenFrame.width * 0.86
                    && abs(frame.maxY - screenFrame.maxY) <= 32
            }
            .sorted { $0.frame.minX < $1.frame.minX }
        guard tallWindows.count >= 2 else { return false }
        for startIndex in tallWindows.indices {
            var union = tallWindows[startIndex].frame
            var lastMaxX = union.maxX
            var distinctOwners = Swift.Set<String>()
            distinctOwners.insert(tallWindows[startIndex].owner)
            for window in tallWindows.dropFirst(startIndex + 1) {
                let gap = window.frame.minX - lastMaxX
                if gap < -32 || gap > 48 {
                    break
                }
                union = union.union(window.frame)
                lastMaxX = max(lastMaxX, window.frame.maxX)
                distinctOwners.insert(window.owner)
                let touchesLeft = abs(union.minX - screenFrame.minX) <= 32
                let touchesRight = abs(union.maxX - screenFrame.maxX) <= 32
                let coversWidth = union.width >= screenFrame.width * 0.92
                let coversHeight = union.height >= screenFrame.height * 0.86
                if distinctOwners.count >= 2 && touchesLeft && touchesRight && coversWidth && coversHeight {
                    return true
                }
            }
        }
        return false
    }
    private func cgWindowDimension(_ bounds: NSDictionary, _ key: String) -> CGFloat {
        if let value = bounds[key] as? CGFloat {
            return value
Release/AppStore-7.6.0-20260524.1652/APP_STORE_CONNECT_METADATA.md
Release/AppStore-7.6.0-20260524.1652/BUILD_SIGN_UPLOAD.md
File was renamed from Release/AppStore-7.6.0-20260523.2335/BUILD_SIGN_UPLOAD.md
@@ -50,7 +50,7 @@
APP_STORE=1 \
CODESIGN_IDENTITY="3rd Party Mac Developer Application: <TEAM NAME> (<TEAMID>)" \
APP_BUILD=20260523.2335 \
APP_BUILD=20260524.1652 \
bash build.sh
productbuild \
Release/AppStore-7.6.0-20260524.1652/FIRST_TIME_MAC_APP_STORE_TODO.md
Release/AppStore-7.6.0-20260524.1652/QA_RELEASE_EVIDENCE.md
File was renamed from Release/AppStore-7.6.0-20260523.2335/QA_RELEASE_EVIDENCE.md
@@ -3,7 +3,7 @@
## Local Build
- Version: `7.6.0`
- Build: `20260523.2335`
- Build: `20260524.1652`
- App path: `/Users/ar/Projects/Taglauncher/build/TagLauncher.app`
- DMG path: `/Users/ar/Projects/Taglauncher/build/TagLauncher.dmg`
- App executable size: `1.4M`
@@ -12,8 +12,8 @@
## Hashes
```text
370adb4ad671ec910cc0edf7e6f1ae3ebdd59cbd063f5d8439f2c7e8b05fd0e1  build/TagLauncher.dmg
9f808b6fc81b587a1508aa31c261cdbe187a3b7727daf8bf163788ba49eb2333  build/TagLauncher.app/Contents/MacOS/TagLauncher
1bf3e53410e18778038c310e1ed083cd89c27b781cc87942dd3dd9fb57d73cb2  build/TagLauncher.dmg
13e74a774662dfec88e69b5f51e5c51c5c46e3e5f8884cbf8cbab5cd44c4442d  build/TagLauncher.app/Contents/MacOS/TagLauncher
```
## Commands Run
@@ -42,6 +42,7 @@
- Fullscreen Space overlay appears above the current fullscreen app.
- Fullscreen Space overlay is checked with `showDockIcon=true` and `showDockIcon=false`.
- Fullscreen Space overlay bounds must match the fullscreen target display and remain stable across repeated samples.
- Split View fullscreen geometry is checked for 50/50 and 33/67 split layouts, while ordinary side-by-side desktop windows are rejected.
- App grid claims foreground, hides Dock, and keeps menu bar visible.
- Settings floats above app grid.
- File panel floats above Settings.
Release/AppStore-7.6.0-20260524.1652/README.md
File was renamed from Release/AppStore-7.6.0-20260523.2335/README.md
@@ -8,9 +8,9 @@
- Platform: macOS / Mac App Store
- Bundle ID: `com.taglauncher.app`
- Version: `7.6.0`
- Local QA build: `20260523.2335`
- Local QA build: `20260524.1652`
- Source branch at preparation time: `main`
- Release folder: `Release/AppStore-7.6.0-20260523.2335`
- Release folder: `Release/AppStore-7.6.0-20260524.1652`
## What Changed For This Release
@@ -22,6 +22,7 @@
- Removed the broken macOS system Help menu entry.
- Added an About-page Help PDF button that opens the online PDF matching the current app language, plus a copy-link button.
- Hardened fullscreen Space presentation so the app grid stays above the current fullscreen app instead of moving to another Space.
- Added Split View fullscreen detection so two apps sharing one fullscreen Space also keep the app grid on the current Space.
- Expanded window QA to cover fullscreen Space behavior with Dock icon both enabled and disabled, including stability checks.
- Strengthened the window logic QA script to cover fullscreen Space, duplicate Dock tiles, repeated self-launch, force quit layering, Settings/file panel layering, Quick Search, and two-display pointer-following behavior.
Scripts/window_logic_qa.sh
@@ -66,6 +66,11 @@
  fi
}
reset_dock_for_qa() {
  killall Dock >/dev/null 2>&1 || true
  sleep 1.5
}
send_keycode() {
  local keycode="$1"
  local modifiers="${2:-}"
@@ -434,6 +439,93 @@
    }
    print("PASS fullscreen overlay above target: overlayLayer=\(tag[0].layer) targetLayer=\(target.layer)")
case "split-geometry":
    func isSingleFullscreenWindow(_ windowFrame: CGRect, on screenFrame: CGRect) -> Bool {
        let widthMatches = abs(windowFrame.width - screenFrame.width) <= 12
        let heightMatches = windowFrame.height >= screenFrame.height * 0.88
        let horizontallyAligned = abs(windowFrame.midX - screenFrame.midX) <= 12
        let verticallyAligned = abs(windowFrame.maxY - screenFrame.maxY) <= 32
        return widthMatches && heightMatches && horizontallyAligned && verticallyAligned
    }
    func hasSplitViewFullscreenWindows(_ windows: [CGRect], on screenFrame: CGRect) -> Bool {
        let clippedWindows = windows.map { $0.intersection(screenFrame) }
        let tallWindows = clippedWindows
            .filter { frame in
                frame.height >= screenFrame.height * 0.86
                    && frame.width >= screenFrame.width * 0.20
                    && frame.width <= screenFrame.width * 0.86
                    && abs(frame.maxY - screenFrame.maxY) <= 32
            }
            .sorted { $0.minX < $1.minX }
        guard tallWindows.count >= 2 else { return false }
        for startIndex in tallWindows.indices {
            var union = tallWindows[startIndex]
            var lastMaxX = union.maxX
            for window in tallWindows.dropFirst(startIndex + 1) {
                let gap = window.minX - lastMaxX
                if gap < -32 || gap > 48 {
                    break
                }
                union = union.union(window)
                lastMaxX = max(lastMaxX, window.maxX)
                let touchesLeft = abs(union.minX - screenFrame.minX) <= 32
                let touchesRight = abs(union.maxX - screenFrame.maxX) <= 32
                let coversWidth = union.width >= screenFrame.width * 0.92
                let coversHeight = union.height >= screenFrame.height * 0.86
                if touchesLeft && touchesRight && coversWidth && coversHeight {
                    return true
                }
            }
        }
        return false
    }
    let screen = CGRect(x: 0, y: 0, width: 1710, height: 1112)
    let single = CGRect(x: 0, y: 39, width: 1710, height: 1073)
    let splitHalf = [
        CGRect(x: 0, y: 39, width: 853, height: 1073),
        CGRect(x: 857, y: 39, width: 853, height: 1073)
    ]
    let splitThird = [
        CGRect(x: 0, y: 39, width: 568, height: 1073),
        CGRect(x: 572, y: 39, width: 1138, height: 1073)
    ]
    let desktopTiledWithLargeGap = [
        CGRect(x: 0, y: 90, width: 700, height: 900),
        CGRect(x: 900, y: 90, width: 700, height: 900)
    ]
    let desktopSideBySideBelowDock = [
        CGRect(x: 0, y: 39, width: 856, height: 983),
        CGRect(x: 854, y: 39, width: 856, height: 983)
    ]
    let halfOnly = [CGRect(x: 0, y: 39, width: 853, height: 1073)]
    guard isSingleFullscreenWindow(single, on: screen) else {
        fail("split geometry expected single fullscreen window to match")
    }
    guard hasSplitViewFullscreenWindows(splitHalf, on: screen) else {
        fail("split geometry expected 50/50 Split View to match")
    }
    guard hasSplitViewFullscreenWindows(splitThird, on: screen) else {
        fail("split geometry expected 33/67 Split View to match")
    }
    guard !hasSplitViewFullscreenWindows(desktopTiledWithLargeGap, on: screen) else {
        fail("split geometry should not match ordinary tiled desktop windows")
    }
    guard !hasSplitViewFullscreenWindows(desktopSideBySideBelowDock, on: screen) else {
        fail("split geometry should not match side-by-side desktop windows below the Dock")
    }
    guard !hasSplitViewFullscreenWindows(halfOnly, on: screen) else {
        fail("split geometry should not match a single half-width window")
    }
    print("PASS split fullscreen geometry detection")
case "screen-count":
    print("INFO screens=\(NSScreen.screens.count) frames=\(NSScreen.screens.map { NSStringFromRect($0.frame) })")
@@ -665,6 +757,7 @@
log "==> Preparing QA defaults"
defaults write "$DEFAULTS_DOMAIN" showDockIcon -bool true
reset_dock_for_qa
log "==> Starting clean app instance"
prepare_isolated_app_instance
@@ -692,6 +785,9 @@
sleep 0.4
wait_swift_assert no-overlay
log "==> QA split-view fullscreen geometry detection"
swift_assert split-geometry
run_fullscreen_space_case() {
  local dock_value="$1"
  log "==> QA fullscreen Space: overlay stays above the current fullscreen app (showDockIcon=$dock_value)"