[nautilus] general: rework clipboard handling



commit 55cf522e8f8c728b9e901ac006005c248b0a878a
Author: Carlos Soriano <csoriano gnome org>
Date:   Thu Sep 29 22:25:15 2016 +0200

    general: rework clipboard handling
    
    We were using a custom clipboard monitor, due to some old behaviour
    in 2004 where not all X servers supported XFIXES, which allows to
    monitor global clipboard changes between processes, which are needed in
    Nautilus for copy, paste and link operations, and their availability
    check.
    Since Nautilus was a single process, it was working for most of the
    time.
    
    However recently we split the desktop in a different process, so we
    were not able to correctly set the GDK action for clipboard, since
    we were relying on sharing the same clipboard in the same process.
    
    In order to fix this, this patch reworks the clipboard handling to a
    more modern way, using the owner-changed signal present in XFIXES.
    This fixes the clipboard changing between the desktop and Nautilus
    and interproccess clipboard handling, fixes small corner cases, and
    in the way this patch makes the code design and ownership of clipboard
    more clearer.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=771046

 src/Makefile.am                  |    2 -
 src/nautilus-canvas-view.c       |  119 +++++++++----
 src/nautilus-clipboard-monitor.c |  343 --------------------------------------
 src/nautilus-clipboard-monitor.h |   80 ---------
 src/nautilus-clipboard.c         |  240 ++++++++++++++++++++++++---
 src/nautilus-clipboard.h         |   17 +-
 src/nautilus-file-utilities.c    |   17 ++
 src/nautilus-file-utilities.h    |    2 +
 src/nautilus-files-view-dnd.c    |    3 +-
 src/nautilus-files-view.c        |  161 ++++++++++--------
 src/nautilus-files-view.h        |    2 -
 src/nautilus-list-view.c         |   83 ++++++----
 12 files changed, 469 insertions(+), 600 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 1f0a7ac..562af23 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -229,8 +229,6 @@ nautilus_no_main_sources = \
        nautilus-canvas-item.c \
        nautilus-canvas-item.h \
        nautilus-canvas-private.h \
-       nautilus-clipboard-monitor.c \
-       nautilus-clipboard-monitor.h \
        nautilus-clipboard.c \
        nautilus-clipboard.h \
        nautilus-column-chooser.c \
diff --git a/src/nautilus-canvas-view.c b/src/nautilus-canvas-view.c
index 28233d5..c7852f2 100644
--- a/src/nautilus-canvas-view.c
+++ b/src/nautilus-canvas-view.c
@@ -34,7 +34,6 @@
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
-#include "nautilus-clipboard-monitor.h"
 #include "nautilus-directory.h"
 #include "nautilus-dnd.h"
 #include "nautilus-file-utilities.h"
@@ -94,8 +93,6 @@ struct NautilusCanvasViewDetails
 
     const SortCriterion *sort;
 
-    gulong clipboard_handler_id;
-
     GtkWidget *canvas_container;
 
     gboolean supports_auto_layout;
@@ -103,6 +100,13 @@ struct NautilusCanvasViewDetails
     gboolean supports_scaling;
     gboolean supports_keep_aligned;
 
+    /* Needed for async operations. Suposedly we would use cancellable and gtask,
+     * sadly gtkclipboard doesn't support that.
+     * We follow this pattern for checking validity of the object in the views.
+     * Ideally we would connect to a weak reference and do a cancellable.
+     */
+    gboolean destroyed;
+
     GIcon *icon;
 };
 
