diff --git a/configure.ac b/configure.ac index 690e1f3..1c9d8d2 100644 --- a/configure.ac +++ b/configure.ac @@ -88,17 +88,16 @@ AC_EXEEXT AM_PROG_LIBTOOL -REQ_DBUS_VERSION=0.76 REQ_GTK_VERSION=2.90 -REQ_GLIB_VERSION=2.6 +REQ_GLIB_VERSION=2.26.0 -pkg_modules="gdk-pixbuf-2.0 glib-2.0 >= $REQ_GLIB_VERSION, dbus-1 >= $REQ_DBUS_VERSION, dbus-glib-1 >= $REQ_DBUS_VERSION" +pkg_modules="gdk-pixbuf-2.0 glib-2.0 >= $REQ_GLIB_VERSION gio-2.0 >= $REQ_GLIB_VERSION" PKG_CHECK_MODULES(PACKAGE, [$pkg_modules]) AC_SUBST(PACKAGE_LIBS) AC_SUBST(PACKAGE_CFLAGS) AC_SUBST(pkg_modules) -tests_modules="gtk+-3.0 >= $REQ_GTK_VERSION dbus-glib-1 >= $REQ_DBUS_VERSION" +tests_modules="gtk+-3.0 >= $REQ_GTK_VERSION" PKG_CHECK_MODULES(TESTS, [$tests_modules]) AC_SUBST(TESTS_LIBS) AC_SUBST(TESTS_CFLAGS) @@ -110,18 +109,6 @@ dnl dnl Check the D-BUS version. dnl -AC_MSG_CHECKING([dbus version]) -DBUS_VERSION=`$PKG_CONFIG --modversion dbus-1` -DBUS_MAJOR_VER=`echo $DBUS_VERSION | cut -d. -f 1` -DBUS_MINOR_VER=`echo $DBUS_VERSION | cut -d. -f 2` -DBUS_MICRO_VER=`echo $DBUS_VERSION | cut -d. -f 3` - -AC_MSG_RESULT($DBUS_VERSION) -AC_DEFINE_UNQUOTED(DBUS_MAJOR_VER, $DBUS_MAJOR_VER, [D-BUS major version.]) -AC_DEFINE_UNQUOTED(DBUS_MINOR_VER, $DBUS_MINOR_VER, [D-BUS minor version.]) -AC_DEFINE_UNQUOTED(DBUS_MICRO_VER, $DBUS_MICRO_VER, [D-BUS micro version.]) - - dnl ################################################################ dnl # Set up gtk-doc dnl ################################################################ diff --git a/docs/reference/libnotify-sections.txt b/docs/reference/libnotify-sections.txt index 485d96f..ca2534f 100644 --- a/docs/reference/libnotify-sections.txt +++ b/docs/reference/libnotify-sections.txt @@ -18,6 +18,7 @@ notify_notification_set_timeout notify_notification_set_category notify_notification_set_urgency notify_notification_set_icon_from_pixbuf +notify_notification_set_hint notify_notification_set_hint_int32 notify_notification_set_hint_double notify_notification_set_hint_string diff --git a/docs/reference/tmpl/notification.sgml b/docs/reference/tmpl/notification.sgml index e5937f3..c2093fd 100644 --- a/docs/reference/tmpl/notification.sgml +++ b/docs/reference/tmpl/notification.sgml @@ -183,6 +183,16 @@ is much like G_CALLBACK(). @icon: + + + + + +@notification: +@key: +@value: + + diff --git a/libnotify/internal.h b/libnotify/internal.h index 9b46406..741d002 100644 --- a/libnotify/internal.h +++ b/libnotify/internal.h @@ -22,19 +22,13 @@ #ifndef _LIBNOTIFY_INTERNAL_H_ #define _LIBNOTIFY_INTERNAL_H_ -#include "config.h" - -#include -#include - #define NOTIFY_DBUS_NAME "org.freedesktop.Notifications" #define NOTIFY_DBUS_CORE_INTERFACE "org.freedesktop.Notifications" #define NOTIFY_DBUS_CORE_OBJECT "/org/freedesktop/Notifications" G_BEGIN_DECLS -DBusGConnection * _notify_get_dbus_g_conn (void); -DBusGProxy * _notify_get_g_proxy (void); +GDBusProxy * _notify_get_proxy (GError **error); void _notify_cache_add_notification (NotifyNotification *n); void _notify_cache_remove_notification (NotifyNotification *n); diff --git a/libnotify/notification.c b/libnotify/notification.c index 2a42236..c947882 100644 --- a/libnotify/notification.c +++ b/libnotify/notification.c @@ -3,6 +3,7 @@ * Copyright (C) 2006 Christian Hammond * Copyright (C) 2006 John Palmieri * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2010 Christian Persch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,8 +23,7 @@ #include "config.h" -#include -#include +#include #include "notify.h" #include "internal.h" @@ -38,15 +38,6 @@ static void notify_notification_class_init (NotifyNotificationClass *klass); static void notify_notification_init (NotifyNotification *sp); static void notify_notification_finalize (GObject *object); -static void _close_signal_handler (DBusGProxy *proxy, - guint32 id, - guint32 reason, - NotifyNotification *notification); - -static void _action_signal_handler (DBusGProxy *proxy, - guint32 id, - char *action, - NotifyNotification *notification); typedef struct { @@ -78,7 +69,8 @@ struct _NotifyNotificationPrivate gboolean has_nondefault_actions; gboolean updates_pending; - gboolean signals_registered; + + gulong proxy_signal_handler; gint closed_reason; }; @@ -298,13 +290,6 @@ notify_notification_get_property (GObject *object, } } -static void -_g_value_free (GValue *value) -{ - g_value_unset (value); - g_free (value); -} - static void destroy_pair (CallbackPair *pair) { @@ -324,29 +309,12 @@ notify_notification_init (NotifyNotification *obj) obj->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GFreeFunc) _g_value_free); + (GDestroyNotify) g_variant_unref); obj->priv->action_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GFreeFunc) destroy_pair); -} - -static void -on_proxy_destroy (DBusGProxy *proxy, - NotifyNotification *notification) -{ - if (notification->priv->signals_registered) { - dbus_g_proxy_disconnect_signal (proxy, - "NotificationClosed", - G_CALLBACK (_close_signal_handler), - notification); - dbus_g_proxy_disconnect_signal (proxy, - "ActionInvoked", - G_CALLBACK (_action_signal_handler), - notification); - notification->priv->signals_registered = FALSE; - } + (GDestroyNotify) destroy_pair); } static void @@ -354,7 +322,7 @@ notify_notification_finalize (GObject *object) { NotifyNotification *obj = NOTIFY_NOTIFICATION (object); NotifyNotificationPrivate *priv = obj->priv; - DBusGProxy *proxy; + GDBusProxy *proxy; _notify_cache_remove_notification (obj); @@ -373,20 +341,9 @@ notify_notification_finalize (GObject *object) if (priv->hints != NULL) g_hash_table_destroy (priv->hints); - proxy = _notify_get_g_proxy (); - if (proxy != NULL && priv->signals_registered) { - g_signal_handlers_disconnect_by_func (proxy, - G_CALLBACK (on_proxy_destroy), - object); - - dbus_g_proxy_disconnect_signal (proxy, - "NotificationClosed", - G_CALLBACK (_close_signal_handler), - object); - dbus_g_proxy_disconnect_signal (proxy, - "ActionInvoked", - G_CALLBACK (_action_signal_handler), - object); + proxy = _notify_get_proxy (NULL); + if (proxy != NULL && priv->proxy_signal_handler != 0) { + g_signal_handler_disconnect (proxy, priv->proxy_signal_handler); } g_free (obj->priv); @@ -466,64 +423,51 @@ notify_notification_update (NotifyNotification *notification, } static void -_close_signal_handler (DBusGProxy *proxy, - guint32 id, - guint32 reason, - NotifyNotification *notification) +proxy_g_signal_cb (GDBusProxy *proxy, + const char *sender_name, + const char *signal_name, + GVariant *parameters, + NotifyNotification *notification) { - if (id == notification->priv->id) { + g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); + + if (g_strcmp0 (signal_name, "NotificationClosed") == 0 && + g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)"))) { + guint32 id, reason; + + g_variant_get (parameters, "(uu)", &id, &reason); + if (id != notification->priv->id) + return; + g_object_ref (G_OBJECT (notification)); notification->priv->closed_reason = reason; g_signal_emit (notification, signals[SIGNAL_CLOSED], 0); notification->priv->id = 0; g_object_unref (G_OBJECT (notification)); - } -} + } else if (g_strcmp0 (signal_name, "ActionInvoked") == 0 && + g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(us)"))) { + guint32 id; + const char *action; + CallbackPair *pair; -static void -_action_signal_handler (DBusGProxy *proxy, - guint32 id, - char *action, - NotifyNotification *notification) -{ - CallbackPair *pair; + g_variant_get (parameters, "(u&s)", &id, &action); - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); + if (id != notification->priv->id) + return; - if (id != notification->priv->id) - return; + pair = (CallbackPair *) g_hash_table_lookup (notification->priv->action_map, + action); - pair = (CallbackPair *) g_hash_table_lookup (notification->priv->action_map, - action); - - if (pair == NULL) { - if (g_ascii_strcasecmp (action, "default")) { - g_warning ("Received unknown action %s", action); + if (pair == NULL) { + if (g_ascii_strcasecmp (action, "default")) { + g_warning ("Received unknown action %s", action); + } + } else { + pair->cb (notification, (char *) action, pair->user_data); } - } else { - pair->cb (notification, action, pair->user_data); } } -static char ** -_gslist_to_string_array (GSList *list) -{ - GSList *l; - GArray *a; - - a = g_array_sized_new (TRUE, - FALSE, - sizeof (char *), - g_slist_length (list)); - - for (l = list; l != NULL; l = l->next) { - g_array_append_val (a, l->data); - } - - return (char **) g_array_free (a, FALSE); -} - /** * notify_notification_show: * @notification: The notification. @@ -539,70 +483,69 @@ notify_notification_show (NotifyNotification *notification, GError **error) { NotifyNotificationPrivate *priv; - GError *tmp_error = NULL; - char **action_array; - DBusGProxy *proxy; + GDBusProxy *proxy; + GVariantBuilder actions_builder, hints_builder; + GSList *l; + GHashTableIter iter; + gpointer key, data; + GVariant *result; g_return_val_if_fail (notification != NULL, FALSE); g_return_val_if_fail (NOTIFY_IS_NOTIFICATION (notification), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); priv = notification->priv; - proxy = _notify_get_g_proxy (); + proxy = _notify_get_proxy (error); if (proxy == NULL) { - g_set_error (error, 0, 0, "Unable to connect to server"); return FALSE; } - if (!priv->signals_registered) { - g_signal_connect (proxy, - "destroy", - G_CALLBACK (on_proxy_destroy), - notification); - - dbus_g_proxy_connect_signal (proxy, - "NotificationClosed", - G_CALLBACK (_close_signal_handler), - notification, - NULL); - - dbus_g_proxy_connect_signal (proxy, - "ActionInvoked", - G_CALLBACK (_action_signal_handler), - notification, - NULL); - - priv->signals_registered = TRUE; + if (priv->proxy_signal_handler == 0) { + priv->proxy_signal_handler = g_signal_connect (proxy, + "g-signal", + G_CALLBACK (proxy_g_signal_cb), + notification); } - action_array = _gslist_to_string_array (priv->actions); + g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("as")); + for (l = priv->actions; l != NULL; l = l->next) { + g_variant_builder_add (&actions_builder, "s", l->data); + } + + g_variant_builder_init (&hints_builder, G_VARIANT_TYPE ("a{sv}")); + g_hash_table_iter_init (&iter, priv->hints); + while (g_hash_table_iter_next (&iter, &key, &data)) { + g_variant_builder_add (&hints_builder, "{sv}", key, data); + } /* TODO: make this nonblocking */ - dbus_g_proxy_call (proxy, - "Notify", - &tmp_error, - G_TYPE_STRING, notify_get_app_name (), - G_TYPE_UINT, priv->id, - G_TYPE_STRING, priv->icon_name, - G_TYPE_STRING, priv->summary, - G_TYPE_STRING, priv->body, - G_TYPE_STRV, action_array, - dbus_g_type_get_map ("GHashTable", - G_TYPE_STRING, - G_TYPE_VALUE), - priv->hints, - G_TYPE_INT, priv->timeout, - G_TYPE_INVALID, - G_TYPE_UINT, &priv->id, - G_TYPE_INVALID); - - /* Don't free the elements because they are owned by priv->actions */ - g_free (action_array); - - if (tmp_error != NULL) { - g_propagate_error (error, tmp_error); + result = g_dbus_proxy_call_sync (proxy, + "Notify", + g_variant_new ("(susssasa{sv}i)", + notify_get_app_name (), + priv->id, + priv->icon_name ? priv->icon_name : "", + priv->summary ? priv->summary : "", + priv->body ? priv->body : "", + &actions_builder, + &hints_builder, + priv->timeout), + G_DBUS_CALL_FLAGS_NONE, + -1 /* FIXME ? */, + NULL, + error); + if (result == NULL) { return FALSE; } + if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(u)"))) { + g_variant_unref (result); + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Unexpected reply type"); + return FALSE; + } + + g_variant_get (result, "(u)", &priv->id); + g_variant_unref (result); return TRUE; } @@ -676,47 +619,6 @@ notify_notification_set_urgency (NotifyNotification *notification, (guchar) urgency); } -static void -_gvalue_array_append_int (GValueArray *array, - gint i) -{ - GValue value = { 0 }; - - g_value_init (&value, G_TYPE_INT); - g_value_set_int (&value, i); - g_value_array_append (array, &value); - g_value_unset (&value); -} - -static void -_gvalue_array_append_bool (GValueArray *array, gboolean b) -{ - GValue value = { 0 }; - - g_value_init (&value, G_TYPE_BOOLEAN); - g_value_set_boolean (&value, b); - g_value_array_append (array, &value); - g_value_unset (&value); -} - -static void -_gvalue_array_append_byte_array (GValueArray *array, - guchar *bytes, - gsize len) -{ - GArray *byte_array; - GValue value = { 0 }; - - byte_array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), len); - g_assert (byte_array != NULL); - byte_array = g_array_append_vals (byte_array, bytes, len); - - g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); - g_value_take_boxed (&value, byte_array); - g_value_array_append (array, &value); - g_value_unset (&value); -} - /** * notify_notification_set_icon_from_pixbuf: * @notification: The notification. @@ -757,12 +659,21 @@ notify_notification_set_image_from_pixbuf (NotifyNotification *notification, guchar *image; gboolean has_alpha; gsize image_len; - GValueArray *image_struct; - GValue *value; + GVariant *value; const char *hint_name; - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); + g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); + + if (_notify_check_spec_version(1, 1)) { + hint_name = "image_data"; + } else { + hint_name = "icon_data"; + } + + if (pixbuf == NULL) { + notify_notification_set_hint (notification, hint_name, NULL); + return; + } g_object_get (pixbuf, "width", &width, @@ -776,29 +687,50 @@ notify_notification_set_image_from_pixbuf (NotifyNotification *notification, image_len = (height - 1) * rowstride + width * ((n_channels * bits_per_sample + 7) / 8); - image_struct = g_value_array_new (1); + value = g_variant_new ("(iiibii@ay)", + width, + height, + rowstride, + has_alpha, + bits_per_sample, + n_channels, + g_variant_new_from_data (G_VARIANT_TYPE ("ay"), + image, + image_len, + TRUE, + (GDestroyNotify) g_object_unref, + pixbuf)); + notify_notification_set_hint (notification, hint_name, value); +} - _gvalue_array_append_int (image_struct, width); - _gvalue_array_append_int (image_struct, height); - _gvalue_array_append_int (image_struct, rowstride); - _gvalue_array_append_bool (image_struct, has_alpha); - _gvalue_array_append_int (image_struct, bits_per_sample); - _gvalue_array_append_int (image_struct, n_channels); - _gvalue_array_append_byte_array (image_struct, image, image_len); +/** + * notify_notification_set_hint: + * @notification: a #NotifyNotification + * @key: the hint key + * @variant: (allow-none): the hint value, or %NULL to unset the hint + * + * Sets a hint for @key with value @variant. If @value is %NULL, + * a previously set hint for @key is unset. + * + * If @variant is floating, it is consumed. + * + * Since: 0.6 + */ +void +notify_notification_set_hint (NotifyNotification *notification, + const char *key, + GVariant *value) +{ + g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); + g_return_if_fail (key != NULL && *key != '\0'); - value = g_new0 (GValue, 1); - g_value_init (value, G_TYPE_VALUE_ARRAY); - g_value_take_boxed (value, image_struct); - - if (_notify_check_spec_version(1, 1)) { - hint_name = "image_data"; + if (value != NULL) { + g_hash_table_insert (notification->priv->hints, + g_strdup (key), + g_variant_ref_sink (value)); } else { - hint_name = "icon_data"; + g_hash_table_remove (notification->priv->hints, key); } - - g_hash_table_insert (notification->priv->hints, - g_strdup (hint_name), - value); } /** @@ -808,24 +740,16 @@ notify_notification_set_image_from_pixbuf (NotifyNotification *notification, * @value: The hint's value. * * Sets a hint with a 32-bit integer value. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_int32 (NotifyNotification *notification, const char *key, gint value) { - GValue *hint_value; - - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, G_TYPE_INT); - g_value_set_int (hint_value, value); - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + notify_notification_set_hint (notification, key, + g_variant_new_int32 (value)); } @@ -836,24 +760,16 @@ notify_notification_set_hint_int32 (NotifyNotification *notification, * @value: The hint's value. * * Sets a hint with an unsigned 32-bit integer value. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_uint32 (NotifyNotification *notification, const char *key, guint value) { - GValue *hint_value; - - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, G_TYPE_UINT); - g_value_set_uint (hint_value, value); - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + notify_notification_set_hint (notification, key, + g_variant_new_uint32 (value)); } /** @@ -863,24 +779,16 @@ notify_notification_set_hint_uint32 (NotifyNotification *notification, * @value: The hint's value. * * Sets a hint with a double value. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_double (NotifyNotification *notification, const char *key, gdouble value) { - GValue *hint_value; - - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, G_TYPE_FLOAT); - g_value_set_float (hint_value, value); - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + notify_notification_set_hint (notification, key, + g_variant_new_double (value)); } /** @@ -890,25 +798,16 @@ notify_notification_set_hint_double (NotifyNotification *notification, * @value: The hint's value. * * Sets a hint with a byte value. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_byte (NotifyNotification *notification, const char *key, guchar value) { - GValue *hint_value; - - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, G_TYPE_UCHAR); - g_value_set_uchar (hint_value, value); - - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + notify_notification_set_hint (notification, key, + g_variant_new_byte (value)); } /** @@ -920,6 +819,8 @@ notify_notification_set_hint_byte (NotifyNotification *notification, * * Sets a hint with a byte array value. The length of @value must be passed * as @len. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_byte_array (NotifyNotification *notification, @@ -927,26 +828,18 @@ notify_notification_set_hint_byte_array (NotifyNotification *notification, const guchar *value, gsize len) { - GValue *hint_value; - GArray *byte_array; + gpointer value_dup; - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - g_return_if_fail (value != NULL); - g_return_if_fail (len > 0); + g_return_if_fail (value != NULL || len == 0); - byte_array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), len); - byte_array = g_array_append_vals (byte_array, value, len); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, dbus_g_type_get_collection ("GArray", - G_TYPE_UCHAR)); - g_value_take_boxed (hint_value, byte_array); - - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + value_dup = g_memdup (value, len); + notify_notification_set_hint (notification, key, + g_variant_new_from_data (G_VARIANT_TYPE ("ay"), + value_dup, + len, + TRUE, + g_free, + value_dup)); } /** @@ -956,24 +849,16 @@ notify_notification_set_hint_byte_array (NotifyNotification *notification, * @value: The hint's value. * * Sets a hint with a string value. + * + * Deprecated: 0.6. Use notify_notification_set_hint() instead */ void notify_notification_set_hint_string (NotifyNotification *notification, const char *key, const char *value) { - GValue *hint_value; - - g_return_if_fail (notification != NULL); - g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); - g_return_if_fail (key != NULL && *key != '\0'); - - hint_value = g_new0 (GValue, 1); - g_value_init (hint_value, G_TYPE_STRING); - g_value_set_string (hint_value, value); - g_hash_table_insert (notification->priv->hints, - g_strdup (key), - hint_value); + notify_notification_set_hint (notification, key, + g_variant_new_string (value)); } static gboolean @@ -1051,7 +936,6 @@ notify_notification_add_action (NotifyNotification *notification, NotifyNotificationPrivate *priv; CallbackPair *pair; - g_return_if_fail (notification != NULL); g_return_if_fail (NOTIFY_IS_NOTIFICATION (notification)); g_return_if_fail (action != NULL && *action != '\0'); g_return_if_fail (label != NULL && *label != '\0'); @@ -1088,44 +972,42 @@ _notify_notification_has_nondefault_actions (const NotifyNotification *n) * @notification: The notification. * @error: The returned error information. * - * Tells the notification server to hide the notification on the screen. + * Synchronously tells the notification server to hide the notification on the screen. * - * Returns: %TRUE if successful. On error, this will return %FALSE and set - * @error. + * Returns: %TRUE on success, or %FALSE on error with @error filled in */ gboolean notify_notification_close (NotifyNotification *notification, GError **error) { NotifyNotificationPrivate *priv; - GError *tmp_error = NULL; - DBusGProxy *proxy; + GDBusProxy *proxy; + GVariant *result; - g_return_val_if_fail (notification != NULL, FALSE); g_return_val_if_fail (NOTIFY_IS_NOTIFICATION (notification), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); priv = notification->priv; - proxy = _notify_get_g_proxy (); + proxy = _notify_get_proxy (error); if (proxy == NULL) { - g_set_error (error, 0, 0, "Unable to connect to server"); return FALSE; } - dbus_g_proxy_call (proxy, - "CloseNotification", - &tmp_error, - G_TYPE_UINT, - priv->id, - G_TYPE_INVALID, - G_TYPE_INVALID); - - if (tmp_error != NULL) { - g_propagate_error (error, tmp_error); + /* FIXME: make this nonblocking! */ + result = g_dbus_proxy_call_sync (proxy, + "CloseNotification", + g_variant_new ("(u)", priv->id), + G_DBUS_CALL_FLAGS_NONE, + -1 /* FIXME! */, + NULL, + error); + if (result == NULL) { return FALSE; } + g_variant_unref (result); + return TRUE; } diff --git a/libnotify/notification.h b/libnotify/notification.h index c117210..b949365 100644 --- a/libnotify/notification.h +++ b/libnotify/notification.h @@ -126,6 +126,10 @@ void notify_notification_set_hint_byte_array (NotifyNotificatio const guchar *value, gsize len); +void notify_notification_set_hint (NotifyNotification *notification, + const char *key, + GVariant *value); + void notify_notification_clear_hints (NotifyNotification *notification); void notify_notification_add_action (NotifyNotification *notification, diff --git a/libnotify/notify.c b/libnotify/notify.c index d8593cc..1ecc67b 100644 --- a/libnotify/notify.c +++ b/libnotify/notify.c @@ -3,6 +3,7 @@ * Copyright (C) 2004-2006 Christian Hammond * Copyright (C) 2004-2006 Mike Hearn * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2010 Christian Persch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,8 +29,7 @@ #include #include -#include -#include +#include #include "notify.h" #include "internal.h" @@ -37,8 +37,7 @@ static gboolean _initted = FALSE; static char *_app_name = NULL; -static DBusGProxy *_proxy = NULL; -static DBusGConnection *_dbus_gconn = NULL; +static GDBusProxy *_proxy = NULL; static GList *_active_notifications = NULL; static int _spec_version_major = 0; static int _spec_version_minor = 0; @@ -55,11 +54,52 @@ _notify_check_spec_version (int major, } static gboolean -_notify_update_spec_version (void) +_notify_get_server_info (char **ret_name, + char **ret_vendor, + char **ret_version, + char **ret_spec_version, + GError **error) +{ + GDBusProxy *proxy; + GVariant *result; + + proxy = _notify_get_proxy (error); + if (proxy == NULL) { + return FALSE; + } + + result = g_dbus_proxy_call_sync (proxy, + "GetServerInformation", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, + -1 /* FIXME shorter timeout? */, + NULL, + error); + if (result == NULL) { + return FALSE; + } + if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(ssss)"))) { + g_variant_unref (result); + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Unexpected reply type"); + return FALSE; + } + + g_variant_get (result, "(ssss)", + ret_name, + ret_vendor, + ret_version, + ret_spec_version); + g_variant_unref (result); + return TRUE; +} + +static gboolean +_notify_update_spec_version (GError **error) { char *spec_version; - if (!notify_get_server_info (NULL, NULL, NULL, &spec_version)) { + if (!_notify_get_server_info (NULL, NULL, NULL, &spec_version, error)) { return FALSE; } @@ -146,6 +186,7 @@ notify_uninit (void) if (_proxy != NULL) { g_object_unref (_proxy); + _proxy = NULL; } _initted = FALSE; @@ -164,136 +205,105 @@ notify_is_initted (void) return _initted; } -DBusGConnection * -_notify_get_dbus_g_conn (void) +/* + * _notify_get_proxy: + * @error: (allow-none): a location to store a #GError, or %NULL + * + * Synchronously creates the #GDBusProxy for the notification service, + * and caches the result. + * + * Returns: the #GDBusProxy for the notification service, or %NULL on error + */ +GDBusProxy * +_notify_get_proxy (GError **error) { - return _dbus_gconn; -} - -static void -on_proxy_destroy (DBusGProxy *proxy, - gpointer data) -{ - _proxy = NULL; -} - -DBusGProxy * -_notify_get_g_proxy (void) -{ - GError *error; - DBusGConnection *bus; - if (_proxy != NULL) return _proxy; - /* lazily initialize D-Bus connection */ - error = NULL; - bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (error != NULL) { - g_error_free (error); + _proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + NOTIFY_DBUS_NAME, + NOTIFY_DBUS_CORE_OBJECT, + NOTIFY_DBUS_CORE_INTERFACE, + NULL, + error); + if (_proxy == NULL) { return NULL; } - _proxy = dbus_g_proxy_new_for_name (bus, - NOTIFY_DBUS_NAME, - NOTIFY_DBUS_CORE_OBJECT, - NOTIFY_DBUS_CORE_INTERFACE); - dbus_g_connection_unref (bus); - - g_signal_connect (_proxy, - "destroy", - G_CALLBACK (on_proxy_destroy), - NULL); - - dbus_g_object_register_marshaller (notify_marshal_VOID__UINT_UINT, - G_TYPE_NONE, - G_TYPE_UINT, - G_TYPE_UINT, - G_TYPE_INVALID); - - dbus_g_object_register_marshaller (notify_marshal_VOID__UINT_STRING, - G_TYPE_NONE, - G_TYPE_UINT, - G_TYPE_STRING, - G_TYPE_INVALID); - - dbus_g_proxy_add_signal (_proxy, - "NotificationClosed", - G_TYPE_UINT, - G_TYPE_UINT, - G_TYPE_INVALID); - dbus_g_proxy_add_signal (_proxy, - "ActionInvoked", - G_TYPE_UINT, - G_TYPE_STRING, - G_TYPE_INVALID); - - if (!_notify_update_spec_version ()) { + if (!_notify_update_spec_version (error)) { + g_object_unref (_proxy); + _proxy = NULL; return NULL; } + g_object_add_weak_pointer (G_OBJECT (_proxy), (gpointer *) &_proxy); + return _proxy; } /** * notify_get_server_caps: * - * Queries the server for its capabilities and returns them in a #GList. + * Synchronously queries the server for its capabilities and returns them in a #GList. * - * Returns: A #GList of server capability strings. + * Returns: (transfer full) (element-type utf-8): a #GList of server capability strings. Free + * the list elements with g_free() and the list itself with g_list_free(). */ GList * notify_get_server_caps (void) { - GError *error; - char **caps; - char **cap; - GList *result; - DBusGProxy *proxy; + GDBusProxy *proxy; + GVariant *result; + char **cap, **caps; + GList *list = NULL; - caps = NULL; - result = NULL; - - proxy = _notify_get_g_proxy (); + proxy = _notify_get_proxy (NULL); if (proxy == NULL) { - return NULL; + return FALSE; } - error = NULL; - if (!dbus_g_proxy_call (proxy, - "GetCapabilities", - &error, - G_TYPE_INVALID, - G_TYPE_STRV, - &caps, - G_TYPE_INVALID)) { - g_error_free (error); - return NULL; + result = g_dbus_proxy_call_sync (proxy, + "GetCapabilities", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, + -1 /* FIXME shorter timeout? */, + NULL, + NULL); + if (result == NULL) { + return FALSE; } + if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(as)"))) { + g_variant_unref (result); + return FALSE; + } + + g_variant_get (result, "(^as)", &caps); for (cap = caps; *cap != NULL; cap++) { - result = g_list_append (result, g_strdup (*cap)); + list = g_list_prepend (list, *cap); } - g_strfreev (caps); + g_free (caps); + g_variant_unref (result); - return result; + return g_list_reverse (list); } /** * notify_get_server_info: - * @ret_name: The resulting server name. - * @ret_vendor: The resulting server vendor. - * @ret_version: The resulting server version. - * @ret_spec_version: The resulting version of the specification the server is - * compliant with. + * @ret_name: (out) (allow-none): a location to store the server name, or %NULL + * @ret_vendor: (out) (allow-none): a location to store the server vendor, or %NULL + * @ret_version: (out) (allow-none): a location to store the server version, or %NULL + * @ret_spec_version: (out) (allow-none): a location to store the version the service is compliant with, or %NULL * - * Queries the server for its information, specifically, the name, vendor, + * Synchronously queries the server for its information, specifically, the name, vendor, * server version, and the version of the notifications specification that it * is compliant with. * - * Returns: %TRUE if successful, and the variables passed will be set. %FALSE - * on failure. + * Returns: %TRUE if successful, and the variables passed will be set, %FALSE + * on error. The returned strings must be freed with g_free */ gboolean notify_get_server_info (char **ret_name, @@ -301,57 +311,7 @@ notify_get_server_info (char **ret_name, char **ret_version, char **ret_spec_version) { - GError *error; - DBusGProxy *proxy; - char *name; - char *vendor; - char *version; - char *spec_version; - - proxy = _notify_get_g_proxy (); - if (proxy == NULL) { - return FALSE; - } - - error = NULL; - if (!dbus_g_proxy_call (proxy, - "GetServerInformation", - &error, - G_TYPE_INVALID, - G_TYPE_STRING, &name, - G_TYPE_STRING, &vendor, - G_TYPE_STRING, &version, - G_TYPE_STRING, &spec_version, - G_TYPE_INVALID)) { - g_error_free (error); - return FALSE; - } - - if (ret_name != NULL) { - *ret_name = name; - } else { - g_free (name); - } - - if (ret_vendor != NULL) { - *ret_vendor = vendor; - } else { - g_free (vendor); - } - - if (ret_version != NULL) { - *ret_version = version; - } else { - g_free (version); - } - - if (ret_spec_version != NULL) { - *ret_spec_version = spec_version; - } else { - g_free (spec_version); - } - - return TRUE; + return _notify_get_server_info (ret_name, ret_vendor, ret_version, ret_spec_version, NULL); } void diff --git a/libnotify/notify.h b/libnotify/notify.h index cceb21e..0235419 100644 --- a/libnotify/notify.h +++ b/libnotify/notify.h @@ -60,25 +60,8 @@ gboolean notify_is_initted (void); */ const char *notify_get_app_name (void); -/** - * Returns the capabilities of the notification server. - * - * @return A list of capability strings. These strings must be freed. - */ GList *notify_get_server_caps (void); -/** - * Returns the server notification information. - * - * The strings returned must be freed. - * - * @param ret_name The returned product name of the server. - * @param ret_vendor The returned vendor. - * @param ret_version The returned server version. - * @param ret_spec_version The returned specification version supported. - * - * @return TRUE if the call succeeded, or FALSE if there were errors. - */ gboolean notify_get_server_info (char **ret_name, char **ret_vendor, char **ret_version, diff --git a/tests/test-default-action.c b/tests/test-default-action.c index 4b70623..e103262 100644 --- a/tests/test-default-action.c +++ b/tests/test-default-action.c @@ -27,13 +27,6 @@ #include #include -#define DBUS_API_SUBJECT_TO_CHANGE - -#include -#include -#include -#include - static GMainLoop *loop; static void @@ -54,16 +47,12 @@ int main () { NotifyNotification *n; - DBusConnection *conn; if (!notify_init ("Default Action Test")) exit (1); - conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); loop = g_main_loop_new (NULL, FALSE); - dbus_connection_setup_with_g_main (conn, NULL); - n = notify_notification_new ("Matt is online", "", NULL); notify_notification_set_timeout (n, NOTIFY_EXPIRES_DEFAULT); notify_notification_add_action (n, diff --git a/tests/test-image.c b/tests/test-image.c index 51b29c4..cb25f88 100644 --- a/tests/test-image.c +++ b/tests/test-image.c @@ -31,14 +31,7 @@ #include #include #include - -#define DBUS_API_SUBJECT_TO_CHANGE - -#include #include -#include -#include -#include GMainLoop *loop; NotifyNotification *n; diff --git a/tests/test-multi-actions.c b/tests/test-multi-actions.c index 55d78a8..f361f79 100644 --- a/tests/test-multi-actions.c +++ b/tests/test-multi-actions.c @@ -26,13 +26,6 @@ #include #include -#define DBUS_API_SUBJECT_TO_CHANGE - -#include -#include -#include -#include - static GMainLoop *loop; static void @@ -82,16 +75,12 @@ int main (int argc, char **argv) { NotifyNotification *n; - DBusConnection *conn; if (!notify_init ("Multi Action Test")) exit (1); - conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); loop = g_main_loop_new (NULL, FALSE); - dbus_connection_setup_with_g_main (conn, NULL); - n = notify_notification_new ("Low disk space", "You can free up some disk space by " "emptying the trash can.", diff --git a/tests/test-xy-actions.c b/tests/test-xy-actions.c index b6e3548..060ffea 100644 --- a/tests/test-xy-actions.c +++ b/tests/test-xy-actions.c @@ -24,11 +24,6 @@ #include #include -#define DBUS_API_SUBJECT_TO_CHANGE -#include -#include -#include - static GMainLoop *loop; static void @@ -44,15 +39,11 @@ int main (int argc, char **argv) { NotifyNotification *n; - DBusConnection *conn; notify_init ("XY"); - conn = dbus_bus_get (DBUS_BUS_SESSION, NULL); loop = g_main_loop_new (NULL, FALSE); - dbus_connection_setup_with_g_main (conn, NULL); - n = notify_notification_new ("System update available", "New system updates are available. It is " "recommended that you install the updates.",