Re: [PATCH] Fixed drag and drop between Nautilus and Mozilla
- From: Jorn Baayen <jbaayen gnome org>
- To: Alexander Larsson <alexl redhat com>
- Cc: nautilus-list gnome org
- Subject: Re: [PATCH] Fixed drag and drop between Nautilus and Mozilla
- Date: Wed, 12 Jan 2005 20:54:17 +0100
Hi,
Thanks for your comments. On the basis of them I have rewritten the
patch - attached.
It is a lot cleaner now, and it works exactly as you described in that
mail. With one exception:
The default mozilla drag action is GDK_ACTION_COPY, and the code opens
the link-or-download dialog on that. We can't distinguish it from a
ctrl-drag, where the dialog will also popup.
I removed the (crappy and broken) custom linking code, as I get the
feeling it either belongs somewhere else in a more generic place within
nautilus, or in gnome-vfs. In a WebDAV window right click->"make link"
doesn't work either ..
Then there still is the remaining issue that the .desktop file
generation code doesn't do an overwrite check.
Cheers,
Jorn
On Wed, 2005-01-12 at 15:34 +0100, Alexander Larsson wrote:
> On Sun, 2005-01-09 at 21:27 +0100, Jorn Baayen wrote:
> > Hi,
> >
> > Not entirely unmotivated by the bounty I have been working on #127553,
> > "Drag and Drop between Gnome and Mozilla". I got the thing mostly
> > solved, but the code could use some reviewing, and I need some
> > directions for solving the last remaining issue:
> >
> > nautilus_link_local_create just overwrites any file without asking. So,
> > we need an overwrite confirmation dialog. However, the standard one is
> > nested in nautilus-file-operations.c:handle_transfer_overwrite. I could
> > move it into its own function, which could then be used in
> > nautilus_link_local_create as well. Another option would be
> > link_local_creating the links in tmp files, and then using
> > fm_directory_view_move_copy_items to move them to the right place.
> >
> > I'll attach the patch to this mail as well for increased reviewing
> > convenience.
>
> Thanks. Btw. I once wrote up how i wanted this to work for another
> bounty seeker:
> http://mail.gnome.org/archives/nautilus-list/2004-February/msg00074.html
> Did you read that?
>
> Anyway, back to the patch:
>
> +if (eel_is_remote_uri (uri)) {
> +/* Create a list of remote uris, so that we only
> + * once have to ask what to do
> + */
>
> This isn't right. eel_is_remote_uri uses gnome_vfs_uri_is_local() which
> does some magic to check the "localness" of the file, such that e.g.
> files on NFS partitions are not local. Use
> eel_vfs_has_capability (uri, EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)
> instead to match the rest of the function. (although the capabilities
> stuff was never really finished well it should work for this.)
>
> nautilus_link_local_create_from_gnome_entry (entry, container_uri,
> - (n_links > 0) ? NULL: &point, screen_num);
> + &point, screen_num);
>
> Why this change? Doesn't that mean all the icons will be placed in the
> same position? Maybe we should just use &point for the first item in the
> list?
>
> +if (n_symlink_uris > 0) {
> +fm_directory_view_move_copy_items (symlink_uri_list, points,
> + container_uri,
> + GDK_ACTION_LINK, x, y, FM_DIRECTORY_VIEW (view));
> +g_list_free (symlink_uri_list);
> +}
>
> Why use GDK_ACTION_LINK here? Shouldn't you use "action" as specified by
> the user? (or as returned by nautilus_drag_drop_action_ask earlier in
> the function).
>
> + if (strcmp (scheme, "http") == 0) {
> + if (n_uris > 1) {
> + prompt = _("Download the links?");
> + detail = _("You can download the links or create bookmarks.");
> + } else {
> + prompt = _("Download the link?");
> + detail = _("You can download the link or create a bookmark.");
> + }
> +
> + link_action = _("_Bookmark");
> + copy_action = _("_Download");
>
> I'm not sure bookmark is the best term here. It has a very specific
> meaning in the context of web browsers, and making a deskop file link is
> not it.
>
> Also, the general handling of dnd modifiers seems wrong to me. If you
> hold down ctrl-shift to force a link, or ctrl to force a copy you should
> never ask the user what they want, since they explicitly requested a
> specific operation. I'm not sure if mozilla supports the ASK action, but
> if ASK is used and specified by the user, it looks like this code will
> ask twice, which strikes me as strange.
>
> While I was looking at this i took the opportunity to remove the old
> "historic" links support and remove some unused nautilus-link stuff. The
> changes conflict (very slightly) with your patch (one argument removed
> from nautilus_link_local_create).
>
> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> Alexander Larsson Red Hat, Inc
> alexl redhat com alla lysator liu se
> He's a globe-trotting Jewish jungle king on the hunt for the last specimen of
> a great and near-mythical creature. She's a provocative motormouth snake
> charmer with the power to see death. They fight crime!
>
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.381
diff -u -r1.381 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c 15 Dec 2004 11:20:41 -0000 1.381
+++ libnautilus-private/nautilus-icon-container.c 12 Jan 2005 19:40:17 -0000
@@ -227,6 +227,7 @@
RENAMING_ICON,
LAYOUT_CHANGED,
MOVE_COPY_ITEMS,
+ HANDLE_URL,
HANDLE_URI_LIST,
PREVIEW,
SELECTION_CHANGED,
@@ -4105,6 +4106,19 @@
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT);
+ signals[HANDLE_URL]
+ = g_signal_new ("handle_url",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (NautilusIconContainerClass,
+ handle_url),
+ NULL, NULL,
+ nautilus_marshal_VOID__STRING_INT_INT_INT,
+ G_TYPE_NONE, 4,
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INT);
signals[HANDLE_URI_LIST]
= g_signal_new ("handle_uri_list",
G_TYPE_FROM_CLASS (class),
@@ -4112,9 +4126,9 @@
G_STRUCT_OFFSET (NautilusIconContainerClass,
handle_uri_list),
NULL, NULL,
- nautilus_marshal_VOID__POINTER_INT_INT_INT,
+ nautilus_marshal_VOID__STRING_INT_INT_INT,
G_TYPE_NONE, 4,
- G_TYPE_POINTER,
+ G_TYPE_STRING,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT);
Index: libnautilus-private/nautilus-icon-container.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.h,v
retrieving revision 1.84
diff -u -r1.84 nautilus-icon-container.h
--- libnautilus-private/nautilus-icon-container.h 10 Jan 2004 20:58:06 -0000 1.84
+++ libnautilus-private/nautilus-icon-container.h 12 Jan 2005 19:40:17 -0000
@@ -100,8 +100,12 @@
int copy_action,
int x,
int y);
+ void (* handle_url) (NautilusIconContainer *container,
+ char *url,
+ int x,
+ int y);
void (* handle_uri_list) (NautilusIconContainer *container,
- GList *item_uris,
+ char *uri_list,
int x,
int y);
Index: libnautilus-private/nautilus-icon-dnd.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-dnd.c,v
retrieving revision 1.140
diff -u -r1.140 nautilus-icon-dnd.c
--- libnautilus-private/nautilus-icon-dnd.c 22 Oct 2004 15:44:16 -0000 1.140
+++ libnautilus-private/nautilus-icon-dnd.c 12 Jan 2005 19:40:17 -0000
@@ -615,6 +615,20 @@
nautilus_icon_container_update_icon (container, drop_target_icon);
}
+/* handle dropped url */
+static void
+receive_dropped_url (NautilusIconContainer *container, const char *encoded_url, GdkDragAction action, int x, int y)
+{
+ if (encoded_url == NULL) {
+ return;
+ }
+
+ g_signal_emit_by_name (container, "handle_url",
+ encoded_url,
+ action,
+ x, y);
+}
+
/* handle dropped uri list */
static void
receive_dropped_uri_list (NautilusIconContainer *container, const char *uri_list, GdkDragAction action, int x, int y)
@@ -1590,8 +1604,13 @@
(NAUTILUS_ICON_CONTAINER (widget),
(char *) data->data, x, y);
break;
- case NAUTILUS_ICON_DND_URI_LIST:
case NAUTILUS_ICON_DND_URL:
+ receive_dropped_url
+ (NAUTILUS_ICON_CONTAINER (widget),
+ (char *) data->data, context->action, x, y);
+ success = TRUE;
+ break;
+ case NAUTILUS_ICON_DND_URI_LIST:
receive_dropped_uri_list
(NAUTILUS_ICON_CONTAINER (widget),
(char *) data->data, context->action, x, y);
Index: libnautilus-private/nautilus-marshal.list
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-marshal.list,v
retrieving revision 1.7
diff -u -r1.7 nautilus-marshal.list
--- libnautilus-private/nautilus-marshal.list 11 Jan 2004 20:34:32 -0000 1.7
+++ libnautilus-private/nautilus-marshal.list 12 Jan 2005 19:40:17 -0000
@@ -6,7 +6,7 @@
INT:POINTER,POINTER
POINTER:VOID
VOID:DOUBLE
-VOID:POINTER,INT,INT,INT
+VOID:STRING,INT,INT,INT
VOID:POINTER,POINTER
VOID:POINTER,POINTER
VOID:POINTER,STRING
Index: src/file-manager/fm-icon-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
retrieving revision 1.303
diff -u -r1.303 fm-icon-view.c
--- src/file-manager/fm-icon-view.c 12 Jan 2005 14:36:42 -0000 1.303
+++ src/file-manager/fm-icon-view.c 12 Jan 2005 19:40:18 -0000
@@ -46,6 +46,7 @@
#include <gtk/gtkradioaction.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkwindow.h>
+#include <gtk/gtkstock.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-desktop-item.h>
@@ -187,7 +188,7 @@
NautilusFile *file,
gboolean start_flag);
static void update_layout_menus (FMIconView *view);
-
+static GdkDragAction ask_link_action (FMIconView *view);
static void fm_icon_view_iface_init (NautilusViewIface *iface);
@@ -2458,27 +2459,140 @@
gtk_widget_show (GTK_WIDGET (icon_container));
}
+/* Handles an URL received from Mozilla */
+static void
+icon_view_handle_url (NautilusIconContainer *container, const char *encoded_url,
+ GdkDragAction action, int x, int y, FMIconView *view)
+{
+ GdkPoint point;
+ GdkScreen *screen;
+ int screen_num;
+ char *url, *title;
+ char *link_name, *link_file_name, *link_display_name;
+ char *container_uri;
+ GArray *points;
+ char **bits;
+ GList *uri_list = NULL;
+
+ if (encoded_url == NULL) {
+ return;
+ }
+
+ container_uri = fm_directory_view_get_backing_uri (FM_DIRECTORY_VIEW (view));
+ g_return_if_fail (container_uri != NULL);
+
+ if (eel_vfs_has_capability (container_uri,
+ EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)) {
+ eel_show_warning_dialog (_("Drag and drop is not supported."),
+ _("Drag and drop is only supported on local file systems."),
+ _("Drag and Drop Error"),
+ fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view)));
+ g_free (container_uri);
+ return;
+ }
+
+ /* GDK_ACTION_COPY is Mozilla's default drag action:
+ * On a standard drag from mozilla we ask the user
+ * whether he wants to copy or link the link. */
+ if (action == GDK_ACTION_COPY || action == GDK_ACTION_ASK) {
+ action = ask_link_action (view);
+ if (action == 0) {
+ g_free (container_uri);
+ return;
+ }
+ }
+
+ /* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
+ * and we don't support combinations either. */
+ if ((action != GDK_ACTION_DEFAULT) &&
+ (action != GDK_ACTION_COPY) &&
+ (action != GDK_ACTION_MOVE) &&
+ (action != GDK_ACTION_LINK)) {
+ eel_show_warning_dialog (_("Drag and drop is not supported."),
+ _("An invalid drag type was used."),
+ _("Drag and Drop Error"),
+ fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view)));
+ g_free (container_uri);
+ return;
+ }
+
+ /* _NETSCAPE_URL_ works like this: $URL\n$TITLE */
+ bits = g_strsplit (encoded_url, "\n", 0);
+ switch (g_strv_length (bits)) {
+ case 0:
+ g_strfreev (bits);
+ g_free (container_uri);
+ return;
+ case 1:
+ url = bits[0];
+ title = NULL;
+ break;
+ default:
+ url = bits[0];
+ title = bits[1];
+ }
+
+ if (action == GDK_ACTION_LINK) {
+ if (eel_str_is_empty (title)) {
+ link_name = eel_uri_get_basename (url);
+ } else {
+ link_name = g_strdup (title);
+ }
+
+ if (!eel_str_is_empty (link_name)) {
+ /* FIXME: Handle name conflicts? */
+ link_file_name = g_strconcat (link_name, ".desktop", NULL);
+ link_display_name = g_strdup_printf (_("link to %s"), link_name);
+
+ point.x = x;
+ point.y = y;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (view));
+ screen_num = gdk_screen_get_number (screen);
+
+ nautilus_link_local_create (container_uri,
+ link_file_name,
+ link_display_name,
+ "gnome-fs-bookmark",
+ url,
+ &point,
+ screen_num);
+
+ g_free (link_file_name);
+ g_free (link_display_name);
+ }
+ g_free (link_name);
+ } else {
+ GdkPoint tmp_point = { 0, 0 };
+
+ /* pass in a 1-item array of icon positions, relative to x, y */
+ points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
+ g_array_append_val (points, tmp_point);
+
+ uri_list = g_list_append (uri_list, url);
+
+ fm_directory_view_move_copy_items (uri_list, points,
+ container_uri,
+ action, x, y, FM_DIRECTORY_VIEW (view));
+
+ g_list_free (uri_list);
+ g_array_free (points, TRUE);
+ }
+
+ g_strfreev (bits);
+
+ g_free (container_uri);
+}
+
static void
icon_view_handle_uri_list (NautilusIconContainer *container, const char *item_uris,
GdkDragAction action, int x, int y, FMIconView *view)
{
-
GList *uri_list;
GList *node, *real_uri_list = NULL;
- GnomeDesktopItem *entry;
- GdkPoint point;
- char *uri;
- char *path;
- char *stripped_uri;
char *container_uri;
- char *mime_type;
- const char *last_slash, *link_name;
- char *link_file_name;
- int n_uris, n_links;
- gboolean all_local;
+ int n_uris;
GArray *points;
- GdkScreen *screen;
- int screen_num;
if (item_uris == NULL) {
return;
@@ -2498,7 +2612,7 @@
}
if (action == GDK_ACTION_ASK) {
- action = nautilus_drag_drop_action_ask
+ action = nautilus_drag_drop_action_ask
(GTK_WIDGET (container),
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
if (action == 0) {
@@ -2506,7 +2620,7 @@
return;
}
}
-
+
/* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
* and we don't support combinations either. */
if ((action != GDK_ACTION_DEFAULT) &&
@@ -2521,128 +2635,43 @@
return;
}
- point.x = x;
- point.y = y;
-
- screen = gtk_widget_get_screen (GTK_WIDGET (view));
- screen_num = gdk_screen_get_number (screen);
-
/* Most of what comes in here is not really URIs, but rather paths that
* have a file: prefix in them. We try to sanitize the uri list as a
- * result. Additionally, if they are all local files, then we can copy
- * them. Otherwise, we just make links.
+ * result.
*/
- all_local = TRUE;
n_uris = 0;
uri_list = nautilus_icon_dnd_uri_list_extract_uris (item_uris);
for (node = uri_list; node != NULL; node = node->next) {
- gchar *sanitized_uri;
+ char *sanitized_uri;
sanitized_uri = eel_make_uri_from_half_baked_uri (node->data);
if (sanitized_uri == NULL)
continue;
real_uri_list = g_list_append (real_uri_list, sanitized_uri);
- if (eel_vfs_has_capability (sanitized_uri,
- EEL_VFS_CAPABILITY_IS_REMOTE_AND_SLOW)) {
- all_local = FALSE;
- }
n_uris++;
}
nautilus_icon_dnd_uri_list_free_strings (uri_list);
- if (all_local == TRUE &&
- (action == GDK_ACTION_COPY ||
- action == GDK_ACTION_MOVE)) {
- /* Copying files */
- if (n_uris == 1) {
- GdkPoint tmp_point = { 0, 0 };
-
- /* pass in a 1-item array of icon positions, relative to x, y */
- points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
- g_array_append_val (points, tmp_point);
- } else {
- points = NULL;
- }
- fm_directory_view_move_copy_items (real_uri_list, points,
- container_uri,
- action, x, y, FM_DIRECTORY_VIEW (view));
-
- if (points)
- g_array_free (points, TRUE);
- } else {
- n_links = 0;
- for (node = real_uri_list; node != NULL; node = node->next) {
- /* Make a link using the desktop file contents? */
- uri = node->data;
- path = gnome_vfs_get_local_path_from_uri (uri);
-
- if (path != NULL) {
- mime_type = gnome_vfs_get_mime_type (uri);
-
- if (mime_type != NULL &&
- (strcmp (mime_type, "application/x-gnome-app-info") == 0 ||
- strcmp (mime_type, "application/x-desktop") == 0)) {
- entry = gnome_desktop_item_new_from_file (path,
- 0,
- NULL);
- } else {
- entry = NULL;
- }
-
- g_free (mime_type);
- g_free (path);
- } else {
- entry = NULL;
- }
+ if (n_uris == 1) {
+ GdkPoint tmp_point = { 0, 0 };
- if (entry != NULL) {
- /* FIXME: Handle name conflicts? */
- nautilus_link_local_create_from_gnome_entry (entry, container_uri,
- (n_links > 0) ? NULL: &point, screen_num);
+ /* pass in a 1-item array of icon positions, relative to x, y */
+ points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
+ g_array_append_val (points, tmp_point);
+ } else {
+ points = NULL;
+ }
- gnome_desktop_item_unref (entry);
- continue;
- }
+ fm_directory_view_move_copy_items (real_uri_list, points,
+ container_uri,
+ action, x, y, FM_DIRECTORY_VIEW (view));
- /* Make a link from the URI alone. Generate the file
- * name by extracting the basename of the URI.
- */
- /* FIXME: This should be using eel_uri_get_basename
- * instead of a "roll our own" solution.
- */
- stripped_uri = eel_str_strip_trailing_chr (uri, '/');
- last_slash = strrchr (stripped_uri, '/');
- link_name = last_slash == NULL ? NULL : last_slash + 1;
-
- if (!eel_str_is_empty (link_name)) {
- link_file_name = g_strconcat (link_name, ".desktop", NULL);
- /* FIXME: Handle name conflicts? */
- nautilus_link_local_create (container_uri,
- link_file_name,
- link_name,
- NULL, uri,
- (n_links > 0) ? NULL: &point,
- screen_num);
- g_free (link_file_name);
- }
-
- n_links++;
- g_free (stripped_uri);
-
- /* The following break statement handles mozilla urls.
- * Do not remove it; otherwise, nautilus will create two
- * links when the url is dropped on the desktop.
- */
- if (path == NULL) {
- break;
- }
- }
- }
-
nautilus_icon_dnd_uri_list_free_strings (real_uri_list);
+ if (points != NULL)
+ g_array_free (points, TRUE);
+
g_free (container_uri);
-
}
static char *
@@ -2681,6 +2710,42 @@
}
}
+static GdkDragAction
+ask_link_action (FMIconView *view)
+{
+ int button_pressed;
+ GdkDragAction result;
+
+ button_pressed = eel_run_simple_dialog (GTK_WIDGET (fm_directory_view_get_containing_window (FM_DIRECTORY_VIEW (view))),
+ TRUE,
+ GTK_MESSAGE_QUESTION,
+ _("Download the link?"),
+ _("You can download it or copy is as link."),
+ NULL, /* as per HIG */
+ _("Copy as _Link"),
+ GTK_STOCK_CANCEL,
+ _("_Download"),
+ NULL);
+
+ switch (button_pressed) {
+ case 0:
+ result = GDK_ACTION_LINK;
+ break;
+ case 1:
+ case GTK_RESPONSE_DELETE_EVENT:
+ result = 0;
+ break;
+ case 2:
+ result = GDK_ACTION_COPY;
+ break;
+ default:
+ g_assert_not_reached ();
+ result = 0;
+ }
+
+ return result;
+}
+
static void
fm_icon_view_class_init (FMIconViewClass *klass)
{
@@ -2805,6 +2870,8 @@
labels_beside_icons_changed_callback,
icon_view, G_OBJECT (icon_view));
+ g_signal_connect_object (get_icon_container (icon_view), "handle_url",
+ G_CALLBACK (icon_view_handle_url), icon_view, 0);
g_signal_connect_object (get_icon_container (icon_view), "handle_uri_list",
G_CALLBACK (icon_view_handle_uri_list), icon_view, 0);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]