@@ -189,6 +193,9 @@ static const SortCriterion *get_sort_criterion_by_sort_type (NautilusFileSortTyp
 static void                 switch_to_manual_layout (NautilusCanvasView *view);
 static const SortCriterion *get_default_sort_order (NautilusFile *file);
 static void                 nautilus_canvas_view_clear (NautilusFilesView *view);
+static void on_clipboard_owner_changed (GtkClipboard *clipboard,
+                                        GdkEvent     *event,
+                                        gpointer      user_data);
 
 G_DEFINE_TYPE (NautilusCanvasView, nautilus_canvas_view, NAUTILUS_TYPE_FILES_VIEW);
 
@@ -196,6 +203,7 @@ static void
 nautilus_canvas_view_destroy (GtkWidget *object)
 {
     NautilusCanvasView *canvas_view;
+    GtkClipboard *clipboard;
 
     canvas_view = NAUTILUS_CANVAS_VIEW (object);
 
@@ -207,12 +215,10 @@ nautilus_canvas_view_destroy (GtkWidget *object)
         canvas_view->details->react_to_canvas_change_idle_id = 0;
     }
 
-    if (canvas_view->details->clipboard_handler_id != 0)
-    {
-        g_signal_handler_disconnect (nautilus_clipboard_monitor_get (),
-                                     canvas_view->details->clipboard_handler_id);
-        canvas_view->details->clipboard_handler_id = 0;
-    }
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_handlers_disconnect_by_func (clipboard,
+                                          on_clipboard_owner_changed,
+                                          canvas_view);
 
     if (canvas_view->details->icons_not_positioned)
     {
@@ -754,20 +760,58 @@ nautilus_canvas_view_begin_loading (NautilusFilesView *view)
 }
 
 static void
-canvas_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
-                                   NautilusClipboardInfo    *info,
-                                   NautilusCanvasView       *canvas_view)
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
 {
-    GList *icon_data;
+    NautilusCanvasView *view = NAUTILUS_CANVAS_VIEW (user_data);
 
-    icon_data = NULL;
-    if (info && info->cut)
+    if (view->details->destroyed)
     {
-        icon_data = info->files;
+        /* We've been destroyed since call */
+        g_object_unref (view);
+        return;
     }
 
-    nautilus_canvas_container_set_highlighted_for_clipboard (
-        get_canvas_container (canvas_view), icon_data);
+    if (nautilus_clipboard_is_cut_from_selection_data (selection_data))
+    {
+        GList *uris;
+        GList *files;
+
+        uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data);
+        files = nautilus_file_list_from_uri_list (uris);
+        nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (view),
+                                                                 files);
+
+        nautilus_file_list_free (files);
+        g_list_free_full (uris, g_free);
+    }
+    else
+    {
+        nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (view),
+                                                                 NULL);
+    }
+
+    g_object_unref (view);
+}
+
+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_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    on_clipboard_contents_received,
+                                    view);
+}
+
+static void
+on_clipboard_owner_changed (GtkClipboard *clipboard,
+                            GdkEvent     *event,
+                            gpointer      user_data)
+{
+    update_clipboard_status (NAUTILUS_CANVAS_VIEW (user_data));
 }
 
 static void
@@ -775,19 +819,11 @@ nautilus_canvas_view_end_loading (NautilusFilesView *view,
                                   gboolean           all_files_seen)
 {
     NautilusCanvasView *canvas_view;
-    GtkWidget *canvas_container;
-    NautilusClipboardMonitor *monitor;
-    NautilusClipboardInfo *info;
 
     canvas_view = NAUTILUS_CANVAS_VIEW (view);
-
-    canvas_container = GTK_WIDGET (get_canvas_container (canvas_view));
-    nautilus_canvas_container_end_loading (NAUTILUS_CANVAS_CONTAINER (canvas_container), all_files_seen);
-
-    monitor = nautilus_clipboard_monitor_get ();
-    info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
-
-    canvas_view_notify_clipboard_info (monitor, info, canvas_view);
+    nautilus_canvas_container_end_loading (nautilus_canvas_view_get_canvas_container (canvas_view),
+                                           all_files_seen);
+    update_clipboard_status (canvas_view);
 }
 
 static NautilusCanvasZoomLevel
@@ -1570,8 +1606,7 @@ canvas_view_move_copy_items (NautilusCanvasContainer *container,
                              NautilusFilesView       *view)
 {
     nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
-                                                item_uris,
-                                                nautilus_files_view_get_copied_files_atom (view));
+                                                item_uris);
     nautilus_files_view_move_copy_items (view, item_uris, relative_item_points, target_dir,
                                          copy_action, x, y);
 }
@@ -1916,6 +1951,17 @@ nautilus_canvas_view_finalize (GObject *object)
     G_OBJECT_CLASS (nautilus_canvas_view_parent_class)->finalize (object);
 }
 
+static void
+nautilus_canvas_view_dispose (GObject *object)
+{
+    NautilusCanvasView *canvas_view;
+
+    canvas_view = NAUTILUS_CANVAS_VIEW (object);
+    canvas_view->details->destroyed = TRUE;
+
+    G_OBJECT_CLASS (nautilus_canvas_view_parent_class)->dispose (object);
+}
+
 static GIcon *
 nautilus_canvas_view_get_icon (NautilusFilesView *view)
 {
@@ -1935,6 +1981,7 @@ nautilus_canvas_view_class_init (NautilusCanvasViewClass *klass)
 
     oclass->set_property = nautilus_canvas_view_set_property;
     oclass->finalize = nautilus_canvas_view_finalize;
+    oclass->dispose = nautilus_canvas_view_dispose;
 
     GTK_WIDGET_CLASS (klass)->destroy = nautilus_canvas_view_destroy;
 
@@ -2008,10 +2055,12 @@ nautilus_canvas_view_init (NautilusCanvasView *canvas_view)
 {
     NautilusCanvasContainer *canvas_container;
     GActionGroup *view_action_group;
+    GtkClipboard *clipboard;
 
     canvas_view->details = g_new0 (NautilusCanvasViewDetails, 1);
     canvas_view->details->sort = &sort_criteria[0];
     canvas_view->details->icon = g_themed_icon_new ("view-grid-symbolic");
+    canvas_view->details->destroyed = FALSE;
 
     canvas_container = create_canvas_container (canvas_view);
     initialize_canvas_container (canvas_view, canvas_container);
@@ -2045,10 +2094,10 @@ nautilus_canvas_view_init (NautilusCanvasView *canvas_view)
     g_signal_connect_object (canvas_container, "handle-hover",
                              G_CALLBACK (canvas_view_handle_hover), canvas_view, 0);
 
-    canvas_view->details->clipboard_handler_id =
-        g_signal_connect (nautilus_clipboard_monitor_get (),
-                          "clipboard-info",
-                          G_CALLBACK (canvas_view_notify_clipboard_info), canvas_view);
+    /* React to clipboard changes */
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_connect (clipboard, "owner-change",
+                      G_CALLBACK (on_clipboard_owner_changed), canvas_view);
 
     view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view));
     g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),
