This commit is contained in:
jahruz67
2026-05-08 17:09:25 -07:00
parent afe0692da3
commit 5bf321b22e
6 changed files with 94 additions and 10 deletions
+8
View File
@@ -74,6 +74,14 @@ func (a *App) startup(ctx context.Context) {
// Initialize components
a.startupHeadless()
// When the user launches the app again while it is already running (tray-only),
// the second process signals us here so the settings window becomes visible.
go func() {
for range secondInstanceWake {
wailsruntime.WindowShow(ctx)
}
}()
// Start system tray in a goroutine
go tray.Start(a)
}
+1 -3
View File
@@ -134,7 +134,5 @@ func getLogPath() (string, error) {
return "", err
}
return filepath.Join(homeDir, ".wis-free-v3", "logs"), nil
return filepath.Join(homeDir, ".wis-free-v3", "logs", time.Now().Format("2006-01-02")+".log"), nil
}
+6 -6
View File
@@ -48,8 +48,13 @@ func main() {
// Ensure only one instance of the application is running
if !acquireInstanceLock() {
// Another copy is already running (often left in the tray). Without this,
// we would exit silently and the user sees "nothing happens" when clicking
// the launcher again.
tryNotifyRunningInstanceToShow()
os.Exit(0)
}
runSecondInstanceListener()
// Initialize the application
app := NewApp()
@@ -64,9 +69,7 @@ func main() {
OnStartup: app.startup,
OnShutdown: app.Shutdown,
OnBeforeClose: app.beforeClose,
// On Linux, starting hidden makes it look like "nothing happens" if the tray icon
// fails to initialize (missing libayatana-appindicator, etc) or is hidden by the DE.
StartHidden: runtime.GOOS == "windows",
StartHidden: true,
Bind: []interface{}{app},
})
@@ -147,6 +150,3 @@ func getLockPath() (string, error) {
}
return filepath.Join(homeDir, configDir, lockFile), nil
}
+10
View File
@@ -0,0 +1,10 @@
//go:build windows
package main
// secondInstanceWake is unused on Windows (second-instance UX not wired here).
var secondInstanceWake = make(chan struct{}, 8)
func tryNotifyRunningInstanceToShow() {}
func runSecondInstanceListener() {}
+65
View File
@@ -0,0 +1,65 @@
//go:build unix && !windows
package main
import (
"io"
"net"
"os"
"path/filepath"
"time"
)
const instanceSockName = "instance.sock"
// secondInstanceWake is closed when a second process asks the running app to show its window.
var secondInstanceWake = make(chan struct{}, 8)
func instanceSocketPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, configDir, instanceSockName), nil
}
func tryNotifyRunningInstanceToShow() {
path, err := instanceSocketPath()
if err != nil {
return
}
c, err := net.DialTimeout("unix", path, 500*time.Millisecond)
if err != nil {
return
}
defer c.Close()
_, _ = c.Write([]byte{1})
}
func runSecondInstanceListener() {
path, err := instanceSocketPath()
if err != nil {
return
}
_ = os.Remove(path)
l, err := net.Listen("unix", path)
if err != nil {
return
}
go func() {
for {
c, err := l.Accept()
if err != nil {
return
}
go func(conn net.Conn) {
defer conn.Close()
_, _ = io.Copy(io.Discard, conn)
select {
case secondInstanceWake <- struct{}{}:
default:
}
}(c)
}
}()
}
+4 -1
View File
@@ -150,12 +150,15 @@ if [[ "$INSTALL" == "y" || "$INSTALL" == "Y" ]]; then
sudo cp "build/appicon.png" "$ICON_PATH"
fi
# Absolute Exec path: some desktop environments do not put /usr/local/bin on PATH
# for .desktop launches, so "Exec=wis-free-v3" can fail with no visible error.
cat << EOF > /tmp/$APP_NAME.desktop
[Desktop Entry]
Type=Application
Name=WIS Free V3
Comment=Voice Dictation App
Exec=$APP_NAME
Exec=/usr/local/bin/$APP_NAME
TryExec=/usr/local/bin/$APP_NAME
Icon=$APP_NAME
Terminal=false
Categories=Utility;Audio;