Skip to content

Commit

Permalink
Fix unwanted animations when some accessibility features are enabled
Browse files Browse the repository at this point in the history
#51 should be fixed
  • Loading branch information
nikitabobko committed Dec 18, 2023
1 parent 583e91a commit 12e7737
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 19 deletions.
15 changes: 0 additions & 15 deletions docs/guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -437,21 +437,6 @@ xref:commands.adoc#move-workspace-to-monitor[move-workspace-to-monitor] command
[#caveats]
== Caveats

=== Unwanted animations

If you use some of the Accessibility features `System Settings -> Accessibility`, you may see weird animations, for no reasons, when AeroSpace moves windows around.
(Shame on you, Apple! 🤦)

Known accessibility features that cause the problem:

* Full Keyboard Access
* Accessibility Keyboard
* Voice Control
* Switch Control
* Maybe something else...

Please reboot after you disable the accessibility features that cause the problem.

=== Dialog heuristics

* Apple provides accessibility API for apps to let others know which of their windows are dialogs
Expand Down
2 changes: 1 addition & 1 deletion src/tree/MacApp.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
final class MacApp: AbstractApp {
let nsApp: NSRunningApplication
private let axApp: AXUIElement
let axApp: AXUIElement

private var axObservers: [AxObserverWrapper] = [] // keep observers in memory

Expand Down
25 changes: 22 additions & 3 deletions src/tree/MacWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,20 @@ final class MacWindow: Window, CustomStringConvertible {
}

override func setSize(_ size: CGSize) {
previousSize = getSize()
axWindow.set(Ax.sizeAttr, size)
disableAnimations {
previousSize = getSize()
axWindow.set(Ax.sizeAttr, size)
}
}

override func getSize() -> CGSize? {
axWindow.get(Ax.sizeAttr)
}

override func setTopLeftCorner(_ point: CGPoint) {
axWindow.set(Ax.topLeftCornerAttr, point)
disableAnimations {
axWindow.set(Ax.topLeftCornerAttr, point)
}
}

override func getTopLeftCorner() -> CGPoint? {
Expand All @@ -145,6 +149,21 @@ final class MacWindow: Window, CustomStringConvertible {
guard let size = getSize() else { return nil }
return Rect(topLeftX: topLeftCorner.x, topLeftY: topLeftCorner.y, width: size.width, height: size.height)
}

// Some undocumented magic
// References: https://github.com/koekeishiya/yabai/commit/3fe4c77b001e1a4f613c26f01ea68c0f09327f3a
// https://github.com/rxhanson/Rectangle/pull/285
private func disableAnimations(_ body: () -> Void) {
let app = (app as! MacApp).axApp
let wasEnabled = app.get(Ax.enhancedUserInterfaceAttr) == true
if wasEnabled {
app.set(Ax.enhancedUserInterfaceAttr, false)
}
body()
if wasEnabled {
app.set(Ax.enhancedUserInterfaceAttr, true)
}
}
}

private func isWindow(_ axWindow: AXUIElement, _ app: MacApp) -> Bool {
Expand Down
5 changes: 5 additions & 0 deletions src/util/accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ enum Ax {
getter: { $0 as? Bool },
setter: { $0 as CFTypeRef }
)
static let enhancedUserInterfaceAttr = WritableAttrImpl<Bool>(
key: "AXEnhancedUserInterface",
getter: { $0 as? Bool },
setter: { $0 as CFTypeRef }
)
static let sizeAttr = WritableAttrImpl<CGSize>(
key: kAXSizeAttribute,
getter: {
Expand Down

0 comments on commit 12e7737

Please sign in to comment.