From 3ef24f71a70fc47eba8bf23f6827a60a4f34a07a Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 04 Jun 2026 00:32:09 +0800
Subject: [PATCH] Fix Shottr and HBuilderX window candidates

---
 C1.source/Resources/Aligner-Info.plist                                         |   48 ++++++------
 C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift |   39 +++++++++
 C1.source/Sources/AlignerCore/Windows/WindowEnumerationPolicy.swift            |   35 +++++++-
 C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift                        |   70 +++++++++++++++++
 4 files changed, 161 insertions(+), 31 deletions(-)

diff --git a/C1.source/Resources/Aligner-Info.plist b/C1.source/Resources/Aligner-Info.plist
index 9639d34..ffe1a14 100644
--- a/C1.source/Resources/Aligner-Info.plist
+++ b/C1.source/Resources/Aligner-Info.plist
@@ -2,29 +2,29 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-    <key>CFBundleDevelopmentRegion</key>
-    <string>en</string>
-    <key>CFBundleExecutable</key>
-    <string>Aligner</string>
-    <key>CFBundleIconFile</key>
-    <string>AppIcon</string>
-    <key>CFBundleIdentifier</key>
-    <string>com.ar.Aligner</string>
-    <key>CFBundleInfoDictionaryVersion</key>
-    <string>6.0</string>
-    <key>CFBundleName</key>
-    <string>Aligner</string>
-    <key>CFBundlePackageType</key>
-    <string>APPL</string>
-    <key>CFBundleShortVersionString</key>
-	<string>0.0.20</string>
-    <key>CFBundleVersion</key>
-	<string>20260603.2338</string>
-    <key>LSMinimumSystemVersion</key>
-    <string>26.0</string>
-    <key>NSHighResolutionCapable</key>
-    <true/>
-    <key>NSPrincipalClass</key>
-    <string>NSApplication</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>Aligner</string>
+	<key>CFBundleIconFile</key>
+	<string>AppIcon</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.ar.Aligner</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>Aligner</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>0.0.21</string>
+	<key>CFBundleVersion</key>
+	<string>20260604.0030</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>26.0</string>
+	<key>NSHighResolutionCapable</key>
+	<true/>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
 </dict>
 </plist>
diff --git a/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift b/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
index 773abed..49a7cf9 100644
--- a/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
+++ b/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
@@ -395,6 +395,7 @@
                 isGhost: isGhost(
                     rawWindow: rawWindow,
                     axWindow: axWindow,
+                    app: app,
                     spaceIDs: spaceIDs,
                     hasAXBackedTitleDuplicate: hasAXBackedTitleDuplicate
                 ),
@@ -583,6 +584,7 @@
     private func isGhost(
         rawWindow: [String: Any],
         axWindow: AXWindowMetadata?,
+        app: AlignerApp,
         spaceIDs: [UInt64],
         hasAXBackedTitleDuplicate: Bool = false
     ) -> Bool {
@@ -596,10 +598,20 @@
             return false
         }
         if axWindow != nil {
-            return layer != 0 || alpha <= 0
+            if alpha <= 0 {
+                return true
+            }
+            if layer == 0 {
+                return false
+            }
+
+            return !isOnscreen
         }
         if hasAXBackedTitleDuplicate {
             return true
+        }
+        if isKnownCGOnlyMainWindow(rawWindow: rawWindow, app: app) {
+            return false
         }
         if !spaceIDs.isEmpty, isLikelyFullscreenAuxiliaryCGWindow(bounds: rawBounds) {
             return true
@@ -618,6 +630,31 @@
         bounds.width < 500 || bounds.height < 160
     }
 
+    private func isKnownCGOnlyMainWindow(rawWindow: [String: Any], app: AlignerApp) -> Bool {
+        let layer = intValue(rawWindow[kCGWindowLayer as String]) ?? 0
+        let alpha = doubleValue(rawWindow[kCGWindowAlpha as String]) ?? 1
+        let isOnscreen = boolValue(rawWindow[kCGWindowIsOnscreen as String])
+        let title = stringValue(rawWindow[kCGWindowName as String]) ?? ""
+        let rawBounds = bounds(rawWindow[kCGWindowBounds as String])
+        let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines)
+
+        if app.bundleIdentifier == "cc.ffitch.shottr" {
+            return alpha > 0
+                && trimmedTitle == "Shottr"
+                && rawBounds.width > WindowEnumerationPolicy.minimumVisibleWidth
+                && rawBounds.height > WindowEnumerationPolicy.minimumVisibleHeight
+        }
+
+        guard app.bundleIdentifier == "io.dcloud.HBuilderX" else { return false }
+
+        return layer == 0
+            && alpha > 0
+            && !isOnscreen
+            && !trimmedTitle.isEmpty
+            && rawBounds.width > WindowEnumerationPolicy.minimumVisibleWidth
+            && rawBounds.height > WindowEnumerationPolicy.minimumVisibleHeight
+    }
+
     private func isDesktopElement(rawWindow: [String: Any], app: AlignerApp) -> Bool {
         guard app.bundleIdentifier == "com.apple.finder" else { return false }
         let title = stringValue(rawWindow[kCGWindowName as String]) ?? ""
diff --git a/C1.source/Sources/AlignerCore/Windows/WindowEnumerationPolicy.swift b/C1.source/Sources/AlignerCore/Windows/WindowEnumerationPolicy.swift
index 75bc119..a219abb 100644
--- a/C1.source/Sources/AlignerCore/Windows/WindowEnumerationPolicy.swift
+++ b/C1.source/Sources/AlignerCore/Windows/WindowEnumerationPolicy.swift
@@ -76,7 +76,7 @@
 
     public static func shouldInclude(_ record: WindowEnumerationRecord) -> Bool {
         guard record.id != 0 else { return false }
-        guard record.activationPolicy == .regular else { return false }
+        guard hasSupportedActivationPolicy(record) else { return false }
         guard isSupportedSubrole(record.subrole) else { return false }
         guard !record.app.isHidden || record.isFullscreen else { return false }
         guard !record.isGhost else { return false }
@@ -87,6 +87,11 @@
         guard !isKnownClosedDocumentPlaceholder(record) else { return false }
 
         return record.isMinimized || record.isFullscreen || isLargeEnough(record.size)
+    }
+
+    private static func hasSupportedActivationPolicy(_ record: WindowEnumerationRecord) -> Bool {
+        record.activationPolicy == .regular
+            || (record.activationPolicy == .accessory && isKnownCGOnlyOffscreenMainWindow(record))
     }
 
     public static func window(from record: WindowEnumerationRecord) -> AlignerWindow? {
@@ -118,11 +123,29 @@
     }
 
     private static func isCGOnlyOffscreenGhost(_ record: WindowEnumerationRecord) -> Bool {
-        record.identifierSource == .cgWindow
-            && !record.hasAXBacking
-            && !record.isOnscreen
-            && !record.isMinimized
-            && !record.isFullscreen
+        guard record.identifierSource == .cgWindow,
+              !record.hasAXBacking,
+              !record.isOnscreen,
+              !record.isMinimized,
+              !record.isFullscreen
+        else {
+            return false
+        }
+
+        return !isKnownCGOnlyOffscreenMainWindow(record)
+    }
+
+    private static func isKnownCGOnlyOffscreenMainWindow(_ record: WindowEnumerationRecord) -> Bool {
+        let trimmedTitle = record.title.trimmingCharacters(in: .whitespacesAndNewlines)
+
+        switch record.app.bundleIdentifier {
+        case "cc.ffitch.shottr":
+            return trimmedTitle == "Shottr" && isLargeEnough(record.size)
+        case "io.dcloud.HBuilderX":
+            return !trimmedTitle.isEmpty && isLargeEnough(record.size)
+        default:
+            return false
+        }
     }
 
     private static func isKnownClosedDocumentPlaceholder(_ record: WindowEnumerationRecord) -> Bool {
diff --git a/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift b/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
index 9eca644..66709a1 100644
--- a/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
+++ b/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
@@ -244,6 +244,76 @@
         XCTAssertEqual(window?.title, "Visible Document.md")
     }
 
+    func testWindowEnumerationPolicyKeepsKnownCGOnlyOffscreenMainWindows() {
+        let hbuilderApp = AlignerApp(
+            bundleIdentifier: "io.dcloud.HBuilderX",
+            name: "HBuilderX",
+            category: .editorIDE
+        )
+        let record = WindowEnumerationRecord(
+            id: 55_388,
+            app: hbuilderApp,
+            title: "lm-app - HBuilder X 5.07",
+            size: CGSize(width: 1048, height: 796),
+            subrole: .standard,
+            hasAXBacking: false,
+            isOnscreen: false
+        )
+        let emptyTitleRecord = WindowEnumerationRecord(
+            id: 55_389,
+            app: hbuilderApp,
+            title: "",
+            size: CGSize(width: 1048, height: 796),
+            subrole: .standard,
+            hasAXBacking: false,
+            isOnscreen: false
+        )
+        let tinyRecord = WindowEnumerationRecord(
+            id: 55_390,
+            app: hbuilderApp,
+            title: "HBuilderX Utility",
+            size: CGSize(width: 80, height: 40),
+            subrole: .standard,
+            hasAXBacking: false,
+            isOnscreen: false
+        )
+
+        XCTAssertEqual(WindowEnumerationPolicy.window(from: record)?.title, "lm-app - HBuilder X 5.07")
+        XCTAssertNil(WindowEnumerationPolicy.window(from: emptyTitleRecord))
+        XCTAssertNil(WindowEnumerationPolicy.window(from: tinyRecord))
+    }
+
+    func testWindowEnumerationPolicyKeepsShottrCGOnlyAnnotationWindow() {
+        let shottrApp = AlignerApp(
+            bundleIdentifier: "cc.ffitch.shottr",
+            name: "Shottr",
+            category: .generic
+        )
+        let annotationRecord = WindowEnumerationRecord(
+            id: 78,
+            app: shottrApp,
+            activationPolicy: .accessory,
+            title: "Shottr",
+            size: CGSize(width: 1710, height: 997),
+            subrole: .standard,
+            hasAXBacking: false,
+            isOnscreen: false
+        )
+        let utilityRecord = WindowEnumerationRecord(
+            id: 102,
+            app: shottrApp,
+            activationPolicy: .accessory,
+            title: "Colors",
+            size: CGSize(width: 250, height: 397),
+            subrole: .standard,
+            hasAXBacking: false,
+            isOnscreen: false
+        )
+
+        XCTAssertEqual(WindowEnumerationPolicy.window(from: annotationRecord)?.title, "Shottr")
+        XCTAssertNil(WindowEnumerationPolicy.window(from: utilityRecord))
+    }
+
     func testWindowEnumerationPolicyKeepsMinimizedAndFullscreenCGOnlyOffscreenWindows() {
         let minimized = makeWindowRecord(
             title: "Minimized Document.md",

--
Gitblit v1.9.3