[nautilus/wip/corey/rework-clipboard: 2/2] files-view: Allow pasting GDK_TYPE_TEXTURE




commit 4c79c6607a0410ebaedb79785f0a0123cf5eba60
Author: Corey Berla <corey berla me>
Date:   Tue Sep 20 15:18:13 2022 -0700

    files-view: Allow pasting GDK_TYPE_TEXTURE
    
    Allow pasting raw images from the clipboard to a file within
    Nautilus.  We just get the raw data, so generate a filename
    automatically.  Just as with other copy operations, the select
    the file after creation.

 src/nautilus-file-operations.c | 155 +++++++++++++++++++++++++++++++++++++++++
 src/nautilus-file-operations.h |   7 ++
 src/nautilus-files-view.c      |  12 +++-
 3 files changed, 173 insertions(+), 1 deletion(-)
---
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index aa8bd29f3..10c864b3d 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -236,6 +236,17 @@ typedef struct
     gpointer done_callback_data;
 } CompressJob;
 
+typedef struct
+{
+    CommonJob common;
+    GFile *location;
+    GFile *dest_dir;
+    gboolean success;
+    GdkTexture *texture;
+    NautilusCopyCallback done_callback;
+    gpointer done_callback_data;
+} PasteImageJob;
+
 static void
 source_info_clear (SourceInfo *source_info)
 {
@@ -8026,6 +8037,150 @@ nautilus_file_operations_new_folder (GtkWidget                      *parent_view
     g_task_run_in_thread (task, create_task_thread_func);
 }
 
+static void
+paste_image_thread_func (GTask        *task,
+                         gpointer      source_object,
+                         gpointer      task_data,
+                         GCancellable *cancellable)
+{
+    PasteImageJob *job = task_data;
+    g_autoptr (GError) output_error = NULL;
+    g_autoptr (GFileOutputStream) stream = NULL;
+    g_autoptr (GBytes) bytes = NULL;
+    int i = 0;
+
+    while (stream == NULL)
+    {
+        g_autoptr (GError) stream_error = NULL;
+        g_autofree gchar *filename = NULL;
+        g_autofree gchar *suffix = NULL;
+        /* Translators: This is used to auto-generate a file name for pasted images from
+         * the clipboard i.e. "Pasted image.png", "Pasted image 1.png", ... */
+        const gchar *base_name = _("Pasted image");
+
+        suffix = i == 0 ? g_strdup (".png") : g_strdup_printf (" %d.png", i);
+        filename = g_strdup_printf ("%s%s", base_name, suffix);
+        job->location = g_file_get_child (job->dest_dir, filename);
+        stream = g_file_create (job->location, 0, job->common.cancellable, &stream_error);
+        if (stream_error == NULL)
+        {
+            break;
+        }
+        else if (IS_IO_ERROR (stream_error, EXISTS))
+        {
+            g_clear_object (&job->location);
+            i++;
+        }
+        else
+        {
+            return;
+        }
+    }
+
+    bytes = gdk_texture_save_to_png_bytes (job->texture);
+    nautilus_progress_info_set_progress (job->common.progress, .75, 1);
+    nautilus_progress_info_set_status (job->common.progress, _("Saving clipboard image to file"));
+    nautilus_progress_info_set_details (job->common.progress, "");
+    g_output_stream_write_bytes (G_OUTPUT_STREAM (stream), bytes, job->common.cancellable, &output_error);
+    if (output_error == NULL)
+    {
+        job->success = TRUE;
+        nautilus_progress_info_set_progress (job->common.progress, 1, 1);
+        nautilus_progress_info_set_status (job->common.progress, _("Successfully pasted clipboard image to 
file"));
+    }
+}
+
+static void
+paste_image_task_done (GObject      *source_object,
+                       GAsyncResult *res,
+                       gpointer      user_data)
+{
+    PasteImageJob *job = user_data;
+    g_autoptr (GHashTable) debuting_files = NULL;
+
+    debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL);
+
+    if (job->location != NULL)
+    {
+        g_hash_table_insert (debuting_files, g_object_ref (job->location), job->location);
+    }
+
+    job->done_callback (debuting_files, job->success, job->done_callback_data);
+
+    if (!job->success)
+    {
+        if (job->location != NULL)
+        {
+            g_file_delete (job->location, NULL, NULL);
+        }
+        nautilus_progress_info_set_status (job->common.progress, _("Failed to paste image"));
+    }
+
+    g_clear_object (&job->location);
+    g_clear_object (&job->dest_dir);
+    g_clear_object (&job->texture);
+
+    finalize_common ((CommonJob *) job);
+}
+
+static void
+paste_image_received_callback (GObject      *source_object,
+                               GAsyncResult *res,
+                               gpointer      user_data)
+{
+    GdkClipboard *clipboard = GDK_CLIPBOARD (source_object);
+    PasteImageJob *job = user_data;
+    g_autoptr (GTask) task = NULL;
+    g_autoptr (GError) clipboard_error = NULL;
+
+    if (job_aborted ((CommonJob *) job))
+    {
+        paste_image_task_done (NULL, NULL, job);
+        return;
+    }
+
+    job->texture = gdk_clipboard_read_texture_finish (clipboard, res, &clipboard_error);
+    if (clipboard_error != NULL)
+    {
+        paste_image_task_done (NULL, NULL, job);
+        return;
+    }
+
+    nautilus_progress_info_set_progress (job->common.progress, .5, 1);
+
+    task = g_task_new (NULL, NULL, paste_image_task_done, job);
+    g_task_set_task_data (task, job, NULL);
+    g_task_run_in_thread (task, paste_image_thread_func);
+}
+
+void
+nautilus_file_operations_paste_image_from_clipboard (GtkWidget                      *parent_view,
+                                                    NautilusFileOperationsDBusData *dbus_data,
+                                                    const char                     *parent_dir_uri,
+                                                    NautilusCopyCallback      done_callback,
+                                                    gpointer                        done_callback_data)
+{
+    PasteImageJob *job;
+    GtkWindow *parent_window = NULL;
+    GdkClipboard *clipboard = gtk_widget_get_clipboard (parent_view);
+
+    if (parent_view)
+    {
+        parent_window = (GtkWindow *) gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW);
+    }
+
+    job = op_job_new (PasteImageJob, parent_window, dbus_data);
+    job->dest_dir = g_file_new_for_uri (parent_dir_uri);
+    job->location = NULL;
+    job->texture = NULL;
+    job->done_callback = done_callback;
+    job->done_callback_data = done_callback_data;
+
+    nautilus_progress_info_start (job->common.progress);
+    nautilus_progress_info_set_status (job->common.progress, _("Retrieving clipboard data"));
+    gdk_clipboard_read_texture_async (clipboard, job->common.cancellable, paste_image_received_callback, 
job);
+}
+
 void
 nautilus_file_operations_new_file_from_template (GtkWidget              *parent_view,
                                                  const char             *parent_dir,
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
index 14d664f80..99afad600 100644
--- a/src/nautilus-file-operations.h
+++ b/src/nautilus-file-operations.h
@@ -164,3 +164,10 @@ void nautilus_file_operations_compress (GList                          *files,
                                         NautilusFileOperationsDBusData *dbus_data,
                                         NautilusCreateCallback          done_callback,
                                         gpointer                        done_callback_data);
+
+void
+nautilus_file_operations_paste_image_from_clipboard (GtkWidget                      *parent_view,
+                                                    NautilusFileOperationsDBusData *dbus_data,
+                                                    const char                     *parent_dir_uri,
+                                                    NautilusCopyCallback            done_callback,
+                                                    gpointer                        done_callback_data);
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index e110534e3..9d927072a 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -2807,6 +2807,15 @@ paste_files (NautilusFilesView *view,
     {
         gdk_clipboard_read_value_async (clipboard, G_TYPE_FILE, 0, priv->clipboard_cancellable, 
paste_value_received_callback, data);
     }
+    else if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE))
+    {
+        nautilus_file_operations_paste_image_from_clipboard (GTK_WIDGET (view),
+                                                             NULL,
+                                                             data->dest_uri,
+                                                             copy_move_done_callback,
+                                                             pre_copy_move (view));
+        paste_callback_data_free (data);
+    }
 }
 
 static void
@@ -7217,7 +7226,8 @@ update_actions_state_for_clipboard_targets (NautilusFilesView *view)
     clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view));
     formats = gdk_clipboard_get_formats (clipboard);
     is_data_copied = gdk_content_formats_contain_gtype (formats, NAUTILUS_TYPE_CLIPBOARD) ||
-                     gdk_content_formats_contain_gtype (formats, G_TYPE_FILE);
+                     gdk_content_formats_contain_gtype (formats, G_TYPE_FILE) ||
+                     gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE);
 
     action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
                                          "paste");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]