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

Generated by: LCOV version 2.0-1