-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotification.go
146 lines (127 loc) · 3.85 KB
/
notification.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package main
// #cgo pkg-config: libnotify
// #include <stdlib.h>
// #include <libnotify/notify.h>
import "C"
import (
"crypto/md5"
"fmt"
"io"
"log"
"os"
"strings"
"unsafe"
)
// Notification represents a notification.
type Notification struct {
App *Application
Name string
Display string
Enabled bool
Icon string
Id string
Title string
Text string
Sticky bool
Priority int
Coalescing string
}
// NotifyUrgency represents the urgency of a notification for libnotify.
type NotifyUrgency int
// The recognized urgency levels of notifications.
const (
NOTIFY_URGENCY_LOW NotifyUrgency = iota
NOTIFY_URGENCY_NORMAL
NOTIFY_URGENCY_CRITICAL
)
// NotifyTimeout represents the timeout of a notification for libnotify.
type NotifyTimeout int
// The recognized timeouts of notifications.
const (
NOTIFY_EXPIRES_DEFAULT NotifyTimeout = iota - 1
NOTIFY_EXPIRES_NEVER
)
// processNotification sends the notification to libnotify.
func processNotification(note *Notification, cache *FileCache) {
if inited := bool(C.notify_is_initted() != 0); !inited {
// We might be able to initialize libnotify here, if doing so is thread
// safe and can be called multiple times.
log.Println("gntp: libnotify is not initted")
return
}
notify_title := C.CString(note.Title)
defer C.free(unsafe.Pointer(notify_title))
notify_text := C.CString(note.Text)
defer C.free(unsafe.Pointer(notify_text))
notify_icon := C.CString("")
icon := note.Icon
var iconFileName string
if strings.HasPrefix(strings.ToLower(icon), "x-growl-resource://") {
icon = icon[19:]
iconFileName = cache.GetFileName(icon)
} else if icon != "" {
hash := md5.New()
io.WriteString(hash, icon)
sum := fmt.Sprintf("%x", hash.Sum(nil))
iconFileName = cache.GetFileName(sum)
}
if _, err := os.Stat(iconFileName); err == nil {
notify_icon = C.CString(iconFileName)
}
defer C.free(unsafe.Pointer(notify_icon))
notify_notification := C.notify_notification_new(notify_title, notify_text, notify_icon)
// TODO: Find the correct way to free notify_notification.
//defer C.free(unsafe.Pointer(¬ify_notification))
notify_app_name := C.CString(note.App.Name)
C.notify_notification_set_app_name(notify_notification, notify_app_name)
defer C.free(unsafe.Pointer(notify_app_name))
var urgency NotifyUrgency
switch note.Priority {
case -2, -1:
urgency = NOTIFY_URGENCY_LOW
case 0:
urgency = NOTIFY_URGENCY_NORMAL
case 1, 2:
urgency = NOTIFY_URGENCY_CRITICAL
default:
log.Printf("gntp: unknown priority %v for notification %v from app %v\n", note.Priority, note.Name, note.App.Name)
urgency = NOTIFY_URGENCY_NORMAL
}
notify_urgency := C.NotifyUrgency(urgency)
C.notify_notification_set_urgency(notify_notification, notify_urgency)
timeout := NOTIFY_EXPIRES_DEFAULT
if note.Sticky {
timeout = NOTIFY_EXPIRES_NEVER
}
notify_timeout := C.gint(timeout)
C.notify_notification_set_timeout(notify_notification, notify_timeout)
// Actually show the notification and report any error.
var err *C.GError
if shown := bool(C.notify_notification_show(notify_notification, &err) != 0); shown {
log.Printf("Notification %s shown\n", note.Id)
} else {
log.Printf("Notification %s not shown\n", note.Id)
if err != nil {
message := C.GoString((*C.char)(err.message))
log.Printf(" %s\n", message)
}
}
}
// NotificationChannel builds and returns a channel for Notifications.
func NotificationChannel(cache *FileCache) chan *Notification {
c := make(chan *Notification)
go func() {
// libnotify needs a default app name when initialized. This will be
// changed later.
appName := C.CString("gntp_notify")
defer C.free(unsafe.Pointer(appName))
if inited := bool(C.notify_init(appName) != 0); !inited {
log.Fatalf("gntp: Could not initialize libnotify")
}
defer C.notify_uninit()
for {
processNotification(<-c, cache)
}
}()
return c
}