From a4af5d51e8fbb8a0e53f98aa9f9e238536aaba24 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 12 Jun 2026 21:08:39 +0800
Subject: [PATCH] Render split view spaces with ordered app halves

---
 C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift |   30 +++++++++++++++++++++++++++---
 1 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift b/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
index bba0912..55b5f44 100644
--- a/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
+++ b/C1.source/Sources/Aligner/Infrastructure/Windows/CGWindowAXWindowService.swift
@@ -642,13 +642,14 @@
                 return nil
             }
 
+            let rawBounds = bounds(rawWindow[kCGWindowBounds as String])
             let ownerPID = int32Value(rawWindow[kCGWindowOwnerPID as String])
             let runningApplication = ownerPID.flatMap(NSRunningApplication.init(processIdentifier:))
             let rawFingerprint = ownerPID.map {
                 AXWindowFingerprint(
                     processIdentifier: $0,
                     title: title(rawWindow: rawWindow, axWindow: nil),
-                    size: bounds(rawWindow[kCGWindowBounds as String]).size
+                    size: rawBounds.size
                 )
             }
             let directAXWindow = axMetadata[windowID]
@@ -668,7 +669,8 @@
                 app: app,
                 activationPolicy: activationPolicy(from: runningApplication),
                 title: title(rawWindow: rawWindow, axWindow: axWindow),
-                size: bounds(rawWindow[kCGWindowBounds as String]).size,
+                size: rawBounds.size,
+                frame: rawBounds,
                 subrole: axWindow?.subrole ?? .standard,
                 isMinimized: axWindow?.isMinimized ?? false,
                 isFullscreen: !Set(spaceIDs).isDisjoint(with: fullscreenSpaceIDs),
@@ -748,6 +750,7 @@
                 title: axWindow.title ?? "",
                 identifierSource: identifierSource,
                 size: axWindow.size,
+                frame: axWindow.frame,
                 subrole: axWindow.subrole,
                 isMinimized: axWindow.isMinimized,
                 isFullscreen: !Set(spaceIDs).isDisjoint(with: fullscreenSpaceIDs),
@@ -990,6 +993,7 @@
     let title: String?
     let isMinimized: Bool
     let size: CGSize
+    let frame: CGRect?
     let subrole: AlignerWindowSubrole
     let hasExplicitSubrole: Bool
     let isInteractable: Bool
@@ -1081,13 +1085,16 @@
 
             for (windowIndex, window) in windows.enumerated() {
                 let subrole = subrole(for: window)
+                let size = size(for: window)
+                let position = position(for: window)
                 result.append(AXWindowMetadata(
                     windowID: windowID(for: window),
                     app: app,
                     activationPolicy: activationPolicy(from: application),
                     title: title(for: window),
                     isMinimized: boolAttribute(kAXMinimizedAttribute as String, for: window) ?? false,
-                    size: size(for: window),
+                    size: size,
+                    frame: position.map { CGRect(origin: $0, size: size) },
                     subrole: subrole.value,
                     hasExplicitSubrole: subrole.isExplicit,
                     isInteractable: boolAttribute(kAXEnabledAttribute as String, for: window) ?? true,
@@ -1214,6 +1221,23 @@
         return size
     }
 
+    private static func position(for window: AXUIElement) -> CGPoint? {
+        var value: CFTypeRef?
+        guard AXUIElementCopyAttributeValue(window, kAXPositionAttribute as CFString, &value) == .success,
+              let axValue = value,
+              CFGetTypeID(axValue) == AXValueGetTypeID()
+        else {
+            return nil
+        }
+
+        var position = CGPoint.zero
+        guard AXValueGetValue(axValue as! AXValue, .cgPoint, &position) else {
+            return nil
+        }
+
+        return position
+    }
+
     private static func subrole(for window: AXUIElement) -> (value: AlignerWindowSubrole, isExplicit: Bool) {
         var value: CFTypeRef?
         guard AXUIElementCopyAttributeValue(window, kAXSubroleAttribute as CFString, &value) == .success,

--
Gitblit v1.9.3