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