pnmixer
Volume mixer for the system tray
notif.c
Go to the documentation of this file.
1 /* notif.c
2  * PNmixer is written by Nick Lanham, a fork of OBmixer
3  * which was programmed by Lee Ferrett, derived
4  * from the program "AbsVolume" by Paul Sherman
5  * This program is free software; you can redistribute
6  * it and/or modify it under the terms of the GNU General
7  * Public License v3. source code is available at
8  * <http://github.com/nicklan/pnmixer>
9  */
10 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include <math.h>
23 #include <glib.h>
24 
25 #ifdef WITH_LIBNOTIFY
26 #include <libnotify/notify.h>
27 #endif
28 
29 #include "audio.h"
30 #include "prefs.h"
31 #include "support-intl.h"
32 #include "support-log.h"
33 #include "notif.h"
34 
35 #include "main.h"
36 
37 #ifdef WITH_LIBNOTIFY
38 
39 #if NOTIFY_CHECK_VERSION (0, 7, 0)
40 #define NOTIFICATION_NEW(summary, body, icon) \
41  notify_notification_new(summary, body, icon)
42 #define NOTIFICATION_SET_HINT_STRING(notification, key, value) \
43  notify_notification_set_hint(notification, key, g_variant_new_string(value))
44 #define NOTIFICATION_SET_HINT_INT32(notification, key, value) \
45  notify_notification_set_hint(notification, key, g_variant_new_int32(value))
46 #else
47 #define NOTIFICATION_NEW(summary, body, icon) \
48  notify_notification_new(summary, body, icon, NULL)
49 #define NOTIFICATION_SET_HINT_STRING(notification, key, value) \
50  notify_notification_set_hint_string(notification, key, value)
51 #define NOTIFICATION_SET_HINT_INT32(notification, key, value) \
52  notify_notification_set_hint_int32(notification, key, value)
53 #endif
54 
55 /* Helpers */
56 
57 static void
58 show_volume_notif(NotifyNotification *notification,
59  const gchar *card, const gchar *channel,
60  gboolean muted, gdouble volume)
61 {
62  GError *error = NULL;
63  gchar *icon, *summary;
64 
65  if (muted)
66  icon = "audio-volume-muted";
67  else if (volume == 0)
68  icon = "audio-volume-off";
69  else if (volume < 33)
70  icon = "audio-volume-low";
71  else if (volume < 66)
72  icon = "audio-volume-medium";
73  else
74  icon = "audio-volume-high";
75 
76  if (muted)
77  summary = g_strdup(_("Volume muted"));
78  else
79  summary = g_strdup_printf("%s (%s)\n"
80  "%s: %ld%%",
81  card, channel,
82  _("Volume"), lround(volume));
83 
84  notify_notification_update(notification, summary, NULL, icon);
85  NOTIFICATION_SET_HINT_INT32(notification, "value", lround(volume));
86 
87  if (!notify_notification_show(notification, &error)) {
88  ERROR("Could not send notification: %s", error->message);
89  g_error_free(error);
90  }
91 
92  g_free(summary);
93 }
94 
95 static void
96 show_text_notif(NotifyNotification *notification,
97  const gchar *summary, const gchar *body)
98 {
99  GError *error = NULL;
100 
101  notify_notification_update(notification, summary, body, NULL);
102 
103  if (!notify_notification_show(notification, &error)) {
104  ERROR("Could not send notification: %s", error->message);
105  g_error_free(error);
106  }
107 }
108 
109 /* Public functions & signal handlers */
110 
111 struct notif {
112  /* Audio system */
113  Audio *audio;
114  /* Preferences */
115  gboolean enabled;
116  gboolean popup;
117  gboolean tray;
118  gboolean hotkey;
119  gboolean external;
120  /* Notifications */
121  NotifyNotification *volume_notif;
122  NotifyNotification *text_notif;
123 
124 };
125 
126 /* Handle signals coming from the audio subsystem. */
127 static void
128 on_audio_changed(G_GNUC_UNUSED Audio *audio, AudioEvent *event, gpointer data)
129 {
130  Notif *notif = (Notif *) data;
131 
132  switch (event->signal) {
133  case AUDIO_NO_CARD:
134  show_text_notif(notif->text_notif,
135  _("No sound card"),
136  _("No playable soundcard found"));
137  break;
138 
140  show_text_notif(notif->text_notif,
141  _("Soundcard disconnected"),
142  _("Soundcard has been disconnected, reloading sound system..."));
143  break;
144 
146  if (!notif->enabled)
147  return;
148 
149  switch (event->user) {
150  case AUDIO_USER_UNKNOWN:
151  if (!notif->external)
152  return;
153  break;
154  case AUDIO_USER_POPUP:
155  if (!notif->popup)
156  return;
157  break;
159  if (!notif->tray)
160  return;
161  break;
162  case AUDIO_USER_HOTKEYS:
163  if (!notif->hotkey)
164  return;
165  break;
166  default:
167  WARN("Unhandled audio user");
168  return;
169  }
170 
171  show_volume_notif(notif->volume_notif,
172  event->card, event->channel,
173  event->muted, event->volume);
174  break;
175 
176  default:
177  break;
178  }
179 }
180 
187 void
189 {
190  guint timeout;
191  NotifyNotification *notification;
192 
193  /* Get preferences */
194  notif->enabled = prefs_get_boolean("EnableNotifications", FALSE);
195  notif->popup = prefs_get_boolean("PopupNotifications", FALSE);
196  notif->tray = prefs_get_boolean("MouseNotifications", TRUE);
197  notif->hotkey = prefs_get_boolean("HotkeyNotifications", TRUE);
198  notif->external = prefs_get_boolean("ExternalNotifications", FALSE);
199  timeout = prefs_get_integer("NotificationTimeout", 1500);
200 
201  /* Create volume notification */
202  notification = NOTIFICATION_NEW("", NULL, NULL);
203  notify_notification_set_timeout(notification, timeout);
204  NOTIFICATION_SET_HINT_STRING(notification, "x-canonical-private-synchronous", "");
205  if (notif->volume_notif)
206  g_object_unref(notif->volume_notif);
207  notif->volume_notif = notification;
208 
209  /* Create text notification */
210  notification = NOTIFICATION_NEW("", NULL, NULL);
211  notify_notification_set_timeout(notification, timeout * 2);
212  NOTIFICATION_SET_HINT_STRING(notification, "x-canonical-private-synchronous", "");
213  if (notif->text_notif)
214  g_object_unref(notif->text_notif);
215  notif->text_notif = notification;
216 }
217 
224 void
226 {
227  if (notif == NULL)
228  return;
229 
230  /* Unref any existing notification */
231  if (notif->volume_notif)
232  g_object_unref(notif->volume_notif);
233  if (notif->text_notif)
234  g_object_unref(notif->text_notif);
235 
236  /* Disconnect audio signal handlers */
238 
239  /* Uninit libnotify. This should be done only once */
240  g_assert(notify_is_initted() == TRUE);
241  notify_uninit();
242 
243  g_free(notif);
244 }
245 
253 Notif *
255 {
256  Notif *notif;
257 
258  notif = g_new0(Notif, 1);
259 
260  /* Init libnotify. This should be done only once */
261  g_assert(notify_is_initted() == FALSE);
262  if (!notify_init(PACKAGE))
263  run_error_dialog("Unable to initialize libnotify. "
264  "Notifications won't be sent.");
265 
266  /* Connect audio signals handlers */
267  notif->audio = audio;
269 
270  /* Load preferences */
272 
273  return notif;
274 }
275 
276 #else
277 
278 void
279 notif_free(G_GNUC_UNUSED Notif *notif)
280 {
281 }
282 
283 Notif *
284 notif_new(G_GNUC_UNUSED Audio *audio)
285 {
286  return NULL;
287 }
288 
289 void
290 notif_reload(G_GNUC_UNUSED Notif *notif)
291 {
292 }
293 
294 #endif // WITH_LIBNOTIFY
#define _(String)
Definition: support-intl.h:44
Internationalization support.
Logging support.
Header for audio.c.
const gchar * card
Definition: audio.h:76
void notif_reload(G_GNUC_UNUSED Notif *notif)
Definition: notif.c:290
static Audio * audio
Definition: main.c:40
void audio_signals_disconnect(Audio *audio, AudioCallback callback, gpointer data)
Definition: audio.c:318
void audio_signals_connect(Audio *audio, AudioCallback callback, gpointer data)
Definition: audio.c:337
Header for prefs.c.
gboolean muted
Definition: audio.h:79
gboolean prefs_get_boolean(const gchar *key, gboolean def)
Definition: prefs.c:102
Header for main.c.
static void on_audio_changed(Audio *audio, AudioEvent *event, G_GNUC_UNUSED gpointer data)
Definition: main.c:291
Definition: audio.c:198
AudioUser user
Definition: audio.h:75
AudioSignal signal
Definition: audio.h:74
#define ERROR(...)
Definition: support-log.h:36
Notif * notif_new(G_GNUC_UNUSED Audio *audio)
Definition: notif.c:284
Definition: hotkey.h:22
const gchar * channel
Definition: audio.h:77
void run_error_dialog(const char *fmt,...)
Definition: main.c:188
gint prefs_get_integer(const gchar *key, gint def)
Definition: prefs.c:125
static Notif * notif
Definition: main.c:45
Header for notif.c.
struct notif Notif
Definition: notif.h:24
void notif_free(G_GNUC_UNUSED Notif *notif)
Definition: notif.c:279
gdouble volume
Definition: audio.h:80
#define WARN(...)
Definition: support-log.h:37