fix(tray): support Windows socket paths and always run the tray companion on Windows

The tray IPC socket was hardcoded to /run/theta/tray.sock and /tmp/theta-tray.sock,
which cannot be bound on Windows (they resolve to C:\run\... and C:\tmp\... and need
admin rights). The daemon now binds a Unix socket under the per-user temp dir on
Windows, and the tray companion dials the same path.

The tray also exited immediately on Windows because it checked DISPLAY/WAYLAND_DISPLAY,
which are never set there. That graphical-session guard is now Windows-only; the tray
always runs on Windows.
This commit is contained in:
2026-08-09 16:11:42 -07:00
parent e13aa6a15c
commit 565a171797
2 changed files with 43 additions and 12 deletions
+17 -4
View File
@@ -26,6 +26,8 @@ import (
"log"
"net"
"os"
"path/filepath"
"runtime"
"time"
"fyne.io/systray"
@@ -33,7 +35,16 @@ import (
// ── IPC types (duplicated from the main agent package; tray is its own binary) ──
const TraySocket = "/run/theta/tray.sock"
// traySocketPaths returns the daemon IPC socket paths for this platform, in
// the same order the daemon tries to bind them. Windows has no /run or /tmp,
// so it uses a Unix socket under the per-user temp dir; Linux keeps the
// original pair.
func traySocketPaths() []string {
if runtime.GOOS == "windows" {
return []string{filepath.Join(os.TempDir(), "theta-tray.sock")}
}
return []string{"/run/theta/tray.sock", "/tmp/theta-tray.sock"}
}
type TrayColor string
@@ -73,8 +84,10 @@ var (
// ── Main ─────────────────────────────────────────────────────────────────────
func main() {
// Silent exit if no graphical session is available.
if os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" {
// Silent exit if no graphical session is available. Only meaningful on
// X11/Wayland: Windows never sets these variables and the tray is simply
// always a valid thing to run there.
if runtime.GOOS != "windows" && os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" {
log.Println("theta-agent-tray: no graphical session detected (DISPLAY/WAYLAND_DISPLAY not set), exiting")
os.Exit(0)
}
@@ -149,7 +162,7 @@ func onReady() {
// between attempts. On connect it streams status updates until the connection
// drops, then retries.
func connectWithRetry() {
socketPaths := []string{"/run/theta/tray.sock", "/tmp/theta-tray.sock"}
socketPaths := traySocketPaths()
for {
var conn net.Conn
var err error