Files
keeporg/cmd/keeporg/desktop.go
T
ReactorcoremeltdownandClaude Opus 5.5 ead82dc777 Turn the desktop client into a system tray application
Started without a command, keeporg now shows a padlock in the system tray
with a menu like midi-webhook's: a status line, the mirror folder, each
database with its state, Sync Now, browser sign-in and sign-out, the web
interface, the configuration, the log, Start at Login, About and Quit. The
commands are unchanged.

config.json now carries every client setting (device_label,
request_timeout_seconds, ca_file, log_file, notifications), is written in
full on first start and is reloaded by the tray when saved.

A lock in the mirror directory admits one agent at a time, since the tray,
`keeporg run` and a service unit could otherwise race each other.

The tray uses fyne.io/systray: pure Go on Linux, BSD and Windows, cgo on
macOS only. The server keeps no third-party dependencies.

Desktop versions go to 0.5.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 12:30:28 +01:00

59 lines
1.6 KiB
Go

package main
import (
"fmt"
"os/exec"
"runtime"
)
// homepage is where About points.
const homepage = "https://garage.rcmd.space/keeporg"
// openPath opens a file, directory or URL with whatever the desktop
// associates with it. It is best effort: a caller that matters also logs or
// prints the target.
func openPath(target string) {
var cmd *exec.Cmd
switch runtime.GOOS {
case "darwin":
cmd = exec.Command("open", target)
case "windows":
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", target)
default:
cmd = exec.Command("xdg-open", target)
}
_ = cmd.Start()
}
// openText opens a file in a text editor. JSON is associated with an IDE or
// a browser often enough that "open" is not good enough for a config file.
func openText(path string) {
switch runtime.GOOS {
case "darwin":
_ = exec.Command("open", "-t", path).Start()
case "windows":
_ = exec.Command("notepad", path).Start()
default:
openPath(path)
}
}
// notify shows a desktop notification, best effort. Windows has none without
// a third-party library; the menu's first line carries the same news there.
func notify(title, message string) {
switch runtime.GOOS {
case "darwin":
_ = exec.Command("osascript", "-e",
fmt.Sprintf("display notification %q with title %q", message, title)).Start()
case "windows":
default:
_ = exec.Command("notify-send", "--app-name=KeepOrg", "--icon=keeporg", title, message).Start()
}
}
// aboutText is the About dialog's body.
func aboutText(configPath string) string {
return fmt.Sprintf("KeepOrg %s\n\nKeePass database synchronization.\n\nConfiguration: %s\n%s",
Version, configPath, homepage)
}