feat: implement system tray interface and manage OS thread locking for cross-platform stability

This commit is contained in:
jahruz67
2026-05-08 16:26:47 -07:00
parent 0cd56ca083
commit f71d6ccd1d
3 changed files with 13 additions and 0 deletions
Binary file not shown.
+7
View File
@@ -5,6 +5,7 @@ package tray
import (
_ "embed"
"os"
"runtime"
"strings"
"wis-free-v3/internal/config"
@@ -40,6 +41,12 @@ var statusMenuItem *systray.MenuItem
// Start initializes and runs the system tray.
// This function blocks until the tray is terminated.
func Start(app App) {
// Pin this goroutine to one OS thread for the whole lifetime of systray.Run.
// getlantern/systray creates the notify icon and runs the Win32 message pump on
// whichever thread calls Run; if the goroutine migrates between threads, callbacks
// and the tray context menu break until restart (often seen after sleep/resume).
runtime.LockOSThread()
defer runtime.UnlockOSThread()
systray.Run(
func() { onReady(app) },
onExit,
+6
View File
@@ -6,6 +6,7 @@ import (
"embed"
"os"
"path/filepath"
"runtime"
"strconv"
"wis-free-v3/internal/logger"
@@ -40,6 +41,11 @@ var instanceLock *os.File
var AppVersion = "dev"
func main() {
// systray's package init calls runtime.LockOSThread() on the program's startup
// thread. Undo that so the main goroutine is not permanently bound; the tray
// goroutine locks itself in tray.Start instead (see internal/ui/tray/tray.go).
runtime.UnlockOSThread()
// Ensure only one instance of the application is running
if !acquireInstanceLock() {
os.Exit(0)