No issues found
1 /*
2 * nautilus-window-slot-dnd.c - Handle DnD for widgets acting as
3 * NautilusWindowSlot proxies
4 *
5 * Copyright (C) 2000, 2001 Eazel, Inc.
6 * Copyright (C) 2010, Red Hat, Inc.
7 *
8 * The Gnome Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * The Gnome Library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with the Gnome Library; see the file COPYING.LIB. If not,
20 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 * Authors: Pavel Cisler <pavel@eazel.com>,
24 * Ettore Perazzoli <ettore@gnu.org>
25 */
26
27 #include <config.h>
28
29 #include "nautilus-view-dnd.h"
30 #include "nautilus-window-slot-dnd.h"
31
32 typedef struct {
33 gboolean have_data;
34 gboolean have_valid_data;
35
36 gboolean drop_occured;
37
38 unsigned int info;
39 union {
40 GList *selection_list;
41 GList *uri_list;
42 char *netscape_url;
43 } data;
44
45 NautilusFile *target_file;
46 NautilusWindowSlot *target_slot;
47 } NautilusDragSlotProxyInfo;
48
49 static gboolean
50 slot_proxy_drag_motion (GtkWidget *widget,
51 GdkDragContext *context,
52 int x,
53 int y,
54 unsigned int time,
55 gpointer user_data)
56 {
57 NautilusDragSlotProxyInfo *drag_info;
58 NautilusWindowSlot *target_slot;
59 GtkWidget *window;
60 GdkAtom target;
61 int action;
62 char *target_uri;
63
64 drag_info = user_data;
65
66 action = 0;
67
68 if (gtk_drag_get_source_widget (context) == widget) {
69 goto out;
70 }
71
72 window = gtk_widget_get_toplevel (widget);
73 g_assert (NAUTILUS_IS_WINDOW (window));
74
75 if (!drag_info->have_data) {
76 target = gtk_drag_dest_find_target (widget, context, NULL);
77
78 if (target == GDK_NONE) {
79 goto out;
80 }
81
82 gtk_drag_get_data (widget, context, target, time);
83 }
84
85 target_uri = NULL;
86 if (drag_info->target_file != NULL) {
87 target_uri = nautilus_file_get_uri (drag_info->target_file);
88 } else {
89 if (drag_info->target_slot != NULL) {
90 target_slot = drag_info->target_slot;
91 } else {
92 target_slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (window));
93 }
94
95 if (target_slot != NULL) {
96 target_uri = nautilus_window_slot_get_current_uri (target_slot);
97 }
98 }
99
100 if (target_uri != NULL) {
101 NautilusFile *file;
102 gboolean can;
103 file = nautilus_file_get_existing_by_uri (target_uri);
104 can = nautilus_file_can_write (file);
105 g_object_unref (file);
106 if (!can) {
107 action = 0;
108 goto out;
109 }
110 }
111
112 if (drag_info->have_data &&
113 drag_info->have_valid_data) {
114 if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
115 nautilus_drag_default_drop_action_for_icons (context, target_uri,
116 drag_info->data.selection_list,
117 &action);
118 } else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) {
119 action = nautilus_drag_default_drop_action_for_uri_list (context, target_uri);
120 } else if (drag_info->info == NAUTILUS_ICON_DND_NETSCAPE_URL) {
121 action = nautilus_drag_default_drop_action_for_netscape_url (context);
122 }
123 }
124
125 g_free (target_uri);
126
127 out:
128 if (action != 0) {
129 gtk_drag_highlight (widget);
130 } else {
131 gtk_drag_unhighlight (widget);
132 }
133
134 gdk_drag_status (context, action, time);
135
136 return TRUE;
137 }
138
139 static void
140 drag_info_free (gpointer user_data)
141 {
142 NautilusDragSlotProxyInfo *drag_info = user_data;
143
144 g_clear_object (&drag_info->target_file);
145 g_clear_object (&drag_info->target_slot);
146
147 g_slice_free (NautilusDragSlotProxyInfo, drag_info);
148 }
149
150 static void
151 drag_info_clear (NautilusDragSlotProxyInfo *drag_info)
152 {
153 if (!drag_info->have_data) {
154 goto out;
155 }
156
157 if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
158 nautilus_drag_destroy_selection_list (drag_info->data.selection_list);
159 } else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) {
160 g_list_free (drag_info->data.uri_list);
161 } else if (drag_info->info == NAUTILUS_ICON_DND_NETSCAPE_URL) {
162 g_free (drag_info->data.netscape_url);
163 }
164
165 out:
166 drag_info->have_data = FALSE;
167 drag_info->have_valid_data = FALSE;
168
169 drag_info->drop_occured = FALSE;
170 }
171
172 static void
173 slot_proxy_drag_leave (GtkWidget *widget,
174 GdkDragContext *context,
175 unsigned int time,
176 gpointer user_data)
177 {
178 NautilusDragSlotProxyInfo *drag_info;
179
180 drag_info = user_data;
181
182 gtk_drag_unhighlight (widget);
183 drag_info_clear (drag_info);
184 }
185
186 static gboolean
187 slot_proxy_drag_drop (GtkWidget *widget,
188 GdkDragContext *context,
189 int x,
190 int y,
191 unsigned int time,
192 gpointer user_data)
193 {
194 GdkAtom target;
195 NautilusDragSlotProxyInfo *drag_info;
196
197 drag_info = user_data;
198 g_assert (!drag_info->have_data);
199
200 drag_info->drop_occured = TRUE;
201
202 target = gtk_drag_dest_find_target (widget, context, NULL);
203 gtk_drag_get_data (widget, context, target, time);
204
205 return TRUE;
206 }
207
208
209 static void
210 slot_proxy_handle_drop (GtkWidget *widget,
211 GdkDragContext *context,
212 unsigned int time,
213 NautilusDragSlotProxyInfo *drag_info)
214 {
215 GtkWidget *window;
216 NautilusWindowSlot *target_slot;
217 NautilusView *target_view;
218 char *target_uri;
219 GList *uri_list;
220
221 if (!drag_info->have_data ||
222 !drag_info->have_valid_data) {
223 gtk_drag_finish (context, FALSE, FALSE, time);
224 drag_info_clear (drag_info);
225 return;
226 }
227
228 window = gtk_widget_get_toplevel (widget);
229 g_assert (NAUTILUS_IS_WINDOW (window));
230
231 if (drag_info->target_slot != NULL) {
232 target_slot = drag_info->target_slot;
233 } else {
234 target_slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (window));
235 }
236
237 target_uri = NULL;
238 if (drag_info->target_file != NULL) {
239 target_uri = nautilus_file_get_uri (drag_info->target_file);
240 } else if (target_slot != NULL) {
241 target_uri = nautilus_window_slot_get_current_uri (target_slot);
242 }
243
244 target_view = NULL;
245 if (target_slot != NULL) {
246 target_view = nautilus_window_slot_get_current_view (target_slot);
247 }
248
249 if (target_slot != NULL && target_view != NULL) {
250 if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
251 uri_list = nautilus_drag_uri_list_from_selection_list (drag_info->data.selection_list);
252 g_assert (uri_list != NULL);
253
254 nautilus_view_drop_proxy_received_uris (target_view,
255 uri_list,
256 target_uri,
257 gdk_drag_context_get_selected_action (context));
258 g_list_free_full (uri_list, g_free);
259 } else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) {
260 nautilus_view_drop_proxy_received_uris (target_view,
261 drag_info->data.uri_list,
262 target_uri,
263 gdk_drag_context_get_selected_action (context));
264 } if (drag_info->info == NAUTILUS_ICON_DND_NETSCAPE_URL) {
265 nautilus_view_handle_netscape_url_drop (target_view,
266 drag_info->data.netscape_url,
267 target_uri,
268 gdk_drag_context_get_selected_action (context),
269 0, 0);
270 }
271
272
273 gtk_drag_finish (context, TRUE, FALSE, time);
274 } else {
275 gtk_drag_finish (context, FALSE, FALSE, time);
276 }
277
278 g_free (target_uri);
279
280 drag_info_clear (drag_info);
281 }
282
283 static void
284 slot_proxy_drag_data_received (GtkWidget *widget,
285 GdkDragContext *context,
286 int x,
287 int y,
288 GtkSelectionData *data,
289 unsigned int info,
290 unsigned int time,
291 gpointer user_data)
292 {
293 NautilusDragSlotProxyInfo *drag_info;
294 char **uris;
295
296 drag_info = user_data;
297
298 g_assert (!drag_info->have_data);
299
300 drag_info->have_data = TRUE;
301 drag_info->info = info;
302
303 if (gtk_selection_data_get_length (data) < 0) {
304 drag_info->have_valid_data = FALSE;
305 return;
306 }
307
308 if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
309 drag_info->data.selection_list = nautilus_drag_build_selection_list (data);
310
311 drag_info->have_valid_data = drag_info->data.selection_list != NULL;
312 } else if (info == NAUTILUS_ICON_DND_URI_LIST) {
313 uris = gtk_selection_data_get_uris (data);
314 drag_info->data.uri_list = nautilus_drag_uri_list_from_array ((const char **) uris);
315 g_strfreev (uris);
316
317 drag_info->have_valid_data = drag_info->data.uri_list != NULL;
318 } else if (info == NAUTILUS_ICON_DND_NETSCAPE_URL) {
319 drag_info->data.netscape_url = g_strdup ((char *) gtk_selection_data_get_data (data));
320
321 drag_info->have_valid_data = drag_info->data.netscape_url != NULL;
322 }
323
324 if (drag_info->drop_occured) {
325 slot_proxy_handle_drop (widget, context, time, drag_info);
326 }
327 }
328
329 void
330 nautilus_drag_slot_proxy_init (GtkWidget *widget,
331 NautilusFile *target_file,
332 NautilusWindowSlot *target_slot)
333 {
334 NautilusDragSlotProxyInfo *drag_info;
335
336 const GtkTargetEntry targets[] = {
337 { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
338 { NAUTILUS_ICON_DND_NETSCAPE_URL_TYPE, 0, NAUTILUS_ICON_DND_NETSCAPE_URL }
339 };
340 GtkTargetList *target_list;
341
342 g_assert (GTK_IS_WIDGET (widget));
343
344 drag_info = g_slice_new0 (NautilusDragSlotProxyInfo);
345
346 g_object_set_data_full (G_OBJECT (widget), "drag-slot-proxy-data", drag_info,
347 drag_info_free);
348
349 if (target_file != NULL)
350 drag_info->target_file = g_object_ref (target_file);
351
352 if (target_slot != NULL)
353 drag_info->target_slot = g_object_ref (target_slot);
354
355 gtk_drag_dest_set (widget, 0,
356 NULL, 0,
357 GDK_ACTION_MOVE |
358 GDK_ACTION_COPY |
359 GDK_ACTION_LINK |
360 GDK_ACTION_ASK);
361
362 target_list = gtk_target_list_new (targets, G_N_ELEMENTS (targets));
363 gtk_target_list_add_uri_targets (target_list, NAUTILUS_ICON_DND_URI_LIST);
364 gtk_drag_dest_set_target_list (widget, target_list);
365 gtk_target_list_unref (target_list);
366
367 g_signal_connect (widget, "drag-motion",
368 G_CALLBACK (slot_proxy_drag_motion),
369 drag_info);
370 g_signal_connect (widget, "drag-drop",
371 G_CALLBACK (slot_proxy_drag_drop),
372 drag_info);
373 g_signal_connect (widget, "drag-data-received",
374 G_CALLBACK (slot_proxy_drag_data_received),
375 drag_info);
376 g_signal_connect (widget, "drag-leave",
377 G_CALLBACK (slot_proxy_drag_leave),
378 drag_info);
379 }