Skip to content

Windows support: tray, toasts, single-instance, native dialogs, icon pipeline - #1

Open
ChampionDesigns wants to merge 1 commit into
johnbuckman:mainfrom
ChampionDesigns:windows-support
Open

Windows support: tray, toasts, single-instance, native dialogs, icon pipeline#1
ChampionDesigns wants to merge 1 commit into
johnbuckman:mainfrom
ChampionDesigns:windows-support

Conversation

@ChampionDesigns

Copy link
Copy Markdown

Makes bping run cleanly on Windows 10/11 from the same codebase, with zero macOS behavior changes — every divergent behavior is gated (process.platform === 'win32' in main.js, a .win32 class on <html> for renderer CSS), per the conventions now documented in CLAUDE.md's new "Windows support" section.

What Windows needed

Area Change
Notifications app.setAppUserModelId (toasts are silently dropped without it) + toast icon
Lifecycle win32-only single-instance lock — a second launch focuses the running app instead of EADDRINUSE-ing the OAuth loopback port; close-to-tray so background ping polling survives the window closing (guarded: never blocks shutdown/logoff, never hides the window if tray creation failed)
Dialogs window.confirm/alert leave the keyboard dead after closing on Windows (long-standing Electron bug), so win32 routes through dialog.showMessageBox IPC; macOS keeps native confirm/alert verbatim
Menu/DevTools Menu.setApplicationMenu(null) on win32 (the default menu renders inside the window, over the 100vh layout); F12 / Ctrl+Shift+I rebound for main-window DevTools, Ctrl+Alt+Shift+I falls through to the webview chord
Window 1240×840 clamped to the display work area (common 150%-DPI laptops have a 720px-logical-height work area; no-op wherever the current size fits, including all modern Macs)
OAuth server best-effort [::1] twin listener (browsers resolve localhost to ::1 first; a stray IPv6 listener could swallow the callback); EACCES gets an actionable message (Windows excluded port ranges); the reflected error param is now HTML-escaped
UI setup screen shows the real per-OS config path via state:get; thin scrollbars scoped under .win32 (Windows scrollbars are always-visible and ate into the fixed 320px sidebar)
Packaging tools/make-ico.js — dependency-free ICNS→ICO converter (PNG entries 32/64/128/256); icon.ico committed as a runtime asset (tray + window icon); npm run package:windist/bping-win32-x64/bping.exe with proper exe metadata. build-dmg.sh and the darwin scripts are untouched

Verified on Windows 11

Boots to the setup screen (real %APPDATA%\bping\config.json path shown, no in-window menu bar), tray created, WM_CLOSE → process survives hidden with polling alive, second launch hands off and re-shows the window, packaged exe boots with close-to-tray intact, full OAuth sign-in flow completed against a real Basecamp account.

Note for review

macOS safety was verified by code trace only (no Mac on hand) — a quick npm start smoke on your machine would be a welcome double-check. The macOS deltas are limited to: restore-if-minimized on notification click, the work-area clamp (no-op on displays where 1240×840 fits), the ::1 twin listener, and the setup screen showing the expanded config path instead of the ~-literal.

🤖 Generated with Claude Code

…pipeline

Make the app run cleanly on Windows while keeping every macOS code path
byte-identical (win32 behavior is gated on process.platform in main.js and
a .win32 <html> class in the renderer):

- app.setAppUserModelId + toast icon so Windows notifications work
- win32-only single-instance lock (second launch focuses the running app
  instead of EADDRINUSE-ing the OAuth loopback port)
- close-to-tray: closing the window hides to the system tray so background
  ping polling survives; guarded so shutdown/logoff are never blocked and
  the window is never hidden without a tray to bring it back
- native dialog IPC (dialog:confirm/alert) replaces window.confirm/alert on
  Windows only (Electron-on-Windows dead-keyboard-after-dialog bug)
- Menu.setApplicationMenu(null) on win32 (default menu renders inside the
  window) with F12 / Ctrl+Shift+I rebound for main-window DevTools
- clamp the 1240x840 window to the display work area (no-op where it fits)
- best-effort [::1] twin for the OAuth callback server; EACCES port errors
  get an actionable message (Windows excluded port ranges)
- setup screen shows the real per-OS config path from state:get
- win32-scoped thin scrollbar CSS; Ctrl variant of the webview DevTools chord
- tools/make-ico.js: dependency-free ICNS->ICO converter; icon.ico committed
  as a runtime asset (tray + window icon); npm run package:win builds
  dist/bping-win32-x64 with proper exe metadata
- HTML-escape the error param reflected by the OAuth callback page
- README + CLAUDE.md Windows sections

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant