Repository navigation
fix(mac): preserve virtual-display arrangement after delayed wake recovery - #28
Draft
raiseCatError wants to merge 1 commit into
Draft
raiseCatError wants to merge 1 commit into
raiseCatError wants to merge 1 commit into
Conversation
After sleep, a mode change that blocked the main actor for ~10 s let the first manageOrigin() tick run after the 6 s restore window armed at creation had already closed. That tick reported macOS's default origin as a user drag, and DisplayArrangement saved it over the device's placement, so every later session put the display back there. The restore/observe policy moves into a pure OriginRestore struct whose window starts on the first tick. A window that closes without one observation starts observing instead of saving wherever macOS left the display; first contact still records the initial spot. Ported onto this line's VirtualDisplay rather than cherry-picked (the original conflicts). The fork-only repositionForHeadlessMain gets retarget(to:), which re-arms the window without marking the new origin observed, so a headless move whose applies all fail never saves the display's current spot. Upstream's nine OriginRestore tests are kept; two more cover the headless retarget. Original change by peetzweg in upstream OpenDisplay (GPL-3.0), PR 392, closing upstream issue 390. (adapted from commit 1522cd2)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A virtual display rebuilt right after the Mac wakes no longer loses its saved position. Before this change, a stalled first check could save macOS's default spot as if the user had dragged the display there. Every later session then placed the display in that wrong spot.
This ports upstream OpenDisplay's fix onto MeowDisplay's
VirtualDisplay. It is a manual adaptation, not a cherry-pick.Upstream source
peetzweg/opendisplay#390: "Display arrangement lost when a post-sleep rebuild stalls the restore window"peetzweg/opendisplay#392: "fix(mac): start the arrangement restore window on the first tick"1522cd22699b21932d69c718b4afc18bee45d546, by peetzweg, GPL-3.0 (the same licence as this repository)The upstream references are in code spans on purpose, so this PR adds no cross-reference events to the upstream tracker.
The bug (present here at
cbbad7f)Mac/VirtualDisplay.swiftstarted the 6 s arrangement restore window ininit.ensureNotMirrored(), thenselectHiDPIMode(), thenmanageOrigin().manageOrigin()runs after the window has already closed. It sees macOS's default origin and reports it throughonOriginChange.DisplayArrangement.savethen overwrites the device's saved placement.resize(…, movingTo:)started its new window from the wall clock in the same way.What changes (4 files, +244 / −47)
Mac/OriginRestore.swift(new): upstream's pure restore/observe policy. The window now starts on the first tick, not when it is armed. A window that closes before any check succeeds starts observing instead of saving wherever macOS left the display. On first contact (no saved placement), the initial spot is still recorded.Mac/VirtualDisplay.swift: three restore fields become oneoriginRestore.initarms the restore.resizecallsrearm(at:).manageOriginswitches ontick(origin:).MacTests/OriginRestoreTests.swift(new): upstream's 9 tests, unchanged, plus 2 tests for this fork.project.yml: addsMac/OriginRestore.swiftto the hostlessOpenSidecarMacTestssources. The app picks it up through- Mac.Why not a cherry-pick
A dry-run cherry-pick of
1522cd2conflicts inMac/VirtualDisplay.swiftandproject.yml. Upstream'sVirtualDisplayhas diverged from this fork's: this fork has its own HiDPI enforcement and a headless-main path that upstream doesn't have.Fork-specific handling: headless main display
This fork's
repositionForHeadlessMain(to:)moves the virtual display to (0,0) when no usable physical display exists. This gives macOS's login and lock UI a main display to render on. It used to re-arm the same restore window.OriginRestore.retarget(to:). This restarts the window on the next tick without marking (0,0) as observed.rearm(at: .zero)instead would have saved a spurious drag when the window closed. A dedicated test covers this case.manageOrigin's; it is split back into two.Not touched: sender session management, transport, pairing/TLS,
DisplayArrangementstorage, the wire protocol, and the existing sleep/lock capture recovery.OriginRestoreis a value type mutated only insideVirtualDisplay, through the same main-thread call sites as the fields it replaces, so there is no new concurrency surface.Verification
xcodebuild test -scheme OpenSidecarMac -destination platform=macOS, unsigned. Result: TEST SUCCEEDED, 1856 tests, 0 failures (1845 before + 11OriginRestoreTests). The touched files compile inOpenSidecarMacandOpenSidecarMacTestswith no warnings; the 7 warnings in the log are pre-existing.879da2c, which contains feat(mac): independent Mirror/Extend per connected device #24 and feat(mac-receiver): keyboard and trackpad control of the sending Mac #25) with this commit. Result: TEST SUCCEEDED, 2013 tests, 0 failures.git merge-treedry runs are clean into feat(mac): independent Mirror/Extend per connected device #2466de410, feat(mac-receiver): keyboard and trackpad control of the sending Mac #25ffd2b6b, feat(mac): one MeowDisplay app that can also be a display #26879da2c, fix(ios): touch-control UX fixes, a Return key and 8× local zoom #272ea0025andrelease/app-store-rc.report(1512,0)(the bug).OriginRestorereturnsapply(saved)and reports nothing afterwards.Tests/mac, Xcode 26.6 on macos-26-arm64): the Mac test step passed: 1856 tests, 0 failures,** TEST SUCCEEDED **, with all 11OriginRestoreTestsgreen. The job then fails in its later iOS build step:iOS/ReceiverControls.swift:1426: the compiler is unable to type-check this expression in reasonable time.cbbad7f.Testsrun since 2026-10-25 11:26, including feat(mac): independent Mirror/Extend per connected device #24–fix(ios): touch-control UX fixes, a Return key and 8× local zoom #27 (fix(ios): touch-control UX fixes, a Return key and 8× local zoom #27 reports line 1488).Not verified
origin … → restored, followed by no arrangement save of macOS's default.Attribution
The original change is by peetzweg in upstream OpenDisplay. The commit message credits peetzweg and records
(adapted from commit 1522cd22699b21932d69c718b4afc18bee45d546). The commit is authored with this repository's maintainer identity because it contains fork-specific code beyond the upstream change.Draft. Not for merge until the hardware check above is done.