Repository navigation
Stream: follow a window the streamed app opens in front, and come back - #182
Open
grub-basket wants to merge 2 commits into
Open
grub-basket wants to merge 2 commits into
grub-basket wants to merge 2 commits into
Conversation
Reported on a device: opening a new window of the app being streamed
(iTerm's New Window, Claude's "Check for Updates..." dialog) left the
iPad on the old window. In regular mode only the picked window is
captured, so a window the app put in front of it never showed; the
stream switched to a new window only after a launch from the device
(pendingLaunch).
- WindowFollow (pure): the frontmost window on the Mac
(topmostWindow(at: nil)) is followed when it is new since the last
catalog (never from the first one), listed now, and of the same app
as the window streaming, by bundle ID (an empty bundle ID never
matches; the streamed window's app is taken from the previous
catalog when it closed in the same poll). back() unwinds a stack of
windows followed from, skipping any that closed, so a dialog over a
dialog over the main window comes back one at a time.
- StreamCoordinator.windowsChanged: after a pending launch, and only
in regular mode (on the virtual display the app's other windows
already show over the picked one) and not mid-switch, a followed
window is selected without bringForward (it is in front already),
with one line ("Following Claude's new window 1234 (from window
987)."). When the streamed window closes and the stack has a
window still listed, the stream goes back to it (brought forward),
with a line, instead of stopping. A device's pick or a launch clears
the stack.
- On by default; `defaults write me.saffer.sill.mac followNewWindows
-bool NO` turns it off (no Settings UI yet).
Known limits: a window that is in the catalog for a poll before it
comes to the front is not followed (the next poll no longer counts it
as new); with an Aa scale set, a followed dialog is fitted to the panel
like any pick.
Tests/checks/window-follow: 18 checks, 9 of 9 mutants caught; README
and CI's mutants matrix.
Tested: swift build -c release, the check and its mutants. Not tested
live: it needs real windows and Screen Recording, and the Mac's Sill
was in use from an iPad at the time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From an independent review of the previous commit. The catalog lists only on-screen windows, so "not in the last catalog" also matched a window that came back rather than one the app opened: un-minimized from the Dock, its app shown again after being hidden, or in front after a switch to another Space. The stream jumped to it, and switching Spaces back and forth bounced between two windows while the follow stack grew. - WindowFollow.next takes `seen`, every window ID a catalog has listed since the first device came; a window in it is not new. The last catalog (`previous`) still judges the first poll and the streamed window's app. This is the same rule the owner suggested for new windows' place in the bar on Saffsanity#111 (new only the first time it is listed in a session). - StreamCoordinator keeps `seenWindows` beside `lastCatalog`, and both, with the follow stack, start afresh when the first device comes and when the last one leaves. Before, a catalog taken with no device (the CLI started with a preselected window) was compared with the first poll after a device connected, possibly hours later, and could follow a window at once. Left as known limits, for the owner's call (in the PR): following goes through the normal pick, so with a window fitted to the device the window followed from goes back to its own size (Saffsanity#57) and the dialog is fitted, then the first window is fitted again on the way back; whether sheets are listed as windows of their own (they would then stream without the window around them); and a follow whose switch fails ends the stream rather than staying on or returning to the first window. Tests/checks/window-follow: 20 checks (2 new: a window back from the Dock or another Space is not followed; one never listed is), 11 of 11 mutants caught (2 new, 1 pattern updated). Tested: the check and its mutants, swift build -c release, and Tests/checks/run-all.sh on the previous commit. Not tested live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Opening a new window of the app being streamed (iTerm's New Window, an app's "Check for Updates…" dialog, a Settings window) leaves the device on the old window. In regular mode only the picked window is captured, so the window the app put in front never shows; today the stream moves to a new window only after a launch from the device (
pendingLaunch).This makes Sill for Mac follow it, the way the Mac's own screen would, and come back when it closes. Mac only: no wire change, nothing on the device.
WindowFollow(pure, new): the frontmost window on the Mac (topmostWindow(at: nil)) is followed when it is new (never listed before since the first device came, so not a window back from the Dock, a hidden app or another Space; never from the first catalog), listed now, and of the same app as the window streaming, by bundle ID (an empty bundle ID never matches; the streamed window's app comes from the previous catalog when it closed in the same poll).back()unwinds a stack of windows followed from, skipping any that closed, so a dialog over a dialog over the main window comes back one at a time.StreamCoordinator.windowsChanged: after a pending launch, and only in regular mode (on the virtual display the app's other windows already show over the picked one) and not mid-switch, a followed window is selected withoutbringForward(it is in front already), with one line: "Following Claude's new window 1234 (from window 987)." When the followed window closes and the stack has a window still listed, the stream goes back to it (brought forward) with a line, instead of stopping. A device's pick or a launch clears the stack.defaults write me.saffer.sill.mac followNewWindows -bool NOturns it off. No Settings row yet: happy to add one (or flip the default) if you'd rather.Tests/checks/window-follow: 20 checks, 11 of 11 mutants caught; in the checks README and CI's mutants matrix.Known limits (your call; happy to change any of them):
Tested:
swift build -c release(only the CaptureProbe warning);Tests/checks/run-all.sh, all passing, on this branch (cut from main at 4d990e9); the new check and its mutants; an independent review, whose findings are fixed in the second commit or listed above. Not tested live: it needs real windows and Screen Recording, so it hasn't been run against a real app stream yet. If it misbehaves in practice I'll update this PR.Related to #111 (new windows go first in the bar), but independent of it.
🤖 Generated with Claude Code