feat(notify): Windows toasts under talk's own identity, icon on Linux
The daemon (and talk test --toast) now register the AppUserModelID m3ta.talk under HKCU with display name and the installed icon, so toasts appear as "talk" with the icon instead of Windows PowerShell; the PowerShell identity stays as fallback until the registration has run once. The redundant "talk" title line is dropped under the own identity. notify.Setup bundles icon install, identity and the talk: protocol handler for both callers. Linux notifications carry the installed icon as app_icon. doctor names the active identity. Verified on the Windows 11 VM: registry key, icon file, toast with working Cancel button, exe icon; Linux via quickshell. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
2e77cf0a11
commit
2d9d2a86e9
10 files changed
+290
-48
No files matched your search
@@ -0,0 +1,60 @@
|
||||
//go:build windows
|
||||
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// appIDKey is where Windows looks up the identity (name, icon) of an
|
||||
// unpackaged program that shows toasts: HKCU, so no admin rights.
|
||||
const appIDKey = `Software\Classes\AppUserModelId\` + AppID
|
||||
|
||||
var (
|
||||
identityMu sync.Mutex
|
||||
identityKnown bool
|
||||
identityOK bool
|
||||
)
|
||||
|
||||
// UseIcon registers talk's own toast identity for the current user: the
|
||||
// AppUserModelID AppID with display name "talk" and the icon at iconPath.
|
||||
// Toasts then appear as coming from talk instead of Windows PowerShell.
|
||||
// Idempotent; rewritten on every call so it follows the icon's location.
|
||||
func UseIcon(iconPath string) error {
|
||||
setIconPath(iconPath)
|
||||
k, _, err := registry.CreateKey(registry.CURRENT_USER, appIDKey, registry.SET_VALUE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("registering toast identity: %w", err)
|
||||
}
|
||||
defer k.Close()
|
||||
if err := k.SetStringValue("DisplayName", Title); err != nil {
|
||||
return fmt.Errorf("registering toast identity: %w", err)
|
||||
}
|
||||
if err := k.SetStringValue("IconUri", iconPath); err != nil {
|
||||
return fmt.Errorf("registering toast identity: %w", err)
|
||||
}
|
||||
identityMu.Lock()
|
||||
identityKnown, identityOK = true, true
|
||||
identityMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ownIdentity reports whether AppID is registered for this user (by this
|
||||
// process or an earlier daemon start); checked once per process.
|
||||
func ownIdentity() bool {
|
||||
identityMu.Lock()
|
||||
defer identityMu.Unlock()
|
||||
if !identityKnown {
|
||||
identityKnown = true
|
||||
identityOK = false
|
||||
if k, err := registry.OpenKey(registry.CURRENT_USER, appIDKey, registry.QUERY_VALUE); err == nil {
|
||||
_, _, err := k.GetStringValue("IconUri")
|
||||
identityOK = err == nil
|
||||
k.Close()
|
||||
}
|
||||
}
|
||||
return identityOK
|
||||
}
|
||||
Reference in new issue
Block a user