[nautilus/wip/corey/rework-clipboard] files-view: Allow pasting GDK_TYPE_PIXBUF
- From: Corey Berla <coreyberla src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/corey/rework-clipboard] files-view: Allow pasting GDK_TYPE_PIXBUF
- Date: Wed, 21 Sep 2022 17:06:50 +0000 (UTC)
commit 9faaf2197ce44d8311110a166b38a3240ed06ec2
Author: Corey Berla <corey berla me>
Date: Tue Sep 20 15:18:13 2022 -0700
files-view: Allow pasting GDK_TYPE_PIXBUF
In my testing, copying images was captured as GDK_TYPE_PIXBUF.
Allow pasting those files into Nautilus. Since we don't have
any information regarding filename, popup a dialog that asks for a
filename and allows choosing a supported filetype.
src/meson.build | 2 +
src/nautilus-files-view.c | 50 +++++++-
src/nautilus-paste-image-dialog-controller.c | 163 ++++++++++++++++++++++++
src/nautilus-paste-image-dialog-controller.h | 36 ++++++
src/resources/nautilus.gresource.xml | 1 +
src/resources/ui/nautilus-paste-image-dialog.ui | 85 ++++++++++++
6 files changed, 336 insertions(+), 1 deletion(-)
---
diff --git a/src/meson.build b/src/meson.build
index 383920c3d..5c022c4fb 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -103,6 +103,8 @@ libnautilus_sources = [
'nautilus-mime-actions.h',
'nautilus-name-cell.c',
'nautilus-name-cell.h',
+ 'nautilus-paste-image-dialog-controller.c',
+ 'nautilus-paste-image-dialog-controller.h',
'nautilus-pathbar.c',
'nautilus-pathbar.h',
'nautilus-places-view.c',
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index c78523f3a..7970ea3bb 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -76,6 +76,7 @@
#include "nautilus-mime-actions.h"
#include "nautilus-module.h"
#include "nautilus-new-folder-dialog-controller.h"
+#include "nautilus-paste-image-dialog-controller.h"
#include "nautilus-previewer.h"
#include "nautilus-profile.h"
#include "nautilus-program-choosing.h"
@@ -2092,6 +2093,21 @@ nautilus_files_view_new_folder_dialog_new (NautilusFilesView *view,
view);
}
+static void
+paste_image_dialog_controller_on_name_accepted (NautilusPasteImageDialogController *controller,
+ gpointer user_data)
+{
+ nautilus_paste_image_dialog_controller_save_pixbuf (controller);
+ g_object_unref (controller);
+}
+
+static void
+paste_image_dialog_controller_on_cancelled (NautilusPasteImageDialogController *controller,
+ gpointer user_data)
+{
+ g_object_unref (controller);
+}
+
typedef struct
{
NautilusFilesView *view;
@@ -2765,6 +2781,26 @@ paste_value_received_callback (GObject *source_object,
paste_callback_data_free (data);
}
+static void
+paste_image_received_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GdkClipboard *clipboard;
+ const GValue *value;
+ NautilusPasteImageDialogController *controller = user_data;
+
+ clipboard = GDK_CLIPBOARD (source_object);
+
+ value = gdk_clipboard_read_value_finish (clipboard, result, NULL);
+
+ if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
+ {
+ GdkPixbuf *pixbuf = g_value_get_object (value);
+ nautilus_paste_image_dialog_controller_set_pixbuf (controller, pixbuf);
+ }
+}
+
static void
paste_files (NautilusFilesView *view,
PasteCallbackData *data)
@@ -2795,6 +2831,17 @@ 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_PIXBUF))
+ {
+ g_autoptr (NautilusDirectory) destination_directory = nautilus_directory_get_by_uri (data->dest_uri);
+
+ NautilusPasteImageDialogController *controller = nautilus_paste_image_dialog_controller_new
(nautilus_files_view_get_containing_window (data->view),
+
destination_directory);
+ g_signal_connect (controller, "name-accepted", G_CALLBACK
(paste_image_dialog_controller_on_name_accepted), NULL);
+ g_signal_connect (controller, "cancelled", G_CALLBACK (paste_image_dialog_controller_on_cancelled),
NULL);
+ gdk_clipboard_read_value_async (clipboard, GDK_TYPE_PIXBUF, 0, priv->clipboard_cancellable,
paste_image_received_callback, controller);
+ paste_callback_data_free (data);
+ }
}
static void
@@ -7211,7 +7258,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_PIXBUF);
action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
"paste");
diff --git a/src/nautilus-paste-image-dialog-controller.c b/src/nautilus-paste-image-dialog-controller.c
new file mode 100644
index 000000000..6976caf0e
--- /dev/null
+++ b/src/nautilus-paste-image-dialog-controller.c
@@ -0,0 +1,163 @@
+/* nautilus-new-folder-dialog-controller.c
+ *
+ * Copyright (C) 2016 the Nautilus developers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib/gi18n.h>
+
+#include "nautilus-paste-image-dialog-controller.h"
+
+
+struct _NautilusPasteImageDialogController
+{
+ NautilusFileNameWidgetController parent_instance;
+
+ GdkPixbuf *pixbuf;
+ gchar *dest_uri;
+ GtkWidget *combo;
+ GtkWidget *entry;
+ GtkWidget *dialog;
+ GtkWidget *preview;
+ GtkWidget *spinner;
+
+ gulong response_handler_id;
+};
+
+G_DEFINE_TYPE (NautilusPasteImageDialogController, nautilus_paste_image_dialog_controller,
NAUTILUS_TYPE_FILE_NAME_WIDGET_CONTROLLER)
+
+static void
+paste_image_dialog_controller_on_response (GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data)
+{
+ NautilusPasteImageDialogController *self = user_data;
+
+ if (response_id != GTK_RESPONSE_OK)
+ {
+ g_signal_emit_by_name (self, "cancelled");
+ }
+}
+
+static gchar *
+real_get_new_name (NautilusFileNameWidgetController *self)
+{
+ NautilusPasteImageDialogController *controller = NAUTILUS_PASTE_IMAGE_DIALOG_CONTROLLER (self);
+ const char *extension = gtk_combo_box_get_active_id (GTK_COMBO_BOX (controller->combo));
+
+ return g_strstrip (g_strdup_printf ("%s.%s", gtk_editable_get_text (GTK_EDITABLE (controller->entry)),
extension));
+}
+
+void
+nautilus_paste_image_dialog_controller_save_pixbuf (NautilusPasteImageDialogController *self)
+{
+ g_autoptr (GFile) parent = g_file_new_for_uri (self->dest_uri);
+ g_autofree gchar *filename = real_get_new_name (NAUTILUS_FILE_NAME_WIDGET_CONTROLLER (self));
+ g_autoptr (GFile) location = g_file_get_child (parent, filename);
+ g_autofree gchar *path = g_file_get_path (location);
+ const char *extension = gtk_combo_box_get_active_id (GTK_COMBO_BOX (self->combo));
+
+ gdk_pixbuf_save (self->pixbuf, path, extension, NULL, NULL);
+}
+
+void nautilus_paste_image_dialog_controller_set_pixbuf (NautilusPasteImageDialogController *self,
+ GdkPixbuf *pixbuf)
+{
+ self->pixbuf = gdk_pixbuf_copy (pixbuf);
+ gtk_widget_set_visible (self->spinner, FALSE);
+ gtk_picture_set_pixbuf (GTK_PICTURE (self->preview), self->pixbuf);
+}
+
+NautilusPasteImageDialogController *
+nautilus_paste_image_dialog_controller_new (GtkWindow *parent_window,
+ NautilusDirectory *destination_directory)
+{
+ NautilusPasteImageDialogController *self;
+ g_autoptr (GtkBuilder) builder = NULL;
+ GtkWidget *paste_image_dialog;
+ GtkWidget *error_revealer;
+ GtkWidget *error_label;
+ GtkWidget *name_entry;
+ GtkWidget *activate_button;
+
+ builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-paste-image-dialog.ui");
+ paste_image_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "paste_image_dialog"));
+ error_revealer = GTK_WIDGET (gtk_builder_get_object (builder, "error_revealer"));
+ error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
+ name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
+ activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
+
+ gtk_window_set_transient_for (GTK_WINDOW (paste_image_dialog),
+ parent_window);
+
+ self = g_object_new (NAUTILUS_TYPE_PASTE_IMAGE_DIALOG_CONTROLLER,
+ "error-revealer", error_revealer,
+ "error-label", error_label,
+ "name-entry", name_entry,
+ "activate-button", activate_button,
+ "containing-directory", destination_directory, NULL);
+
+ self->combo = GTK_WIDGET (gtk_builder_get_object (builder, "combo"));
+ self->entry = name_entry;
+ self->dest_uri = nautilus_directory_get_uri (destination_directory);
+ self->dialog = paste_image_dialog;
+ self->preview = GTK_WIDGET (gtk_builder_get_object (builder, "picture_preview"));
+ self->spinner = GTK_WIDGET (gtk_builder_get_object (builder, "spinner"));
+
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (self->combo), "png");
+
+ g_signal_connect (paste_image_dialog, "response", G_CALLBACK
(paste_image_dialog_controller_on_response), self);
+ gtk_widget_show (paste_image_dialog);
+
+ return self;
+}
+
+static void
+nautilus_paste_image_dialog_controller_init (NautilusPasteImageDialogController *self)
+{
+}
+
+static void
+nautilus_paste_image_dialog_controller_finalize (GObject *object)
+{
+ NautilusPasteImageDialogController *self;
+
+ self = NAUTILUS_PASTE_IMAGE_DIALOG_CONTROLLER (object);
+ g_clear_object (&self->pixbuf);
+ g_free (self->dest_uri);
+ self->dest_uri = NULL;
+
+ if (self->dialog != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (self->dialog, paste_image_dialog_controller_on_response, self);
+
+ gtk_window_destroy (GTK_WINDOW (self->dialog));
+ self->dialog = NULL;
+ }
+
+ G_OBJECT_CLASS (nautilus_paste_image_dialog_controller_parent_class)->finalize (object);
+}
+
+static void
+nautilus_paste_image_dialog_controller_class_init (NautilusPasteImageDialogControllerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NautilusFileNameWidgetControllerClass *parent_class = NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_CLASS (klass);
+
+ object_class->finalize = nautilus_paste_image_dialog_controller_finalize;
+
+ parent_class->get_new_name = real_get_new_name;
+}
diff --git a/src/nautilus-paste-image-dialog-controller.h b/src/nautilus-paste-image-dialog-controller.h
new file mode 100644
index 000000000..5a6b010a8
--- /dev/null
+++ b/src/nautilus-paste-image-dialog-controller.h
@@ -0,0 +1,36 @@
+/* nautilus-rename-file-popover-controller.h
+ *
+ * Copyright (C) 2016 the Nautilus developers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-file-name-widget-controller.h"
+
+#define NAUTILUS_TYPE_PASTE_IMAGE_DIALOG_CONTROLLER nautilus_paste_image_dialog_controller_get_type ()
+G_DECLARE_FINAL_TYPE (NautilusPasteImageDialogController, nautilus_paste_image_dialog_controller, NAUTILUS,
PASTE_IMAGE_DIALOG_CONTROLLER, NautilusFileNameWidgetController)
+
+NautilusPasteImageDialogController * nautilus_paste_image_dialog_controller_new (GtkWindow
*parent_window,
+ NautilusDirectory
*destination_directory);
+
+void nautilus_paste_image_dialog_controller_save_pixbuf (NautilusPasteImageDialogController *self);
+
+void nautilus_paste_image_dialog_controller_set_pixbuf (NautilusPasteImageDialogController *self,
+ GdkPixbuf *pixbuf);
diff --git a/src/resources/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml
index bfe8b2bd3..e1550d5d6 100644
--- a/src/resources/nautilus.gresource.xml
+++ b/src/resources/nautilus.gresource.xml
@@ -28,6 +28,7 @@
<file>ui/nautilus-operations-ui-manager-request-passphrase.ui</file>
<file>ui/nautilus-grid-cell.ui</file>
<file>ui/nautilus-name-cell.ui</file>
+ <file>ui/nautilus-paste-image-dialog.ui</file>
<file alias="gtk/ui/nautilusgtksidebarrow.ui">../gtk/nautilusgtksidebarrow.ui</file>
<file alias="gtk/ui/nautilusgtkplacesview.ui">../gtk/nautilusgtkplacesview.ui</file>
<file alias="gtk/ui/nautilusgtkplacesviewrow.ui">../gtk/nautilusgtkplacesviewrow.ui</file>
diff --git a/src/resources/ui/nautilus-paste-image-dialog.ui b/src/resources/ui/nautilus-paste-image-dialog.ui
new file mode 100644
index 000000000..be9304823
--- /dev/null
+++ b/src/resources/ui/nautilus-paste-image-dialog.ui
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <object class="GtkDialog" id="paste_image_dialog">
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="use-header-bar">1</property>
+ <property name="width_request">450</property>
+ <property name="title" translatable="yes">New Image from Clipboard</property>
+ <child internal-child="content_area">
+ <object class="GtkBox" id="content_area">
+ <property name="orientation">vertical</property>
+ <property name="margin_top">18</property>
+ <property name="margin_bottom">12</property>
+ <property name="margin_start">18</property>
+ <property name="margin_end">18</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinner" id="spinner">
+ <property name="spinning">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="AdwClamp">
+ <property name="maximum-size">320</property>
+ <property name="child">
+ <object class="GtkPicture" id="picture_preview">
+ <property name="content-fit">GTK_CONTENT_FIT_SCALE_DOWN</property>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="name_entry">
+ <property name="placeholder-text" translatable="yes">Enter desired filename for pasted
image</property>
+ <property name="activates-default">true</property>
+ <property name="hexpand">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="combo">
+ <items>
+ <item id="png">png</item>
+ <item id="jpeg">jpeg</item>
+ <item id="bmp">bmp</item>
+ </items>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="error_revealer">
+ <property name="child">
+ <object class="GtkLabel" id="error_label">
+ <property name="margin_top">4</property>
+ <property name="margin_bottom">4</property>
+ <property name="xalign">0</property>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="action">
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">Cancel</property>
+ </object>
+ </child>
+ <child type="action">
+ <object class="GtkButton" id="ok_button">
+ <property name="label" translatable="yes">Save</property>
+ <property name="sensitive">False</property>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="ok" default="true">ok_button</action-widget>
+ <action-widget response="cancel">cancel_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]