diff --git a/src/nautilus-clipboard.c b/src/nautilus-clipboard.c
index 1409e26..957e11b 100644
--- a/src/nautilus-clipboard.c
+++ b/src/nautilus-clipboard.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 1999, 2000  Free Software Foundaton
  * Copyright (C) 2000, 2001  Eazel, Inc.
+ * Copyright (C) 2016 Carlos Soriano <csoriano gnome org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -26,52 +27,100 @@
 #include <config.h>
 #include "nautilus-clipboard.h"
 #include "nautilus-file-utilities.h"
+#include "nautilus-file.h"
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <string.h>
 
+static GdkAtom copied_files_atom;
+
+typedef struct
+{
+    gboolean cut;
+    GList *files;
+} ClipboardInfo;
+
 static GList *
-convert_lines_to_str_list (char     **lines,
-                           gboolean  *cut)
+convert_lines_to_str_list (char **lines)
 {
     int i;
     GList *result;
 
-    if (cut)
+    if (lines[0] == NULL)
     {
-        *cut = FALSE;
+        return NULL;
     }
 
-    if (lines[0] == NULL)
+    result = NULL;
+    for (i = 0; lines[i] != NULL; i++)
     {
-        return NULL;
+        result = g_list_prepend (result, g_strdup (lines[i]));
     }
+    return g_list_reverse (result);
+}
+
+static char *
+convert_file_list_to_string (ClipboardInfo *info,
+                             gboolean       format_for_text,
+                             gsize         *len)
+{
+    GString *uris;
+    char *uri, *tmp;
+    GFile *f;
+    guint i;
+    GList *l;
 
-    if (strcmp (lines[0], "cut") == 0)
+    if (format_for_text)
     {
-        if (cut)
-        {
-            *cut = TRUE;
-        }
+        uris = g_string_new (NULL);
     }
-    else if (strcmp (lines[0], "copy") != 0)
+    else
     {
-        return NULL;
+        uris = g_string_new (info->cut ? "cut" : "copy");
     }
 
-    result = NULL;
-    for (i = 1; lines[i] != NULL; i++)
+    for (i = 0, l = info->files; l != NULL; l = l->next, i++)
     {
-        result = g_list_prepend (result, g_strdup (lines[i]));
+        uri = nautilus_file_get_uri (l->data);
+
+        if (format_for_text)
+        {
+            f = g_file_new_for_uri (uri);
+            tmp = g_file_get_parse_name (f);
+            g_object_unref (f);
+
+            if (tmp != NULL)
+            {
+                g_string_append (uris, tmp);
+                g_free (tmp);
+            }
+            else
+            {
+                g_string_append (uris, uri);
+            }
+
+            /* skip newline for last element */
+            if (i + 1 < g_list_length (info->files))
+            {
+                g_string_append_c (uris, '\n');
+            }
+        }
+        else
+        {
+            g_string_append_c (uris, '\n');
+            g_string_append (uris, uri);
+        }
+
+        g_free (uri);
     }
-    return g_list_reverse (result);
+
+    *len = uris->len;
+    return g_string_free (uris, FALSE);
 }
 
-GList *
-nautilus_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection_data,
-                                                     gboolean         *cut,
-                                                     GdkAtom           copied_files_atom)
+static GList *
+get_item_list_from_selection_data (GtkSelectionData *selection_data)
 {
     GList *items;
     char **lines;
@@ -92,13 +141,28 @@ nautilus_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection
         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, cut);
+        items = convert_lines_to_str_list (lines);
         g_strfreev (lines);
     }
 
     return items;
 }
 
