@@ -25,30 +25,106 @@ APP_PID=$!
2525echo $APP_PID > app.pid
2626echo " Application launched with PID: $APP_PID "
2727
28- # Wait for application startup
29- sleep 3
28+ # CoreGraphics can expose the window id used by screencapture -l even when
29+ # Accessibility does not provide AXWindowNumber on GitHub-hosted runners.
30+ if [ ! -x get_cg_window_info ]; then
31+ cat > get_cg_window_info.swift << 'SWIFT '
32+ import CoreGraphics
33+ import Foundation
3034
31- # Wait for the window to appear
32- echo " Waiting for window to appear..."
33- for i in {1..20}; do
34- EXISTS=$( osascript -e " tell application \" System Events\" to return exists process \" $APP_NAME \" " || true)
35- if [ " $EXISTS " = " true" ]; then
36- HAS_WIN=$( osascript -e " tell application \" System Events\" to tell process \" $APP_NAME \" to return (count of windows) > 0" || true)
37- if [ " $HAS_WIN " = " true" ]; then
38- break
39- fi
40- fi
41- sleep 0.5
42- done
35+ let appName = CommandLine.arguments[1]
36+ let appPid = Int(CommandLine.arguments[2]) ?? 0
4337
44- if [ " $EXISTS " != " true" ] || [ " $HAS_WIN " != " true" ]; then
45- echo " ERROR: process or window not found"
46- osascript -e ' tell application "System Events" to get name of every process' | tr " ," " \n" | head -50
47- # Fallback: full screen capture
48- screencapture -x " $OUTPUT_FILE "
49- exit 0
38+ struct Candidate {
39+ let layer: Int
40+ let area: Int
41+ let id: Int
42+ let x: Int
43+ let y: Int
44+ let width: Int
45+ let height: Int
46+ }
47+
48+ func intValue(_ value: Any?) -> Int {
49+ if let number = value as? NSNumber {
50+ return number.intValue
51+ }
52+ if let int = value as? Int {
53+ return int
54+ }
55+ if let double = value as? Double {
56+ return Int(double)
57+ }
58+ return 0
59+ }
60+
61+ func doubleValue(_ value: Any?, default defaultValue: Double = 0) -> Double {
62+ if let number = value as? NSNumber {
63+ return number.doubleValue
64+ }
65+ if let double = value as? Double {
66+ return double
67+ }
68+ if let int = value as? Int {
69+ return Double(int)
70+ }
71+ return defaultValue
72+ }
73+
74+ for _ in 0..<30 {
75+ let info = CGWindowListCopyWindowInfo(.optionOnScreenOnly, kCGNullWindowID) as? [[String: Any]] ?? []
76+ var candidates: [Candidate] = []
77+
78+ for window in info {
79+ let ownerPid = intValue(window[kCGWindowOwnerPID as String])
80+ let ownerName = window[kCGWindowOwnerName as String] as? String ?? ""
81+ if ownerPid != appPid && ownerName != appName {
82+ continue
83+ }
84+
85+ let bounds = window[kCGWindowBounds as String] as? [String: Any] ?? [:]
86+ let width = intValue(bounds["Width"])
87+ let height = intValue(bounds["Height"])
88+ let windowID = intValue(window[kCGWindowNumber as String])
89+ let alpha = doubleValue(window[kCGWindowAlpha as String], default: 1)
90+ if width <= 1 || height <= 1 || windowID <= 0 || alpha <= 0 {
91+ continue
92+ }
93+
94+ candidates.append(Candidate(
95+ layer: intValue(window[kCGWindowLayer as String]),
96+ area: width * height,
97+ id: windowID,
98+ x: intValue(bounds["X"]),
99+ y: intValue(bounds["Y"]),
100+ width: width,
101+ height: height
102+ ))
103+ }
104+
105+ if let best = candidates.sorted(by: {
106+ if $0.layer == $1.layer {
107+ return $0.area > $1.area
108+ }
109+ return $0.layer < $1.layer
110+ }).first {
111+ print("\(best.id),\(best.x),\(best.y),\(best.width),\(best.height)")
112+ exit(0)
113+ }
114+
115+ Thread.sleep(forTimeInterval: 0.5)
116+ }
117+
118+ print("ERROR: CoreGraphics window not found")
119+ exit(1)
120+ SWIFT
121+
122+ swiftc get_cg_window_info.swift -o get_cg_window_info
50123fi
51124
125+ # Wait for application startup
126+ sleep 3
127+
52128# Write AppleScript to a temporary file to avoid heredoc issues.
53129# AXWindowNumber is the CoreGraphics window id used by screencapture -l, but
54130# some GitHub-hosted macOS images do not expose it for every Accessibility
77153sed -i ' ' " s/APP_NAME_PLACEHOLDER/$APP_NAME /g" get_window_info.applescript
78154
79155# Get window id and rect as id,x,y,w,h
80- WINDOW_INFO=$( osascript get_window_info.applescript)
156+ echo " Waiting for window to appear..."
157+ WINDOW_INFO=$( ./get_cg_window_info " $APP_NAME " " $APP_PID " || true)
158+ if [[ " $WINDOW_INFO " == ERROR:* ]] || [ -z " $WINDOW_INFO " ]; then
159+ echo " $WINDOW_INFO "
160+ echo " CoreGraphics lookup failed; trying Accessibility window lookup."
161+ for i in {1..20}; do
162+ EXISTS=$( osascript -e " tell application \" System Events\" to return exists process \" $APP_NAME \" " || true)
163+ if [ " $EXISTS " = " true" ]; then
164+ HAS_WIN=$( osascript -e " tell application \" System Events\" to tell process \" $APP_NAME \" to return (count of windows) > 0" || true)
165+ if [ " $HAS_WIN " = " true" ]; then
166+ break
167+ fi
168+ fi
169+ sleep 0.5
170+ done
171+
172+ if [ " ${EXISTS:- false} " != " true" ] || [ " ${HAS_WIN:- false} " != " true" ]; then
173+ echo " ERROR: process or window not found"
174+ osascript -e ' tell application "System Events" to get name of every process' | tr " ," " \n" | head -50
175+ # Fallback: full screen capture
176+ screencapture -x " $OUTPUT_FILE "
177+ exit 0
178+ fi
179+
180+ WINDOW_INFO=$( osascript get_window_info.applescript)
181+ fi
81182case " $WINDOW_INFO " in
82183 ERROR:* ) echo " $WINDOW_INFO " ; screencapture -x " $OUTPUT_FILE " ; exit 0 ;;
83184esac
0 commit comments