LCOV - code coverage report
Current view: top level - src/plugins/notification - valent-notification-upload.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 76.6 % 273 209
Test Date: 2025-10-09 19:29:51 Functions: 91.3 % 23 21
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 41.6 % 214 89

             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-notification-upload"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <gio/gio.h>
       9                 :             : #include <json-glib/json-glib.h>
      10                 :             : #include <valent.h>
      11                 :             : 
      12                 :             : #ifdef HAVE_GLYCIN
      13                 :             : #include <glycin.h>
      14                 :             : #endif /* HAVE_GLYCIN */
      15                 :             : #ifdef HAVE_GTK4
      16                 :             : #include <gtk/gtk.h>
      17                 :             : #endif /* HAVE_GTK4 */
      18                 :             : 
      19                 :             : #include "valent-notification-upload.h"
      20                 :             : 
      21                 :             : #define DEFAULT_ICON_SIZE 512
      22                 :             : 
      23                 :             : 
      24                 :             : /**
      25                 :             :  * ValentNotificationUpload:
      26                 :             :  *
      27                 :             :  * A class for notification icon uploads.
      28                 :             :  *
      29                 :             :  * `ValentNotificationUpload` is a class that abstracts uploading notifications
      30                 :             :  * with icon payloads for `ValentNotificationPlugin`.
      31                 :             :  */
      32                 :             : 
      33                 :             : struct _ValentNotificationUpload
      34                 :             : {
      35                 :             :   ValentTransfer  parent_instance;
      36                 :             : 
      37                 :             :   ValentDevice   *device;
      38                 :             :   JsonNode       *packet;
      39                 :             :   GIcon          *icon;
      40                 :             : };
      41                 :             : 
      42   [ +  +  +  - ]:          10 : G_DEFINE_FINAL_TYPE (ValentNotificationUpload, valent_notification_upload, VALENT_TYPE_TRANSFER)
      43                 :             : 
      44                 :             : typedef enum {
      45                 :             :   PROP_DEVICE = 1,
      46                 :             :   PROP_ICON,
      47                 :             :   PROP_PACKET,
      48                 :             : } ValentNotificationUploadProperty;
      49                 :             : 
      50                 :             : static GParamSpec *properties[PROP_PACKET + 1] = { NULL, };
      51                 :             : 
      52                 :             : static ValentChannel *
      53                 :           0 : _valent_device_next_channel (ValentDevice  *device,
      54                 :             :                              ValentChannel *channel)
      55                 :             : {
      56                 :           0 :   GListModel *channels = NULL;
      57                 :           0 :   unsigned int n_items = 0;
      58                 :             : 
      59                 :           0 :   channels = valent_device_get_channels (device);
      60                 :           0 :   n_items = g_list_model_get_n_items (channels);
      61         [ #  # ]:           0 :   for (unsigned int i = 0; i < n_items; i++)
      62                 :             :     {
      63                 :           0 :       g_autoptr (ValentChannel) next = NULL;
      64                 :             : 
      65                 :           0 :       next = g_list_model_get_item (channels, i);
      66         [ #  # ]:           0 :       if (next != channel)
      67                 :             :         return g_steal_pointer (&next);
      68                 :             :     }
      69                 :             : 
      70                 :             :   return NULL;
      71                 :             : }
      72                 :             : 
      73                 :             : /*
      74                 :             :  * GtkIconTheme Helpers
      75                 :             :  */
      76                 :             : #ifdef HAVE_GTK4
      77                 :             : static GtkIconTheme *
      78                 :           2 : _gtk_icon_theme_get_default (void)
      79                 :             : {
      80                 :           2 :   static GtkIconTheme *icon_theme = NULL;
      81                 :           2 :   size_t guard = 0;
      82                 :             : 
      83   [ +  -  +  - ]:           2 :   if (g_once_init_enter (&guard))
      84                 :             :     {
      85         [ +  - ]:           2 :       if (gtk_is_initialized ())
      86                 :             :         {
      87                 :           2 :           GdkDisplay *display = NULL;
      88                 :             : 
      89                 :           2 :           display = gdk_display_get_default ();
      90         [ +  - ]:           2 :           if (display != NULL)
      91                 :           2 :             icon_theme = gtk_icon_theme_get_for_display (display);
      92                 :             :         }
      93                 :             : 
      94                 :           2 :       g_once_init_leave (&guard, 1);
      95                 :             :     }
      96                 :             : 
      97                 :           2 :   return icon_theme;
      98                 :             : }
      99                 :             : 
     100                 :             : static int
     101                 :           2 : _gtk_icon_theme_get_largest_size (GtkIconTheme *theme,
     102                 :             :                                   const char   *name)
     103                 :             : {
     104                 :           4 :   g_autofree int *sizes = NULL;
     105                 :           2 :   int ret = 0;
     106                 :             : 
     107   [ +  -  +  -  :           2 :   g_assert (GTK_IS_ICON_THEME (theme));
             -  +  -  - ]
     108         [ +  - ]:           2 :   g_assert (name != NULL);
     109                 :             : 
     110         [ +  - ]:           2 :   if (!gtk_icon_theme_has_icon (theme, name))
     111                 :             :     return ret;
     112                 :             : 
     113                 :           2 :   sizes = gtk_icon_theme_get_icon_sizes (theme, name);
     114         [ +  - ]:           2 :   for (unsigned int i = 0; sizes[i] != 0; i++)
     115                 :             :     {
     116         [ -  + ]:           2 :       if (sizes[i] == -1)
     117                 :             :         return -1;
     118                 :             : 
     119                 :           0 :       if (sizes[i] > ret)
     120                 :             :         ret = sizes[i];
     121                 :             :     }
     122                 :             : 
     123                 :             :   return ret;
     124                 :             : }
     125                 :             : 
     126                 :             : static GFile *
     127                 :           2 : _gtk_icon_theme_get_largest_file (GIcon   *icon,
     128                 :             :                                   GError **error)
     129                 :             : {
     130                 :           2 :   GtkIconTheme *icon_theme = NULL;
     131                 :           2 :   const char * const *names;
     132                 :             : 
     133   [ +  -  +  -  :           2 :   g_assert (G_IS_THEMED_ICON (icon));
             -  +  -  - ]
     134                 :             : 
     135                 :           2 :   icon_theme = _gtk_icon_theme_get_default ();
     136         [ -  + ]:           2 :   if (icon_theme == NULL)
     137                 :             :     {
     138                 :           0 :       g_set_error_literal (error,
     139                 :             :                            G_IO_ERROR,
     140                 :             :                            G_IO_ERROR_NOT_SUPPORTED,
     141                 :             :                            "Failed to load icon theme");
     142                 :           0 :       return NULL;
     143                 :             :     }
     144                 :             : 
     145                 :           2 :   names = g_themed_icon_get_names (G_THEMED_ICON (icon));
     146         [ +  - ]:           2 :   for (size_t i = 0; names[i]; i++)
     147                 :             :     {
     148                 :           2 :       g_autoptr (GtkIconPaintable) paintable = NULL;
     149                 :           2 :       int size;
     150                 :             : 
     151                 :           2 :       size = _gtk_icon_theme_get_largest_size (icon_theme, names[i]);
     152         [ -  + ]:           2 :       if (size == 0)
     153                 :           0 :         continue;
     154                 :             : 
     155                 :           2 :       paintable = gtk_icon_theme_lookup_icon (icon_theme,
     156                 :             :                                               names[i],
     157                 :             :                                               NULL,
     158                 :             :                                               size,
     159                 :             :                                               1,
     160                 :             :                                               GTK_TEXT_DIR_NONE,
     161                 :             :                                               0);
     162         [ +  - ]:           2 :       if (paintable != NULL)
     163                 :             :         {
     164                 :           2 :           g_autoptr (GFile) ret = NULL;
     165                 :             : 
     166                 :           2 :           ret = gtk_icon_paintable_get_file (paintable);
     167         [ +  - ]:           2 :           if (ret != NULL)
     168                 :           2 :             return g_steal_pointer (&ret);
     169                 :             :         }
     170                 :             :     }
     171                 :             : 
     172                 :           0 :   g_set_error_literal (error,
     173                 :             :                        G_IO_ERROR,
     174                 :             :                        G_IO_ERROR_NOT_FOUND,
     175                 :             :                        "Failed to find icon");
     176                 :           0 :   return NULL;
     177                 :             : }
     178                 :             : #endif /* HAVE_GTK4 */
     179                 :             : 
     180                 :             : /*
     181                 :             :  * Glycin Helpers
     182                 :             :  */
     183                 :             : #ifdef HAVE_GLYCIN
     184                 :             : static void
     185                 :           4 : _glycin_encode_icon_bytes_task (GTask        *task,
     186                 :             :                                 gpointer      source_object,
     187                 :             :                                 gpointer      task_data,
     188                 :             :                                 GCancellable *cancellable)
     189                 :             : {
     190                 :           4 :   GBytes *bytes = (GBytes *)task_data;
     191                 :           4 :   g_autoptr (GlyLoader) loader = NULL;
     192   [ +  -  -  - ]:           4 :   g_autoptr (GlyImage) image = NULL;
     193                 :           4 :   const char *mime_type = NULL;
     194                 :           4 :   GError *error = NULL;
     195                 :             : 
     196                 :             :   /* Attempt to load the image data
     197                 :             :    */
     198                 :           4 :   loader = gly_loader_new_for_bytes (bytes);
     199                 :           4 :   image = gly_loader_load (loader, &error);
     200         [ -  + ]:           4 :   if (image == NULL)
     201                 :             :     {
     202                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
     203                 :           0 :       return;
     204                 :             :     }
     205                 :             : 
     206                 :             :   /* Attempt to convert the image data
     207                 :             :    *
     208                 :             :    * NOTE: kdeconnect-android only seems to accept PNG/JPEG
     209                 :             :    */
     210                 :           4 :   mime_type = gly_image_get_mime_type (image);
     211   [ +  -  +  + ]:           8 :   if (g_strcmp0 (mime_type, "image/jpeg") != 0 &&
     212                 :           4 :       g_strcmp0 (mime_type, "image/png") != 0)
     213                 :             :     {
     214         [ -  - ]:           4 :       g_autoptr (GlyFrameRequest) request = NULL;
     215   [ +  -  -  - ]:           2 :       g_autoptr (GlyFrame) frame = NULL;
     216         [ -  - ]:           2 :       g_autoptr (GlyCreator) creator = NULL;
     217         [ -  - ]:           2 :       g_autoptr (GlyNewFrame) new_frame = NULL;
     218         [ -  - ]:           2 :       g_autoptr (GlyEncodedImage) encoded_image = NULL;
     219                 :             : 
     220                 :             :       /* Attempt to resize the icon
     221                 :             :        */
     222                 :           2 :       request = gly_frame_request_new ();
     223                 :           2 :       gly_frame_request_set_scale (request, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
     224                 :           2 :       frame = gly_image_get_specific_frame (image, request, &error);
     225         [ -  + ]:           2 :       if (frame == NULL)
     226                 :             :         {
     227                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     228                 :           0 :           return;
     229                 :             :         }
     230                 :             : 
     231                 :           2 :       creator = gly_creator_new ("image/png", &error);
     232         [ -  + ]:           2 :       if (creator == NULL)
     233                 :             :         {
     234                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     235                 :           0 :           return;
     236                 :             :         }
     237                 :             : 
     238                 :           2 :       new_frame = gly_creator_add_frame_with_stride (creator,
     239                 :             :                                                      gly_frame_get_width (frame),
     240                 :             :                                                      gly_frame_get_height (frame),
     241                 :             :                                                      gly_frame_get_stride (frame),
     242                 :             :                                                      gly_frame_get_memory_format (frame),
     243                 :             :                                                      gly_frame_get_buf_bytes (frame),
     244                 :             :                                                      &error);
     245         [ -  + ]:           2 :       if (new_frame == NULL)
     246                 :             :         {
     247                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     248                 :           0 :           return;
     249                 :             :         }
     250                 :             : 
     251                 :           2 :       encoded_image = gly_creator_create (creator, &error);
     252         [ -  + ]:           2 :       if (encoded_image == NULL)
     253                 :             :         {
     254                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     255                 :           0 :           return;
     256                 :             :         }
     257                 :             : 
     258                 :           2 :       g_task_return_pointer (task,
     259                 :           2 :                              gly_encoded_image_get_data (encoded_image),
     260                 :             :                              (GDestroyNotify)g_bytes_unref);
     261                 :             :     }
     262                 :             :   else
     263                 :             :     {
     264                 :           2 :       g_task_return_pointer (task,
     265                 :           2 :                              g_bytes_ref (bytes),
     266                 :             :                              (GDestroyNotify)g_bytes_unref);
     267                 :             :     }
     268                 :             : }
     269                 :             : #endif /* HAVE_GLYCIN */
     270                 :             : 
     271                 :             : static void
     272                 :           4 : _glycin_encode_icon_bytes (GBytes              *bytes,
     273                 :             :                            GCancellable        *cancellable,
     274                 :             :                            GAsyncReadyCallback  callback,
     275                 :             :                            gpointer             user_data)
     276                 :             : {
     277                 :           8 :   g_autoptr (GTask) task = NULL;
     278                 :             : 
     279         [ -  + ]:           4 :   g_assert (bytes != NULL);
     280   [ +  -  +  -  :           4 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  +  -  - ]
     281                 :             : 
     282                 :           4 :   task = g_task_new (NULL, cancellable, callback, user_data);
     283         [ +  - ]:           4 :   g_task_set_source_tag (task, _glycin_encode_icon_bytes);
     284                 :             : #ifdef HAVE_GLYCIN
     285                 :           4 :   g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
     286         [ +  - ]:           4 :   g_task_run_in_thread (task, _glycin_encode_icon_bytes_task);
     287                 :             : #else
     288                 :             :   g_task_return_pointer (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
     289                 :             : #endif /* HAVE_GLYCIN */
     290                 :           4 : }
     291                 :             : 
     292                 :             : static GBytes *
     293                 :           4 : _glycin_encode_icon_bytes_finish (GAsyncResult  *result,
     294                 :             :                                   GError       **error)
     295                 :             : {
     296   [ +  -  +  -  :           4 :   g_assert (G_IS_TASK (result));
             -  +  -  - ]
     297   [ +  -  +  - ]:           4 :   g_assert (error == NULL || *error == NULL);
     298                 :             : 
     299                 :           4 :   return g_task_propagate_pointer (G_TASK (result), error);
     300                 :             : }
     301                 :             : 
     302                 :             : /*
     303                 :             :  * ValentTransfer Helpers
     304                 :             :  */
     305                 :             : static void
     306                 :           4 : g_output_stream_write_all_cb (GOutputStream *stream,
     307                 :             :                               GAsyncResult  *result,
     308                 :             :                               gpointer       user_data)
     309                 :             : {
     310                 :           8 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
     311                 :           4 :   GError *error = NULL;
     312                 :             : 
     313         [ -  + ]:           4 :   if (!g_output_stream_write_all_finish (stream, result, NULL, &error))
     314                 :             :     {
     315                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
     316         [ #  # ]:           0 :       return;
     317                 :             :     }
     318                 :             : 
     319         [ +  - ]:           4 :   g_task_return_boolean (task, TRUE);
     320                 :             : }
     321                 :             : 
     322                 :             : static void
     323                 :           4 : valent_channel_upload_cb (ValentChannel *channel,
     324                 :             :                           GAsyncResult  *result,
     325                 :             :                           gpointer       user_data)
     326                 :             : {
     327                 :           8 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
     328                 :           4 :   ValentNotificationUpload *self = g_task_get_source_object (task);
     329                 :           4 :   GCancellable *cancellable = g_task_get_cancellable (task);
     330   [ +  -  -  - ]:           4 :   g_autoptr (GIOStream) target = NULL;
     331                 :           4 :   GBytes *bytes = NULL;
     332                 :           4 :   const uint8_t *payload_data = NULL;
     333                 :           4 :   size_t payload_size = 0;
     334                 :           4 :   GError *error = NULL;
     335                 :             : 
     336                 :           4 :   target = valent_channel_upload_finish (channel, result, &error);
     337         [ -  + ]:           4 :   if (target == NULL)
     338                 :             :     {
     339         [ #  # ]:           0 :       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     340                 :             :         {
     341                 :           0 :           g_autoptr (ValentChannel) next = NULL;
     342                 :             : 
     343                 :           0 :           next = _valent_device_next_channel (self->device, channel);
     344         [ #  # ]:           0 :           if (next != NULL)
     345                 :             :             {
     346                 :           0 :               valent_channel_upload_async (next,
     347                 :             :                                            self->packet,
     348                 :             :                                            g_task_get_cancellable (task),
     349                 :             :                                            (GAsyncReadyCallback)valent_channel_upload_cb,
     350                 :             :                                            g_object_ref (task));
     351                 :           0 :               return;
     352                 :             :             }
     353                 :             :         }
     354                 :             : 
     355                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
     356                 :           0 :       return;
     357                 :             :     }
     358                 :             : 
     359                 :           4 :   bytes = g_task_get_task_data (task);
     360                 :           4 :   payload_data = g_bytes_get_data (bytes, &payload_size);
     361                 :           4 :   g_output_stream_write_all_async (g_io_stream_get_output_stream (target),
     362                 :             :                                    payload_data,
     363                 :             :                                    payload_size,
     364                 :             :                                    G_PRIORITY_DEFAULT,
     365                 :             :                                    cancellable,
     366                 :             :                                    (GAsyncReadyCallback)g_output_stream_write_all_cb,
     367                 :             :                                    g_object_ref (task));
     368                 :             : }
     369                 :             : 
     370                 :             : static void
     371                 :           4 : valent_notification_upload_transfer_bytes (GTask  *task,
     372                 :             :                                            GBytes *bytes)
     373                 :             : {
     374                 :           4 :   ValentNotificationUpload *self = g_task_get_source_object (task);
     375                 :           4 :   GCancellable *cancellable = g_task_get_cancellable (task);
     376                 :           4 :   g_autoptr (ValentChannel) channel = NULL;
     377                 :           4 :   g_autofree char *payload_hash = NULL;
     378                 :           4 :   const uint8_t *payload_data = NULL;
     379                 :           4 :   size_t payload_size = 0;
     380                 :             : 
     381                 :             :   /* A payload hash is included, allowing the remote device to ignore icon
     382                 :             :    * transfers that it already has cached.
     383                 :             :    */
     384                 :           4 :   payload_data = g_bytes_get_data (bytes, &payload_size);
     385                 :           4 :   payload_hash = g_compute_checksum_for_data (G_CHECKSUM_MD5,
     386                 :             :                                               payload_data,
     387                 :             :                                               payload_size);
     388                 :           4 :   json_object_set_string_member (valent_packet_get_body (self->packet),
     389                 :             :                                  "payloadHash",
     390                 :             :                                  payload_hash);
     391                 :           4 :   valent_packet_set_payload_size (self->packet, payload_size);
     392                 :             : 
     393                 :           4 :   channel = g_list_model_get_item (valent_device_get_channels (self->device), 0);
     394         [ -  + ]:           4 :   if (channel == NULL)
     395                 :             :     {
     396                 :           0 :       g_task_return_new_error (task,
     397                 :             :                                G_IO_ERROR,
     398                 :             :                                G_IO_ERROR_NOT_CONNECTED,
     399                 :             :                                "Device is disconnected");
     400                 :           0 :       return;
     401                 :             :     }
     402                 :             : 
     403                 :           4 :   g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
     404                 :           4 :   valent_channel_upload_async (channel,
     405                 :             :                                self->packet,
     406                 :             :                                cancellable,
     407                 :             :                                (GAsyncReadyCallback)valent_channel_upload_cb,
     408                 :             :                                g_object_ref (task));
     409                 :             : }
     410                 :             : 
     411                 :             : static void
     412                 :           4 : _glycin_encode_icon_bytes_cb (GObject      *object,
     413                 :             :                               GAsyncResult *result,
     414                 :             :                               gpointer      user_data)
     415                 :             : {
     416                 :           4 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
     417         [ +  - ]:           4 :   g_autoptr (GBytes) bytes = NULL;
     418                 :           4 :   GError *error = NULL;
     419                 :             : 
     420                 :           4 :   bytes = _glycin_encode_icon_bytes_finish (result, &error);
     421         [ -  + ]:           4 :   if (bytes == NULL)
     422                 :             :     {
     423                 :           0 :       g_debug ("%s(): %s", G_STRFUNC, error->message);
     424                 :           0 :       bytes = g_bytes_ref (g_task_get_task_data (task));
     425                 :             :     }
     426                 :             : 
     427         [ +  - ]:           4 :   valent_notification_upload_transfer_bytes (task, bytes);
     428                 :           4 : }
     429                 :             : 
     430                 :             : static void
     431                 :           3 : g_file_load_bytes_cb (GFile        *file,
     432                 :             :                       GAsyncResult *result,
     433                 :             :                       gpointer      user_data)
     434                 :             : {
     435                 :           6 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
     436                 :           3 :   GCancellable *cancellable = g_task_get_cancellable (task);
     437   [ -  -  +  - ]:           3 :   g_autoptr (GBytes) bytes = NULL;
     438                 :           3 :   GError *error = NULL;
     439                 :             : 
     440                 :           3 :   bytes = g_file_load_bytes_finish (file, result, NULL, &error);
     441         [ -  + ]:           3 :   if (bytes == NULL)
     442                 :             :     {
     443                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
     444         [ #  # ]:           0 :       return;
     445                 :             :     }
     446                 :             : 
     447                 :           3 :   g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
     448                 :           3 :   _glycin_encode_icon_bytes (bytes,
     449                 :             :                              cancellable,
     450                 :             :                              (GAsyncReadyCallback)_glycin_encode_icon_bytes_cb,
     451                 :             :                              g_object_ref (task));
     452                 :             : }
     453                 :             : 
     454                 :             : static void
     455                 :           4 : valent_notification_upload_transfer_icon (GTask *task,
     456                 :             :                                           GIcon *icon)
     457                 :             : {
     458                 :           4 :   GCancellable *cancellable = g_task_get_cancellable (task);
     459                 :           4 :   GError *error = NULL;
     460                 :             : 
     461   [ +  -  +  -  :           4 :   g_assert (G_IS_TASK (task));
             -  +  -  - ]
     462   [ +  -  +  -  :           4 :   g_assert (G_IS_ICON (icon));
             +  -  +  - ]
     463                 :             : 
     464   [ +  -  +  +  :           4 :   if (G_IS_BYTES_ICON (icon))
                   -  + ]
     465                 :             :     {
     466                 :           1 :       GBytes *bytes;
     467                 :             : 
     468                 :           1 :       bytes = g_bytes_icon_get_bytes (G_BYTES_ICON (icon));
     469                 :           1 :       g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
     470                 :           1 :       _glycin_encode_icon_bytes (bytes,
     471                 :             :                                  cancellable,
     472                 :             :                                  (GAsyncReadyCallback)_glycin_encode_icon_bytes_cb,
     473                 :             :                                  g_object_ref (task));
     474                 :             :     }
     475   [ +  -  +  +  :           3 :   else if (G_IS_FILE_ICON (icon))
                   -  + ]
     476                 :             :     {
     477                 :           1 :       GFile *file;
     478                 :             : 
     479                 :           1 :       file = g_file_icon_get_file (G_FILE_ICON (icon));
     480                 :           1 :       g_file_load_bytes_async (file,
     481                 :             :                                cancellable,
     482                 :             :                                (GAsyncReadyCallback)g_file_load_bytes_cb,
     483                 :             :                                g_object_ref (task));
     484                 :             :     }
     485                 :             : #ifdef HAVE_GTK4
     486   [ +  -  -  +  :           2 :   else if (G_IS_THEMED_ICON (icon))
                   -  - ]
     487                 :             :     {
     488                 :           2 :       g_autoptr (GFile) file = NULL;
     489                 :             : 
     490                 :           2 :       file = _gtk_icon_theme_get_largest_file (icon, &error);
     491         [ -  + ]:           2 :       if (file == NULL)
     492                 :             :         {
     493                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     494                 :           0 :           return;
     495                 :             :         }
     496                 :             : 
     497                 :           2 :       g_file_load_bytes_async (file,
     498                 :             :                                cancellable,
     499                 :             :                                (GAsyncReadyCallback)g_file_load_bytes_cb,
     500                 :             :                                g_object_ref (task));
     501                 :             :     }
     502                 :             : #endif /* HAVE_GTK4 */
     503                 :             :   else
     504                 :             :     {
     505                 :           0 :       g_task_return_new_error (task,
     506                 :             :                                G_IO_ERROR,
     507                 :             :                                G_IO_ERROR_NOT_SUPPORTED,
     508                 :             :                                "Unsupported icon type \"%s\"",
     509                 :             :                                G_OBJECT_TYPE_NAME (icon));
     510                 :             :     }
     511                 :             : }
     512                 :             : 
     513                 :             : /*
     514                 :             :  * ValentTransfer
     515                 :             :  */
     516                 :             : static void
     517                 :           4 : valent_notification_upload_execute (ValentTransfer      *transfer,
     518                 :             :                                     GCancellable        *cancellable,
     519                 :             :                                     GAsyncReadyCallback  callback,
     520                 :             :                                     gpointer             user_data)
     521                 :             : {
     522                 :           4 :   ValentNotificationUpload *self = VALENT_NOTIFICATION_UPLOAD (transfer);
     523                 :           8 :   g_autoptr (GTask) task = NULL;
     524                 :             : 
     525         [ -  + ]:           4 :   g_assert (VALENT_IS_NOTIFICATION_UPLOAD (self));
     526   [ +  -  +  -  :           4 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  +  -  - ]
     527                 :             : 
     528                 :           4 :   task = g_task_new (transfer, cancellable, callback, user_data);
     529         [ +  - ]:           4 :   g_task_set_source_tag (task, valent_notification_upload_execute);
     530         [ +  - ]:           4 :   valent_notification_upload_transfer_icon (task, self->icon);
     531                 :           4 : }
     532                 :             : 
     533                 :             : /*
     534                 :             :  * GObject
     535                 :             :  */
     536                 :             : static void
     537                 :           4 : valent_notification_upload_finalize (GObject *object)
     538                 :             : {
     539                 :           4 :   ValentNotificationUpload *self = VALENT_NOTIFICATION_UPLOAD (object);
     540                 :             : 
     541                 :           4 :   valent_object_lock (VALENT_OBJECT (self));
     542         [ +  - ]:           4 :   g_clear_object (&self->device);
     543         [ +  - ]:           4 :   g_clear_object (&self->icon);
     544         [ +  - ]:           4 :   g_clear_pointer (&self->packet, json_node_unref);
     545                 :           4 :   valent_object_unlock (VALENT_OBJECT (self));
     546                 :             : 
     547                 :           4 :   G_OBJECT_CLASS (valent_notification_upload_parent_class)->finalize (object);
     548                 :           4 : }
     549                 :             : 
     550                 :             : static void
     551                 :           0 : valent_notification_upload_get_property (GObject    *object,
     552                 :             :                                          guint       prop_id,
     553                 :             :                                          GValue     *value,
     554                 :             :                                          GParamSpec *pspec)
     555                 :             : {
     556                 :           0 :   ValentNotificationUpload *self = VALENT_NOTIFICATION_UPLOAD (object);
     557                 :             : 
     558   [ #  #  #  # ]:           0 :   switch ((ValentNotificationUploadProperty)prop_id)
     559                 :             :     {
     560                 :             :     case PROP_DEVICE:
     561                 :           0 :       valent_object_lock (VALENT_OBJECT (self));
     562                 :           0 :       g_value_set_object (value, self->device);
     563                 :           0 :       valent_object_unlock (VALENT_OBJECT (self));
     564                 :           0 :       break;
     565                 :             : 
     566                 :             :     case PROP_ICON:
     567                 :           0 :       valent_object_lock (VALENT_OBJECT (self));
     568                 :           0 :       g_value_set_object (value, self->icon);
     569                 :           0 :       valent_object_unlock (VALENT_OBJECT (self));
     570                 :           0 :       break;
     571                 :             : 
     572                 :             :     case PROP_PACKET:
     573                 :           0 :       valent_object_lock (VALENT_OBJECT (self));
     574                 :           0 :       g_value_set_boxed (value, self->packet);
     575                 :           0 :       valent_object_unlock (VALENT_OBJECT (self));
     576                 :           0 :       break;
     577                 :             : 
     578                 :           0 :     default:
     579                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     580                 :             :     }
     581                 :           0 : }
     582                 :             : 
     583                 :             : static void
     584                 :          12 : valent_notification_upload_set_property (GObject      *object,
     585                 :             :                                          guint         prop_id,
     586                 :             :                                          const GValue *value,
     587                 :             :                                          GParamSpec   *pspec)
     588                 :             : {
     589                 :          12 :   ValentNotificationUpload *self = VALENT_NOTIFICATION_UPLOAD (object);
     590                 :             : 
     591   [ +  +  +  - ]:          12 :   switch ((ValentNotificationUploadProperty)prop_id)
     592                 :             :     {
     593                 :             :     case PROP_DEVICE:
     594                 :           4 :       valent_object_lock (VALENT_OBJECT (self));
     595                 :           4 :       self->device = g_value_dup_object (value);
     596                 :           4 :       valent_object_unlock (VALENT_OBJECT (self));
     597                 :           4 :       break;
     598                 :             : 
     599                 :             :     case PROP_ICON:
     600                 :           4 :       valent_object_lock (VALENT_OBJECT (self));
     601                 :           4 :       self->icon = g_value_dup_object (value);
     602                 :           4 :       valent_object_unlock (VALENT_OBJECT (self));
     603                 :           4 :       break;
     604                 :             : 
     605                 :             :     case PROP_PACKET:
     606                 :           4 :       valent_object_lock (VALENT_OBJECT (self));
     607                 :           4 :       self->packet = g_value_dup_boxed (value);
     608                 :           4 :       valent_object_unlock (VALENT_OBJECT (self));
     609                 :           4 :       break;
     610                 :             : 
     611                 :           0 :     default:
     612                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     613                 :             :     }
     614                 :          12 : }
     615                 :             : 
     616                 :             : static void
     617                 :           1 : valent_notification_upload_class_init (ValentNotificationUploadClass *klass)
     618                 :             : {
     619                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     620                 :           1 :   ValentTransferClass *transfer_class = VALENT_TRANSFER_CLASS (klass);
     621                 :             : 
     622                 :           1 :   object_class->finalize = valent_notification_upload_finalize;
     623                 :           1 :   object_class->get_property = valent_notification_upload_get_property;
     624                 :           1 :   object_class->set_property = valent_notification_upload_set_property;
     625                 :             : 
     626                 :           1 :   transfer_class->execute = valent_notification_upload_execute;
     627                 :             : 
     628                 :             :   /**
     629                 :             :    * ValentNotificationUpload:device:
     630                 :             :    *
     631                 :             :    * The [class@Valent.Device] this transfer is for.
     632                 :             :    */
     633                 :           2 :   properties [PROP_DEVICE] =
     634                 :           1 :     g_param_spec_object ("device", NULL, NULL,
     635                 :             :                          VALENT_TYPE_DEVICE,
     636                 :             :                          (G_PARAM_READWRITE |
     637                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     638                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     639                 :             :                           G_PARAM_STATIC_STRINGS));
     640                 :             : 
     641                 :             :   /**
     642                 :             :    * ValentNotificationUpload:icon:
     643                 :             :    *
     644                 :             :    * The [iface@Gio.Icon] for the notification.
     645                 :             :    */
     646                 :           2 :   properties [PROP_ICON] =
     647                 :           1 :     g_param_spec_object ("icon", NULL, NULL,
     648                 :             :                          G_TYPE_ICON,
     649                 :             :                          (G_PARAM_READWRITE |
     650                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     651                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     652                 :             :                           G_PARAM_STATIC_STRINGS));
     653                 :             : 
     654                 :             :   /**
     655                 :             :    * ValentNotificationUpload:packet:
     656                 :             :    *
     657                 :             :    * The packet to send the payload with.
     658                 :             :    */
     659                 :           2 :   properties [PROP_PACKET] =
     660                 :           1 :     g_param_spec_boxed ("packet", NULL, NULL,
     661                 :             :                         JSON_TYPE_NODE,
     662                 :             :                         (G_PARAM_READWRITE |
     663                 :             :                          G_PARAM_CONSTRUCT_ONLY |
     664                 :             :                          G_PARAM_EXPLICIT_NOTIFY |
     665                 :             :                          G_PARAM_STATIC_STRINGS));
     666                 :             : 
     667                 :           1 :   g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
     668                 :           1 : }
     669                 :             : 
     670                 :             : static void
     671                 :           4 : valent_notification_upload_init (ValentNotificationUpload *self)
     672                 :             : {
     673                 :           4 : }
     674                 :             : 
     675                 :             : /**
     676                 :             :  * valent_notification_upload_new:
     677                 :             :  * @device: a `ValentDevice`
     678                 :             :  * @packet: a KDE Connect packet
     679                 :             :  * @icon: a `GIcon`
     680                 :             :  *
     681                 :             :  * Create a new `ValentNotificationUpload` for @packet and @icon.
     682                 :             :  *
     683                 :             :  * Returns: (transfer full): a `ValentNotificationUpload`
     684                 :             :  */
     685                 :             : ValentTransfer *
     686                 :           4 : valent_notification_upload_new (ValentDevice *device,
     687                 :             :                                 JsonNode     *packet,
     688                 :             :                                 GIcon        *icon)
     689                 :             : {
     690         [ -  + ]:           4 :   g_return_val_if_fail (VALENT_IS_DEVICE (device), NULL);
     691         [ +  - ]:           4 :   g_return_val_if_fail (VALENT_IS_PACKET (packet), NULL);
     692   [ +  -  +  -  :           4 :   g_return_val_if_fail (G_IS_ICON (icon), NULL);
             +  -  +  - ]
     693                 :             : 
     694                 :           4 :   return g_object_new (VALENT_TYPE_NOTIFICATION_UPLOAD,
     695                 :             :                        "device", device,
     696                 :             :                        "icon",   icon,
     697                 :             :                        "packet", packet,
     698                 :             :                        NULL);
     699                 :             : }
     700                 :             : 
        

Generated by: LCOV version 2.0-1