+GList *
+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 "cut" or "copy", so uris start at line 1. */
+        items = g_list_remove (items, items->data);
+    }
+
+    return items;
+}
+
 GtkClipboard *
 nautilus_clipboard_get (GtkWidget *widget)
 {
@@ -108,8 +172,7 @@ nautilus_clipboard_get (GtkWidget *widget)
 
 void
 nautilus_clipboard_clear_if_colliding_uris (GtkWidget   *widget,
-                                            const GList *item_uris,
-                                            GdkAtom      copied_files_atom)
+                                            const GList *item_uris)
 {
     GtkSelectionData *data;
     GList *clipboard_item_uris, *l;
@@ -123,8 +186,7 @@ nautilus_clipboard_clear_if_colliding_uris (GtkWidget   *widget,
         return;
     }
 
-    clipboard_item_uris = nautilus_clipboard_get_uri_list_from_selection_data (data, NULL,
-                                                                               copied_files_atom);
+    clipboard_item_uris = nautilus_clipboard_get_uri_list_from_selection_data (data);
 
     for (l = (GList *) item_uris; l; l = l->next)
     {
@@ -146,3 +208,129 @@ nautilus_clipboard_clear_if_colliding_uris (GtkWidget   *widget,
         g_list_free_full (clipboard_item_uris, g_free);
     }
 }
+
+gboolean
+nautilus_clipboard_is_cut_from_selection_data (GtkSelectionData *selection_data)
+{
+    GList *items;
+
+    items = get_item_list_from_selection_data (selection_data);
+    if (items == NULL)
+    {
+        return FALSE;
+    }
+
+    if (strcmp ((gchar *) items->data, "cut") == 0)
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+static void
+on_get_clipboard (GtkClipboard     *clipboard,
+                  GtkSelectionData *selection_data,
+                  guint             info,
+                  gpointer          user_data)
+{
+    char **uris;
+    GList *l;
+    int i;
+    ClipboardInfo *clipboard_info;
+    GdkAtom target;
+
+    clipboard_info = (ClipboardInfo *) user_data;
+
+    target = gtk_selection_data_get_target (selection_data);
+
+    if (gtk_targets_include_uri (&target, 1))
+    {
+        uris = g_malloc ((g_list_length (clipboard_info->files) + 1) * sizeof (char *));
+        i = 0;
+
+        for (l = clipboard_info->files; l != NULL; l = l->next)
+        {
+            uris[i] = nautilus_file_get_uri (l->data);
+            i++;
+        }
+
+        uris[i] = NULL;
+
+        gtk_selection_data_set_uris (selection_data, uris);
+
+        g_strfreev (uris);
+    }
+    else if (gtk_targets_include_text (&target, 1))
+    {
+        char *str;
+        gsize 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
+on_clear_clipboard (GtkClipboard *clipboard,
+                    gpointer      user_data)
+{
+    ClipboardInfo *clipboard_info = (ClipboardInfo *) user_data;
+
+    nautilus_file_list_free (clipboard_info->files);
+
+    g_free (clipboard_info);
+}
+
+void
+nautilus_clipboard_prepare_for_files (GtkClipboard *clipboard,
+                                      GList        *files,
+                                      gboolean      cut)
+{
+
+    GtkTargetList *target_list;
+    GtkTargetEntry *targets;
+    int n_targets;
+    ClipboardInfo *clipboard_info;
+
+    clipboard_info = g_new (ClipboardInfo, 1);
+    clipboard_info->cut = cut;
+    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);
+
+    targets = gtk_target_table_new_from_list (target_list, &n_targets);
+    gtk_target_list_unref (target_list);
+
+    gtk_clipboard_set_with_data (clipboard,
+                                 targets, n_targets,
+                                 on_get_clipboard, on_clear_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 1452b0f..c6ef98e 100644
--- a/src/nautilus-clipboard.h
+++ b/src/nautilus-clipboard.h
@@ -26,12 +26,15 @@
 #include <gtk/gtk.h>
 
 void nautilus_clipboard_clear_if_colliding_uris    (GtkWidget          *widget,
-                                                   const GList        *item_uris,
-                                                   GdkAtom             copied_files_atom);
-GtkClipboard* nautilus_clipboard_get                (GtkWidget          *widget);
-GList* nautilus_clipboard_get_uri_list_from_selection_data
-                                                  (GtkSelectionData   *selection_data,
-                                                   gboolean           *cut,
-                                                   GdkAtom             copied_files_atom);
+                                                    const GList        *item_uris);
+GtkClipboard* nautilus_clipboard_get               (GtkWidget          *widget);
+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_cut_from_selection_data (GtkSelectionData *selection_data);
 
 #endif /* NAUTILUS_CLIPBOARD_H */
diff --git a/src/nautilus-file-utilities.c b/src/nautilus-file-utilities.c
index 9a6683e..a99ddaf 100644
--- a/src/nautilus-file-utilities.c
+++ b/src/nautilus-file-utilities.c
@@ -870,6 +870,23 @@ nautilus_trashed_files_get_original_directories (GList  *files,
     return directories;
 }
 
+GList *
+nautilus_file_list_from_uri_list (GList *uris)
+{
+    GList *l;
+    GList *result = NULL;
+
+    for (l = uris; l != NULL; l = l->next)
+    {
+        g_autoptr (GFile) location = NULL;
+
+        location = g_file_new_for_uri (l->data);
+        result = g_list_prepend (result, nautilus_file_get (location));
+    }
+
+    return g_list_reverse (result);
+}
+
 static GList *
 locations_from_file_list (GList *file_list)
 {
diff --git a/src/nautilus-file-utilities.h b/src/nautilus-file-utilities.h
index bd6c06c..29ad7b3 100644
--- a/src/nautilus-file-utilities.h
+++ b/src/nautilus-file-utilities.h
@@ -122,4 +122,6 @@ void nautilus_ensure_extension_builtins (void);
 
 gboolean nautilus_file_can_rename_files (GList *files);
 
+GList * nautilus_file_list_from_uri_list (GList *uris);
+
 #endif /* NAUTILUS_FILE_UTILITIES_H */
diff --git a/src/nautilus-files-view-dnd.c b/src/nautilus-files-view-dnd.c
index 9f73624..b34e00f 100644
--- a/src/nautilus-files-view-dnd.c
+++ b/src/nautilus-files-view-dnd.c
@@ -573,8 +573,7 @@ nautilus_files_view_drop_proxy_received_uris (NautilusFilesView *view,
     }
 
     nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
-                                                source_uri_list,
-                                                nautilus_files_view_get_copied_files_atom (view));
+                                                source_uri_list);
 
     nautilus_files_view_move_copy_items (view, source_uri_list, NULL,
                                          target_uri != NULL ? target_uri : container_uri,
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index 2cb130e..0a6bb6c 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -74,7 +74,6 @@
 
 #include <libnautilus-extension/nautilus-menu-provider.h>
 #include "nautilus-clipboard.h"
-#include "nautilus-clipboard-monitor.h"
 #include "nautilus-search-directory.h"
 #include "nautilus-directory.h"
 #include "nautilus-dnd.h"
@@ -163,8 +162,6 @@ enum
 
 static guint signals[LAST_SIGNAL];
 
-static GdkAtom copied_files_atom;
-
 static char *scripts_directory_uri = NULL;
 static int scripts_directory_uri_length;
 
@@ -296,8 +293,9 @@ static void     trash_or_delete_files (GtkWindow         *parent_window,
                                        NautilusFilesView *view);
 static void     load_directory (NautilusFilesView *view,
                                 NautilusDirectory *directory);
-static void     clipboard_changed_callback (NautilusClipboardMonitor *monitor,
-                                            NautilusFilesView        *view);
+static void on_clipboard_owner_changed (GtkClipboard *clipboard,
+                                        GdkEvent     *event,
+                                        gpointer      user_data);
 static void     open_one_in_new_window (gpointer data,
                                         gpointer callback_data);
 static void     schedule_update_context_menus (NautilusFilesView *view);
@@ -2469,8 +2467,7 @@ handle_clipboard_data (NautilusFilesView *view,
 {
     GList *item_uris;
 
-    item_uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data, NULL,
-                                                                     copied_files_atom);
+    item_uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data);
 
     if (item_uris != NULL && destination_uri != NULL)
     {
@@ -2494,9 +2491,17 @@ paste_clipboard_data (NautilusFilesView *view,
                       char              *destination_uri)
 {
     GdkDragAction action;
+    const guchar* data;
 
-    action = nautilus_clipboard_monitor_is_cut (nautilus_clipboard_monitor_get ()) ?
-             GDK_ACTION_MOVE : GDK_ACTION_COPY;
+    data = gtk_selection_data_get_data (selection_data);
+    if (nautilus_clipboard_is_cut_from_selection_data (selection_data))
+    {
+        action = GDK_ACTION_MOVE;
+    }
+    else
+    {
+        action = GDK_ACTION_COPY;
+    }
 
     handle_clipboard_data (view, selection_data, destination_uri, action);
 }
@@ -2536,7 +2541,7 @@ action_paste_files (GSimpleAction *action,
 
     g_object_ref (view);
     gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                    copied_files_atom,
+                                    nautilus_clipboard_get_atom (),
                                     paste_clipboard_received_callback,
                                     view);
 }
@@ -2576,7 +2581,7 @@ action_create_links (GSimpleAction *action,
 
     g_object_ref (view);
     gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                    copied_files_atom,
+                                    nautilus_clipboard_get_atom (),
                                     create_links_clipboard_received_callback,
                                     view);
 }
@@ -2963,6 +2968,7 @@ static void
 nautilus_files_view_destroy (GtkWidget *object)
 {
     NautilusFilesView *view;
+    GtkClipboard *clipboard;
     GList *node, *next;
 
     view = NAUTILUS_FILES_VIEW (object);
@@ -3035,8 +3041,9 @@ nautilus_files_view_destroy (GtkWidget *object)
                                           schedule_update_context_menus, view);
     g_signal_handlers_disconnect_by_func (nautilus_trash_monitor_get (),
                                           nautilus_files_view_trash_state_changed_callback, view);
-    g_signal_handlers_disconnect_by_func (nautilus_clipboard_monitor_get (),
-                                          clipboard_changed_callback, view);
+
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_handlers_disconnect_by_func (clipboard, on_clipboard_owner_changed, view);
 
     nautilus_file_unref (view->details->directory_as_file);
     view->details->directory_as_file = NULL;
@@ -4400,14 +4407,6 @@ nautilus_files_view_get_content_widget (NautilusFilesView *view)
     return view->details->scrolled_window;
 }
 
-GdkAtom
-nautilus_files_view_get_copied_files_atom (NautilusFilesView *view)
-{
-    g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), GDK_NONE);
-
-    return copied_files_atom;
-}
-
 static void
 offset_drop_points (GArray *relative_item_points,
                     int     x_offset,
@@ -5725,47 +5724,20 @@ copy_or_move_selection (NautilusFilesView *view,
 }
 
 static void
-copy_or_cut_files (NautilusFilesView *view,
-                   GList             *clipboard_contents,
-                   gboolean           cut)
-{
-    NautilusClipboardInfo info;
-    GtkTargetList *target_list;
-    GtkTargetEntry *targets;
-    int n_targets;
-
-    info.files = clipboard_contents;
-    info.cut = cut;
-
-    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);
-
-    targets = gtk_target_table_new_from_list (target_list, &n_targets);
-    gtk_target_list_unref (target_list);
-
-    gtk_clipboard_set_with_data (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                 targets, n_targets,
-                                 nautilus_get_clipboard_callback, nautilus_clear_clipboard_callback,
-                                 NULL);
-    gtk_target_table_free (targets, n_targets);
-
-    nautilus_clipboard_monitor_set_clipboard_info (nautilus_clipboard_monitor_get (), &info);
-}
-
-static void
 action_copy (GSimpleAction *action,
              GVariant      *state,
              gpointer       user_data)
 {
     NautilusFilesView *view;
+    GtkClipboard *clipboard;
     GList *selection;
 
     view = NAUTILUS_FILES_VIEW (user_data);
 
     selection = nautilus_files_view_get_selection_for_file_transfer (view);
-    copy_or_cut_files (view, selection, FALSE);
+    clipboard = nautilus_clipboard_get (GTK_WIDGET (view));
+    nautilus_clipboard_prepare_for_files (clipboard, selection, FALSE);
+
     nautilus_file_list_free (selection);
 }
 
@@ -5776,11 +5748,14 @@ action_cut (GSimpleAction *action,
 {
     NautilusFilesView *view;
     GList *selection;
+    GtkClipboard *clipboard;
 
     view = NAUTILUS_FILES_VIEW (user_data);
 
     selection = nautilus_files_view_get_selection_for_file_transfer (view);
-    copy_or_cut_files (view, selection, TRUE);
+    clipboard = nautilus_clipboard_get (GTK_WIDGET (view));
+    nautilus_clipboard_prepare_for_files (clipboard, selection, TRUE);
+
     nautilus_file_list_free (selection);
 }
 
@@ -5886,7 +5861,7 @@ paste_into (NautilusFilesView *view,
     data->target = nautilus_file_ref (target);
 
     gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
-                                    copied_files_atom,
+                                    nautilus_clipboard_get_atom (),
                                     paste_into_clipboard_received_callback,
                                     data);
 }
@@ -6779,7 +6754,44 @@ can_paste_into_file (NautilusFile *file)
 }
 
 static void
-clipboard_targets_received (GtkClipboard *clipboard,
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
+{
+    NautilusFilesView *view;
+    gboolean can_link_from_copied_files;
+    gboolean settings_show_create_link;
+    gboolean is_read_only;
+    gboolean selection_contains_recent;
+    GAction *action;
+
+    view = NAUTILUS_FILES_VIEW (user_data);
+
+    if (view->details->slot == NULL ||
+        !view->details->active)
+    {
+        /* We've been destroyed or became inactive since call */
+        g_object_unref (view);
+        return;
+    }
+
+    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);
+    selection_contains_recent = showing_recent_directory (view);
+    can_link_from_copied_files = !nautilus_clipboard_is_cut_from_selection_data (selection_data) &&
+                                 !selection_contains_recent && !is_read_only;
+
+    action = g_action_map_lookup_action (G_ACTION_MAP (view->details->view_action_group),
+                                         "create-link");
+    g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                                 can_link_from_copied_files &&
+                                 settings_show_create_link);
+
+}
+
+static void
+on_clipboard_targets_received (GtkClipboard *clipboard,
                             GdkAtom      *targets,
                             int           n_targets,
                             gpointer      user_data)
@@ -6804,7 +6816,7 @@ clipboard_targets_received (GtkClipboard *clipboard,
     {
         for (i = 0; i < n_targets; i++)
         {
-            if (targets[i] == copied_files_atom)
+            if (targets[i] == nautilus_clipboard_get_atom ())
             {
                 is_data_copied = TRUE;
             }
@@ -6933,11 +6945,14 @@ can_restore_from_trash (GList *files)
 }
 
 static void
-clipboard_changed_callback (NautilusClipboardMonitor *monitor,
-                            NautilusFilesView        *view)
+on_clipboard_owner_changed (GtkClipboard *clipboard,
+                            GdkEvent     *event,
+                            gpointer      user_data)
 {
+    NautilusFilesView *self = NAUTILUS_FILES_VIEW (user_data);
+
     /* Update paste menu item */
-    nautilus_files_view_update_context_menus (view);
+    nautilus_files_view_update_context_menus (self);
 }
 
 static gboolean
@@ -7033,7 +7048,6 @@ real_update_actions_state (NautilusFilesView *view)
     gboolean can_move_files;
     gboolean can_trash_files;
     gboolean can_copy_files;
-    gboolean can_link_from_copied_files;
     gboolean can_paste_files_into;
     gboolean can_extract_files;
     gboolean can_compress_files;
@@ -7080,8 +7094,6 @@ real_update_actions_state (NautilusFilesView *view)
         !selection_contains_desktop_or_home_dir;
     can_copy_files = selection_count != 0
                      && !selection_contains_special_link;
-    can_link_from_copied_files = !nautilus_clipboard_monitor_is_cut (nautilus_clipboard_monitor_get ()) &&
-                                 !selection_contains_recent && !is_read_only;
     can_move_files = can_delete_files && !selection_contains_recent;
     can_paste_files_into = (!selection_contains_recent &&
                             selection_count == 1 &&
@@ -7335,12 +7347,6 @@ real_update_actions_state (NautilusFilesView *view)
                                  !is_read_only && !selection_contains_recent);
 
     action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
-                                         "create-link");
-    g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
-                                 can_link_from_copied_files &&
-                                 settings_show_create_link);
-
-    action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
                                          "paste-into");
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
                                  !selection_is_read_only && !selection_contains_recent &&
@@ -7357,12 +7363,19 @@ real_update_actions_state (NautilusFilesView *view)
                                  !selection_contains_recent &&
                                  view->details->templates_present);
 
-    /* Ask the clipboard */
+    /* 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)),
-                                   clipboard_targets_received,
+                                   on_clipboard_targets_received,
                                    view);
 
+    g_object_ref (view);     /* Need to keep the object alive until we get the reply */
+    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");
     g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
@@ -9002,8 +9015,6 @@ nautilus_files_view_class_init (NautilusFilesViewClass *klass)
     klass->update_actions_state = real_update_actions_state;
     klass->check_empty_states = real_check_empty_states;
 
-    copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE);
-
     g_object_class_install_property (
         oclass,
         PROP_WINDOW_SLOT,
@@ -9038,6 +9049,7 @@ nautilus_files_view_init (NautilusFilesView *view)
     NautilusDirectory *scripts_directory;
     NautilusDirectory *templates_directory;
     gchar *templates_uri;
+    GtkClipboard *clipboard;
     GApplication *app;
     const gchar *open_accels[] =
     {
@@ -9186,8 +9198,9 @@ nautilus_files_view_init (NautilusFilesView *view)
                              G_CALLBACK (nautilus_files_view_trash_state_changed_callback), view, 0);
 
     /* React to clipboard changes */
-    g_signal_connect_object (nautilus_clipboard_monitor_get (), "clipboard-changed",
-                             G_CALLBACK (clipboard_changed_callback), view, 0);
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_connect (clipboard, "owner-change",
+                      G_CALLBACK (on_clipboard_owner_changed), view);
 
     /* Register to menu provider extension signal managing menu updates */
     g_signal_connect_object (nautilus_signaller_get_current (), "popup-menu-changed",
diff --git a/src/nautilus-files-view.h b/src/nautilus-files-view.h
index 1a42f4e..888613f 100644
--- a/src/nautilus-files-view.h
+++ b/src/nautilus-files-view.h
@@ -280,8 +280,6 @@ char *              nautilus_files_view_get_uri                          (Nautil
 
 void                nautilus_files_view_display_selection_info           (NautilusFilesView *view);
 
-GdkAtom                    nautilus_files_view_get_copied_files_atom     (NautilusFilesView *view);
-
 /* Wrappers for signal emitters. These are normally called
  * only by NautilusFilesView itself. They have corresponding signals
  * that observers might want to connect with.
diff --git a/src/nautilus-list-view.c b/src/nautilus-list-view.c
index 490b4ba..d71ef30 100644
--- a/src/nautilus-list-view.c
+++ b/src/nautilus-list-view.c
@@ -43,7 +43,6 @@
 #include <glib-object.h>
 #include <libgd/gd.h>
 #include <libnautilus-extension/nautilus-column-provider.h>
-#include "nautilus-clipboard-monitor.h"
 #include "nautilus-column-chooser.h"
 #include "nautilus-column-utilities.h"
 #include "nautilus-dnd.h"
@@ -96,6 +95,9 @@ static char **get_visible_columns (NautilusListView *list_view);
 static char **get_default_visible_columns (NautilusListView *list_view);
 static char **get_column_order (NautilusListView *list_view);
 static char **get_default_column_order (NautilusListView *list_view);
+static void on_clipboard_owner_changed (GtkClipboard *clipboard,
+                                        GdkEvent     *event,
+                                        gpointer      user_data);
 
 
 G_DEFINE_TYPE (NautilusListView, nautilus_list_view, NAUTILUS_TYPE_FILES_VIEW);
@@ -1254,8 +1256,7 @@ move_copy_items_callback (NautilusTreeViewDragDest *dest,
     NautilusFilesView *view = user_data;
 
     nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
-                                                item_uris,
-                                                nautilus_files_view_get_copied_files_atom (view));
+                                                item_uris);
     nautilus_files_view_move_copy_items (view,
                                          item_uris,
                                          NULL,
@@ -3204,6 +3205,7 @@ static void
 nautilus_list_view_dispose (GObject *object)
 {
     NautilusListView *list_view;
+    GtkClipboard *clipboard;
 
     list_view = NAUTILUS_LIST_VIEW (object);
 
@@ -3219,12 +3221,8 @@ nautilus_list_view_dispose (GObject *object)
         list_view->details->drag_dest = NULL;
     }
 
-    if (list_view->details->clipboard_handler_id != 0)
-    {
-        g_signal_handler_disconnect (nautilus_clipboard_monitor_get (),
-                                     list_view->details->clipboard_handler_id);
-        list_view->details->clipboard_handler_id = 0;
-    }
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_handlers_disconnect_by_func (clipboard, on_clipboard_owner_changed, list_view);
 
     G_OBJECT_CLASS (nautilus_list_view_parent_class)->dispose (object);
 }
@@ -3361,39 +3359,63 @@ list_view_scroll_to_file (NautilusFilesView *view,
 }
 
 static void
-list_view_notify_clipboard_info (NautilusClipboardMonitor *monitor,
-                                 NautilusClipboardInfo    *info,
-                                 NautilusListView         *view)
+on_clipboard_contents_received (GtkClipboard     *clipboard,
+                                GtkSelectionData *selection_data,
+                                gpointer          user_data)
 {
-    /* this could be called as a result of _end_loading() being
-     * called after _dispose(), where the model is cleared.
-     */
-    if (view->details->model == NULL)
+    NautilusListView *view = NAUTILUS_LIST_VIEW (user_data);
+
+    if (!view->details->model)
     {
+        /* We've been destroyed since call */
+        g_object_unref (view);
         return;
     }
 
-    if (info != NULL && info->cut)
+    if (nautilus_clipboard_is_cut_from_selection_data (selection_data))
     {
-        nautilus_list_model_set_highlight_for_files (view->details->model, info->files);
+        GList *uris;
+        GList *files;
+
+        uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data);
+        files = nautilus_file_list_from_uri_list (uris);
+        nautilus_list_model_set_highlight_for_files (view->details->model, files);
+
+        nautilus_file_list_free (files);
+        g_list_free_full (uris, g_free);
     }
     else
     {
         nautilus_list_model_set_highlight_for_files (view->details->model, NULL);
     }
+
+    g_object_unref (view);
 }
 
 static void
-nautilus_list_view_end_loading (NautilusFilesView *view,
-                                gboolean           all_files_seen)
+update_clipboard_status (NautilusListView *view)
 {
-    NautilusClipboardMonitor *monitor;
-    NautilusClipboardInfo *info;
 
-    monitor = nautilus_clipboard_monitor_get ();
-    info = nautilus_clipboard_monitor_get_clipboard_info (monitor);
+    g_object_ref (view);     /* Need to keep the object alive until we get the reply */
+    gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
+                                    nautilus_clipboard_get_atom (),
+                                    on_clipboard_contents_received,
+                                    view);
+}
+
+static void
+on_clipboard_owner_changed (GtkClipboard *clipboard,
+                            GdkEvent     *event,
+                            gpointer      user_data)
+{
+    update_clipboard_status (NAUTILUS_LIST_VIEW (user_data));
+}
 
-    list_view_notify_clipboard_info (monitor, info, NAUTILUS_LIST_VIEW (view));
+static void
+nautilus_list_view_end_loading (NautilusFilesView *view,
+                                gboolean           all_files_seen)
+{
+    update_clipboard_status (NAUTILUS_LIST_VIEW (view));
 }
 
 static guint
@@ -3498,6 +3520,8 @@ static void
 nautilus_list_view_init (NautilusListView *list_view)
 {
     GActionGroup *view_action_group;
+    GtkClipboard *clipboard;
+
     list_view->details = g_new0 (NautilusListViewDetails, 1);
 
     list_view->details->icon = g_themed_icon_new ("view-list-symbolic");
@@ -3527,16 +3551,17 @@ nautilus_list_view_init (NautilusListView *list_view)
                               G_CALLBACK (default_column_order_changed_callback),
                               list_view);
 
+    /* React to clipboard changes */
+    clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    g_signal_connect (clipboard, "owner-change",
+                      G_CALLBACK (on_clipboard_owner_changed), list_view);
+
     nautilus_list_view_click_policy_changed (NAUTILUS_FILES_VIEW (list_view));
 
     nautilus_list_view_sort_directories_first_changed (NAUTILUS_FILES_VIEW (list_view));
     nautilus_list_view_set_zoom_level (list_view, get_default_zoom_level ());
 
     list_view->details->hover_path = NULL;
-    list_view->details->clipboard_handler_id =
-        g_signal_connect (nautilus_clipboard_monitor_get (),
-                          "clipboard-info",
-                          G_CALLBACK (list_view_notify_clipboard_info), list_view);
 
     view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (list_view));
     g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),



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