Two independent gaps meant the packaged app showed no icon at runtime:
bcc.spec had datas=[] — the icons/ folder was never bundled into the frozen app, so any runtime QIcon(...) load failed in packaged builds (this also silently broke the About-dialog icon).
main() never set an application/window icon and did not set a Windows AppUserModelID, so the taskbar/window fell back to the default host icon even though the .exe PE resource icon (icons/app.ico) was set.
Fix
bcc.spec: datas=[("icons", "icons")] so the icon assets ship inside the bundle (all platforms).
bcc.py:
_asset_dir() — resolves assets for both a source run and a frozen PyInstaller onefile build (sys._MEIPASS).
_app_icon() — builds a multi-resolution QIcon from the bundled PNGs (16–512), falling back to app.ico.
main() sets app.setWindowIcon(_app_icon()), and on Windows calls SetCurrentProcessExplicitAppUserModelID(...) (guarded in try/except) so the taskbar groups under our own icon.
AboutDialog now resolves its icon via _asset_dir() too, so it works in packaged builds.
tests/test_core.py: a guard test asserting the referenced icon assets exist (so the spec mapping / icon sizes can't silently drift).
Verification
ruff check, ruff format --check, pytest all green (166 tests). bcc.py validated via ast.parse + ruff (PySide6 not installed in CI sandbox).
Needs real-Windows confirmation
The runtime taskbar-icon behavior (AppUserModelID + bundled icon) can only be fully verified on a packaged Windows build — the code path is correct-by-inspection and fully guarded, but worth a visual check on the next Windows release artifact.
Closes #20
## Root cause
Two independent gaps meant the packaged app showed no icon at runtime:
1. **`bcc.spec` had `datas=[]`** — the `icons/` folder was never bundled into the frozen app, so any runtime `QIcon(...)` load failed in packaged builds (this also silently broke the About-dialog icon).
2. **`main()` never set an application/window icon** and did not set a Windows **AppUserModelID**, so the taskbar/window fell back to the default host icon even though the `.exe` PE resource icon (`icons/app.ico`) was set.
## Fix
- `bcc.spec`: `datas=[("icons", "icons")]` so the icon assets ship inside the bundle (all platforms).
- `bcc.py`:
- `_asset_dir()` — resolves assets for both a source run and a frozen PyInstaller onefile build (`sys._MEIPASS`).
- `_app_icon()` — builds a multi-resolution `QIcon` from the bundled PNGs (16–512), falling back to `app.ico`.
- `main()` sets `app.setWindowIcon(_app_icon())`, and on Windows calls `SetCurrentProcessExplicitAppUserModelID(...)` (guarded in try/except) so the taskbar groups under our own icon.
- `AboutDialog` now resolves its icon via `_asset_dir()` too, so it works in packaged builds.
- `tests/test_core.py`: a guard test asserting the referenced icon assets exist (so the spec mapping / icon sizes can't silently drift).
## Verification
`ruff check`, `ruff format --check`, `pytest` all green (166 tests). `bcc.py` validated via `ast.parse` + ruff (PySide6 not installed in CI sandbox).
## Needs real-Windows confirmation
The runtime taskbar-icon behavior (AppUserModelID + bundled icon) can only be fully verified on a packaged Windows build — the code path is correct-by-inspection and fully guarded, but worth a visual check on the next Windows release artifact.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #20
Root cause
Two independent gaps meant the packaged app showed no icon at runtime:
bcc.spechaddatas=[]— theicons/folder was never bundled into the frozen app, so any runtimeQIcon(...)load failed in packaged builds (this also silently broke the About-dialog icon).main()never set an application/window icon and did not set a Windows AppUserModelID, so the taskbar/window fell back to the default host icon even though the.exePE resource icon (icons/app.ico) was set.Fix
bcc.spec:datas=[("icons", "icons")]so the icon assets ship inside the bundle (all platforms).bcc.py:_asset_dir()— resolves assets for both a source run and a frozen PyInstaller onefile build (sys._MEIPASS)._app_icon()— builds a multi-resolutionQIconfrom the bundled PNGs (16–512), falling back toapp.ico.main()setsapp.setWindowIcon(_app_icon()), and on Windows callsSetCurrentProcessExplicitAppUserModelID(...)(guarded in try/except) so the taskbar groups under our own icon.AboutDialognow resolves its icon via_asset_dir()too, so it works in packaged builds.tests/test_core.py: a guard test asserting the referenced icon assets exist (so the spec mapping / icon sizes can't silently drift).Verification
ruff check,ruff format --check,pytestall green (166 tests).bcc.pyvalidated viaast.parse+ ruff (PySide6 not installed in CI sandbox).Needs real-Windows confirmation
The runtime taskbar-icon behavior (AppUserModelID + bundled icon) can only be fully verified on a packaged Windows build — the code path is correct-by-inspection and fully guarded, but worth a visual check on the next Windows release artifact.