Skip to content

fix: smooth move/resize on Chromium/Electron apps by disabling AXEnhancedUserInterface during the gesture#177

Merged
pablopunk merged 2 commits into
pablopunk:mainfrom
fpwex9:fix/electron-enhanced-ui
Jun 22, 2026
Merged

fix: smooth move/resize on Chromium/Electron apps by disabling AXEnhancedUserInterface during the gesture#177
pablopunk merged 2 commits into
pablopunk:mainfrom
fpwex9:fix/electron-enhanced-ui

Conversation

@fpwex9

@fpwex9 fpwex9 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Problem

On macOS Tahoe (26.x), moving/resizing Chromium/Electron windows (Chrome, VS Code, Obsidian, …) with Swift Shift is laggy and "smeared", while it stays perfectly smooth on native AppKit apps (Finder, Terminal, Sublime, Notes). Crucially, dragging the same Electron window by its native title bar, or resizing it by its native corner, is smooth — so the renderer can relayout in real time; the lag is specific to the AX-driven path. Related: #157, #106, #167.

Root cause

Chromium/Electron apps enable AXEnhancedUserInterface on their application element while an AX client is active. With it on, programmatic AXUIElementSetAttributeValue updates of kAXPosition / kAXSize become slow and non-live — which is exactly what Swift Shift does on every mouse move. (Lowering the 120 Hz minimumUpdateInterval in MouseTracker only helps marginally, confirming it's the per-call cost, not the update rate.)

Fix

Temporarily disable AXEnhancedUserInterface on the tracked window's application for the duration of the gesture, and restore the previous value on mouse-up:

  • prepareTracking → read & remember the app's current AXEnhancedUserInterface, set it to false if it was on.
  • stopTracking → restore the previous value.

Public AX API only, no SIP, no private frameworks. Native apps are unaffected (they don't have the attribute set). Tested on macOS 26.5.1 (Apple Silicon): Chrome / VS Code / Obsidian now move and resize as smoothly as native windows.

Design note

I restore the attribute on mouse-up to avoid permanently changing the app's accessibility state. The alternative (what yabai does) is to leave it off while the WM is active — simpler, but it alters the app's a11y behaviour globally. Happy to switch, or gate it behind a setting.

Test plan

  • Build Release, grant Accessibility + Input Monitoring.
  • Move/resize Chrome, VS Code, Obsidian → smooth (previously laggy).
  • Move/resize Finder, Terminal → unchanged.
  • Confirm VoiceOver/accessibility still works after a gesture (attribute restored).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved stability of window move and resize operations by temporarily adjusting accessibility behavior for the tracked app during gestures, then restoring it afterward to minimize disruption and ensure normal functionality resumes.

…ncedUserInterface during the gesture

Chromium/Electron apps enable AXEnhancedUserInterface while an AX client is active,
which makes programmatic kAXPosition/kAXSize updates slow and non-live (laggy drag/
resize) even though native title-bar drag / corner-resize of the same window stays
smooth. Disable it on the tracked app for the duration of the gesture and restore on
mouse-up. Public AX API, no SIP. Addresses the Electron-app lag from pablopunk#157 / pablopunk#106 / pablopunk#167.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codesandbox

codesandbox Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

@Wex9 is attempting to deploy a commit to the Pablo Varela's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43bc53c6-983b-4669-95f2-4667d3e813c8

📥 Commits

Reviewing files that changed from the base of the PR and between c8b2cf3 and 7cac176.

📒 Files selected for processing (1)
  • Swift Shift/src/Manager/MouseTracker.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Swift Shift/src/Manager/MouseTracker.swift

Walkthrough

MouseTracker is updated to temporarily disable the AXEnhancedUserInterface Accessibility attribute on the tracked application during move/resize gestures. Two internal stored properties are added: one for the AX application element reference and one to record the prior value of the attribute. Two private helper methods manage reading and writing the attribute via the AX API using the tracked app's PID. disableEnhancedUIForTrackedApp() is called in prepareTracking(), and restoreEnhancedUIForTrackedApp() is called in the stop/cleanup path.

Suggested Reviewers

  • pablopunk
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: disabling AXEnhancedUserInterface during move/resize gestures for Chromium/Electron apps. It is specific, concise, and directly reflects the primary purpose of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Swift` Shift/src/Manager/MouseTracker.swift:
- Around line 51-52: The restoreEnhancedUIForTrackedApp() call in stopTracking
is being executed before the pending mouse updates are flushed, which causes the
final move/resize operations to still run on the slow Chromium/Electron AX path.
Move the restoreEnhancedUIForTrackedApp() call to after both
flushQueuedExternalMouseUpdate() and flushPendingMouseUpdate() have completed,
then followed by the remaining cleanup operations (invalidateTrackingTimer,
removeMouseEventMonitor, resetTrackingVariables, clearQueuedExternalMouseUpdate,
and isTracking = false).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5515b16f-1424-4bd6-9918-f9a38f41179b

📥 Commits

Reviewing files that changed from the base of the PR and between 397e91a and c8b2cf3.

📒 Files selected for processing (1)
  • Swift Shift/src/Manager/MouseTracker.swift

Comment thread Swift Shift/src/Manager/MouseTracker.swift Outdated
CodeRabbit: in stopTracking, restore AXEnhancedUserInterface AFTER the final
flushQueuedExternalMouseUpdate()/flushPendingMouseUpdate() so the last applied
move/resize still runs on the fast path. Also add docstrings to the helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pablopunk

Copy link
Copy Markdown
Owner

@fpwex9 thanks for the PR and the explanation! Would you mind adding a before/after video? I can't test this because resizing is always smooth for me. Look:

Chrome

CleanShot.2026-06-22.at.10.39.34.mp4

And electron apps behave the same for me

@fpwex9

fpwex9 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @pablopunk! Before/after below — macOS 26.5.1, Apple Silicon, resizing the same Chrome window with the same gesture:

Before (stock):

before.mov

After (this PR):

after.mov

According to Claude Code – the lag only appears while the app actually has AXEnhancedUserInterface ON, which Chromium toggles depending on the attached AX clients (and seems to vary by macOS version / what else is observing accessibility). When it's off, this PR is a complete no-op — so it's safe for setups like yours that are already smooth.

(Also addressed CodeRabbit's note in 7cac176 — the attribute is now restored after the final flush.)

@pablopunk

Copy link
Copy Markdown
Owner

Funny enough, I just tried your code and it does fix a similar issue I only have with the Zen browser. So it seems it's not only chromium-based apps lol. Will merge! ty

@pablopunk pablopunk merged commit 7806462 into pablopunk:main Jun 22, 2026
5 of 6 checks passed
@fpwex9 fpwex9 deleted the fix/electron-enhanced-ui branch June 22, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants