Skip to content

⚡ Harden input monitor lifecycle + improve shutdown#1094

Merged
mrkai77 merged 10 commits into
developfrom
kai/1093-loop-crashes-quietly
May 11, 2026
Merged

⚡ Harden input monitor lifecycle + improve shutdown#1094
mrkai77 merged 10 commits into
developfrom
kai/1093-loop-crashes-quietly

Conversation

@mrkai77
Copy link
Copy Markdown
Owner

@mrkai77 mrkai77 commented May 8, 2026

This PR moves global event monitoring off the main run loop and onto a dedicated event-tap run loop. This keeps event delivery and event tap teardown from depending on Loop’s main run loop, which should reduce the chance that a main-thread stall leaves Loop intercepting input or prevents the user from quitting/interacting with the app.

It also hardens Loop’s shutdown path. Previously, Loop returned .terminateLater and waited for all stashed windows to restore before allowing termination to continue. If that restore path stalled, Loop could remain stuck in termination indefinitely. This was worse if input event taps were still active. Loop now stops LoopManager and WindowDragManager input monitors before waiting on stash restoration, and stash shutdown is bounded so termination can continue.

A few small thread-safety helpers were added as well:

  • OneShotContinuation prevents an async continuation from being resumed more than once.
  • isLoopActiveAtomic and hasParentCycleActionAtomic provide synchronous, thread-safe snapshots for event-tap callbacks. These event-tap reads cannot use actors directly because CoreGraphics event tap callbacks are synchronous (for obvious reasons)

Also fixes #1077 where stashed windows would not respect a preserved window size, caused by earlier concurrency fixes :)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

🚧 Development Build Finished

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR moves global CoreGraphics event taps onto a dedicated run loop thread to decouple input monitoring from the app’s main run loop, and hardens shutdown/termination so Loop can reliably stop intercepting input and exit even if stash restoration stalls. It also adjusts stash frame computation to refresh resolved window state, addressing the reported “preserve size” regression for stashed windows.

Changes:

  • Introduces a dedicated EventTapThread run loop and routes event-tap sources through it (instead of the main run loop).
  • Adds explicit shutdown paths for LoopManager and WindowDragManager, and bounds stash shutdown during app termination via a timeout.
  • Makes stash “revealed frame” computation async and refreshes resolved state before computing target frames.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Loop/Window Management/Window/Window.swift Runs animated frame changes on @MainActor and starts window transform animations without an extra task wrapper.
Loop/Window Management/Window Manipulation/WindowTransformAnimation.swift Marks the animation class @MainActor to keep UI animation interactions on the main actor.
Loop/Utilities/Event Monitoring/EventTapThread.swift Adds a dedicated thread + run loop for global event taps.
Loop/Utilities/Event Monitoring/BaseEventTapMonitor.swift Attaches event taps to the dedicated run loop and centralizes teardown logic.
Loop/Stashing/StashManager.swift Makes revealed-frame access async and updates call sites to await it.
Loop/Stashing/StashedWindowInfo.swift Refreshes resolved state before computing revealed frames to better preserve size/geometry.
Loop/Core/WindowDragManager.swift Adds shutdown() and ensures listeners are reset before re-adding.
Loop/Core/Observers/MouseInteractionObserver.swift Ensures start() clears any prior monitors/state via stop().
Loop/Core/LoopManager.swift Adds atomic snapshot helpers for event-tap callbacks and improves open/close/shutdown lifecycle handling.
Loop/App/AppDelegate.swift Stops input monitors before stash restoration and bounds stash shutdown during termination with a timeout helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Loop/Utilities/Event Monitoring/BaseEventTapMonitor.swift Outdated
@mrkai77 mrkai77 force-pushed the kai/1093-loop-crashes-quietly branch from 5b3fa3a to 92bd278 Compare May 8, 2026 05:25
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

🚧 Development Build Finished

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

🚧 Development Build Finished

@mrkai77 mrkai77 force-pushed the kai/1093-loop-crashes-quietly branch from 1aaedf3 to aa1f04c Compare May 11, 2026 20:35
@mrkai77 mrkai77 merged commit 2f9d207 into develop May 11, 2026
1 check passed
@mrkai77 mrkai77 deleted the kai/1093-loop-crashes-quietly branch May 11, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐞 Loop crashes quietly 🐞 Stash alters original window size when unstashing

2 participants