[nautilus/wip/antoniof/gtk4-restore-clipboard: 99/102] clipboard: Reintroduce non-local clipboard handling
- From: António Fernandes <antoniof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/antoniof/gtk4-restore-clipboard: 99/102] clipboard: Reintroduce non-local clipboard handling
- Date: Wed, 5 Jan 2022 13:44:16 +0000 (UTC)
commit b74ef1163a8e3428ef08c15dccdd9e81288eddf5
Author: António Fernandes <antoniof gnome org>
Date: Tue Jan 4 01:34:03 2022 +0000
clipboard: Reintroduce non-local clipboard handling
The old implementation supported providing 3 clipboard targers:
- the "x-special/gnome-copied-files" MIME Type
- the "text/uri-list" MIME Type
- plain text clipboard
We would build slightly different strings for each target.
For pasting, only the first target was supported, but the provider
could be any other program, not necessarily ourselves.
In orther to restore this non-local clipboard functionality, we need to
serialize content into these target types or deserialize into a GType.
- For the first one, we register our own custom [de]serializers,
which replicate the old implementation format.
- For the other two, we have GDK do it from GTK_TYPE_FILE_LIST.
src/nautilus-application.c | 3 +
src/nautilus-clipboard.c | 247 +++++++++++++++++++++++++--------------------
src/nautilus-clipboard.h | 2 +
3 files changed, 143 insertions(+), 109 deletions(-)
---
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index d7854dcec..06255587d 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -42,6 +42,7 @@
#include "nautilus-debug.h"
#include "nautilus-bookmark-list.h"
+#include "nautilus-clipboard.h"
#include "nautilus-dbus-manager.h"
#include "nautilus-directory-private.h"
#include "nautilus-file.h"
@@ -1110,6 +1111,8 @@ nautilus_application_init (NautilusApplication *self)
nautilus_ensure_extension_points ();
nautilus_ensure_extension_builtins ();
+
+ nautilus_clipboard_register ();
}
static void
diff --git a/src/nautilus-clipboard.c b/src/nautilus-clipboard.c
index c1a71f4c8..63183641d 100644
--- a/src/nautilus-clipboard.c
+++ b/src/nautilus-clipboard.c
@@ -44,129 +44,54 @@ struct _NautilusClipboard
G_DEFINE_BOXED_TYPE (NautilusClipboard, nautilus_clipboard,
nautilus_clipboard_copy, nautilus_clipboard_free)
-#if 0 && NAUTILUS_CLIPBOARD_NEEDS_GTK4_REIMPLEMENTATION
-static GList *
-convert_lines_to_str_list (char **lines)
-{
- int i;
- GList *result;
-
- if (lines[0] == NULL)
- {
- return NULL;
- }
-
- result = NULL;
- for (i = 0; lines[i] != NULL; i++)
- {
- 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)
+nautilus_clipboard_to_string (NautilusClipboard *clip)
{
GString *uris;
- char *uri, *tmp;
- GFile *f;
+ char *uri;
guint i;
GList *l;
- if (format_for_text)
- {
- uris = g_string_new (NULL);
- }
- else
- {
- uris = g_string_new (info->cut ? "cut" : "copy");
- }
+ uris = g_string_new (clip->cut ? "cut" : "copy");
- for (i = 0, l = info->files; l != NULL; l = l->next, i++)
+ for (i = 0, l = clip->files; l != NULL; l = l->next, 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_string_append_c (uris, '\n');
+ g_string_append (uris, uri);
g_free (uri);
}
- *len = uris->len;
return g_string_free (uris, FALSE);
}
-static GList *
-get_item_list_from_selection_data (GtkSelectionData *selection_data)
+static NautilusClipboard *
+nautilus_clipboard_from_string (char *string)
{
- GList *items;
- char **lines;
+ NautilusClipboard *clip;
+ g_auto (GStrv) lines = NULL;
- if (gtk_selection_data_get_data_type (selection_data) != copied_files_atom
- || gtk_selection_data_get_length (selection_data) <= 0)
- {
- items = NULL;
- }
- else
- {
- 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.
- */
- 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;
-}
-
-GList *
-nautilus_clipboard_get_uri_list_from_selection_data (GtkSelectionData *selection_data)
-{
- GList *items;
+ clip = g_new0 (NautilusClipboard, 1);
- items = get_item_list_from_selection_data (selection_data);
- if (items)
+ if (string != NULL)
{
+ lines = g_strsplit (string, "\n", 0);
+
/* Line 0 is "cut" or "copy", so uris start at line 1. */
- items = g_list_remove (items, items->data);
+ clip->cut = g_str_equal (lines[0], "cut");
+ for (int i = 1; lines[i] != NULL; i++)
+ {
+ clip->files = g_list_prepend (clip->files, nautilus_file_get_by_uri (lines[i]));
+ }
+ clip->files = g_list_reverse (clip->files);
}
- return items;
+ return clip;
}
+#if 0 && NAUTILUS_DND_NEEDS_GTK4_REIMPLEMENTATION
void
nautilus_clipboard_clear_if_colliding_uris (GtkWidget *widget,
const GList *item_uris)
@@ -207,6 +132,95 @@ nautilus_clipboard_clear_if_colliding_uris (GtkWidget *widget,
}
#endif
+/*
+ * This asumes the implementation of GTK_TYPE_FILE_LIST is a GSList<GFile>.
+ * As of writing this, the API docs don't provide for this assumption.
+ */
+static GSList *
+convert_file_list_to_gdk_file_list (NautilusClipboard *clip)
+{
+ GSList *file_list = NULL;
+ for (GList *l = clip->files; l != NULL; l = l->next)
+ {
+ file_list = g_slist_prepend (file_list,
+ nautilus_file_get_location (l->data));
+ }
+ return g_slist_reverse (file_list);
+}
+
+static void
+nautilus_clipboard_serialize (GdkContentSerializer *serializer)
+{
+ NautilusClipboard *clip;
+ g_autofree gchar *str;
+ g_autoptr (GError) error = NULL;
+
+ clip = g_value_get_boxed (gdk_content_serializer_get_value (serializer));
+
+ str = nautilus_clipboard_to_string (clip);
+
+ if (g_output_stream_printf (gdk_content_serializer_get_output_stream (serializer),
+ NULL,
+ gdk_content_serializer_get_cancellable (serializer),
+ &error,
+ "%s", str))
+ {
+ gdk_content_serializer_return_success (serializer);
+ }
+ else
+ {
+ gdk_content_serializer_return_error (serializer, error);
+ }
+}
+
+static void
+nautilus_clipboard_deserialize_finish (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GdkContentDeserializer *deserializer = user_data;
+ GOutputStream *output = G_OUTPUT_STREAM (source);
+ GError *error = NULL;
+ g_autofree gchar *string = NULL;
+ g_autoptr (NautilusClipboard) clip = NULL;
+
+ if (g_output_stream_splice_finish (output, result, &error) < 0)
+ {
+ gdk_content_deserializer_return_error (deserializer, error);
+ return;
+ }
+
+ /* write terminating NULL */
+ if (g_output_stream_write (output, "", 1, NULL, &error) < 0 ||
+ !g_output_stream_close (output, NULL, &error))
+ {
+ gdk_content_deserializer_return_error (deserializer, error);
+ return;
+ }
+
+ string = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (output));
+
+ clip = nautilus_clipboard_from_string (string);
+
+ g_value_set_boxed (gdk_content_deserializer_get_value (deserializer), clip);
+ gdk_content_deserializer_return_success (deserializer);
+}
+
+static void
+nautilus_clipboard_deserialize (GdkContentDeserializer *deserializer)
+{
+ g_autoptr (GOutputStream) output = NULL;
+
+ output = g_memory_output_stream_new_resizable ();
+ g_output_stream_splice_async (output,
+ gdk_content_deserializer_get_input_stream (deserializer),
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+ gdk_content_deserializer_get_priority (deserializer),
+ gdk_content_deserializer_get_cancellable (deserializer),
+ nautilus_clipboard_deserialize_finish,
+ deserializer);
+}
+
/**
* nautilus_clipboard_get_uri_list:
* @clip: The current local clipboard value.
@@ -256,25 +270,40 @@ nautilus_clipboard_prepare_for_files (GdkClipboard *clipboard,
gboolean cut)
{
g_autoptr (NautilusClipboard) clip = NULL;
- GdkContentProvider *provider;
+ g_autoslist (GFile) file_list = NULL;
+ GdkContentProvider *providers[2];
+ g_autoptr (GdkContentProvider) provider = NULL;
clip = g_new (NautilusClipboard, 1);
clip->cut = cut;
clip->files = nautilus_file_list_copy (files);
- provider = gdk_content_provider_new_typed (NAUTILUS_TYPE_CLIPBOARD, clip);
+ file_list = convert_file_list_to_gdk_file_list (clip);
+
+ providers[0] = gdk_content_provider_new_typed (NAUTILUS_TYPE_CLIPBOARD, clip);
+ providers[1] = gdk_content_provider_new_typed (GDK_TYPE_FILE_LIST, file_list);
+
+ provider = gdk_content_provider_new_union (providers, 2);
gdk_clipboard_set_content (clipboard, provider);
}
-#if 0 && NAUTILUS_CLIPBOARD_NEEDS_GTK4_REIMPLEMENTATION
-GdkAtom
-nautilus_clipboard_get_atom (void)
+void
+nautilus_clipboard_register (void)
{
- if (!copied_files_atom)
- {
- copied_files_atom = gdk_atom_intern_static_string ("x-special/gnome-copied-files");
- }
-
- return copied_files_atom;
+ /*
+ * While it'is not a public API and the format is not documented, some apps
+ * have come to use this atom/mime type to integrate with our clipboard.
+ */
+ const gchar *nautilus_clipboard_mime_type = "x-special/gnome-copied-files";
+
+ gdk_content_register_serializer (NAUTILUS_TYPE_CLIPBOARD,
+ nautilus_clipboard_mime_type,
+ nautilus_clipboard_serialize,
+ NULL,
+ NULL);
+ gdk_content_register_deserializer (nautilus_clipboard_mime_type,
+ NAUTILUS_TYPE_CLIPBOARD,
+ nautilus_clipboard_deserialize,
+ NULL,
+ NULL);
}
-#endif
diff --git a/src/nautilus-clipboard.h b/src/nautilus-clipboard.h
index 13bb8b3ac..137a14e69 100644
--- a/src/nautilus-clipboard.h
+++ b/src/nautilus-clipboard.h
@@ -42,3 +42,5 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (NautilusClipboard, nautilus_clipboard_free)
void nautilus_clipboard_prepare_for_files (GdkClipboard *clipboard,
GList *files,
gboolean cut);
+
+void nautilus_clipboard_register (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]