Repository navigation
Conversation
Three things the tray needed, all in the same subsystem. The icon was not authored for a menu bar slot. A slot is 18pt, so 64px covers it at 3.5x and the Windows tray at 4x -- but the artwork was a 1254px canvas whose ring interior was filled with opaque white: invisible against a white page, a white blob on a dark menu bar, and 383,807 bytes of it. Rebuilt from the same artwork: interior and background made transparent so only the ring remains, cropped to the ink, resampled to the 64px ICON_PX already hands over. menubar-icon.png for a light menu bar and menubar-icon-dark.png for a dark one, where the navy arc is lifted toward a light slate and the blue accent is left alone. 383,807 bytes -> 8,789. That exposed a precedence bug: custom_icon_path() returns the first file that exists, and the bundled default was listed before ~/.headroom/icon.png, so a per-user icon could never win once an icon shipped. The per-user file now comes first, and a test pins it. A detached venv process lost Tcl. A venv interpreter resolves tcl_library from its base prefix, but a process started with start_new_session loses that and dies with "Cannot find a usable init.tcl" -- which reads as a missing Tk but is a search-path problem. That is exactly the setup the README recommends (~/.headroom/venv), so the menu bar could not start at all. Setting TCL_LIBRARY/TK_LIBRARY at import time makes every launch path behave the same. The card itself: the refresh button is a flat pill rather than a Tk button (Aqua ignores a button's background), the meter is a thin rounded line instead of a heavy bar, the percentage is split from its label, and the mood caption sits under a hairline. Fonts come from one UI_FONT/CJK_FONT pair so the card follows the platform instead of hard-coded Segoe UI. The icon was undocumented. README, README.zh-CN and SKILL.md now describe the bundled pair, the -dark sibling, HEADROOM_ICON and ~/.headroom/icon.png, and the drawn fallback. Tests pass on CPython 3.10, 3.11, 3.12 and 3.13, and with the tray dependencies installed so TrayIconTests actually run.
cat0825
force-pushed
the
logo-and-card
branch
from
September 26, 2026 04:58
c69973f to
7fc6ca2
Compare
…nswer a click The reader thread published its result with a plain put(), so `busy` was cleared only when a result arrived. A reader that raised outside the caught set -- or hit a full queue -- left every later refresh a silent no-op, which is exactly what "clicking refresh does nothing" looks like from the outside. The result is now published from a finally, and a full queue is drained rather than dropped. Clicking refresh also shows the loading label immediately, because the percentage rarely changes between two reads and the click otherwise looks ignored. Clicking the mood image did nothing in the card either, although the web dashboard plays a clip for it. The card now hops the image and plays one of the bundled audio clips with afplay, rotating so repeated clicks do not repeat the same sound. Tk cannot decode video, so the tray card stays audio-only; the animated clips remain in the web dashboard.
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.
Four things the tray needed, all in the same subsystem. If you would rather take them one at a time, the two bug fixes (Tcl discovery, the refresh button) are the ones worth splitting out; the rest is presentation.
1. The icon was not authored for a menu bar slot
A slot is 18pt, so 64px covers it at 3.5× and the Windows tray at 4×. The artwork was a 1254px canvas whose ring interior was filled with opaque white — invisible against a white page, a white blob on a dark menu bar — and 383,807 bytes of it.
Rebuilt from the same artwork:
ICON_PXalready hands overmenubar-icon.pngfor a light menu bar,menubar-icon-dark.pngfor a dark one, where the navy arc is lifted toward a light slate and the blue accent is left alone.custom_icon_path()already prefers a-darksibling, so this replaces the per-pixellighten_for_dark()pass with a hand-tuned file383,807 bytes → 8,789, and the drawn fallback is untouched — it still renders at 64px with a transparent corner and a white centre, exactly as
test_tray.pyasserts.A precedence bug that shipping an icon exposes
custom_icon_path()returns the first file that exists, and the bundled default was listed before~/.headroom/icon.png— so once an icon ships, a per-user icon can never win. The per-user file now comes first, and a test pins the order. This was dead code before; it would have become a silent bug the moment an icon landed.2. A detached venv process lost Tcl
A venv interpreter resolves
tcl_libraryfrom its base prefix, but a process started withstart_new_sessionloses that and dies with:That reads as a missing Tk, but it is a search-path problem — and it is exactly the setup the README recommends (
~/.headroom/venvplusrequirements-desktop.txt), so the macOS menu bar could not start at all in the documented configuration. SettingTCL_LIBRARY/TK_LIBRARYat import time makes every launch path behave the same.3. The refresh button could wedge permanently
The reader thread published its result with a plain
put(), sobusywas cleared only when a result arrived. A reader that raised outside the caught set — or hit a full queue — left every later refresh a silent no-op. That is exactly what "clicking refresh does nothing" looks like from the outside. The result is now published from afinally, a full queue is drained rather than dropped, and a click shows the loading label immediately because the percentage rarely changes between two reads.4. The card itself
tk.Button— Aqua ignores a button's background, so the old one rendered as the system default, not as designed.UI_FONT/CJK_FONTpair, so the card follows the platform instead of hard-codedSegoe UI/Microsoft YaHei UI.afplay, rotating so repeated clicks do not repeat the same sound. Tk cannot decode video, so the tray card stays audio-only.Docs
The icon was undocumented —
grep HEADROOM_ICON README.mdreturned nothing. README, README.zh-CN and SKILL.md now describe the bundled pair, the-darksibling,HEADROOM_ICON,~/.headroom/icon.png, and the drawn fallback.Tests
TrayIconTests(custom icon resolution, the-darksibling, the per-user precedence),TclLibraryTests(the search path, and that existing variables are left alone) and two new desktop tests for the reader and the mood click. Full suite passes on CPython 3.10, 3.11, 3.12 and 3.13, and with the tray dependencies installed so the tray tests actually execute rather than skip.One note on that last point:
test_tray.pyonly runs on Windows, so an earlier revision of this branch that raisedICON_PXto 72 passed locally and failed there. Reverted — 64 is the sizedraw_iconis drawn on, and raising it without rescaling that geometry would have left the drawn fallback off-centre.