From 04c4abd81855ad8e818886a790840b2ac21561b3 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Wed, 3 Feb 1999 11:46:01 +0000 Subject: [PATCH] 1999-02-03 Federico Mena Quintero * gdnd.c (gdnd_validate_action): Added an "on_desktop" argument; this specifies that the user is dragging over the desktop. Added cases for drags of desktop icons and URLs. (gdnd_perform_drop): New public function to handle drops. This is now the master function to handle drops -- use this to make all of MC consistent. (drop_on_directory): Made static and renamed from gdnd_drop_on_directory(). Made it fit for use by gdnd_perform_drop(). (drop_url_on_directory): New function to drop an url on a directory, moved over from gdesktop.c. (drop_uri_list_on_directory): New function to handle drops of URI lists on a directory. (drop_on_file): New function to handle drops on a non-directory file entry. This is moved over from gdesktop.c, desktop_icon_drop_uri_list(). This is yet to be finished. * gdesktop.c (desktop_icon_drop_uri_list): Fix memory leak. (desktop_drag_motion): Use gdnd_validate_action(). (dnd_icon_targets): Allow dropping URLs on icons. (icon_drag_motion): Use gdnd_validate_action(). (desktop_drag_data_received): Use gdnd_perform_drop(). (icon_drag_data_received): Use gdnd_perform_drop(). * gscreen.c (panel_icon_list_drag_data_received): Use gdnd_perform_drop(). (panel_clist_drag_data_received): Use gdnd_perform_drop(). (panel_tree_drag_data_received): Use gdnd_perform_drop(). * gcmd.c (gnome_about_cmd): Fixed Foundation typo, and updated the copyright date. --- gnome/ChangeLog | 34 ++++++ gnome/gdesktop.c | 239 +++++++------------------------------- gnome/gdnd.c | 297 +++++++++++++++++++++++++++++++++++------------ gnome/gdnd.h | 11 +- gnome/gscreen.c | 91 ++++++++++----- 5 files changed, 370 insertions(+), 302 deletions(-) diff --git a/gnome/ChangeLog b/gnome/ChangeLog index 77d146b5c..199c4ce34 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,37 @@ +1999-02-03 Federico Mena Quintero + + * gdnd.c (gdnd_validate_action): Added an "on_desktop" argument; + this specifies that the user is dragging over the desktop. Added + cases for drags of desktop icons and URLs. + (gdnd_perform_drop): New public function to handle drops. This is + now the master function to handle drops -- use this to make all of + MC consistent. + (drop_on_directory): Made static and renamed from + gdnd_drop_on_directory(). Made it fit for use by + gdnd_perform_drop(). + (drop_url_on_directory): New function to drop an url on a + directory, moved over from gdesktop.c. + (drop_uri_list_on_directory): New function to handle drops of URI + lists on a directory. + (drop_on_file): New function to handle drops on a non-directory + file entry. This is moved over from gdesktop.c, + desktop_icon_drop_uri_list(). This is yet to be finished. + + * gdesktop.c (desktop_icon_drop_uri_list): Fix memory leak. + (desktop_drag_motion): Use gdnd_validate_action(). + (dnd_icon_targets): Allow dropping URLs on icons. + (icon_drag_motion): Use gdnd_validate_action(). + (desktop_drag_data_received): Use gdnd_perform_drop(). + (icon_drag_data_received): Use gdnd_perform_drop(). + + * gscreen.c (panel_icon_list_drag_data_received): Use + gdnd_perform_drop(). + (panel_clist_drag_data_received): Use gdnd_perform_drop(). + (panel_tree_drag_data_received): Use gdnd_perform_drop(). + + * gcmd.c (gnome_about_cmd): Fixed Foundation typo, and updated the + copyright date. + 1999-02-02 Miguel de Icaza * gnome-file-property-dialog.c (create_general_properties): Use diff --git a/gnome/gdesktop.c b/gnome/gdesktop.c index 9bf807de9..dd15253aa 100644 --- a/gnome/gdesktop.c +++ b/gnome/gdesktop.c @@ -73,6 +73,7 @@ static GtkTargetEntry dnd_icon_sources[] = { static GtkTargetEntry dnd_icon_targets[] = { { TARGET_MC_DESKTOP_ICON_TYPE, 0, TARGET_MC_DESKTOP_ICON }, { TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST }, + { TARGET_URL_TYPE, 0, TARGET_URL } }; static GtkTargetEntry dnd_desktop_targets[] = { @@ -1163,8 +1164,7 @@ setup_icon_dnd_source (DesktopIconInfo *dii) dii); } -/* - * Callback used when we get a drag_motion event from a desktop icon. We have +/* Callback used when we get a drag_motion event from a desktop icon. We have * to decide which operation to perform based on the type of the data the user * is dragging. */ @@ -1176,27 +1176,25 @@ icon_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, gu char *filename; file_entry *fe; GdkDragAction action; + GtkWidget *source_widget; + int is_desktop_icon; dii = data; - filename = g_concat_dir_and_file (desktop_directory, dii->filename); fe = file_entry_from_file (filename); g_free (filename); + if (!fe) + return 0; /* eeek */ - action = 0; /* be pessimistic by defaulting to nothing */ + gdnd_find_panel_by_drag_context (context, &source_widget); + is_desktop_icon = gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON); - if (dii->selected - && gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON) - && (context->actions & GDK_ACTION_MOVE)) - action = GDK_ACTION_MOVE; - else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) { - if (S_ISDIR (fe->buf.st_mode) || fe->f.link_to_dir) - action = context->suggested_action; - else if (is_exe (fe->buf.st_mode) - && if_link_is_exe (fe) - && (context->actions & GDK_ACTION_COPY)) - action = GDK_ACTION_COPY; - } + action = gdnd_validate_action (context, + TRUE, + source_widget != NULL, + source_widget && is_desktop_icon, + fe, + dii->selected); gdk_drag_status (context, action, time); return TRUE; @@ -1245,11 +1243,6 @@ drop_desktop_icons (GdkDragContext *context, GtkSelectionData *data, int x, int GList *l; GSList *sel_icons, *sl; - /* - * FIXME: this needs to do the right thing (what Windows does) - * when desktop_auto_placement is enabled. - */ - /* Find the icon that the user is dragging */ source_dii = find_icon_by_drag_context (context); @@ -1292,94 +1285,6 @@ drop_desktop_icons (GdkDragContext *context, GtkSelectionData *data, int x, int g_slist_free (sel_icons); } -/** - * drop_on_file_entry - */ -static void -desktop_icon_drop_uri_list (DesktopIconInfo *dii, GdkDragContext *context, GtkSelectionData *data) -{ - char *filename; - file_entry *fe; - int size; - char *buf; - const char *mime_type; - - filename = g_concat_dir_and_file (desktop_directory, dii->filename); - - fe = file_entry_from_file (filename); - if (!fe) - return; /* eek */ - - /* 1. If it is a directory, drop the files there */ - - if (fe->f.link_to_dir) { - gdnd_drop_on_directory (context, data, filename); - goto out; - } - - /* 2. Try to use a metadata-based drop action */ - - if (gnome_metadata_get (filename, "drop-action", &size, &buf) == 0) { - /*action_drop (filename, buf, context, data);*/ /* Fixme: i'm undefined */ - g_free (buf); - goto out; - } - - /* 3. Try a drop action from the mime-type */ - - mime_type = gnome_mime_type_or_default (filename, NULL); - if (mime_type) { - char *action; - - action = gnome_mime_get_value (mime_type, "drop-action"); - - if (action) { - /*action_drop (filename, action, context, data);*/ /* Fixme: i'm undefined */ - goto out; - } - } - - /* 4. Executable. Try metadata keys for "open" */ - - if (is_exe (fe->buf.st_mode) && if_link_is_exe (fe)) { - GList *names, *l; - int len, i; - char **drops; - - /* Convert the list of filenames into an array of char */ - - names = gnome_uri_list_extract_uris (data->data); - len = g_list_length (names); - drops = (char **) g_malloc (sizeof (char *) * (len+1)); - - for (l = names, i = 0; i < len; i++, l = l->next) { - char *text = l->data; - - if (strncmp (text, "file:", 5) == 0) - text += 5; - - drops [i] = text; - } - drops [i] = NULL; - - if (gnome_metadata_get (filename, "open", &size, &buf) == 0) { - exec_extension (filename, buf, drops, NULL, 0); - goto out2; - } - - exec_extension (filename, "%f %q", drops, NULL, 0); - - g_free (drops); - out2: - gnome_uri_list_free_strings (names); - g_free (buf); - - } - - out: - file_entry_free (fe); -} - static void icon_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer user_data) @@ -1388,22 +1293,21 @@ icon_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gin dii = user_data; - switch (info) { - case TARGET_MC_DESKTOP_ICON: - if (dii->selected) - drop_desktop_icons (context, data, x + dii->x, y + dii->y); - else - printf ("FIXME: what do drop?\n"); /* FIXME */ + if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON) && dii->selected) + drop_desktop_icons (context, data, x + dii->x, y + dii->y); + else { + char *full_name; + file_entry *fe; - break; + full_name = g_concat_dir_and_file (desktop_directory, dii->filename); + fe = file_entry_from_file (full_name); + if (!fe) + return; /* eeeek */ - case TARGET_URI_LIST: - printf ("Wheeeeee!\n"); - desktop_icon_drop_uri_list (dii, context, data); - break; + if (gdnd_perform_drop (context, data, fe, full_name)) + reload_desktop_icons (TRUE, x, y); - default: - break; + file_entry_free (fe); } } @@ -1727,73 +1631,27 @@ desktop_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, { GdkDragAction action; GtkWidget *source_widget; + int is_desktop_icon; - action = context->suggested_action; /* this is the default */ + gdnd_find_panel_by_drag_context (context, &source_widget); + is_desktop_icon = gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON); - if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON)) - action = GDK_ACTION_MOVE; - else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) { - source_widget = gtk_drag_get_source_widget (context); - - /* If it comes from ourselves, make move the default unless the - * user is explicitly asking for ASK. - */ - if (source_widget - && context->suggested_action != GDK_ACTION_ASK - && (context->actions & GDK_ACTION_MOVE)) - action = GDK_ACTION_MOVE; - } else if (gdnd_drag_context_has_target (context, TARGET_URL)) { - /* FIXME: right now we only allow links. We should see if we - * can move or copy stuff instead (for ftp instead of http - * sites, for example). - */ - if (context->actions & GDK_ACTION_LINK) - action = GDK_ACTION_LINK; - else - action = 0; - } else - action = 0; /* we cannot handle that type of data */ + action = gdnd_validate_action (context, + TRUE, + source_widget != NULL, + source_widget && is_desktop_icon, + NULL, + FALSE); gdk_drag_status (context, action, time); return TRUE; } -/* - * drop_url: Invoked when we have received an URL from Netscape. - * Install the url on the ~/desktop directory - */ -static void -drop_url (GdkDragContext *context, GtkSelectionData *data, gint x, gint y) -{ - char *template; - - template = g_concat_dir_and_file (desktop_directory, "urlXXXXXX"); - - if (mktemp (template)) { - FILE *f; - - f = fopen (template, "w"); - if (f){ - fprintf (f, "URL: %s\n", data->data); - fclose (f); - - gnome_metadata_set (template, "desktop-url", - strlen (data->data) + 1, - data->data); - - reload_desktop_icons (TRUE, x, y); - } - } - - g_free (template); -} - /* Callback used when the root window receives a drop */ static void desktop_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, gpointer user_data) { - int retval; gint dx, dy; /* Fix the proxy window offsets */ @@ -1802,23 +1660,19 @@ desktop_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, x += dx; y += dy; - switch (info) { - case TARGET_MC_DESKTOP_ICON: + if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON)) drop_desktop_icons (context, data, x, y); - break; + else { + file_entry *desktop_fe; - case TARGET_URI_LIST: - retval = gdnd_drop_on_directory (context, data, desktop_directory); - if (retval) + desktop_fe = file_entry_from_file (desktop_directory); + if (!desktop_fe) + return; /* eeek */ + + if (gdnd_perform_drop (context, data, desktop_fe, desktop_directory)) reload_desktop_icons (TRUE, x, y); - break; - case TARGET_URL: - drop_url (context, data, x, y); - break; - - default: - break; + file_entry_free (desktop_fe); } } @@ -1984,11 +1838,6 @@ icon_is_in_area (DesktopIconInfo *dii, int x1, int y1, int x2, int y2) dicon = DESKTOP_ICON (dii->dicon); - /* FIXME: this only intersects the rectangle with the icon image's - * bounds. Doing the "hard" intersection with the actual shape of the - * image is left as an exercise to the reader. - */ - x1 -= dii->x; y1 -= dii->y; x2 -= dii->x; diff --git a/gnome/gdnd.c b/gnome/gdnd.c index 40364cff6..289ddaeb6 100644 --- a/gnome/gdnd.c +++ b/gnome/gdnd.c @@ -13,6 +13,7 @@ #include "fileopctx.h" #include "main.h" #include "panel.h" +#include "ext.h" #include "gscreen.h" #include "../vfs/vfs.h" #include @@ -96,21 +97,20 @@ get_action (GdkDragContext *context) return action; } -/* - * Performs a drop action on the specified panel. Only supports copy - * and move operations. The files are moved or copied to the - * specified destination directory. +/* Performs a drop action on the specified panel. Only supports copy and move + * operations. The files are moved or copied to the specified destination + * directory. */ static void -perform_action_on_panel (WPanel *source_panel, GdkDragAction action, char *destdir, int ask) +perform_action_on_panel (WPanel *source_panel, GdkDragAction action, char *destdir) { switch (action) { case GDK_ACTION_COPY: - panel_operate (source_panel, OP_COPY, destdir, ask); + panel_operate (source_panel, OP_COPY, destdir, FALSE); break; case GDK_ACTION_MOVE: - panel_operate (source_panel, OP_MOVE, destdir, ask); + panel_operate (source_panel, OP_MOVE, destdir, FALSE); break; default: @@ -146,11 +146,10 @@ perform_links (GList *names, char *destdir) } } -/* - * Performs a drop action manually, by going through the list of files - * to operate on. The files are copied or moved to the specified - * directory. This should also encompass symlinking when the file - * operations window supports links. +/* Performs a drop action manually, by going through the list of files to + * operate on. The files are copied or moved to the specified directory. This + * should also encompass symlinking when the file operations window supports + * links. */ static void perform_action (GList *names, GdkDragAction action, char *destdir) @@ -226,46 +225,24 @@ perform_action (GList *names, GdkDragAction action, char *destdir) file_op_context_destroy (ctx); } -/** - * gdnd_drop_on_directory: - * @context: The drag context received from the drag_data_received callback - * @selection_data: The selection data from the drag_data_received callback - * @dirname: The name of the directory to drop onto - * - * Extracts an URI list from the selection data and drops all the files in the - * specified directory. - * - * Return Value: TRUE if the drop was sucessful, FALSE if it was not. - **/ -int -gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *destdir) +/* Drop a URI list on a directory. If the data comes from a panel, use the nice + * MC progress display; otherwise `do it by hand'. + */ +static void +drop_uri_list_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, + GdkDragAction action, char *destdir) { - GdkDragAction action; WPanel *source_panel; GtkWidget *source_widget; GList *names; - if (context->action == GDK_ACTION_ASK) { - action = get_action (context); - - if (action == GDK_ACTION_ASK) - return FALSE; - - } else - action = context->action; - - /* If we are dragging from a file panel, we can display a nicer status - * display. But if the drag was from the tree, we cannot do this. - */ source_panel = gdnd_find_panel_by_drag_context (context, &source_widget); - if (source_widget == source_panel->tree) - source_panel = NULL; - /* Symlinks do not use file.c */ - - if (source_panel && action != GDK_ACTION_LINK) - perform_action_on_panel (source_panel, action, destdir, - context->action == GDK_ACTION_ASK); + /* We cannot use file.c if we are going to symlink or if we are dragging + * from a tree. + */ + if (source_panel && source_widget != source_panel->tree && action != GDK_ACTION_LINK) + perform_action_on_panel (source_panel, action, destdir); else { names = gnome_uri_list_extract_uris (selection_data->data); @@ -276,10 +253,153 @@ gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_dat gnome_uri_list_free_strings (names); } +} + +/* Drop a Netscape URL in a directory */ +static void +drop_url_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *destdir) +{ + char *template; + + template = g_concat_dir_and_file (destdir, "urlXXXXXX"); + + if (mktemp (template)) { + FILE *f; + + f = fopen (template, "w"); + if (f) { + fprintf (f, "URL: %s\n", selection_data->data); + fclose (f); + + gnome_metadata_set (template, "desktop-url", + strlen (selection_data->data) + 1, + selection_data->data); + } + } + + g_free (template); +} + +/* Drop stuff on a directory */ +static int +drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *destdir) +{ + GdkDragAction action; + + if (context->action == GDK_ACTION_ASK) { + action = get_action (context); + + if (action == GDK_ACTION_ASK) + return FALSE; + } else + action = context->action; + + if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) + drop_uri_list_on_directory (context, selection_data, action, destdir); + else if (gdnd_drag_context_has_target (context, TARGET_URL)) + drop_url_on_directory (context, selection_data, destdir); + else + return FALSE; return TRUE; } +/* Drop stuff on a non-directory file. This uses metadata and MIME as well. */ +static int +drop_on_file (GdkDragContext *context, GtkSelectionData *selection_data, + file_entry *dest_fe, char *dest_name) +{ + int size; + char *buf; + const char *mime_type; + + /* 1. Try to use a metadata-based drop action */ + + if (gnome_metadata_get (dest_name, "drop-action", &size, &buf) == 0) { + /*action_drop (dest_name, buf, context, selection_data);*/ /* Fixme: i'm undefined */ + g_free (buf); + return TRUE; + } + + /* 2. Try a drop action from the MIME-type */ + + mime_type = gnome_mime_type_or_default (dest_name, NULL); + if (mime_type) { + char *action; + + action = gnome_mime_get_value (mime_type, "drop-action"); + if (action) { + /* Fixme: i'm undefined */ + /*action_drop (dest_name, action, context, selection_data);*/ + return TRUE; + } + } + + /* 3. If executable, try metadata keys for "open" */ + + if (is_exe (dest_fe->buf.st_mode) && if_link_is_exe (dest_fe)) { + GList *names, *l; + int len, i; + char **drops; + + /* FIXME: handle the case for Netscape URLs */ + + /* Convert the data list into an array of strings */ + + names = gnome_uri_list_extract_uris (selection_data->data); + len = g_list_length (names); + drops = g_new (char *, len + 1); + + for (l = names, i = 0; i < len; i++, l = l->next) { + char *text = l->data; + + if (strncmp (text, "file:", 5) == 0) + text += 5; + + drops[i] = text; + } + drops[i] = NULL; + + if (gnome_metadata_get (dest_name, "open", &size, &buf) == 0) + exec_extension (dest_name, buf, drops, NULL, 0); + else + exec_extension (dest_name, "%f %q", drops, NULL, 0); + + g_free (drops); + gnome_uri_list_free_strings (names); + g_free (buf); + + return TRUE; + } + + return FALSE; /* could not drop */ +} + +int +gdnd_perform_drop (GdkDragContext *context, GtkSelectionData *selection_data, + file_entry *dest_fe, char *dest_name) +{ + GdkDragAction action; + + g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (selection_data != NULL, FALSE); + g_return_val_if_fail (dest_fe != NULL, FALSE); + + /* Get action */ + + if (context->action == GDK_ACTION_ASK) { + action = get_action (context); + if (action == GDK_ACTION_ASK) + return FALSE; + } else + action = context->action; + + if (S_ISDIR (dest_fe->buf.st_mode) || dest_fe->f.link_to_dir) + return drop_on_directory (context, selection_data, dest_name); + else + return drop_on_file (context, selection_data, dest_fe, dest_name); +} + /** * gdnd_drag_context_has_target: * @context: The context to query for a target type @@ -348,6 +468,7 @@ gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **source_wid /** * gdnd_validate_action: * @context: The drag context for this drag operation. + * @on_desktop: Whether we are dragging onto the desktop or a desktop icon. * @same_process: Whether the drag comes from the same process or not. * @same_source: If same_process, then whether the source and dest widgets are the same. * @dest: The destination file entry, or NULL if dropping on empty space. @@ -359,48 +480,70 @@ gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **source_wid * Return value: The computed action, meant to be passed to gdk_drag_action(). **/ GdkDragAction -gdnd_validate_action (GdkDragContext *context, int same_process, int same_source, +gdnd_validate_action (GdkDragContext *context, + int on_desktop, int same_process, int same_source, file_entry *dest_fe, int dest_selected) { int on_directory; int on_exe; - if (dest_fe) { - on_directory = dest_fe->f.link_to_dir || S_ISDIR (dest_fe->buf.st_mode); - on_exe = is_exe (dest_fe->buf.st_mode) && if_link_is_exe (dest_fe); - } + g_return_val_if_fail (context != NULL, 0); - if (dest_fe) { - if (same_source && dest_selected) - return 0; + /* If we are dragging a desktop icon onto the desktop or onto a selected + * desktop icon, unconditionally specify MOVE. + */ + if (on_desktop + && gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON) + && (!dest_fe || dest_selected)) + return GDK_ACTION_MOVE; - if (on_directory) { - if ((same_source || same_process) - && (context->actions & GDK_ACTION_MOVE) - && context->suggested_action != GDK_ACTION_ASK) + if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) { + if (dest_fe) { + on_directory = S_ISDIR (dest_fe->buf.st_mode) || dest_fe->f.link_to_dir; + on_exe = is_exe (dest_fe->buf.st_mode) && if_link_is_exe (dest_fe); + } + + if (dest_fe) { + if (same_source && dest_selected) + return 0; + + if (on_directory) { + if ((same_source || same_process) + && (context->actions & GDK_ACTION_MOVE) + && context->suggested_action != GDK_ACTION_ASK) + return GDK_ACTION_MOVE; + else + return context->suggested_action; + } else if (on_exe) { + if (context->actions & GDK_ACTION_COPY) + return GDK_ACTION_COPY; + } else if (same_source) + return 0; + else if (same_process + && (context->actions & GDK_ACTION_MOVE) + && context->suggested_action != GDK_ACTION_ASK) return GDK_ACTION_MOVE; else return context->suggested_action; - } else if (on_exe) { - if (context->actions & GDK_ACTION_COPY) - return GDK_ACTION_COPY; - } else if (same_source) - return 0; - else if (same_process - && (context->actions & GDK_ACTION_MOVE) - && context->suggested_action != GDK_ACTION_ASK) - return GDK_ACTION_MOVE; - else - return context->suggested_action; - } else { - if (same_source) - return 0; - else if (same_process - && (context->actions & GDK_ACTION_MOVE) - && context->suggested_action != GDK_ACTION_ASK) - return GDK_ACTION_MOVE; - else - return context->suggested_action; + } else { + if (same_source) + return 0; + else if (same_process + && (context->actions & GDK_ACTION_MOVE) + && context->suggested_action != GDK_ACTION_ASK) + return GDK_ACTION_MOVE; + else + return context->suggested_action; + } + } + + if (gdnd_drag_context_has_target (context, TARGET_URL)) { + /* FIXME: right now we only allow links. We should see if we + * can move or copy stuff instead (for ftp instead of http + * sites, for example). + */ + if (context->actions & GDK_ACTION_LINK) + return GDK_ACTION_LINK; } return 0; diff --git a/gnome/gdnd.h b/gnome/gdnd.h index 95c2cd3f0..2d843749f 100644 --- a/gnome/gdnd.h +++ b/gnome/gdnd.h @@ -35,8 +35,12 @@ extern GdkAtom dnd_target_atoms[]; /* Initializes drag and drop by interning the target convenience atoms */ void gdnd_init (void); -/* Drop the list of URIs in the selection data to the specified directory */ -int gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *dirname); +/* Perform a drop on the specified file entry. This function takes care of + * determining how to drop the stuff epending on the type of the file entry. + * Returns TRUE if an action was performed, FALSE otherwise (i.e. invalid drop). + */ +int gdnd_perform_drop (GdkDragContext *context, GtkSelectionData *selection_data, + file_entry *dest_fe, char *dest_name); /* Test whether the specified context has a certain target type */ int gdnd_drag_context_has_target (GdkDragContext *context, TargetType type); @@ -47,7 +51,8 @@ WPanel *gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **so /* Computes the final drag action based on the suggested actions and the * specified conditions. */ -GdkDragAction gdnd_validate_action (GdkDragContext *context, int same_process, int same_source, +GdkDragAction gdnd_validate_action (GdkDragContext *context, + int on_desktop, int same_process, int same_source, file_entry *dest_fe, int dest_selected); diff --git a/gnome/gscreen.c b/gnome/gscreen.c index b145e6975..8b160fe16 100644 --- a/gnome/gscreen.c +++ b/gnome/gscreen.c @@ -776,25 +776,38 @@ panel_icon_list_drag_data_received (GtkWidget *widget, WPanel *panel) { GnomeIconList *gil = GNOME_ICON_LIST (widget); - char *dir; + file_entry *fe; + char *file; + int free_file, free_fe; int idx; gboolean reload; - + idx = gnome_icon_list_get_icon_at (gil, x, y); - if (idx == -1) - dir = g_strdup (panel->cwd); - else { - if (panel->dir.list [idx].f.link_to_dir || - S_ISDIR (panel->dir.list [idx].buf.st_mode)) - dir = concat_dir_and_file (panel->cwd, panel->dir.list [idx].fname); - else - dir = g_strdup (panel->cwd); + if (idx == -1) { + file = panel->cwd; + fe = file_entry_from_file (file); + if (!fe) + return; /* eeeek */ + + free_file = FALSE; + free_fe = TRUE; + } else { + file = g_concat_dir_and_file (panel->cwd, panel->dir.list[idx].fname); + fe = &panel->dir.list[idx]; + + free_file = TRUE; + free_fe = FALSE; } - reload = gdnd_drop_on_directory (context, selection_data, dir); - g_free (dir); + reload = gdnd_perform_drop (context, selection_data, fe, file); - if (reload){ + if (free_file) + g_free (file); + + if (free_fe) + file_entry_free (fe); + + if (reload) { update_one_panel_widget (panel, 0, UP_KEEPSEL); panel_update_contents (panel); } @@ -817,26 +830,42 @@ panel_clist_drag_data_received (GtkWidget *widget, WPanel *panel) { GtkCList *clist = GTK_CLIST (widget); - char *dir; + file_entry *fe; + char *file; + int free_file, free_fe; int row; + int reload; - if (gtk_clist_get_selection_info (clist, x, y, &row, NULL) == 0) - dir = g_strdup (panel->cwd); - else { + if (gtk_clist_get_selection_info (clist, x, y, &row, NULL) == 0) { + file = panel->cwd; + fe = file_entry_from_file (file); + if (!fe) + return; /* eeeek */ + + free_file = FALSE; + free_fe = TRUE; + } else { g_assert (row < panel->count); - if (S_ISDIR (panel->dir.list [row].buf.st_mode) || - panel->dir.list [row].f.link_to_dir) - dir = concat_dir_and_file (panel->cwd, panel->dir.list [row].fname); - else - dir = g_strdup (panel->cwd); + file = g_concat_dir_and_file (panel->cwd, panel->dir.list[row].fname); + fe = &panel->dir.list[row]; + + free_file = TRUE; + free_fe = FALSE; } - gdnd_drop_on_directory (context, selection_data, dir); - g_free (dir); + reload = gdnd_perform_drop (context, selection_data, fe, file); - update_one_panel_widget (panel, 0, UP_KEEPSEL); - panel_update_contents (panel); + if (free_file) + g_free (file); + + if (free_fe) + file_entry_free (fe); + + if (reload) { + update_one_panel_widget (panel, 0, UP_KEEPSEL); + panel_update_contents (panel); + } } /** @@ -857,6 +886,7 @@ panel_tree_drag_data_received (GtkWidget *widget, GtkDTree *dtree = GTK_DTREE (widget); GtkCTreeNode *node; int row, col; + file_entry *fe; char *path; if (!gtk_clist_get_selection_info (GTK_CLIST (dtree), x, y, &row, &col)) @@ -866,10 +896,15 @@ panel_tree_drag_data_received (GtkWidget *widget, if (!node) return; gtk_ctree_expand_recursive (GTK_CTREE (dtree), node); + path = gtk_dtree_get_row_path (dtree, node, 0); + fe = file_entry_from_file (path); + if (!fe) + return; /* eeeek */ - gdnd_drop_on_directory (context, selection_data, path); + gdnd_perform_drop (context, selection_data, fe, path); + file_entry_free (fe); g_free (path); } @@ -1073,6 +1108,7 @@ panel_clist_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gin fe = &panel->dir.list[idx]; action = gdnd_validate_action (context, + FALSE, source_widget != NULL, source_widget == widget, fe, @@ -1187,6 +1223,7 @@ panel_icon_list_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, fe = (idx == -1) ? NULL : &panel->dir.list[idx]; action = gdnd_validate_action (context, + FALSE, source_widget != NULL, source_widget == widget, fe,