mc/gnome/gdnd.c

622 lines
15 KiB
C
Raw Normal View History

/* Drag and Drop functionality for the Midnight Commander
*
* Copyright (C) 1998 The Free Software Foundation
*
* Authors: Federico Mena <federico@nuclecu.unam.mx>
* Miguel de Icaza <miguel@nuclecu.unam.mx>
*/
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "global.h"
#include "file.h"
#include "fileopctx.h"
#include "main.h"
#include "panel.h"
#include "ext.h"
#include "gscreen.h"
#include "../vfs/vfs.h"
#include <gdk/gdkprivate.h>
These are a bunch of changes to fix CORBA and session management. They are almost complete (i.e. to handle all nitty gritty cases), but they seem to be working OK right now. SM should be much more stable now. Please tell me if you find any weird behavior - Federico 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * gdesktop-icon.c (desktop_icon_realize): Remove the WM_CLIENT_LEADER property from icon windows so that window managers will not store SM information for them. * gnome-open-dialog.c: Added missing #includes. * gdesktop-init.c (desktop_init_at): Removed an unused variable. * gdesktop.h: Added some missing prototypes. * gmain.h: Added some missing prototypes. * Makefile.in: Added gsession.[ch] to the list of sources. * gmain.c (create_panels): Consider whether we have a CORBA server and session management. * gdesktop.c: #include "gdesktop-init.h" * gdesktop.c: Added a missing cast to GNOME_DIALOG. * gmain.c (create_panels): Removed the run_desktop global variable. * glayout.c (create_container): Set the wmclass of the panel to include its unique ID. * gsession.[ch]: New file with the functions that deal with session management. * glayout.c (gnome_exit): Use session_set_restart(). * gcorba.c (corba_init): Now returns an int with an error value. (corba_init_server): Initialize the server properly. Fixed all the object implementation code. (corba_create_window): New function used to create a window with the CORBA server. * gmain.c (gnome_check_super_user): Now the check for running as root is done here. There should be no GUI code in src/. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * dlg.c (dlg_run_done): Do not call the callback of a NULL current widget. * setup.h: Added missing prototype for setup_init(). * filegui.c (check_progress_buttons): Added a missing return value. * dlg.c (remove_widget): Added a missing return value. * main.c: Removed the global directory_list variable. Removed the main_corba_register_server() function. * main.h: Removed the global run_desktop variable. * panel.h: Now the panel structure has a unique numerical ID used for session management. * screen.c (panel_new): Maintain a unique ID for each panel. * main.c (maybe_display_linksdir): Handle display of the desktop init dir here. (main): Call gnome_check_super_user(). (init_corba_with_args): Call corba_init_server(). * main.c (init_corba_with_args): Do CORBA initialization here. Also removed the global force_activation option. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * vfs.c (vfs_add_current_stamps): Only do stamping of the panels if they exist. * mcserv.c: #include <sys/wait.h> (get_client): Put `#ifdef __EMX__' around an otherwise-unused variable. * utilvfs.c (vfs_split_url): Fix NULL <-> 0 confusion when comparing characters. * ftpfs.c (retrieve_dir): Removed unused variable dot_dot_found. * extfs.c (extfs_init): Assign `key' to c, not `&key'.
1999-03-30 10:09:56 +04:00
#include "gdesktop.h"
#include "gdnd.h"
/* Atoms for the DnD target types */
GdkAtom dnd_target_atoms[TARGET_NTARGETS];
/**
* gdnd_init:
*
* Initializes the dnd_target_atoms array by interning the DnD target atom names.
**/
void
gdnd_init (void)
{
dnd_target_atoms[TARGET_MC_DESKTOP_ICON] =
gdk_atom_intern (TARGET_MC_DESKTOP_ICON_TYPE, FALSE);
dnd_target_atoms[TARGET_URI_LIST] =
gdk_atom_intern (TARGET_URI_LIST_TYPE, FALSE);
dnd_target_atoms[TARGET_TEXT_PLAIN] =
gdk_atom_intern (TARGET_TEXT_PLAIN_TYPE, FALSE);
dnd_target_atoms[TARGET_URL] =
gdk_atom_intern (TARGET_URL_TYPE, FALSE);
}
/* The menu of DnD actions */
static GnomeUIInfo actions[] = {
GNOMEUIINFO_ITEM_NONE (N_("_Move here"), NULL, NULL),
GNOMEUIINFO_ITEM_NONE (N_("_Copy here"), NULL, NULL),
GNOMEUIINFO_ITEM_NONE (N_("_Link here"), NULL, NULL),
GNOMEUIINFO_SEPARATOR,
1998-12-17 11:39:16 +03:00
GNOMEUIINFO_ITEM_NONE (N_("Cancel drag"), NULL, NULL),
GNOMEUIINFO_END
};
/* Pops up a menu of actions to perform on dropped files */
static GdkDragAction
get_action (GdkDragContext *context)
{
GtkWidget *menu;
int a;
GdkDragAction action;
/* Create the menu and set the sensitivity of the items based on the
* allowed actions.
*/
menu = gnome_popup_menu_new (actions);
gtk_widget_set_sensitive (actions[0].widget, (context->actions & GDK_ACTION_MOVE) != 0);
gtk_widget_set_sensitive (actions[1].widget, (context->actions & GDK_ACTION_COPY) != 0);
gtk_widget_set_sensitive (actions[2].widget, (context->actions & GDK_ACTION_LINK) != 0);
a = gnome_popup_menu_do_popup_modal (menu, NULL, NULL, NULL, NULL);
switch (a) {
case 0:
action = GDK_ACTION_MOVE;
break;
case 1:
action = GDK_ACTION_COPY;
break;
case 2:
action = GDK_ACTION_LINK;
break;
default:
action = GDK_ACTION_ASK; /* Magic value to indicate cancellation */
}
gtk_widget_destroy (menu);
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.
*/
static void
perform_action_on_panel (WPanel *source_panel, GdkDragAction action, char *destdir)
{
switch (action) {
case GDK_ACTION_COPY:
panel_operate (source_panel, OP_COPY, destdir, FALSE);
break;
case GDK_ACTION_MOVE:
panel_operate (source_panel, OP_MOVE, destdir, FALSE);
break;
default:
g_assert_not_reached ();
}
/* Finish up */
update_one_panel_widget (source_panel, FALSE, UP_KEEPSEL);
if (action == GDK_ACTION_MOVE)
panel_update_contents (source_panel);
}
1998-11-29 10:50:44 +03:00
/*
* Performs handling of symlinks via drag and drop. This should go
* away when operation windows support links.
*/
static void
perform_links (GList *names, char *destdir)
{
char *name;
char *dest_name;
for (; names; names = names->next) {
name = names->data;
if (strncmp (name, "file:", 5) == 0)
name += 5;
dest_name = g_concat_dir_and_file (destdir, x_basename (name));
mc_symlink (name, dest_name);
g_free (dest_name);
}
}
/* 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)
{
struct stat s;
char *name;
char *dest_name;
int result;
FileOpContext *ctx;
ctx = file_op_context_new ();
switch (action) {
case GDK_ACTION_COPY:
file_op_context_create_ui (ctx, OP_COPY, FALSE);
break;
case GDK_ACTION_MOVE:
file_op_context_create_ui (ctx, OP_MOVE, FALSE);
break;
default:
g_assert_not_reached ();
}
for (; names; names = names->next) {
name = names->data;
if (strncmp (name, "file:", 5) == 0)
name += 5;
dest_name = g_concat_dir_and_file (destdir, x_basename (name));
do {
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
result = mc_lstat (name, &s);
if (result != 0) {
/* FIXME: this error message sucks */
if (file_error (_("Could not stat %s\n%s"), dest_name) != FILE_RETRY)
result = 0;
} else {
long count = 0;
double bytes = 0;
if (S_ISDIR (s.st_mode)) {
if (action == GDK_ACTION_COPY)
copy_dir_dir (ctx,
name, dest_name,
TRUE, FALSE,
FALSE, FALSE,
&count, &bytes);
else
move_dir_dir (ctx,
name, dest_name,
&count, &bytes);
} else {
if (action == GDK_ACTION_COPY)
copy_file_file (ctx,
name, dest_name,
TRUE,
&count, &bytes, 1);
else
move_file_file (ctx,
name, dest_name,
&count, &bytes);
}
}
} while (result != 0);
g_free (dest_name);
}
file_op_context_destroy (ctx);
}
/* 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)
{
WPanel *source_panel;
GtkWidget *source_widget;
GList *names;
source_panel = gdnd_find_panel_by_drag_context (context, &source_widget);
/* 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);
if (action == GDK_ACTION_LINK)
perform_links (names, destdir);
else
perform_action (names, action, destdir);
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)) {
char *icon;
icon = g_concat_dir_and_file (ICONDIR, "gnome-http-url.png");
desktop_create_url (
template,
selection_data->data,
selection_data->data,
icon);
g_free (icon);
}
g_free (template);
}
/* Drop stuff on a directory */
static int
drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data,
GdkDragAction action, char *directory)
{
int retval;
retval = FALSE;
if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
drop_uri_list_on_directory (context, selection_data, action, directory);
retval = TRUE;
} else if (gdnd_drag_context_has_target (context, TARGET_URL)) {
drop_url_on_directory (context, selection_data, directory);
retval = TRUE;
}
return retval;
}
/* Returns whether a file has the drop-action metadata or MIME property defined
* for it.
*/
static int
file_has_drop_action (char *filename)
{
char *buf;
int size;
const char *mime_type;
if (gnome_metadata_get (filename, "drop-action", &size, &buf) == 0) {
g_free (buf);
return TRUE;
} else {
mime_type = gnome_mime_type_or_default (filename, NULL);
if (!mime_type)
return FALSE;
if (gnome_mime_get_value (mime_type, "drop-action") != NULL)
return TRUE;
else
return FALSE;
}
}
/* Drop stuff on a non-directory file. This uses metadata and MIME as well. */
static int
drop_on_file (GdkDragContext *context, GtkSelectionData *selection_data,
char *dest_full_name, file_entry *dest_fe)
{
int size;
char *buf;
const char *mime_type;
int retval;
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
GList *names, *l;
int len, i;
char **drops;
retval = FALSE; /* assume we cannot drop */
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
/* Convert the data list into an array of strings */
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
names = gnome_uri_list_extract_uris (selection_data->data);
len = g_list_length (names);
drops = g_new (char *, len + 1);
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
for (l = names, i = 0; i < len; i++, l = l->next) {
char *text = l->data;
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
if (strncmp (text, "file:", 5) == 0)
text += 5;
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
drops[i] = text;
}
drops[i] = NULL;
/* 1. Try to use a metadata-based drop action */
if (gnome_metadata_get (dest_full_name, "drop-action", &size, &buf) == 0) {
exec_extension (dest_full_name, buf, drops, NULL, 0, 0);
g_free (buf);
retval = TRUE;
goto out;
}
/* 2. Try a drop action from the MIME-type */
mime_type = gnome_mime_type_or_default (dest_full_name, NULL);
if (mime_type) {
const char *action;
action = gnome_mime_get_value (mime_type, "drop-action");
if (action) {
exec_extension (dest_full_name, action, drops, NULL, 0, 0);
retval = TRUE;
goto out;
}
}
/* 3. If executable, try metadata keys for "open" */
if (is_exe (dest_fe->buf.st_mode) && if_link_is_exe (dest_full_name, dest_fe)) {
/* FIXME: handle the case for Netscape URLs */
if (gnome_metadata_get (dest_full_name, "open", &size, &buf) == 0)
exec_extension (dest_full_name, buf, drops, NULL, 0, 0);
else
exec_extension (dest_full_name, "%f %q", drops, NULL, 0, 0);
g_free (buf);
retval = TRUE;
goto out;
}
out:
1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> This is a semi-big slew of changes to integrate the DESKTOP_BRANCH into the main trunk. Now the gdesktop code creates a temprary WPanel structure and passes it on to the core file management functions. Also, the menu code is improved (we now use gpopup2; gpopup should go away shortly and gpopup2 should replace it). This makes the desktop act consistently with the file panels. Thanks to Jonathan for his help with this branch. * gdnd.c (perform_action): Use mc_lstat(), not mc_stat(). * glayout.c (update_panels): Do not update the panels that are desktop panels. * gdesktop.c (icon_is_in_area): An icon is not considered to be in a 0x0 area. * gpopup2.c (handle_open): Fetch the desktop icon from the filename and call desktop_icon_info_open(). * gdesktop.c (desktop_icon_info_get_by_filename): New function to look up a desktop icon by its filename. * glayout.c (create_new_menu_from): Test for the ".desktop" suffix correctly. * gpopup2.c (handle_properties): If the file comes from a desktop panel, always allow edition of the icon image. 1999-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx> * file.c (erase_dir): Erase metadata for directories as well. (erase_dir_iff_empty): Likewise. (copy_file_file): Delete/copy the metadata even for char/block/sock/fifo files. Same thing for when copying symlinks. (copy_dir_dir): Delete/copy the metadata. (move_dir_dir): Delete/move the metadata. (recursive_erase): Delete the metadata.
1999-03-11 05:40:53 +03:00
g_free (drops);
gnome_uri_list_free_strings (names);
return retval;
}
/**
* gdnd_perform_drop:
* @context: Drag context for operation.
* @selection_data: Selection data from drag_data_received.
* @dest_full_name: Complete name of the destination file or directory.
* @dest_fe: File entry for the destination file or directory.
*
* Performs a drop operation on a directory or file.
*
* Return value: TRUE if the drop is successful, FALSE otherwise.
**/
int
gdnd_perform_drop (GdkDragContext *context, GtkSelectionData *selection_data,
char *dest_full_name, file_entry *dest_fe)
{
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_full_name != 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, action, dest_full_name);
else
return drop_on_file (context, selection_data, dest_full_name, dest_fe);
}
/**
* gdnd_drag_context_has_target:
* @context: The context to query for a target type
* @type: The sought target type
*
* Tests whether the specified drag context has a target of the specified type.
*
* Return value: TRUE if the context has the specified target type, FALSE
* otherwise.
**/
int
gdnd_drag_context_has_target (GdkDragContext *context, TargetType type)
{
GList *l;
g_return_val_if_fail (context != NULL, FALSE);
for (l = context->targets; l; l = l->next)
if (dnd_target_atoms[type] == GPOINTER_TO_INT (l->data))
return TRUE;
return FALSE;
}
/**
* gdnd_find_panel_by_drag_context:
* @context: The context by which to find a panel.
* @source_widget: The source widget is returned here.
*
* Looks in the list of panels for the one that corresponds to the specified
* drag context.
*
* Return value: The sought panel, or NULL if no panel corresponds to the
* context.
**/
WPanel *
gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **source_widget)
{
GtkWidget *source;
GtkWidget *toplevel;
GList *l;
WPanel *panel;
g_return_val_if_fail (context != NULL, NULL);
source = gtk_drag_get_source_widget (context);
if (source_widget)
*source_widget = source;
if (!source)
return NULL; /* different process */
toplevel = gtk_widget_get_toplevel (source);
for (l = containers; l; l = l->next) {
panel = ((PanelContainer *) l->data)->panel;
if (panel->xwindow == toplevel)
return panel;
}
return NULL;
}
/**
* 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_full_name: Complete name of the destination file or directory.
* @dest_fe: File entry for the destination file, or NULL if directory.
* @dest_selected: If dest is non-NULL, whether it is selected or not.
*
* Computes the final drag action based on the suggested action of the specified
* context and conditions.
*
* Return value: The computed action, meant to be passed to gdk_drag_action().
**/
GdkDragAction
gdnd_validate_action (GdkDragContext *context,
int on_desktop, int same_process, int same_source,
char *dest_full_name, file_entry *dest_fe, int dest_selected)
{
int on_directory;
int on_exe;
g_return_val_if_fail (context != NULL, 0);
g_return_val_if_fail (dest_full_name != NULL, 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;
/* See what kind of file the destination is, if any */
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_full_name, dest_fe);
}
if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
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 (file_has_drop_action (dest_full_name)) {
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;
}
}
if (gdnd_drag_context_has_target (context, TARGET_URL)) {
/* FIXME: right now we only allow linking to directories. We
* should see if we can move or copy stuff instead (for ftp
* instead of http sites, for example).
*/
if (dest_fe) {
if (on_directory) {
if (context->actions & GDK_ACTION_LINK)
return GDK_ACTION_LINK;
} else if (context->actions & GDK_ACTION_COPY)
return GDK_ACTION_COPY;
} else if (context->actions & GDK_ACTION_LINK)
return GDK_ACTION_LINK;
}
return 0;
}
/**
* gdnd_can_drop_on_file:
* @full_name: Complete name of the file.
* @fe: File entry for the file.
*
* Computes whether a non-directory file can take drops.
*
* Return value: TRUE if the file can take drops, FALSE otherwise.
**/
int
gdnd_can_drop_on_file (char *full_name, file_entry *fe)
{
g_return_val_if_fail (full_name != NULL, FALSE);
g_return_val_if_fail (fe != NULL, FALSE);
if ((is_exe (fe->buf.st_mode) && if_link_is_exe (full_name, fe))
|| file_has_drop_action (full_name))
return TRUE;
else
return FALSE;
}