diff options
21 files changed, 1362 insertions, 847 deletions
@@ -1,3 +1,146 @@ +2001-03-22 Darin Adler <darin@eazel.com> + + reviewed by: John Sullivan <sullivan@eazel.com> + + Fix bug 6613 (no way to delete files without using trash) by + integrating Maciej's patch to add an optional Delete command (with + some fixes to the patch). There may still be some loose ends. + + Fix bug 2206 (No way to move or copy a file to a different + directory from keyboard) by implementing Cut, Copy, and Paste for + files, in a way that will be familiar to Windows users. The + positioning of the new files is not right yet (they inherit their + position from the old files), there is no feedback when you have + cut some files (Arlo's idea, which I might implement, is to make + them translucent to show they are "on the way out") or when you + have copied some files, and I think there are some other loose + ends. + + Fixed cut, copy, and paste within the file names when you do a + rename. This wasn't working at all. + + Got rid of configure-time checks that were looking at the + existence of some special system files. + + Fixed a few minor bugs discovered by code inspection. + + * libnautilus-extensions/nautilus-global-preferences.h: + * libnautilus-extensions/nautilus-global-preferences.c: + (global_preferences_install_descriptions), + (global_preferences_install_defaults), + (global_preferences_install_visibility), + (global_preferences_create_dialog): Add expert preference to add a + Delete command that bypasses the Trash. + * src/file-manager/nautilus-directory-view-ui.xml: Add Delete, Cut + Files, Copy Files, and Paste Files. + * src/file-manager/fm-directory-view.c: (confirm_delete_directly), + (delete_callback): Add delete code. + (bonobo_menu_empty_trash_callback): Get rid of extraneous cast. + (fm_directory_view_initialize): Track the delete preference. Set + the flags properly to indicate we have our own X window. Add a + target so GTK knows that we accept pastes of copied files. + (forget_clipboard_contents): Helper for when we are no longer the + clipboard owner. + (fm_directory_view_destroy): Remove the delete preference + callback. Free the clipboard contents. + (offset_drop_points): Change so it handles NULL for the list of + points. + (trash_or_delete_files_common): Remove unneeded parameters. + (get_current_event_time): New function, placeholder that just + returned GDK_CURRENT_TIME. Perhaps we should get the real event + time here for use in clipboard manipulation calls. + (copy_or_cut_files): New function. Save the selection for later + use in a paste. + (copy_files_callback), (cut_files_callback): Call the new + copy_or_cut_files function. + (paste_files_callback): Do the clipboard convert that results in + the paste operation. + (real_selection_clear_event): Forget the clipboard contents. + (real_selection_get): Convert the selection into the appropriate + format and put it on the clipboard. + (convert_lines_to_str_list): Helper function for decoding incoming + pasted files. + (real_selection_received): Handle pasted files by parsing and then + triggering a file copy operation. + (real_merge_menus): Add verbs for cut, copy, and paste. + (enable_delete_changed_callback): Keep track of delete command + status in a boolean. + (real_update_menus): Show delete command if the preference is on + and we are not showing "Delete from Trash". Update names of the + Cut and Copy command depending on how many files are selected. + Also desensitize them when none are selected. + (fm_directory_view_select_file): Initialize an uninitialized field. + (fm_directory_view_move_copy_items): Allow relative_item_points to + be NULL. + (real_realize): Create our own X window. + (real_size_allocate): Trick GtkScrolledWindow into doing the right + thing despite the fact that we have our own X window. + (fm_directory_view_initialize_class): Moved down to the bottom so + we don't need so many forward declaractions. Added code to set up + some needed atoms and new default handlers. + + * libnautilus-extensions/nautilus-icon-text-item.c: + (send_focus_event), (iti_stop_editing), (iti_start_editing): Add + code to send the appropriate focus events to the fake off-screen + GtkEntry. This makes the clipboard code that tracks focus-related + signals work properly with this entry. + (iti_event): Tweak the sequence and simplify the code a bit. + * libnautilus/nautilus-clipboard.c: + (set_paste_sensitive_if_clipboard_contains_data): Add more + FIXMEs. This function is very far from useful, and it's not clear + that it can be implemented efficiently under X. + (nautilus_clipboard_set_up_editable): Get rid of silly + "grab_focus" hack that was an attempt to address the problems with + the NautilusIconTextItem. The real solution was to do focusing for + that item too. + (nautilus_clipboard_set_up_editable_in_control): Fix this so it + works when called on an editable that is already focused. + * src/file-manager/fm-icon-view.c: (renaming_icon_callback): Get + rid of "grab_focus" workaround, which wasn't working. + + * acconfig.h: + * configure.in: + Remove all configure checks that were checking the existence of + files. + * libnautilus-extensions/nautilus-medusa-support.c: + (nautilus_medusa_check_cron_is_enabled): Simplify logic so there's + less room for confusion (I did this as a fix for the bug that was + reported on the mailing list, but Rebecka checked in the small + patch first). Also change it so we don't need a configure-time + check for the existence of the process directory and fix it so we + won't get a core dump if the file doesn't have a space character + in it. Also change the logic so we don't leave the directory open + when we do find the cron process. + * libnautilus-extensions/nautilus-volume-monitor.c: + (nautilus_volume_monitor_initialize_class), + (has_removable_mntent_options), (get_removable_volumes), + (volume_is_removable), (volume_is_read_only), + (mount_volume_get_cdrom_name), (mount_volume_activate_cdda), + (mount_volume_activate_cdrom), (build_volume_list_delta), + (get_current_mount_list), (mount_lists_are_identical), + (verify_current_mount_state), (mount_volume_floppy_add), + (get_cdrom_type_solaris), (mount_volume_iso9660_add), + (display_mount_status), (close_error_pipe), + (nautilus_volume_monitor_mount_unmount_removable), + (mount_volume_add_filesystem): Make changes throughout to get rid + of dependence on configure-time file checks and do things at + runtime instead. Also use typedefs to make less code conditional. + Also fix the Solaris CD-ROM code which was casting a GString to + a (char *) before, so it used absurd file names, and failed to open + and returned FALSE all the time. + + * libnautilus-extensions/nautilus-icon-container.c: + (nautilus_icon_container_start_renaming_selected_item): Send the + renaming signal before setting up the rest of the icon. This + change is not really needed, but it's a better order to do things. + + * libnautilus/nautilus-clipboard-ui.xml: Move tips into the + commands instead of the menu items (for style mostly, no practical + implications at the moment). + * src/nautilus-shell-ui.xml: Remove tips from Cut, Copy, and Paste, + since tips from insensitive items aren't used, and if we had tips, + we'd put them on the command, not the menu item, anyway. + 2001-03-22 John Harper <jsh@eazel.com> Fixed bug 7366 (Smooth text layout cache checks take too long): diff --git a/acconfig.h b/acconfig.h index 3f2d8b10a..fc3b04c93 100644 --- a/acconfig.h +++ b/acconfig.h @@ -25,9 +25,3 @@ #undef bzopen #undef bzread #undef bzwrite -#undef HAVE_DEV -#undef HAVE_VOL_DEV -#undef HAVE_VOL -#undef HAVE_ETC_MNTTAB -#undef HAVE_PROC_MOUNTS -#undef HAVE_PROC_PROCESS_FILES diff --git a/configure.in b/configure.in index d01ee6940..056378b90 100644 --- a/configure.in +++ b/configure.in @@ -158,12 +158,6 @@ Determining mount system properties: " AC_CHECK_FUNCS( setmntent endmntent ) AC_CHECK_HEADERS( mntent.h sys/mnttab.h sys/vfstab.h sys/cdio.h ) -AC_CHECK_FILES( /dev, AC_DEFINE(HAVE_DEV)) -AC_CHECK_FILES( /vol/dev, AC_DEFINE(HAVE_VOL_DEV)) -AC_CHECK_FILES( /vol, AC_DEFINE(HAVE_VOL)) -AC_CHECK_FILES( /etc/mnttab, AC_DEFINE(HAVE_ETC_MNTTAB)) -AC_CHECK_FILES( /proc/mounts, AC_DEFINE(HAVE_PROC_MOUNTS)) -AC_CHECK_FILES( /proc/1, AC_DEFINE(HAVE_PROC_PROCESS_FILES)) echo " " diff --git a/libnautilus-extensions/nautilus-global-preferences.c b/libnautilus-extensions/nautilus-global-preferences.c index 14ad7312b..918fadd4f 100644 --- a/libnautilus-extensions/nautilus-global-preferences.c +++ b/libnautilus-extensions/nautilus-global-preferences.c @@ -2,7 +2,7 @@ /* nautilus-prefs-dialog.c - Implementation for preferences dialog. - Copyright (C) 1999, 2000 Eazel, Inc. + Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -100,7 +100,10 @@ global_preferences_install_descriptions (void) _("Open each file or folder in a separate window")); nautilus_preferences_set_description (NAUTILUS_PREFERENCES_CONFIRM_TRASH, - _("Ask before emptying the Trash")); + _("Ask before emptying the Trash or deleting files")); + + nautilus_preferences_set_description (NAUTILUS_PREFERENCES_ENABLE_DELETE, + _("Include a Delete command that bypasses Trash")); nautilus_preferences_set_description (NAUTILUS_PREFERENCES_CLICK_POLICY, _("Click Behavior")); @@ -260,6 +263,10 @@ global_preferences_install_defaults (void) NAUTILUS_USER_LEVEL_NOVICE, TRUE); + nautilus_preferences_default_set_boolean (NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_USER_LEVEL_NOVICE, + FALSE); + nautilus_preferences_default_set_integer (NAUTILUS_PREFERENCES_SHOW_TEXT_IN_ICONS, NAUTILUS_USER_LEVEL_NOVICE, NAUTILUS_SPEED_TRADEOFF_LOCAL_ONLY); @@ -426,6 +433,9 @@ global_preferences_install_visibility (void) nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_CONFIRM_TRASH, NAUTILUS_USER_LEVEL_ADVANCED); + nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_USER_LEVEL_ADVANCED); + nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES, NAUTILUS_USER_LEVEL_INTERMEDIATE); @@ -612,6 +622,11 @@ global_preferences_create_dialog (void) NAUTILUS_PREFERENCES_CONFIRM_TRASH, NAUTILUS_PREFERENCE_ITEM_BOOLEAN); + nautilus_preferences_pane_add_item_to_nth_group (NAUTILUS_PREFERENCES_PANE (windows_and_desktop_pane), + 2, + NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_PREFERENCE_ITEM_BOOLEAN); + /* FIXME: This group clearly doesn't belong in Windows & * Desktop, but there's no obviously-better place for it and * it probably doesn't deserve a pane of its own. diff --git a/libnautilus-extensions/nautilus-global-preferences.h b/libnautilus-extensions/nautilus-global-preferences.h index ab2452e74..26678f255 100644 --- a/libnautilus-extensions/nautilus-global-preferences.h +++ b/libnautilus-extensions/nautilus-global-preferences.h @@ -2,7 +2,7 @@ /* nautilus-global-prefs.h - Nautilus main preferences api. - Copyright (C) 1999, 2000 Eazel, Inc. + Copyright (C) 1999, 2000, 2001 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -49,6 +49,7 @@ BEGIN_GNOME_DECLS /* Trash options */ #define NAUTILUS_PREFERENCES_CONFIRM_TRASH "preferences/confirm_trash" +#define NAUTILUS_PREFERENCES_ENABLE_DELETE "preferences/enable_delete" /* Desktop options */ #define NAUTILUS_PREFERENCES_SHOW_DESKTOP "preferences/show_desktop" diff --git a/libnautilus-extensions/nautilus-icon-container.c b/libnautilus-extensions/nautilus-icon-container.c index 56c8154dd..32e948611 100644 --- a/libnautilus-extensions/nautilus-icon-container.c +++ b/libnautilus-extensions/nautilus-icon-container.c @@ -4862,21 +4862,22 @@ nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *con gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (details->rename_widget), &icon_rect.x0, &icon_rect.y0); gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (details->rename_widget), &icon_rect.x1, &icon_rect.y1); - nautilus_icon_text_item_configure ( - details->rename_widget, - (icon_rect.x0 + icon_rect.x1) / 2, /* x_center */ - icon_rect.y1, /* y_top */ - nautilus_icon_canvas_item_get_max_text_width (icon->item), /* max_text_width */ - details->label_font[details->zoom_level], /* font */ - editable_text, /* text */ - FALSE); /* allocate local copy */ + nautilus_icon_text_item_configure + (details->rename_widget, + (icon_rect.x0 + icon_rect.x1) / 2, /* x_center */ + icon_rect.y1, /* y_top */ + nautilus_icon_canvas_item_get_max_text_width (icon->item), /* max_text_width */ + details->label_font[details->zoom_level], /* font */ + editable_text, /* text */ + FALSE); /* allocate local copy */ nautilus_icon_text_item_start_editing (details->rename_widget); - nautilus_icon_container_update_icon (container, icon); gtk_signal_emit (GTK_OBJECT (container), signals[RENAMING_ICON], nautilus_icon_text_item_get_renaming_editable (details->rename_widget)); + + nautilus_icon_container_update_icon (container, icon); /* We are in renaming mode */ details->renaming = TRUE; diff --git a/libnautilus-extensions/nautilus-icon-text-item.c b/libnautilus-extensions/nautilus-icon-text-item.c index 03d28357a..d1cf5388e 100644 --- a/libnautilus-extensions/nautilus-icon-text-item.c +++ b/libnautilus-extensions/nautilus-icon-text-item.c @@ -90,6 +90,36 @@ enum { }; static guint iti_signals [LAST_SIGNAL] = { 0 }; +static void +send_focus_event (Iti *iti, gboolean in) +{ + ItiPrivate *priv; + GtkWidget *widget; + gboolean has_focus; + GdkEvent fake_event; + + g_assert (in == FALSE || in == TRUE); + + priv = iti->priv; + if (priv->entry == NULL) { + g_assert (!in); + return; + } + + widget = GTK_WIDGET (priv->entry); + has_focus = GTK_WIDGET_HAS_FOCUS (widget); + if (has_focus == in) { + return; + } + + memset (&fake_event, 0, sizeof (fake_event)); + fake_event.focus_change.type = GDK_FOCUS_CHANGE; + fake_event.focus_change.window = widget->window; + fake_event.focus_change.in = in; + gtk_widget_event (widget, &fake_event); + g_assert (GTK_WIDGET_HAS_FOCUS (widget) == in); +} + /* Stops the editing state of an icon text item */ static void iti_stop_editing (Iti *iti) @@ -100,6 +130,8 @@ iti_stop_editing (Iti *iti) iti->editing = FALSE; + send_focus_event (iti, FALSE); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STOPPED]); @@ -232,7 +264,7 @@ iti_start_editing (Iti *iti) gtk_signal_connect (GTK_OBJECT (priv->entry), "activate", GTK_SIGNAL_FUNC (iti_entry_activate), iti); /* Make clipboard functions cause an update the appearance of - the icon text item iteself, since the clipboard functions + the icon text item itself, since the clipboard functions will change the offscreen entry */ gtk_signal_connect_after (GTK_OBJECT (priv->entry), "changed", GTK_SIGNAL_FUNC (iti_entry_text_changed_by_clipboard), iti); @@ -249,6 +281,8 @@ iti_start_editing (Iti *iti) iti->editing = TRUE; + send_focus_event (iti, TRUE); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STARTED]); @@ -1067,13 +1101,13 @@ iti_event (GnomeCanvasItem *item, GdkEvent *event) } else { GTK_WIDGET_UNSET_FLAGS (item->canvas, GTK_HAS_FOCUS); } - - if (iti->editing && !event->focus_change.in) { - iti_edition_accept (iti); - } if (iti->editing) { gtk_widget_event (GTK_WIDGET (priv->entry), event); + + if (!event->focus_change.in) { + iti_edition_accept (iti); + } } return TRUE; diff --git a/libnautilus-extensions/nautilus-medusa-support.c b/libnautilus-extensions/nautilus-medusa-support.c index 2ae619fc4..94a079e66 100644 --- a/libnautilus-extensions/nautilus-medusa-support.c +++ b/libnautilus-extensions/nautilus-medusa-support.c @@ -25,16 +25,13 @@ */ #include <config.h> -#include <glib.h> - -#include <string.h> -#include <sys/types.h> -#include <stdio.h> -#include <dirent.h> +#include "nautilus-medusa-support.h" #include "nautilus-glib-extensions.h" -#include "nautilus-medusa-support.h" #include "nautilus-string.h" +#include <dirent.h> +#include <stdio.h> +#include <sys/types.h> #ifdef HAVE_MEDUSA #include <libmedusa/medusa-system-state.h> @@ -85,7 +82,6 @@ nautilus_medusa_add_system_state_changed_callback (NautilusMedusaChangedCallback NautilusCronStatus nautilus_medusa_check_cron_is_enabled (void) { -#ifdef HAVE_PROC_PROCESS_FILES DIR *proc_directory; struct dirent *file; char *stat_file_name; @@ -93,6 +89,7 @@ nautilus_medusa_check_cron_is_enabled (void) char stat_file_data[128]; const char *stat_file_process_name; int process_number, bytes_read; + NautilusCronStatus status; /* We figure out whether cron is running by reading the proc directory, and checking for a process named or ending with @@ -103,37 +100,39 @@ nautilus_medusa_check_cron_is_enabled (void) return NAUTILUS_CRON_STATUS_UNKNOWN; } - file = readdir (proc_directory); - while (file != NULL) { + status = NAUTILUS_CRON_STATUS_UNKNOWN; + + while ((file = readdir (proc_directory)) != NULL) { /* Process files have numbers */ - if (nautilus_str_to_int (file->d_name, - &process_number)) { - stat_file_name = g_strdup_printf ("/proc/%d/stat", process_number); - stat_file = fopen (stat_file_name, "r"); - g_free (stat_file_name); - - if (stat_file == NULL) { - file = readdir (proc_directory); - continue; - } - - bytes_read = fread (stat_file_data, sizeof (char), NAUTILUS_N_ELEMENTS (stat_file_data) - 1, stat_file); - fclose (stat_file); - stat_file_data[bytes_read] = 0; - - stat_file_process_name = strchr (stat_file_data, ' ') + 1; - - if (nautilus_str_has_prefix (stat_file_process_name, "(crond)")) { - return NAUTILUS_CRON_STATUS_ON; - } + if (!nautilus_str_to_int (file->d_name, &process_number)) { + continue; + } + /* Since we've seen at least one process file, we can change our state + * from "unknown" to "presumed off until proved otherwise". + */ + status = NAUTILUS_CRON_STATUS_OFF; + + stat_file_name = g_strdup_printf ("/proc/%d/stat", process_number); + stat_file = fopen (stat_file_name, "r"); + g_free (stat_file_name); + + if (stat_file == NULL) { + continue; + } + + bytes_read = fread (stat_file_data, 1, sizeof (stat_file_data) - 1, stat_file); + fclose (stat_file); + stat_file_data[bytes_read] = '\0'; + + stat_file_process_name = strchr (stat_file_data, ' '); + + if (nautilus_str_has_prefix (stat_file_process_name, " (crond)")) { + status = NAUTILUS_CRON_STATUS_ON; + break; } - file = readdir (proc_directory); } closedir (proc_directory); - return NAUTILUS_CRON_STATUS_OFF; -#else - return NAUTILUS_CRON_STATUS_UNKNOWN; -#endif + return status; } diff --git a/libnautilus-extensions/nautilus-volume-monitor.c b/libnautilus-extensions/nautilus-volume-monitor.c index e32254a22..8055b44cd 100644 --- a/libnautilus-extensions/nautilus-volume-monitor.c +++ b/libnautilus-extensions/nautilus-volume-monitor.c @@ -2,7 +2,7 @@ /* nautilus-volume-monitor.c - Desktop volume mounting routines. - Copyright (C) 2000 Eazel, Inc. + Copyright (C) 2000, 2001 Eazel, Inc. The Gnome Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -23,8 +23,6 @@ */ #include <config.h> -#include <sys/types.h> - #include "nautilus-volume-monitor.h" #include "nautilus-cdrom-extensions.h" @@ -64,11 +62,13 @@ #ifdef HAVE_MNTENT_H #include <mntent.h> +#define MOUNT_TABLE_PATH _PATH_MNTTAB #endif #ifdef HAVE_SYS_MNTTAB_H #define SOLARIS_MNT 1 #include <sys/mnttab.h> +#define MOUNT_TABLE_PATH "/etc/mnttab" #endif #ifdef SOLARIS_MNT @@ -77,7 +77,16 @@ #define USE_VOLRMMOUNT 0 #endif +#ifndef MNTOPT_RO +#define MNTOPT_RO "ro" +#endif + +#ifndef HAVE_SETMNTENT +#define setmntent(f,m) fopen(f,m) +#endif + #ifdef HAVE_CDDA + #define size16 short #define size32 int @@ -94,48 +103,17 @@ * due to our strict error checking. */ char **broken_header_fix = strerror_tr; -#endif - -#define CHECK_STATUS_INTERVAL 2000 -#ifdef HAVE_ETC_MNTTAB -#define PATH_PROC_MOUNTS "/etc/mnttab" -#define PROC_MOUNTS_SEPARATOR "\t" #endif -#ifdef HAVE_PROC_MOUNTS -#define PATH_PROC_MOUNTS "/proc/mounts" -#define PROC_MOUNTS_SEPARATOR " " -#endif +#define CHECK_STATUS_INTERVAL 2000 #define FLOPPY_MOUNT_PATH_PREFIX "/mnt/fd" -#ifdef HAVE_VOL_DEV -#define FLOPPY_DEVICE_PATH_PREFIX "/vol/dev/diskette" -#else -#define FLOPPY_DEVICE_PATH_PREFIX "/dev/fd" -#endif - #ifdef HAVE_SYS_MNTTAB_H -#define PATH_MOUNT_TABLE "/etc/mnttab" -#endif - -#ifdef HAVE_MNTENT_H -#define PATH_MOUNT_TABLE _PATH_MNTTAB -#endif - -#ifdef HAVE_VOL -# define MNTOPT_NOAUTO "/vol/" -# else -# define MNTOPT_NOAUTO "noauto" -#endif - -#ifndef MNTOPT_RO -# define MNTOPT_RO "ro" -#endif - -#ifndef HAVE_SETMNTENT -#define setmntent(f,m) fopen(f,m) +typedef struct mnttab MountTableEntry; +#else +typedef struct mntent MountTableEntry; #endif struct NautilusVolumeMonitorDetails @@ -147,6 +125,8 @@ struct NautilusVolumeMonitorDetails }; static NautilusVolumeMonitor *global_volume_monitor = NULL; +static const char *floppy_device_path_prefix; +static const char *noauto_string; /* The NautilusVolumeMonitor signals. */ @@ -182,7 +162,7 @@ static GList *mount_volume_add_filesystem (NautilusVolume *volume, static NautilusVolume *create_volume (const char *device_path, const char *mount_path, const char *filesystem); -static NautilusVolume *copy_volume (NautilusVolume *volume); +static NautilusVolume *copy_volume (NautilusVolume *volume); static void find_volumes (NautilusVolumeMonitor *monitor); static void free_mount_list (GList *mount_list); static GList *get_removable_volumes (void); @@ -194,7 +174,8 @@ static gboolean locate_audio_cd (void); #endif #ifdef SOLARIS_MNT -static int get_cdrom_type_solaris(char *vol_dev_path, int* fd) ; +static int get_cdrom_type_solaris (const char *vol_dev_path, + int *fd); #endif NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusVolumeMonitor, @@ -242,7 +223,19 @@ nautilus_volume_monitor_initialize_class (NautilusVolumeMonitorClass *klass) gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); - gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + + /* Check environment a bit. */ + if (g_file_exists ("/vol/dev")) { + floppy_device_path_prefix = "/vol/dev/diskette/"; + } else { + floppy_device_path_prefix = "/dev/fd/"; + } + if (g_file_exists ("/vol")) { + noauto_string = "/vol/"; + } else { + noauto_string = "/dev/fd/"; + } } static void @@ -330,31 +323,20 @@ nautilus_volume_monitor_get_removable_volumes (NautilusVolumeMonitor *monitor) } -#ifdef HAVE_SYS_MNTTAB_H - -static gboolean -has_removable_mntent_options (struct mnttab *ent) -{ - -#else - static gboolean -has_removable_mntent_options (struct mntent *ent) +has_removable_mntent_options (MountTableEntry *ent) { - -#endif /* HAVE_SYS_MNTTAB_H */ - /* Use "owner" or "user" or "users" as our way of determining a removable volume */ if (hasmntopt (ent, "user") != NULL || hasmntopt (ent, "users") != NULL || hasmntopt (ent, "owner") != NULL) { - return TRUE; + return TRUE; } -#if SOLARIS_MNT && HAVE_VOL - if (strstr (ent->mnt_special, "/vol/") == ent->mnt_special) { - return TRUE; - } +#ifdef SOLARIS_MNT + if (nautilus_str_has_prefix (ent->mnt_special, "/vol/")) { + return TRUE; + } #endif return FALSE; @@ -372,36 +354,38 @@ get_removable_volumes (void) { FILE *file; GList *volumes; -#if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; -#else - struct mntent *ent; -#endif /* HAVE_SYS_MNTTAB_H */ + MountTableEntry *ent; NautilusVolume *volume; +#if HAVE_SYS_MNTTAB_H + MountTableEntry ent_storage; +#endif volumes = NULL; - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return NULL; } #if HAVE_SYS_MNTTAB_H + ent = &ent_storage; while (! getmntent (file, ent)) { /* On Solaris look for /vol/ for determining a removable volume */ - if (strstr (ent->mnt_special, MNTOPT_NOAUTO) == ent->mnt_special) { + if (nautilus_str_has_prefix (ent->mnt_special, noauto_string)) { volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); volume->is_removable = TRUE; - volume->is_read_only = (hasmntopt (ent, MNTOPT_RO) !=NULL); + volume->is_read_only = hasmntopt (ent, MNTOPT_RO) != NULL; + volumes = mount_volume_add_filesystem (volume, volumes); + } + } #else while ((ent = getmntent (file)) != NULL) { if (has_removable_mntent_options (ent)) { volume = create_volume (ent->mnt_fsname, ent->mnt_dir, ent->mnt_type); -#endif /* HAVE_SYS_MNTTAB_H */ volumes = mount_volume_add_filesystem (volume, volumes); - } + } } +#endif /* HAVE_SYS_MNTTAB_H */ fclose (file); @@ -419,26 +403,24 @@ static gboolean volume_is_removable (const NautilusVolume *volume) { FILE *file; + MountTableEntry *ent; #if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; -#else - struct mntent *ent; -#endif /* HAVE_SYS_MNTTAB_H */ + MountTableEntry ent_storage; +#endif - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } /* Search for our device in the fstab */ #if HAVE_SYS_MNTTAB_H + MountTableEntry *ent = &ent_storage; while (!getmntent (file, ent)) { if (strcmp (volume->device_path, ent->mnt_special) == 0) { /* On Solaris look for /vol/ for determining a removable volume */ - if (strstr (ent->mnt_special, MNTOPT_NOAUTO) - == ent->mnt_special) { + if (nautilus_str_has_prefix (ent->mnt_special, noauto_string)) { fclose (file); return TRUE; } @@ -452,7 +434,6 @@ volume_is_removable (const NautilusVolume *volume) return TRUE; } } - #endif /* HAVE_SYS_MNTTAB_H */ fclose (file); @@ -463,18 +444,19 @@ static gboolean volume_is_read_only (const NautilusVolume *volume) { FILE *file; + MountTableEntry *ent; #if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; - - file = setmntent (PATH_MOUNT_TABLE, "r"); + MountTableEntry ent_storage; + + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } /* Search for our device in the fstab */ - while (!getmntent (file, ent)) { + ent = &ent_storage; + while (!getmntent (file, ent)) { if (strcmp (volume->device_path, ent->mnt_special) == 0) { if (strstr (ent->mnt_mntopts, MNTOPT_RO) != NULL) { fclose (file); @@ -483,9 +465,7 @@ volume_is_read_only (const NautilusVolume *volume) } } #else - struct mntent *ent; - - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } @@ -629,14 +609,12 @@ mount_volume_get_cdrom_name (NautilusVolume *volume) { int fd, disctype; - #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); - - #else +#if SOLARIS_MNT + disctype = get_cdrom_type_solaris (volume->device_path, &fd); +#else fd = open (volume->device_path, O_RDONLY|O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); - - #endif +#endif switch (disctype) { case CDS_AUDIO: @@ -672,7 +650,7 @@ mount_volume_activate_cdda (NautilusVolumeMonitor *monitor, NautilusVolume *volu int fd, disctype; #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); + disctype = get_cdrom_type_solaris (volume->device_path, &fd); #else fd = open (volume->device_path, O_RDONLY | O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); @@ -693,7 +671,7 @@ mount_volume_activate_cdrom (NautilusVolumeMonitor *monitor, NautilusVolume *vol { int fd, disctype; #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); + disctype = get_cdrom_type_solaris (volume->device_path, &fd); #else fd = open (volume->device_path, O_RDONLY | O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); @@ -918,19 +896,18 @@ build_volume_list_delta (GList *list_one, GList *list_two) GList *ptrOne, *ptrTwo; GList *new_list; NautilusVolume *volOne, *volTwo, *new_volume; - int index; gboolean found_match; new_list = NULL; - for (ptrOne = list_one, index = 0; ptrOne != NULL; ptrOne = ptrOne->next, index++) { + for (ptrOne = list_one; ptrOne != NULL; ptrOne = ptrOne->next) { found_match = FALSE; - volOne = (NautilusVolume *)ptrOne->data; + volOne = (NautilusVolume *) ptrOne->data; for (ptrTwo = list_two; ptrTwo != NULL; ptrTwo = ptrTwo->next) { - volTwo = (NautilusVolume *)ptrTwo->data; + volTwo = (NautilusVolume *) ptrTwo->data; /* Check and see if mount point from list one is in list two */ if (strcmp (volOne->mount_path, volTwo->mount_path) == 0) { @@ -958,32 +935,36 @@ get_current_mount_list (void) FILE *fh; #ifdef SOLARIS_MNT - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; - - fh = setmntent (PATH_MOUNT_TABLE, "r"); - if (fh == NULL) { - return NULL; - } - while (! getmntent (fh, ent)) { - volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); - volume->is_removable = has_removable_mntent_options(ent); - volume->is_read_only = (hasmntopt (ent, MNTOPT_RO) != NULL); - current_mounts = mount_volume_add_filesystem (volume, current_mounts); - } + MountTableEntry ent_storage; + MountTableEntry *ent = &ent_storage; + + fh = setmntent (MOUNT_TABLE_PATH, "r"); + if (fh != NULL) { + while (! getmntent (fh, ent)) { + volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); + volume->is_removable = has_removable_mntent_options(ent); + volume->is_read_only = hasmntopt (ent, MNTOPT_RO) != NULL; + current_mounts = mount_volume_add_filesystem (volume, current_mounts); + } + } #else char line[PATH_MAX * 3]; char device_name[sizeof (line)]; NautilusStringList *list; char *device_path, *mount_path, *filesystem; + const char *separator; - /* Open /proc/mounts */ - fh = fopen (PATH_PROC_MOUNTS, "r"); + fh = fopen ("/etc/mnttab", "r"); + separator = "\t"; + if (fh == NULL) { + fh = fopen ("/proc/mounts", "r"); + separator = " "; + } g_return_val_if_fail (fh != NULL, NULL); while (fgets (line, sizeof(line), fh)) { if (sscanf (line, "%s", device_name) == 1) { - list = nautilus_string_list_new_from_tokens (line, PROC_MOUNTS_SEPARATOR, FALSE); + list = nautilus_string_list_new_from_tokens (line, separator, FALSE); if (list != NULL) { /* The string list needs to have at least 3 items per line. * We need to find at least device path, mount path and file system type. @@ -1002,9 +983,12 @@ get_current_mount_list (void) } } } - #endif /* SOLARIS_MNT */ + if (fh != NULL) { + fclose (fh); + } + #ifdef HAVE_CDDA /* CD Audio tricks */ if (locate_audio_cd ()) { @@ -1014,8 +998,6 @@ get_current_mount_list (void) } #endif - fclose (fh); - return current_mounts; } @@ -1035,7 +1017,6 @@ update_modifed_volume_name (GList *mount_list, NautilusVolume *volume) } } - static gboolean mount_lists_are_identical (GList *list_a, GList *list_b) { @@ -1043,7 +1024,6 @@ mount_lists_are_identical (GList *list_a, GList *list_b) NautilusVolume *volumeOne, *volumeTwo; for (p = list_a, q = list_b; p != NULL && q != NULL; p = p->next, q = q->next) { - volumeOne = p->data; volumeTwo = q->data; @@ -1058,17 +1038,7 @@ static void verify_current_mount_state (NautilusVolumeMonitor *monitor) { GList *new_mounts, *old_mounts, *current_mounts; - GList *saved_mount_list; - gboolean free_new_mounts; - - new_mounts = old_mounts = current_mounts = saved_mount_list = NULL; - - /* Free the new mount list only if it is not a copy of the current mount list. */ - if (monitor->details->mounts != NULL) { - free_new_mounts = TRUE; - } else { - free_new_mounts = FALSE; - } + GList *saved_mount_list, *p; /* Get all current mounts */ current_mounts = get_current_mount_list (); @@ -1082,17 +1052,9 @@ verify_current_mount_state (NautilusVolumeMonitor *monitor) return; } - /* If saved mounts is NULL, this is the first time we have been here. New mounts - * are the same as current mounts - */ - if (monitor->details->mounts == NULL) { - new_mounts = current_mounts; - old_mounts = NULL; - } else { - /* Create list of new and old mounts */ - new_mounts = build_volume_list_delta (current_mounts, monitor->details->mounts); - old_mounts = build_volume_list_delta (monitor->details->mounts, current_mounts); - } + /* Create list of new and old mounts */ + new_mounts = build_volume_list_delta (current_mounts, monitor->details->mounts); + old_mounts = build_volume_list_delta (monitor->details->mounts, current_mounts); /* Stash a copy of the current mount list for updating mount names later. */ saved_mount_list = monitor->details->mounts; @@ -1101,36 +1063,24 @@ verify_current_mount_state (NautilusVolumeMonitor *monitor) monitor->details->mounts = current_mounts; /* Check and see if we have new mounts to add */ - if (new_mounts != NULL) { - GList *p; - for (p = new_mounts; p != NULL; p = p->next) { - mount_volume_activate (monitor, (NautilusVolume *)p->data); - } - } + for (p = new_mounts; p != NULL; p = p->next) { + mount_volume_activate (monitor, (NautilusVolume *)p->data); + } /* Check and see if we have old mounts to remove */ - if (old_mounts != NULL) { - GList *p; - - for (p = old_mounts; p != NULL; p = p->next) { - /* First we need to update the volume names in this list with modified names in the old list. Names in - * the old list may have been modifed due to icon name conflicts. The list of old mounts is unable - * take this into account when it is created - */ - update_modifed_volume_name (saved_mount_list, (NautilusVolume *)p->data); - - /* Deactivate the volume. */ - mount_volume_deactivate (monitor, (NautilusVolume *)p->data); - } - free_mount_list (old_mounts); + for (p = old_mounts; p != NULL; p = p->next) { + /* First we need to update the volume names in this list with modified names in the old list. Names in + * the old list may have been modifed due to icon name conflicts. The list of old mounts is unable + * take this into account when it is created + */ + update_modifed_volume_name (saved_mount_list, (NautilusVolume *) p->data); + + /* Deactivate the volume. */ + mount_volume_deactivate (monitor, (NautilusVolume *) p->data); } - /* Free the new mount list only if it is not a copy of the current mount list. - * It will be a copy if there are no previous mounts. - */ - if (free_new_mounts) { - free_mount_list (new_mounts); - } + free_mount_list (old_mounts); + free_mount_list (new_mounts); free_mount_list (saved_mount_list); } @@ -1148,6 +1098,7 @@ static gboolean mount_volume_floppy_add (NautilusVolume *volume) { volume->type = NAUTILUS_VOLUME_FLOPPY; + return TRUE; } @@ -1184,43 +1135,49 @@ mount_volume_msdos_add (NautilusVolume *volume) } #ifdef SOLARIS_MNT -static int get_cdrom_type_solaris(char *vol_dev_path, int* fd) { +static int +get_cdrom_type_solaris (const char *vol_dev_path, int* fd) +{ GString *new_dev_path; struct cdrom_tocentry entry; - struct cdrom_tochdr header; - gboolean audio; - -/* For ioctl call to work dev_path has to be /vol/dev/rdsk.... - there has to be a nicer way to do this. */ + struct cdrom_tochdr header; + int type; - new_dev_path = g_string_new(vol_dev_path); - new_dev_path = g_string_insert_c(new_dev_path, 9, 'r'); - - - *fd = open((char *)new_dev_path, O_RDONLY | O_NONBLOCK); - - ioctl (*fd, CDROMREADTOCHDR, &header); - entry.cdte_track = 1; - entry.cdte_format = CDROM_LBA; - audio = TRUE; - while(entry.cdte_track<=header.cdth_trk1 && audio) { + /* For ioctl call to work dev_path has to be /vol/dev/rdsk. + * There has to be a nicer way to do this. + */ + new_dev_path = g_string_new (vol_dev_path); + new_dev_path = g_string_insert_c (new_dev_path, 9, 'r'); + *fd = open (new_dev_path.str, O_RDONLY | O_NONBLOCK); + g_string_free (new_dev_path, TRUE); - ioctl (*fd, CDROMREADTOCENTRY, &entry); - if(entry.cdte_ctrl & CDROM_DATA_TRACK) - audio = FALSE; - entry.cdte_track++; + if (*fd < 0) { + return CDS_DATA_1; } - g_string_free(new_dev_path, TRUE); + if (ioctl (*fd, CDROMREADTOCHDR, &header) == 0) { + return CDS_DATA_1; + } - if(audio) - return(CDS_AUDIO); + type = CDS_DATA_1; + + for (entry.cdte_track = 1; + entry.cdte_track <= header.cdth_trk1; + entry.cdte_track++) { + entry.cdte_format = CDROM_LBA; + if (ioctl (*fd, CDROMREADTOCENTRY, &entry) == 0) { + if (entry.cdte_ctrl & CDROM_DATA_TRACK) { + type = CDS_AUDIO; + break; + } + } + } - return(CDS_DATA_1); + return type; } -#endif +#endif static void cdrom_ioctl_get_info (int fd) @@ -1233,7 +1190,6 @@ cdrom_ioctl_get_info (int fd) static gboolean mount_volume_iso9660_add (NautilusVolume *volume) { - #ifndef SOLARIS_MNT int fd; @@ -1249,7 +1205,7 @@ mount_volume_iso9660_add (NautilusVolume *volume) cdrom_ioctl_get_info (fd); close (fd); -#endif /* #ifndef SOLARIS_MNT */ +#endif volume->type = NAUTILUS_VOLUME_CDROM; @@ -1376,22 +1332,6 @@ find_volumes (NautilusVolumeMonitor *monitor) monitor); } -#if 0 -void -nautilus_volume_monitor_each_volume (NautilusVolumeMonitor *monitor, - NautilusEachVolumeFunction function, - gpointer context) -{ - GList *p; - - for (p = monitor->details->mounts; p != NULL; p = p->next) { - if ((* function) ((NautilusVolume *) p->data, context)) { - break; - } - } -} -#endif - void nautilus_volume_monitor_each_mounted_volume (NautilusVolumeMonitor *monitor, NautilusEachVolumeFunction function, @@ -1434,9 +1374,9 @@ static const char *volrmmount_locations [] = { }; #define MOUNT_COMMAND volrmmount_locations -#define MOUNT_SEPERATOR " -i " +#define MOUNT_SEPARATOR " -i " #define UMOUNT_COMMAND volrmmount_locations -#define UMOUNT_SEPERATOR " -e " +#define UMOUNT_SEPARATOR " -e " #else @@ -1453,9 +1393,9 @@ static const char *umount_known_locations [] = { }; #define MOUNT_COMMAND mount_known_locations -#define MOUNT_SEPERATOR " " +#define MOUNT_SEPARATOR " " #define UMOUNT_COMMAND umount_known_locations -#define UMOUNT_SEPERATOR " " +#define UMOUNT_SEPARATOR " " #endif /* USE_VOLRMMOUNT */ @@ -1503,7 +1443,7 @@ typedef struct { typedef struct { char *message; char *detailed_message; - char *title; + const char *title; } MountStatusInfo; @@ -1517,7 +1457,6 @@ display_mount_status (gpointer callback_data) g_free (info->message); g_free (info->detailed_message); - g_free (info->title); g_free (info); return FALSE; @@ -1527,34 +1466,33 @@ static void close_error_pipe (gboolean mount, const char *mount_path) { char *message; - const char *title; char detailed_msg[MAX_PIPE_SIZE]; - int length = 0; + int length; gboolean is_floppy; MountStatusInfo *info; - - if (mount) { - title = _("Mount Error"); - } else { - title = _("Unmount Error"); + + if (old_error < 0) { + return; } - - if (old_error >= 0) { - close (2); - dup (old_error); - close (old_error); - - do { - length = read (error_pipe[0], detailed_msg, MAX_PIPE_SIZE); - } while (length < 0); - - if (length >= 0) { - detailed_msg[length] = 0; - } - - close (error_pipe[0]); + + close (2); + dup (old_error); + close (old_error); + + /* FIXME: This keeps reading into the same buffer over and + * over again and makes no attempt to save bytes from any + * calls other than the last read call. + */ + do { + length = read (error_pipe[0], detailed_msg, MAX_PIPE_SIZE); + } while (length < 0); + + if (length >= 0) { + detailed_msg[length] = 0; } + close (error_pipe[0]); + /* No output to show */ if (length == 0) { return; @@ -1605,13 +1543,11 @@ close_error_pipe (gboolean mount, const char *mount_path) /* Set up info and pass it to callback to display dialog. We do this because this routine may be called from a thread */ info = g_new0 (MountStatusInfo, 1); - info->message = g_strdup (message); + info->message = message; info->detailed_message = g_strdup (detailed_msg); - info->title = g_strdup (title); + info->title = mount ? _("Mount Error") : _("Unmount Error"); gtk_idle_add (display_mount_status, info); - - g_free (message); } @@ -1667,19 +1603,19 @@ nautilus_volume_monitor_mount_unmount_removable (NautilusVolumeMonitor *monitor, if (name != NULL) { name = name + 1; } else { - name = mount_point; + name = mount_point; } #else name = mount_point; #endif /* USE_VOLRMMOUNT */ - + if (should_mount) { command = find_command (MOUNT_COMMAND); - command_string = g_strconcat (command, MOUNT_SEPERATOR, name, NULL); + command_string = g_strconcat (command, MOUNT_SEPARATOR, name, NULL); } else { command = find_command (UMOUNT_COMMAND); - command_string = g_strconcat (command, UMOUNT_SEPERATOR, name, NULL); + command_string = g_strconcat (command, UMOUNT_SEPARATOR, name, NULL); } mount_info = g_new0 (MountThreadInfo, 1); @@ -1883,7 +1819,7 @@ mount_volume_add_filesystem (NautilusVolume *volume, GList *volume_list) { gboolean mounted = FALSE; - if (nautilus_str_has_prefix (volume->device_path, FLOPPY_DEVICE_PATH_PREFIX)) { + if (nautilus_str_has_prefix (volume->device_path, floppy_device_path_prefix)) { mounted = mount_volume_floppy_add (volume); } else if (strcmp (volume->filesystem, "affs") == 0) { mounted = mount_volume_affs_add (volume); @@ -1931,7 +1867,7 @@ mount_volume_add_filesystem (NautilusVolume *volume, GList *volume_list) #ifndef SOLARIS_MNT volume->is_removable = volume_is_removable (volume); volume->is_read_only = volume_is_read_only (volume); -#endif /* SOLARIS_MNT */ +#endif mount_volume_get_name (volume); volume_list = g_list_append (volume_list, volume); } else { diff --git a/libnautilus-private/nautilus-global-preferences.c b/libnautilus-private/nautilus-global-preferences.c index 14ad7312b..918fadd4f 100644 --- a/libnautilus-private/nautilus-global-preferences.c +++ b/libnautilus-private/nautilus-global-preferences.c @@ -2,7 +2,7 @@ /* nautilus-prefs-dialog.c - Implementation for preferences dialog. - Copyright (C) 1999, 2000 Eazel, Inc. + Copyright (C) 1999, 2000, 2001 Eazel, Inc. The Gnome Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -100,7 +100,10 @@ global_preferences_install_descriptions (void) _("Open each file or folder in a separate window")); nautilus_preferences_set_description (NAUTILUS_PREFERENCES_CONFIRM_TRASH, - _("Ask before emptying the Trash")); + _("Ask before emptying the Trash or deleting files")); + + nautilus_preferences_set_description (NAUTILUS_PREFERENCES_ENABLE_DELETE, + _("Include a Delete command that bypasses Trash")); nautilus_preferences_set_description (NAUTILUS_PREFERENCES_CLICK_POLICY, _("Click Behavior")); @@ -260,6 +263,10 @@ global_preferences_install_defaults (void) NAUTILUS_USER_LEVEL_NOVICE, TRUE); + nautilus_preferences_default_set_boolean (NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_USER_LEVEL_NOVICE, + FALSE); + nautilus_preferences_default_set_integer (NAUTILUS_PREFERENCES_SHOW_TEXT_IN_ICONS, NAUTILUS_USER_LEVEL_NOVICE, NAUTILUS_SPEED_TRADEOFF_LOCAL_ONLY); @@ -426,6 +433,9 @@ global_preferences_install_visibility (void) nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_CONFIRM_TRASH, NAUTILUS_USER_LEVEL_ADVANCED); + nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_USER_LEVEL_ADVANCED); + nautilus_preferences_set_visible_user_level (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES, NAUTILUS_USER_LEVEL_INTERMEDIATE); @@ -612,6 +622,11 @@ global_preferences_create_dialog (void) NAUTILUS_PREFERENCES_CONFIRM_TRASH, NAUTILUS_PREFERENCE_ITEM_BOOLEAN); + nautilus_preferences_pane_add_item_to_nth_group (NAUTILUS_PREFERENCES_PANE (windows_and_desktop_pane), + 2, + NAUTILUS_PREFERENCES_ENABLE_DELETE, + NAUTILUS_PREFERENCE_ITEM_BOOLEAN); + /* FIXME: This group clearly doesn't belong in Windows & * Desktop, but there's no obviously-better place for it and * it probably doesn't deserve a pane of its own. diff --git a/libnautilus-private/nautilus-global-preferences.h b/libnautilus-private/nautilus-global-preferences.h index ab2452e74..26678f255 100644 --- a/libnautilus-private/nautilus-global-preferences.h +++ b/libnautilus-private/nautilus-global-preferences.h @@ -2,7 +2,7 @@ /* nautilus-global-prefs.h - Nautilus main preferences api. - Copyright (C) 1999, 2000 Eazel, Inc. + Copyright (C) 1999, 2000, 2001 Eazel, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -49,6 +49,7 @@ BEGIN_GNOME_DECLS /* Trash options */ #define NAUTILUS_PREFERENCES_CONFIRM_TRASH "preferences/confirm_trash" +#define NAUTILUS_PREFERENCES_ENABLE_DELETE "preferences/enable_delete" /* Desktop options */ #define NAUTILUS_PREFERENCES_SHOW_DESKTOP "preferences/show_desktop" diff --git a/libnautilus-private/nautilus-icon-container.c b/libnautilus-private/nautilus-icon-container.c index 56c8154dd..32e948611 100644 --- a/libnautilus-private/nautilus-icon-container.c +++ b/libnautilus-private/nautilus-icon-container.c @@ -4862,21 +4862,22 @@ nautilus_icon_container_start_renaming_selected_item (NautilusIconContainer *con gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (details->rename_widget), &icon_rect.x0, &icon_rect.y0); gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (details->rename_widget), &icon_rect.x1, &icon_rect.y1); - nautilus_icon_text_item_configure ( - details->rename_widget, - (icon_rect.x0 + icon_rect.x1) / 2, /* x_center */ - icon_rect.y1, /* y_top */ - nautilus_icon_canvas_item_get_max_text_width (icon->item), /* max_text_width */ - details->label_font[details->zoom_level], /* font */ - editable_text, /* text */ - FALSE); /* allocate local copy */ + nautilus_icon_text_item_configure + (details->rename_widget, + (icon_rect.x0 + icon_rect.x1) / 2, /* x_center */ + icon_rect.y1, /* y_top */ + nautilus_icon_canvas_item_get_max_text_width (icon->item), /* max_text_width */ + details->label_font[details->zoom_level], /* font */ + editable_text, /* text */ + FALSE); /* allocate local copy */ nautilus_icon_text_item_start_editing (details->rename_widget); - nautilus_icon_container_update_icon (container, icon); gtk_signal_emit (GTK_OBJECT (container), signals[RENAMING_ICON], nautilus_icon_text_item_get_renaming_editable (details->rename_widget)); + + nautilus_icon_container_update_icon (container, icon); /* We are in renaming mode */ details->renaming = TRUE; diff --git a/libnautilus-private/nautilus-icon-text-item.c b/libnautilus-private/nautilus-icon-text-item.c index 03d28357a..d1cf5388e 100644 --- a/libnautilus-private/nautilus-icon-text-item.c +++ b/libnautilus-private/nautilus-icon-text-item.c @@ -90,6 +90,36 @@ enum { }; static guint iti_signals [LAST_SIGNAL] = { 0 }; +static void +send_focus_event (Iti *iti, gboolean in) +{ + ItiPrivate *priv; + GtkWidget *widget; + gboolean has_focus; + GdkEvent fake_event; + + g_assert (in == FALSE || in == TRUE); + + priv = iti->priv; + if (priv->entry == NULL) { + g_assert (!in); + return; + } + + widget = GTK_WIDGET (priv->entry); + has_focus = GTK_WIDGET_HAS_FOCUS (widget); + if (has_focus == in) { + return; + } + + memset (&fake_event, 0, sizeof (fake_event)); + fake_event.focus_change.type = GDK_FOCUS_CHANGE; + fake_event.focus_change.window = widget->window; + fake_event.focus_change.in = in; + gtk_widget_event (widget, &fake_event); + g_assert (GTK_WIDGET_HAS_FOCUS (widget) == in); +} + /* Stops the editing state of an icon text item */ static void iti_stop_editing (Iti *iti) @@ -100,6 +130,8 @@ iti_stop_editing (Iti *iti) iti->editing = FALSE; + send_focus_event (iti, FALSE); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STOPPED]); @@ -232,7 +264,7 @@ iti_start_editing (Iti *iti) gtk_signal_connect (GTK_OBJECT (priv->entry), "activate", GTK_SIGNAL_FUNC (iti_entry_activate), iti); /* Make clipboard functions cause an update the appearance of - the icon text item iteself, since the clipboard functions + the icon text item itself, since the clipboard functions will change the offscreen entry */ gtk_signal_connect_after (GTK_OBJECT (priv->entry), "changed", GTK_SIGNAL_FUNC (iti_entry_text_changed_by_clipboard), iti); @@ -249,6 +281,8 @@ iti_start_editing (Iti *iti) iti->editing = TRUE; + send_focus_event (iti, TRUE); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (iti)); gtk_signal_emit (GTK_OBJECT (iti), iti_signals[EDITING_STARTED]); @@ -1067,13 +1101,13 @@ iti_event (GnomeCanvasItem *item, GdkEvent *event) } else { GTK_WIDGET_UNSET_FLAGS (item->canvas, GTK_HAS_FOCUS); } - - if (iti->editing && !event->focus_change.in) { - iti_edition_accept (iti); - } if (iti->editing) { gtk_widget_event (GTK_WIDGET (priv->entry), event); + + if (!event->focus_change.in) { + iti_edition_accept (iti); + } } return TRUE; diff --git a/libnautilus-private/nautilus-medusa-support.c b/libnautilus-private/nautilus-medusa-support.c index 2ae619fc4..94a079e66 100644 --- a/libnautilus-private/nautilus-medusa-support.c +++ b/libnautilus-private/nautilus-medusa-support.c @@ -25,16 +25,13 @@ */ #include <config.h> -#include <glib.h> - -#include <string.h> -#include <sys/types.h> -#include <stdio.h> -#include <dirent.h> +#include "nautilus-medusa-support.h" #include "nautilus-glib-extensions.h" -#include "nautilus-medusa-support.h" #include "nautilus-string.h" +#include <dirent.h> +#include <stdio.h> +#include <sys/types.h> #ifdef HAVE_MEDUSA #include <libmedusa/medusa-system-state.h> @@ -85,7 +82,6 @@ nautilus_medusa_add_system_state_changed_callback (NautilusMedusaChangedCallback NautilusCronStatus nautilus_medusa_check_cron_is_enabled (void) { -#ifdef HAVE_PROC_PROCESS_FILES DIR *proc_directory; struct dirent *file; char *stat_file_name; @@ -93,6 +89,7 @@ nautilus_medusa_check_cron_is_enabled (void) char stat_file_data[128]; const char *stat_file_process_name; int process_number, bytes_read; + NautilusCronStatus status; /* We figure out whether cron is running by reading the proc directory, and checking for a process named or ending with @@ -103,37 +100,39 @@ nautilus_medusa_check_cron_is_enabled (void) return NAUTILUS_CRON_STATUS_UNKNOWN; } - file = readdir (proc_directory); - while (file != NULL) { + status = NAUTILUS_CRON_STATUS_UNKNOWN; + + while ((file = readdir (proc_directory)) != NULL) { /* Process files have numbers */ - if (nautilus_str_to_int (file->d_name, - &process_number)) { - stat_file_name = g_strdup_printf ("/proc/%d/stat", process_number); - stat_file = fopen (stat_file_name, "r"); - g_free (stat_file_name); - - if (stat_file == NULL) { - file = readdir (proc_directory); - continue; - } - - bytes_read = fread (stat_file_data, sizeof (char), NAUTILUS_N_ELEMENTS (stat_file_data) - 1, stat_file); - fclose (stat_file); - stat_file_data[bytes_read] = 0; - - stat_file_process_name = strchr (stat_file_data, ' ') + 1; - - if (nautilus_str_has_prefix (stat_file_process_name, "(crond)")) { - return NAUTILUS_CRON_STATUS_ON; - } + if (!nautilus_str_to_int (file->d_name, &process_number)) { + continue; + } + /* Since we've seen at least one process file, we can change our state + * from "unknown" to "presumed off until proved otherwise". + */ + status = NAUTILUS_CRON_STATUS_OFF; + + stat_file_name = g_strdup_printf ("/proc/%d/stat", process_number); + stat_file = fopen (stat_file_name, "r"); + g_free (stat_file_name); + + if (stat_file == NULL) { + continue; + } + + bytes_read = fread (stat_file_data, 1, sizeof (stat_file_data) - 1, stat_file); + fclose (stat_file); + stat_file_data[bytes_read] = '\0'; + + stat_file_process_name = strchr (stat_file_data, ' '); + + if (nautilus_str_has_prefix (stat_file_process_name, " (crond)")) { + status = NAUTILUS_CRON_STATUS_ON; + break; } - file = readdir (proc_directory); } closedir (proc_directory); - return NAUTILUS_CRON_STATUS_OFF; -#else - return NAUTILUS_CRON_STATUS_UNKNOWN; -#endif + return status; } diff --git a/libnautilus-private/nautilus-volume-monitor.c b/libnautilus-private/nautilus-volume-monitor.c index e32254a22..8055b44cd 100644 --- a/libnautilus-private/nautilus-volume-monitor.c +++ b/libnautilus-private/nautilus-volume-monitor.c @@ -2,7 +2,7 @@ /* nautilus-volume-monitor.c - Desktop volume mounting routines. - Copyright (C) 2000 Eazel, Inc. + Copyright (C) 2000, 2001 Eazel, Inc. The Gnome Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -23,8 +23,6 @@ */ #include <config.h> -#include <sys/types.h> - #include "nautilus-volume-monitor.h" #include "nautilus-cdrom-extensions.h" @@ -64,11 +62,13 @@ #ifdef HAVE_MNTENT_H #include <mntent.h> +#define MOUNT_TABLE_PATH _PATH_MNTTAB #endif #ifdef HAVE_SYS_MNTTAB_H #define SOLARIS_MNT 1 #include <sys/mnttab.h> +#define MOUNT_TABLE_PATH "/etc/mnttab" #endif #ifdef SOLARIS_MNT @@ -77,7 +77,16 @@ #define USE_VOLRMMOUNT 0 #endif +#ifndef MNTOPT_RO +#define MNTOPT_RO "ro" +#endif + +#ifndef HAVE_SETMNTENT +#define setmntent(f,m) fopen(f,m) +#endif + #ifdef HAVE_CDDA + #define size16 short #define size32 int @@ -94,48 +103,17 @@ * due to our strict error checking. */ char **broken_header_fix = strerror_tr; -#endif - -#define CHECK_STATUS_INTERVAL 2000 -#ifdef HAVE_ETC_MNTTAB -#define PATH_PROC_MOUNTS "/etc/mnttab" -#define PROC_MOUNTS_SEPARATOR "\t" #endif -#ifdef HAVE_PROC_MOUNTS -#define PATH_PROC_MOUNTS "/proc/mounts" -#define PROC_MOUNTS_SEPARATOR " " -#endif +#define CHECK_STATUS_INTERVAL 2000 #define FLOPPY_MOUNT_PATH_PREFIX "/mnt/fd" -#ifdef HAVE_VOL_DEV -#define FLOPPY_DEVICE_PATH_PREFIX "/vol/dev/diskette" -#else -#define FLOPPY_DEVICE_PATH_PREFIX "/dev/fd" -#endif - #ifdef HAVE_SYS_MNTTAB_H -#define PATH_MOUNT_TABLE "/etc/mnttab" -#endif - -#ifdef HAVE_MNTENT_H -#define PATH_MOUNT_TABLE _PATH_MNTTAB -#endif - -#ifdef HAVE_VOL -# define MNTOPT_NOAUTO "/vol/" -# else -# define MNTOPT_NOAUTO "noauto" -#endif - -#ifndef MNTOPT_RO -# define MNTOPT_RO "ro" -#endif - -#ifndef HAVE_SETMNTENT -#define setmntent(f,m) fopen(f,m) +typedef struct mnttab MountTableEntry; +#else +typedef struct mntent MountTableEntry; #endif struct NautilusVolumeMonitorDetails @@ -147,6 +125,8 @@ struct NautilusVolumeMonitorDetails }; static NautilusVolumeMonitor *global_volume_monitor = NULL; +static const char *floppy_device_path_prefix; +static const char *noauto_string; /* The NautilusVolumeMonitor signals. */ @@ -182,7 +162,7 @@ static GList *mount_volume_add_filesystem (NautilusVolume *volume, static NautilusVolume *create_volume (const char *device_path, const char *mount_path, const char *filesystem); -static NautilusVolume *copy_volume (NautilusVolume *volume); +static NautilusVolume *copy_volume (NautilusVolume *volume); static void find_volumes (NautilusVolumeMonitor *monitor); static void free_mount_list (GList *mount_list); static GList *get_removable_volumes (void); @@ -194,7 +174,8 @@ static gboolean locate_audio_cd (void); #endif #ifdef SOLARIS_MNT -static int get_cdrom_type_solaris(char *vol_dev_path, int* fd) ; +static int get_cdrom_type_solaris (const char *vol_dev_path, + int *fd); #endif NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusVolumeMonitor, @@ -242,7 +223,19 @@ nautilus_volume_monitor_initialize_class (NautilusVolumeMonitorClass *klass) gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); - gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + + /* Check environment a bit. */ + if (g_file_exists ("/vol/dev")) { + floppy_device_path_prefix = "/vol/dev/diskette/"; + } else { + floppy_device_path_prefix = "/dev/fd/"; + } + if (g_file_exists ("/vol")) { + noauto_string = "/vol/"; + } else { + noauto_string = "/dev/fd/"; + } } static void @@ -330,31 +323,20 @@ nautilus_volume_monitor_get_removable_volumes (NautilusVolumeMonitor *monitor) } -#ifdef HAVE_SYS_MNTTAB_H - -static gboolean -has_removable_mntent_options (struct mnttab *ent) -{ - -#else - static gboolean -has_removable_mntent_options (struct mntent *ent) +has_removable_mntent_options (MountTableEntry *ent) { - -#endif /* HAVE_SYS_MNTTAB_H */ - /* Use "owner" or "user" or "users" as our way of determining a removable volume */ if (hasmntopt (ent, "user") != NULL || hasmntopt (ent, "users") != NULL || hasmntopt (ent, "owner") != NULL) { - return TRUE; + return TRUE; } -#if SOLARIS_MNT && HAVE_VOL - if (strstr (ent->mnt_special, "/vol/") == ent->mnt_special) { - return TRUE; - } +#ifdef SOLARIS_MNT + if (nautilus_str_has_prefix (ent->mnt_special, "/vol/")) { + return TRUE; + } #endif return FALSE; @@ -372,36 +354,38 @@ get_removable_volumes (void) { FILE *file; GList *volumes; -#if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; -#else - struct mntent *ent; -#endif /* HAVE_SYS_MNTTAB_H */ + MountTableEntry *ent; NautilusVolume *volume; +#if HAVE_SYS_MNTTAB_H + MountTableEntry ent_storage; +#endif volumes = NULL; - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return NULL; } #if HAVE_SYS_MNTTAB_H + ent = &ent_storage; while (! getmntent (file, ent)) { /* On Solaris look for /vol/ for determining a removable volume */ - if (strstr (ent->mnt_special, MNTOPT_NOAUTO) == ent->mnt_special) { + if (nautilus_str_has_prefix (ent->mnt_special, noauto_string)) { volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); volume->is_removable = TRUE; - volume->is_read_only = (hasmntopt (ent, MNTOPT_RO) !=NULL); + volume->is_read_only = hasmntopt (ent, MNTOPT_RO) != NULL; + volumes = mount_volume_add_filesystem (volume, volumes); + } + } #else while ((ent = getmntent (file)) != NULL) { if (has_removable_mntent_options (ent)) { volume = create_volume (ent->mnt_fsname, ent->mnt_dir, ent->mnt_type); -#endif /* HAVE_SYS_MNTTAB_H */ volumes = mount_volume_add_filesystem (volume, volumes); - } + } } +#endif /* HAVE_SYS_MNTTAB_H */ fclose (file); @@ -419,26 +403,24 @@ static gboolean volume_is_removable (const NautilusVolume *volume) { FILE *file; + MountTableEntry *ent; #if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; -#else - struct mntent *ent; -#endif /* HAVE_SYS_MNTTAB_H */ + MountTableEntry ent_storage; +#endif - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } /* Search for our device in the fstab */ #if HAVE_SYS_MNTTAB_H + MountTableEntry *ent = &ent_storage; while (!getmntent (file, ent)) { if (strcmp (volume->device_path, ent->mnt_special) == 0) { /* On Solaris look for /vol/ for determining a removable volume */ - if (strstr (ent->mnt_special, MNTOPT_NOAUTO) - == ent->mnt_special) { + if (nautilus_str_has_prefix (ent->mnt_special, noauto_string)) { fclose (file); return TRUE; } @@ -452,7 +434,6 @@ volume_is_removable (const NautilusVolume *volume) return TRUE; } } - #endif /* HAVE_SYS_MNTTAB_H */ fclose (file); @@ -463,18 +444,19 @@ static gboolean volume_is_read_only (const NautilusVolume *volume) { FILE *file; + MountTableEntry *ent; #if HAVE_SYS_MNTTAB_H - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; - - file = setmntent (PATH_MOUNT_TABLE, "r"); + MountTableEntry ent_storage; + + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } /* Search for our device in the fstab */ - while (!getmntent (file, ent)) { + ent = &ent_storage; + while (!getmntent (file, ent)) { if (strcmp (volume->device_path, ent->mnt_special) == 0) { if (strstr (ent->mnt_mntopts, MNTOPT_RO) != NULL) { fclose (file); @@ -483,9 +465,7 @@ volume_is_read_only (const NautilusVolume *volume) } } #else - struct mntent *ent; - - file = setmntent (PATH_MOUNT_TABLE, "r"); + file = setmntent (MOUNT_TABLE_PATH, "r"); if (file == NULL) { return FALSE; } @@ -629,14 +609,12 @@ mount_volume_get_cdrom_name (NautilusVolume *volume) { int fd, disctype; - #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); - - #else +#if SOLARIS_MNT + disctype = get_cdrom_type_solaris (volume->device_path, &fd); +#else fd = open (volume->device_path, O_RDONLY|O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); - - #endif +#endif switch (disctype) { case CDS_AUDIO: @@ -672,7 +650,7 @@ mount_volume_activate_cdda (NautilusVolumeMonitor *monitor, NautilusVolume *volu int fd, disctype; #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); + disctype = get_cdrom_type_solaris (volume->device_path, &fd); #else fd = open (volume->device_path, O_RDONLY | O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); @@ -693,7 +671,7 @@ mount_volume_activate_cdrom (NautilusVolumeMonitor *monitor, NautilusVolume *vol { int fd, disctype; #ifdef SOLARIS_MNT - disctype = get_cdrom_type_solaris(volume->device_path, &fd); + disctype = get_cdrom_type_solaris (volume->device_path, &fd); #else fd = open (volume->device_path, O_RDONLY | O_NONBLOCK); disctype = ioctl (fd, CDROM_DISC_STATUS, CDSL_CURRENT); @@ -918,19 +896,18 @@ build_volume_list_delta (GList *list_one, GList *list_two) GList *ptrOne, *ptrTwo; GList *new_list; NautilusVolume *volOne, *volTwo, *new_volume; - int index; gboolean found_match; new_list = NULL; - for (ptrOne = list_one, index = 0; ptrOne != NULL; ptrOne = ptrOne->next, index++) { + for (ptrOne = list_one; ptrOne != NULL; ptrOne = ptrOne->next) { found_match = FALSE; - volOne = (NautilusVolume *)ptrOne->data; + volOne = (NautilusVolume *) ptrOne->data; for (ptrTwo = list_two; ptrTwo != NULL; ptrTwo = ptrTwo->next) { - volTwo = (NautilusVolume *)ptrTwo->data; + volTwo = (NautilusVolume *) ptrTwo->data; /* Check and see if mount point from list one is in list two */ if (strcmp (volOne->mount_path, volTwo->mount_path) == 0) { @@ -958,32 +935,36 @@ get_current_mount_list (void) FILE *fh; #ifdef SOLARIS_MNT - struct mnttab dummy_ent; - struct mnttab *ent = &dummy_ent; - - fh = setmntent (PATH_MOUNT_TABLE, "r"); - if (fh == NULL) { - return NULL; - } - while (! getmntent (fh, ent)) { - volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); - volume->is_removable = has_removable_mntent_options(ent); - volume->is_read_only = (hasmntopt (ent, MNTOPT_RO) != NULL); - current_mounts = mount_volume_add_filesystem (volume, current_mounts); - } + MountTableEntry ent_storage; + MountTableEntry *ent = &ent_storage; + + fh = setmntent (MOUNT_TABLE_PATH, "r"); + if (fh != NULL) { + while (! getmntent (fh, ent)) { + volume = create_volume (ent->mnt_special, ent->mnt_mountp, ent->mnt_fstype); + volume->is_removable = has_removable_mntent_options(ent); + volume->is_read_only = hasmntopt (ent, MNTOPT_RO) != NULL; + current_mounts = mount_volume_add_filesystem (volume, current_mounts); + } + } #else char line[PATH_MAX * 3]; char device_name[sizeof (line)]; NautilusStringList *list; char *device_path, *mount_path, *filesystem; + const char *separator; - /* Open /proc/mounts */ - fh = fopen (PATH_PROC_MOUNTS, "r"); + fh = fopen ("/etc/mnttab", "r"); + separator = "\t"; + if (fh == NULL) { + fh = fopen ("/proc/mounts", "r"); + separator = " "; + } g_return_val_if_fail (fh != NULL, NULL); while (fgets (line, sizeof(line), fh)) { if (sscanf (line, "%s", device_name) == 1) { - list = nautilus_string_list_new_from_tokens (line, PROC_MOUNTS_SEPARATOR, FALSE); + list = nautilus_string_list_new_from_tokens (line, separator, FALSE); if (list != NULL) { /* The string list needs to have at least 3 items per line. * We need to find at least device path, mount path and file system type. @@ -1002,9 +983,12 @@ get_current_mount_list (void) } } } - #endif /* SOLARIS_MNT */ + if (fh != NULL) { + fclose (fh); + } + #ifdef HAVE_CDDA /* CD Audio tricks */ if (locate_audio_cd ()) { @@ -1014,8 +998,6 @@ get_current_mount_list (void) } #endif - fclose (fh); - return current_mounts; } @@ -1035,7 +1017,6 @@ update_modifed_volume_name (GList *mount_list, NautilusVolume *volume) } } - static gboolean mount_lists_are_identical (GList *list_a, GList *list_b) { @@ -1043,7 +1024,6 @@ mount_lists_are_identical (GList *list_a, GList *list_b) NautilusVolume *volumeOne, *volumeTwo; for (p = list_a, q = list_b; p != NULL && q != NULL; p = p->next, q = q->next) { - volumeOne = p->data; volumeTwo = q->data; @@ -1058,17 +1038,7 @@ static void verify_current_mount_state (NautilusVolumeMonitor *monitor) { GList *new_mounts, *old_mounts, *current_mounts; - GList *saved_mount_list; - gboolean free_new_mounts; - - new_mounts = old_mounts = current_mounts = saved_mount_list = NULL; - - /* Free the new mount list only if it is not a copy of the current mount list. */ - if (monitor->details->mounts != NULL) { - free_new_mounts = TRUE; - } else { - free_new_mounts = FALSE; - } + GList *saved_mount_list, *p; /* Get all current mounts */ current_mounts = get_current_mount_list (); @@ -1082,17 +1052,9 @@ verify_current_mount_state (NautilusVolumeMonitor *monitor) return; } - /* If saved mounts is NULL, this is the first time we have been here. New mounts - * are the same as current mounts - */ - if (monitor->details->mounts == NULL) { - new_mounts = current_mounts; - old_mounts = NULL; - } else { - /* Create list of new and old mounts */ - new_mounts = build_volume_list_delta (current_mounts, monitor->details->mounts); - old_mounts = build_volume_list_delta (monitor->details->mounts, current_mounts); - } + /* Create list of new and old mounts */ + new_mounts = build_volume_list_delta (current_mounts, monitor->details->mounts); + old_mounts = build_volume_list_delta (monitor->details->mounts, current_mounts); /* Stash a copy of the current mount list for updating mount names later. */ saved_mount_list = monitor->details->mounts; @@ -1101,36 +1063,24 @@ verify_current_mount_state (NautilusVolumeMonitor *monitor) monitor->details->mounts = current_mounts; /* Check and see if we have new mounts to add */ - if (new_mounts != NULL) { - GList *p; - for (p = new_mounts; p != NULL; p = p->next) { - mount_volume_activate (monitor, (NautilusVolume *)p->data); - } - } + for (p = new_mounts; p != NULL; p = p->next) { + mount_volume_activate (monitor, (NautilusVolume *)p->data); + } /* Check and see if we have old mounts to remove */ - if (old_mounts != NULL) { - GList *p; - - for (p = old_mounts; p != NULL; p = p->next) { - /* First we need to update the volume names in this list with modified names in the old list. Names in - * the old list may have been modifed due to icon name conflicts. The list of old mounts is unable - * take this into account when it is created - */ - update_modifed_volume_name (saved_mount_list, (NautilusVolume *)p->data); - - /* Deactivate the volume. */ - mount_volume_deactivate (monitor, (NautilusVolume *)p->data); - } - free_mount_list (old_mounts); + for (p = old_mounts; p != NULL; p = p->next) { + /* First we need to update the volume names in this list with modified names in the old list. Names in + * the old list may have been modifed due to icon name conflicts. The list of old mounts is unable + * take this into account when it is created + */ + update_modifed_volume_name (saved_mount_list, (NautilusVolume *) p->data); + + /* Deactivate the volume. */ + mount_volume_deactivate (monitor, (NautilusVolume *) p->data); } - /* Free the new mount list only if it is not a copy of the current mount list. - * It will be a copy if there are no previous mounts. - */ - if (free_new_mounts) { - free_mount_list (new_mounts); - } + free_mount_list (old_mounts); + free_mount_list (new_mounts); free_mount_list (saved_mount_list); } @@ -1148,6 +1098,7 @@ static gboolean mount_volume_floppy_add (NautilusVolume *volume) { volume->type = NAUTILUS_VOLUME_FLOPPY; + return TRUE; } @@ -1184,43 +1135,49 @@ mount_volume_msdos_add (NautilusVolume *volume) } #ifdef SOLARIS_MNT -static int get_cdrom_type_solaris(char *vol_dev_path, int* fd) { +static int +get_cdrom_type_solaris (const char *vol_dev_path, int* fd) +{ GString *new_dev_path; struct cdrom_tocentry entry; - struct cdrom_tochdr header; - gboolean audio; - -/* For ioctl call to work dev_path has to be /vol/dev/rdsk.... - there has to be a nicer way to do this. */ + struct cdrom_tochdr header; + int type; - new_dev_path = g_string_new(vol_dev_path); - new_dev_path = g_string_insert_c(new_dev_path, 9, 'r'); - - - *fd = open((char *)new_dev_path, O_RDONLY | O_NONBLOCK); - - ioctl (*fd, CDROMREADTOCHDR, &header); - entry.cdte_track = 1; - entry.cdte_format = CDROM_LBA; - audio = TRUE; - while(entry.cdte_track<=header.cdth_trk1 && audio) { + /* For ioctl call to work dev_path has to be /vol/dev/rdsk. + * There has to be a nicer way to do this. + */ + new_dev_path = g_string_new (vol_dev_path); + new_dev_path = g_string_insert_c (new_dev_path, 9, 'r'); + *fd = open (new_dev_path.str, O_RDONLY | O_NONBLOCK); + g_string_free (new_dev_path, TRUE); - ioctl (*fd, CDROMREADTOCENTRY, &entry); - if(entry.cdte_ctrl & CDROM_DATA_TRACK) - audio = FALSE; - entry.cdte_track++; + if (*fd < 0) { + return CDS_DATA_1; } - g_string_free(new_dev_path, TRUE); + if (ioctl (*fd, CDROMREADTOCHDR, &header) == 0) { + return CDS_DATA_1; + } - if(audio) - return(CDS_AUDIO); + type = CDS_DATA_1; + + for (entry.cdte_track = 1; + entry.cdte_track <= header.cdth_trk1; + entry.cdte_track++) { + entry.cdte_format = CDROM_LBA; + if (ioctl (*fd, CDROMREADTOCENTRY, &entry) == 0) { + if (entry.cdte_ctrl & CDROM_DATA_TRACK) { + type = CDS_AUDIO; + break; + } + } + } - return(CDS_DATA_1); + return type; } -#endif +#endif static void cdrom_ioctl_get_info (int fd) @@ -1233,7 +1190,6 @@ cdrom_ioctl_get_info (int fd) static gboolean mount_volume_iso9660_add (NautilusVolume *volume) { - #ifndef SOLARIS_MNT int fd; @@ -1249,7 +1205,7 @@ mount_volume_iso9660_add (NautilusVolume *volume) cdrom_ioctl_get_info (fd); close (fd); -#endif /* #ifndef SOLARIS_MNT */ +#endif volume->type = NAUTILUS_VOLUME_CDROM; @@ -1376,22 +1332,6 @@ find_volumes (NautilusVolumeMonitor *monitor) monitor); } -#if 0 -void -nautilus_volume_monitor_each_volume (NautilusVolumeMonitor *monitor, - NautilusEachVolumeFunction function, - gpointer context) -{ - GList *p; - - for (p = monitor->details->mounts; p != NULL; p = p->next) { - if ((* function) ((NautilusVolume *) p->data, context)) { - break; - } - } -} -#endif - void nautilus_volume_monitor_each_mounted_volume (NautilusVolumeMonitor *monitor, NautilusEachVolumeFunction function, @@ -1434,9 +1374,9 @@ static const char *volrmmount_locations [] = { }; #define MOUNT_COMMAND volrmmount_locations -#define MOUNT_SEPERATOR " -i " +#define MOUNT_SEPARATOR " -i " #define UMOUNT_COMMAND volrmmount_locations -#define UMOUNT_SEPERATOR " -e " +#define UMOUNT_SEPARATOR " -e " #else @@ -1453,9 +1393,9 @@ static const char *umount_known_locations [] = { }; #define MOUNT_COMMAND mount_known_locations -#define MOUNT_SEPERATOR " " +#define MOUNT_SEPARATOR " " #define UMOUNT_COMMAND umount_known_locations -#define UMOUNT_SEPERATOR " " +#define UMOUNT_SEPARATOR " " #endif /* USE_VOLRMMOUNT */ @@ -1503,7 +1443,7 @@ typedef struct { typedef struct { char *message; char *detailed_message; - char *title; + const char *title; } MountStatusInfo; @@ -1517,7 +1457,6 @@ display_mount_status (gpointer callback_data) g_free (info->message); g_free (info->detailed_message); - g_free (info->title); g_free (info); return FALSE; @@ -1527,34 +1466,33 @@ static void close_error_pipe (gboolean mount, const char *mount_path) { char *message; - const char *title; char detailed_msg[MAX_PIPE_SIZE]; - int length = 0; + int length; gboolean is_floppy; MountStatusInfo *info; - - if (mount) { - title = _("Mount Error"); - } else { - title = _("Unmount Error"); + + if (old_error < 0) { + return; } - - if (old_error >= 0) { - close (2); - dup (old_error); - close (old_error); - - do { - length = read (error_pipe[0], detailed_msg, MAX_PIPE_SIZE); - } while (length < 0); - - if (length >= 0) { - detailed_msg[length] = 0; - } - - close (error_pipe[0]); + + close (2); + dup (old_error); + close (old_error); + + /* FIXME: This keeps reading into the same buffer over and + * over again and makes no attempt to save bytes from any + * calls other than the last read call. + */ + do { + length = read (error_pipe[0], detailed_msg, MAX_PIPE_SIZE); + } while (length < 0); + + if (length >= 0) { + detailed_msg[length] = 0; } + close (error_pipe[0]); + /* No output to show */ if (length == 0) { return; @@ -1605,13 +1543,11 @@ close_error_pipe (gboolean mount, const char *mount_path) /* Set up info and pass it to callback to display dialog. We do this because this routine may be called from a thread */ info = g_new0 (MountStatusInfo, 1); - info->message = g_strdup (message); + info->message = message; info->detailed_message = g_strdup (detailed_msg); - info->title = g_strdup (title); + info->title = mount ? _("Mount Error") : _("Unmount Error"); gtk_idle_add (display_mount_status, info); - - g_free (message); } @@ -1667,19 +1603,19 @@ nautilus_volume_monitor_mount_unmount_removable (NautilusVolumeMonitor *monitor, if (name != NULL) { name = name + 1; } else { - name = mount_point; + name = mount_point; } #else name = mount_point; #endif /* USE_VOLRMMOUNT */ - + if (should_mount) { command = find_command (MOUNT_COMMAND); - command_string = g_strconcat (command, MOUNT_SEPERATOR, name, NULL); + command_string = g_strconcat (command, MOUNT_SEPARATOR, name, NULL); } else { command = find_command (UMOUNT_COMMAND); - command_string = g_strconcat (command, UMOUNT_SEPERATOR, name, NULL); + command_string = g_strconcat (command, UMOUNT_SEPARATOR, name, NULL); } mount_info = g_new0 (MountThreadInfo, 1); @@ -1883,7 +1819,7 @@ mount_volume_add_filesystem (NautilusVolume *volume, GList *volume_list) { gboolean mounted = FALSE; - if (nautilus_str_has_prefix (volume->device_path, FLOPPY_DEVICE_PATH_PREFIX)) { + if (nautilus_str_has_prefix (volume->device_path, floppy_device_path_prefix)) { mounted = mount_volume_floppy_add (volume); } else if (strcmp (volume->filesystem, "affs") == 0) { mounted = mount_volume_affs_add (volume); @@ -1931,7 +1867,7 @@ mount_volume_add_filesystem (NautilusVolume *volume, GList *volume_list) #ifndef SOLARIS_MNT volume->is_removable = volume_is_removable (volume); volume->is_read_only = volume_is_read_only (volume); -#endif /* SOLARIS_MNT */ +#endif mount_volume_get_name (volume); volume_list = g_list_append (volume_list, volume); } else { diff --git a/libnautilus/nautilus-clipboard-ui.xml b/libnautilus/nautilus-clipboard-ui.xml index 431cb2017..b673c5a8f 100644 --- a/libnautilus/nautilus-clipboard-ui.xml +++ b/libnautilus/nautilus-clipboard-ui.xml @@ -1,33 +1,43 @@ <Root> <commands> - <cmd name="Cut" accel="*Control*x" sensitive="1"/> - <cmd name="Copy" accel="*Control*c" sensitive="1"/> - <cmd name="Paste" accel="*Control*v" sensitive="1"/> - <cmd name="Clear" sensitive="1"/> - <cmd name="Select All" accel="*Control*a" sensitive="1"/> + <cmd name="Cut" + _label="Cut Text" + accel="*Control*x" + _tip="Cut the selected text to the clipboard"/> + <cmd name="Copy" + _label="Copy Text" + accel="*Control*c" + _tip="Copy the selected text to the clipboard"/> + <cmd name="Paste" + _label="Paste Text" + _tip="Paste the text stored on the clipboard" + accel="*Control*v"/> + <cmd name="Clear" + _tip="Remove the selected text without putting it on the clipboard" + _label="Clear Text"/> + <cmd name="Select All" + _label="Select All" + _tip="Select all the text in a text field" + accel="*Control*a"/> </commands> <menu> <submenu name="Edit"> <menuitem name="Cut" _label="Cut _Text" - _tip="Cut the selected text to the clipboard" pixtype="stock" pixname="Cut" verb="Cut"/> <menuitem name="Copy" _label="_Copy Text" - _tip="Copy the selected text to the clipboard" pixtype="stock" pixname="Copy" verb="Copy"/> <menuitem name="Paste" _label="_Paste Text" - _tip="Paste the text stored on the clipboard" pixtype="stock" pixname="Paste" verb="Paste"/> <menuitem name="Clear" _label="C_lear Text" - _tip="Remove the selected text without putting it on the clipboard" pixtype="stock" pixname="Clear" verb="Clear"/> <menuitem name="Select All" @@ -35,4 +45,5 @@ verb="Select All"/> </submenu> </menu> + </Root> diff --git a/libnautilus/nautilus-clipboard.c b/libnautilus/nautilus-clipboard.c index badb92339..d13682281 100644 --- a/libnautilus/nautilus-clipboard.c +++ b/libnautilus/nautilus-clipboard.c @@ -205,6 +205,12 @@ set_paste_sensitive_if_clipboard_contains_data (BonoboUIComponent *component) * process, which may not be the case, and we may still be * able to paste data. */ + /* FIXME: PRIMARY is wrong here. We are interested in + * CLIPBOARD, not PRIMARY. + */ + /* FIXME: This doesn't tell us what kind of data is on the + * clipboard, and we only want to be sensitive if it's text. + */ clipboard_contains_data = (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) != NULL); @@ -350,13 +356,6 @@ focus_changed_callback (GtkWidget *widget, } static void -grab_focus_callback (GtkWidget *widget, - gpointer data) -{ - focus_changed_callback (widget, NULL, data); -} - -static void selection_changed_callback (GtkWidget *widget, gpointer callback_data) { @@ -440,16 +439,13 @@ nautilus_clipboard_set_up_editable (GtkEditable *target, g_return_if_fail (GTK_IS_EDITABLE (target)); g_return_if_fail (ui_container != CORBA_OBJECT_NIL); + target_data = initialize_clipboard_component_with_callback_data + (target, + ui_container, + shares_selection_changes); - target_data = initialize_clipboard_component_with_callback_data (target, - ui_container, - shares_selection_changes); gtk_signal_connect_after (GTK_OBJECT (target), "focus_in_event", focus_changed_callback, target_data); - /* Allow widgets that are already focused when they set up tell the clipboard - to manually consider them */ - gtk_signal_connect (GTK_OBJECT (target), "grab_focus", - grab_focus_callback, target_data); gtk_signal_connect_after (GTK_OBJECT (target), "focus_out_event", focus_changed_callback, target_data); @@ -489,7 +485,6 @@ first_focus_callback (GtkWidget *widget, widget_was_set_up_with_selection_sensitivity (widget)); } - static void control_destroyed_callback (GtkObject *object, gpointer callback_data) @@ -506,6 +501,14 @@ nautilus_clipboard_set_up_editable_in_control (GtkEditable *target, g_return_if_fail (GTK_IS_EDITABLE (target)); g_return_if_fail (BONOBO_IS_CONTROL (control)); + if (GTK_WIDGET_HAS_FOCUS (target)) { + nautilus_clipboard_set_up_editable + (target, + bonobo_control_get_remote_ui_container (control), + shares_selection_changes); + return; + } + /* Use lazy initialization, so that we wait until after * embedding. At that point, the UI container will be set up, * but it's not necessarily set up now. diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c index fcf0c6641..eeaace714 100644 --- a/src/file-manager/fm-directory-view.c +++ b/src/file-manager/fm-directory-view.c @@ -98,11 +98,15 @@ #define FM_DIRECTORY_VIEW_COMMAND_REMOVE_CUSTOM_ICONS "/commands/Remove Custom Icons" #define FM_DIRECTORY_VIEW_COMMAND_OTHER_APPLICATION "/commands/OtherApplication" #define FM_DIRECTORY_VIEW_COMMAND_OTHER_VIEWER "/commands/OtherViewer" +#define FM_DIRECTORY_VIEW_COMMAND_CUT_FILES "/commands/Cut Files" +#define FM_DIRECTORY_VIEW_COMMAND_COPY_FILES "/commands/Copy Files" +#define FM_DIRECTORY_VIEW_COMMAND_PASTE_FILES "/commands/Paste Files" #define FM_DIRECTORY_VIEW_MENU_PATH_OPEN_IN_NEW_WINDOW "/menu/File/Open Placeholder/OpenNew" #define FM_DIRECTORY_VIEW_MENU_PATH_OPEN_WITH "/menu/File/Open Placeholder/Open With" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS "/menu/File/Open Placeholder/Scripts" #define FM_DIRECTORY_VIEW_MENU_PATH_TRASH "/menu/File/File Items Placeholder/Trash" +#define FM_DIRECTORY_VIEW_MENU_PATH_DELETE "/menu/File/File Items Placeholder/Delete" #define FM_DIRECTORY_VIEW_MENU_PATH_EMPTY_TRASH "/menu/File/Global File Items Placeholder/Empty Trash" #define FM_DIRECTORY_VIEW_MENU_PATH_CREATE_LINK "/menu/File/File Items Placeholder/Create Link" #define FM_DIRECTORY_VIEW_MENU_PATH_REMOVE_CUSTOM_ICONS "/menu/Edit/Edit Items Placeholder/Remove Custom Icons" @@ -112,6 +116,9 @@ #define FM_DIRECTORY_VIEW_MENU_PATH_OTHER_VIEWER "/menu/File/Open Placeholder/Open With/OtherViewer" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER "/menu/File/Open Placeholder/Scripts/Scripts Placeholder" #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_SEPARATOR "/menu/File/Open Placeholder/Scripts/After Scripts" +#define FM_DIRECTORY_VIEW_MENU_PATH_CUT_FILES "/menu/Edit/Cut" +#define FM_DIRECTORY_VIEW_MENU_PATH_COPY_FILES "/menu/Edit/Copy" +#define FM_DIRECTORY_VIEW_MENU_PATH_PASTE_FILES "/menu/File/Paste" #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND "/popups/background" #define FM_DIRECTORY_VIEW_POPUP_PATH_SELECTION "/popups/selection" @@ -138,6 +145,11 @@ enum { static guint signals[LAST_SIGNAL]; +static GdkAtom clipboard_atom; +static GdkAtom copied_files_atom; + +static gboolean show_delete_command; + struct FMDirectoryViewDetails { NautilusView *nautilus_view; @@ -190,6 +202,9 @@ struct FMDirectoryViewDetails NautilusFile *file_monitored_for_open_with; NautilusDirectory *directory_monitored_for_activation; + + GList *clipboard_contents; + gboolean clipboard_contents_were_cut; }; typedef enum { @@ -220,31 +235,21 @@ static void fm_directory_view_initialize static void fm_directory_view_duplicate_selection (FMDirectoryView *view, GList *files, GArray *item_locations); +static gboolean fm_directory_view_confirm_deletion (FMDirectoryView *view, + GList *uris, + gboolean all); static void fm_directory_view_create_links_for_files (FMDirectoryView *view, GList *files, GArray *item_locations); static void fm_directory_view_trash_or_delete_files (const GList *files, FMDirectoryView *view); -static void fm_directory_view_destroy (GtkObject *object); static void fm_directory_view_activate_file (FMDirectoryView *view, NautilusFile *file, WindowChoice choice); static void load_directory (FMDirectoryView *view, NautilusDirectory *directory); static void fm_directory_view_merge_menus (FMDirectoryView *view); -static void real_file_limit_reached (FMDirectoryView *view); -static gboolean real_display_pending_files (FMDirectoryView *view, - GList **pending_files_added, - GList **pending_files_changed); -static void real_load_error (FMDirectoryView *view, - GnomeVFSResult result); -static void real_merge_menus (FMDirectoryView *view); -static void real_update_menus (FMDirectoryView *view); -static gboolean real_is_read_only (FMDirectoryView *view); -static gboolean real_supports_creating_files (FMDirectoryView *view); -static gboolean real_accepts_dragged_files (FMDirectoryView *view); -static gboolean real_supports_zooming (FMDirectoryView *view); -static gboolean real_supports_properties (FMDirectoryView *view); +static char * file_name_from_uri (const char *uri); static BonoboControl * get_bonobo_control (FMDirectoryView *view); static void stop_loading_callback (NautilusView *nautilus_view, FMDirectoryView *directory_view); @@ -278,9 +283,6 @@ static void unschedule_display_of_pending_files static void disconnect_model_handlers (FMDirectoryView *view); static void disconnect_script_handlers (FMDirectoryView *view); static void filtering_changed_callback (gpointer callback_data); -static NautilusStringList *real_get_emblem_names_to_exclude (FMDirectoryView *view); -static void start_renaming_item (FMDirectoryView *view, - const char *uri); static void metadata_for_directory_as_file_ready_callback (NautilusFile *file, gpointer callback_data); static void metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory, @@ -312,106 +314,6 @@ NAUTILUS_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, select_all) NAUTILUS_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, set_selection) NAUTILUS_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_selected_icon_locations) -static void -fm_directory_view_initialize_class (FMDirectoryViewClass *klass) -{ - GtkObjectClass *object_class; - - object_class = GTK_OBJECT_CLASS (klass); - - object_class->destroy = fm_directory_view_destroy; - - signals[CLEAR] = - gtk_signal_new ("clear", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, clear), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - signals[BEGIN_ADDING_FILES] = - gtk_signal_new ("begin_adding_files", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, begin_adding_files), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - signals[ADD_FILE] = - gtk_signal_new ("add_file", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, add_file), - gtk_marshal_NONE__BOXED, - GTK_TYPE_NONE, 1, GTK_TYPE_BOXED); - signals[FILE_CHANGED] = - gtk_signal_new ("file_changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, file_changed), - gtk_marshal_NONE__BOXED, - GTK_TYPE_NONE, 1, GTK_TYPE_BOXED); - signals[DONE_ADDING_FILES] = - gtk_signal_new ("done_adding_files", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, done_adding_files), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - signals[BEGIN_LOADING] = - gtk_signal_new ("begin_loading", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, begin_loading), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - signals[END_LOADING] = - gtk_signal_new ("end_loading", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, end_loading), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - signals[LOAD_ERROR] = - gtk_signal_new ("load_error", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (FMDirectoryViewClass, load_error), - gtk_marshal_NONE__INT, - GTK_TYPE_NONE, 1, GTK_TYPE_INT); - - klass->merge_menus = real_merge_menus; - klass->update_menus = real_update_menus; - klass->display_pending_files = real_display_pending_files; - klass->get_emblem_names_to_exclude = real_get_emblem_names_to_exclude; - klass->start_renaming_item = start_renaming_item; - klass->is_read_only = real_is_read_only; - klass->supports_creating_files = real_supports_creating_files; - klass->accepts_dragged_files = real_accepts_dragged_files; - klass->supports_zooming = real_supports_zooming; - klass->supports_properties = real_supports_properties; - klass->file_limit_reached = real_file_limit_reached; - klass->load_error = real_load_error; - klass->reveal_selection = NULL; - - /* Function pointers that subclasses must override */ - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, add_file); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, bump_zoom_level); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, zoom_to_level); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, restore_default_zoom_level); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_in); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_out); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_background_widget); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, clear); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, file_changed); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selection); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, is_empty); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, select_all); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, set_selection); - NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selected_icon_locations); - - gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); - -} - typedef struct { GnomeVFSMimeApplication *application; NautilusFile *file; @@ -818,6 +720,77 @@ trash_callback (BonoboUIComponent *component, gpointer callback_data, const char nautilus_file_list_free (selection); } +static gboolean +confirm_delete_directly (FMDirectoryView *view, + GList *uris) +{ + GnomeDialog *dialog; + char *prompt; + char *file_name; + int uri_count; + + g_assert (FM_IS_DIRECTORY_VIEW (view)); + + /* Just Say Yes if the preference says not to confirm. */ + if (!nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_CONFIRM_TRASH)) { + return TRUE; + } + + uri_count = g_list_length (uris); + g_assert (uri_count > 0); + + if (uri_count == 1) { + file_name = file_name_from_uri ((char *) uris->data); + prompt = g_strdup_printf (_("Are you sure you want to permanently delete \"%s\"?"), + file_name); + g_free (file_name); + } else { + prompt = g_strdup_printf (_("Are you sure you want to permanently delete " + "the %d selected items?"), uri_count); + } + + dialog = nautilus_show_yes_no_dialog + (prompt, + _("Delete?"), + _("Delete"), + GNOME_STOCK_BUTTON_CANCEL, + fm_directory_view_get_containing_window (view)); + + g_free (prompt); + + return gnome_dialog_run (dialog) == GNOME_OK; +} + + +static void +delete_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) +{ + FMDirectoryView *view; + GList *selection; + GList *node; + GList *file_uris; + + view = FM_DIRECTORY_VIEW (callback_data); + selection = fm_directory_view_get_selection (view); + if (selection_not_empty_in_menu_callback (view, selection)) { + + file_uris = NULL; + for (node = selection; node != NULL; node = node->next) { + file_uris = g_list_prepend (file_uris, + nautilus_file_get_uri ((NautilusFile *) node->data)); + } + + if (confirm_delete_directly (view, + file_uris)) { + nautilus_file_operations_delete (file_uris, GTK_WIDGET (view)); + } + + nautilus_g_list_free_deep (file_uris); + } + + nautilus_file_list_free (selection); +} + static void duplicate_callback (BonoboUIComponent *component, gpointer callback_data, const char *verb) { @@ -891,7 +864,7 @@ bonobo_menu_empty_trash_callback (BonoboUIComponent *component, { g_assert (FM_IS_DIRECTORY_VIEW (callback_data)); - nautilus_file_operations_empty_trash (GTK_WIDGET (FM_DIRECTORY_VIEW (callback_data))); + nautilus_file_operations_empty_trash (GTK_WIDGET (callback_data)); } static void @@ -1127,12 +1100,18 @@ connect_script_handlers (FMDirectoryView *view) view); } - - static void fm_directory_view_initialize (FMDirectoryView *view) { view->details = g_new0 (FMDirectoryViewDetails, 1); + + /* We need to have our own X window so that cut, copy, and + * paste work. The window is created by our realize method, + * but we also have to do this additional set-up here. + */ + GTK_WIDGET_UNSET_FLAGS (view, GTK_NO_WINDOW); + gtk_selection_add_target (GTK_WIDGET (view), clipboard_atom, + copied_files_atom, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC, @@ -1200,58 +1179,49 @@ fm_directory_view_initialize (FMDirectoryView *view) filtering_changed_callback (view); - /* Keep track of changes in this pref to filter files accordingly. */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES, filtering_changed_callback, view); - - /* Keep track of changes in this pref to filter files accordingly. */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES, filtering_changed_callback, view); - - /* Keep track of changes in this pref to display menu names correctly. */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_CONFIRM_TRASH, schedule_update_menus_callback, view); - - /* Keep track of changes in text attribute names */ + nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ENABLE_DELETE, + schedule_update_menus_callback, + view); nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, text_attribute_names_changed_callback, view); - - /* Keep track of changes in image display policy */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS, image_display_policy_changed_callback, view); - - /* Keep track of changes in the font family */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_DIRECTORY_VIEW_FONT_FAMILY, directory_view_font_family_changed_callback, view); - - /* Keep track of changes in the smooth font */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_DIRECTORY_VIEW_SMOOTH_FONT, directory_view_smooth_font_changed_callback, view); - - /* Keep track of changes in clicking policy */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_CLICK_POLICY, click_policy_changed_callback, view); - - /* Keep track of changes in graphics trade offs */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SMOOTH_GRAPHICS_MODE, smooth_graphics_mode_changed_callback, view); - - /* Keep track of changes in sort order */ nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST, sort_directories_first_changed_callback, view); } static void +forget_clipboard_contents (FMDirectoryView *view) +{ + nautilus_file_list_free (view->details->clipboard_contents); + view->details->clipboard_contents = NULL; +} + +static void fm_directory_view_destroy (GtkObject *object) { FMDirectoryView *view; @@ -1291,6 +1261,9 @@ fm_directory_view_destroy (GtkObject *object) nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_CONFIRM_TRASH, schedule_update_menus_callback, view); + nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ENABLE_DELETE, + schedule_update_menus_callback, + view); nautilus_preferences_remove_callback (NAUTILUS_PREFERENCES_ICON_CAPTIONS, text_attribute_names_changed_callback, view); @@ -1313,6 +1286,8 @@ fm_directory_view_destroy (GtkObject *object) sort_directories_first_changed_callback, view); + forget_clipboard_contents (view); + g_free (view->details); NAUTILUS_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object)); @@ -2528,6 +2503,10 @@ offset_drop_points (GArray *relative_item_points, { guint index; + if (relative_item_points == NULL) { + return; + } + for (index = 0; index < relative_item_points->len; index++) { g_array_index (relative_item_points, GdkPoint, index).x += x_offset; g_array_index (relative_item_points, GdkPoint, index).y += y_offset; @@ -2555,8 +2534,9 @@ fm_directory_view_create_links_for_files (FMDirectoryView *view, GList *files, /* offset the drop locations a bit so that we don't pile * up the icons on top of each other */ - offset_drop_points (relative_item_points, DUPLICATE_HORIZONTAL_ICON_OFFSET, - DUPLICATE_VERTICAL_ICON_OFFSET); + offset_drop_points (relative_item_points, + DUPLICATE_HORIZONTAL_ICON_OFFSET, + DUPLICATE_VERTICAL_ICON_OFFSET); copy_move_done_data = pre_copy_move (view); nautilus_file_operations_copy_move (uris, relative_item_points, NULL, GDK_ACTION_LINK, @@ -2585,8 +2565,9 @@ fm_directory_view_duplicate_selection (FMDirectoryView *view, GList *files, /* offset the drop locations a bit so that we don't pile * up the icons on top of each other */ - offset_drop_points (relative_item_points, DUPLICATE_HORIZONTAL_ICON_OFFSET, - DUPLICATE_VERTICAL_ICON_OFFSET); + offset_drop_points (relative_item_points, + DUPLICATE_HORIZONTAL_ICON_OFFSET, + DUPLICATE_VERTICAL_ICON_OFFSET); copy_move_done_data = pre_copy_move (view); nautilus_file_operations_copy_move (uris, relative_item_points, NULL, GDK_ACTION_COPY, @@ -2809,13 +2790,13 @@ fm_directory_view_confirm_deletion (FMDirectoryView *view, GList *uris, gboolean } } - dialog = nautilus_show_yes_no_dialog ( - prompt, - _("Delete Immediately?"), - _("Delete"), - GNOME_STOCK_BUTTON_CANCEL, - fm_directory_view_get_containing_window (view)); - + dialog = nautilus_show_yes_no_dialog + (prompt, + _("Delete Immediately?"), + _("Delete"), + GNOME_STOCK_BUTTON_CANCEL, + fm_directory_view_get_containing_window (view)); + g_free (prompt); return gnome_dialog_run (dialog) == GNOME_OK; @@ -2840,8 +2821,7 @@ confirm_delete_from_trash (FMDirectoryView *view, GList *uris) g_assert (uri_count > 0); if (uri_count == 1) { - file_name = file_name_from_uri ((char *)uris->data); - + file_name = file_name_from_uri ((char *) uris->data); prompt = g_strdup_printf (_("Are you sure you want to permanently delete \"%s\" " "from the Trash?"), file_name); g_free (file_name); @@ -2867,7 +2847,6 @@ trash_or_delete_files_common (const GList *file_uris, GArray *relative_item_points, const char *target_uri, int copy_action, - int x, int y, FMDirectoryView *view) { const GList *file_node; @@ -2944,7 +2923,7 @@ fm_directory_view_trash_or_delete_files (const GList *files, file_uris = g_list_reverse (file_uris); trash_or_delete_files_common (file_uris, NULL, NAUTILUS_TRASH_URI, - GDK_ACTION_MOVE, 0, 0, view); + GDK_ACTION_MOVE, view); nautilus_g_list_free_deep (file_uris); } @@ -2999,7 +2978,9 @@ fm_directory_view_new_folder (FMDirectoryView *directory_view) char *parent_uri; parent_uri = fm_directory_view_get_uri (directory_view); - nautilus_file_operations_new_folder (GTK_WIDGET (directory_view), parent_uri, new_folder_done, directory_view); + nautilus_file_operations_new_folder (GTK_WIDGET (directory_view), + parent_uri, + new_folder_done, directory_view); g_free (parent_uri); } @@ -3685,8 +3666,6 @@ open_scripts_folder_callback (BonoboUIComponent *component, } } - - static BonoboWindow * get_bonobo_window (FMDirectoryView *view) { @@ -3715,25 +3694,197 @@ create_popup_menu (FMDirectoryView *view, const char *popup_path) return menu; } +static guint +get_current_event_time (void) +{ + /* FIXME: Maybe we should implement this for real? */ + return GDK_CURRENT_TIME; +} + +static void +copy_or_cut_files (FMDirectoryView *view, + gboolean cut) +{ + if (gtk_selection_owner_set (GTK_WIDGET (view), + clipboard_atom, + get_current_event_time ())) { + nautilus_file_list_free (view->details->clipboard_contents); + view->details->clipboard_contents + = fm_directory_view_get_selection (view); + view->details->clipboard_contents_were_cut = cut; + } +} + +static void +copy_files_callback (BonoboUIComponent *component, + gpointer callback_data, + const char *verb) +{ + copy_or_cut_files (callback_data, FALSE); +} + +static void +cut_files_callback (BonoboUIComponent *component, + gpointer callback_data, + const char *verb) +{ + copy_or_cut_files (callback_data, TRUE); +} + +static void +paste_files_callback (BonoboUIComponent *component, + gpointer callback_data, + const char *verb) +{ + gtk_selection_convert (GTK_WIDGET (callback_data), + clipboard_atom, + copied_files_atom, + get_current_event_time ()); +} + +static gboolean +real_selection_clear_event (GtkWidget *widget, + GdkEventSelection *event) +{ + FMDirectoryView *view; + + view = FM_DIRECTORY_VIEW (widget); + + if (!gtk_selection_clear (widget, event)) { + return FALSE; + } + + forget_clipboard_contents (view); + return TRUE; +} + +static void +real_selection_get (GtkWidget *widget, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + FMDirectoryView *view; + GString *uris; + GList *node; + char *uri; + + view = FM_DIRECTORY_VIEW (widget); + + uris = g_string_new (view->details->clipboard_contents_were_cut + ? "cut" : "copy"); + + for (node = view->details->clipboard_contents; + node != NULL; node = node->next) { + uri = nautilus_file_get_uri (node->data); + g_string_append_c (uris, '\n'); + g_string_append (uris, uri); + g_free (uri); + } + + gtk_selection_data_set (selection_data, + copied_files_atom, + 8, + uris->str, + uris->len); + + g_string_free (uris, TRUE); +} + +static GList * +convert_lines_to_str_list (char **lines, gboolean *cut) +{ + int i; + GList *result; + + if (lines[0] == NULL) { + return NULL; + } + + if (strcmp (lines[0], "cut") == 0) { + *cut = TRUE; + } else if (strcmp (lines[0], "copy") == 0) { + *cut = FALSE; + } else { + return NULL; + } + + result = NULL; + for (i = 1; lines[i] != NULL; i++) { + result = g_list_prepend (result, g_strdup (lines[i])); + } + return g_list_reverse (result); +} + +static void +real_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint time) +{ + FMDirectoryView *view; + char **lines; + gboolean cut; + GList *item_uris; + char *view_uri; + + view = FM_DIRECTORY_VIEW (widget); + + if (selection_data->type != copied_files_atom + || selection_data->length <= 0) { + return; + } + + /* Not sure why it's legal to assume there's an extra byte + * past the end of the selection data that it's safe to write + * to. But gtk_editable_selection_received does this, so I + * think it is OK. + */ + selection_data->data[selection_data->length] = '\0'; + lines = g_strsplit (selection_data->data, "\n", 0); + item_uris = convert_lines_to_str_list (lines, &cut); + g_strfreev (lines); + if (item_uris == NULL) { + return; + } + + view_uri = fm_directory_view_get_uri (view); + if (view_uri == NULL) { + nautilus_g_list_free_deep (item_uris); + return; + } + + fm_directory_view_move_copy_items (item_uris, NULL, view_uri, + cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY, + 0, 0, + view); + + nautilus_g_list_free_deep (item_uris); + g_free (view_uri); +} + static void real_merge_menus (FMDirectoryView *view) { BonoboUIVerb verbs [] = { + BONOBO_UI_VERB ("Copy Files", copy_files_callback), + BONOBO_UI_VERB ("Create Link", create_link_callback), + BONOBO_UI_VERB ("Cut Files", cut_files_callback), + BONOBO_UI_VERB ("Delete", delete_callback), + BONOBO_UI_VERB ("Duplicate", duplicate_callback), + BONOBO_UI_VERB ("Empty Trash", bonobo_menu_empty_trash_callback), BONOBO_UI_VERB ("New Folder", new_folder_callback), + BONOBO_UI_VERB ("Open Scripts Folder", open_scripts_folder_callback), BONOBO_UI_VERB ("Open", open_callback), BONOBO_UI_VERB ("OpenNew", open_in_new_window_callback), BONOBO_UI_VERB ("OtherApplication", other_application_callback), BONOBO_UI_VERB ("OtherViewer", other_viewer_callback), - BONOBO_UI_VERB ("Show Properties", open_properties_window_callback), - BONOBO_UI_VERB ("Trash", trash_callback), - BONOBO_UI_VERB ("Duplicate", duplicate_callback), - BONOBO_UI_VERB ("Create Link", create_link_callback), - BONOBO_UI_VERB ("Show Trash", show_trash_callback), - BONOBO_UI_VERB ("Empty Trash", bonobo_menu_empty_trash_callback), - BONOBO_UI_VERB ("Select All", bonobo_menu_select_all_callback), + BONOBO_UI_VERB ("Paste Files", paste_files_callback), BONOBO_UI_VERB ("Remove Custom Icons", remove_custom_icons_callback), BONOBO_UI_VERB ("Reset Background", reset_background_callback), - BONOBO_UI_VERB ("Open Scripts Folder", open_scripts_folder_callback), + BONOBO_UI_VERB ("Select All", bonobo_menu_select_all_callback), + BONOBO_UI_VERB ("Show Properties", open_properties_window_callback), + BONOBO_UI_VERB ("Show Trash", show_trash_callback), + BONOBO_UI_VERB ("Trash", trash_callback), BONOBO_UI_VERB_END }; @@ -3770,14 +3921,24 @@ confirm_trash_changed_callback (gpointer callback_data) } static void +enable_delete_changed_callback (gpointer callback_data) +{ + show_delete_command = nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_ENABLE_DELETE); +} + +static void real_update_menus (FMDirectoryView *view) { static gboolean confirm_trash_changed_callback_installed = FALSE; + static gboolean enable_delete_changed_callback_installed = FALSE; GList *selection; gint selection_count; + const char *tip, *accelerator, *label; char *label_with_underscore; gboolean selection_contains_special_link; gboolean can_create_files; + gboolean can_delete_files; + gboolean show_separate_delete_command; NautilusBackground *background; selection = fm_directory_view_get_selection (view); @@ -3793,6 +3954,17 @@ real_update_menus (FMDirectoryView *view) /* Peek for the first time */ confirm_trash_changed_callback (NULL); } + + /* Add the callback once for the life of our process */ + if (!enable_delete_changed_callback_installed) { + nautilus_preferences_add_callback (NAUTILUS_PREFERENCES_ENABLE_DELETE, + enable_delete_changed_callback, + NULL); + enable_delete_changed_callback_installed = TRUE; + + /* Peek for the first time */ + enable_delete_changed_callback (NULL); + } selection_contains_special_link = special_link_in_selection (view); can_create_files = fm_directory_view_supports_creating_files (view); @@ -3833,36 +4005,50 @@ real_update_menus (FMDirectoryView *view) /* Broken into its own function just for convenience */ reset_bonobo_open_with_menu (view, selection); - if (fm_directory_all_selected_items_in_trash (view)) { - nautilus_bonobo_set_tip (view->details->ui, - FM_DIRECTORY_VIEW_MENU_PATH_TRASH, - _("Delete all selected items permanently")); - nautilus_bonobo_set_accelerator (view->details->ui, - FM_DIRECTORY_VIEW_MENU_PATH_TRASH, - ""); - label_with_underscore = g_strdup (confirm_trash - ? _("Delete from _Trash...") - : _("Delete from _Trash")); + label = confirm_trash ? _("Delete from _Trash...") : _("Delete from _Trash"); + accelerator = ""; + tip = _("Delete all selected items permanently"); + show_separate_delete_command = FALSE; } else { - nautilus_bonobo_set_tip (view->details->ui, - FM_DIRECTORY_VIEW_MENU_PATH_TRASH, - _("Move all selected items to the Trash")); - nautilus_bonobo_set_accelerator (view->details->ui, - FM_DIRECTORY_VIEW_MENU_PATH_TRASH, - "*Control*t"); - label_with_underscore = g_strdup (_("Move to _Trash")); + label = _("Move to _Trash"); + accelerator = "*Control*t"; + tip = _("Move all selected items to the Trash"); + show_separate_delete_command = show_delete_command; } + + can_delete_files = !fm_directory_view_is_read_only (view) + && selection_count != 0 + && !selection_contains_special_link; + nautilus_bonobo_set_label_for_menu_item_and_command (view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_TRASH, FM_DIRECTORY_VIEW_COMMAND_TRASH, - label_with_underscore); + label); + nautilus_bonobo_set_accelerator (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_TRASH, + accelerator); + nautilus_bonobo_set_tip (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_TRASH, + tip); nautilus_bonobo_set_sensitive (view->details->ui, FM_DIRECTORY_VIEW_COMMAND_TRASH, - !fm_directory_view_is_read_only (view) - && selection_count != 0 - && !selection_contains_special_link); + can_delete_files); + + nautilus_bonobo_set_hidden (view->details->ui, + FM_DIRECTORY_VIEW_COMMAND_DELETE, + !show_separate_delete_command); + if (show_separate_delete_command) { + nautilus_bonobo_set_label_for_menu_item_and_command + (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_DELETE, + FM_DIRECTORY_VIEW_COMMAND_DELETE, + confirm_trash ? _("Delete...") : _("Delete")); + nautilus_bonobo_set_sensitive (view->details->ui, + FM_DIRECTORY_VIEW_COMMAND_DELETE, + can_delete_files); + } nautilus_bonobo_set_sensitive (view->details->ui, FM_DIRECTORY_VIEW_COMMAND_DUPLICATE, @@ -3894,7 +4080,6 @@ real_update_menus (FMDirectoryView *view) selection_count != 0 && fm_directory_view_supports_properties (view)); - nautilus_bonobo_set_label_for_menu_item_and_command (view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_EMPTY_TRASH, @@ -3922,6 +4107,32 @@ real_update_menus (FMDirectoryView *view) NAUTILUS_COMMAND_SELECT_ALL, !fm_directory_view_is_empty (view)); + nautilus_bonobo_set_label_for_menu_item_and_command + (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_CUT_FILES, + FM_DIRECTORY_VIEW_COMMAND_CUT_FILES, + selection_count == 1 + ? _("Cu_t File") + : _("Cu_t Files")); + nautilus_bonobo_set_sensitive (view->details->ui, + FM_DIRECTORY_VIEW_COMMAND_CUT_FILES, + selection_count != 0); + + nautilus_bonobo_set_label_for_menu_item_and_command + (view->details->ui, + FM_DIRECTORY_VIEW_MENU_PATH_COPY_FILES, + FM_DIRECTORY_VIEW_COMMAND_COPY_FILES, + selection_count == 1 + ? _("_Copy File") + : _("_Copy Files")); + nautilus_bonobo_set_sensitive (view->details->ui, + FM_DIRECTORY_VIEW_COMMAND_COPY_FILES, + selection_count != 0); + + /* FIXME: Would be nice to set up paste item here based on + * contents of CLIPBOARD, but I'm not sure that's possible due + * to limitations of X clipboard support. + */ bonobo_ui_component_thaw (view->details->ui, NULL); @@ -3930,7 +4141,6 @@ real_update_menus (FMDirectoryView *view) if (view->details->scripts_invalid) { schedule_reset_scripts_menu (view); } - } /** @@ -4723,8 +4933,10 @@ static void fm_directory_view_select_file (FMDirectoryView *view, NautilusFile *file) { GList file_list; + file_list.data = file; file_list.next = NULL; + file_list.prev = NULL; fm_directory_view_set_selection (view, &file_list); } @@ -4993,8 +5205,9 @@ fm_directory_view_move_copy_items (const GList *item_uris, int length; const GList *p; - g_assert (relative_item_points->len == 0 - || g_list_length ((GList *)item_uris) == relative_item_points->len); + g_assert (relative_item_points == NULL + || relative_item_points->len == 0 + || g_list_length ((GList *)item_uris) == relative_item_points->len); /* add the drop location to the icon offsets */ offset_drop_points (relative_item_points, x, y); @@ -5035,7 +5248,7 @@ fm_directory_view_move_copy_items (const GList *item_uris, if (nautilus_uri_is_trash (target_uri)) { trash_or_delete_files_common (item_uris, relative_item_points, target_uri, copy_action, - x, y, view); + view); } else { nautilus_file_operations_copy_move (item_uris, relative_item_points, @@ -5161,3 +5374,168 @@ monitor_file_for_activation (FMDirectoryView *view, TRUE, TRUE, NULL); } } + +static void +real_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_EXPOSURE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); +} + +static void +real_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkAllocation allocation_to_fool_scrolled_window; + + /* Trick GtkScrolledWindow into working. */ + + allocation_to_fool_scrolled_window.x = 0; + allocation_to_fool_scrolled_window.y = 0; + allocation_to_fool_scrolled_window.width = allocation->width; + allocation_to_fool_scrolled_window.height = allocation->height; + NAUTILUS_CALL_PARENT (GTK_WIDGET_CLASS, size_allocate, + (widget, &allocation_to_fool_scrolled_window)); + + /* The rest of this is just identical to what GtkWidget does. */ + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + } +} + +static void +fm_directory_view_initialize_class (FMDirectoryViewClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = GTK_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->destroy = fm_directory_view_destroy; + + widget_class->realize = real_realize; + widget_class->selection_clear_event = real_selection_clear_event; + widget_class->selection_get = real_selection_get; + widget_class->selection_received = real_selection_received; + widget_class->size_allocate = real_size_allocate; + + signals[CLEAR] = + gtk_signal_new ("clear", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, clear), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + signals[BEGIN_ADDING_FILES] = + gtk_signal_new ("begin_adding_files", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, begin_adding_files), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + signals[ADD_FILE] = + gtk_signal_new ("add_file", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, add_file), + gtk_marshal_NONE__BOXED, + GTK_TYPE_NONE, 1, GTK_TYPE_BOXED); + signals[FILE_CHANGED] = + gtk_signal_new ("file_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, file_changed), + gtk_marshal_NONE__BOXED, + GTK_TYPE_NONE, 1, GTK_TYPE_BOXED); + signals[DONE_ADDING_FILES] = + gtk_signal_new ("done_adding_files", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, done_adding_files), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + signals[BEGIN_LOADING] = + gtk_signal_new ("begin_loading", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, begin_loading), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + signals[END_LOADING] = + gtk_signal_new ("end_loading", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, end_loading), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + signals[LOAD_ERROR] = + gtk_signal_new ("load_error", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (FMDirectoryViewClass, load_error), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + klass->merge_menus = real_merge_menus; + klass->update_menus = real_update_menus; + klass->display_pending_files = real_display_pending_files; + klass->get_emblem_names_to_exclude = real_get_emblem_names_to_exclude; + klass->start_renaming_item = start_renaming_item; + klass->is_read_only = real_is_read_only; + klass->supports_creating_files = real_supports_creating_files; + klass->accepts_dragged_files = real_accepts_dragged_files; + klass->supports_zooming = real_supports_zooming; + klass->supports_properties = real_supports_properties; + klass->file_limit_reached = real_file_limit_reached; + klass->load_error = real_load_error; + klass->reveal_selection = NULL; + + /* Function pointers that subclasses must override */ + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, add_file); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, bump_zoom_level); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, zoom_to_level); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, restore_default_zoom_level); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_in); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_out); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_background_widget); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, clear); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, file_changed); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selection); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, is_empty); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, select_all); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, set_selection); + NAUTILUS_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selected_icon_locations); + + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); + + clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); + copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); +} diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c index 9b868564e..85b8c43f6 100644 --- a/src/file-manager/fm-icon-view.c +++ b/src/file-manager/fm-icon-view.c @@ -1456,21 +1456,17 @@ icon_container_preview_callback (NautilusIconContainer *container, static void renaming_icon_callback (NautilusIconContainer *container, - gpointer editable_data, + GtkEditable *editable, gpointer callback_data) { FMDirectoryView *directory_view; directory_view = FM_DIRECTORY_VIEW (callback_data); - nautilus_clipboard_set_up_editable_in_control (GTK_EDITABLE (editable_data), - fm_directory_view_get_bonobo_control (directory_view), - TRUE); - /* Focus the editable in so the clipboard items will get turned on - while we're renaming; the hack that the nautilus entry is a - virtual widget prevents this from happening normally */ - gtk_signal_emit_by_name (GTK_OBJECT (editable_data), "grab_focus"); - + nautilus_clipboard_set_up_editable_in_control + (editable, + fm_directory_view_get_bonobo_control (directory_view), + TRUE); } static int @@ -1486,7 +1482,7 @@ icon_container_compare_icons_callback (NautilusIconContainer *container, return nautilus_file_compare_for_sort (file_a, file_b, icon_view->details->sort->sort_type, - fm_directory_view_should_sort_directories_first (FM_DIRECTORY_VIEW (icon_view)), + fm_directory_view_should_sort_directories_first (FM_DIRECTORY_VIEW (icon_view)), icon_view->details->sort_reversed); } diff --git a/src/file-manager/nautilus-directory-view-ui.xml b/src/file-manager/nautilus-directory-view-ui.xml index 9cf56b1a3..fe0f3700b 100644 --- a/src/file-manager/nautilus-directory-view-ui.xml +++ b/src/file-manager/nautilus-directory-view-ui.xml @@ -3,6 +3,9 @@ <cmd name="Create Link" _label="Create Link" _tip="Create a symbolic link for each selected item"/> + <cmd name="Delete" + _label="Delete" + _tip="Delete each selected item, without moving to the Trash"/> <cmd name="Duplicate" _label="Duplicate" _tip="Duplicate each selected item"/> @@ -33,6 +36,15 @@ <cmd name="Reset Background" _label="Reset Background" _tip="Remove any custom pattern or color from the background of this location"/> + <cmd name="Cut Files" + _label="Cut Files" + _tip="Prepare the selected files to be moved with a Paste Files command"/> + <cmd name="Copy Files" + _label="Copy Files" + _tip="Prepare the selected files to be copied with a Paste Files command"/> + <cmd name="Paste Files" + _label="Paste Files" + _tip="Move or copy files previously selected by a Cut Files or Copy Files command"/> <cmd name="Select All" _label="Select All Files" _tip="Select all items in this window"/> @@ -96,6 +108,9 @@ _label="Move to _Trash" accel="*Control*t" verb="Trash"/> + <menuitem name="Delete" + _label="Delete" + verb="Delete"/> <menuitem name="Duplicate" _label="_Duplicate" accel="*Control*d" @@ -117,6 +132,18 @@ </submenu> <submenu name="Edit"> + <menuitem name="Cut" + _label="Cu_t Files" + accel="*Control*x" + verb="Cut Files"/> + <menuitem name="Copy" + _label="_Copy Files" + accel="*Control*c" + verb="Copy Files"/> + <menuitem name="Paste" + _label="_Paste Files" + accel="*Control*v" + verb="Paste Files"/> <menuitem name="Select All" _label="Select _All Files" accel="*Control*a" @@ -172,6 +199,7 @@ <placeholder name="File Actions" delimit="top"> <menuitem name="Show Properties" verb="Show Properties"/> <menuitem name="Trash" verb="Trash"/> + <menuitem name="Delete" verb="Delete"/> <menuitem name="Duplicate" verb="Duplicate"/> <menuitem name="Create Link" verb="Create Link"/> </placeholder> diff --git a/src/nautilus-shell-ui.xml b/src/nautilus-shell-ui.xml index a1a77c9af..17c9300c4 100644 --- a/src/nautilus-shell-ui.xml +++ b/src/nautilus-shell-ui.xml @@ -93,23 +93,19 @@ --> <menuitem name="Cut" - _label="Cut _Text" - _tip="Cut the selected text to the clipboard" + _label="Cut _Text" pixtype="stock" pixname="Cut" verb="Cut"/> <menuitem name="Copy" - _label="_Copy Text" - _tip="Copy the selected text to the clipboard" + _label="_Copy Text" pixtype="stock" pixname="Copy" verb="Copy"/> <menuitem name="Paste" - _label="_Paste Text" - _tip="Paste the text stored on the clipboard" + _label="_Paste Text" pixtype="stock" pixname="Paste" verb="Paste"/> <menuitem name="Clear" - _label="C_lear Text" - _tip="Removes the selected text without putting it on the clipboard" + _label="C_lear Text" verb="Clear"/> <separator/> |