LCOV - code coverage report
Current view: top level - src/libvalent/notifications - valent-notifications.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 72.6 % 106 77
Test Date: 2025-10-27 20:54:50 Functions: 85.7 % 14 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 44.3 % 70 31

             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                 :             : struct _ValentNotifications
      32                 :             : {
      33                 :             :   ValentComponent  parent_instance;
      34                 :             : 
      35                 :             :   GVariant        *applications;
      36                 :             : };
      37                 :             : 
      38   [ +  +  +  - ]:         163 : G_DEFINE_FINAL_TYPE (ValentNotifications, valent_notifications, VALENT_TYPE_COMPONENT)
      39                 :             : 
      40                 :             : static GVariant *
      41                 :           0 : app_info_serialize (GAppInfo *info)
      42                 :             : {
      43                 :           0 :   GVariantDict dict;
      44                 :           0 :   const char *name;
      45                 :           0 :   GIcon *icon;
      46                 :             : 
      47   [ #  #  #  #  :           0 :   g_assert (G_IS_APP_INFO (info));
             #  #  #  # ]
      48                 :             : 
      49                 :           0 :   g_variant_dict_init (&dict, NULL);
      50                 :             : 
      51         [ #  # ]:           0 :   if ((name = g_app_info_get_display_name (info)) != NULL)
      52                 :           0 :     g_variant_dict_insert (&dict, "name", "s", name);
      53                 :             : 
      54         [ #  # ]:           0 :   if ((icon = g_app_info_get_icon (info)) != NULL)
      55                 :             :     {
      56                 :           0 :       g_autoptr (GVariant) iconv = NULL;
      57                 :             : 
      58                 :           0 :       iconv = g_icon_serialize (icon);
      59         [ #  # ]:           0 :       g_variant_dict_insert_value (&dict, "icon", iconv);
      60                 :             :     }
      61                 :             : 
      62                 :           0 :   return g_variant_dict_end (&dict);
      63                 :             : }
      64                 :             : 
      65                 :             : static GVariant *
      66                 :           5 : notification_serialize (ValentNotification *notification)
      67                 :             : {
      68                 :           5 :   GVariantDict dict;
      69                 :           5 :   const char *app_name;
      70                 :           5 :   GIcon *icon;
      71                 :             : 
      72                 :           5 :   g_variant_dict_init (&dict, NULL);
      73                 :             : 
      74         [ +  + ]:           5 :   if ((app_name = valent_notification_get_application (notification)) != NULL)
      75                 :           4 :     g_variant_dict_insert (&dict, "name", "s", app_name);
      76                 :             : 
      77         [ +  + ]:           5 :   if ((icon = valent_notification_get_icon (notification)) != NULL)
      78                 :             :     {
      79                 :           8 :       g_autoptr (GVariant) iconv = NULL;
      80                 :             : 
      81                 :           3 :       iconv = g_icon_serialize (icon);
      82         [ +  - ]:           3 :       g_variant_dict_insert_value (&dict, "icon", iconv);
      83                 :             :     }
      84                 :             : 
      85                 :           5 :   return g_variant_dict_end (&dict);
      86                 :             : }
      87                 :             : 
      88                 :             : static void
      89                 :           4 : query_applications (ValentNotifications *self)
      90                 :             : {
      91                 :           4 :   GVariantDict dict;
      92                 :           8 :   g_autolist (GAppInfo) infos = NULL;
      93                 :             : 
      94         [ -  + ]:           4 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
      95                 :             : 
      96                 :           4 :   g_variant_dict_init (&dict, NULL);
      97                 :           4 :   infos = g_app_info_get_all ();
      98                 :             : 
      99         [ -  + ]:           4 :   for (const GList *iter = infos; iter; iter = iter->next)
     100                 :             :     {
     101                 :           0 :       const char *desktop_id;
     102                 :           0 :       const char *name;
     103                 :             : 
     104                 :           0 :       desktop_id = g_app_info_get_id (iter->data);
     105                 :             : 
     106   [ #  #  #  #  :           0 :       if G_UNLIKELY (g_str_has_prefix (desktop_id, APPLICATION_ID))
                   #  # ]
     107                 :           0 :         continue;
     108                 :             : 
     109         [ #  # ]:           0 :       if (!g_desktop_app_info_get_boolean (iter->data, "X-GNOME-UsesNotifications"))
     110                 :           0 :         continue;
     111                 :             : 
     112                 :           0 :       name = g_app_info_get_display_name (iter->data);
     113                 :           0 :       g_variant_dict_insert_value (&dict, name, app_info_serialize (iter->data));
     114                 :             :     }
     115                 :             : 
     116                 :           4 :   self->applications = g_variant_ref_sink (g_variant_dict_end (&dict));
     117                 :           4 : }
     118                 :             : 
     119                 :             : static void
     120                 :           5 : add_application (ValentNotifications *self,
     121                 :             :                  GVariant            *application)
     122                 :             : {
     123                 :           5 :   GVariantDict dict;
     124                 :           5 :   const char *name;
     125                 :             : 
     126         [ -  + ]:           5 :   if (self->applications == NULL)
     127                 :           0 :     query_applications (self);
     128                 :             : 
     129                 :           5 :   g_variant_dict_init (&dict, self->applications);
     130                 :             : 
     131         [ +  + ]:           5 :   if (g_variant_lookup (application, "name", "&s", &name))
     132                 :           4 :     g_variant_dict_insert_value (&dict, name, g_variant_ref_sink (application));
     133                 :           5 :   g_variant_unref (application);
     134                 :             : 
     135         [ +  - ]:           5 :   g_clear_pointer (&self->applications, g_variant_unref);
     136                 :           5 :   self->applications = g_variant_ref_sink (g_variant_dict_end (&dict));
     137                 :           5 : }
     138                 :             : 
     139                 :             : static void
     140                 :           6 : on_items_changed (GListModel          *list,
     141                 :             :                   unsigned int         position,
     142                 :             :                   unsigned int         removed,
     143                 :             :                   unsigned int         added,
     144                 :             :                   ValentNotifications *self)
     145                 :             : {
     146         [ -  + ]:           6 :   g_assert (G_IS_LIST_MODEL (list));
     147         [ +  - ]:           6 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     148                 :             : 
     149         [ +  + ]:          11 :   for (unsigned int i = 0; i < added; i++)
     150                 :             :     {
     151                 :           5 :       g_autoptr (ValentNotification) notification = NULL;
     152                 :             : 
     153                 :           5 :       notification = g_list_model_get_item (list, position + i);
     154         [ +  - ]:           5 :       add_application (self, notification_serialize (notification));
     155                 :             :     }
     156                 :           6 : }
     157                 :             : 
     158                 :             : /*
     159                 :             :  * ValentComponent
     160                 :             :  */
     161                 :             : static void
     162                 :           5 : valent_notifications_bind_extension (ValentComponent *component,
     163                 :             :                                      ValentExtension *extension)
     164                 :             : {
     165                 :           5 :   ValentNotifications *self = VALENT_NOTIFICATIONS (component);
     166                 :           5 :   ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (extension);
     167                 :             : 
     168                 :           5 :   VALENT_ENTRY;
     169                 :             : 
     170         [ -  + ]:           5 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     171         [ +  - ]:           5 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     172                 :             : 
     173                 :           5 :   g_signal_connect_object (adapter,
     174                 :             :                            "items-changed",
     175                 :             :                            G_CALLBACK (on_items_changed),
     176                 :             :                            self,
     177                 :             :                            G_CONNECT_DEFAULT);
     178                 :             : 
     179                 :           5 :   VALENT_EXIT;
     180                 :             : }
     181                 :             : 
     182                 :             : static void
     183                 :           2 : valent_notifications_unbind_extension (ValentComponent *component,
     184                 :             :                                        ValentExtension *extension)
     185                 :             : {
     186                 :           2 :   ValentNotifications *self = VALENT_NOTIFICATIONS (component);
     187                 :           2 :   ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (extension);
     188                 :             : 
     189         [ -  + ]:           2 :   g_assert (VALENT_IS_NOTIFICATIONS (self));
     190         [ +  - ]:           2 :   g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
     191                 :             : 
     192                 :           2 :   g_signal_handlers_disconnect_by_func (adapter, on_items_changed, self);
     193                 :           2 : }
     194                 :             : 
     195                 :             : 
     196                 :             : /*
     197                 :             :  * GObject
     198                 :             :  */
     199                 :             : static void
     200                 :           0 : valent_notifications_finalize (GObject *object)
     201                 :             : {
     202                 :           0 :   ValentNotifications *self = VALENT_NOTIFICATIONS (object);
     203                 :             : 
     204         [ #  # ]:           0 :   g_clear_pointer (&self->applications, g_variant_unref);
     205                 :             : 
     206                 :           0 :   G_OBJECT_CLASS (valent_notifications_parent_class)->finalize (object);
     207                 :           0 : }
     208                 :             : 
     209                 :             : static void
     210                 :           5 : valent_notifications_class_init (ValentNotificationsClass *klass)
     211                 :             : {
     212                 :           5 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     213                 :           5 :   ValentComponentClass *component_class = VALENT_COMPONENT_CLASS (klass);
     214                 :             : 
     215                 :           5 :   object_class->finalize = valent_notifications_finalize;
     216                 :             : 
     217                 :           5 :   component_class->bind_extension = valent_notifications_bind_extension;
     218                 :           5 :   component_class->unbind_extension = valent_notifications_unbind_extension;
     219                 :             : }
     220                 :             : 
     221                 :             : static void
     222                 :           4 : valent_notifications_init (ValentNotifications *self)
     223                 :             : {
     224                 :           4 :   query_applications (self);
     225                 :           4 : }
     226                 :             : 
     227                 :             : /**
     228                 :             :  * valent_notifications_get_default:
     229                 :             :  *
     230                 :             :  * Get the default [class@Valent.Notifications].
     231                 :             :  *
     232                 :             :  * Returns: (transfer none) (not nullable): a `ValentNotifications`
     233                 :             :  *
     234                 :             :  * Since: 1.0
     235                 :             :  */
     236                 :             : ValentNotifications *
     237                 :          33 : valent_notifications_get_default (void)
     238                 :             : {
     239                 :          33 :   static ValentNotifications *default_instance = NULL;
     240                 :             : 
     241         [ +  + ]:          33 :   if (default_instance == NULL)
     242                 :             :     {
     243                 :           4 :       default_instance = g_object_new (VALENT_TYPE_NOTIFICATIONS,
     244                 :             :                                        "plugin-domain", "notifications",
     245                 :             :                                        "plugin-type",   VALENT_TYPE_NOTIFICATIONS_ADAPTER,
     246                 :             :                                        NULL);
     247                 :           4 :       g_object_add_weak_pointer (G_OBJECT (default_instance),
     248                 :             :                                  (gpointer)&default_instance);
     249                 :             :     }
     250                 :             : 
     251                 :          33 :   return default_instance;
     252                 :             : }
     253                 :             : 
     254                 :             : /**
     255                 :             :  * valent_notifications_get_applications:
     256                 :             :  * @notifications: (nullable): a `ValentNotifications`
     257                 :             :  *
     258                 :             :  * Get a dictionary of applications that are known to send notifications.
     259                 :             :  *
     260                 :             :  * Returns: (transfer none): a `GVariant`
     261                 :             :  *
     262                 :             :  * Since: 1.0
     263                 :             :  */
     264                 :             : GVariant *
     265                 :           4 : valent_notifications_get_applications (ValentNotifications *notifications)
     266                 :             : {
     267   [ +  +  -  + ]:           4 :   g_return_val_if_fail (notifications == NULL || VALENT_IS_NOTIFICATIONS (notifications), NULL);
     268                 :             : 
     269         [ +  + ]:           4 :   if (notifications == NULL)
     270                 :           3 :       notifications = valent_notifications_get_default ();
     271                 :             : 
     272         [ -  + ]:           4 :   if (notifications->applications == NULL)
     273                 :           0 :     query_applications (notifications);
     274                 :             : 
     275                 :           4 :   return notifications->applications;
     276                 :             : }
     277                 :             : 
        

Generated by: LCOV version 2.0-1