1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * gimpdnd-xds.c
5  * Copyright (C) 2005  Sven Neumann <sven@gimp.org>
6  *
7  * Saving Files via Drag-and-Drop:
8  * The Direct Save Protocol for the X Window System
9  *
10  *   http://www.newplanetsoftware.com/xds/
11  *   http://rox.sourceforge.net/xds.html
12  *
13  * This program is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
25  */
26 
27 #include "config.h"
28 
29 #include <string.h>
30 
31 #undef GSEAL_ENABLE
32 
33 #include <gegl.h>
34 #include <gtk/gtk.h>
35 
36 #include "libgimpbase/gimpbase.h"
37 #include "libgimpwidgets/gimpwidgets.h"
38 
39 #include "widgets-types.h"
40 
41 #include "core/gimp.h"
42 #include "core/gimp-utils.h"
43 #include "core/gimpimage.h"
44 
45 #include "plug-in/gimppluginmanager-file.h"
46 
47 #include "file/file-save.h"
48 
49 #include "gimpdnd-xds.h"
50 #include "gimpfiledialog.h"
51 #include "gimpmessagebox.h"
52 #include "gimpmessagedialog.h"
53 
54 #include "gimp-log.h"
55 #include "gimp-intl.h"
56 
57 
58 #define MAX_URI_LEN 4096
59 
60 
61 /*  local function prototypes  */
62 
63 static gboolean   gimp_file_overwrite_dialog (GtkWidget *parent,
64                                               GFile     *file);
65 
66 
67 /*  public functions  */
68 
69 void
gimp_dnd_xds_source_set(GdkDragContext * context,GimpImage * image)70 gimp_dnd_xds_source_set (GdkDragContext *context,
71                          GimpImage      *image)
72 {
73   GdkAtom  property;
74 
75   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
76   g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
77 
78   GIMP_LOG (DND, NULL);
79 
80   property = gdk_atom_intern_static_string ("XdndDirectSave0");
81 
82   if (image)
83     {
84       GdkAtom  type = gdk_atom_intern_static_string ("text/plain");
85       GFile   *untitled;
86       GFile   *file;
87       gchar   *basename;
88 
89       basename = g_strconcat (_("Untitled"), ".xcf", NULL);
90       untitled = g_file_new_for_path (basename);
91       g_free (basename);
92 
93       file = gimp_image_get_any_file (image);
94 
95       if (file)
96         {
97           GFile *xcf_file = gimp_file_with_new_extension (file, untitled);
98           basename = g_file_get_basename (xcf_file);
99           g_object_unref (xcf_file);
100         }
101       else
102         {
103           basename = g_file_get_path (untitled);
104         }
105 
106       g_object_unref (untitled);
107 
108       gdk_property_change (context->source_window,
109                            property, type, 8, GDK_PROP_MODE_REPLACE,
110                            (const guchar *) basename,
111                            basename ? strlen (basename) : 0);
112 
113       g_free (basename);
114     }
115   else
116     {
117       gdk_property_delete (context->source_window, property);
118     }
119 }
120 
121 void
gimp_dnd_xds_save_image(GdkDragContext * context,GimpImage * image,GtkSelectionData * selection)122 gimp_dnd_xds_save_image (GdkDragContext   *context,
123                          GimpImage        *image,
124                          GtkSelectionData *selection)
125 {
126   GimpPlugInProcedure *proc;
127   GdkAtom              property;
128   GdkAtom              type;
129   gint                 length;
130   guchar              *data;
131   gchar               *uri;
132   GFile               *file;
133   gboolean             export = FALSE;
134   GError              *error  = NULL;
135 
136   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
137   g_return_if_fail (GIMP_IS_IMAGE (image));
138 
139   GIMP_LOG (DND, NULL);
140 
141   property = gdk_atom_intern_static_string ("XdndDirectSave0");
142   type     = gdk_atom_intern_static_string ("text/plain");
143 
144   if (! gdk_property_get (context->source_window, property, type,
145                           0, MAX_URI_LEN, FALSE,
146                           NULL, NULL, &length, &data))
147     return;
148 
149 
150   uri = g_strndup ((const gchar *) data, length);
151   g_free (data);
152 
153   file = g_file_new_for_uri (uri);
154 
155   proc = gimp_plug_in_manager_file_procedure_find (image->gimp->plug_in_manager,
156                                                    GIMP_FILE_PROCEDURE_GROUP_SAVE,
157                                                    file, NULL);
158   if (! proc)
159     {
160       proc = gimp_plug_in_manager_file_procedure_find (image->gimp->plug_in_manager,
161                                                        GIMP_FILE_PROCEDURE_GROUP_EXPORT,
162                                                        file, NULL);
163       export = TRUE;
164     }
165 
166   if (proc)
167     {
168       if (! g_file_query_exists (file, NULL) ||
169           gimp_file_overwrite_dialog (NULL, file))
170         {
171           if (file_save (image->gimp,
172                          image, NULL,
173                          file, proc, GIMP_RUN_INTERACTIVE,
174                          ! export, FALSE, export,
175                          &error) == GIMP_PDB_SUCCESS)
176             {
177               gtk_selection_data_set (selection,
178                                       gtk_selection_data_get_target (selection),
179                                       8, (const guchar *) "S", 1);
180             }
181           else
182             {
183               gtk_selection_data_set (selection,
184                                       gtk_selection_data_get_target (selection),
185                                       8, (const guchar *) "E", 1);
186 
187               if (error)
188                 {
189                   gimp_message (image->gimp, NULL, GIMP_MESSAGE_ERROR,
190                                 _("Saving '%s' failed:\n\n%s"),
191                                 gimp_file_get_utf8_name (file),
192                                 error->message);
193                   g_clear_error (&error);
194                 }
195             }
196         }
197     }
198   else
199     {
200       gtk_selection_data_set (selection,
201                               gtk_selection_data_get_target (selection),
202                               8, (const guchar *) "E", 1);
203 
204       gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR,
205                             _("The given filename does not have any known "
206                               "file extension."));
207     }
208 
209   g_object_unref (file);
210   g_free (uri);
211 }
212 
213 
214 /*  private functions  */
215 
216 static gboolean
gimp_file_overwrite_dialog(GtkWidget * parent,GFile * file)217 gimp_file_overwrite_dialog (GtkWidget *parent,
218                             GFile     *file)
219 {
220   GtkWidget *dialog;
221   gboolean   overwrite = FALSE;
222 
223   dialog = gimp_message_dialog_new (_("File Exists"),
224                                     GIMP_ICON_DIALOG_WARNING,
225                                     parent, GTK_DIALOG_DESTROY_WITH_PARENT,
226                                     gimp_standard_help_func, NULL,
227 
228                                     _("_Cancel"),  GTK_RESPONSE_CANCEL,
229                                     _("_Replace"), GTK_RESPONSE_OK,
230 
231                                     NULL);
232 
233   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
234                                            GTK_RESPONSE_OK,
235                                            GTK_RESPONSE_CANCEL,
236                                            -1);
237 
238   gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
239                                      _("A file named '%s' already exists."),
240                                      gimp_file_get_utf8_name (file));
241 
242   gimp_message_box_set_text (GIMP_MESSAGE_DIALOG (dialog)->box,
243                              _("Do you want to replace it with the image "
244                                "you are saving?"));
245 
246   if (GTK_IS_DIALOG (parent))
247     gtk_dialog_set_response_sensitive (GTK_DIALOG (parent),
248                                        GTK_RESPONSE_CANCEL, FALSE);
249 
250   g_object_ref (dialog);
251 
252   overwrite = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
253 
254   gtk_widget_destroy (dialog);
255   g_object_unref (dialog);
256 
257   if (GTK_IS_DIALOG (parent))
258     gtk_dialog_set_response_sensitive (GTK_DIALOG (parent),
259                                        GTK_RESPONSE_CANCEL, TRUE);
260 
261   return overwrite;
262 }
263