nautilus-3.6.3/src/nautilus-window-slot-dnd.c

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 }