mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 18:52:09 +01:00
tests: Add test for GNotification portal backend
The portal backend for notifications didn't have any tests this adds add least some. This also adjusts the mock notification server used to test the GTK backend to allow to test the portal as well.
This commit is contained in:
parent
c15ce5f9b8
commit
944fb70942
@ -22,6 +22,7 @@
|
|||||||
#include "gnotification-server.h"
|
#include "gnotification-server.h"
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
typedef GObjectClass GNotificationServerClass;
|
typedef GObjectClass GNotificationServerClass;
|
||||||
|
|
||||||
@ -33,10 +34,16 @@ struct _GNotificationServer
|
|||||||
guint name_owner_id;
|
guint name_owner_id;
|
||||||
guint object_id;
|
guint object_id;
|
||||||
|
|
||||||
|
gchar *backend_name;
|
||||||
|
guint backend_version;
|
||||||
|
|
||||||
guint is_running;
|
guint is_running;
|
||||||
|
|
||||||
/* app_ids -> hashtables of notification ids -> a{sv} */
|
/* app_ids -> hashtables of notification ids -> a{sv} */
|
||||||
GHashTable *applications;
|
GHashTable *applications;
|
||||||
|
|
||||||
|
/* notification -> unix_fd_list */
|
||||||
|
GHashTable *unix_fd_lists;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (GNotificationServer, g_notification_server, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (GNotificationServer, g_notification_server, G_TYPE_OBJECT)
|
||||||
@ -44,9 +51,27 @@ G_DEFINE_TYPE (GNotificationServer, g_notification_server, G_TYPE_OBJECT)
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_IS_RUNNING
|
PROP_IS_RUNNING,
|
||||||
|
PROP_BACKEND_NAME,
|
||||||
|
PROP_BACKEND_VERSION
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
get_bus_name (GNotificationServer *server) {
|
||||||
|
if (g_strcmp0 (server->backend_name, "portal") == 0)
|
||||||
|
return "org.freedesktop.portal.Desktop";
|
||||||
|
|
||||||
|
return "org.gtk.Notifications";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
get_object_path (GNotificationServer *server) {
|
||||||
|
if (g_strcmp0 (server->backend_name, "portal") == 0)
|
||||||
|
return "/org/freedesktop/portal/desktop";
|
||||||
|
|
||||||
|
return "/org/gtk/Notifications";
|
||||||
|
}
|
||||||
|
|
||||||
static GDBusInterfaceInfo *
|
static GDBusInterfaceInfo *
|
||||||
org_gtk_Notifications_get_interface (void)
|
org_gtk_Notifications_get_interface (void)
|
||||||
{
|
{
|
||||||
@ -85,6 +110,52 @@ org_gtk_Notifications_get_interface (void)
|
|||||||
return iface_info;
|
return iface_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GDBusInterfaceInfo *
|
||||||
|
org_freedesktop_portal_notification_get_interface (void)
|
||||||
|
{
|
||||||
|
static GDBusInterfaceInfo *iface_info;
|
||||||
|
|
||||||
|
if (iface_info == NULL)
|
||||||
|
{
|
||||||
|
GDBusNodeInfo *info;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
info = g_dbus_node_info_new_for_xml (
|
||||||
|
"<node>"
|
||||||
|
" <interface name='org.freedesktop.portal.Notification'>"
|
||||||
|
" <method name='AddNotification'>"
|
||||||
|
" <arg type='s' direction='in' />"
|
||||||
|
" <arg type='a{sv}' direction='in' />"
|
||||||
|
" </method>"
|
||||||
|
" <method name='RemoveNotification'>"
|
||||||
|
" <arg type='s' direction='in' />"
|
||||||
|
" </method>"
|
||||||
|
" <property name='version' type='u' access='read'/>"
|
||||||
|
" </interface>"
|
||||||
|
"</node>", &error);
|
||||||
|
|
||||||
|
if (info == NULL)
|
||||||
|
g_error ("%s", error->message);
|
||||||
|
|
||||||
|
iface_info = g_dbus_node_info_lookup_interface (info, "org.freedesktop.portal.Notification");
|
||||||
|
g_assert (iface_info);
|
||||||
|
|
||||||
|
g_dbus_interface_info_ref (iface_info);
|
||||||
|
g_dbus_node_info_unref (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GDBusInterfaceInfo *
|
||||||
|
get_interface (GNotificationServer *server)
|
||||||
|
{
|
||||||
|
if (g_strcmp0 (server->backend_name, "portal") == 0)
|
||||||
|
return org_freedesktop_portal_notification_get_interface ();
|
||||||
|
|
||||||
|
return org_gtk_Notifications_get_interface ();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_notification_server_notification_added (GNotificationServer *server,
|
g_notification_server_notification_added (GNotificationServer *server,
|
||||||
const gchar *app_id,
|
const gchar *app_id,
|
||||||
@ -116,6 +187,8 @@ g_notification_server_notification_removed (GNotificationServer *server,
|
|||||||
notifications = g_hash_table_lookup (server->applications, app_id);
|
notifications = g_hash_table_lookup (server->applications, app_id);
|
||||||
if (notifications)
|
if (notifications)
|
||||||
{
|
{
|
||||||
|
g_hash_table_remove (server->unix_fd_lists,
|
||||||
|
g_hash_table_lookup (notifications, notification_id));
|
||||||
g_hash_table_remove (notifications, notification_id);
|
g_hash_table_remove (notifications, notification_id);
|
||||||
if (g_hash_table_size (notifications) == 0)
|
if (g_hash_table_size (notifications) == 0)
|
||||||
g_hash_table_remove (server->applications, app_id);
|
g_hash_table_remove (server->applications, app_id);
|
||||||
@ -164,56 +237,74 @@ org_gtk_Notifications_method_call (GDBusConnection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_notification_server_dispose (GObject *object)
|
org_freedesktop_portal_notification_method_call (GDBusConnection *connection,
|
||||||
|
const gchar *sender,
|
||||||
|
const gchar *object_path,
|
||||||
|
const gchar *interface_name,
|
||||||
|
const gchar *method_name,
|
||||||
|
GVariant *parameters,
|
||||||
|
GDBusMethodInvocation *invocation,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
GNotificationServer *server = user_data;
|
||||||
|
|
||||||
g_notification_server_stop (server);
|
if (g_str_equal (method_name, "AddNotification"))
|
||||||
|
|
||||||
g_clear_pointer (&server->applications, g_hash_table_unref);
|
|
||||||
g_clear_object (&server->connection);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (g_notification_server_parent_class)->dispose (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
g_notification_server_get_property (GObject *object,
|
|
||||||
guint property_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
|
||||||
|
|
||||||
switch (property_id)
|
|
||||||
{
|
{
|
||||||
case PROP_IS_RUNNING:
|
const gchar *notification_id;
|
||||||
g_value_set_boolean (value, server->is_running);
|
g_autoptr(GVariant) notification = NULL;
|
||||||
break;
|
GUnixFDList* fd_list;
|
||||||
|
|
||||||
default:
|
fd_list = g_dbus_message_get_unix_fd_list (g_dbus_method_invocation_get_message (invocation));
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
|
g_variant_get (parameters, "(&s@a{sv})", ¬ification_id, ¬ification);
|
||||||
|
|
||||||
|
if (fd_list)
|
||||||
|
g_hash_table_replace (server->unix_fd_lists, g_variant_ref (notification), g_object_ref (fd_list));
|
||||||
|
|
||||||
|
g_notification_server_notification_added (server, "", notification_id, notification);
|
||||||
|
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||||
|
}
|
||||||
|
else if (g_str_equal (method_name, "RemoveNotification"))
|
||||||
|
{
|
||||||
|
const gchar *notification_id;
|
||||||
|
|
||||||
|
g_variant_get (parameters, "(&s)", ¬ification_id);
|
||||||
|
g_notification_server_notification_removed (server, "", notification_id);
|
||||||
|
g_dbus_method_invocation_return_value (invocation, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_dbus_error (invocation, "UnknownMethod", "No such method");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static GVariant *
|
||||||
static void
|
org_freedesktop_portal_notification_get_property (GDBusConnection *connection,
|
||||||
g_notification_server_class_init (GNotificationServerClass *class)
|
const gchar *sender,
|
||||||
|
const gchar *object_path,
|
||||||
|
const gchar *interface_name,
|
||||||
|
const gchar *property_name,
|
||||||
|
GError **error,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
GNotificationServer *server = user_data;
|
||||||
|
|
||||||
object_class->get_property = g_notification_server_get_property;
|
if (g_strcmp0 (property_name, "version") == 0)
|
||||||
object_class->dispose = g_notification_server_dispose;
|
return g_variant_new_uint32 (server->backend_version);
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_IS_RUNNING,
|
return NULL;
|
||||||
g_param_spec_boolean ("is-running", "", "", FALSE,
|
}
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
||||||
|
|
||||||
g_signal_new ("notification-received", G_TYPE_NOTIFICATION_SERVER, G_SIGNAL_RUN_FIRST,
|
|
||||||
0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 3,
|
|
||||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_VARIANT);
|
|
||||||
|
|
||||||
g_signal_new ("notification-removed", G_TYPE_NOTIFICATION_SERVER, G_SIGNAL_RUN_FIRST,
|
static GDBusInterfaceVTable
|
||||||
0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
|
get_vtable (GNotificationServer *server)
|
||||||
G_TYPE_STRING, G_TYPE_STRING);
|
{
|
||||||
|
const GDBusInterfaceVTable vtable = {
|
||||||
|
(g_strcmp0 (server->backend_name, "portal") == 0) ? org_freedesktop_portal_notification_method_call : org_gtk_Notifications_method_call,
|
||||||
|
(g_strcmp0 (server->backend_name, "portal") == 0) ? org_freedesktop_portal_notification_get_property : NULL,
|
||||||
|
NULL, { 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
return vtable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -221,13 +312,11 @@ g_notification_server_bus_acquired (GDBusConnection *connection,
|
|||||||
const gchar *name,
|
const gchar *name,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
const GDBusInterfaceVTable vtable = {
|
|
||||||
org_gtk_Notifications_method_call, NULL, NULL, { 0 }
|
|
||||||
};
|
|
||||||
GNotificationServer *server = user_data;
|
GNotificationServer *server = user_data;
|
||||||
|
const GDBusInterfaceVTable vtable = get_vtable (server);
|
||||||
|
|
||||||
server->object_id = g_dbus_connection_register_object (connection, "/org/gtk/Notifications",
|
server->object_id = g_dbus_connection_register_object (connection, get_object_path (server),
|
||||||
org_gtk_Notifications_get_interface (),
|
get_interface (server),
|
||||||
&vtable, server, NULL, NULL);
|
&vtable, server, NULL, NULL);
|
||||||
|
|
||||||
/* register_object only fails if the same object is exported more than once */
|
/* register_object only fails if the same object is exported more than once */
|
||||||
@ -261,13 +350,15 @@ g_notification_server_name_lost (GDBusConnection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_notification_server_init (GNotificationServer *server)
|
g_notification_server_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
server->applications = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
||||||
g_free, (GDestroyNotify) g_hash_table_unref);
|
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (g_notification_server_parent_class)->constructed (object);
|
||||||
|
|
||||||
server->name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
server->name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||||
"org.gtk.Notifications",
|
get_bus_name (server),
|
||||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||||
g_notification_server_bus_acquired,
|
g_notification_server_bus_acquired,
|
||||||
g_notification_server_name_acquired,
|
g_notification_server_name_acquired,
|
||||||
@ -275,10 +366,119 @@ g_notification_server_init (GNotificationServer *server)
|
|||||||
server, NULL);
|
server, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
GNotificationServer *
|
static void
|
||||||
g_notification_server_new (void)
|
g_notification_server_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
return g_object_new (G_TYPE_NOTIFICATION_SERVER, NULL);
|
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
||||||
|
|
||||||
|
g_notification_server_stop (server);
|
||||||
|
|
||||||
|
g_clear_pointer (&server->applications, g_hash_table_unref);
|
||||||
|
g_clear_pointer (&server->unix_fd_lists, g_hash_table_unref);
|
||||||
|
g_clear_object (&server->connection);
|
||||||
|
g_clear_pointer (&server->backend_name, g_free);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (g_notification_server_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_notification_server_set_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_BACKEND_NAME:
|
||||||
|
server->backend_name = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_BACKEND_VERSION:
|
||||||
|
server->backend_version = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_notification_server_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_IS_RUNNING:
|
||||||
|
g_value_set_boolean (value, server->is_running);
|
||||||
|
break;
|
||||||
|
case PROP_BACKEND_NAME:
|
||||||
|
g_value_set_string (value, server->backend_name);
|
||||||
|
break;
|
||||||
|
case PROP_BACKEND_VERSION:
|
||||||
|
g_value_set_uint (value, server->backend_version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_notification_server_class_init (GNotificationServerClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||||
|
|
||||||
|
object_class->set_property = g_notification_server_set_property;
|
||||||
|
object_class->get_property = g_notification_server_get_property;
|
||||||
|
object_class->constructed = g_notification_server_constructed;
|
||||||
|
object_class->dispose = g_notification_server_dispose;
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_IS_RUNNING,
|
||||||
|
g_param_spec_boolean ("is-running", "", "", FALSE,
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_BACKEND_NAME,
|
||||||
|
g_param_spec_string ("backend-name", "", "", NULL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class, PROP_BACKEND_VERSION,
|
||||||
|
g_param_spec_uint ("backend-version", "", "", 0, G_MAXUINT32, 0,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_signal_new ("notification-received", G_TYPE_NOTIFICATION_SERVER, G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 3,
|
||||||
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_VARIANT);
|
||||||
|
|
||||||
|
g_signal_new ("notification-removed", G_TYPE_NOTIFICATION_SERVER, G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_STRING, G_TYPE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_notification_server_init (GNotificationServer *server)
|
||||||
|
{
|
||||||
|
server->applications = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
g_free, (GDestroyNotify) g_hash_table_unref);
|
||||||
|
|
||||||
|
server->unix_fd_lists = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
(GDestroyNotify) g_variant_unref,
|
||||||
|
(GDestroyNotify) g_object_unref);
|
||||||
|
server->backend_version = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GNotificationServer *
|
||||||
|
g_notification_server_new (const gchar *backend_name,
|
||||||
|
guint backend_version)
|
||||||
|
{
|
||||||
|
return g_object_new (G_TYPE_NOTIFICATION_SERVER,
|
||||||
|
"backend-name", backend_name,
|
||||||
|
"backend-version", backend_version,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -321,6 +521,16 @@ g_notification_server_list_applications (GNotificationServer *server)
|
|||||||
return (gchar **) g_hash_table_get_keys_as_array (server->applications, NULL);
|
return (gchar **) g_hash_table_get_keys_as_array (server->applications, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUnixFDList *
|
||||||
|
g_notification_server_get_unix_fd_list_for_notification (GNotificationServer *server,
|
||||||
|
GVariant *notification)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (G_IS_NOTIFICATION_SERVER (server), NULL);
|
||||||
|
g_return_val_if_fail (notification != NULL, NULL);
|
||||||
|
|
||||||
|
return g_hash_table_lookup (server->unix_fd_lists, notification);
|
||||||
|
}
|
||||||
|
|
||||||
gchar **
|
gchar **
|
||||||
g_notification_server_list_notifications (GNotificationServer *server,
|
g_notification_server_list_notifications (GNotificationServer *server,
|
||||||
const gchar *app_id)
|
const gchar *app_id)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define __G_NOTIFICATION_SERVER_H__
|
#define __G_NOTIFICATION_SERVER_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <gio/gunixfdlist.h>
|
||||||
|
|
||||||
#define G_TYPE_NOTIFICATION_SERVER (g_notification_server_get_type ())
|
#define G_TYPE_NOTIFICATION_SERVER (g_notification_server_get_type ())
|
||||||
#define G_NOTIFICATION_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NOTIFICATION_SERVER, GNotificationServer))
|
#define G_NOTIFICATION_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NOTIFICATION_SERVER, GNotificationServer))
|
||||||
@ -32,12 +33,15 @@ typedef struct _GNotificationServer GNotificationServer;
|
|||||||
|
|
||||||
GType g_notification_server_get_type (void);
|
GType g_notification_server_get_type (void);
|
||||||
|
|
||||||
GNotificationServer * g_notification_server_new (void);
|
GNotificationServer * g_notification_server_new (const gchar *backend_name,
|
||||||
|
guint backend_version);
|
||||||
|
|
||||||
void g_notification_server_stop (GNotificationServer *server);
|
void g_notification_server_stop (GNotificationServer *server);
|
||||||
|
|
||||||
gboolean g_notification_server_get_is_running (GNotificationServer *server);
|
gboolean g_notification_server_get_is_running (GNotificationServer *server);
|
||||||
|
|
||||||
|
GUnixFDList * g_notification_server_get_unix_fd_list_for_notification (GNotificationServer *server,
|
||||||
|
GVariant *notification);
|
||||||
gchar ** g_notification_server_list_applications (GNotificationServer *server);
|
gchar ** g_notification_server_list_applications (GNotificationServer *server);
|
||||||
|
|
||||||
gchar ** g_notification_server_list_notifications (GNotificationServer *server,
|
gchar ** g_notification_server_list_notifications (GNotificationServer *server,
|
||||||
|
@ -148,7 +148,7 @@ basic (void)
|
|||||||
|
|
||||||
loop = g_main_loop_new (NULL, FALSE);
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
server = g_notification_server_new ();
|
server = g_notification_server_new ("gtk", 1);
|
||||||
g_signal_connect (server, "notification-received", G_CALLBACK (notification_received), &received_count);
|
g_signal_connect (server, "notification-received", G_CALLBACK (notification_received), &received_count);
|
||||||
g_signal_connect (server, "notification-removed", G_CALLBACK (notification_removed), &removed_count);
|
g_signal_connect (server, "notification-removed", G_CALLBACK (notification_removed), &removed_count);
|
||||||
g_signal_connect (server, "notify::is-running", G_CALLBACK (server_notify_is_running), loop);
|
g_signal_connect (server, "notify::is-running", G_CALLBACK (server_notify_is_running), loop);
|
||||||
|
@ -528,6 +528,9 @@ if host_machine.system() != 'windows'
|
|||||||
'gnotification' : {
|
'gnotification' : {
|
||||||
'extra_sources' : [extra_sources, 'gnotification-server.c'],
|
'extra_sources' : [extra_sources, 'gnotification-server.c'],
|
||||||
},
|
},
|
||||||
|
'portal-notification-backend' : {
|
||||||
|
'extra_sources' : [extra_sources, 'gnotification-server.c'],
|
||||||
|
},
|
||||||
'gdbus-test-codegen-old' : {
|
'gdbus-test-codegen-old' : {
|
||||||
'source' : 'gdbus-test-codegen.c',
|
'source' : 'gdbus-test-codegen.c',
|
||||||
'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info],
|
'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info],
|
||||||
|
598
gio/tests/portal-notification-backend.c
Normal file
598
gio/tests/portal-notification-backend.c
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 Lars Uebernickel
|
||||||
|
* Copyright © 2024 GNOME Foundation Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*
|
||||||
|
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authors: Lars Uebernickel <lars@uebernic.de>
|
||||||
|
* Julian Sparber <jsparber@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gio/gunixfdlist.h>
|
||||||
|
|
||||||
|
#include "gnotification-server.h"
|
||||||
|
#include "gdbus-sessionbus.h"
|
||||||
|
|
||||||
|
#define TEST_DATA "some test data"
|
||||||
|
|
||||||
|
struct _GNotification
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
gchar *title;
|
||||||
|
gchar *body;
|
||||||
|
gchar *markup_body;
|
||||||
|
GIcon *icon;
|
||||||
|
GNotificationSound *sound;
|
||||||
|
GNotificationPriority priority;
|
||||||
|
gchar *category;
|
||||||
|
GNotificationDisplayHintFlags display_hint;
|
||||||
|
GPtrArray *buttons;
|
||||||
|
gchar *default_action;
|
||||||
|
GVariant *default_action_target;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SOUND_TYPE_DEFAULT,
|
||||||
|
SOUND_TYPE_FILE,
|
||||||
|
SOUND_TYPE_BYTES,
|
||||||
|
SOUND_TYPE_CUSTOM,
|
||||||
|
} SoundType;
|
||||||
|
|
||||||
|
struct _GNotificationSound
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
SoundType sound_type;
|
||||||
|
union {
|
||||||
|
GFile *file;
|
||||||
|
GBytes *bytes;
|
||||||
|
struct {
|
||||||
|
gchar *action;
|
||||||
|
GVariant *target;
|
||||||
|
} custom;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar *label;
|
||||||
|
gchar *purpose;
|
||||||
|
gchar *action_name;
|
||||||
|
GVariant *target;
|
||||||
|
} Button;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar *id;
|
||||||
|
GNotification *notification;
|
||||||
|
GMainLoop *loop;
|
||||||
|
} TestData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_data_free (gpointer pointer)
|
||||||
|
{
|
||||||
|
TestData *data = pointer;
|
||||||
|
|
||||||
|
g_clear_pointer (&data->id, g_free);
|
||||||
|
g_clear_object (&data->notification);
|
||||||
|
g_main_loop_unref (data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_and_wait (TestData *data,
|
||||||
|
GApplication *application,
|
||||||
|
const gchar *id,
|
||||||
|
GNotification *notification)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&data->id, g_free);
|
||||||
|
data->id = g_strdup (id);
|
||||||
|
g_set_object (&data->notification, notification);
|
||||||
|
|
||||||
|
g_application_send_notification (application, id, notification);
|
||||||
|
|
||||||
|
while (g_main_context_iteration (g_main_loop_get_context (data->loop), TRUE))
|
||||||
|
{
|
||||||
|
if (data->id == NULL && data->notification == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_and_wait_finish (TestData *data)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&data->id, g_free);
|
||||||
|
g_clear_object (&data->notification);
|
||||||
|
|
||||||
|
g_main_context_wakeup (g_main_loop_get_context (data->loop));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GFile *
|
||||||
|
get_test_file (void) {
|
||||||
|
GFile *file = NULL;
|
||||||
|
g_autoptr(GFileIOStream) iostream = NULL;
|
||||||
|
GOutputStream *stream = NULL;
|
||||||
|
|
||||||
|
file = g_file_new_tmp ("notification-testXXXXXX", &iostream, NULL);
|
||||||
|
stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
|
||||||
|
g_output_stream_write_all (stream, TEST_DATA, strlen (TEST_DATA), NULL, NULL, NULL);
|
||||||
|
g_output_stream_close (stream, NULL, NULL);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_app (GApplication *application,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestData *data = user_data;
|
||||||
|
g_autoptr(GNotification) notification = NULL;
|
||||||
|
g_autoptr(GIcon) icon = NULL;
|
||||||
|
g_autoptr(GBytes) bytes = NULL;
|
||||||
|
g_autoptr(GNotificationSound) sound = NULL;
|
||||||
|
g_autoptr(GFile) file = NULL;
|
||||||
|
|
||||||
|
bytes = g_bytes_new_static (TEST_DATA, strlen (TEST_DATA));
|
||||||
|
file = get_test_file ();
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test");
|
||||||
|
send_and_wait (data, application, "test1", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test2");
|
||||||
|
send_and_wait (data, application, "test2", notification);
|
||||||
|
|
||||||
|
g_application_withdraw_notification (application, "test1");
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test3");
|
||||||
|
send_and_wait (data, application, "test3", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test4");
|
||||||
|
icon = g_themed_icon_new ("i-c-o-n");
|
||||||
|
g_notification_set_icon (notification, icon);
|
||||||
|
g_clear_object (&icon);
|
||||||
|
g_notification_set_body (notification, "body");
|
||||||
|
g_notification_set_body_with_markup (notification, "markup-body");
|
||||||
|
g_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_URGENT);
|
||||||
|
g_notification_set_default_action_and_target (notification, "app.action", "i", 42);
|
||||||
|
g_notification_add_button_with_purpose_and_target_value (notification,
|
||||||
|
"label",
|
||||||
|
"x-gnome.purpose",
|
||||||
|
"app.action2",
|
||||||
|
g_variant_new_string ("bla"));
|
||||||
|
g_notification_set_category (notification, "x-gnome.category");
|
||||||
|
g_notification_set_display_hint_flags (notification, G_NOTIFICATION_DISPLAY_HINT_TRANSIENT);
|
||||||
|
send_and_wait (data, application, "test4", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test5");
|
||||||
|
icon = g_file_icon_new (file);
|
||||||
|
g_notification_set_icon (notification, icon);
|
||||||
|
g_clear_object (&icon);
|
||||||
|
send_and_wait (data, application, "test5", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test6");
|
||||||
|
icon = g_bytes_icon_new (bytes);
|
||||||
|
g_notification_set_icon (notification, icon);
|
||||||
|
g_clear_object (&icon);
|
||||||
|
send_and_wait (data, application, "test6", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test7");
|
||||||
|
sound = g_notification_sound_new_default ();
|
||||||
|
g_notification_set_sound (notification, sound);
|
||||||
|
g_clear_object (&sound);
|
||||||
|
send_and_wait (data, application, "test7", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test8");
|
||||||
|
sound = g_notification_sound_new_from_file (file);
|
||||||
|
g_notification_set_sound (notification, sound);
|
||||||
|
g_clear_object (&sound);
|
||||||
|
send_and_wait (data, application, "test8", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test9");
|
||||||
|
sound = g_notification_sound_new_from_bytes (bytes);
|
||||||
|
g_notification_set_sound (notification, sound);
|
||||||
|
g_clear_object (&sound);
|
||||||
|
send_and_wait (data, application, "test9", notification);
|
||||||
|
|
||||||
|
notification = g_notification_new ("Test10");
|
||||||
|
sound = g_notification_sound_new_custom ("app.play-custom-sound", g_variant_new_string ("some target"));
|
||||||
|
g_notification_set_sound (notification, sound);
|
||||||
|
g_clear_object (&sound);
|
||||||
|
send_and_wait (data, application, "test10", notification);
|
||||||
|
|
||||||
|
send_and_wait (data, application, NULL, notification);
|
||||||
|
|
||||||
|
g_dbus_connection_flush_sync (g_application_get_dbus_connection (application), NULL, NULL);
|
||||||
|
|
||||||
|
g_assert_true (g_file_delete (file, NULL, NULL));
|
||||||
|
g_main_loop_quit (data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
notification_received (GNotificationServer *server,
|
||||||
|
const gchar *app_id,
|
||||||
|
const gchar *notification_id,
|
||||||
|
GVariant *notification,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
TestData *exp_data = user_data;
|
||||||
|
struct _GNotification *exp_notification;
|
||||||
|
|
||||||
|
g_assert_nonnull (exp_data);
|
||||||
|
exp_notification = (struct _GNotification *)exp_data->notification;
|
||||||
|
g_assert_nonnull (exp_notification);
|
||||||
|
|
||||||
|
if (exp_data->id)
|
||||||
|
g_assert_cmpstr (exp_data->id, ==, notification_id);
|
||||||
|
else
|
||||||
|
g_assert_true (g_dbus_is_guid (notification_id));
|
||||||
|
|
||||||
|
if (exp_notification->title)
|
||||||
|
{
|
||||||
|
const gchar *title;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "title", "&s", &title));
|
||||||
|
g_assert_cmpstr (title, ==, exp_notification->title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->body && !exp_notification->markup_body)
|
||||||
|
{
|
||||||
|
const gchar *body;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "body", "&s", &body));
|
||||||
|
g_assert_cmpstr (body, ==, exp_notification->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->markup_body)
|
||||||
|
{
|
||||||
|
const gchar *body;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "markup-body", "&s", &body));
|
||||||
|
g_assert_cmpstr (body, ==, exp_notification->markup_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->icon)
|
||||||
|
{
|
||||||
|
g_autoptr(GVariant) serialized_icon = NULL;
|
||||||
|
|
||||||
|
serialized_icon = g_variant_lookup_value (notification, "icon", NULL);
|
||||||
|
if (G_IS_THEMED_ICON (exp_notification->icon))
|
||||||
|
{
|
||||||
|
g_autoptr(GIcon) icon = NULL;
|
||||||
|
|
||||||
|
icon = g_icon_deserialize (serialized_icon);
|
||||||
|
g_assert_true (g_icon_equal (exp_notification->icon, icon));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GBytes) bytes = NULL;
|
||||||
|
g_autoptr(GBytes) exp_bytes = NULL;
|
||||||
|
GUnixFDList *fd_list;
|
||||||
|
int fd;
|
||||||
|
int fd_id;
|
||||||
|
gchar *key;
|
||||||
|
g_autoptr(GVariant) handle = NULL;
|
||||||
|
g_autoptr(GMappedFile) mapped = NULL;
|
||||||
|
|
||||||
|
g_assert_true (g_variant_is_of_type (serialized_icon, G_VARIANT_TYPE("(sv)")));
|
||||||
|
g_variant_get (serialized_icon, "(&sv)", &key, &handle);
|
||||||
|
g_assert_cmpstr (key, ==, "file-descriptor");
|
||||||
|
|
||||||
|
fd_list = g_notification_server_get_unix_fd_list_for_notification (server, notification);
|
||||||
|
g_assert_nonnull (fd_list);
|
||||||
|
fd_id = g_variant_get_handle (handle);
|
||||||
|
fd = g_unix_fd_list_get (fd_list, fd_id, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert_cmpint (fd, >, -1);
|
||||||
|
|
||||||
|
mapped = g_mapped_file_new_from_fd (fd, FALSE, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
bytes = g_mapped_file_get_bytes (mapped);
|
||||||
|
|
||||||
|
if (G_IS_BYTES_ICON (exp_notification->icon))
|
||||||
|
{
|
||||||
|
exp_bytes = g_bytes_ref (g_bytes_icon_get_bytes (G_BYTES_ICON (exp_notification->icon)));
|
||||||
|
}
|
||||||
|
else if (G_IS_FILE_ICON (exp_notification->icon))
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
|
||||||
|
file = g_file_icon_get_file (G_FILE_ICON (exp_notification->icon));
|
||||||
|
exp_bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
}
|
||||||
|
g_assert_true (g_bytes_equal (exp_bytes, bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->sound)
|
||||||
|
{
|
||||||
|
struct _GNotificationSound *exp_sound = (struct _GNotificationSound *)exp_notification->sound;
|
||||||
|
g_autoptr(GVariant) serialized_sound = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GBytes) bytes = NULL;
|
||||||
|
|
||||||
|
serialized_sound = g_variant_lookup_value (notification, "sound", NULL);
|
||||||
|
if (exp_sound->sound_type == SOUND_TYPE_FILE || exp_sound->sound_type == SOUND_TYPE_BYTES)
|
||||||
|
{
|
||||||
|
GUnixFDList *fd_list;
|
||||||
|
int fd;
|
||||||
|
int fd_id;
|
||||||
|
gchar *key;
|
||||||
|
g_autoptr(GVariant) handle = NULL;
|
||||||
|
g_autoptr(GMappedFile) mapped = NULL;
|
||||||
|
|
||||||
|
g_assert_true (g_variant_is_of_type (serialized_sound, G_VARIANT_TYPE("(sv)")));
|
||||||
|
g_variant_get (serialized_sound, "(&sv)", &key, &handle);
|
||||||
|
g_assert_cmpstr (key, ==, "file-descriptor");
|
||||||
|
|
||||||
|
fd_list = g_notification_server_get_unix_fd_list_for_notification (server, notification);
|
||||||
|
g_assert_nonnull (fd_list);
|
||||||
|
fd_id = g_variant_get_handle (handle);
|
||||||
|
fd = g_unix_fd_list_get (fd_list, fd_id, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert_cmpint (fd, >, -1);
|
||||||
|
|
||||||
|
mapped = g_mapped_file_new_from_fd (fd, FALSE, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
bytes = g_mapped_file_get_bytes (mapped);
|
||||||
|
}
|
||||||
|
else if (exp_sound->sound_type == SOUND_TYPE_DEFAULT)
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
|
||||||
|
g_assert_true (g_variant_is_of_type (serialized_sound, G_VARIANT_TYPE("s")));
|
||||||
|
key = g_variant_get_string (serialized_sound, NULL);
|
||||||
|
g_assert_cmpstr (key, ==, "default");
|
||||||
|
}
|
||||||
|
else if (exp_sound->sound_type == SOUND_TYPE_CUSTOM)
|
||||||
|
{
|
||||||
|
/* The portal uses a button with a specific purpose for custom sound action */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_sound->sound_type == SOUND_TYPE_FILE)
|
||||||
|
{
|
||||||
|
g_autoptr(GBytes) exp_bytes = NULL;
|
||||||
|
exp_bytes = g_file_load_bytes (exp_sound->file, NULL, NULL, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert_true (g_bytes_equal (exp_bytes, bytes));
|
||||||
|
}
|
||||||
|
else if (exp_sound->sound_type == SOUND_TYPE_BYTES)
|
||||||
|
{
|
||||||
|
g_assert_true (g_bytes_equal (exp_sound->bytes, bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
g_autoptr(GVariant) serialized_sound = NULL;
|
||||||
|
|
||||||
|
serialized_sound = g_variant_lookup_value (notification, "sound", NULL);
|
||||||
|
if (serialized_sound)
|
||||||
|
{
|
||||||
|
g_assert_true (g_variant_is_of_type (serialized_sound, G_VARIANT_TYPE("s")));
|
||||||
|
key = g_variant_get_string (serialized_sound, NULL);
|
||||||
|
|
||||||
|
g_assert_cmpstr (key, ==, "silent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->priority)
|
||||||
|
{
|
||||||
|
g_autoptr(GEnumClass) enum_class = NULL;
|
||||||
|
GEnumValue *enum_value;
|
||||||
|
const gchar *priority = NULL;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "priority", "&s", &priority));
|
||||||
|
|
||||||
|
enum_class = g_type_class_ref (G_TYPE_NOTIFICATION_PRIORITY);
|
||||||
|
g_assert_nonnull (enum_class);
|
||||||
|
enum_value = g_enum_get_value_by_nick (enum_class, priority);
|
||||||
|
g_assert_nonnull (enum_value);
|
||||||
|
|
||||||
|
g_assert_true ((GNotificationPriority) enum_value->value == exp_notification->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->display_hint)
|
||||||
|
{
|
||||||
|
g_autoptr(GFlagsClass) flags_class = NULL;
|
||||||
|
GNotificationDisplayHintFlags display_hint = G_NOTIFICATION_DISPLAY_HINT_UPDATE;
|
||||||
|
const gchar** flags = NULL;
|
||||||
|
gsize i;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "display-hint", "^a&s", &flags));
|
||||||
|
|
||||||
|
flags_class = g_type_class_ref (G_TYPE_NOTIFICATION_DISPLAY_HINT_FLAGS);
|
||||||
|
g_assert_nonnull (flags_class);
|
||||||
|
|
||||||
|
for (i = 0; flags[i]; i++)
|
||||||
|
{
|
||||||
|
GFlagsValue *flags_value;
|
||||||
|
|
||||||
|
if (g_strcmp0 (flags[i], "show-as-new") == 0)
|
||||||
|
{
|
||||||
|
display_hint &= ~G_NOTIFICATION_DISPLAY_HINT_UPDATE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags_value = g_flags_get_value_by_nick (flags_class, flags[i]);
|
||||||
|
g_assert_nonnull (flags_value);
|
||||||
|
display_hint |= flags_value->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_true (display_hint == exp_notification->display_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->category)
|
||||||
|
{
|
||||||
|
const gchar *category;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "category", "&s", &category));
|
||||||
|
g_assert_cmpstr (category, ==, exp_notification->category);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->default_action)
|
||||||
|
{
|
||||||
|
const gchar *default_action;
|
||||||
|
g_assert_true (g_variant_lookup (notification, "default-action", "&s", &default_action));
|
||||||
|
g_assert_cmpstr (default_action, ==, exp_notification->default_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_notification->default_action_target)
|
||||||
|
{
|
||||||
|
g_autoptr(GVariant) default_action_target = NULL;
|
||||||
|
default_action_target = g_variant_lookup_value (notification, "default-action-target", NULL);
|
||||||
|
g_assert_true (g_variant_equal (default_action_target, exp_notification->default_action_target));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom sound is a special system button for the portal
|
||||||
|
if ((exp_notification->buttons && exp_notification->buttons->len > 0) ||
|
||||||
|
(exp_notification->sound && exp_notification->sound->sound_type == SOUND_TYPE_CUSTOM))
|
||||||
|
{
|
||||||
|
gsize i;
|
||||||
|
g_autoptr(GVariant) buttons = NULL;
|
||||||
|
buttons = g_variant_lookup_value (notification, "buttons", G_VARIANT_TYPE("aa{sv}"));
|
||||||
|
g_assert_nonnull (buttons);
|
||||||
|
|
||||||
|
for (i = 0; i < g_variant_n_children (buttons); i++)
|
||||||
|
{
|
||||||
|
Button *exp_button;
|
||||||
|
g_autoptr(GVariant) button = NULL;
|
||||||
|
const gchar *label = NULL;
|
||||||
|
const gchar *purpose = NULL;
|
||||||
|
const gchar *action_name = NULL;
|
||||||
|
g_autoptr(GVariant) action_target = NULL;
|
||||||
|
|
||||||
|
button = g_variant_get_child_value (buttons, i);
|
||||||
|
g_assert_nonnull (button);
|
||||||
|
|
||||||
|
if (g_variant_lookup (button, "purpose", "&s", &purpose) &&
|
||||||
|
g_strcmp0 (purpose, "system.custom-alert") == 0)
|
||||||
|
{
|
||||||
|
g_assert_nonnull (exp_notification->sound);
|
||||||
|
g_assert_false (g_variant_lookup (button, "label", "&s", &label));
|
||||||
|
|
||||||
|
g_assert_true (g_variant_lookup (button, "action", "&s", &action_name));
|
||||||
|
g_assert_cmpstr (action_name, ==, exp_notification->sound->custom.action);
|
||||||
|
|
||||||
|
action_target = g_variant_lookup_value (button, "target", NULL);
|
||||||
|
g_assert_true (g_variant_equal (action_target, exp_notification->sound->custom.target));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
exp_button = (Button*)g_ptr_array_index (exp_notification->buttons, i);
|
||||||
|
g_assert_nonnull (exp_button);
|
||||||
|
|
||||||
|
if (exp_button->label)
|
||||||
|
{
|
||||||
|
g_assert_true (g_variant_lookup (button, "label", "&s", &label));
|
||||||
|
g_assert_cmpstr (label, ==, exp_button->label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_button->purpose)
|
||||||
|
{
|
||||||
|
g_assert_true (g_variant_lookup (button, "purpose", "&s", &purpose));
|
||||||
|
g_assert_cmpstr (purpose, ==, exp_button->purpose);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_button->action_name)
|
||||||
|
{
|
||||||
|
g_assert_true (g_variant_lookup (button, "action", "&s", &action_name));
|
||||||
|
g_assert_cmpstr (action_name, ==, exp_button->action_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
action_target = g_variant_lookup_value (button, "target", NULL);
|
||||||
|
g_assert_true (g_variant_equal (action_target, exp_button->target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_and_wait_finish (exp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
notification_removed (GNotificationServer *server,
|
||||||
|
const gchar *app_id,
|
||||||
|
const gchar *notification_id,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
gint *count = user_data;
|
||||||
|
|
||||||
|
g_assert_cmpstr (notification_id, ==, "test1");
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
server_notify_is_running (GObject *object,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GNotificationServer *server = G_NOTIFICATION_SERVER (object);
|
||||||
|
GApplication *app;
|
||||||
|
|
||||||
|
g_assert_true (g_notification_server_get_is_running (server));
|
||||||
|
|
||||||
|
app = g_application_new ("org.gtk.TestApplication", G_APPLICATION_DEFAULT_FLAGS);
|
||||||
|
g_signal_connect (app, "activate", G_CALLBACK (activate_app), user_data);
|
||||||
|
|
||||||
|
g_application_run (app, 0, NULL);
|
||||||
|
|
||||||
|
g_object_unref (app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
basic (void)
|
||||||
|
{
|
||||||
|
TestData *data;
|
||||||
|
GNotificationServer *server;
|
||||||
|
GMainLoop *loop;
|
||||||
|
gint removed_count = 0;
|
||||||
|
|
||||||
|
session_bus_up ();
|
||||||
|
|
||||||
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
data = g_new0 (TestData, 1);
|
||||||
|
data->loop = g_main_loop_ref (loop);
|
||||||
|
|
||||||
|
server = g_notification_server_new ("portal", 2);
|
||||||
|
g_signal_connect (server, "notification-received", G_CALLBACK (notification_received), data);
|
||||||
|
g_signal_connect (server, "notification-removed", G_CALLBACK (notification_removed), &removed_count);
|
||||||
|
g_signal_connect (server, "notify::is-running", G_CALLBACK (server_notify_is_running), data);
|
||||||
|
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
|
test_data_free (data);
|
||||||
|
|
||||||
|
g_assert_cmpint (removed_count, ==, 1);
|
||||||
|
|
||||||
|
g_object_unref (server);
|
||||||
|
g_main_loop_unref (loop);
|
||||||
|
session_bus_down ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_setenv ("GIO_USE_PORTALS", "1", TRUE);
|
||||||
|
|
||||||
|
g_test_add_func ("/portal-notification-backend/basic", basic);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user