Skip to content

Commit

Permalink
Merge pull request rxhanson#1007 from decodism/master-2
Browse files Browse the repository at this point in the history
Stage Manager: clean up workaround
  • Loading branch information
rxhanson authored Nov 30, 2022
2 parents 571b9da + 4781412 commit 9fd9e39
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 52 deletions.
51 changes: 30 additions & 21 deletions Rectangle/AccessibilityElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class AccessibilityElement {
return childElements?.filter { $0.role == role }
}

var windowId: CGWindowID? {
fileprivate var windowId: CGWindowID? {
wrappedElement.getWindowId()
}

Expand Down Expand Up @@ -261,27 +261,31 @@ extension AccessibilityElement {
if let element = AccessibilityElement(position), let windowElement = element.windowElement {
return windowElement
}
if !Defaults.dragFromStage.userDisabled && StageUtil.stageCapable && StageUtil.stageEnabled && StageUtil.isStageStripVisible() {
if let group = (StageUtil.getStageStripGroups().first { $0.frame.contains(position) }),
let windowId = group.windowIds.first,
let element = StageWindowAccessibilityElement(windowId) {
return element
}
}
if let info = getWindowInfo(position), let windowElements = AccessibilityElement(info.pid).windowElements {
if let windowElement = (windowElements.first { $0.windowId == info.id }) {
if Logger.logging {
let appName = NSRunningApplication(processIdentifier: info.pid)?.localizedName ?? ""
Logger.log("Window under cursor fallback matched: \(appName) \(info)")
if let info = getWindowInfo(position) {
if !Defaults.dragFromStage.userDisabled {
if StageUtil.stageCapable && StageUtil.stageEnabled,
let group = StageUtil.getStageStripWindowGroup(info.id),
let windowId = group.first,
windowId != info.id,
let element = StageWindowAccessibilityElement(windowId) {
return element
}
return windowElement
}
if let windowElement = (windowElements.first { $0.frame == info.frame }) {
if Logger.logging {
let appName = NSRunningApplication(processIdentifier: info.pid)?.localizedName ?? ""
Logger.log("Window under cursor fallback matched: \(appName) \(info)")
if let windowElements = AccessibilityElement(info.pid).windowElements {
if let windowElement = (windowElements.first { $0.windowId == info.id }) {
if Logger.logging {
let appName = NSRunningApplication(processIdentifier: info.pid)?.localizedName ?? ""
Logger.log("Window under cursor fallback matched: \(appName) \(info)")
}
return windowElement
}
if let windowElement = (windowElements.first { $0.frame == info.frame }) {
if Logger.logging {
let appName = NSRunningApplication(processIdentifier: info.pid)?.localizedName ?? ""
Logger.log("Window under cursor fallback matched: \(appName) \(info)")
}
return windowElement
}
return windowElement
}
}
Logger.log("Unable to obtain the accessibility element with the specified attribute at mouse location")
Expand All @@ -293,6 +297,11 @@ extension AccessibilityElement {
return AccessibilityElement(bundleIdentifier)?.windowElements?.first
}

static func getWindowElement(_ windowId: CGWindowID) -> AccessibilityElement? {
guard let pid = WindowUtil.getWindowList([windowId]).first?.pid else { return nil }
return AccessibilityElement(pid).windowElements?.first { $0.windowId == windowId }
}

static func getAllWindowElements() -> [AccessibilityElement] {
return WindowUtil.getWindowList().uniqueMap { $0.pid }.compactMap { AccessibilityElement($0).windowElements }.flatMap { $0 }
}
Expand All @@ -302,7 +311,7 @@ class StageWindowAccessibilityElement: AccessibilityElement {
private let _windowId: CGWindowID

init?(_ windowId: CGWindowID) {
guard let element = (AccessibilityElement.getAllWindowElements().first { $0.windowId == windowId }) else { return nil }
guard let element = AccessibilityElement.getWindowElement(windowId) else { return nil }
_windowId = windowId
super.init(element.wrappedElement)
}
Expand All @@ -313,7 +322,7 @@ class StageWindowAccessibilityElement: AccessibilityElement {
return .init(origin: info.frame.origin, size: frame.size)
}

override var windowId: CGWindowID? {
override fileprivate var windowId: CGWindowID? {
_windowId
}
}
Expand Down
10 changes: 7 additions & 3 deletions Rectangle/ScreenDetection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,13 @@ extension NSScreen {
get {
var newFrame = visibleFrame

if Defaults.stageSize.value > 0 && StageUtil.stageCapable && StageUtil.stageEnabled && StageUtil.stageStripShow && StageUtil.isStageStripVisible() {
if StageUtil.stageStripPosition == .left { newFrame.origin.x += Defaults.stageSize.cgFloat }
newFrame.size.width -= Defaults.stageSize.cgFloat
if Defaults.stageSize.value > 0 {
if StageUtil.stageCapable && StageUtil.stageEnabled && StageUtil.stageStripShow && StageUtil.getStageStripWindowGroups().count > 0 {
if StageUtil.stageStripPosition == .left {
newFrame.origin.x += Defaults.stageSize.cgFloat
}
newFrame.size.width -= Defaults.stageSize.cgFloat
}
}

if Defaults.todo.userEnabled, Defaults.todoMode.enabled, TodoManager.todoScreen == self {
Expand Down
6 changes: 2 additions & 4 deletions Rectangle/Snapping/SnappingManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,8 @@ class SnappingManager {
}
}
if let windowId = windowId {
if StageUtil.stageCapable && StageUtil.stageEnabled && StageUtil.isStageStripVisible() {
if (StageUtil.getStageStripGroups().contains { $0.windowIds.contains(windowId) }) {
return false
}
if StageUtil.stageCapable && StageUtil.stageEnabled && StageUtil.getStageStripWindowGroup(windowId) != nil {
return false
}
}
return true
Expand Down
9 changes: 5 additions & 4 deletions Rectangle/Utilities/AXExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ extension AXValue {
func toValue<T>() -> T? {
let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
let success = AXValueGetValue(self, AXValueGetType(self), pointer)
return success ? pointer.pointee : nil
let value = pointer.pointee
pointer.deallocate()
return success ? value : nil
}

static func from<T>(value: T, type: AXValueType) -> AXValue? {
let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
pointer.pointee = value
return AXValueCreate(type, pointer)
var value = value
return AXValueCreate(type, &value)
}
}

Expand Down
25 changes: 8 additions & 17 deletions Rectangle/Utilities/StageUtil.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,30 @@ class StageUtil {
return !defaults.bool(forKey: "AutoHide")
}

static func isStageStripVisible() -> Bool {
let infos = WindowUtil.getWindowList().filter { $0.bundleIdentifier == "com.apple.WindowManager" }
// A single window could be for the dragged window
return infos.count >= 2
}

static var stageStripPosition: StageStripPosition {
guard let defaults = UserDefaults(suiteName: "com.apple.dock"), defaults.object(forKey: "orientation") != nil
else { return .left }
return defaults.string(forKey: "orientation") == "left" ? .right : .left
}

static func getStageStripGroups() -> [StageStripGroup] {
var groups = [StageStripGroup]()
static func getStageStripWindowGroups() -> [[CGWindowID]] {
var groups = [[CGWindowID]]()
if let appElement = AccessibilityElement("com.apple.WindowManager"),
let groupElements = appElement.getChildElement(.group)?.getChildElement(.list)?.getChildElements(.button) {
for groupElement in groupElements {
let frame = groupElement.frame
guard !frame.isNull, let windowIds = groupElement.windowIds else { continue }
let group = StageStripGroup(frame: frame, windowIds: windowIds)
groups.append(group)
guard let windowIds = groupElement.windowIds else { continue }
groups.append(windowIds)
}
}
return groups
}

static func getStageStripWindowGroup(_ windowId: CGWindowID) -> [CGWindowID]? {
return getStageStripWindowGroups().first { $0.contains(windowId) }
}
}

enum StageStripPosition {
case left
case right
}

struct StageStripGroup {
let frame: CGRect
let windowIds: [CGWindowID]
}
4 changes: 1 addition & 3 deletions Rectangle/Utilities/WindowUtil.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ class WindowUtil {
for i in 0..<count {
let dictionary = array.getValue(i) as CFDictionary
let id = dictionary.getValue(kCGWindowNumber) as CFNumber
let layer = dictionary.getValue(kCGWindowLayer) as CFNumber
let frame = (dictionary.getValue(kCGWindowBounds) as CFDictionary).toRect()
let pid = dictionary.getValue(kCGWindowOwnerPID) as CFNumber
if let frame = frame {
let info = WindowInfo(id: id as! CGWindowID, layer: layer as! Int, frame: frame, pid: pid as! pid_t)
let info = WindowInfo(id: id as! CGWindowID, frame: frame, pid: pid as! pid_t)
infos.append(info)
}
}
Expand All @@ -45,7 +44,6 @@ class WindowUtil {

struct WindowInfo {
let id: CGWindowID
let layer: Int
let frame: CGRect
let pid: pid_t
var bundleIdentifier: String? { NSRunningApplication(processIdentifier: pid)?.bundleIdentifier }
Expand Down

0 comments on commit 9fd9e39

Please sign in to comment.