LCOV - code coverage report
Current view: top level - src/libvalent/notifications - valent-notifications.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 79.8 % 119 95
Test Date: 2024-10-26 05:41:03 Functions: 93.8 % 16 15
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 40.5 % 74 30

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-notifications"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <gio/gio.h>
       9                 :             : #include <gio/gdesktopappinfo.h>
      10                 :             : #include <libpeas.h>
      11                 :             : #include <libvalent-core.h>
      12                 :             : 
      13                 :             : #include "valent-notification.h"
      14                 :             : #include "valent-notifications.h"
      15                 :             : #include "valent-notifications-adapter.h"
      16                 :             : 
      17                 :             : 
      18                 :             : /**
      19                 :             :  * ValentNotifications:
      20                 :             :  *
      21                 :             :  * A class for sending and receiving notifications.
      22                 :             :  *
      23                 :             :  * `ValentNotifications` is an aggregator of notifications, intended for use by
      24                 :             :  * [class@Valent.DevicePlugin] implementations.
      25                 :             :  *
      26                 :             :  * Plugins can implement [class@Valent.NotificationsAdapter] to provide an
      27                 :             :  * interface to monitor, send and withdraw notifications.
      28                 :             :  *
      29                 :             :  * Since: 1.0
      30                 :             :  */
      31                 :             : 
      32                 :             : struct _ValentNotifications
      33                 :             : {
      34                 :             :   ValentComponent  parent_instance;
      35                 :             : 
      36                 :             :   GVariant        *applications;
      37                 :             : };
      38                 :             : 
      39   [ +  +  +  - ]:         191 : G_DEFINE_FINAL_TYPE (ValentNotifications, valent_notifications, VALENT_TYPE_COMPONENT)
      40                 :             : 
      41                 :             : enum {
      42                 :             :   NOTIFICATION_ADDED,
      43                 :             :   NOTIFICATION_REMOVED,
      44                 :             :   N_SIGNALS
      45                 :             : };
      46                 :             : 
      47                 :             : static guint signals[N_SIGNALS] = { 0, };
      48                 :             : 
      49                 :             : 
      50                 :             : static ValentNotifications *default_listener = NULL;
      51                 :             : 
      52                 :             : 
      53                 :             : static GVariant *
      54                 :           0 : app_info_serialize (GAppInfo *info)
      55                 :             : {
      56                 :           0 :   GVariantDict dict;
      57                 :           0 :   const char *name;
      58                 :           0 :   GIcon *icon;
      59                 :             : 
      60   [ #  #  #  #  :           0 :   g_assert (G_IS_APP_INFO (info));
             #  #  #  # ]
      61                 :             : 
      62                 :           0 :   g_variant_dict_init (&dict, NULL);
      63                 :             : 
      64         [ #  # ]:           0 :   if ((name = g_app_info_get_display_name (info)) != NULL)
      65                 :           0 :     g_variant_dict_insert (&dict, "name", "s", name);
      66                 :             : 
      67         [ #  # ]:           0 :   if ((icon = g_app_info_get_icon (info)) != NULL)
      68                 :             :     {
      69                 :           0 :       g_autoptr (GVariant) iconv = NULL;
      70                 :             : 
      71                 :           0 :       iconv = g_icon_serialize (icon);
      72         [ #  # ]:           0 :       g_variant_dict_insert_value (&dict, "icon", iconv);
      73                 :             :     }
      74                 :             : 
      75                 :           0 :   return g_variant_dict_end (&dict);
      76                 :             : }
      77                 :             : 
      78                 :             : static GVariant *
      79                 :          11 : notification_serialize (ValentNotification *notification)
      80                 :             : {
      81                 :          11 :   GVariantDict dict;
      82                 :          11 :   const char *app_name;
      83                 :          11 :   GIcon *icon;
      84                 :             : 
      85                 :          11 :   g_variant_dict_init (&dict, NULL);
      86                 :             : 
      87         [ +  + ]:          11 :   if ((app_name = valent_notification_get_application (notification)) != NULL)
      88                 :           7 :     g_variant_dict_insert (&dict, "name", "s", app_name);
      89                 :             : 
      90         [ +  + ]:          11 :   if ((icon = valent_notification_get_icon (notification)) != NULL)
      91                 :             :     {
      92                 :          18 :       g_autoptr (GVariant) iconv = NULL;
      93                 :             : 
      94                 :           7 :       iconv = g_icon_serialize (icon);
      95         [ +  - ]:           7 :       g_variant_dict_insert_value (&dict, "icon", iconv);
      96                 :             :     }
      97                 :             : 
      98                 :          11 :   return g_variant_dict_end (&dict);
      99                 :             : }
     100                 :             : 
     101                 :             : static void
     102                 :           7 : query_applications (ValentNotifications *self)
     103                 :             : {
     104                 :           7 :   GVariantDict dict;
     105                 :          14 :   g_autolist (GAppInfo) infos = NULL;
     106                 :             : 
     107         [ +  - ]:           7 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     108                 :             : 
     109                 :           7 :   g_variant_dict_init (&dict, NULL);
     110                 :           7 :   infos = g_app_info_get_all ();
     111                 :             : 
     112         [ -  + ]:           7 :   for (const GList *iter = infos; iter; iter = iter->next)
     113                 :             :     {
     114                 :           0 :       const char *desktop_id;
     115                 :           0 :       const char *name;
     116                 :             : 
     117                 :           0 :       desktop_id = g_app_info_get_id (iter->data);
     118                 :             : 
     119   [ #  #  #  #  :           0 :       if G_UNLIKELY (g_str_has_prefix (desktop_id, APPLICATION_ID))
                   #  # ]
     120                 :           0 :         continue;
     121                 :             : 
     122         [ #  # ]:           0 :       if (!g_desktop_app_info_get_boolean (iter->data, "X-GNOME-UsesNotifications"))
     123                 :           0 :         continue;
     124                 :             : 
     125                 :           0 :       name = g_app_info_get_display_name (iter->data);
     126                 :           0 :       g_variant_dict_insert_value (&dict, name, app_info_serialize (iter->data));
     127                 :             :     }
     128                 :             : 
     129                 :           7 :   self->applications = g_variant_ref_sink (g_variant_dict_end (&dict));
     130                 :           7 : }
     131                 :             : 
     132                 :             : static void
     133                 :          11 : add_application (ValentNotifications *self,
     134                 :             :                  GVariant            *application)
     135                 :             : {
     136                 :          11 :   GVariantDict dict;
     137                 :          11 :   const char *name;
     138                 :             : 
     139         [ -  + ]:          11 :   if (self->applications == NULL)
     140                 :           0 :     query_applications (self);
     141                 :             : 
     142                 :          11 :   g_variant_dict_init (&dict, self->applications);
     143                 :             : 
     144         [ +  + ]:          11 :   if (g_variant_lookup (application, "name", "&s", &name))
     145                 :           7 :     g_variant_dict_insert_value (&dict, name, g_variant_ref_sink (application));
     146                 :          11 :   g_variant_unref (application);
     147                 :             : 
     148         [ +  - ]:          11 :   g_clear_pointer (&self->applications, g_variant_unref);
     149                 :          11 :   self->applications = g_variant_ref_sink (g_variant_dict_end (&dict));
     150                 :          11 : }
     151                 :             : 
     152                 :             : 
     153                 :             : /*
     154                 :             :  * ValentNotificationsAdapter Callbacks
     155                 :             :  */
     156                 :             : static void
     157                 :          11 : on_notification_added (ValentNotificationsAdapter *adapter,
     158                 :             :                        ValentNotification         *notification,
     159                 :             :                        ValentNotifications        *self)
     160                 :             : {
     161         [ +  - ]:          11 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     162         [ -  + ]:          11 :   g_assert (VALENT_IS_NOTIFICATION (notification));
     163         [ -  + ]:          11 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     164                 :             : 
     165                 :          11 :   add_application (self, notification_serialize (notification));
     166                 :             : 
     167                 :          11 :   g_signal_emit (G_OBJECT (self), signals [NOTIFICATION_ADDED], 0, notification);
     168                 :          11 : }
     169                 :             : 
     170                 :             : static void
     171                 :           6 : on_notification_removed (ValentNotificationsAdapter *adapter,
     172                 :             :                          const char                 *id,
     173                 :             :                          ValentNotifications        *self)
     174                 :             : {
     175         [ +  - ]:           6 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     176         [ -  + ]:           6 :   g_assert (id != NULL);
     177         [ -  + ]:           6 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     178                 :             : 
     179                 :           6 :   g_signal_emit (G_OBJECT (self), signals [NOTIFICATION_REMOVED], 0, id);
     180                 :           6 : }
     181                 :             : 
     182                 :             : 
     183                 :             : /*
     184                 :             :  * ValentComponent
     185                 :             :  */
     186                 :             : static void
     187                 :           7 : valent_notifications_bind_extension (ValentComponent *component,
     188                 :             :                                      GObject         *extension)
     189                 :             : {
     190                 :           7 :   ValentNotifications *self = VALENT_NOTIFICATIONS (component);
     191                 :           7 :   ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (extension);
     192                 :             : 
     193                 :           7 :   VALENT_ENTRY;
     194                 :             : 
     195         [ +  - ]:           7 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     196         [ -  + ]:           7 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     197                 :             : 
     198                 :           7 :   g_signal_connect_object (adapter,
     199                 :             :                            "notification-added",
     200                 :             :                            G_CALLBACK (on_notification_added),
     201                 :             :                            self, 0);
     202                 :             : 
     203                 :           7 :   g_signal_connect_object (adapter,
     204                 :             :                            "notification-removed",
     205                 :             :                            G_CALLBACK (on_notification_removed),
     206                 :             :                            self, 0);
     207                 :             : 
     208                 :           7 :   VALENT_EXIT;
     209                 :             : }
     210                 :             : 
     211                 :             : static void
     212                 :           5 : valent_notifications_unbind_extension (ValentComponent *component,
     213                 :             :                                        GObject         *extension)
     214                 :             : {
     215                 :           5 :   ValentNotifications *self = VALENT_NOTIFICATIONS (component);
     216                 :           5 :   ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (extension);
     217                 :             : 
     218         [ +  - ]:           5 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     219         [ -  + ]:           5 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     220                 :             : 
     221                 :           5 :   g_signal_handlers_disconnect_by_func (adapter, on_notification_added, self);
     222                 :           5 :   g_signal_handlers_disconnect_by_func (adapter, on_notification_removed, self);
     223                 :           5 : }
     224                 :             : 
     225                 :             : 
     226                 :             : /*
     227                 :             :  * GObject
     228                 :             :  */
     229                 :             : static void
     230                 :           5 : valent_notifications_finalize (GObject *object)
     231                 :             : {
     232                 :           5 :   ValentNotifications *self = VALENT_NOTIFICATIONS (object);
     233                 :             : 
     234         [ +  - ]:           5 :   g_clear_pointer (&self->applications, g_variant_unref);
     235                 :             : 
     236                 :           5 :   G_OBJECT_CLASS (valent_notifications_parent_class)->finalize (object);
     237                 :           5 : }
     238                 :             : 
     239                 :             : static void
     240                 :           6 : valent_notifications_class_init (ValentNotificationsClass *klass)
     241                 :             : {
     242                 :           6 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     243                 :           6 :   ValentComponentClass *component_class = VALENT_COMPONENT_CLASS (klass);
     244                 :             : 
     245                 :           6 :   object_class->finalize = valent_notifications_finalize;
     246                 :             : 
     247                 :           6 :   component_class->bind_extension = valent_notifications_bind_extension;
     248                 :           6 :   component_class->unbind_extension = valent_notifications_unbind_extension;
     249                 :             : 
     250                 :             :   /**
     251                 :             :    * ValentNotifications::notification-added:
     252                 :             :    * @notifications: a `ValentNotifications`
     253                 :             :    * @notification: a `ValentNotification`
     254                 :             :    *
     255                 :             :    * Emitted when a notification is added to a
     256                 :             :    * [class@Valent.NotificationsAdapter].
     257                 :             :    *
     258                 :             :    * Since: 1.0
     259                 :             :    */
     260                 :          12 :   signals [NOTIFICATION_ADDED] =
     261                 :           6 :     g_signal_new ("notification-added",
     262                 :             :                   G_TYPE_FROM_CLASS (klass),
     263                 :             :                   G_SIGNAL_RUN_FIRST,
     264                 :             :                   0,
     265                 :             :                   NULL, NULL,
     266                 :             :                   g_cclosure_marshal_VOID__OBJECT,
     267                 :             :                   G_TYPE_NONE, 1, VALENT_TYPE_NOTIFICATION);
     268                 :           6 :   g_signal_set_va_marshaller (signals [NOTIFICATION_ADDED],
     269                 :             :                               G_TYPE_FROM_CLASS (klass),
     270                 :             :                               g_cclosure_marshal_VOID__OBJECTv);
     271                 :             : 
     272                 :             :   /**
     273                 :             :    * ValentNotifications::notification-removed:
     274                 :             :    * @notifications: a `ValentNotifications`
     275                 :             :    * @id: a notification id
     276                 :             :    *
     277                 :             :    * Emitted when a notification is removed from a
     278                 :             :    * [class@Valent.NotificationsAdapter].
     279                 :             :    *
     280                 :             :    * Since: 1.0
     281                 :             :    */
     282                 :          12 :   signals [NOTIFICATION_REMOVED] =
     283                 :           6 :     g_signal_new ("notification-removed",
     284                 :             :                   G_TYPE_FROM_CLASS (klass),
     285                 :             :                   G_SIGNAL_RUN_FIRST,
     286                 :             :                   0,
     287                 :             :                   NULL, NULL,
     288                 :             :                   g_cclosure_marshal_VOID__STRING,
     289                 :             :                   G_TYPE_NONE, 1, G_TYPE_STRING);
     290                 :           6 :   g_signal_set_va_marshaller (signals [NOTIFICATION_REMOVED],
     291                 :             :                               G_TYPE_FROM_CLASS (klass),
     292                 :             :                               g_cclosure_marshal_VOID__STRINGv);
     293                 :           6 : }
     294                 :             : 
     295                 :             : static void
     296                 :           7 : valent_notifications_init (ValentNotifications *self)
     297                 :             : {
     298                 :           7 :   query_applications (self);
     299                 :           7 : }
     300                 :             : 
     301                 :             : /**
     302                 :             :  * valent_notifications_get_default:
     303                 :             :  *
     304                 :             :  * Get the default [class@Valent.Notifications].
     305                 :             :  *
     306                 :             :  * Returns: (transfer none) (not nullable): a `ValentNotifications`
     307                 :             :  *
     308                 :             :  * Since: 1.0
     309                 :             :  */
     310                 :             : ValentNotifications *
     311                 :          45 : valent_notifications_get_default (void)
     312                 :             : {
     313         [ +  + ]:          45 :   if (default_listener == NULL)
     314                 :             :     {
     315                 :           7 :       default_listener = g_object_new (VALENT_TYPE_NOTIFICATIONS,
     316                 :             :                                        "plugin-domain", "notifications",
     317                 :             :                                        "plugin-type",   VALENT_TYPE_NOTIFICATIONS_ADAPTER,
     318                 :             :                                        NULL);
     319                 :             : 
     320                 :           7 :       g_object_add_weak_pointer (G_OBJECT (default_listener),
     321                 :             :                                  (gpointer)&default_listener);
     322                 :             :     }
     323                 :             : 
     324                 :          45 :   return default_listener;
     325                 :             : }
     326                 :             : 
     327                 :             : /**
     328                 :             :  * valent_notifications_get_applications:
     329                 :             :  * @notifications: (nullable): a `ValentNotifications`
     330                 :             :  *
     331                 :             :  * Get a dictionary of applications that are known to send notifications.
     332                 :             :  *
     333                 :             :  * Returns: (transfer none): a `GVariant`
     334                 :             :  *
     335                 :             :  * Since: 1.0
     336                 :             :  */
     337                 :             : GVariant *
     338                 :           1 : valent_notifications_get_applications (ValentNotifications *notifications)
     339                 :             : {
     340   [ -  +  -  - ]:           1 :   g_return_val_if_fail (notifications == NULL || VALENT_IS_NOTIFICATIONS (notifications), NULL);
     341                 :             : 
     342         [ +  - ]:           1 :   if (notifications == NULL)
     343                 :           1 :       notifications = valent_notifications_get_default ();
     344                 :             : 
     345         [ -  + ]:           1 :   if (notifications->applications == NULL)
     346                 :           0 :     query_applications (notifications);
     347                 :             : 
     348                 :           1 :   return notifications->applications;
     349                 :             : }
     350                 :             : 
        

Generated by: LCOV version 2.0-1