Release version 0.2.2
Add Linux desktop integration that installs a user-level .desktop file and icon under XDG data directories so taskbars can match the PySentry window to the application icon. Pass the installed icon path into Linux autostart desktop entries when available, while keeping the Windows and fallback autostart APIs compatible. Bump the application version to 0.2.2, update README artifact examples, and record the release notes in docs/CHANGELOG.md. Also adjust the Mermaid architecture diagram so Gitea can render it without invalid SVG line-break tags.
This commit is contained in:
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
const autostartDesktopFileName = "pysentry.desktop"
|
||||
|
||||
func SetAutostart(enabled bool, executablePath string) error {
|
||||
func SetAutostart(enabled bool, executablePath string, iconPath string) error {
|
||||
desktopPath, err := autostartDesktopPath()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -31,9 +31,10 @@ Type=Application
|
||||
Name=PySentry
|
||||
Comment=PySentry desktop scheduler
|
||||
Exec=%s
|
||||
%s
|
||||
Terminal=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
`, quoteDesktopExec(executablePath))
|
||||
`, quoteDesktopExec(executablePath), desktopIconLine(iconPath))
|
||||
return os.WriteFile(desktopPath, []byte(desktopFile), 0o644)
|
||||
}
|
||||
|
||||
@@ -84,6 +85,13 @@ func quoteDesktopExec(path string) string {
|
||||
return strconv.Quote(path)
|
||||
}
|
||||
|
||||
func desktopIconLine(iconPath string) string {
|
||||
if strings.TrimSpace(iconPath) == "" {
|
||||
return ""
|
||||
}
|
||||
return "Icon=" + iconPath
|
||||
}
|
||||
|
||||
func cleanupLegacySystemdAutostart() error {
|
||||
unitPath, err := legacySystemdUnitPath()
|
||||
if err != nil {
|
||||
|
||||
@@ -4,7 +4,7 @@ package core
|
||||
|
||||
import "fmt"
|
||||
|
||||
func SetAutostart(enabled bool, executablePath string) error {
|
||||
func SetAutostart(enabled bool, executablePath string, iconPath string) error {
|
||||
if !enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
const autostartName = "PySentry"
|
||||
|
||||
func SetAutostart(enabled bool, executablePath string) error {
|
||||
func SetAutostart(enabled bool, executablePath string, iconPath string) error {
|
||||
if enabled {
|
||||
// Remove any stale entry first. This makes "uncheck, save, check, save"
|
||||
// and even a plain "check, save" repair an old path after the executable
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//go:build linux
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func InstallDesktopIntegration(appID string, executablePath string, icon []byte) (string, error) {
|
||||
dataHome, err := xdgDataHome()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// The taskbar can only show the application icon reliably when the desktop
|
||||
// environment can match the window app id to an installed .desktop file and
|
||||
// icon. Use the user's XDG data directory so portable builds do not need root
|
||||
// access or a package manager install step.
|
||||
iconPath := filepath.Join(dataHome, "icons", "hicolor", "256x256", "apps", "pysentry.png")
|
||||
if err := writeUserFile(iconPath, icon, 0o644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
desktopPath := filepath.Join(dataHome, "applications", appID+".desktop")
|
||||
desktopFile := fmt.Sprintf(`[Desktop Entry]
|
||||
Type=Application
|
||||
Name=PySentry
|
||||
Comment=PySentry desktop scheduler
|
||||
Exec=%s
|
||||
Icon=%s
|
||||
Terminal=false
|
||||
Categories=Utility;
|
||||
StartupWMClass=%s
|
||||
`, quoteDesktopExec(executablePath), iconPath, appID)
|
||||
if err := writeUserFile(desktopPath, []byte(desktopFile), 0o644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return iconPath, nil
|
||||
}
|
||||
|
||||
func xdgDataHome() (string, error) {
|
||||
dataHome := os.Getenv("XDG_DATA_HOME")
|
||||
if dataHome == "" {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dataHome = filepath.Join(home, ".local", "share")
|
||||
}
|
||||
return dataHome, nil
|
||||
}
|
||||
|
||||
func writeUserFile(path string, data []byte, perm os.FileMode) error {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, perm)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build !linux
|
||||
|
||||
package core
|
||||
|
||||
func InstallDesktopIntegration(appID string, executablePath string, icon []byte) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
@@ -25,6 +25,7 @@ type Paths struct {
|
||||
JobsDir string
|
||||
JobsPath string
|
||||
LogsDir string
|
||||
DesktopIcon string
|
||||
}
|
||||
|
||||
func ResolvePaths() (Paths, error) {
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ package core
|
||||
// Version is the application version shown in the GUI and used by build
|
||||
// scripts in artifact names. It is a var rather than a const so release builds
|
||||
// can override it with Go ldflags when CI tags a build.
|
||||
var Version = "0.2.1"
|
||||
var Version = "0.2.2"
|
||||
|
||||
Reference in New Issue
Block a user