r39: Dropping on the panel now works correctly.
[rox-filer.git] / ROX-Filer / src / dnd.c
blob8d29ace712c1fca1822754cb54682f0c36d708d7
1 /* vi: set cindent:
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
6 */
8 /* dnd.c - code for handling drag and drop */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <errno.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xatom.h>
20 #include <gtk/gtk.h>
21 #include <collection.h>
23 #include "filer.h"
24 #include "pixmaps.h"
25 #include "gui_support.h"
26 #include "support.h"
28 #define MAXURILEN 4096 /* Longest URI to allow */
30 /* Possible values for drop_dest_type (can also be NULL).
31 * In either case, drop_dest_path is the app/file/dir to use.
33 static char *drop_dest_prog = "drop_dest_prog"; /* Run a program */
34 static char *drop_dest_dir = "drop_dest_dir"; /* Save to path */
36 enum
38 TARGET_RAW,
39 TARGET_URI_LIST,
40 TARGET_XDS,
43 GdkAtom XdndDirectSave0;
44 GdkAtom text_plain;
45 GdkAtom text_uri_list;
46 GdkAtom application_octet_stream;
48 /* Static prototypes */
49 static char *get_dest_path(FilerWindow *filer_window, GdkDragContext *context);
50 static void create_uri_list(GString *string,
51 Collection *collection,
52 FilerWindow *filer_window);
53 static gboolean drag_drop(GtkWidget *widget,
54 GdkDragContext *context,
55 gint x,
56 gint y,
57 guint time);
58 static gboolean provides(GdkDragContext *context, GdkAtom target);
59 static void set_xds_prop(GdkDragContext *context, char *text);
60 static gboolean drag_motion(GtkWidget *widget,
61 GdkDragContext *context,
62 gint x,
63 gint y,
64 guint time);
65 static void drag_leave(GtkWidget *widget,
66 GdkDragContext *context);
67 static void drag_data_received(GtkWidget *widget,
68 GdkDragContext *context,
69 gint x,
70 gint y,
71 GtkSelectionData *selection_data,
72 guint info,
73 guint32 time);
74 static void got_data_xds_reply(GtkWidget *widget,
75 GdkDragContext *context,
76 GtkSelectionData *selection_data,
77 guint32 time);
78 static void got_data_raw(GtkWidget *widget,
79 GdkDragContext *context,
80 GtkSelectionData *selection_data,
81 guint32 time);
82 static gboolean load_file(char *pathname, char **data_out, long *length_out);
83 static GSList *uri_list_to_gslist(char *uri_list);
84 static void got_uri_list(GtkWidget *widget,
85 GdkDragContext *context,
86 GtkSelectionData *selection_data,
87 guint32 time);
88 char *get_local_path(char *uri);
89 static void run_with_files(char *path, GSList *uri_list);
91 void dnd_init()
93 XdndDirectSave0 = gdk_atom_intern("XdndDirectSave0", FALSE);
94 text_plain = gdk_atom_intern("text/plain", FALSE);
95 text_uri_list = gdk_atom_intern("text/uri-list", FALSE);
96 application_octet_stream = gdk_atom_intern("application/octet-stream",
97 FALSE);
100 static char *get_dest_path(FilerWindow *filer_window, GdkDragContext *context)
102 char *path;
104 path = g_dataset_get_data(context, "drop_dest_path");
106 return path ? path : filer_window->path;
109 /* Set the XdndDirectSave0 property on the source window for this context */
110 static void set_xds_prop(GdkDragContext *context, char *text)
112 gdk_property_change(context->source_window,
113 XdndDirectSave0,
114 text_plain, 8,
115 GDK_PROP_MODE_REPLACE,
116 text,
117 strlen(text));
120 static char *get_xds_prop(GdkDragContext *context)
122 guchar *prop_text;
123 gint length;
125 if (gdk_property_get(context->source_window,
126 XdndDirectSave0,
127 text_plain,
128 0, MAXURILEN,
129 FALSE,
130 NULL, NULL,
131 &length, &prop_text) && prop_text)
133 /* Terminate the string */
134 prop_text = g_realloc(prop_text, length + 1);
135 prop_text[length] = '\0';
136 return prop_text;
139 return NULL;
142 /* Is the sender willing to supply this target type? */
143 static gboolean provides(GdkDragContext *context, GdkAtom target)
145 GList *targets = context->targets;
147 while (targets && ((GdkAtom) targets->data != target))
148 targets = targets->next;
150 return targets != NULL;
153 /* Convert a URI to a local pathname (or NULL if it isn't local).
154 * The returned pointer points inside the input string.
155 * Possible formats:
156 * /path
157 * ///path
158 * //host/path
159 * file://host/path
161 char *get_local_path(char *uri)
163 char *host;
165 host = our_host_name();
167 if (*uri == '/')
169 char *path;
171 if (uri[1] != '/')
172 return uri; /* Just a local path - no host part */
174 path = strchr(uri + 2, '/');
175 if (!path)
176 return NULL; /* //something */
178 if (path - uri == 2)
179 return path; /* ///path */
180 if (strlen(host) == path - uri - 2 &&
181 strncmp(uri + 2, host, path - uri - 2) == 0)
182 return path; /* //myhost/path */
184 return NULL; /* From a different host */
186 else
188 if (strncasecmp(uri, "file:", 5))
189 return NULL; /* Don't know this format */
191 uri += 5;
193 if (*uri == '/')
194 return get_local_path(uri);
196 return NULL;
200 /* Convert a list of URIs into a list of strings.
201 * Lines beginning with # are skipped.
202 * The text block passed in is zero terminated (after the final CRLF)
204 static GSList *uri_list_to_gslist(char *uri_list)
206 GSList *list = NULL;
208 while (*uri_list)
210 char *linebreak;
211 char *uri;
212 int length;
214 linebreak = strchr(uri_list, 13);
216 if (!linebreak || linebreak[1] != 10)
218 delayed_error("uri_list_to_gslist",
219 "Incorrect or missing line break "
220 "in text/uri-list data");
221 return list;
224 length = linebreak - uri_list;
226 if (length && uri_list[0] != '#')
228 uri = g_malloc(sizeof(char) * (length + 1));
229 strncpy(uri, uri_list, length);
230 uri[length] = 0;
231 list = g_slist_append(list, uri);
234 uri_list = linebreak + 2;
237 return list;
240 /* Append all the URIs in the selection to the string */
241 static void create_uri_list(GString *string,
242 Collection *collection,
243 FilerWindow *filer_window)
245 GString *leader;
246 int i, num_selected;
248 leader = g_string_new("file://");
249 g_string_append(leader, our_host_name());
250 g_string_append(leader, filer_window->path);
251 if (leader->str[leader->len - 1] != '/')
252 g_string_append_c(leader, '/');
254 num_selected = collection->number_selected;
256 for (i = 0; num_selected > 0; i++)
258 if (collection->items[i].selected)
260 FileItem *item = (FileItem *) collection->items[i].data;
262 g_string_append(string, leader->str);
263 g_string_append(string, item->leafname);
264 g_string_append(string, "\r\n");
265 num_selected--;
269 g_string_free(leader, TRUE);
272 /* DRAGGING FROM US */
274 /* The user has held the mouse button down over an item and moved -
275 * start a drag.
277 * We always provide text/uri-list. If we are dragging a single, regular file
278 * then we also offer application/octet-stream.
280 void drag_selection(Collection *collection,
281 GdkEventMotion *event,
282 gint number_selected,
283 gpointer user_data)
285 FilerWindow *filer_window = (FilerWindow *) user_data;
286 GtkWidget *widget;
287 MaskedPixmap *image;
288 GdkDragContext *context;
289 GtkTargetList *target_list;
290 GtkTargetEntry target_table[] =
292 {"text/uri-list", 0, TARGET_URI_LIST},
293 {"application/octet-stream", 0, TARGET_RAW},
295 FileItem *item;
297 if (number_selected == 1)
298 item = selected_item(collection);
299 else
300 item = NULL;
302 widget = GTK_WIDGET(collection);
304 target_list = gtk_target_list_new(target_table,
305 item && item->base_type == TYPE_FILE ? 2 : 1);
307 context = gtk_drag_begin(widget,
308 target_list,
309 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK,
310 (event->state & GDK_BUTTON1_MASK) ? 1 : 2,
311 (GdkEvent *) event);
312 g_dataset_set_data(context, "filer_window", filer_window);
314 image = item ? item->image : &default_pixmap[TYPE_MULTIPLE];
316 gtk_drag_set_icon_pixmap(context,
317 gtk_widget_get_colormap(widget),
318 image->pixmap,
319 image->mask,
320 0, 0);
323 /* Called when a remote app wants us to send it some data.
324 * TODO: Maybe we should handle errors better (ie, let the remote app know
325 * the drag has failed)?
327 void drag_data_get(GtkWidget *widget,
328 GdkDragContext *context,
329 GtkSelectionData *selection_data,
330 guint info,
331 guint32 time)
333 char *to_send = "E"; /* Default to sending an error */
334 long to_send_length = 1;
335 gboolean delete_once_sent = FALSE;
336 GdkAtom type = XA_STRING;
337 GString *string;
338 FilerWindow *filer_window;
339 FileItem *item;
341 filer_window = g_dataset_get_data(context, "filer_window");
342 g_return_if_fail(filer_window != NULL);
344 switch (info)
346 case TARGET_RAW:
347 item = selected_item(filer_window->collection);
348 if (item && load_file(make_path(filer_window->path,
349 item->leafname)->str,
350 &to_send, &to_send_length))
352 delete_once_sent = TRUE;
353 type = application_octet_stream; /* XXX */
354 break;
356 return;
357 case TARGET_URI_LIST:
358 string = g_string_new(NULL);
359 create_uri_list(string,
360 COLLECTION(widget),
361 filer_window);
362 to_send = string->str;
363 to_send_length = string->len;
364 delete_once_sent = TRUE;
365 g_string_free(string, FALSE);
366 break;
367 default:
368 delayed_error("drag_data_get",
369 "Internal error - bad info type\n");
370 break;
373 gtk_selection_data_set(selection_data,
374 type,
376 to_send,
377 to_send_length);
379 if (delete_once_sent)
380 g_free(to_send);
383 /* Load the file into memory. Return TRUE on success. */
384 static gboolean load_file(char *pathname, char **data_out, long *length_out)
386 FILE *file;
387 long length;
388 char *buffer;
389 gboolean retval = FALSE;
391 file = fopen(pathname, "r");
393 if (!file)
395 delayed_error("Opening file for DND", g_strerror(errno));
396 return FALSE;
399 fseek(file, 0, SEEK_END);
400 length = ftell(file);
402 buffer = malloc(length);
403 if (buffer)
405 fseek(file, 0, SEEK_SET);
406 fread(buffer, 1, length, file);
408 if (ferror(file))
410 delayed_error("Loading file for DND",
411 g_strerror(errno));
412 g_free(buffer);
414 else
416 *data_out = buffer;
417 *length_out = length;
418 retval = TRUE;
421 else
422 delayed_error("Loading file for DND",
423 "Can't allocate memory for buffer to "
424 "transfer this file");
426 fclose(file);
428 return retval;
431 /* DRAGGING TO US */
433 /* Set up this filer window as a drop target. Called once, when the
434 * filer window is first created.
436 void drag_set_dest(GtkWidget *widget, FilerWindow *filer_window)
438 GtkTargetEntry target_table[] =
440 {"text/uri-list", 0, TARGET_URI_LIST},
441 {"XdndDirectSave0", 0, TARGET_XDS},
442 {"application/octet-stream", 0, TARGET_RAW},
445 gtk_drag_dest_set(widget,
446 0, /* GTK_DEST_DEFAULT_MOTION, */
447 target_table,
448 sizeof(target_table) / sizeof(*target_table),
449 GDK_ACTION_COPY | GDK_ACTION_MOVE
450 | GDK_ACTION_LINK | GDK_ACTION_PRIVATE);
452 gtk_signal_connect(GTK_OBJECT(widget), "drag_motion",
453 GTK_SIGNAL_FUNC(drag_motion), filer_window);
454 gtk_signal_connect(GTK_OBJECT(widget), "drag_leave",
455 GTK_SIGNAL_FUNC(drag_leave), filer_window);
456 gtk_signal_connect(GTK_OBJECT(widget), "drag_drop",
457 GTK_SIGNAL_FUNC(drag_drop), filer_window);
458 gtk_signal_connect(GTK_OBJECT(widget), "drag_data_received",
459 GTK_SIGNAL_FUNC(drag_data_received), filer_window);
462 /* Decide if panel drag is OK, setting drop_dest_type and drop_dest_path
463 * on the context as needed.
465 static gboolean panel_drag_ok(FilerWindow *filer_window,
466 GdkDragContext *context,
467 int item)
469 FileItem *fileitem = NULL;
470 char *old_path;
471 char *new_path;
472 char *type;
474 panel_set_timeout(NULL, 0);
476 if (item >= 0)
477 fileitem = (FileItem *)
478 filer_window->collection->items[item].data;
480 if (item == -1)
482 new_path = NULL;
484 else if (fileitem->flags & (ITEM_FLAG_APPDIR | ITEM_FLAG_EXEC_FILE))
486 if (provides(context, text_uri_list))
488 type = drop_dest_prog;
489 new_path = make_path(filer_window->path,
490 fileitem->leafname)->str;
492 else
493 new_path = NULL;
495 else if (fileitem->base_type == TYPE_DIRECTORY)
497 type = drop_dest_dir;
498 new_path = make_path(filer_window->path,
499 fileitem->leafname)->str;
501 else
502 new_path = NULL;
504 old_path = g_dataset_get_data(context, "drop_dest_path");
505 if (old_path == new_path ||
506 (old_path && new_path && strcmp(old_path, new_path) == 0))
508 return new_path != NULL; /* Same as before */
511 if (new_path)
513 g_dataset_set_data(context, "drop_dest_type", type);
514 g_dataset_set_data_full(context, "drop_dest_path",
515 g_strdup(new_path), g_free);
517 else
519 item = -1;
520 g_dataset_set_data(context, "drop_dest_path", NULL);
523 collection_set_cursor_item(filer_window->collection, item);
525 return new_path != NULL;
528 /* Called during the drag when the mouse is in a widget registered
529 * as a drop target. Returns TRUE if we can accept the drop.
531 static gboolean drag_motion(GtkWidget *widget,
532 GdkDragContext *context,
533 gint x,
534 gint y,
535 guint time)
537 FilerWindow *filer_window;
538 int item;
540 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
541 g_return_val_if_fail(filer_window != NULL, TRUE);
543 if (gtk_drag_get_source_widget(context) == widget)
544 return FALSE; /* Not within a single widget! */
546 if (filer_window->panel == FALSE)
548 gdk_drag_status(context, context->suggested_action, time);
549 return TRUE;
552 /* OK, this is a drag to a panel.
553 * Allow drags to directories, applications and X bit files only.
555 item = collection_get_item(filer_window->collection, x, y);
557 if (panel_drag_ok(filer_window, context, item))
559 gdk_drag_status(context, context->suggested_action, time);
560 return TRUE;
563 return FALSE;
566 /* Remove panel highlights */
567 static void drag_leave(GtkWidget *widget,
568 GdkDragContext *context)
570 FilerWindow *filer_window;
572 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
573 g_return_if_fail(filer_window != NULL);
575 panel_set_timeout(NULL, 0);
576 collection_set_cursor_item(filer_window->collection, -1);
579 /* User has tried to drop some data on us. Decide what format we would
580 * like the data in.
582 static gboolean drag_drop(GtkWidget *widget,
583 GdkDragContext *context,
584 gint x,
585 gint y,
586 guint time)
588 char *error = NULL;
589 char *leafname = NULL;
590 FilerWindow *filer_window;
591 GdkAtom target;
592 char *dest_path;
593 char *dest_type;
595 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
596 g_return_val_if_fail(filer_window != NULL, TRUE);
598 dest_path = g_dataset_get_data(context, "drop_dest_path");
599 if (dest_path == NULL)
601 if (filer_window->panel)
602 error = "Bad drop on panel";
603 else
605 dest_path = filer_window->path;
606 dest_type = drop_dest_dir;
609 else
611 dest_type = g_dataset_get_data(context, "drop_dest_type");
614 if (error)
616 /* Do nothing */
618 else if (dest_type == drop_dest_dir
619 && provides(context, XdndDirectSave0))
621 leafname = get_xds_prop(context);
622 if (leafname)
624 if (strchr(leafname, '/'))
626 error = "XDS protocol error: "
627 "leafname may not contain '/'\n";
628 g_free(leafname);
630 leafname = NULL;
632 else
634 GString *uri;
636 uri = g_string_new(NULL);
637 g_string_sprintf(uri, "file://%s%s",
638 our_host_name(),
639 make_path(dest_path,
640 leafname)->str);
641 set_xds_prop(context, uri->str);
642 g_string_free(uri, TRUE);
644 target = XdndDirectSave0;
645 g_dataset_set_data_full(context, "leafname",
646 leafname, g_free);
649 else
650 error = "XdndDirectSave0 target provided, but the atom "
651 "XdndDirectSave0 (type text/plain) did not "
652 "contain a leafname\n";
654 else if (provides(context, text_uri_list))
655 target = text_uri_list;
656 else
658 if (dest_type == drop_dest_dir)
659 error = "Sorry - I require a target type of "
660 "text/uri-list or XdndDirectSave0.";
661 else
662 error = "Sorry - I require a target type of "
663 "text/uri-list.";
666 if (error)
668 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
670 delayed_error("ROX-Filer", error);
672 else
673 gtk_drag_get_data(widget, context, target, time);
675 return TRUE;
678 /* Called when some data arrives from the remote app (which we asked for
679 * in drag_drop).
681 static void drag_data_received(GtkWidget *widget,
682 GdkDragContext *context,
683 gint x,
684 gint y,
685 GtkSelectionData *selection_data,
686 guint info,
687 guint32 time)
689 if (!selection_data->data)
691 /* Timeout? */
692 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
693 return;
696 switch (info)
698 case TARGET_XDS:
699 got_data_xds_reply(widget, context,
700 selection_data, time);
701 break;
702 case TARGET_RAW:
703 got_data_raw(widget, context, selection_data, time);
704 break;
705 case TARGET_URI_LIST:
706 got_uri_list(widget, context, selection_data, time);
707 break;
708 default:
709 gtk_drag_finish(context, FALSE, FALSE, time);
710 delayed_error("drag_data_received", "Unknown target");
711 break;
715 static void got_data_xds_reply(GtkWidget *widget,
716 GdkDragContext *context,
717 GtkSelectionData *selection_data,
718 guint32 time)
720 gboolean mark_unsafe = TRUE;
721 char response = *selection_data->data;
722 char *error = NULL;
724 if (selection_data->length != 1)
725 response = '?';
727 if (response == 'F')
729 /* Sender couldn't save there - ask for another
730 * type if possible.
732 if (provides(context, application_octet_stream))
734 mark_unsafe = FALSE; /* Wait and see */
736 gtk_drag_get_data(widget, context,
737 application_octet_stream, time);
739 else
740 error = "Remote app can't or won't send me "
741 "the data - sorry";
743 else if (response == 'S')
745 FilerWindow *filer_window;
747 /* Success - data is saved */
748 mark_unsafe = FALSE; /* It really is safe */
749 gtk_drag_finish(context, TRUE, FALSE, time);
751 filer_window = gtk_object_get_data(GTK_OBJECT(widget),
752 "filer_window");
753 g_return_if_fail(filer_window != NULL);
755 scan_dir(filer_window);
757 else if (response != 'E')
759 error = "XDS protocol error: "
760 "return code should be 'S', 'F' or 'E'\n";
762 /* else: error has been reported by the sender */
764 if (mark_unsafe)
766 set_xds_prop(context, "");
767 /* Unsave also implies that the drag failed */
768 gtk_drag_finish(context, FALSE, FALSE, time);
771 if (error)
772 delayed_error("ROX-Filer", error);
775 static void got_data_raw(GtkWidget *widget,
776 GdkDragContext *context,
777 GtkSelectionData *selection_data,
778 guint32 time)
780 FilerWindow *filer_window;
781 char *leafname;
782 int fd;
783 char *error = NULL;
784 char *dest_path;
786 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
787 g_return_if_fail(filer_window != NULL);
789 leafname = g_dataset_get_data(context, "leafname");
790 if (!leafname)
791 leafname = "UntitledData";
793 dest_path = get_dest_path(filer_window, context);
795 fd = open(make_path(dest_path, leafname)->str,
796 O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY,
797 S_IRUSR | S_IRGRP | S_IROTH |
798 S_IWUSR | S_IWGRP | S_IWOTH);
800 if (fd == -1)
801 error = g_strerror(errno);
802 else
804 if (write(fd,
805 selection_data->data,
806 selection_data->length) == -1)
807 error = g_strerror(errno);
809 if (close(fd) == -1 && !error)
810 error = g_strerror(errno);
812 scan_dir(filer_window);
815 if (error)
817 if (provides(context, XdndDirectSave0))
818 set_xds_prop(context, "");
819 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
820 delayed_error("Error saving file", error);
822 else
823 gtk_drag_finish(context, TRUE, FALSE, time); /* Success! */
826 /* Execute this program, passing all the URIs in the list as arguments.
827 * URIs that are files on the local machine will be passed as simple
828 * pathnames. The uri_list should be freed after this function returns.
830 static void run_with_files(char *path, GSList *uri_list)
832 char **argv;
833 int argc = 0;
834 struct stat info;
836 if (stat(path, &info))
838 delayed_error("ROX-Filer", "Program not found - deleted?");
839 return;
842 argv = g_malloc(sizeof(char *) * (g_slist_length(uri_list) + 2));
844 if (S_ISDIR(info.st_mode))
845 argv[argc++] = make_path(path, "AppRun")->str;
846 else
847 argv[argc++] = path;
849 while (uri_list)
851 char *uri = (char *) uri_list->data;
852 char *local;
854 local = get_local_path(uri);
855 if (local)
856 argv[argc++] = local;
857 else
858 argv[argc++] = uri;
859 uri_list = uri_list->next;
862 argv[argc++] = NULL;
864 if (!spawn(argv))
865 delayed_error("ROX-Filer", "Failed to fork() child process");
868 /* We've got a list of URIs from somewhere (probably another filer).
869 * If the files are on the local machine then try to copy them ourselves,
870 * otherwise, if there was only one file and application/octet-stream was
871 * provided, get the data via the X server.
873 static void got_uri_list(GtkWidget *widget,
874 GdkDragContext *context,
875 GtkSelectionData *selection_data,
876 guint32 time)
878 FilerWindow *filer_window;
879 GSList *uri_list;
880 char *error = NULL;
881 char **argv = NULL; /* Command to exec, or NULL */
882 GSList *next_uri;
883 gboolean send_reply = TRUE;
884 char *dest_path;
885 char *type;
887 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
888 g_return_if_fail(filer_window != NULL);
890 dest_path = get_dest_path(filer_window, context);
891 type = g_dataset_get_data(context, "drop_dest_type");
893 uri_list = uri_list_to_gslist(selection_data->data);
895 if (!uri_list)
896 error = "No URIs in the text/uri-list (nothing to do!)";
897 else if (type == drop_dest_prog)
898 run_with_files(dest_path, uri_list);
899 else if ((!uri_list->next) && (!get_local_path(uri_list->data)))
901 /* There is one URI in the list, and it's not on the local
902 * machine. Get it via the X server if possible.
905 if (provides(context, application_octet_stream))
907 char *leaf;
908 leaf = strrchr(uri_list->data, '/');
909 if (leaf)
910 leaf++;
911 else
912 leaf = uri_list->data;
913 g_dataset_set_data_full(context, "leafname",
914 g_strdup(leaf), g_free);
915 gtk_drag_get_data(widget, context,
916 application_octet_stream, time);
917 send_reply = FALSE;
919 else
920 error = "Can't get data from remote machine "
921 "(application/octet-stream not provided)";
923 else
925 int local_files = 0;
926 const char *start_args[] = {"xterm", "-wf", "-e"};
927 int argc = sizeof(start_args) / sizeof(char *);
929 next_uri = uri_list;
931 argv = g_malloc(sizeof(start_args) +
932 sizeof(char *) * (g_slist_length(uri_list) + 4));
933 memcpy(argv, start_args, sizeof(start_args));
935 if (context->action == GDK_ACTION_MOVE)
937 argv[argc++] = "mv";
938 argv[argc++] = "-iv";
940 else if (context->action == GDK_ACTION_LINK)
942 argv[argc++] = "ln";
943 argv[argc++] = "-vis";
945 else
947 argv[argc++] = "cp";
948 argv[argc++] = "-Riva";
951 /* Either one local URI, or a list. If anything in the list
952 * isn't local then we are stuck.
955 while (next_uri)
957 char *path;
959 path = get_local_path((char *) next_uri->data);
961 if (path)
963 argv[argc++] = path;
964 local_files++;
966 else
967 error = "Some of these files are on a "
968 "different machine - they will be "
969 "ignored - sorry";
971 next_uri = next_uri->next;
974 if (local_files < 1)
976 error = "None of these files are on the local machine "
977 "- I can't operate on multiple remote files - "
978 "sorry.";
979 g_free(argv);
980 argv = NULL;
982 else
984 argv[argc++] = dest_path;
985 argv[argc++] = NULL;
989 if (error)
991 gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */
992 delayed_error("Error getting file list", error);
994 else if (send_reply)
996 gtk_drag_finish(context, TRUE, FALSE, time); /* Success! */
997 if (argv)
999 int child; /* Child process ID */
1001 child = spawn(argv);
1002 if (child)
1003 g_hash_table_insert(child_to_filer,
1004 (gpointer) child, filer_window);
1005 else
1006 delayed_error("ROX-Filer",
1007 "Failed to fork() child process");
1008 g_free(argv);
1012 next_uri = uri_list;
1013 while (next_uri)
1015 g_free(next_uri->data);
1016 next_uri = next_uri->next;
1018 g_slist_free(uri_list);