aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--internal/notify/service.go27
-rw-r--r--internal/notify/service_test.go29
-rwxr-xr-xtest-notifyctl.sh6
3 files changed, 58 insertions, 4 deletions
diff --git a/internal/notify/service.go b/internal/notify/service.go
index 2442127..7bfad6e 100644
--- a/internal/notify/service.go
+++ b/internal/notify/service.go
@@ -73,6 +73,9 @@ func (s *Service) Start() error {
if err := s.conn.Export(&control{s}, dbus.ObjectPath(ctrlPath), ctrlIface); err != nil {
return err
}
+ if err := os.RemoveAll(ImagesDir(s.dir)); err != nil {
+ log.Printf("notifyd: clear images: %v", err)
+ }
s.store.Reset()
return nil
}
@@ -83,9 +86,10 @@ func (s *Service) emitClosed(id, reason uint32) {
// GetCapabilities tells clients what the daemon understands. actions and
// body-markup are load-bearing: mail-notify sends actions and escapes its body
-// because the running dunst advertises markup.
+// because the running dunst advertises markup. body-images says the daemon
+// decodes image-data and image-path, not just a static app icon.
func (s *Service) GetCapabilities() ([]string, *dbus.Error) {
- return []string{"actions", "body-markup", "icon-static", "persistence"}, nil
+ return []string{"actions", "body-markup", "body-images", "icon-static", "persistence"}, nil
}
func (s *Service) GetServerInformation() (string, string, string, string, *dbus.Error) {
@@ -99,19 +103,36 @@ func (s *Service) Notify(appName string, replacesID uint32, appIcon, summary, bo
tag := StackTagFromHints(hints)
now := time.Now().UnixMilli()
ms := EffectiveTimeoutMS(expireTimeout, u)
+ // image-data wins over image-path, and its blob cannot be written until
+ // Add has assigned the id the filename is derived from.
+ var pendingImage []byte
n := &Popup{
App: appName,
Summary: summary,
Body: body,
Urgency: u,
- Icon: appIcon,
+ Icon: ResolveIcon(appIcon),
Actions: ParseActions(actions),
Created: now,
}
+ if raw, ok := ImageDataFromHints(hints); ok {
+ if data, err := raw.PNG(); err == nil {
+ pendingImage = data
+ }
+ } else if path, ok := ImagePathFromHints(hints); ok {
+ n.Image = ResolveIcon(path)
+ }
if ms > 0 {
n.Expires = now + ms
}
id, _ := s.store.Add(n, tag, replacesID)
+ if pendingImage != nil {
+ if path, err := WriteImage(s.dir, id, pendingImage); err == nil {
+ s.store.SetImage(id, path)
+ } else {
+ log.Printf("notifyd: write image: %v", err)
+ }
+ }
s.arm(id, ms)
return id, nil
}
diff --git a/internal/notify/service_test.go b/internal/notify/service_test.go
index 871a0c7..735d01c 100644
--- a/internal/notify/service_test.go
+++ b/internal/notify/service_test.go
@@ -67,6 +67,35 @@ func TestIdentityAndCapabilities(t *testing.T) {
}
}
+func TestCapabilitiesIncludeBodyImages(t *testing.T) {
+ caps, err := NewService(nil, t.TempDir()).GetCapabilities()
+ if err != nil {
+ t.Fatal(err)
+ }
+ found := false
+ for _, c := range caps {
+ if c == "body-images" {
+ found = true
+ }
+ }
+ if !found {
+ t.Fatalf("body-images missing from %v", caps)
+ }
+}
+
+func TestNotifyPublishesImagePath(t *testing.T) {
+ var live []Popup
+ s := &Service{dir: t.TempDir(), timers: map[uint32]*time.Timer{}}
+ s.store = NewStore(s.emitClosed, func(l, _ []Popup) { live = l }, s.removeImage)
+ hints := map[string]dbus.Variant{"image-path": dbus.MakeVariant("/tmp/shot.png")}
+ if _, err := s.Notify("t", 0, "", "s", "b", nil, hints, -1); err != nil {
+ t.Fatal(err)
+ }
+ if len(live) != 1 || live[0].Image != "/tmp/shot.png" {
+ t.Fatalf("published %+v", live)
+ }
+}
+
func TestNotifyReturnsAnIDAndPublishes(t *testing.T) {
conn := busOrSkip(t)
dir := t.TempDir()
diff --git a/test-notifyctl.sh b/test-notifyctl.sh
index 7018e2a..e91307a 100755
--- a/test-notifyctl.sh
+++ b/test-notifyctl.sh
@@ -51,6 +51,9 @@ dbus-run-session -- bash -c '
notify-send -a test -u normal "t1" "b1" || exit 3
sleep 0.3
echo "$(notifyctl list | grep -c "\"summary\": \"t1\"")"
+ notify-send -a test -u normal --hint=string:image-path:/tmp/x.png "t2" "b2" || exit 3
+ sleep 0.3
+ echo "$(notifyctl list | grep -c "\"image\": \"/tmp/x.png\"")"
notifyctl close-all
sleep 0.3
echo "$(notifyctl list | grep -c "\"summary\": \"t1\"")"
@@ -58,7 +61,8 @@ dbus-run-session -- bash -c '
' _ "$tmp" > "$tmp/out" 2>"$tmp/err"
check "list shows the notification" "1" "$(sed -n 1p "$tmp/out")"
-check "close-all empties the live queue" "0" "$(sed -n 2p "$tmp/out")"
+check "image-path is published" "1" "$(sed -n 2p "$tmp/out")"
+check "list clears" "0" "$(sed -n 3p "$tmp/out")"
check "no errors on stderr" "" "$(cat "$tmp/err")"
printf '\n%d passed, %d failed\n' "$pass" "$fail"