1// Package notify provides an implementation of the Gnome DBus notifications 2// specification. 3package notify 4 5import "github.com/godbus/dbus" 6 7// Notification object paths and interfaces. 8const ( 9 DbusObjectPath = "/org/freedesktop/Notifications" 10 DbusInterfacePath = "org.freedesktop.Notifications" 11 SignalNotificationClosed = "org.freedesktop.Notifications.NotificationClosed" 12 SignalActionInvoked = "org.freedesktop.Notifications.ActionInvoked" 13 CallGetCapabilities = "org.freedesktop.Notifications.GetCapabilities" 14 CallCloseNotification = "org.freedesktop.Notifications.CloseNotification" 15 CallNotify = "org.freedesktop.Notifications.Notify" 16 CallGetServerInformation = "org.freedesktop.Notifications.GetServerInformation" 17 DbusMemberActionInvoked = "ActionInvoked" 18 DbusMemberNotificationClosed = "NotificationClosed" 19) 20 21// Notification expire timeout. 22const ( 23 ExpiresDefault = -1 24 ExpiresNever = 0 25) 26 27// Notification Categories 28const ( 29 ClassDevice = "device" 30 ClassDeviceAdded = "device.added" 31 ClassDeviceError = "device.error" 32 ClassDeviceRemoved = "device.removed" 33 ClassEmail = "email" 34 ClassEmailArrived = "email.arrived" 35 ClassEmailBounced = "email.bounced" 36 ClassIm = "im" 37 ClassImError = "im.error" 38 ClassImReceived = "im.received" 39 ClassNetwork = "network" 40 ClassNetworkConnected = "network.connected" 41 ClassNetworkDisconnected = "network.disconnected" 42 ClassNetworkError = "network.error" 43 ClassPresence = "presence" 44 ClassPresenceOffline = "presence.offline" 45 ClassPresenceOnline = "presence.online" 46 ClassTransfer = "transfer" 47 ClassTransferComplete = "transfer.complete" 48 ClassTransferError = "transfer.error" 49) 50 51// Urgency Levels 52const ( 53 UrgencyLow = byte(0) 54 UrgencyNormal = byte(1) 55 UrgencyCritical = byte(2) 56) 57 58// Hints 59const ( 60 HintActionIcons = "action-icons" 61 HintCategory = "category" 62 HintDesktopEntry = "desktop-entry" 63 HintImageData = "image-data" 64 HintImagePath = "image-path" 65 HintResident = "resident" 66 HintSoundFile = "sound-file" 67 HintSoundName = "sound-name" 68 HintSuppressSound = "suppress-sound" 69 HintTransient = "transient" 70 HintX = "x" 71 HintY = "y" 72 HintUrgency = "urgency" 73) 74 75// Capabilities is a struct containing the capabilities of the notification 76// server. 77type Capabilities struct { 78 // Supports using icons instead of text for displaying actions. 79 ActionIcons bool 80 81 // The server will provide any specified actions to the user. 82 Actions bool 83 84 // Supports body text. Some implementations may only show the summary. 85 Body bool 86 87 // The server supports hyperlinks in the notifications. 88 BodyHyperlinks bool 89 90 // The server supports images in the notifications. 91 BodyImages bool 92 93 // Supports markup in the body text. 94 BodyMarkup bool 95 96 // The server will render an animation of all the frames in a given 97 // image array. 98 IconMulti bool 99 100 // Supports display of exactly 1 frame of any given image array. 101 IconStatic bool 102 103 // The server supports persistence of notifications. Notifications will 104 // be retained until they are acknowledged or removed by the user or 105 // recalled by the sender. 106 Persistence bool 107 108 // The server supports sounds on notifications. 109 Sound bool 110} 111 112// GetCapabilities returns the capabilities of the notification server. 113func GetCapabilities() (c Capabilities, err error) { 114 conn, err := dbus.SessionBus() 115 if err != nil { 116 return 117 } 118 119 obj := conn.Object(DbusInterfacePath, DbusObjectPath) 120 call := obj.Call(CallGetCapabilities, 0) 121 if err = call.Err; err != nil { 122 return 123 } 124 125 s := []string{} 126 if err = call.Store(&s); err != nil { 127 return 128 } 129 130 for _, v := range s { 131 switch v { 132 case "action-icons": 133 c.ActionIcons = true 134 break 135 case "actions": 136 c.Actions = true 137 break 138 case "body": 139 c.Body = true 140 break 141 case "body-hyperlinks": 142 c.BodyHyperlinks = true 143 break 144 case "body-images": 145 c.BodyImages = true 146 break 147 case "body-markup": 148 c.BodyMarkup = true 149 break 150 case "icon-multi": 151 c.IconMulti = true 152 break 153 case "icon-static": 154 c.IconStatic = true 155 break 156 case "persistence": 157 c.Persistence = true 158 break 159 case "sound": 160 c.Sound = true 161 break 162 } 163 } 164 return 165} 166 167// ServerInformation is a struct containing information about the server such 168// as its name and version. 169type ServerInformation struct { 170 // The name of the notification server daemon 171 Name string 172 173 // The vendor of the notification server 174 Vendor string 175 176 // Version of the notification server 177 Version string 178 179 // Spec version the notification server conforms to 180 SpecVersion string 181} 182 183// GetServerInformation returns information about the notification server such 184// as its name and version. 185func GetServerInformation() (i ServerInformation, err error) { 186 conn, err := dbus.SessionBus() 187 if err != nil { 188 return 189 } 190 191 obj := conn.Object(DbusInterfacePath, DbusObjectPath) 192 call := obj.Call(CallGetServerInformation, 0) 193 if err = call.Err; err != nil { 194 return 195 } 196 197 err = call.Store(&i.Name, &i.Vendor, &i.Version, &i.SpecVersion) 198 return 199} 200 201// Notification is a struct which describes the notification to be displayed 202// by the notification server. 203type Notification struct { 204 // The optional name of the application sending the notification. 205 // Can be blank. 206 AppName string 207 208 // The optional notification ID that this notification replaces. 209 ReplacesID uint32 210 211 // The optional program icon of the calling application. 212 AppIcon string 213 214 // The summary text briefly describing the notification. 215 Summary string 216 217 // The optional detailed body text. 218 Body string 219 220 // The actions send a request message back to the notification client 221 // when invoked. 222 Actions []string 223 224 // Hints are a way to provide extra data to a notification server. 225 Hints map[string]interface{} 226 227 // The timeout time in milliseconds since the display of the 228 // notification at which the notification should automatically close. 229 Timeout int32 230} 231 232// NewNotification creates a new notification object with some basic 233// information. 234func NewNotification(summary, body string) Notification { 235 return Notification{ 236 Summary: summary, 237 Body: body, 238 Timeout: ExpiresDefault, 239 } 240} 241 242// Show sends the information in the notification object to the server to be 243// displayed. 244func (n Notification) Show() (id uint32, err error) { 245 conn, err := dbus.SessionBus() 246 if err != nil { 247 return 248 } 249 250 // We need to convert the interface type of the map to dbus.Variant as 251 // people dont want to have to import the dbus package just to make use 252 // of the notification hints. 253 hints := map[string]dbus.Variant{} 254 for k, v := range n.Hints { 255 hints[k] = dbus.MakeVariant(v) 256 } 257 258 obj := conn.Object(DbusInterfacePath, DbusObjectPath) 259 call := obj.Call( 260 CallNotify, 261 0, 262 n.AppName, 263 n.ReplacesID, 264 n.AppIcon, 265 n.Summary, 266 n.Body, 267 n.Actions, 268 hints, 269 n.Timeout) 270 if err = call.Err; err != nil { 271 return 272 } 273 274 err = call.Store(&id) 275 return 276} 277 278// CloseNotification closes the notification if it exists using its id. 279func CloseNotification(id uint32) (err error) { 280 conn, err := dbus.SessionBus() 281 if err != nil { 282 return 283 } 284 285 obj := conn.Object(DbusInterfacePath, DbusObjectPath) 286 call := obj.Call(CallCloseNotification, 0, id) 287 err = call.Err 288 return 289} 290