diff --git a/gio/Makefile.am b/gio/Makefile.am index a6fd62c94..d57510c50 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -267,6 +267,7 @@ unix_sources = \ gcontenttype.c \ gcontenttypeprivate.h \ gfdonotificationbackend.c \ + ggtknotificationbackend.c \ $(NULL) diff --git a/gio/gfdonotificationbackend.c b/gio/gfdonotificationbackend.c index 91af2787c..ad665bed5 100644 --- a/gio/gfdonotificationbackend.c +++ b/gio/gfdonotificationbackend.c @@ -176,7 +176,7 @@ call_notify (GDBusConnection *con, guint n_buttons; guint i; GVariantBuilder hints_builder; - GIcon *image; + GIcon *icon; GVariant *parameters; const gchar *body; @@ -222,12 +222,12 @@ call_notify (GDBusConnection *con, g_variant_new_string (g_application_get_application_id (app))); if (g_notification_get_urgent (notification)) g_variant_builder_add (&hints_builder, "{sv}", "urgency", g_variant_new_byte (2)); - image = g_notification_get_image (notification); - if (image != NULL && G_IS_FILE_ICON (image)) + icon = g_notification_get_icon (notification); + if (icon != NULL && G_IS_FILE_ICON (icon)) { GFile *file; - file = g_file_icon_get_file (G_FILE_ICON (image)); + file = g_file_icon_get_file (G_FILE_ICON (icon)); g_variant_builder_add (&hints_builder, "{sv}", "image-path", g_variant_new_take_string (g_file_get_uri (file))); } @@ -339,7 +339,7 @@ g_fdo_notification_backend_send_notification (GNotificationBackend *backend, n = g_fdo_notification_backend_find_notification (self, id); if (n == NULL) { - n = g_slice_new (FreedesktopNotification); + n = g_slice_new0 (FreedesktopNotification); n->backend = self; n->id = g_strdup (id); n->notify_id = 0; @@ -349,9 +349,8 @@ g_fdo_notification_backend_send_notification (GNotificationBackend *backend, else { /* Only clear default action. All other fields are still valid */ - g_free (n->default_action); - if (n->default_action_target) - g_variant_unref (n->default_action_target); + g_clear_pointer (&n->default_action, g_free); + g_clear_pointer (&n->default_action_target, g_variant_unref); } g_notification_get_default_action (notification, &n->default_action, &n->default_action_target); diff --git a/gio/ggtknotificationbackend.c b/gio/ggtknotificationbackend.c new file mode 100644 index 000000000..79486b18a --- /dev/null +++ b/gio/ggtknotificationbackend.c @@ -0,0 +1,144 @@ +/* +* Copyright © 2013 Lars Uebernickel +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* Public License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place, Suite 330, +* Boston, MA 02111-1307, USA. +* +* Authors: Lars Uebernickel +*/ + +#include "gnotificationbackend.h" + +#include "giomodule-priv.h" +#include "gdbusconnection.h" +#include "gapplication.h" +#include "gnotification-private.h" + +#define G_TYPE_GTK_NOTIFICATION_BACKEND (g_gtk_notification_backend_get_type ()) +#define G_GTK_NOTIFICATION_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GTK_NOTIFICATION_BACKEND, GGtkNotificationBackend)) + +typedef struct _GGtkNotificationBackend GGtkNotificationBackend; +typedef GNotificationBackendClass GGtkNotificationBackendClass; + +struct _GGtkNotificationBackend +{ + GNotificationBackend parent; + + GDBusConnection *session_bus; +}; + +GType g_gtk_notification_backend_get_type (void); + +G_DEFINE_TYPE_WITH_CODE (GGtkNotificationBackend, g_gtk_notification_backend, G_TYPE_NOTIFICATION_BACKEND, + _g_io_modules_ensure_extension_points_registered (); + g_io_extension_point_implement (G_NOTIFICATION_BACKEND_EXTENSION_POINT_NAME, + g_define_type_id, "gtk", 100)) + +static void +g_gtk_notification_backend_dispose (GObject *object) +{ + GGtkNotificationBackend *backend = G_GTK_NOTIFICATION_BACKEND (object); + + g_clear_object (&backend->session_bus); + + G_OBJECT_CLASS (g_gtk_notification_backend_parent_class)->dispose (object); +} + +static gboolean +g_gtk_notification_backend_is_supported (void) +{ + GDBusConnection *session_bus; + GVariant *reply; + + /* Find out if the notification server is running. This is a + * synchronous call because gio extension points don't support asnyc + * backend verification. This is only run once and only contacts the + * dbus daemon. */ + + session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + if (session_bus == NULL) + return FALSE; + + reply = g_dbus_connection_call_sync (session_bus, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", + "GetNameOwner", g_variant_new ("(s)", "org.gtk.Notifications"), + G_VARIANT_TYPE ("(s)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); + + g_object_unref (session_bus); + + if (reply) + { + g_variant_unref (reply); + return TRUE; + } + else + return FALSE; +} + +static void +g_gtk_notification_backend_send_notification (GNotificationBackend *backend, + const gchar *id, + GNotification *notification) +{ + GApplication *application; + GVariant *params; + + application = g_notification_backend_get_application (backend); + + params = g_variant_new ("(ss@a{sv})", g_application_get_application_id (application), + id, + g_notification_serialize (notification)); + + g_dbus_connection_call (g_notification_backend_get_dbus_connection (backend), + "org.gtk.Notifications", "/org/gtk/Notifications", + "org.gtk.Notifications", "AddNotification", params, + G_VARIANT_TYPE_UNIT, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); +} + +static void +g_gtk_notification_backend_withdraw_notification (GNotificationBackend *backend, + const gchar *id) +{ + GGtkNotificationBackend *self = G_GTK_NOTIFICATION_BACKEND (backend); + GApplication *application; + GVariant *params; + + application = g_notification_backend_get_application (backend); + + params = g_variant_new ("(ss)", g_application_get_application_id (application), id); + + g_dbus_connection_call (self->session_bus, "org.gtk.Notifications", + "/org/gtk/Notifications", "org.gtk.Notifications", + "RemoveNotification", params, G_VARIANT_TYPE_UNIT, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); +} + +static void +g_gtk_notification_backend_init (GGtkNotificationBackend *backend) +{ +} + +static void +g_gtk_notification_backend_class_init (GGtkNotificationBackendClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GNotificationBackendClass *backend_class = G_NOTIFICATION_BACKEND_CLASS (class); + + object_class->dispose = g_gtk_notification_backend_dispose; + + backend_class->is_supported = g_gtk_notification_backend_is_supported; + backend_class->send_notification = g_gtk_notification_backend_send_notification; + backend_class->withdraw_notification = g_gtk_notification_backend_withdraw_notification; +} diff --git a/gio/giomodule.c b/gio/giomodule.c index 77624addb..92aa97bdc 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -897,6 +897,7 @@ extern GType _g_network_monitor_netlink_get_type (void); #ifdef G_OS_UNIX extern GType g_fdo_notification_backend_get_type (void); +extern GType g_gtk_notification_backend_get_type (void); #endif #ifdef G_PLATFORM_WIN32 @@ -1074,6 +1075,7 @@ _g_io_modules_ensure_loaded (void) #ifdef G_OS_UNIX g_type_ensure (_g_unix_volume_monitor_get_type ()); g_type_ensure (g_fdo_notification_backend_get_type ()); + g_type_ensure (g_gtk_notification_backend_get_type ()); #endif #ifdef G_OS_WIN32 g_type_ensure (_g_winhttp_vfs_get_type ()); diff --git a/gio/gnotification-private.h b/gio/gnotification-private.h index 9521b8011..e6513b331 100644 --- a/gio/gnotification-private.h +++ b/gio/gnotification-private.h @@ -30,7 +30,7 @@ const gchar * g_notification_get_title (GNotifi const gchar * g_notification_get_body (GNotification *notification); -GIcon * g_notification_get_image (GNotification *notification); +GIcon * g_notification_get_icon (GNotification *notification); gboolean g_notification_get_urgent (GNotification *notification); @@ -51,4 +51,6 @@ gboolean g_notification_get_default_action (GNotifi GVariant * g_notification_serialize (GNotification *notification); +GVariant * g_notification_serialize (GNotification *notification); + #endif diff --git a/gio/gnotification.c b/gio/gnotification.c index d912e9f71..ec6e06106 100644 --- a/gio/gnotification.c +++ b/gio/gnotification.c @@ -34,7 +34,7 @@ struct _GNotification gchar *title; gchar *body; - GIcon *image; + GIcon *icon; gboolean urgent; GPtrArray *buttons; gchar *default_action; @@ -68,7 +68,7 @@ g_notification_dispose (GObject *object) { GNotification *notification = G_NOTIFICATION (object); - g_clear_object (¬ification->image); + g_clear_object (¬ification->icon); G_OBJECT_CLASS (g_notification_parent_class)->dispose (object); } @@ -210,42 +210,42 @@ g_notification_set_body (GNotification *notification, } /** - * g_notification_get_image: + * g_notification_get_icon: * @notification: a #GNotification * - * Gets the image currently set on @notification. + * Gets the icon currently set on @notification. * - * Returns: (transfer none): the image associated with @notification + * Returns: (transfer none): the icon associated with @notification * * Since: 2.40 */ GIcon * -g_notification_get_image (GNotification *notification) +g_notification_get_icon (GNotification *notification) { g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL); - return notification->image; + return notification->icon; } /** - * g_notification_set_image: + * g_notification_set_icon: * @notification: a #GNotification - * @image: the image to be shown in @notification, as a #GIcon + * @icon: the icon to be shown in @notification, as a #GIcon * - * Sets the image of @notification to @image. + * Sets the icon of @notification to @icon. * * Since: 2.40 */ void -g_notification_set_image (GNotification *notification, - GIcon *image) +g_notification_set_icon (GNotification *notification, + GIcon *icon) { g_return_if_fail (G_IS_NOTIFICATION (notification)); - if (notification->image) - g_object_unref (notification->image); + if (notification->icon) + g_object_unref (notification->icon); - notification->image = g_object_ref (image); + notification->icon = g_object_ref (icon); } /** @@ -637,3 +637,81 @@ g_notification_set_default_action_and_target_value (GNotification *notification, if (target) notification->default_action_target = g_variant_ref_sink (target); } + +static GVariant * +g_notification_serialize_button (Button *button) +{ + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (button->label)); + g_variant_builder_add (&builder, "{sv}", "action", g_variant_new_string (button->action_name)); + + if (button->target) + g_variant_builder_add (&builder, "{sv}", "target", button->target); + + return g_variant_builder_end (&builder); +} + +/*< private > + * g_notification_serialize: + * + * Serializes @notification into an floating variant of type a{sv}. + * + * Returns: the serialized @notification as a floating variant. + */ +GVariant * +g_notification_serialize (GNotification *notification) +{ + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + if (notification->title) + g_variant_builder_add (&builder, "{sv}", "title", g_variant_new_string (notification->title)); + + if (notification->body) + g_variant_builder_add (&builder, "{sv}", "body", g_variant_new_string (notification->body)); + + if (notification->icon) + { + GVariant *serialized_icon; + + if ((serialized_icon = g_icon_serialize (notification->icon))) + { + g_variant_builder_add (&builder, "{sv}", "icon", serialized_icon); + g_variant_unref (serialized_icon); + } + } + + g_variant_builder_add (&builder, "{sv}", "urgent", g_variant_new_boolean (notification->urgent)); + + if (notification->default_action) + { + g_variant_builder_add (&builder, "{sv}", "default-action", + g_variant_new_string (notification->default_action)); + + if (notification->default_action_target) + g_variant_builder_add (&builder, "{sv}", "default-action-target", + notification->default_action_target); + } + + if (notification->buttons->len > 0) + { + GVariantBuilder actions_builder; + guint i; + + g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}")); + + for (i = 0; i < notification->buttons->len; i++) + { + Button *button = g_ptr_array_index (notification->buttons, i); + g_variant_builder_add (&actions_builder, "@a{sv}", g_notification_serialize_button (button)); + } + + g_variant_builder_add (&builder, "{sv}", "buttons", g_variant_builder_end (&actions_builder)); + } + + return g_variant_builder_end (&builder); +} diff --git a/gio/gnotification.h b/gio/gnotification.h index 652d7ddd7..c7e827786 100644 --- a/gio/gnotification.h +++ b/gio/gnotification.h @@ -49,8 +49,8 @@ void g_notification_set_body (GNotifi const gchar *body); GLIB_AVAILABLE_IN_2_40 -void g_notification_set_image (GNotification *notification, - GIcon *image); +void g_notification_set_icon (GNotification *notification, + GIcon *icon); GLIB_AVAILABLE_IN_2_40 void g_notification_set_urgent (GNotification *notification, diff --git a/gio/gnotificationbackend.c b/gio/gnotificationbackend.c index d5ced9c08..a3bcde5b6 100644 --- a/gio/gnotificationbackend.c +++ b/gio/gnotificationbackend.c @@ -97,10 +97,16 @@ g_notification_backend_activate_action (GNotificationBackend *backend, GVariant *parameter) { g_return_if_fail (G_IS_NOTIFICATION_BACKEND (backend)); - g_return_if_fail (name != NULL); - if (g_str_has_prefix (name, "app.")) - g_action_group_activate_action (G_ACTION_GROUP (backend->application), name + 4, parameter); + if (name) + { + if (g_str_has_prefix (name, "app.")) + g_action_group_activate_action (G_ACTION_GROUP (backend->application), name + 4, parameter); + } + else + { + g_application_activate (backend->application); + } } GDBusConnection *