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)
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
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 */
33 #include <X11/Xatom.h>
35 #include "collection.h"
40 #include "gui_support.h"
44 #define MAXURILEN 4096 /* Longest URI to allow */
46 /* Static prototypes */
47 static char *get_dest_path(FilerWindow
*filer_window
, GdkDragContext
*context
);
48 static void create_uri_list(GString
*string
,
49 Collection
*collection
,
50 FilerWindow
*filer_window
);
51 static gboolean
drag_drop(GtkWidget
*widget
,
52 GdkDragContext
*context
,
56 static gboolean
provides(GdkDragContext
*context
, GdkAtom target
);
57 static void set_xds_prop(GdkDragContext
*context
, char *text
);
58 static gboolean
drag_motion(GtkWidget
*widget
,
59 GdkDragContext
*context
,
63 static void drag_leave(GtkWidget
*widget
,
64 GdkDragContext
*context
);
65 static void drag_data_received(GtkWidget
*widget
,
66 GdkDragContext
*context
,
69 GtkSelectionData
*selection_data
,
72 static void got_data_xds_reply(GtkWidget
*widget
,
73 GdkDragContext
*context
,
74 GtkSelectionData
*selection_data
,
76 static void got_data_raw(GtkWidget
*widget
,
77 GdkDragContext
*context
,
78 GtkSelectionData
*selection_data
,
80 static GSList
*uri_list_to_gslist(char *uri_list
);
81 static void got_uri_list(GtkWidget
*widget
,
82 GdkDragContext
*context
,
83 GtkSelectionData
*selection_data
,
85 static char *get_local_path(char *uri
);
86 static void run_with_files(char *path
, GSList
*uri_list
);
87 static GtkWidget
*create_options();
88 static void update_options();
89 static void set_options();
90 static void save_options();
91 static char *load_no_hostnames(char *data
);
93 /* Possible values for drop_dest_type (can also be NULL).
94 * In either case, drop_dest_path is the app/file/dir to use.
96 static char *drop_dest_prog
= "drop_dest_prog"; /* Run a program */
97 static char *drop_dest_dir
= "drop_dest_dir"; /* Save to path */
99 static OptionsSection options
=
101 "Drag and Drop options",
115 GdkAtom XdndDirectSave0
;
116 GdkAtom xa_text_plain
;
117 GdkAtom text_uri_list
;
118 GdkAtom application_octet_stream
;
122 XdndDirectSave0
= gdk_atom_intern("XdndDirectSave0", FALSE
);
123 xa_text_plain
= gdk_atom_intern("text/plain", FALSE
);
124 text_uri_list
= gdk_atom_intern("text/uri-list", FALSE
);
125 application_octet_stream
= gdk_atom_intern("application/octet-stream",
128 options_sections
= g_slist_prepend(options_sections
, &options
);
129 option_register("dnd_no_hostnames", load_no_hostnames
);
134 static gboolean o_no_hostnames
= FALSE
;
135 static GtkWidget
*toggle_no_hostnames
;
137 /* Build up some option widgets to go in the options dialog, but don't
140 static GtkWidget
*create_options()
142 GtkWidget
*vbox
, *label
;
144 vbox
= gtk_vbox_new(FALSE
, 0);
145 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
147 label
= gtk_label_new("Some older applications don't support XDND "
148 "fully and may need to have this option turned on. "
149 "Use this if dragging files to an application shows "
150 "a + sign on the pointer but the drop doesn't work.");
151 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
152 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, TRUE
, 0);
154 toggle_no_hostnames
=
155 gtk_check_button_new_with_label("Don't use hostnames");
156 gtk_box_pack_start(GTK_BOX(vbox
), toggle_no_hostnames
, FALSE
, TRUE
, 0);
161 static void update_options()
163 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_no_hostnames
),
167 static void set_options()
169 o_no_hostnames
= gtk_toggle_button_get_active(
170 GTK_TOGGLE_BUTTON(toggle_no_hostnames
));
173 static void save_options()
175 option_write("dnd_no_hostnames", o_no_hostnames
? "1" : "0");
178 static char *load_no_hostnames(char *data
)
180 o_no_hostnames
= atoi(data
) != 0;
184 /* SUPPORT FUNCTIONS */
186 static char *get_dest_path(FilerWindow
*filer_window
, GdkDragContext
*context
)
190 path
= g_dataset_get_data(context
, "drop_dest_path");
192 return path
? path
: filer_window
->path
;
195 /* Set the XdndDirectSave0 property on the source window for this context */
196 static void set_xds_prop(GdkDragContext
*context
, char *text
)
198 gdk_property_change(context
->source_window
,
201 GDK_PROP_MODE_REPLACE
,
206 static char *get_xds_prop(GdkDragContext
*context
)
211 if (gdk_property_get(context
->source_window
,
217 &length
, &prop_text
) && prop_text
)
219 /* Terminate the string */
220 prop_text
= g_realloc(prop_text
, length
+ 1);
221 prop_text
[length
] = '\0';
228 /* Is the sender willing to supply this target type? */
229 static gboolean
provides(GdkDragContext
*context
, GdkAtom target
)
231 GList
*targets
= context
->targets
;
233 while (targets
&& ((GdkAtom
) targets
->data
!= target
))
234 targets
= targets
->next
;
236 return targets
!= NULL
;
239 /* Convert a URI to a local pathname (or NULL if it isn't local).
240 * The returned pointer points inside the input string.
247 static char *get_local_path(char *uri
)
251 host
= our_host_name();
258 return uri
; /* Just a local path - no host part */
260 path
= strchr(uri
+ 2, '/');
262 return NULL
; /* //something */
265 return path
; /* ///path */
266 if (strlen(host
) == path
- uri
- 2 &&
267 strncmp(uri
+ 2, host
, path
- uri
- 2) == 0)
268 return path
; /* //myhost/path */
270 return NULL
; /* From a different host */
274 if (strncasecmp(uri
, "file:", 5))
275 return NULL
; /* Don't know this format */
280 return get_local_path(uri
);
286 /* Convert a list of URIs into a list of strings.
287 * Lines beginning with # are skipped.
288 * The text block passed in is zero terminated (after the final CRLF)
290 static GSList
*uri_list_to_gslist(char *uri_list
)
300 linebreak
= strchr(uri_list
, 13);
302 if (!linebreak
|| linebreak
[1] != 10)
304 delayed_error("uri_list_to_gslist",
305 "Incorrect or missing line break "
306 "in text/uri-list data");
310 length
= linebreak
- uri_list
;
312 if (length
&& uri_list
[0] != '#')
314 uri
= g_malloc(sizeof(char) * (length
+ 1));
315 strncpy(uri
, uri_list
, length
);
317 list
= g_slist_append(list
, uri
);
320 uri_list
= linebreak
+ 2;
326 /* Append all the URIs in the selection to the string */
327 static void create_uri_list(GString
*string
,
328 Collection
*collection
,
329 FilerWindow
*filer_window
)
334 leader
= g_string_new("file://");
336 g_string_append(leader
, our_host_name());
337 g_string_append(leader
, filer_window
->path
);
338 if (leader
->str
[leader
->len
- 1] != '/')
339 g_string_append_c(leader
, '/');
341 num_selected
= collection
->number_selected
;
343 for (i
= 0; num_selected
> 0; i
++)
345 if (collection
->items
[i
].selected
)
347 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
349 g_string_append(string
, leader
->str
);
350 g_string_append(string
, item
->leafname
);
351 g_string_append(string
, "\r\n");
356 g_string_free(leader
, TRUE
);
359 /* DRAGGING FROM US */
361 /* The user has held the mouse button down over an item and moved -
364 * We always provide text/uri-list. If we are dragging a single, regular file
365 * then we also offer application/octet-stream and the type of the file.
367 void drag_selection(Collection
*collection
,
368 GdkEventMotion
*event
,
369 gint number_selected
,
372 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
375 GdkDragContext
*context
;
376 GtkTargetList
*target_list
;
377 GtkTargetEntry target_table
[] =
379 {"text/uri-list", 0, TARGET_URI_LIST
},
380 {"application/octet-stream", 0, TARGET_RAW
},
385 if (number_selected
== 1)
386 item
= selected_item(collection
);
390 widget
= GTK_WIDGET(collection
);
392 if (item
&& item
->mime_type
)
394 MIME_type
*t
= item
->mime_type
;
396 target_table
[2].target
= g_strconcat(t
->media_type
, "/",
398 target_list
= gtk_target_list_new(target_table
, 3);
399 g_free(target_table
[2].target
);
402 target_list
= gtk_target_list_new(target_table
, 1);
404 context
= gtk_drag_begin(widget
,
406 GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_LINK
,
407 (event
->state
& GDK_BUTTON1_MASK
) ? 1 : 2,
409 g_dataset_set_data(context
, "filer_window", filer_window
);
411 image
= item
? item
->image
: &default_pixmap
[TYPE_MULTIPLE
];
413 gtk_drag_set_icon_pixmap(context
,
414 gtk_widget_get_colormap(widget
),
420 /* Called when a remote app wants us to send it some data.
421 * TODO: Maybe we should handle errors better (ie, let the remote app know
422 * the drag has failed)?
424 void drag_data_get(GtkWidget
*widget
,
425 GdkDragContext
*context
,
426 GtkSelectionData
*selection_data
,
430 char *to_send
= "E"; /* Default to sending an error */
431 long to_send_length
= 1;
432 gboolean delete_once_sent
= FALSE
;
433 GdkAtom type
= XA_STRING
;
435 FilerWindow
*filer_window
;
438 filer_window
= g_dataset_get_data(context
, "filer_window");
439 g_return_if_fail(filer_window
!= NULL
);
444 item
= selected_item(filer_window
->collection
);
445 if (item
&& load_file(make_path(filer_window
->path
,
446 item
->leafname
)->str
,
447 &to_send
, &to_send_length
))
449 delete_once_sent
= TRUE
;
451 type
= type_to_atom(item
->mime_type
);
453 type
= application_octet_stream
;
457 case TARGET_URI_LIST
:
458 string
= g_string_new(NULL
);
459 create_uri_list(string
,
462 to_send
= string
->str
;
463 to_send_length
= string
->len
;
464 delete_once_sent
= TRUE
;
465 g_string_free(string
, FALSE
);
468 delayed_error("drag_data_get",
469 "Internal error - bad info type\n");
473 gtk_selection_data_set(selection_data
,
479 if (delete_once_sent
)
485 /* Set up this filer window as a drop target. Called once, when the
486 * filer window is first created.
488 void drag_set_dest(GtkWidget
*widget
, FilerWindow
*filer_window
)
490 GtkTargetEntry target_table
[] =
492 {"text/uri-list", 0, TARGET_URI_LIST
},
493 {"XdndDirectSave0", 0, TARGET_XDS
},
494 {"application/octet-stream", 0, TARGET_RAW
},
497 gtk_drag_dest_set(widget
,
498 0, /* GTK_DEST_DEFAULT_MOTION, */
500 sizeof(target_table
) / sizeof(*target_table
),
501 GDK_ACTION_COPY
| GDK_ACTION_MOVE
502 | GDK_ACTION_LINK
| GDK_ACTION_PRIVATE
);
504 gtk_signal_connect(GTK_OBJECT(widget
), "drag_motion",
505 GTK_SIGNAL_FUNC(drag_motion
), filer_window
);
506 gtk_signal_connect(GTK_OBJECT(widget
), "drag_leave",
507 GTK_SIGNAL_FUNC(drag_leave
), filer_window
);
508 gtk_signal_connect(GTK_OBJECT(widget
), "drag_drop",
509 GTK_SIGNAL_FUNC(drag_drop
), filer_window
);
510 gtk_signal_connect(GTK_OBJECT(widget
), "drag_data_received",
511 GTK_SIGNAL_FUNC(drag_data_received
), filer_window
);
514 /* Decide if panel drag is OK, setting drop_dest_type and drop_dest_path
515 * on the context as needed.
517 static gboolean
panel_drag_ok(FilerWindow
*filer_window
,
518 GdkDragContext
*context
,
521 DirItem
*fileitem
= NULL
;
524 char *type
= NULL
; /* Quiet gcc */
527 fileitem
= (DirItem
*)
528 filer_window
->collection
->items
[item
].data
;
531 new_path
= NULL
; /* Drag to panel background - disallow */
532 else if (fileitem
->flags
&
533 (ITEM_FLAG_APPDIR
| ITEM_FLAG_EXEC_FILE
))
535 if (provides(context
, text_uri_list
))
537 type
= drop_dest_prog
;
538 new_path
= make_path(filer_window
->path
,
539 fileitem
->leafname
)->str
;
544 else if (fileitem
->base_type
== TYPE_DIRECTORY
)
546 type
= drop_dest_dir
;
547 new_path
= make_path(filer_window
->path
,
548 fileitem
->leafname
)->str
;
553 if (new_path
&& access(new_path
, W_OK
))
556 old_path
= g_dataset_get_data(context
, "drop_dest_path");
557 if (old_path
== new_path
||
558 (old_path
&& new_path
&& strcmp(old_path
, new_path
) == 0))
560 return new_path
!= NULL
; /* Same as before */
565 g_dataset_set_data(context
, "drop_dest_type", type
);
566 g_dataset_set_data_full(context
, "drop_dest_path",
567 g_strdup(new_path
), g_free
);
572 g_dataset_set_data(context
, "drop_dest_path", NULL
);
575 collection_set_cursor_item(filer_window
->collection
, item
);
577 return new_path
!= NULL
;
580 /* Called during the drag when the mouse is in a widget registered
581 * as a drop target. Returns TRUE if we can accept the drop.
583 static gboolean
drag_motion(GtkWidget
*widget
,
584 GdkDragContext
*context
,
589 FilerWindow
*filer_window
;
592 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
593 g_return_val_if_fail(filer_window
!= NULL
, TRUE
);
595 if (gtk_drag_get_source_widget(context
) == widget
)
596 return FALSE
; /* Not within a single widget! */
598 if (filer_window
->panel
== FALSE
)
600 if (access(filer_window
->path
, W_OK
))
601 return FALSE
; /* We can't write here */
602 gdk_drag_status(context
, context
->suggested_action
, time
);
606 /* OK, this is a drag to a panel.
607 * Allow drags to directories, applications and X bit files only.
609 item
= collection_get_item(filer_window
->collection
, x
, y
);
611 if (panel_drag_ok(filer_window
, context
, item
))
613 gdk_drag_status(context
, context
->suggested_action
, time
);
620 /* Remove panel highlights */
621 static void drag_leave(GtkWidget
*widget
,
622 GdkDragContext
*context
)
624 FilerWindow
*filer_window
;
626 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
627 g_return_if_fail(filer_window
!= NULL
);
629 collection_set_cursor_item(filer_window
->collection
, -1);
632 /* User has tried to drop some data on us. Decide what format we would
635 static gboolean
drag_drop(GtkWidget
*widget
,
636 GdkDragContext
*context
,
642 char *leafname
= NULL
;
643 FilerWindow
*filer_window
;
644 GdkAtom target
= GDK_NONE
;
646 char *dest_type
= NULL
;
648 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
649 g_return_val_if_fail(filer_window
!= NULL
, TRUE
);
651 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
652 if (dest_path
== NULL
)
654 if (filer_window
->panel
)
655 error
= "Bad drop on panel";
658 dest_path
= filer_window
->path
;
659 dest_type
= drop_dest_dir
;
664 dest_type
= g_dataset_get_data(context
, "drop_dest_type");
671 else if (dest_type
== drop_dest_dir
672 && provides(context
, XdndDirectSave0
))
674 leafname
= get_xds_prop(context
);
677 if (strchr(leafname
, '/'))
679 error
= "XDS protocol error: "
680 "leafname may not contain '/'\n";
689 uri
= g_string_new(NULL
);
690 g_string_sprintf(uri
, "file://%s%s",
694 set_xds_prop(context
, uri
->str
);
695 g_string_free(uri
, TRUE
);
697 target
= XdndDirectSave0
;
698 g_dataset_set_data_full(context
, "leafname",
703 error
= "XdndDirectSave0 target provided, but the atom "
704 "XdndDirectSave0 (type text/plain) did not "
705 "contain a leafname\n";
707 else if (provides(context
, text_uri_list
))
708 target
= text_uri_list
;
711 if (dest_type
== drop_dest_dir
)
712 error
= "Sorry - I require a target type of "
713 "text/uri-list or XdndDirectSave0.";
715 error
= "Sorry - I require a target type of "
721 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
723 delayed_error("ROX-Filer", error
);
726 gtk_drag_get_data(widget
, context
, target
, time
);
731 /* Called when some data arrives from the remote app (which we asked for
734 static void drag_data_received(GtkWidget
*widget
,
735 GdkDragContext
*context
,
738 GtkSelectionData
*selection_data
,
742 if (!selection_data
->data
)
745 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
752 got_data_xds_reply(widget
, context
,
753 selection_data
, time
);
756 got_data_raw(widget
, context
, selection_data
, time
);
758 case TARGET_URI_LIST
:
759 got_uri_list(widget
, context
, selection_data
, time
);
762 gtk_drag_finish(context
, FALSE
, FALSE
, time
);
763 delayed_error("drag_data_received", "Unknown target");
768 static void got_data_xds_reply(GtkWidget
*widget
,
769 GdkDragContext
*context
,
770 GtkSelectionData
*selection_data
,
773 gboolean mark_unsafe
= TRUE
;
774 char response
= *selection_data
->data
;
777 if (selection_data
->length
!= 1)
782 /* Sender couldn't save there - ask for another
785 if (provides(context
, application_octet_stream
))
787 mark_unsafe
= FALSE
; /* Wait and see */
789 gtk_drag_get_data(widget
, context
,
790 application_octet_stream
, time
);
793 error
= "Remote app can't or won't send me "
796 else if (response
== 'S')
798 FilerWindow
*filer_window
;
800 /* Success - data is saved */
801 mark_unsafe
= FALSE
; /* It really is safe */
802 gtk_drag_finish(context
, TRUE
, FALSE
, time
);
804 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
),
806 g_return_if_fail(filer_window
!= NULL
);
808 update_dir(filer_window
, TRUE
);
810 else if (response
!= 'E')
812 error
= "XDS protocol error: "
813 "return code should be 'S', 'F' or 'E'\n";
815 /* else: error has been reported by the sender */
819 set_xds_prop(context
, "");
820 /* Unsave also implies that the drag failed */
821 gtk_drag_finish(context
, FALSE
, FALSE
, time
);
825 delayed_error("ROX-Filer", error
);
828 static void got_data_raw(GtkWidget
*widget
,
829 GdkDragContext
*context
,
830 GtkSelectionData
*selection_data
,
833 FilerWindow
*filer_window
;
839 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
840 g_return_if_fail(filer_window
!= NULL
);
842 leafname
= g_dataset_get_data(context
, "leafname");
844 leafname
= "UntitledData";
846 dest_path
= get_dest_path(filer_window
, context
);
848 fd
= open(make_path(dest_path
, leafname
)->str
,
849 O_WRONLY
| O_CREAT
| O_EXCL
| O_NOCTTY
,
850 S_IRUSR
| S_IRGRP
| S_IROTH
|
851 S_IWUSR
| S_IWGRP
| S_IWOTH
);
854 error
= g_strerror(errno
);
858 selection_data
->data
,
859 selection_data
->length
) == -1)
860 error
= g_strerror(errno
);
862 if (close(fd
) == -1 && !error
)
863 error
= g_strerror(errno
);
865 update_dir(filer_window
, TRUE
);
870 if (provides(context
, XdndDirectSave0
))
871 set_xds_prop(context
, "");
872 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
873 delayed_error("Error saving file", error
);
876 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
879 /* Execute this program, passing all the URIs in the list as arguments.
880 * URIs that are files on the local machine will be passed as simple
881 * pathnames. The uri_list should be freed after this function returns.
883 static void run_with_files(char *path
, GSList
*uri_list
)
889 if (stat(path
, &info
))
891 delayed_error("ROX-Filer", "Program not found - deleted?");
895 argv
= g_malloc(sizeof(char *) * (g_slist_length(uri_list
) + 2));
897 if (S_ISDIR(info
.st_mode
))
898 argv
[argc
++] = make_path(path
, "AppRun")->str
;
904 char *uri
= (char *) uri_list
->data
;
907 local
= get_local_path(uri
);
909 argv
[argc
++] = local
;
912 uri_list
= uri_list
->next
;
917 if (!spawn_full(argv
, getenv("HOME")))
918 delayed_error("ROX-Filer", "Failed to fork() child process");
921 /* We've got a list of URIs from somewhere (probably another filer window).
922 * If the files are on the local machine then try to copy them ourselves,
923 * otherwise, if there was only one file and application/octet-stream was
924 * provided, get the data via the X server.
926 static void got_uri_list(GtkWidget
*widget
,
927 GdkDragContext
*context
,
928 GtkSelectionData
*selection_data
,
931 FilerWindow
*filer_window
;
935 gboolean send_reply
= TRUE
;
939 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
940 g_return_if_fail(filer_window
!= NULL
);
942 dest_path
= get_dest_path(filer_window
, context
);
943 type
= g_dataset_get_data(context
, "drop_dest_type");
945 uri_list
= uri_list_to_gslist(selection_data
->data
);
948 error
= "No URIs in the text/uri-list (nothing to do!)";
949 else if (type
== drop_dest_prog
)
950 run_with_files(dest_path
, uri_list
);
951 else if ((!uri_list
->next
) && (!get_local_path(uri_list
->data
)))
953 /* There is one URI in the list, and it's not on the local
954 * machine. Get it via the X server if possible.
957 if (provides(context
, application_octet_stream
))
960 leaf
= strrchr(uri_list
->data
, '/');
964 leaf
= uri_list
->data
;
965 g_dataset_set_data_full(context
, "leafname",
966 g_strdup(leaf
), g_free
);
967 gtk_drag_get_data(widget
, context
,
968 application_octet_stream
, time
);
972 error
= "Can't get data from remote machine "
973 "(application/octet-stream not provided)";
977 GSList
*local_paths
= NULL
;
980 /* Either one local URI, or a list. If everything in the list
981 * isn't local then we are stuck.
984 for (next_uri
= uri_list
; next_uri
; next_uri
= next_uri
->next
)
988 path
= get_local_path((char *) next_uri
->data
);
991 local_paths
= g_slist_append(local_paths
,
994 error
= "Some of these files are on a "
995 "different machine - they will be "
1001 error
= "None of these files are on the local machine "
1002 "- I can't operate on multiple remote files - "
1005 else if (context
->action
== GDK_ACTION_MOVE
)
1006 action_move(local_paths
, dest_path
);
1007 else if (context
->action
== GDK_ACTION_COPY
)
1008 action_copy(local_paths
, dest_path
);
1009 else if (context
->action
== GDK_ACTION_LINK
)
1010 action_link(local_paths
, dest_path
);
1012 error
= "Unknown action requested";
1014 for (next
= local_paths
; next
; next
= next
->next
)
1016 g_slist_free(local_paths
);
1021 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
1022 delayed_error("Error getting file list", error
);
1024 else if (send_reply
)
1025 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
1027 next_uri
= uri_list
;
1030 g_free(next_uri
->data
);
1031 next_uri
= next_uri
->next
;
1033 g_slist_free(uri_list
);