4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, 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 <sys/param.h>
36 #include <X11/Xatom.h>
38 #include "collection.h"
44 #include "gui_support.h"
50 #define MAXURILEN 4096 /* Longest URI to allow */
52 /* Static prototypes */
53 static void create_uri_list(GString
*string
,
54 Collection
*collection
,
55 FilerWindow
*filer_window
);
56 static gboolean
drag_drop(GtkWidget
*widget
,
57 GdkDragContext
*context
,
61 FilerWindow
*filer_window
);
62 static gboolean
provides(GdkDragContext
*context
, GdkAtom target
);
63 static void set_xds_prop(GdkDragContext
*context
, char *text
);
64 static gboolean
drag_motion(GtkWidget
*widget
,
65 GdkDragContext
*context
,
69 FilerWindow
*filer_window
);
70 static void drag_leave(GtkWidget
*widget
,
71 GdkDragContext
*context
,
73 FilerWindow
*filer_window
);
74 static void drag_data_received(GtkWidget
*widget
,
75 GdkDragContext
*context
,
78 GtkSelectionData
*selection_data
,
81 FilerWindow
*filer_window
);
82 static void desktop_drag_data_received(GtkWidget
*widget
,
83 GdkDragContext
*context
,
86 GtkSelectionData
*selection_data
,
89 FilerWindow
*filer_window
);
90 static void got_data_xds_reply(GtkWidget
*widget
,
91 GdkDragContext
*context
,
92 GtkSelectionData
*selection_data
,
94 FilerWindow
*filer_window
);
95 static void got_data_raw(GtkWidget
*widget
,
96 GdkDragContext
*context
,
97 GtkSelectionData
*selection_data
,
99 static GSList
*uri_list_to_gslist(char *uri_list
);
100 static void got_uri_list(GtkWidget
*widget
,
101 GdkDragContext
*context
,
102 GtkSelectionData
*selection_data
,
104 static GtkWidget
*create_options();
105 static void update_options();
106 static void set_options();
107 static void save_options();
108 static char *load_no_hostnames(char *data
);
109 static char *drag_to_icons(char *data
);
110 static void drag_end(GtkWidget
*widget
,
111 GdkDragContext
*context
,
112 FilerWindow
*filer_window
);
114 /* Possible values for drop_dest_type (can also be NULL).
115 * In either case, drop_dest_path is the app/file/dir to use.
117 static char *drop_dest_prog
= "drop_dest_prog"; /* Run a program */
118 static char *drop_dest_dir
= "drop_dest_dir"; /* Save to path */
120 static OptionsSection options
=
122 N_("Drag and Drop options"),
137 GdkAtom XdndDirectSave0
;
138 GdkAtom _rox_run_action
;
139 GdkAtom xa_text_plain
;
140 GdkAtom text_uri_list
;
141 GdkAtom application_octet_stream
;
145 XdndDirectSave0
= gdk_atom_intern("XdndDirectSave0", FALSE
);
146 _rox_run_action
= gdk_atom_intern("_ROX_RUN_ACTION", FALSE
);
147 xa_text_plain
= gdk_atom_intern("text/plain", FALSE
);
148 text_uri_list
= gdk_atom_intern("text/uri-list", FALSE
);
149 application_octet_stream
= gdk_atom_intern("application/octet-stream",
152 options_sections
= g_slist_prepend(options_sections
, &options
);
153 option_register("dnd_no_hostnames", load_no_hostnames
);
154 option_register("dnd_drag_to_icons", drag_to_icons
);
159 static gboolean o_no_hostnames
= FALSE
;
160 static gboolean o_drag_to_icons
= TRUE
;
161 static GtkWidget
*toggle_no_hostnames
;
162 static GtkWidget
*toggle_drag_to_icons
;
164 /* Build up some option widgets to go in the options dialog, but don't
167 static GtkWidget
*create_options()
169 GtkWidget
*vbox
, *label
;
171 vbox
= gtk_vbox_new(FALSE
, 0);
172 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
174 label
= gtk_label_new(_("Some older applications don't support XDND "
175 "fully and may need to have this option turned on. "
176 "Use this if dragging files to an application shows "
177 "a + sign on the pointer but the drop doesn't work."));
178 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
179 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, TRUE
, 0);
181 toggle_no_hostnames
=
182 gtk_check_button_new_with_label(_("Don't use hostnames"));
183 gtk_box_pack_start(GTK_BOX(vbox
), toggle_no_hostnames
, FALSE
, TRUE
, 0);
185 toggle_drag_to_icons
=
186 gtk_check_button_new_with_label(_("Allow dragging to icons in "
188 gtk_box_pack_start(GTK_BOX(vbox
), toggle_drag_to_icons
, FALSE
, TRUE
, 0);
193 static void update_options()
195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_no_hostnames
),
197 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_drag_to_icons
),
201 static void set_options()
203 o_no_hostnames
= gtk_toggle_button_get_active(
204 GTK_TOGGLE_BUTTON(toggle_no_hostnames
));
205 o_drag_to_icons
= gtk_toggle_button_get_active(
206 GTK_TOGGLE_BUTTON(toggle_drag_to_icons
));
209 static void save_options()
211 option_write("dnd_no_hostnames", o_no_hostnames
? "1" : "0");
212 option_write("dnd_drag_to_icons", o_drag_to_icons
? "1" : "0");
215 static char *load_no_hostnames(char *data
)
217 o_no_hostnames
= atoi(data
) != 0;
221 static char *drag_to_icons(char *data
)
223 o_drag_to_icons
= atoi(data
) != 0;
227 /* SUPPORT FUNCTIONS */
229 /* Set the XdndDirectSave0 property on the source window for this context */
230 static void set_xds_prop(GdkDragContext
*context
, char *text
)
232 gdk_property_change(context
->source_window
,
235 GDK_PROP_MODE_REPLACE
,
240 static char *get_xds_prop(GdkDragContext
*context
)
245 if (gdk_property_get(context
->source_window
,
251 &length
, &prop_text
) && prop_text
)
253 /* Terminate the string */
254 prop_text
= g_realloc(prop_text
, length
+ 1);
255 prop_text
[length
] = '\0';
262 /* Is the sender willing to supply this target type? */
263 static gboolean
provides(GdkDragContext
*context
, GdkAtom target
)
265 GList
*targets
= context
->targets
;
267 while (targets
&& ((GdkAtom
) targets
->data
!= target
))
268 targets
= targets
->next
;
270 return targets
!= NULL
;
273 /* Convert a list of URIs into a list of strings.
274 * Lines beginning with # are skipped.
275 * The text block passed in is zero terminated (after the final CRLF)
277 static GSList
*uri_list_to_gslist(char *uri_list
)
287 linebreak
= strchr(uri_list
, 13);
289 if (!linebreak
|| linebreak
[1] != 10)
291 delayed_error("uri_list_to_gslist",
292 _("Incorrect or missing line "
293 "break in text/uri-list data"));
297 length
= linebreak
- uri_list
;
299 if (length
&& uri_list
[0] != '#')
301 uri
= g_malloc(sizeof(char) * (length
+ 1));
302 strncpy(uri
, uri_list
, length
);
304 list
= g_slist_append(list
, uri
);
307 uri_list
= linebreak
+ 2;
313 /* Append all the URIs in the selection to the string */
314 static void create_uri_list(GString
*string
,
315 Collection
*collection
,
316 FilerWindow
*filer_window
)
321 leader
= g_string_new("file://");
323 g_string_append(leader
, our_host_name());
324 g_string_append(leader
, filer_window
->path
);
325 if (leader
->str
[leader
->len
- 1] != '/')
326 g_string_append_c(leader
, '/');
328 num_selected
= collection
->number_selected
;
330 for (i
= 0; num_selected
> 0; i
++)
332 if (collection
->items
[i
].selected
)
334 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
336 g_string_append(string
, leader
->str
);
337 g_string_append(string
, item
->leafname
);
338 g_string_append(string
, "\r\n");
343 g_string_free(leader
, TRUE
);
346 /* DRAGGING FROM US */
348 /* The user has held the mouse button down over an item and moved -
351 * We always provide text/uri-list. If we are dragging a single, regular file
352 * then we also offer application/octet-stream and the type of the file.
354 * If the RUN_ACTION minibuffer is open then only drags to other executables
355 * shown in our windows are allowed.
357 void drag_selection(Collection
*collection
,
358 GdkEventMotion
*event
,
359 gint number_selected
,
360 FilerWindow
*filer_window
)
364 GdkDragContext
*context
;
365 GtkTargetList
*target_list
;
366 GtkTargetEntry target_table
[] =
368 {"text/uri-list", 0, TARGET_URI_LIST
},
369 {"application/octet-stream", 0, TARGET_RAW
},
373 GdkDragAction actions
;
375 if (number_selected
== 1)
376 item
= selected_item(collection
);
380 widget
= GTK_WIDGET(collection
);
382 if (filer_window
->mini_type
== MINI_RUN_ACTION
)
384 GtkTargetEntry target_table
[] = {
385 {"_ROX_RUN_ACTION", 0, TARGET_RUN_ACTION
},
388 if (collection
->number_selected
!= 1)
391 target_list
= gtk_target_list_new(target_table
, 1);
393 else if (item
&& item
->base_type
== TYPE_FILE
)
395 MIME_type
*t
= item
->mime_type
;
397 target_table
[2].target
= g_strconcat(t
->media_type
, "/",
399 target_list
= gtk_target_list_new(target_table
, 3);
400 g_free(target_table
[2].target
);
403 target_list
= gtk_target_list_new(target_table
, 1);
405 if (event
->state
& GDK_BUTTON1_MASK
)
406 actions
= GDK_ACTION_COPY
| GDK_ACTION_MOVE
| GDK_ACTION_LINK
;
408 actions
= GDK_ACTION_MOVE
;
410 context
= gtk_drag_begin(widget
,
413 (event
->state
& GDK_BUTTON1_MASK
) ? 1 :
414 (event
->state
& GDK_BUTTON2_MASK
) ? 2 : 3,
417 image
= item
? item
->image
: im_multiple
;
419 gtk_drag_set_icon_pixmap(context
,
420 gtk_widget_get_colormap(widget
),
426 static void drag_end(GtkWidget
*widget
,
427 GdkDragContext
*context
,
428 FilerWindow
*filer_window
)
430 collection_clear_selection(filer_window
->collection
);
431 if (filer_window
->mini_type
== MINI_RUN_ACTION
)
432 minibuffer_hide(filer_window
);
435 /* Called when a remote app wants us to send it some data.
436 * TODO: Maybe we should handle errors better (ie, let the remote app know
437 * the drag has failed)?
439 void drag_data_get(GtkWidget
*widget
,
440 GdkDragContext
*context
,
441 GtkSelectionData
*selection_data
,
444 FilerWindow
*filer_window
)
446 char *to_send
= "E"; /* Default to sending an error */
447 long to_send_length
= 1;
448 gboolean delete_once_sent
= FALSE
;
449 GdkAtom type
= XA_STRING
;
456 item
= selected_item(filer_window
->collection
);
457 if (item
&& load_file(make_path(filer_window
->path
,
458 item
->leafname
)->str
,
459 &to_send
, &to_send_length
))
461 delete_once_sent
= TRUE
;
462 type
= selection_data
->target
;
465 g_warning("drag_data_get: Can't find selected item\n");
467 case TARGET_URI_LIST
:
468 string
= g_string_new(NULL
);
469 create_uri_list(string
,
472 to_send
= string
->str
;
473 to_send_length
= string
->len
;
474 delete_once_sent
= TRUE
;
475 g_string_free(string
, FALSE
);
477 case TARGET_RUN_ACTION
:
478 item
= selected_item(filer_window
->collection
);
479 if (item
&& item
->mime_type
)
481 MIME_type
*type
= item
->mime_type
;
482 to_send
= g_strconcat(type
->media_type
, "/",
483 type
->subtype
, NULL
);
484 to_send_length
= strlen(to_send
);
485 delete_once_sent
= TRUE
;
488 g_warning("drag_data_get: Can't find MIME-type\n");
491 delayed_error("drag_data_get",
492 _("Internal error - bad info type"));
496 gtk_selection_data_set(selection_data
,
502 if (delete_once_sent
)
508 /* Set up this filer window as a drop target. Called once, when the
509 * filer window is first created.
511 void drag_set_dest(FilerWindow
*filer_window
)
513 GtkWidget
*widget
= GTK_WIDGET(filer_window
->collection
);
514 GtkTargetEntry target_table
[] =
516 {"text/uri-list", 0, TARGET_URI_LIST
},
517 {"XdndDirectSave0", 0, TARGET_XDS
},
518 {"application/octet-stream", 0, TARGET_RAW
},
519 {"_ROX_RUN_ACTION", 0, TARGET_RUN_ACTION
},
522 gtk_drag_dest_set(widget
,
523 0, /* GTK_DEST_DEFAULT_MOTION, */
525 sizeof(target_table
) / sizeof(*target_table
),
526 GDK_ACTION_COPY
| GDK_ACTION_MOVE
527 | GDK_ACTION_LINK
| GDK_ACTION_PRIVATE
);
529 gtk_signal_connect(GTK_OBJECT(widget
), "drag_motion",
530 GTK_SIGNAL_FUNC(drag_motion
), filer_window
);
531 gtk_signal_connect(GTK_OBJECT(widget
), "drag_leave",
532 GTK_SIGNAL_FUNC(drag_leave
), filer_window
);
533 gtk_signal_connect(GTK_OBJECT(widget
), "drag_drop",
534 GTK_SIGNAL_FUNC(drag_drop
), filer_window
);
535 gtk_signal_connect(GTK_OBJECT(widget
), "drag_data_received",
536 GTK_SIGNAL_FUNC(drag_data_received
), filer_window
);
538 gtk_signal_connect(GTK_OBJECT(widget
), "drag_end",
539 GTK_SIGNAL_FUNC(drag_end
), filer_window
);
542 /* Like drag_set_dest, but for a pinboard-type widget.
543 * You must ensure that dnd events reach this widget (eg with
544 * setup_xdnd_proxy() for the root window).
546 void drag_set_pinboard_dest(GtkWidget
*widget
)
548 GtkTargetEntry target_table
[] = {
549 {"text/uri-list", 0, TARGET_URI_LIST
},
552 gtk_drag_dest_set(widget
,
553 GTK_DEST_DEFAULT_MOTION
| GTK_DEST_DEFAULT_DROP
,
555 sizeof(target_table
) / sizeof(*target_table
),
557 gtk_signal_connect(GTK_OBJECT(widget
), "drag_data_received",
558 (GtkSignalFunc
) desktop_drag_data_received
,
562 /* Called during the drag when the mouse is in a widget registered
563 * as a drop target. Returns TRUE if we can accept the drop.
565 static gboolean
drag_motion(GtkWidget
*widget
,
566 GdkDragContext
*context
,
570 FilerWindow
*filer_window
)
574 GdkDragAction action
= context
->suggested_action
;
575 char *new_path
= NULL
;
578 if (o_drag_to_icons
|| filer_window
->panel_type
!= PANEL_NO
)
579 item_number
= collection_get_item(filer_window
->collection
,
584 item
= item_number
>= 0
585 ? (DirItem
*) filer_window
->collection
->items
[item_number
].data
588 if (provides(context
, _rox_run_action
))
590 /* This is a special internal type. The user is dragging
591 * to an executable item to set the run action.
596 if (item
->flags
& (ITEM_FLAG_APPDIR
| ITEM_FLAG_EXEC_FILE
))
598 type
= drop_dest_prog
;
599 new_path
= make_path(filer_window
->path
,
600 item
->leafname
)->str
;
608 /* If we didn't drop onto a directory, application or
609 * executable file then act as though the drop is to the
612 if (item
->base_type
!= TYPE_DIRECTORY
613 && !(item
->flags
& ITEM_FLAG_EXEC_FILE
))
619 /* Drop onto the window background */
620 collection_set_cursor_item(filer_window
->collection
,
623 if (gtk_drag_get_source_widget(context
) == widget
)
626 if (access(filer_window
->path
, W_OK
) != 0)
627 goto out
; /* No write permission */
629 if (filer_window
->panel_type
!= PANEL_NO
)
631 if (context
->actions
& GDK_ACTION_LINK
)
633 action
= GDK_ACTION_LINK
;
634 type
= drop_dest_dir
;
638 type
= drop_dest_dir
;
641 new_path
= g_strdup(filer_window
->path
);
645 /* Drop onto a program/directory of some sort */
647 if (gtk_drag_get_source_widget(context
) == widget
)
649 Collection
*collection
= filer_window
->collection
;
651 if (collection
->items
[item_number
].selected
)
655 if (item
->base_type
== TYPE_DIRECTORY
&&
656 !(item
->flags
& ITEM_FLAG_APPDIR
))
658 if (provides(context
, text_uri_list
) ||
659 provides(context
, XdndDirectSave0
))
660 type
= drop_dest_dir
;
664 if (provides(context
, text_uri_list
) ||
665 provides(context
, application_octet_stream
))
666 type
= drop_dest_prog
;
671 new_path
= make_path(filer_window
->path
,
672 item
->leafname
)->str
;
673 collection_set_cursor_item(filer_window
->collection
,
679 g_dataset_set_data(context
, "drop_dest_type", type
);
682 gdk_drag_status(context
, action
, time
);
683 g_dataset_set_data_full(context
, "drop_dest_path",
684 g_strdup(new_path
), g_free
);
692 /* Remove panel highlights */
693 static void drag_leave(GtkWidget
*widget
,
694 GdkDragContext
*context
,
696 FilerWindow
*filer_window
)
698 collection_set_cursor_item(filer_window
->collection
, -1);
701 /* User has tried to drop some data on us. Decide what format we would
704 static gboolean
drag_drop(GtkWidget
*widget
,
705 GdkDragContext
*context
,
709 FilerWindow
*filer_window
)
712 char *leafname
= NULL
;
713 GdkAtom target
= GDK_NONE
;
715 char *dest_type
= NULL
;
717 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
718 dest_type
= g_dataset_get_data(context
, "drop_dest_type");
720 g_return_val_if_fail(dest_path
!= NULL
, TRUE
);
722 if (dest_type
== drop_dest_dir
&& provides(context
, XdndDirectSave0
))
724 leafname
= get_xds_prop(context
);
727 if (strchr(leafname
, '/'))
729 error
= _("XDS protocol error: "
730 "leafname may not contain '/'\n");
739 uri
= g_string_new(NULL
);
740 g_string_sprintf(uri
, "file://%s%s",
744 set_xds_prop(context
, uri
->str
);
745 g_string_free(uri
, TRUE
);
747 target
= XdndDirectSave0
;
748 g_dataset_set_data_full(context
, "leafname",
754 "XdndDirectSave0 target provided, but the atom "
755 "XdndDirectSave0 (type text/plain) did not "
756 "contain a leafname\n");
758 else if (provides(context
, text_uri_list
))
759 target
= text_uri_list
;
760 else if (provides(context
, application_octet_stream
))
761 target
= application_octet_stream
;
762 else if (dest_type
== drop_dest_prog
&&
763 provides(context
, _rox_run_action
))
764 target
= _rox_run_action
;
767 if (dest_type
== drop_dest_dir
)
768 error
= _("Sorry - I require a target type of "
769 "text/uri-list or XdndDirectSave0.");
771 error
= _("Sorry - I require a target type of "
772 "text/uri-list or application/octet-stream.");
777 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
779 delayed_error(PROJECT
, error
);
782 gtk_drag_get_data(widget
, context
, target
, time
);
787 static void got_run_action(GtkWidget
*widget
,
788 GdkDragContext
*context
,
789 GtkSelectionData
*selection_data
,
792 char *type
= selection_data
->data
;
794 char *dest_path
, *link
;
795 char buffer
[MAXPATHLEN
+ 1];
798 g_return_if_fail(type
!= NULL
);
800 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
802 /* dest_path might be a symlink - dereference it if so */
803 len
= readlink(dest_path
, buffer
, sizeof(buffer
) - 1);
810 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
812 sub
= strchr(type
, '/');
813 g_return_if_fail(sub
!= NULL
);
815 media
= g_strndup(type
, sub
- type
);
818 link
= type_ask_which_action(media
, sub
);
823 if (symlink(dest_path
, link
))
824 delayed_error(PROJECT
, g_strerror(errno
));
827 /* Called when a text/uri-list arrives */
828 static void desktop_drag_data_received(GtkWidget
*widget
,
829 GdkDragContext
*context
,
832 GtkSelectionData
*selection_data
,
835 FilerWindow
*filer_window
)
840 if (!selection_data
->data
)
846 gdk_window_get_position (widget
->window
, &dx
, &dy
);
850 uris
= uri_list_to_gslist(selection_data
->data
);
852 for (next
= uris
; next
; next
= next
->next
)
856 path
= get_local_path((gchar
*) next
->data
);
859 pinboard_pin(path
, NULL
, x
, y
);
870 /* Called when some data arrives from the remote app (which we asked for
873 static void drag_data_received(GtkWidget
*widget
,
874 GdkDragContext
*context
,
877 GtkSelectionData
*selection_data
,
880 FilerWindow
*filer_window
)
882 if (!selection_data
->data
)
885 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
892 got_data_xds_reply(widget
, context
,
893 selection_data
, time
,
897 got_data_raw(widget
, context
, selection_data
, time
);
899 case TARGET_URI_LIST
:
900 got_uri_list(widget
, context
, selection_data
, time
);
902 case TARGET_RUN_ACTION
:
903 got_run_action(widget
, context
, selection_data
, time
);
906 gtk_drag_finish(context
, FALSE
, FALSE
, time
);
907 delayed_error("drag_data_received",
908 _("Unknown target"));
913 static void got_data_xds_reply(GtkWidget
*widget
,
914 GdkDragContext
*context
,
915 GtkSelectionData
*selection_data
,
917 FilerWindow
*filer_window
)
919 gboolean mark_unsafe
= TRUE
;
920 char response
= *selection_data
->data
;
924 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
926 if (selection_data
->length
!= 1)
931 /* Sender couldn't save there - ask for another
934 if (provides(context
, application_octet_stream
))
936 mark_unsafe
= FALSE
; /* Wait and see */
938 gtk_drag_get_data(widget
, context
,
939 application_octet_stream
, time
);
942 error
= _("Remote app can't or won't send me "
945 else if (response
== 'S')
947 /* Success - data is saved */
948 mark_unsafe
= FALSE
; /* It really is safe */
949 gtk_drag_finish(context
, TRUE
, FALSE
, time
);
951 refresh_dirs(dest_path
);
953 else if (response
!= 'E')
955 error
= _("XDS protocol error: "
956 "return code should be 'S', 'F' or 'E'\n");
958 /* else: error has been reported by the sender */
962 set_xds_prop(context
, "");
963 /* Unsave also implies that the drag failed */
964 gtk_drag_finish(context
, FALSE
, FALSE
, time
);
968 delayed_error(PROJECT
, error
);
971 static void got_data_raw(GtkWidget
*widget
,
972 GdkDragContext
*context
,
973 GtkSelectionData
*selection_data
,
981 g_return_if_fail(selection_data
->data
!= NULL
);
983 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
985 if (g_dataset_get_data(context
, "drop_dest_type") == drop_dest_prog
)
987 /* The data needs to be sent to an application */
988 run_with_data(dest_path
,
989 selection_data
->data
, selection_data
->length
);
990 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
994 leafname
= g_dataset_get_data(context
, "leafname");
996 leafname
= _("UntitledData");
998 fd
= open(make_path(dest_path
, leafname
)->str
,
999 O_WRONLY
| O_CREAT
| O_EXCL
| O_NOCTTY
,
1000 S_IRUSR
| S_IRGRP
| S_IROTH
|
1001 S_IWUSR
| S_IWGRP
| S_IWOTH
);
1004 error
= g_strerror(errno
);
1008 selection_data
->data
,
1009 selection_data
->length
) == -1)
1010 error
= g_strerror(errno
);
1012 if (close(fd
) == -1 && !error
)
1013 error
= g_strerror(errno
);
1015 refresh_dirs(dest_path
);
1020 if (provides(context
, XdndDirectSave0
))
1021 set_xds_prop(context
, "");
1022 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
1023 delayed_error(_("Error saving file"), error
);
1026 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
1029 /* We've got a list of URIs from somewhere (probably another filer window).
1030 * If the files are on the local machine then try to copy them ourselves,
1031 * otherwise, if there was only one file and application/octet-stream was
1032 * provided, get the data via the X server.
1034 static void got_uri_list(GtkWidget
*widget
,
1035 GdkDragContext
*context
,
1036 GtkSelectionData
*selection_data
,
1042 gboolean send_reply
= TRUE
;
1046 dest_path
= g_dataset_get_data(context
, "drop_dest_path");
1047 type
= g_dataset_get_data(context
, "drop_dest_type");
1049 g_return_if_fail(dest_path
!= NULL
);
1051 uri_list
= uri_list_to_gslist(selection_data
->data
);
1054 error
= _("No URIs in the text/uri-list (nothing to do!)");
1055 else if (type
== drop_dest_prog
)
1056 run_with_files(dest_path
, uri_list
);
1057 else if ((!uri_list
->next
) && (!get_local_path(uri_list
->data
)))
1059 /* There is one URI in the list, and it's not on the local
1060 * machine. Get it via the X server if possible.
1063 if (provides(context
, application_octet_stream
))
1066 leaf
= strrchr(uri_list
->data
, '/');
1070 leaf
= uri_list
->data
;
1071 g_dataset_set_data_full(context
, "leafname",
1072 g_strdup(leaf
), g_free
);
1073 gtk_drag_get_data(widget
, context
,
1074 application_octet_stream
, time
);
1078 error
= _("Can't get data from remote machine "
1079 "(application/octet-stream not provided)");
1083 GSList
*local_paths
= NULL
;
1086 /* Either one local URI, or a list. If everything in the list
1087 * isn't local then we are stuck.
1090 for (next_uri
= uri_list
; next_uri
; next_uri
= next_uri
->next
)
1094 path
= get_local_path((char *) next_uri
->data
);
1097 local_paths
= g_slist_append(local_paths
,
1100 error
= _("Some of these files are on a "
1101 "different machine - they will be "
1107 error
= _("None of these files are on the local "
1108 "machine - I can't operate on multiple "
1109 "remote files - sorry.");
1111 else if (context
->action
== GDK_ACTION_MOVE
)
1112 action_move(local_paths
, dest_path
);
1113 else if (context
->action
== GDK_ACTION_COPY
)
1114 action_copy(local_paths
, dest_path
, NULL
);
1115 else if (context
->action
== GDK_ACTION_LINK
)
1116 action_link(local_paths
, dest_path
);
1118 error
= _("Unknown action requested");
1120 for (next
= local_paths
; next
; next
= next
->next
)
1122 g_slist_free(local_paths
);
1127 gtk_drag_finish(context
, FALSE
, FALSE
, time
); /* Failure */
1128 delayed_error(_("Error getting file list"), error
);
1130 else if (send_reply
)
1131 gtk_drag_finish(context
, TRUE
, FALSE
, time
); /* Success! */
1133 next_uri
= uri_list
;
1136 g_free(next_uri
->data
);
1137 next_uri
= next_uri
->next
;
1139 g_slist_free(uri_list
);