r200: Fixed some problems with styles and the collection widget. Still not quite
[rox-filer.git] / ROX-Filer / src / dnd.c
blob5c6c333e8b5b493932e4f983fbf50592a7c26d20
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* dnd.c - code for handling drag and drop */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <string.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xatom.h>
34 #include <gtk/gtk.h>
35 #include "collection.h"
37 #include "filer.h"
38 #include "action.h"
39 #include "pixmaps.h"
40 #include "gui_support.h"
41 #include "support.h"
42 #include "options.h"
43 #include "run.h"
45 #define MAXURILEN 4096 /* Longest URI to allow */
47 /* Static prototypes */
48 static char *get_dest_path(FilerWindow *filer_window, GdkDragContext *context);
49 static void create_uri_list(GString *string,
50 Collection *collection,
51 FilerWindow *filer_window);
52 static gboolean drag_drop(GtkWidget *widget,
53 GdkDragContext *context,
54 gint x,
55 gint y,
56 guint time);
57 static gboolean provides(GdkDragContext *context, GdkAtom target);
58 static void set_xds_prop(GdkDragContext *context, char *text);
59 static gboolean drag_motion(GtkWidget *widget,
60 GdkDragContext *context,
61 gint x,
62 gint y,
63 guint time);
64 static void drag_leave(GtkWidget *widget,
65 GdkDragContext *context);
66 static void drag_data_received(GtkWidget *widget,
67 GdkDragContext *context,
68 gint x,
69 gint y,
70 GtkSelectionData *selection_data,
71 guint info,
72 guint32 time);
73 static void got_data_xds_reply(GtkWidget *widget,
74 GdkDragContext *context,
75 GtkSelectionData *selection_data,
76 guint32 time);
77 static void got_data_raw(GtkWidget *widget,
78 GdkDragContext *context,
79 GtkSelectionData *selection_data,
80 guint32 time);
81 static GSList *uri_list_to_gslist(char *uri_list);
82 static void got_uri_list(GtkWidget *widget,
83 GdkDragContext *context,
84 GtkSelectionData *selection_data,
85 guint32 time);
86 static GtkWidget *create_options();
87 static void update_options();
88 static void set_options();
89 static void save_options();
90 static char *load_no_hostnames(char *data);
92 /* Possible values for drop_dest_type (can also be NULL).
93 * In either case, drop_dest_path is the app/file/dir to use.
95 static char *drop_dest_prog = "drop_dest_prog"; /* Run a program */
96 static char *drop_dest_dir = "drop_dest_dir"; /* Save to path */
98 static OptionsSection options =
100 "Drag and Drop options",
101 create_options,
102 update_options,
103 set_options,
104 save_options
107 enum
109 TARGET_RAW,
110 TARGET_URI_LIST,
111 TARGET_XDS,
114 GdkAtom XdndDirectSave0;
115 GdkAtom xa_text_plain;
116 GdkAtom text_uri_list;
117 GdkAtom application_octet_stream;
119 void dnd_init()
121 XdndDirectSave0 = gdk_atom_intern("XdndDirectSave0", FALSE);
122 xa_text_plain = gdk_atom_intern("text/plain", FALSE);
123 text_uri_list = gdk_atom_intern("text/uri-list", FALSE);
124 application_octet_stream = gdk_atom_intern("application/octet-stream",
125 FALSE);
127 options_sections = g_slist_prepend(options_sections, &options);
128 option_register("dnd_no_hostnames", load_no_hostnames);
131 /* OPTIONS */
133 static gboolean o_no_hostnames = FALSE;
134 static GtkWidget *toggle_no_hostnames;
136 /* Build up some option widgets to go in the options dialog, but don't
137 * fill them in yet.
139 static GtkWidget *create_options()
141 GtkWidget *vbox, *label;
143 vbox = gtk_vbox_new(FALSE, 0);
144 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
146 label = gtk_label_new("Some older applications don't support XDND "
147 "fully and may need to have this option turned on. "
148 "Use this if dragging files to an application shows "
149 "a + sign on the pointer but the drop doesn't work.");
150 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
151 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
153 toggle_no_hostnames =
154 gtk_check_button_new_with_label("Don't use hostnames");
155 gtk_box_pack_start(GTK_BOX(vbox), toggle_no_hostnames, FALSE, TRUE, 0);
157 return vbox;
160 static void update_options()
162 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_no_hostnames),
163 o_no_hostnames);
166 static void set_options()
168 o_no_hostnames = gtk_toggle_button_get_active(
169 GTK_TOGGLE_BUTTON(toggle_no_hostnames));
172 static void save_options()
174 option_write("dnd_no_hostnames", o_no_hostnames ? "1" : "0");
177 static char *load_no_hostnames(char *data)
179 o_no_hostnames = atoi(data) != 0;
180 return NULL;
183 /* SUPPORT FUNCTIONS */
185 static char *get_dest_path(FilerWindow *filer_window, GdkDragContext *context)
187 char *path;
189 path = g_dataset_get_data(context, "drop_dest_path");
191 return path ? path : filer_window->path;
194 /* Set the XdndDirectSave0 property on the source window for this context */
195 static void set_xds_prop(GdkDragContext *context, char *text)
197 gdk_property_change(context->source_window,
198 XdndDirectSave0,
199 xa_text_plain, 8,
200 GDK_PROP_MODE_REPLACE,
201 text,
202 strlen(text));
205 static char *get_xds_prop(GdkDragContext *context)
207 guchar *prop_text;
208 gint length;
210 if (gdk_property_get(context->source_window,
211 XdndDirectSave0,
212 xa_text_plain,
213 0, MAXURILEN,
214 FALSE,
215 NULL, NULL,
216 &length, &prop_text) && prop_text)
218 /* Terminate the string */
219 prop_text = g_realloc(prop_text, length + 1);
220 prop_text[length] = '\0';
221 return prop_text;
224 return NULL;
227 /* Is the sender willing to supply this target type? */
228 static gboolean provides(GdkDragContext *context, GdkAtom target)
230 GList *targets = context->targets;
232 while (targets && ((GdkAtom) targets->data != target))
233 targets = targets->next;
235 return targets != NULL;
238 /* Convert a list of URIs into a list of strings.
239 * Lines beginning with # are skipped.
240 * The text block passed in is zero terminated (after the final CRLF)
242 static GSList *uri_list_to_gslist(char *uri_list)
244 GSList *list = NULL;
246 while (*uri_list)
248 char *linebreak;
249 char *uri;
250 int length;
252 linebreak = strchr(uri_list, 13);
254 if (!linebreak || linebreak[1] != 10)
256 delayed_error("uri_list_to_gslist",
257 "Incorrect or missing line break "
258 "in text/uri-list data");
259 return list;
262 length = linebreak - uri_list;
264 if (length && uri_list[0] != '#')
266 uri = g_malloc(sizeof(char) * (length + 1));
267 strncpy(uri, uri_list, length);
268 uri[length] = 0;
269 list = g_slist_append(list, uri);
272 uri_list = linebreak + 2;
275 return list;
278 /* Append all the URIs in the selection to the string */
279 static void create_uri_list(GString *string,
280 Collection *collection,
281 FilerWindow *filer_window)
283 GString *leader;
284 int i, num_selected;
286 leader = g_string_new("file://");
287 if (!o_no_hostnames)
288 g_string_append(leader, our_host_name());
289 g_string_append(leader, filer_window->path);
290 if (leader->str[leader->len - 1] != '/')
291 g_string_append_c(leader, '/');
293 num_selected = collection->number_selected;
295 for (i = 0; num_selected > 0; i++)
297 if (collection->items[i].selected)
299 DirItem *item = (DirItem *) collection->items[i].data;
301 g_string_append(string, leader->str);
302 g_string_append(string, item->leafname);
303 g_string_append(string, "\r\n");
304 num_selected--;
308 g_string_free(leader, TRUE);
311 /* DRAGGING FROM US */
313 /* The user has held the mouse button down over an item and moved -
314 * start a drag.
316 * We always provide text/uri-list. If we are dragging a single, regular file
317 * then we also offer application/octet-stream and the type of the file.
319 void drag_selection(Collection *collection,
320 GdkEventMotion *event,
321 gint number_selected,
322 gpointer user_data)
324 FilerWindow *filer_window = (FilerWindow *) user_data;
325 GtkWidget *widget;
326 MaskedPixmap *image;
327 GdkDragContext *context;
328 GtkTargetList *target_list;
329 GtkTargetEntry target_table[] =
331 {"text/uri-list", 0, TARGET_URI_LIST},
332 {"application/octet-stream", 0, TARGET_RAW},
333 {"", 0, TARGET_RAW},
335 DirItem *item;
337 if (number_selected == 1)
338 item = selected_item(collection);
339 else
340 item = NULL;
342 widget = GTK_WIDGET(collection);
344 if (item && item->mime_type)
346 MIME_type *t = item->mime_type;
348 target_table[2].target = g_strconcat(t->media_type, "/",
349 t->subtype, NULL);
350 target_list = gtk_target_list_new(target_table, 3);
351 g_free(target_table[2].target);
353 else
354 target_list = gtk_target_list_new(target_table, 1);
356 context = gtk_drag_begin(widget,
357 target_list,
358 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK,
359 (event->state & GDK_BUTTON1_MASK) ? 1 : 2,
360 (GdkEvent *) event);
361 g_dataset_set_data(context, "filer_window", filer_window);
363 image = item ? item->image : &default_pixmap[TYPE_MULTIPLE];
365 gtk_drag_set_icon_pixmap(context,
366 gtk_widget_get_colormap(widget),
367 image->pixmap,
368 image->mask,
369 0, 0);
372 /* Called when a remote app wants us to send it some data.
373 * TODO: Maybe we should handle errors better (ie, let the remote app know
374 * the drag has failed)?
376 void drag_data_get(GtkWidget *widget,
377 GdkDragContext *context,
378 GtkSelectionData *selection_data,
379 guint info,
380 guint32 time)
382 char *to_send = "E"; /* Default to sending an error */
383 long to_send_length = 1;
384 gboolean delete_once_sent = FALSE;
385 GdkAtom type = XA_STRING;
386 GString *string;
387 FilerWindow *filer_window;
388 DirItem *item;
390 filer_window = g_dataset_get_data(context, "filer_window");
391 g_return_if_fail(filer_window != NULL);
393 switch (info)
395 case TARGET_RAW:
396 item = selected_item(filer_window->collection);
397 if (item && load_file(make_path(filer_window->path,
398 item->leafname)->str,
399 &to_send, &to_send_length))
401 delete_once_sent = TRUE;
402 type = selection_data->type;
403 break;
405 g_warning("drag_data_get: Can't find selected item\n");
406 return;
407 case TARGET_URI_LIST:
408 string = g_string_new(NULL);
409 create_uri_list(string,
410 COLLECTION(widget),
411 filer_window);
412 to_send = string->str;
413 to_send_length = string->len;
414 delete_once_sent = TRUE;
415 g_string_free(string, FALSE);
416 break;
417 default:
418 delayed_error("drag_data_get",
419 "Internal error - bad info type\n");
420 break;
423 gtk_selection_data_set(selection_data,
424 type,
426 to_send,
427 to_send_length);
429 if (delete_once_sent)
430 g_free(to_send);
432 collection_clear_selection(filer_window->collection);
435 /* DRAGGING TO US */
437 /* Set up this filer window as a drop target. Called once, when the
438 * filer window is first created.
440 void drag_set_dest(GtkWidget *widget, FilerWindow *filer_window)
442 GtkTargetEntry target_table[] =
444 {"text/uri-list", 0, TARGET_URI_LIST},
445 {"XdndDirectSave0", 0, TARGET_XDS},
446 {"application/octet-stream", 0, TARGET_RAW},
449 gtk_drag_dest_set(widget,
450 0, /* GTK_DEST_DEFAULT_MOTION, */
451 target_table,
452 sizeof(target_table) / sizeof(*target_table),
453 GDK_ACTION_COPY | GDK_ACTION_MOVE
454 | GDK_ACTION_LINK | GDK_ACTION_PRIVATE);
456 gtk_signal_connect(GTK_OBJECT(widget), "drag_motion",
457 GTK_SIGNAL_FUNC(drag_motion), filer_window);
458 gtk_signal_connect(GTK_OBJECT(widget), "drag_leave",
459 GTK_SIGNAL_FUNC(drag_leave), filer_window);
460 gtk_signal_connect(GTK_OBJECT(widget), "drag_drop",
461 GTK_SIGNAL_FUNC(drag_drop), filer_window);
462 gtk_signal_connect(GTK_OBJECT(widget), "drag_data_received",
463 GTK_SIGNAL_FUNC(drag_data_received), filer_window);
466 /* Called during the drag when the mouse is in a widget registered
467 * as a drop target. Returns TRUE if we can accept the drop.
469 static gboolean drag_motion(GtkWidget *widget,
470 GdkDragContext *context,
471 gint x,
472 gint y,
473 guint time)
475 FilerWindow *filer_window;
476 DirItem *item;
477 int item_number;
478 GdkDragAction action = context->suggested_action;
479 char *new_path = NULL;
480 char *type = NULL;
482 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
483 g_return_val_if_fail(filer_window != NULL, TRUE);
485 item_number = collection_get_item(filer_window->collection, x, y);
487 item = item_number >= 0
488 ? (DirItem *) filer_window->collection->items[item_number].data
489 : NULL;
491 if (item && !(item->flags & (ITEM_FLAG_APPDIR | ITEM_FLAG_EXEC_FILE)))
492 item = NULL; /* Drop onto non-executable == no item */
494 if (!item)
496 /* Drop onto the window background */
497 collection_set_cursor_item(filer_window->collection,
498 -1);
500 if (gtk_drag_get_source_widget(context) == widget)
501 goto out;
503 if (access(filer_window->path, W_OK) != 0)
504 goto out; /* No write permission */
506 if (filer_window->panel_type != PANEL_NO)
508 if (context->actions & GDK_ACTION_LINK)
510 action = GDK_ACTION_LINK;
511 type = drop_dest_dir;
514 else
515 type = drop_dest_dir;
517 if (type)
518 new_path = g_strdup(filer_window->path);
520 else
522 /* Drop onto a program of some sort */
523 if (!(provides(context, text_uri_list) ||
524 provides(context, application_octet_stream)))
525 goto out;
527 if (gtk_drag_get_source_widget(context) == widget)
529 Collection *collection = filer_window->collection;
531 if (collection->items[item_number].selected)
532 goto out;
535 /* Actually, we should probably allow any data type */
536 type = drop_dest_prog;
537 new_path = make_path(filer_window->path,
538 item->leafname)->str;
539 collection_set_cursor_item(filer_window->collection,
540 item_number);
543 out:
544 g_dataset_set_data(context, "drop_dest_type", type);
545 if (type)
547 gdk_drag_status(context, action, time);
548 g_dataset_set_data_full(context, "drop_dest_path",
549 g_strdup(new_path), g_free);
551 else
552 g_free(new_path);
554 return type != NULL;
557 /* Remove panel highlights */
558 static void drag_leave(GtkWidget *widget,
559 GdkDragContext *context)
561 FilerWindow *filer_window;
563 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
564 g_return_if_fail(filer_window != NULL);
566 collection_set_cursor_item(filer_window->collection, -1);
569 /* User has tried to drop some data on us. Decide what format we would
570 * like the data in.
572 static gboolean drag_drop(GtkWidget *widget,
573 GdkDragContext *context,
574 gint x,
575 gint y,
576 guint time)
578 char *error = NULL;
579 char *leafname = NULL;
580 FilerWindow *filer_window;
581 GdkAtom target = GDK_NONE;
582 char *dest_path;
583 char *dest_type = NULL;
585 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
586 g_return_val_if_fail(filer_window != NULL, TRUE);
588 dest_path = g_dataset_get_data(context, "drop_dest_path");
589 dest_type = g_dataset_get_data(context, "drop_dest_type");
591 g_return_val_if_fail(dest_path != NULL, TRUE);
593 if (dest_type == drop_dest_dir && provides(context, XdndDirectSave0))
595 leafname = get_xds_prop(context);
596 if (leafname)
598 if (strchr(leafname, '/'))
600 error = "XDS protocol error: "
601 "leafname may not contain '/'\n";
602 g_free(leafname);
604 leafname = NULL;
606 else
608 GString *uri;
610 uri = g_string_new(NULL);
611 g_string_sprintf(uri, "file://%s%s",
612 our_host_name(),
613 make_path(dest_path,
614 leafname)->str);
615 set_xds_prop(context, uri->str);
616 g_string_free(uri, TRUE);
618 target = XdndDirectSave0;
619 g_dataset_set_data_full(context, "leafname",
620 leafname, g_free);
623 else
624 error = "XdndDirectSave0 target provided, but the atom "
625 "XdndDirectSave0 (type text/plain) did not "
626 "contain a leafname\n";
628 else if (provides(context, text_uri_list))
629 target = text_uri_list;
630 else if (provides(context, application_octet_stream))
631 target = application_octet_stream;
632 else
634 if (dest_type == drop_dest_dir)
635 error = "Sorry - I require a target type of "
636 "text/uri-list or XdndDirectSave0.";
637 else
638 error = "Sorry - I require a target type of "
639 "text/uri-list or application/octet-stream.";
642 if (error)
644 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
646 delayed_error("ROX-Filer", error);
648 else
649 gtk_drag_get_data(widget, context, target, time);
651 return TRUE;
654 /* Called when some data arrives from the remote app (which we asked for
655 * in drag_drop).
657 static void drag_data_received(GtkWidget *widget,
658 GdkDragContext *context,
659 gint x,
660 gint y,
661 GtkSelectionData *selection_data,
662 guint info,
663 guint32 time)
665 if (!selection_data->data)
667 /* Timeout? */
668 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
669 return;
672 switch (info)
674 case TARGET_XDS:
675 got_data_xds_reply(widget, context,
676 selection_data, time);
677 break;
678 case TARGET_RAW:
679 got_data_raw(widget, context, selection_data, time);
680 break;
681 case TARGET_URI_LIST:
682 got_uri_list(widget, context, selection_data, time);
683 break;
684 default:
685 gtk_drag_finish(context, FALSE, FALSE, time);
686 delayed_error("drag_data_received", "Unknown target");
687 break;
691 static void got_data_xds_reply(GtkWidget *widget,
692 GdkDragContext *context,
693 GtkSelectionData *selection_data,
694 guint32 time)
696 gboolean mark_unsafe = TRUE;
697 char response = *selection_data->data;
698 char *error = NULL;
700 if (selection_data->length != 1)
701 response = '?';
703 if (response == 'F')
705 /* Sender couldn't save there - ask for another
706 * type if possible.
708 if (provides(context, application_octet_stream))
710 mark_unsafe = FALSE; /* Wait and see */
712 gtk_drag_get_data(widget, context,
713 application_octet_stream, time);
715 else
716 error = "Remote app can't or won't send me "
717 "the data - sorry";
719 else if (response == 'S')
721 FilerWindow *filer_window;
723 /* Success - data is saved */
724 mark_unsafe = FALSE; /* It really is safe */
725 gtk_drag_finish(context, TRUE, FALSE, time);
727 filer_window = gtk_object_get_data(GTK_OBJECT(widget),
728 "filer_window");
729 g_return_if_fail(filer_window != NULL);
731 update_dir(filer_window, TRUE);
733 else if (response != 'E')
735 error = "XDS protocol error: "
736 "return code should be 'S', 'F' or 'E'\n";
738 /* else: error has been reported by the sender */
740 if (mark_unsafe)
742 set_xds_prop(context, "");
743 /* Unsave also implies that the drag failed */
744 gtk_drag_finish(context, FALSE, FALSE, time);
747 if (error)
748 delayed_error("ROX-Filer", error);
751 static void got_data_raw(GtkWidget *widget,
752 GdkDragContext *context,
753 GtkSelectionData *selection_data,
754 guint32 time)
756 FilerWindow *filer_window;
757 char *leafname;
758 int fd;
759 char *error = NULL;
760 char *dest_path;
762 g_return_if_fail(selection_data->data != NULL);
764 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
765 g_return_if_fail(filer_window != NULL);
766 dest_path = get_dest_path(filer_window, context);
768 if (g_dataset_get_data(context, "drop_dest_type") == drop_dest_prog)
770 /* The data needs to be sent to an application */
771 run_with_data(dest_path,
772 selection_data->data, selection_data->length);
773 gtk_drag_finish(context, TRUE, FALSE, time); /* Success! */
774 return;
777 leafname = g_dataset_get_data(context, "leafname");
778 if (!leafname)
779 leafname = "UntitledData";
781 fd = open(make_path(dest_path, leafname)->str,
782 O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY,
783 S_IRUSR | S_IRGRP | S_IROTH |
784 S_IWUSR | S_IWGRP | S_IWOTH);
786 if (fd == -1)
787 error = g_strerror(errno);
788 else
790 if (write(fd,
791 selection_data->data,
792 selection_data->length) == -1)
793 error = g_strerror(errno);
795 if (close(fd) == -1 && !error)
796 error = g_strerror(errno);
798 update_dir(filer_window, TRUE);
801 if (error)
803 if (provides(context, XdndDirectSave0))
804 set_xds_prop(context, "");
805 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
806 delayed_error("Error saving file", error);
808 else
809 gtk_drag_finish(context, TRUE, FALSE, time); /* Success! */
812 /* We've got a list of URIs from somewhere (probably another filer window).
813 * If the files are on the local machine then try to copy them ourselves,
814 * otherwise, if there was only one file and application/octet-stream was
815 * provided, get the data via the X server.
817 static void got_uri_list(GtkWidget *widget,
818 GdkDragContext *context,
819 GtkSelectionData *selection_data,
820 guint32 time)
822 FilerWindow *filer_window;
823 GSList *uri_list;
824 char *error = NULL;
825 GSList *next_uri;
826 gboolean send_reply = TRUE;
827 char *dest_path;
828 char *type;
830 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
831 g_return_if_fail(filer_window != NULL);
833 dest_path = get_dest_path(filer_window, context);
834 type = g_dataset_get_data(context, "drop_dest_type");
836 uri_list = uri_list_to_gslist(selection_data->data);
838 if (!uri_list)
839 error = "No URIs in the text/uri-list (nothing to do!)";
840 else if (type == drop_dest_prog)
841 run_with_files(dest_path, uri_list);
842 else if ((!uri_list->next) && (!get_local_path(uri_list->data)))
844 /* There is one URI in the list, and it's not on the local
845 * machine. Get it via the X server if possible.
848 if (provides(context, application_octet_stream))
850 char *leaf;
851 leaf = strrchr(uri_list->data, '/');
852 if (leaf)
853 leaf++;
854 else
855 leaf = uri_list->data;
856 g_dataset_set_data_full(context, "leafname",
857 g_strdup(leaf), g_free);
858 gtk_drag_get_data(widget, context,
859 application_octet_stream, time);
860 send_reply = FALSE;
862 else
863 error = "Can't get data from remote machine "
864 "(application/octet-stream not provided)";
866 else
868 GSList *local_paths = NULL;
869 GSList *next;
871 /* Either one local URI, or a list. If everything in the list
872 * isn't local then we are stuck.
875 for (next_uri = uri_list; next_uri; next_uri = next_uri->next)
877 char *path;
879 path = get_local_path((char *) next_uri->data);
881 if (path)
882 local_paths = g_slist_append(local_paths,
883 g_strdup(path));
884 else
885 error = "Some of these files are on a "
886 "different machine - they will be "
887 "ignored - sorry";
890 if (!local_paths)
892 error = "None of these files are on the local machine "
893 "- I can't operate on multiple remote files - "
894 "sorry.";
896 else if (context->action == GDK_ACTION_MOVE)
897 action_move(local_paths, dest_path);
898 else if (context->action == GDK_ACTION_COPY)
899 action_copy(local_paths, dest_path);
900 else if (context->action == GDK_ACTION_LINK)
901 action_link(local_paths, dest_path);
902 else
903 error = "Unknown action requested";
905 for (next = local_paths; next; next = next->next)
906 g_free(next->data);
907 g_slist_free(local_paths);
910 if (error)
912 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
913 delayed_error("Error getting file list", error);
915 else if (send_reply)
916 gtk_drag_finish(context, TRUE, FALSE, time); /* Success! */
918 next_uri = uri_list;
919 while (next_uri)
921 g_free(next_uri->data);
922 next_uri = next_uri->next;
924 g_slist_free(uri_list);