[nautilus/revert-text-only-clipboard] Revert "clipboard: Use text based clipboard only"



commit f7d0a6aafef019cca5dc716f377946886ac63d20
Author: António Fernandes <antoniof gnome org>
Date:   Sat Jul 18 22:01:20 2020 +0100

    Revert "clipboard: Use text based clipboard only"
    
    After removing the non-default "icons on desktop" functionality from
    nautilus, a gnome-shell extension was created as a substitute. This
    extension needed to interoperate with nautilus for file operations,
    but its access to clipboard was limited to plain text, so, in order to
    ensure interoperation, nautilus had to use plain text clipboard only.
    
    However, this temporary regression resulted in implementation details
    leaking into the text clipboard, instead of a plain file path.
    
    But now St.Clipboard can handle any type of clipboard content[1], the
    extension will be able to handle any clipboard type, so we can finally
    fix this regression on our side.
    
    This reverts commit 1f77023b5769c773dd9261e5294c0738bf6a3115
    and its fixup commit 80a38f9621319a306ec326470c328ca75887c71a
    
    Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/634

 src/nautilus-canvas-view.c |  13 ++---
 src/nautilus-clipboard.c   | 116 ++++++++++++++++++++++-----------------------
 src/nautilus-clipboard.h   |   5 +-
 src/nautilus-files-view.c  | 113 ++++++++++++++++++++++++++++++-------------
 src/nautilus-list-view.c   |  13 ++---
 5 files changed, 153 insertions(+), 107 deletions(-)
---
diff --git a/src/nautilus-canvas-view.c b/src/nautilus-canvas-view.c
index 4b3197bd7..09a72be6b 100644
--- a/src/nautilus-canvas-view.c
+++ b/src/nautilus-canvas-view.c
@@ -528,9 +528,9 @@ nautilus_canvas_view_begin_loading (NautilusFilesView *view)
 }
 
 static void
-on_clipboard_contents_received (GtkClipboard *clipboard,
-                                const gchar  *selection_data,
-                                gpointer      user_data)
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
 {
     NautilusCanvasView *canvas_view;
 
@@ -569,9 +569,10 @@ static void
 update_clipboard_status (NautilusCanvasView *view)
 {
     g_object_ref (view);     /* Need to keep the object alive until we get the reply */
-    gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                on_clipboard_contents_received,
-                                view);
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    on_clipboard_contents_received,
+                                    view);
 }
 
 static void
diff --git a/src/nautilus-clipboard.c b/src/nautilus-clipboard.c
index fb7e96d4b..02bf05497 100644
--- a/src/nautilus-clipboard.c
+++ b/src/nautilus-clipboard.c
@@ -33,6 +33,8 @@
 #include <gtk/gtk.h>
 #include <string.h>
 
+static GdkAtom copied_files_atom;
+
 typedef struct
 {
     gboolean cut;
@@ -40,31 +42,21 @@ typedef struct
 } ClipboardInfo;
 
 static GList *
-convert_selection_data_to_str_list (const gchar *data)
+convert_lines_to_str_list (char **lines)
 {
-    g_auto (GStrv) lines = NULL;
-    guint number_of_lines;
+    int i;
     GList *result;
 
-    lines = g_strsplit (data, "\n", 0);
-    number_of_lines = g_strv_length (lines);
-    if (number_of_lines == 0)
+    if (lines[0] == NULL)
     {
-        /* An empty string will result in g_strsplit() returning an empty
-         * array, so, naturally, 0 - 1 = UINT_MAX and we read all sorts
-         * of invalid memory.
-         */
         return NULL;
     }
-    result = NULL;
 
-    /* Also, this skips the last line, since it would be an
-     * empty string from the split */
-    for (guint i = 0; i < number_of_lines - 1; i++)
+    result = NULL;
+    for (i = 0; lines[i] != NULL; i++)
     {
         result = g_list_prepend (result, g_strdup (lines[i]));
     }
-
     return g_list_reverse (result);
 }
 
@@ -85,8 +77,7 @@ convert_file_list_to_string (ClipboardInfo *info,
     }
     else
     {
-        uris = g_string_new ("x-special/nautilus-clipboard\n");
-        g_string_append (uris, info->cut ? "cut\n" : "copy\n");
+        uris = g_string_new (info->cut ? "cut" : "copy");
     }
 
     for (i = 0, l = info->files; l != NULL; l = l->next, i++)
@@ -109,12 +100,16 @@ convert_file_list_to_string (ClipboardInfo *info,
                 g_string_append (uris, uri);
             }
 
-            g_string_append_c (uris, '\n');
+            /* skip newline for last element */
+            if (i + 1 < g_list_length (info->files))
+            {
+                g_string_append_c (uris, '\n');
+            }
         }
         else
         {
-            g_string_append (uris, uri);
             g_string_append_c (uris, '\n');
+            g_string_append (uris, uri);
         }
 
         g_free (uri);
@@ -125,60 +120,43 @@ convert_file_list_to_string (ClipboardInfo *info,
 }
 
 static GList *
-get_item_list_from_selection_data (const gchar *selection_data)
+get_item_list_from_selection_data (GtkSelectionData *selection_data)
 {
-    GList *items = NULL;
+    GList *items;
+    char **lines;
 
-    if (selection_data != NULL)
+    if (gtk_selection_data_get_data_type (selection_data) != copied_files_atom
+        || gtk_selection_data_get_length (selection_data) <= 0)
+    {
+        items = NULL;
+    }
+    else
     {
-        gboolean valid_data = TRUE;
+        gchar *data;
         /* Not sure why it's legal to assume there's an extra byte
          * past the end of the selection data that it's safe to write
          * to. But gtk_editable_selection_received does this, so I
          * think it is OK.
          */
-        items = convert_selection_data_to_str_list (selection_data);
-        if (items == NULL || g_strcmp0 (items->data, "x-special/nautilus-clipboard") != 0)
-        {
-            valid_data = FALSE;
-        }
-        else if (items->next == NULL)
-        {
-            valid_data = FALSE;
-        }
-        else if (g_strcmp0 (items->next->data, "cut") != 0 &&
-                 g_strcmp0 (items->next->data, "copy") != 0)
-        {
-            valid_data = FALSE;
-        }
-
-        if (!valid_data)
-        {
-            g_list_free_full (items, g_free);
-            items = NULL;
-        }
+        data = (gchar *) gtk_selection_data_get_data (selection_data);
+        data[gtk_selection_data_get_length (selection_data)] = '\0';
+        lines = g_strsplit (data, "\n", 0);
+        items = convert_lines_to_str_list (lines);
+        g_strfreev (lines);
     }
 
     return items;
 }
 
-gboolean
-nautilus_clipboard_is_data_valid_from_selection_data (const gchar *selection_data)
-{
-    return nautilus_clipboard_get_uri_list_from_selection_data (selection_data) != NULL;
-}
-
 GList *
-nautilus_clipboard_get_uri_list_from_selection_data (const gchar *selection_data)
+nautilus_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection_data)
 {
     GList *items;
 
     items = get_item_list_from_selection_data (selection_data);
     if (items)
     {
-        /* Line 0 is x-special/nautilus-clipboard. */
-        items = g_list_remove (items, items->data);
-        /* Line 1 is "cut" or "copy", so uris start at line 2. */
+        /* Line 0 is "cut" or "copy", so uris start at line 1. */
         items = g_list_remove (items, items->data);
     }
 
@@ -196,12 +174,13 @@ void
 nautilus_clipboard_clear_if_colliding_uris (GtkWidget   *widget,
                                             const GList *item_uris)
 {
-    g_autofree gchar *data = NULL;
+    GtkSelectionData *data;
     GList *clipboard_item_uris, *l;
     gboolean collision;
 
     collision = FALSE;
-    data = gtk_clipboard_wait_for_text (nautilus_clipboard_get (widget));
+    data = gtk_clipboard_wait_for_contents (nautilus_clipboard_get (widget),
+                                            copied_files_atom);
     if (data == NULL)
     {
         return;
@@ -231,14 +210,14 @@ nautilus_clipboard_clear_if_colliding_uris (GtkWidget   *widget,
 }
 
 gboolean
-nautilus_clipboard_is_cut_from_selection_data (const gchar *selection_data)
+nautilus_clipboard_is_cut_from_selection_data (GtkSelectionData *selection_data)
 {
     GList *items;
     gboolean is_cut_from_selection_data;
 
     items = get_item_list_from_selection_data (selection_data);
     is_cut_from_selection_data = items != NULL &&
-                                 g_strcmp0 ((gchar *) items->next->data, "cut") == 0;
+                                 g_strcmp0 ((gchar *) items->data, "cut") == 0;
 
     g_list_free_full (items, g_free);
 
@@ -283,10 +262,19 @@ on_get_clipboard (GtkClipboard     *clipboard,
         char *str;
         gsize len;
 
-        str = convert_file_list_to_string (clipboard_info, FALSE, &len);
+        str = convert_file_list_to_string (clipboard_info, TRUE, &len);
         gtk_selection_data_set_text (selection_data, str, len);
         g_free (str);
     }
+    else if (target == copied_files_atom)
+    {
+        char *str;
+        gsize len;
+
+        str = convert_file_list_to_string (clipboard_info, FALSE, &len);
+        gtk_selection_data_set (selection_data, copied_files_atom, 8, (guchar *) str, len);
+        g_free (str);
+    }
 }
 
 static void
@@ -315,6 +303,7 @@ nautilus_clipboard_prepare_for_files (GtkClipboard *clipboard,
     clipboard_info->files = nautilus_file_list_copy (files);
 
     target_list = gtk_target_list_new (NULL, 0);
+    gtk_target_list_add (target_list, copied_files_atom, 0, 0);
     gtk_target_list_add_uri_targets (target_list, 0);
     gtk_target_list_add_text_targets (target_list, 0);
 
@@ -327,3 +316,14 @@ nautilus_clipboard_prepare_for_files (GtkClipboard *clipboard,
                                  clipboard_info);
     gtk_target_table_free (targets, n_targets);
 }
+
+GdkAtom
+nautilus_clipboard_get_atom (void)
+{
+    if (!copied_files_atom)
+    {
+        copied_files_atom = gdk_atom_intern_static_string ("x-special/gnome-copied-files");
+    }
+
+    return copied_files_atom;
+}
diff --git a/src/nautilus-clipboard.h b/src/nautilus-clipboard.h
index 61810c154..1dd26d7c2 100644
--- a/src/nautilus-clipboard.h
+++ b/src/nautilus-clipboard.h
@@ -27,10 +27,9 @@
 void nautilus_clipboard_clear_if_colliding_uris    (GtkWidget          *widget,
                                                     const GList        *item_uris);
 GtkClipboard* nautilus_clipboard_get               (GtkWidget          *widget);
-GList* nautilus_clipboard_get_uri_list_from_selection_data (const gchar *selection_data);
-gboolean nautilus_clipboard_is_cut_from_selection_data (const gchar *selection_data);
+GList* nautilus_clipboard_get_uri_list_from_selection_data (GtkSelectionData   *selection_data);
+gboolean nautilus_clipboard_is_cut_from_selection_data (GtkSelectionData *selection_data);
 void nautilus_clipboard_prepare_for_files (GtkClipboard *clipboard,
                                            GList        *files,
                                            gboolean      cut);
 GdkAtom nautilus_clipboard_get_atom (void);
-gboolean nautilus_clipboard_is_data_valid_from_selection_data (const gchar *selection_data);
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index 2d8439283..db8ab21c5 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -2638,7 +2638,7 @@ action_open_item_new_window (GSimpleAction *action,
 
 static void
 handle_clipboard_data (NautilusFilesView *view,
-                       const gchar       *selection_data,
+                       GtkSelectionData  *selection_data,
                        char              *destination_uri,
                        GdkDragAction      action)
 {
@@ -2663,7 +2663,7 @@ handle_clipboard_data (NautilusFilesView *view,
 
 static void
 paste_clipboard_data (NautilusFilesView *view,
-                      const gchar       *selection_data,
+                      GtkSelectionData  *selection_data,
                       char              *destination_uri)
 {
     GdkDragAction action;
@@ -2681,9 +2681,9 @@ paste_clipboard_data (NautilusFilesView *view,
 }
 
 static void
-paste_clipboard_text_received_callback (GtkClipboard *clipboard,
-                                        const gchar  *selection_data,
-                                        gpointer      data)
+paste_clipboard_received_callback (GtkClipboard     *clipboard,
+                                   GtkSelectionData *selection_data,
+                                   gpointer          data)
 {
     NautilusFilesView *view;
     NautilusFilesViewPrivate *priv;
@@ -2715,10 +2715,10 @@ paste_files (NautilusFilesView *view)
      * is in the callback.
      */
     g_object_ref (view);
-
-    gtk_clipboard_request_text (clipboard,
-                                paste_clipboard_text_received_callback,
-                                view);
+    gtk_clipboard_request_contents (clipboard,
+                                    nautilus_clipboard_get_atom (),
+                                    paste_clipboard_received_callback,
+                                    view);
 }
 
 static void
@@ -2756,9 +2756,9 @@ action_paste_files_accel (GSimpleAction *action,
 }
 
 static void
-create_links_clipboard_received_callback (GtkClipboard *clipboard,
-                                          const gchar  *selection_data,
-                                          gpointer      data)
+create_links_clipboard_received_callback (GtkClipboard     *clipboard,
+                                          GtkSelectionData *selection_data,
+                                          gpointer          data)
 {
     NautilusFilesView *view;
     NautilusFilesViewPrivate *priv;
@@ -2791,9 +2791,10 @@ action_create_links (GSimpleAction *action,
     view = NAUTILUS_FILES_VIEW (user_data);
 
     g_object_ref (view);
-    gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                create_links_clipboard_received_callback,
-                                view);
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    create_links_clipboard_received_callback,
+                                    view);
 }
 
 static void
@@ -6222,9 +6223,9 @@ typedef struct
 } PasteIntoData;
 
 static void
-paste_into_clipboard_received_callback (GtkClipboard *clipboard,
-                                        const gchar  *selection_data,
-                                        gpointer      callback_data)
+paste_into_clipboard_received_callback (GtkClipboard     *clipboard,
+                                        GtkSelectionData *selection_data,
+                                        gpointer          callback_data)
 {
     NautilusFilesViewPrivate *priv;
     PasteIntoData *data;
@@ -6264,9 +6265,10 @@ paste_into (NautilusFilesView *view,
     data->view = g_object_ref (view);
     data->target = nautilus_file_ref (target);
 
-    gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                paste_into_clipboard_received_callback,
-                                data);
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    paste_into_clipboard_received_callback,
+                                    data);
 }
 
 static void
@@ -7141,9 +7143,9 @@ can_paste_into_file (NautilusFile *file)
 }
 
 static void
-on_clipboard_contents_received (GtkClipboard *clipboard,
-                                const gchar  *selection_data,
-                                gpointer      user_data)
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
 {
     NautilusFilesViewPrivate *priv;
     NautilusFilesView *view;
@@ -7153,7 +7155,6 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
     gboolean selection_contains_recent;
     gboolean selection_contains_starred;
     GAction *action;
-    gboolean is_data_valid;
 
     view = NAUTILUS_FILES_VIEW (user_data);
     priv = nautilus_files_view_get_instance_private (view);
@@ -7166,7 +7167,6 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
         return;
     }
 
-    is_data_valid = nautilus_clipboard_is_data_valid_from_selection_data (selection_data);
     settings_show_create_link = g_settings_get_boolean (nautilus_preferences,
                                                         NAUTILUS_PREFERENCES_SHOW_CREATE_LINK);
     is_read_only = nautilus_files_view_is_read_only (view);
@@ -7174,7 +7174,7 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
     selection_contains_starred = showing_starred_directory (view);
     can_link_from_copied_files = !nautilus_clipboard_is_cut_from_selection_data (selection_data) &&
                                  !selection_contains_recent && !selection_contains_starred &&
-                                 !is_read_only && selection_data != NULL;
+                                 !is_read_only && gtk_selection_data_get_length (selection_data) > 0;
 
     action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
                                          "create-link");
@@ -7182,25 +7182,62 @@ on_clipboard_contents_received (GtkClipboard *clipboard,
                                  can_link_from_copied_files &&
                                  settings_show_create_link);
 
+    g_object_unref (view);
+}
+
+static void
+on_clipboard_targets_received (GtkClipboard *clipboard,
+                               GdkAtom      *targets,
+                               int           n_targets,
+                               gpointer      user_data)
+{
+    NautilusFilesViewPrivate *priv;
+    NautilusFilesView *view;
+    gboolean is_data_copied;
+    int i;
+    GAction *action;
+
+    view = NAUTILUS_FILES_VIEW (user_data);
+    priv = nautilus_files_view_get_instance_private (view);
+    is_data_copied = FALSE;
+
+    if (priv->slot == NULL ||
+        !priv->active)
+    {
+        /* We've been destroyed or became inactive since call */
+        g_object_unref (view);
+        return;
+    }
+
+    if (targets)
+    {
+        for (i = 0; i < n_targets; i++)
+        {
+            if (targets[i] == nautilus_clipboard_get_atom ())
+            {
+                is_data_copied = TRUE;
+            }
+        }
+    }
+
     action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
                                          "paste");
     /* Take into account if the action was previously disabled for other reasons,
      * like the directory not being writabble */
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
-                                 is_data_valid && g_action_get_enabled (action));
+                                 is_data_copied && g_action_get_enabled (action));
 
     action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
                                          "paste-into");
 
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
-                                 is_data_valid && g_action_get_enabled (action));
+                                 is_data_copied && g_action_get_enabled (action));
 
     action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
                                          "create-link");
 
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
-                                 is_data_valid && g_action_get_enabled (action));
-
+                                 is_data_copied && g_action_get_enabled (action));
 
     g_object_unref (view);
 }
@@ -7748,10 +7785,18 @@ real_update_actions_state (NautilusFilesView *view)
                                  !selection_contains_starred &&
                                  priv->templates_present);
 
+    /* Actions that are related to the clipboard need request, request the data
+     * and update them once we have the data */
+    g_object_ref (view);     /* Need to keep the object alive until we get the reply */
+    gtk_clipboard_request_targets (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                   on_clipboard_targets_received,
+                                   view);
+
     g_object_ref (view);     /* Need to keep the object alive until we get the reply */
-    gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                on_clipboard_contents_received,
-                                view);
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    on_clipboard_contents_received,
+                                    view);
 
     action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
                                          "select-all");
diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
index 2ac0890e5..8b739fadf 100644
--- a/src/nautilus-list-view.c
+++ b/src/nautilus-list-view.c
@@ -3838,9 +3838,9 @@ list_view_scroll_to_file (NautilusFilesView *view,
 }
 
 static void
-on_clipboard_contents_received (GtkClipboard *clipboard,
-                                const gchar  *selection_data,
-                                gpointer      user_data)
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
 {
     NautilusListView *view = NAUTILUS_LIST_VIEW (user_data);
 
@@ -3875,9 +3875,10 @@ static void
 update_clipboard_status (NautilusListView *view)
 {
     g_object_ref (view);     /* Need to keep the object alive until we get the reply */
-    gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                on_clipboard_contents_received,
-                                view);
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    on_clipboard_contents_received,
+                                    view);
 }
 
 static void


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