/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis * * pikadnd-xds.c * Copyright (C) 2005 Sven Neumann * * Saving Files via Drag-and-Drop: * The Direct Save Protocol for the X Window System * * http://www.newplanetsoftware.com/xds/ * http://rox.sourceforge.net/xds.html * * 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 3 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 . */ #include "config.h" #include #include #include #include "libpikabase/pikabase.h" #include "libpikawidgets/pikawidgets.h" #include "widgets-types.h" #include "core/pika.h" #include "core/pika-utils.h" #include "core/pikaimage.h" #include "plug-in/pikapluginmanager-file.h" #include "file/file-save.h" #include "pikadnd-xds.h" #include "pikafiledialog.h" #include "pikamessagebox.h" #include "pikamessagedialog.h" #include "pika-log.h" #include "pika-intl.h" #define MAX_URI_LEN 4096 /* local function prototypes */ static gboolean pika_file_overwrite_dialog (GtkWidget *parent, GFile *file); /* public functions */ void pika_dnd_xds_source_set (GdkDragContext *context, PikaImage *image) { GdkAtom property; g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); g_return_if_fail (image == NULL || PIKA_IS_IMAGE (image)); PIKA_LOG (DND, NULL); property = gdk_atom_intern_static_string ("XdndDirectSave0"); if (image) { GdkAtom type = gdk_atom_intern_static_string ("text/plain"); GFile *untitled; GFile *file; gchar *basename; basename = g_strconcat (_("Untitled"), ".xcf", NULL); untitled = g_file_new_for_path (basename); g_free (basename); file = pika_image_get_any_file (image); if (file) { GFile *xcf_file = pika_file_with_new_extension (file, untitled); basename = g_file_get_basename (xcf_file); g_object_unref (xcf_file); } else { basename = g_file_get_path (untitled); } g_object_unref (untitled); gdk_property_change (gdk_drag_context_get_source_window (context), property, type, 8, GDK_PROP_MODE_REPLACE, (const guchar *) basename, basename ? strlen (basename) : 0); g_free (basename); } else { gdk_property_delete (gdk_drag_context_get_source_window (context), property); } } void pika_dnd_xds_save_image (GdkDragContext *context, PikaImage *image, GtkSelectionData *selection) { PikaPlugInProcedure *proc; GdkAtom property; GdkAtom type; gint length; guchar *data; gchar *uri; GFile *file; gboolean export = FALSE; GError *error = NULL; g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); g_return_if_fail (PIKA_IS_IMAGE (image)); PIKA_LOG (DND, NULL); property = gdk_atom_intern_static_string ("XdndDirectSave0"); type = gdk_atom_intern_static_string ("text/plain"); if (! gdk_property_get (gdk_drag_context_get_source_window (context), property, type, 0, MAX_URI_LEN, FALSE, NULL, NULL, &length, &data)) return; uri = g_strndup ((const gchar *) data, length); g_free (data); file = g_file_new_for_uri (uri); proc = pika_plug_in_manager_file_procedure_find (image->pika->plug_in_manager, PIKA_FILE_PROCEDURE_GROUP_SAVE, file, NULL); if (! proc) { proc = pika_plug_in_manager_file_procedure_find (image->pika->plug_in_manager, PIKA_FILE_PROCEDURE_GROUP_EXPORT, file, NULL); export = TRUE; } if (proc) { if (! g_file_query_exists (file, NULL) || pika_file_overwrite_dialog (NULL, file)) { if (file_save (image->pika, image, NULL, file, proc, PIKA_RUN_INTERACTIVE, ! export, FALSE, export, &error) == PIKA_PDB_SUCCESS) { gtk_selection_data_set (selection, gtk_selection_data_get_target (selection), 8, (const guchar *) "S", 1); } else { gtk_selection_data_set (selection, gtk_selection_data_get_target (selection), 8, (const guchar *) "E", 1); if (error) { pika_message (image->pika, NULL, PIKA_MESSAGE_ERROR, _("Saving '%s' failed:\n\n%s"), pika_file_get_utf8_name (file), error->message); g_clear_error (&error); } } } } else { gtk_selection_data_set (selection, gtk_selection_data_get_target (selection), 8, (const guchar *) "E", 1); pika_message_literal (image->pika, NULL, PIKA_MESSAGE_ERROR, _("The given filename does not have any known " "file extension.")); } g_object_unref (file); g_free (uri); } /* private functions */ static gboolean pika_file_overwrite_dialog (GtkWidget *parent, GFile *file) { GtkWidget *dialog; gboolean overwrite = FALSE; dialog = pika_message_dialog_new (_("File Exists"), PIKA_ICON_DIALOG_WARNING, parent, GTK_DIALOG_DESTROY_WITH_PARENT, pika_standard_help_func, NULL, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Replace"), GTK_RESPONSE_OK, NULL); pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); pika_message_box_set_primary_text (PIKA_MESSAGE_DIALOG (dialog)->box, _("A file named '%s' already exists."), pika_file_get_utf8_name (file)); pika_message_box_set_text (PIKA_MESSAGE_DIALOG (dialog)->box, _("Do you want to replace it with the image " "you are saving?")); if (GTK_IS_DIALOG (parent)) gtk_dialog_set_response_sensitive (GTK_DIALOG (parent), GTK_RESPONSE_CANCEL, FALSE); g_object_ref (dialog); overwrite = (pika_dialog_run (PIKA_DIALOG (dialog)) == GTK_RESPONSE_OK); gtk_widget_destroy (dialog); g_object_unref (dialog); if (GTK_IS_DIALOG (parent)) gtk_dialog_set_response_sensitive (GTK_DIALOG (parent), GTK_RESPONSE_CANCEL, TRUE); return overwrite; }