1// Command trayitems lists the StatusNotifierItems registered on the session
2// bus, then prints their changes as they happen.
3package main
4
5import (
6 "fmt"
7 "log"
8 "strings"
9
10 "github.com/bnema/zerobus"
11)
12
13const (
14 watcher = "org.kde.StatusNotifierWatcher"
15 watcherPath = "/StatusNotifierWatcher"
16 props = "org.freedesktop.DBus.Properties"
17 item = "org.kde.StatusNotifierItem"
18)
19
20func main() {
21 c, err := zerobus.SessionBus()
22 if err != nil {
23 log.Fatal(err)
24 }
25 defer func() { _ = c.Close() }()
26
27 e := c.NewCall(watcher, watcherPath, props, "Get", "ss")
28 e.Str(watcher)
29 e.Str("RegisteredStatusNotifierItems")
30 m, err := c.Call()
31 if err != nil {
32 log.Fatal(err)
33 }
34 // The reply is a variant holding an array of strings. Copy the names:
35 // the next call reuses the buffer they point into.
36 r := m.Body()
37 var items []string
38 if r.Variant() == "as" {
39 end := r.Array('s')
40 for r.More(end) {
41 items = append(items, strings.Clone(r.Str()))
42 }
43 }
44 if r.Err() != nil {
45 log.Fatal(r.Err())
46 }
47
48 for _, it := range items {
49 // An item is "bus-name/object/path", or only a bus name.
50 dest, path, ok := strings.Cut(it, "/")
51 if ok {
52 path = "/" + path
53 } else {
54 path = "/StatusNotifierItem"
55 }
56 fmt.Printf("%s\n id=%q icon=%q status=%q\n", it, get(c, dest, path, "Id"), get(c, dest, path, "IconName"), get(c, dest, path, "Status"))
57 }
58
59 if err := c.AddMatch("type='signal',interface='" + item + "'"); err != nil {
60 log.Fatal(err)
61 }
62 fmt.Println("waiting for changes (Ctrl+C to stop)")
63 for {
64 m, err := c.ReadMessage()
65 if err != nil {
66 log.Fatal(err)
67 }
68 if m.Type == zerobus.TypeSignal {
69 fmt.Printf("%s %s %s\n", m.Sender, m.Path, m.Member)
70 }
71 }
72}
73
74// get reads a string property, or returns "" when it has none.
75func get(c *zerobus.Conn, dest, path, name string) string {
76 e := c.NewCall(dest, path, props, "Get", "ss")
77 e.Str(item)
78 e.Str(name)
79 m, err := c.Call()
80 if err != nil {
81 return ""
82 }
83 r := m.Body()
84 if r.Variant() != "s" {
85 return ""
86 }
87 return strings.Clone(r.Str())
88}