1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2004-2006 Christian Hammond <chipx86@chipx86.com>
4 * Copyright (C) 2004-2006 Mike Hearn <mike@navi.cx>
5 * Copyright (C) 2010 Red Hat, Inc.
6 * Copyright © 2010 Christian Persch
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30
31 #include <glib.h>
32 #include <gio/gio.h>
33
34 #include "notify.h"
35 #include "internal.h"
36 #include "notify-marshal.h"
37
38 /**
39 * SECTION:notify
40 * @Short_description: Notification API
41 * @Title: notify
42 */
43
44 static gboolean _initted = FALSE;
45 static char *_app_name = NULL;
46 static GDBusProxy *_proxy = NULL;
47 static GList *_active_notifications = NULL;
48 static int _spec_version_major = 0;
49 static int _spec_version_minor = 0;
50
51 gboolean
_notify_check_spec_version(int major,int minor)52 _notify_check_spec_version (int major,
53 int minor)
54 {
55 if (_spec_version_major > major)
56 return TRUE;
57 if (_spec_version_major < major)
58 return FALSE;
59 return _spec_version_minor >= minor;
60 }
61
62 static gboolean
_notify_get_server_info(char ** ret_name,char ** ret_vendor,char ** ret_version,char ** ret_spec_version,GError ** error)63 _notify_get_server_info (char **ret_name,
64 char **ret_vendor,
65 char **ret_version,
66 char **ret_spec_version,
67 GError **error)
68 {
69 GDBusProxy *proxy;
70 GVariant *result;
71
72 proxy = _notify_get_proxy (error);
73 if (proxy == NULL) {
74 return FALSE;
75 }
76
77 result = g_dbus_proxy_call_sync (proxy,
78 "GetServerInformation",
79 g_variant_new ("()"),
80 G_DBUS_CALL_FLAGS_NONE,
81 -1 /* FIXME shorter timeout? */,
82 NULL,
83 error);
84 if (result == NULL) {
85 return FALSE;
86 }
87 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(ssss)"))) {
88 g_variant_unref (result);
89 g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
90 "Unexpected reply type");
91 return FALSE;
92 }
93
94 g_variant_get (result, "(ssss)",
95 ret_name,
96 ret_vendor,
97 ret_version,
98 ret_spec_version);
99 g_variant_unref (result);
100 return TRUE;
101 }
102
103 static gboolean
_notify_update_spec_version(GError ** error)104 _notify_update_spec_version (GError **error)
105 {
106 char *spec_version;
107
108 if (!_notify_get_server_info (NULL, NULL, NULL, &spec_version, error)) {
109 return FALSE;
110 }
111
112 sscanf (spec_version,
113 "%d.%d",
114 &_spec_version_major,
115 &_spec_version_minor);
116
117 g_free (spec_version);
118
119 return TRUE;
120 }
121
122
123 /**
124 * notify_set_app_name:
125 * @app_name: The name of the application
126 *
127 * Sets the application name.
128 *
129 */
130 void
notify_set_app_name(const char * app_name)131 notify_set_app_name (const char *app_name)
132 {
133 g_free (_app_name);
134 _app_name = g_strdup (app_name);
135 }
136
137 /**
138 * notify_init:
139 * @app_name: The name of the application initializing libnotify.
140 *
141 * Initialized libnotify. This must be called before any other functions.
142 *
143 * Returns: %TRUE if successful, or %FALSE on error.
144 */
145 gboolean
notify_init(const char * app_name)146 notify_init (const char *app_name)
147 {
148 g_return_val_if_fail (app_name != NULL, FALSE);
149 g_return_val_if_fail (*app_name != '\0', FALSE);
150
151 if (_initted)
152 return TRUE;
153
154 notify_set_app_name (app_name);
155
156 #if !GLIB_CHECK_VERSION (2, 36, 0)
157 g_type_init ();
158 #endif
159
160 _initted = TRUE;
161
162 return TRUE;
163 }
164
165 /**
166 * notify_get_app_name:
167 *
168 * Gets the application name registered.
169 *
170 * Returns: The registered application name, passed to notify_init().
171 */
172 const char *
notify_get_app_name(void)173 notify_get_app_name (void)
174 {
175 return _app_name;
176 }
177
178 /**
179 * notify_uninit:
180 *
181 * Uninitialized libnotify.
182 *
183 * This should be called when the program no longer needs libnotify for
184 * the rest of its lifecycle, typically just before exitting.
185 */
186 void
notify_uninit(void)187 notify_uninit (void)
188 {
189 GList *l;
190
191 if (!_initted) {
192 return;
193 }
194
195 if (_app_name != NULL) {
196 g_free (_app_name);
197 _app_name = NULL;
198 }
199
200 for (l = _active_notifications; l != NULL; l = l->next) {
201 NotifyNotification *n = NOTIFY_NOTIFICATION (l->data);
202
203 if (_notify_notification_get_timeout (n) == 0 ||
204 _notify_notification_has_nondefault_actions (n)) {
205 notify_notification_close (n, NULL);
206 }
207 }
208
209 if (_proxy != NULL) {
210 g_object_unref (_proxy);
211 _proxy = NULL;
212 }
213
214 _initted = FALSE;
215 }
216
217 /**
218 * notify_is_initted:
219 *
220 * Gets whether or not libnotify is initialized.
221 *
222 * Returns: %TRUE if libnotify is initialized, or %FALSE otherwise.
223 */
224 gboolean
notify_is_initted(void)225 notify_is_initted (void)
226 {
227 return _initted;
228 }
229
230 /*
231 * _notify_get_proxy:
232 * @error: (allow-none): a location to store a #GError, or %NULL
233 *
234 * Synchronously creates the #GDBusProxy for the notification service,
235 * and caches the result.
236 *
237 * Returns: the #GDBusProxy for the notification service, or %NULL on error
238 */
239 GDBusProxy *
_notify_get_proxy(GError ** error)240 _notify_get_proxy (GError **error)
241 {
242 if (_proxy != NULL)
243 return _proxy;
244
245 _proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
246 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
247 NULL,
248 NOTIFY_DBUS_NAME,
249 NOTIFY_DBUS_CORE_OBJECT,
250 NOTIFY_DBUS_CORE_INTERFACE,
251 NULL,
252 error);
253 if (_proxy == NULL) {
254 return NULL;
255 }
256
257 if (!_notify_update_spec_version (error)) {
258 g_object_unref (_proxy);
259 _proxy = NULL;
260 return NULL;
261 }
262
263 g_object_add_weak_pointer (G_OBJECT (_proxy), (gpointer *) &_proxy);
264
265 return _proxy;
266 }
267
268 /**
269 * notify_get_server_caps:
270 *
271 * Synchronously queries the server for its capabilities and returns them in a #GList.
272 *
273 * Returns: (transfer full) (element-type utf8): a #GList of server capability strings. Free
274 * the list elements with g_free() and the list itself with g_list_free().
275 */
276 GList *
notify_get_server_caps(void)277 notify_get_server_caps (void)
278 {
279 GDBusProxy *proxy;
280 GVariant *result;
281 char **cap, **caps;
282 GList *list = NULL;
283
284 proxy = _notify_get_proxy (NULL);
285 if (proxy == NULL) {
286 g_warning ("Failed to connect to proxy");
287 return NULL;
288 }
289
290 result = g_dbus_proxy_call_sync (proxy,
291 "GetCapabilities",
292 g_variant_new ("()"),
293 G_DBUS_CALL_FLAGS_NONE,
294 -1 /* FIXME shorter timeout? */,
295 NULL,
296 NULL);
297 if (result == NULL) {
298 return NULL;
299 }
300 if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)"))) {
301 g_variant_unref (result);
302 return NULL;
303 }
304
305 g_variant_get (result, "(^as)", &caps);
306
307 for (cap = caps; *cap != NULL; cap++) {
308 list = g_list_prepend (list, *cap);
309 }
310
311 g_free (caps);
312 g_variant_unref (result);
313
314 return g_list_reverse (list);
315 }
316
317 /**
318 * notify_get_server_info:
319 * @ret_name: (out) (allow-none) (transfer full): a location to store the server name, or %NULL
320 * @ret_vendor: (out) (allow-none) (transfer full): a location to store the server vendor, or %NULL
321 * @ret_version: (out) (allow-none) (transfer full): a location to store the server version, or %NULL
322 * @ret_spec_version: (out) (allow-none) (transfer full): a location to store the version the service is compliant with, or %NULL
323 *
324 * Synchronously queries the server for its information, specifically, the name, vendor,
325 * server version, and the version of the notifications specification that it
326 * is compliant with.
327 *
328 * Returns: %TRUE if successful, and the variables passed will be set, %FALSE
329 * on error. The returned strings must be freed with g_free
330 */
331 gboolean
notify_get_server_info(char ** ret_name,char ** ret_vendor,char ** ret_version,char ** ret_spec_version)332 notify_get_server_info (char **ret_name,
333 char **ret_vendor,
334 char **ret_version,
335 char **ret_spec_version)
336 {
337 return _notify_get_server_info (ret_name, ret_vendor, ret_version, ret_spec_version, NULL);
338 }
339
340 void
_notify_cache_add_notification(NotifyNotification * n)341 _notify_cache_add_notification (NotifyNotification *n)
342 {
343 _active_notifications = g_list_prepend (_active_notifications, n);
344 }
345
346 void
_notify_cache_remove_notification(NotifyNotification * n)347 _notify_cache_remove_notification (NotifyNotification *n)
348 {
349 _active_notifications = g_list_remove (_active_notifications, n);
350 }
351