LCOV - code coverage report
Current view: top level - src/plugins/gtk - valent-gdk-clipboard.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 68.9 % 122 84
Test Date: 2024-12-21 23:29:11 Functions: 85.7 % 14 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 33.3 % 138 46

             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-gdk-clipboard"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <gdk/gdk.h>
       9                 :             : #include <valent.h>
      10                 :             : 
      11                 :             : #include "valent-gdk-clipboard.h"
      12                 :             : 
      13                 :             : #define CLIPBOARD_MAXSIZE (16 * 1024)
      14                 :             : 
      15                 :             : 
      16                 :             : struct _ValentGdkClipboard
      17                 :             : {
      18                 :             :   ValentClipboardAdapter  parent_instance;
      19                 :             : 
      20                 :             :   GdkClipboard           *clipboard;
      21                 :             :   int64_t                 timestamp;
      22                 :             : };
      23                 :             : 
      24   [ +  +  +  - ]:          20 : G_DEFINE_FINAL_TYPE (ValentGdkClipboard, valent_gdk_clipboard, VALENT_TYPE_CLIPBOARD_ADAPTER)
      25                 :             : 
      26                 :             : static const char * const text_mimetypes[] = {
      27                 :             :   "text/plain;charset=utf-8",
      28                 :             :   "text/plain",
      29                 :             :   "UTF8_STRING",
      30                 :             :   "STRING",
      31                 :             :   "TEXT",
      32                 :             :   "COMPOUND_TEXT",
      33                 :             :   NULL,
      34                 :             : };
      35                 :             : 
      36                 :             : 
      37                 :             : /*
      38                 :             :  * GdkClipboard Callbacks
      39                 :             :  */
      40                 :             : static void
      41                 :           3 : on_changed (GdkClipboard       *clipboard,
      42                 :             :             ValentGdkClipboard *self)
      43                 :             : {
      44                 :           3 :   ValentClipboardAdapter *adapter = VALENT_CLIPBOARD_ADAPTER (self);
      45                 :             : 
      46         [ +  - ]:           3 :   g_assert (VALENT_IS_GDK_CLIPBOARD (self));
      47         [ -  + ]:           3 :   g_assert (VALENT_IS_CLIPBOARD_ADAPTER (adapter));
      48                 :             : 
      49                 :             :   // TODO: get the actual TIMESTAMP value
      50                 :           3 :   self->timestamp = valent_timestamp_ms ();
      51                 :           3 :   valent_clipboard_adapter_changed (adapter);
      52                 :           3 : }
      53                 :             : 
      54                 :             : static void
      55                 :           0 : g_input_stream_read_bytes_cb (GInputStream *stream,
      56                 :             :                               GAsyncResult *result,
      57                 :             :                               gpointer      user_data)
      58                 :             : {
      59                 :           0 :   g_autoptr (GTask) task = G_TASK (user_data);
      60   [ #  #  #  # ]:           0 :   g_autoptr (GBytes) bytes = NULL;
      61         [ #  # ]:           0 :   g_autoptr (GError) error = NULL;
      62                 :             : 
      63                 :           0 :   bytes = g_input_stream_read_bytes_finish (stream, result, &error);
      64                 :             : 
      65         [ #  # ]:           0 :   if (bytes == NULL)
      66         [ #  # ]:           0 :     return g_task_return_error (task, g_steal_pointer (&error));
      67                 :             : 
      68         [ #  # ]:           0 :   g_task_return_pointer (task,
      69                 :           0 :                          g_bytes_ref (bytes),
      70                 :             :                          (GDestroyNotify)g_bytes_unref);
      71                 :             : }
      72                 :             : 
      73                 :             : static void
      74                 :           0 : gdk_clipboard_read_cb (GdkClipboard *clipboard,
      75                 :             :                        GAsyncResult *result,
      76                 :             :                        gpointer      user_data)
      77                 :             : {
      78                 :           0 :   g_autoptr (GTask) task = G_TASK (user_data);
      79                 :           0 :   GCancellable *cancellable = g_task_get_cancellable (task);
      80         [ #  # ]:           0 :   g_autoptr (GInputStream) input = NULL;
      81                 :           0 :   const char *mimetype = NULL;
      82         [ #  # ]:           0 :   g_autoptr (GError) error = NULL;
      83                 :             : 
      84   [ #  #  #  #  :           0 :   g_assert (GDK_IS_CLIPBOARD (clipboard));
             #  #  #  # ]
      85         [ #  # ]:           0 :   g_assert (g_task_is_valid (result, clipboard));
      86                 :             : 
      87                 :           0 :   input = gdk_clipboard_read_finish (clipboard, result, &mimetype, &error);
      88                 :             : 
      89         [ #  # ]:           0 :   if (input == NULL)
      90         [ #  # ]:           0 :     return g_task_return_error (task, g_steal_pointer (&error));
      91                 :             : 
      92         [ #  # ]:           0 :   g_input_stream_read_bytes_async (input,
      93                 :             :                                    G_PRIORITY_DEFAULT,
      94                 :             :                                    CLIPBOARD_MAXSIZE,
      95                 :             :                                    cancellable,
      96                 :             :                                    (GAsyncReadyCallback)g_input_stream_read_bytes_cb,
      97                 :             :                                    g_steal_pointer (&task));
      98                 :             : }
      99                 :             : 
     100                 :             : static void
     101                 :           3 : gdk_clipboard_read_text_cb (GdkClipboard *clipboard,
     102                 :             :                             GAsyncResult *result,
     103                 :             :                             gpointer      user_data)
     104                 :             : {
     105                 :           3 :   g_autoptr (GTask) task = G_TASK (user_data);
     106                 :           3 :   char *text = NULL;
     107                 :           3 :   GError *error = NULL;
     108                 :             : 
     109   [ +  -  +  -  :           3 :   g_assert (GDK_IS_CLIPBOARD (clipboard));
             +  -  -  + ]
     110         [ -  + ]:           3 :   g_assert (g_task_is_valid (result, clipboard));
     111                 :             : 
     112                 :           3 :   text = gdk_clipboard_read_text_finish (clipboard, result, &error);
     113                 :             : 
     114         [ -  + ]:           3 :   if (text == NULL)
     115         [ #  # ]:           0 :     return g_task_return_error (task, error);
     116                 :             : 
     117         [ +  - ]:           3 :   g_task_return_pointer (task,
     118                 :           3 :                          g_bytes_new_take (text, strlen (text) + 1),
     119                 :             :                          (GDestroyNotify)g_bytes_unref);
     120                 :             : }
     121                 :             : 
     122                 :             : /*
     123                 :             :  * ValentClipboardAdapter
     124                 :             :  */
     125                 :             : static GStrv
     126                 :           4 : valent_gdk_clipboard_get_mimetypes (ValentClipboardAdapter *adapter)
     127                 :             : {
     128                 :           4 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (adapter);
     129                 :           4 :   GdkContentFormats *formats = NULL;
     130                 :           4 :   const char * const *mimetypes = NULL;
     131                 :             : 
     132         [ +  - ]:           4 :   g_assert (VALENT_IS_GDK_CLIPBOARD (self));
     133   [ +  -  +  -  :           4 :   g_return_val_if_fail (GDK_IS_CLIPBOARD (self->clipboard), NULL);
             +  -  -  + ]
     134                 :             : 
     135         [ -  + ]:           4 :   if ((formats = gdk_clipboard_get_formats (self->clipboard)) == NULL)
     136                 :             :     return NULL;
     137                 :             : 
     138                 :           4 :   mimetypes = gdk_content_formats_get_mime_types (formats, NULL);
     139                 :             : 
     140                 :           4 :   return g_strdupv ((char **)mimetypes);
     141                 :             : }
     142                 :             : 
     143                 :             : static int64_t
     144                 :           2 : valent_gdk_clipboard_get_timestamp (ValentClipboardAdapter *adapter)
     145                 :             : {
     146                 :           2 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (adapter);
     147                 :             : 
     148         [ +  - ]:           2 :   g_assert (VALENT_IS_GDK_CLIPBOARD (self));
     149   [ +  -  +  -  :           2 :   g_return_val_if_fail (GDK_IS_CLIPBOARD (self->clipboard), 0);
             +  -  -  + ]
     150                 :             : 
     151                 :           2 :   return self->timestamp;
     152                 :             : }
     153                 :             : 
     154                 :             : static void
     155                 :           3 : valent_gdk_clipboard_read_bytes (ValentClipboardAdapter *adapter,
     156                 :             :                                  const char             *mimetype,
     157                 :             :                                  GCancellable           *cancellable,
     158                 :             :                                  GAsyncReadyCallback     callback,
     159                 :             :                                  gpointer                user_data)
     160                 :             : {
     161                 :           3 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (adapter);
     162                 :           3 :   g_autoptr (GTask) task = NULL;
     163                 :           3 :   GdkContentFormats *formats = NULL;
     164                 :             : 
     165         [ +  - ]:           3 :   g_assert (VALENT_IS_GDK_CLIPBOARD (self));
     166   [ +  -  -  + ]:           3 :   g_assert (mimetype != NULL && *mimetype != '\0');
     167                 :             : 
     168   [ +  -  +  -  :           3 :   if G_UNLIKELY (!GDK_IS_CLIPBOARD (self->clipboard))
             +  -  +  - ]
     169                 :             :     {
     170                 :           0 :       g_task_report_new_error (adapter, callback, user_data,
     171                 :             :                                valent_gdk_clipboard_read_bytes,
     172                 :             :                                G_IO_ERROR,
     173                 :             :                                G_IO_ERROR_NOT_SUPPORTED,
     174                 :             :                                "Clipboard not available");
     175                 :           0 :       return;
     176                 :             :     }
     177                 :             : 
     178                 :             :   /* Special case for text */
     179         [ +  - ]:           3 :   if (g_strv_contains (text_mimetypes, mimetype))
     180                 :             :     {
     181                 :           3 :       task = g_task_new (adapter, cancellable, callback, user_data);
     182         [ +  - ]:           3 :       g_task_set_source_tag (task, valent_gdk_clipboard_read_bytes);
     183                 :             : 
     184                 :           3 :       gdk_clipboard_read_text_async (self->clipboard,
     185                 :             :                                      cancellable,
     186                 :             :                                      (GAsyncReadyCallback)gdk_clipboard_read_text_cb,
     187                 :             :                                      g_steal_pointer (&task));
     188                 :           3 :       return;
     189                 :             :     }
     190                 :             : 
     191         [ #  # ]:           0 :   if ((formats = gdk_clipboard_get_formats (self->clipboard)) == NULL)
     192                 :             :     {
     193                 :           0 :       g_task_report_new_error (adapter, callback, user_data,
     194                 :             :                                valent_gdk_clipboard_read_bytes,
     195                 :             :                                G_IO_ERROR,
     196                 :             :                                G_IO_ERROR_NOT_SUPPORTED,
     197                 :             :                                "Clipboard empty");
     198                 :           0 :       return;
     199                 :             :     }
     200                 :             : 
     201         [ #  # ]:           0 :   if (!gdk_content_formats_contain_mime_type (formats, mimetype))
     202                 :             :     {
     203                 :           0 :       g_task_report_new_error (adapter, callback, user_data,
     204                 :             :                                valent_gdk_clipboard_read_bytes,
     205                 :             :                                G_IO_ERROR,
     206                 :             :                                G_IO_ERROR_NOT_SUPPORTED,
     207                 :             :                                "%s format not available.",
     208                 :             :                                mimetype);
     209                 :           0 :       return;
     210                 :             :     }
     211                 :             : 
     212                 :           0 :   task = g_task_new (adapter, cancellable, callback, user_data);
     213         [ #  # ]:           0 :   g_task_set_source_tag (task, valent_gdk_clipboard_read_bytes);
     214         [ #  # ]:           0 :   g_task_set_task_data (task, g_strdup (mimetype), g_free);
     215                 :             : 
     216                 :           0 :   gdk_clipboard_read_async (self->clipboard,
     217                 :           0 :                             (const char *[]){ mimetype, NULL },
     218                 :             :                             G_PRIORITY_DEFAULT,
     219                 :             :                             cancellable,
     220                 :             :                             (GAsyncReadyCallback)gdk_clipboard_read_cb,
     221                 :             :                             g_steal_pointer (&task));
     222                 :             : }
     223                 :             : 
     224                 :             : static void
     225                 :           2 : valent_gdk_clipboard_write_bytes (ValentClipboardAdapter *adapter,
     226                 :             :                                   const char             *mimetype,
     227                 :             :                                   GBytes                 *bytes,
     228                 :             :                                   GCancellable           *cancellable,
     229                 :             :                                   GAsyncReadyCallback     callback,
     230                 :             :                                   gpointer                user_data)
     231                 :             : {
     232                 :           2 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (adapter);
     233                 :           4 :   g_autoptr (GdkContentProvider) content = NULL;
     234   [ -  -  +  - ]:           2 :   g_autoptr (GTask) task = NULL;
     235                 :             : 
     236         [ +  - ]:           2 :   g_assert (VALENT_IS_GDK_CLIPBOARD (self));
     237   [ -  +  -  -  :           2 :   g_assert (bytes != NULL || (mimetype != NULL && *mimetype != '\0'));
                   -  - ]
     238   [ +  -  +  -  :           2 :   g_return_if_fail (GDK_IS_CLIPBOARD (self->clipboard));
             +  -  -  + ]
     239                 :             : 
     240         [ +  - ]:           2 :   if (bytes != NULL)
     241                 :           2 :     content = gdk_content_provider_new_for_bytes (mimetype, bytes);
     242                 :             : 
     243         [ -  + ]:           2 :   if (!gdk_clipboard_set_content (self->clipboard, content))
     244                 :             :     {
     245                 :           0 :       g_task_report_new_error (adapter, callback, user_data,
     246                 :             :                                valent_gdk_clipboard_write_bytes,
     247                 :             :                                G_IO_ERROR,
     248                 :             :                                G_IO_ERROR_FAILED,
     249                 :             :                                "Failed to set clipboard content");
     250         [ #  # ]:           0 :       return;
     251                 :             :     }
     252                 :             : 
     253                 :           2 :   task = g_task_new (adapter, cancellable, callback, user_data);
     254         [ +  - ]:           2 :   g_task_set_source_tag (task, valent_gdk_clipboard_write_bytes);
     255         [ +  - ]:           2 :   g_task_return_boolean (task, TRUE);
     256                 :             : }
     257                 :             : 
     258                 :             : /*
     259                 :             :  * ValentObject
     260                 :             :  */
     261                 :             : static void
     262                 :           2 : valent_gdk_clipboard_destroy (ValentObject *object)
     263                 :             : {
     264                 :           2 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (object);
     265                 :             : 
     266         [ +  + ]:           2 :   if (self->clipboard != NULL)
     267                 :             :     {
     268                 :           1 :       g_signal_handlers_disconnect_by_data (self->clipboard, self);
     269                 :           1 :       self->clipboard = NULL;
     270                 :             :     }
     271                 :             : 
     272                 :           2 :   VALENT_OBJECT_CLASS (valent_gdk_clipboard_parent_class)->destroy (object);
     273                 :           2 : }
     274                 :             : 
     275                 :             : /*
     276                 :             :  * GObject
     277                 :             :  */
     278                 :             : static void
     279                 :           1 : valent_gdk_clipboard_constructed (GObject *object)
     280                 :             : {
     281                 :           1 :   ValentGdkClipboard *self = VALENT_GDK_CLIPBOARD (object);
     282                 :           1 :   GdkDisplay *display;
     283                 :             : 
     284         [ +  - ]:           1 :   if ((display = gdk_display_get_default ()) != NULL)
     285                 :             :     {
     286                 :           1 :       self->clipboard = gdk_display_get_clipboard (display);
     287                 :           1 :       g_signal_connect_object (self->clipboard,
     288                 :             :                                "changed",
     289                 :             :                                G_CALLBACK (on_changed),
     290                 :             :                                self, 0);
     291                 :             :     }
     292                 :             :   else
     293                 :             :     {
     294                 :           0 :       valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
     295                 :             :                                              VALENT_PLUGIN_STATE_INACTIVE,
     296                 :             :                                              NULL);
     297                 :             :     }
     298                 :             : 
     299                 :           1 :   G_OBJECT_CLASS (valent_gdk_clipboard_parent_class)->constructed (object);
     300                 :           1 : }
     301                 :             : 
     302                 :             : static void
     303                 :           2 : valent_gdk_clipboard_class_init (ValentGdkClipboardClass *klass)
     304                 :             : {
     305                 :           2 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     306                 :           2 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     307                 :           2 :   ValentClipboardAdapterClass *clipboard_class = VALENT_CLIPBOARD_ADAPTER_CLASS (klass);
     308                 :             : 
     309                 :           2 :   object_class->constructed = valent_gdk_clipboard_constructed;
     310                 :             : 
     311                 :           2 :   vobject_class->destroy = valent_gdk_clipboard_destroy;
     312                 :             : 
     313                 :           2 :   clipboard_class->get_mimetypes = valent_gdk_clipboard_get_mimetypes;
     314                 :           2 :   clipboard_class->get_timestamp = valent_gdk_clipboard_get_timestamp;
     315                 :           2 :   clipboard_class->read_bytes = valent_gdk_clipboard_read_bytes;
     316                 :           2 :   clipboard_class->write_bytes = valent_gdk_clipboard_write_bytes;
     317                 :             : }
     318                 :             : 
     319                 :             : static void
     320                 :           1 : valent_gdk_clipboard_init (ValentGdkClipboard *self)
     321                 :             : {
     322                 :           1 : }
     323                 :             : 
        

Generated by: LCOV version 2.0-1