| | |
| | | |
| | | cat >"$assert_swift" <<'SWIFT' |
| | | import AppKit |
| | | import AppKit |
| | | import CoreGraphics |
| | | import Foundation |
| | | |
| | |
| | | guard let target = windows.first(where: { $0.name == "TagLauncherFullscreenQATargetFullscreen" }) else { |
| | | fail("fullscreen target disappeared; TagLauncher likely switched to another Space") |
| | | } |
| | | let overlayWidth = dimension(tag[0].bounds, "Width") |
| | | let overlayHeight = dimension(tag[0].bounds, "Height") |
| | | let overlayMidX = dimension(tag[0].bounds, "X") + overlayWidth / 2 |
| | | let targetWidth = dimension(target.bounds, "Width") |
| | | let targetHeight = dimension(target.bounds, "Height") |
| | | let targetMidX = dimension(target.bounds, "X") + targetWidth / 2 |
| | | guard abs(overlayWidth - targetWidth) <= 12, |
| | | overlayHeight >= targetHeight * 0.88, |
| | | abs(overlayMidX - targetMidX) <= 12 else { |
| | | fail("fullscreen overlay is not on the target fullscreen display: overlay=\(tag[0].bounds) target=\(target.bounds)") |
| | | } |
| | | guard tag[0].layer > target.layer else { |
| | | fail("TagLauncher layer \(tag[0].layer) is not above fullscreen target layer \(target.layer)") |
| | | } |
| | |
| | | SWIFT |
| | | |
| | | cat >"$coords_swift" <<'SWIFT' |
| | | import AppKit |
| | | import CoreGraphics |
| | | import Foundation |
| | | |
| | | let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? [] |
| | | let tag = raw.filter { ($0[kCGWindowOwnerName as String] as? String) == "TagLauncher" } |
| | | let mode = CommandLine.arguments.dropFirst().first ?? "" |
| | | |
| | | func dimension(_ bounds: NSDictionary, _ key: String) -> CGFloat { |
| | | if let value = bounds[key] as? CGFloat { |
| | | return value |
| | | } |
| | | if let value = bounds[key] as? NSNumber { |
| | | return CGFloat(truncating: value) |
| | | } |
| | | return 0 |
| | | } |
| | | |
| | | switch mode { |
| | | case "data-tab": |
| | | guard let settings = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty == false }), |
| | |
| | | } |
| | | print("\(Int(round(x + 375))) \(Int(round(y + 331)))") |
| | | case "overlay-outside": |
| | | guard let overlay = tag.first(where: { (($0[kCGWindowName as String] as? String) ?? "").isEmpty }), |
| | | let overlayBounds = overlay[kCGWindowBounds as String] as? NSDictionary, |
| | | let overlayX = overlayBounds["X"] as? CGFloat, |
| | | let overlayY = overlayBounds["Y"] as? CGFloat else { |
| | | fputs("FAIL: could not find overlay window bounds\n", stderr) |
| | | exit(1) |
| | | guard let overlay = tag.max(by: { lhs, rhs in |
| | | let lhsBounds = lhs[kCGWindowBounds as String] as? NSDictionary ?? [:] |
| | | let rhsBounds = rhs[kCGWindowBounds as String] as? NSDictionary ?? [:] |
| | | let lhsArea = dimension(lhsBounds, "Width") * dimension(lhsBounds, "Height") |
| | | let rhsArea = dimension(rhsBounds, "Width") * dimension(rhsBounds, "Height") |
| | | return lhsArea < rhsArea |
| | | }), let overlayBounds = overlay[kCGWindowBounds as String] as? NSDictionary else { |
| | | let screen = NSScreen.screens.first?.frame ?? CGRect(x: 0, y: 0, width: 1200, height: 800) |
| | | print("\(Int(round(screen.minX + 120))) \(160)") |
| | | exit(0) |
| | | } |
| | | let overlayX = dimension(overlayBounds, "X") |
| | | let overlayY = dimension(overlayBounds, "Y") |
| | | print("\(Int(round(overlayX + 120))) \(Int(round(overlayY + 160)))") |
| | | default: |
| | | fputs("FAIL: unknown coords mode \(mode)\n", stderr) |
| | |
| | | return 1 |
| | | } |
| | | |
| | | assert_fullscreen_overlay_stable() { |
| | | local output="" |
| | | for _ in {1..20}; do |
| | | if ! output="$(swift "$assert_swift" fullscreen-overlay 2>&1)"; then |
| | | printf '%s\n' "$output" >&2 |
| | | return 1 |
| | | fi |
| | | sleep 0.1 |
| | | done |
| | | printf '%s\n' "$output" |
| | | } |
| | | |
| | | show_overlay() { |
| | | send_main_hotkey |
| | | if wait_swift_assert overlay >/dev/null 2>&1; then |
| | |
| | | sleep 0.4 |
| | | wait_swift_assert no-overlay |
| | | |
| | | log "==> QA fullscreen Space: overlay stays above the current fullscreen app" |
| | | start_fullscreen_qa_target |
| | | send_main_hotkey |
| | | wait_swift_assert fullscreen-overlay |
| | | frontmost="$(osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true')" |
| | | [[ "$frontmost" == "TagLauncher" ]] || { echo "FAIL: fullscreen overlay frontmost app is $frontmost, expected TagLauncher" >&2; exit 1; } |
| | | send_keycode 53 |
| | | sleep 0.4 |
| | | wait_swift_assert no-overlay |
| | | kill_fullscreen_qa_target |
| | | run_fullscreen_space_case() { |
| | | local dock_value="$1" |
| | | log "==> QA fullscreen Space: overlay stays above the current fullscreen app (showDockIcon=$dock_value)" |
| | | defaults write "$DEFAULTS_DOMAIN" showDockIcon -bool "$dock_value" |
| | | prepare_isolated_app_instance |
| | | start_fullscreen_qa_target |
| | | send_main_hotkey |
| | | wait_swift_assert fullscreen-overlay |
| | | assert_fullscreen_overlay_stable |
| | | send_keycode 53 |
| | | sleep 0.4 |
| | | wait_swift_assert no-overlay |
| | | kill_fullscreen_qa_target |
| | | } |
| | | |
| | | run_fullscreen_space_case true |
| | | run_fullscreen_space_case false |
| | | |
| | | log "==> Restoring dock-visible QA app instance for remaining checks" |
| | | defaults write "$DEFAULTS_DOMAIN" showDockIcon -bool true |
| | | prepare_isolated_app_instance |
| | | |
| | | log "==> QA 1/7: overlay claims foreground, hides Dock, keeps menu bar visible" |
| | | show_overlay |