Repository navigation
Adopt ktsu.TrayApp and delete what it now owns - #3
Merged
Merged
Conversation
The tray host, the tray-versus-console decision and its fallback, Ctrl+C and SIGTERM, the --for timer, the standard flags, the --status report, the remembered tray state, and the MSBuild props that trim the tool payload were all extracted into ktsu.TrayApp. NoSleep consumes the package and deletes its copies: Cli/, Tray/, ConsoleRunner, DesktopSession, StatusReport, TrayPreferences, and the _TrimToolRuntimeAssets target. The NoSleep library - ISleepBlocker, KeepAwakeController, the platform blockers - is untouched. What is left in the tool is the menu, the three flags NoSleep adds, the --status rows only NoSleep can answer, and the wiring between them and KeepAwakeController. Program keeps the user's keep-awake intent in a local bool rather than calling Enable() from the toggle's setter, because a run restores preferences first, then applies the command line, and only then runs OnStart: a setter that enabled directly would have OnStart override an explicit --off, or a remembered "off", a moment later. Persistence moves from ktsu.AppDataStorage to ktsu.Essentials over the ConfigHome/Json/Native providers, assembled here because the library takes IPersistenceProvider<string> and nothing else. Remembered state now lives in nosleep/tray.json under the config home, so a previous install's state is not carried over. Three behaviour changes come with the move, none of them papered over: - nosleep --status now exits 0 on a machine with no inhibitor, where it used to exit 1. The library has no hook for the exit code. - The tray's status line no longer mentions the --for window: the library parses the duration and does not pass it to the status callback. - --off now applies in the console mode too, where it used to be ignored, because a flag handler cannot see which mode the run resolved to. Also: the debug environment variable is TRAYAPP_DEBUG rather than NOSLEEP_DEBUG, the generated usage block has no Examples section, and the console mode's own wording comes from the library. Verified: clean build with no warnings, 27 tests passing through the test host, the tray registering a StatusNotifierItem under Xvfb and D-Bus with a menu click flipping its state, the no-DISPLAY fallback, and a packed payload of 50,209,047 bytes against 190,046,536 with the package's trimming disabled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UfEY8ztrV4M9EuzX65T8QU
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.
ktsu.TrayAppwas extracted from this tool, so this migration is mostly deletion:NoSleep.Toolnow describes itself toTrayAppBuilderand the library brings the tray host, the tray-versus-console decision and its fallback, Ctrl+C andSIGTERM, the--fortimer, the standard flags, the--statusreport, debounced preference persistence, and the MSBuild props that trim the tool payload.The
NoSleeplibrary —ISleepBlocker,KeepAwakeController, the platform blockers — is untouched.What changed
Deleted (1,300 lines):
Cli/CommandLineOptions.cs,Cli/CommandLineParser.cs,Cli/DurationParser.cs,Cli/HelpText.cs,Tray/TrayApplication.cs,Tray/TrayIconAssets.cs,ConsoleRunner.cs,DesktopSession.cs,StatusReport.cs,TrayPreferences.cs, the_TrimToolRuntimeAssetstarget andNoSleepToolRuntimeIdentifiersin the csproj, theAvalonia/Avalonia.Desktop/Avalonia.Native/ktsu.AppDataStoragepackage references, and the tests that covered the deleted code (CommandLineParserTests,DurationParserTests, and the CLI/status/desktop-session cases inPlatformIntegrationTests).Added:
ktsu.TrayApp1.1.1, plusktsu.Essentialsand its ConfigHome / Json / Native providers, assembled inProgrambecause the library depends onIPersistenceProvider<string>only.Kept:
Assets/*.pngand theirEmbeddedResourceitem, and the embedded-resource assertion — retargeted to the tool assembly, since the names are still passed to the library as strings and a renamed asset is otherwise only a run-time failure on a machine with a display.Program.csis now the menu, the three flags NoSleep adds, the--statusrows only NoSleep can answer, and the wiring toKeepAwakeController.The one load-bearing detail
Programkeeps whether the user wants to be kept awake in a localbooland only acts on it inOnStart. A run restores preferences (tray only), then applies the command line, then starts; a toggle setter that calledEnable()directly would haveOnStartoverride an explicit--off, or a remembered "off", a moment later. Both paths are verified below.Behaviour differences
These are reported rather than worked around.
1.
nosleep --statusnow exits 0 on a machine with no inhibitor (it used to exit 1).TrayAppBuilder.RunAsyncwrites the report and returnsExitSuccessunconditionally, with no hook for the code. A script doingnosleep --status || ...changes behaviour; theKeep awake:row still saysnot supported on this machine. Verified here withenv PATH=/nonexistent nosleep --status→ exit 0.Proposed follow-up on
ktsu-dev/TrayApp: a.StatusExitCode(Func<int>)on the builder, defaulting to 0, consulted whereRunAsyncreturns after printing the report. NoSleep would pass() => controller.IsSupported ? 0 : 1and the difference disappears. (Not filed as an issue — say the word and I will.)2. The status line lost the
--forwindow. The tray used to readKeeping system awake for 2h; it now readsKeeping system awake. The library parses--forand does not expose the duration to the status callback. The console mode still prints, stopping after 0:00:05, so only the tray and theState:row of--statusare affected.Proposed follow-up: pass the resolved duration to the status callback (an overload taking
TimeSpan?, or aTrayRunContext).3.
--offnow applies in the console mode too, where it used to be documented and implemented as tray-only (ConsoleRunnerenabled unconditionally). A flag handler cannot see which mode the run resolved to —--tray/--no-trayare the library's and are not surfaced — so the flag now means what it says in both modes.nosleep --no-tray --off --for 3sruns for three seconds holding nothing. The(tray only)note is gone from the README.Proposed follow-up: hand
OnStartthe resolved mode, which would let a tool restore the old semantics.4. Smaller ones, all cosmetic but user-visible:
TRAYAPP_DEBUG=1, notNOSLEEP_DEBUG=1(README updated).Examples:section; the hand-written one did.nosleep: Keeping system awake, stopping after 0:00:05. Press Ctrl+C to stop.thennosleep: stopped., where it used to name the mechanism and end withreleased. This machine may sleep again.--statusgained aState:row and its rows reordered (Platform,Tray icon,State, then NoSleep'sMechanism/Keep awake/Keep display).NoSleep: ...) rather than the command name.ktsu.AppDataStoragetonosleep/tray.jsonunder the config home, so an existing install's remembered state is not carried over. It starts from the defaults once.Dependency note
Pinned to 1.1.1, the latest published version, and the restore guard is not in it. 1.1.1 is dependabot's Avalonia and ktsu-group bumps (ktsu-dev/TrayApp #2 and #4), cut from
mainbefore the guard branched. The fix for ktsu-dev/TrayApp#6 — an unguarded preference restore, where a toggle setter that throws while a remembered value is applied escapesRunAsyncand kills the process before the tray appears — is still unmerged and will land as 1.1.2 or later. Bump this pin once it publishes.NoSleep does not depend on that fix, and not by swallowing anything. Both toggles were checked against the code rather than assumed:
Keep awake— its setter records intent into a localbooland only touches the controller oncestartedis set inOnStart, so the restore never reachesEnable().Keep display awake too— passescontroller.SetKeepDisplayAwakestraight through, and that is invoked during the restore, beforeOnStart. It cannot throw there.SetKeepDisplayAwakedelegates toSetRequest, which touches the blocker only underif (isActive); nothing has enabled the controller yet, so there is noAcquireto refuse and noSleepBlockExceptionorPlatformNotSupportedExceptionto escape. Its only other throw isObjectDisposedException, and the controller is constructed inMainand disposed only afterRunAsyncreturns. ItsStateChangedinvocation is a no-op at that point too: the sole subscriber is wired byRefreshOn, which the library invokes inTrayApplication.OnFrameworkInitializationCompleted— afterLoadPreferences.So that toggle needs no intent-then-apply treatment of its own on 1.1.1. The refusal still surfaces from
OnStart, which the library runs throughTrayMenu.Run, so the tray comes up with the message in its status line — verified below. Worth re-checking if that setter ever gains work that can throw while the controller is inactive.Verification
All on this branch, in this container.
Build and tests.
dotnet buildclean, 0 warnings, 0 errors. 27/27 passing through the test host directly (./NoSleep.Test/bin/Debug/net10.0/ktsu.NoSleep.Test), sincedotnet testreports "Zero tests ran" here.Packaging — the win holds.
dotnet pack NoSleep.Tool -c Releaseruntimes/.pdbmain(csproj target)win-x64,win-x86,win-arm64,osx,linux-x64,linux-arm64,linux-arm)-p:TrayAppTrimToolRuntimeAssets=falseThe third row is the point: the props arriving from the package are doing the work, not a payload that happens to be small.
The tray, end to end (Xvfb +
dbus-launch+ the library'sscripts/status-notifier-watcher.pyandclick-tray-menu.py, with shimmed inhibitor helpers since this container has no logind bus). The watcher loggedregistered item: org.kde.StatusNotifierItem-2123-0, the run lasted its full window and exited 0, and clickingKeep awakegave:— the checked state flips, the status line re-reads itself, and
~/.config/nosleep/tray.jsongains"keep-awake": false.The start/stop ordering, which is the part that was easy to get wrong:
false: menu opens onNoSleep is off - this machine may sleep.OnStartdid not override it.--offagainst a rememberedtrue: same, so the flag beats the preference.Keep display awake toopersists"keep-display-awake": truealongside it.Failure and fallback:
PATH: the icon still comes up, status line readsNoSleep failed: Neither systemd-inhibit nor gnome-session-inhibit is installed..., both toggles disabled, quit works, exit 0 — no regression against today.--traywith noDISPLAY:nosleep: could not show a tray icon (XOpenDisplay failed). Staying in the terminal instead.then the run continues and exits 0.Command line:
--helpand--versionexit 0;--statusexits 0;--for 5sruns 5.3s and exits 0; an unknown option prints the usage and exits 2;SIGTERMreleases the helper process (no orphan) and exits 0;--display --reason "…"reaches the request before the inhibitor is taken.Not done
Not merged by me, and nothing pushed to
main— a push there runsktsubuild releaseand publishes, which is the owner's call.🤖 Generated with Claude Code
https://claude.ai/code/session_01UfEY8ztrV4M9EuzX65T8QU