On Mi, 2005-10-19 at 11:54 +0200, Alexander Larsson wrote: > On Tue, 2005-10-04 at 13:10 +0200, Christian Neumair wrote: > > The attached two patches change the Nautilus semantics for dealing with > > multiple files. The trick is to be notified about all activation URIs > > and decide what to do with the individual files later. We can then > > cumulate multiple files and pass them to the same application handler. > > > > From quickly taking a look at the patch it looks like we sometimes leak > > the activation->files list, this can be resolved right before the > > commit, though. > (review) It's frustrating. I fail to see why the refcount is hosed after the file activation. I'm sending what I have now back to the list for review. Using gdb and printf-debugging didn't yield anything. -- Christian Neumair <chris gnome-de org>
Index: file-manager/fm-directory-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.c,v
retrieving revision 1.718
diff -u -p -r1.718 fm-directory-view.c
--- file-manager/fm-directory-view.c 14 Nov 2005 14:56:12 -0000 1.718
+++ file-manager/fm-directory-view.c 18 Nov 2005 17:53:10 -0000
@@ -271,12 +271,13 @@ typedef enum {
typedef struct {
FMDirectoryView *view;
- NautilusFile *file;
+ GList *files;
+ NautilusFileListHandle *files_handle;
+ NautilusFileListCallback callback;
NautilusWindowOpenMode mode;
NautilusWindowOpenFlags flags;
- NautilusFileCallback callback;
- gboolean mounted;
- gboolean mounting;
+ gboolean mount_success;
+ unsigned int pending_mounts;
gboolean cancelled;
} ActivateParameters;
@@ -347,7 +348,7 @@ static void fm_directory_view_select
static void monitor_file_for_open_with (FMDirectoryView *view,
NautilusFile *file);
static void create_scripts_directory (void);
-static void activate_activation_uri_ready_callback (NautilusFile *file,
+static void activate_activation_uris_ready_callback (GList *files,
gpointer callback_data);
static gboolean can_show_default_app (FMDirectoryView *view,
NautilusFile *file);
@@ -7340,13 +7341,9 @@ cancel_activate (gpointer callback_data)
parameters->cancelled = TRUE;
- if (!parameters->mounting) {
- nautilus_file_cancel_call_when_ready (parameters->file,
- parameters->callback,
- parameters);
-
- nautilus_file_unref (parameters->file);
-
+ if (parameters->pending_mounts == 0) {
+ nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
+ nautilus_file_list_free (parameters->files);
g_free (parameters);
}
}
@@ -7384,11 +7381,19 @@ stop_activate (ActivateParameters *param
}
static void
-activate_callback (NautilusFile *file, gpointer callback_data)
+activate_callback (GList *files, gpointer callback_data)
{
ActivateParameters *parameters;
FMDirectoryView *view;
- char *orig_uri, *uri, *file_uri;
+ NautilusFile *file;
+ GList *launch_desktop_files;
+ GList *launch_from_command_files;
+ GList *launch_files;
+ GList *launch_in_terminal_files;
+ GList *open_in_app_files;
+ GList *open_in_view_files;
+ GList *l;
+ char *uri;
char *executable_path, *quoted_path, *name;
char *old_working_dir;
ActivationAction action;
@@ -7400,64 +7405,150 @@ activate_callback (NautilusFile *file, g
view = FM_DIRECTORY_VIEW (parameters->view);
- if (!activate_check_mime_types (view, file, TRUE)
- || nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
- nautilus_file_unref (file);
- g_free (parameters);
-
- return;
- }
+ screen = gtk_widget_get_screen (GTK_WIDGET (view));
- orig_uri = uri = nautilus_file_get_activation_uri (file);
+ launch_desktop_files = NULL;
+ launch_from_command_files = NULL;
+ launch_files = NULL;
+ launch_in_terminal_files = NULL;
+ open_in_app_files = NULL;
+ open_in_view_files = NULL;
- action = get_activation_action (file);
+ for (l = files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
- screen = gtk_widget_get_screen (GTK_WIDGET (view));
+ if (!activate_check_mime_types (view, file, TRUE) ||
+ nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
+ continue;
+ }
- if (action == ACTIVATION_ACTION_ASK) {
- /* Special case for executable text files, since it might be
- * dangerous & unexpected to launch these.
- */
- action = get_executable_text_file_action (view, file);
+ action = get_activation_action (file);
+ if (action == ACTIVATION_ACTION_ASK) {
+ /* Special case for executable text files, since it might be
+ * dangerous & unexpected to launch these.
+ */
+ action = get_executable_text_file_action (view, file);
+ }
+
+ switch (action) {
+ case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE :
+ launch_desktop_files = g_list_prepend (launch_desktop_files, file);
+ break;
+ case ACTIVATION_ACTION_LAUNCH_APPLICATION_FROM_COMMAND :
+ launch_from_command_files = g_list_prepend (launch_from_command_files, file);
+ break;
+ case ACTIVATION_ACTION_LAUNCH :
+ launch_files = g_list_prepend (launch_files, file);
+ break;
+ case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL :
+ launch_in_terminal_files = g_list_prepend (launch_in_terminal_files, file);
+ break;
+ case ACTIVATION_ACTION_OPEN_IN_VIEW :
+ open_in_view_files = g_list_prepend (open_in_view_files, file);
+ break;
+ case ACTIVATION_ACTION_OPEN_IN_APPLICATION :
+ open_in_app_files = g_list_prepend (open_in_app_files, file);
+ break;
+ case ACTIVATION_ACTION_DO_NOTHING :
+ break;
+ case ACTIVATION_ACTION_ASK :
+ g_assert_not_reached ();
+ break;
+ }
}
-
- switch (action) {
- case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE :
- file_uri = nautilus_file_get_uri (file);
+
+
+ launch_desktop_files = g_list_reverse (launch_desktop_files);
+ for (l = launch_desktop_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
+ uri = nautilus_file_get_uri (file);
nautilus_launch_desktop_file (
- screen, file_uri, NULL,
+ screen, uri, NULL,
fm_directory_view_get_containing_window (view));
- g_free (file_uri);
- break;
- case ACTIVATION_ACTION_LAUNCH_APPLICATION_FROM_COMMAND :
- uri += strlen (NAUTILUS_COMMAND_SPECIFIER);
- nautilus_launch_application_from_command (screen, NULL, uri, NULL, FALSE);
- break;
- case ACTIVATION_ACTION_LAUNCH :
- case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL :
+ g_free (uri);
+ }
+
+ launch_from_command_files = g_list_reverse (launch_from_command_files);
+ for (l = launch_from_command_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
+ uri = nautilus_file_get_activation_uri (file);
+ nautilus_launch_application_from_command (
+ screen, NULL, uri + strlen (NAUTILUS_COMMAND_SPECIFIER),
+ NULL, FALSE);
+ g_free (uri);
+ }
+
+ old_working_dir = NULL;
+ if (launch_files != NULL || launch_in_terminal_files != NULL) {
old_working_dir = change_to_view_directory (view);
+ }
+
+ launch_files = g_list_reverse (launch_files);
+ for (l = launch_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+ uri = nautilus_file_get_activation_uri (file);
executable_path = gnome_vfs_get_local_path_from_uri (uri);
quoted_path = g_shell_quote (executable_path);
name = nautilus_file_get_name (file);
- nautilus_launch_application_from_command
- (screen, name, quoted_path, NULL,
- (action == ACTIVATION_ACTION_LAUNCH_IN_TERMINAL) /* use terminal */ );
+ nautilus_launch_application_from_command (screen, name, quoted_path, NULL, FALSE);
g_free (name);
g_free (quoted_path);
+ g_free (executable_path);
+ g_free (uri);
+
+ }
+
+ launch_in_terminal_files = g_list_reverse (launch_in_terminal_files);
+ for (l = launch_in_terminal_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+ uri = nautilus_file_get_activation_uri (file);
+ executable_path = gnome_vfs_get_local_path_from_uri (uri);
+ quoted_path = g_shell_quote (executable_path);
+ name = nautilus_file_get_name (file);
+ nautilus_launch_application_from_command (screen, name, quoted_path, NULL, TRUE);
+ g_free (name);
+ g_free (quoted_path);
+ g_free (executable_path);
+ g_free (uri);
+ }
+
+ if (old_working_dir != NULL) {
chdir (old_working_dir);
g_free (old_working_dir);
- g_free (executable_path);
-
- break;
- case ACTIVATION_ACTION_OPEN_IN_VIEW :
- open_location (view, uri, parameters->mode, parameters->flags);
- break;
- case ACTIVATION_ACTION_OPEN_IN_APPLICATION :
+ }
+
+ open_in_view_files = g_list_reverse (open_in_view_files);
+ if (g_list_length (open_in_view_files) < 2 ||
+ fm_directory_view_confirm_multiple_windows (view, g_list_length (open_in_view_files))) {
+ NautilusWindowOpenFlags flags;
+
+ flags = parameters->flags;
+ if (g_list_length (open_in_view_files) > 1) {
+ flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
+ }
+
+ for (l = open_in_view_files; l != NULL; l = l->next) {
+ /* The ui should ask for navigation or object windows
+ * depending on what the current one is */
+ file = NAUTILUS_FILE (l->data);
+
+ uri = nautilus_file_get_activation_uri (file);
+ open_location (view, uri, parameters->mode, flags);
+ g_free (uri);
+ }
+ }
+
+ open_in_app_files = g_list_reverse (open_in_app_files);
+ for (l = open_in_app_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
nautilus_launch_show_file
(file, fm_directory_view_get_containing_window (view));
-
+
if ((parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0) {
if (nautilus_window_info_get_window_type (view->details->window) == NAUTILUS_WINDOW_SPATIAL) {
nautilus_window_info_close (view->details->window);
@@ -7467,21 +7558,20 @@ activate_callback (NautilusFile *file, g
/* We should not add trash and directory uris.*/
if ((!nautilus_file_is_in_trash (file)) &&
(!nautilus_file_is_directory (file))) {
- file_uri = nautilus_file_get_uri (file);
- egg_recent_model_add (nautilus_recent_get_model (), file_uri);
- g_free (file_uri);
+ uri = nautilus_file_get_uri (file);
+ egg_recent_model_add (nautilus_recent_get_model (), uri);
+ g_free (uri);
}
- break;
- case ACTIVATION_ACTION_DO_NOTHING :
- break;
- case ACTIVATION_ACTION_ASK :
- g_assert_not_reached ();
- break;
}
- nautilus_file_unref (file);
+ g_list_free (launch_desktop_files);
+ g_list_free (launch_from_command_files);
+ g_list_free (launch_files);
+ g_list_free (launch_in_terminal_files);
+ g_list_free (open_in_view_files);
+ g_list_free (open_in_app_files);
- g_free (orig_uri);
+ nautilus_file_list_free (parameters->files);
g_free (parameters);
}
@@ -7495,79 +7585,126 @@ activation_drive_mounted_callback (gbool
parameters = callback_data;
- parameters->mounted = TRUE;
- parameters->mounting = FALSE;
-
- if (succeeded && !parameters->cancelled) {
- activate_activation_uri_ready_callback (parameters->file,
- parameters);
- } else {
- if (!parameters->cancelled) {
- stop_activate (parameters);
+ parameters->mount_success &= succeeded;
- eel_show_error_dialog_with_details (error, NULL,
- _("Mount Error"),
- detailed_error,
- NULL);
- }
-
- nautilus_file_unref (parameters->file);
-
+ if (!succeeded) {
+ eel_show_error_dialog_with_details (error, NULL,
+ _("Mount Error"),
+ detailed_error,
+ NULL);
+ }
+
+ if (--parameters->pending_mounts > 0) {
+ /* wait for other mounts to finish... */
+ return;
+ }
+
+ if (parameters->cancelled || !parameters->mount_success) {
+ stop_activate (parameters);
+
+ nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
+ nautilus_file_list_free (parameters->files);
g_free (parameters);
+ return;
}
+
+ /* all drives were mounted successfully */
+ activate_activation_uris_ready_callback (parameters->files,
+ parameters);
}
+static void
+mount_foreach (gpointer drive,
+ gpointer callback_data)
+{
+ gnome_vfs_drive_mount (drive, activation_drive_mounted_callback, callback_data);
+}
static void
-activate_activation_uri_ready_callback (NautilusFile *file, gpointer callback_data)
+activate_activation_uris_ready_callback (GList *files,
+ gpointer callback_data)
{
ActivateParameters *parameters;
+ GList *not_yet_mounted;
+ GList *l;
+ NautilusFile *file;
NautilusFile *actual_file;
NautilusFileAttributes attributes;
GnomeVFSDrive *drive;
char *uri;
parameters = callback_data;
+ not_yet_mounted = NULL;
+
+ /* we can safely unref them here, since the files
+ * list also holds a reference */
+ nautilus_file_list_free (parameters->files);
+ parameters->files = NULL;
+
+ for (l = files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
+ if (nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
+ continue;
+ }
+
+ if (nautilus_file_is_broken_symbolic_link (file)) {
+ report_broken_symbolic_link (parameters->view, file);
+ continue;
+ }
+
+ parameters->files = g_list_prepend (parameters->files, nautilus_file_ref (file));
+
+ if (!parameters->mount_success && nautilus_file_has_drive (file)) {
+ drive = nautilus_file_get_drive (file);
+ if (drive != NULL &&
+ !gnome_vfs_drive_is_mounted (drive)) {
+ not_yet_mounted = g_list_prepend (not_yet_mounted, drive);
+ parameters->pending_mounts++;
+ }
+ }
+ }
+
+ parameters->files = g_list_reverse (parameters->files);
+
+ if (parameters->files == NULL) {
+ g_assert (not_yet_mounted == NULL);
- if (nautilus_file_is_broken_symbolic_link (file)) {
stop_activate (parameters);
- report_broken_symbolic_link (parameters->view, file);
- nautilus_file_unref (parameters->file);
+ nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
g_free (parameters);
+ g_list_free (not_yet_mounted);
return;
}
- if (nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
- stop_activate (parameters);
- nautilus_file_unref (parameters->file);
- g_free (parameters);
+ if (not_yet_mounted != NULL) {
+ not_yet_mounted = g_list_reverse (not_yet_mounted);
+ g_list_foreach (not_yet_mounted, mount_foreach, callback_data);
+ g_list_free (not_yet_mounted);
+
+ /* activation_drive_mounted_callback will reveal whether all mounts were successful */
+ parameters->mount_success = TRUE;
return;
}
- if (!parameters->mounted && nautilus_file_has_drive (file)) {
- drive = nautilus_file_get_drive (file);
- if (drive != NULL &&
- !gnome_vfs_drive_is_mounted (drive)) {
- parameters->mounting = TRUE;
- gnome_vfs_drive_mount (drive, activation_drive_mounted_callback, callback_data);
- return;
+ for (l = parameters->files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+
+ /* We want the file for the activation URI since we care
+ * about the attributes for that, not for the original file.
+ */
+ actual_file = NULL;
+ uri = nautilus_file_get_activation_uri (file);
+ if (!(eel_str_has_prefix (uri, NAUTILUS_DESKTOP_COMMAND_SPECIFIER) ||
+ eel_str_has_prefix (uri, NAUTILUS_COMMAND_SPECIFIER))) {
+ actual_file = nautilus_file_get (uri);
+ }
+ g_free (uri);
+
+ if (actual_file != NULL) {
+ nautilus_file_unref (file);
+ l->data = actual_file;
}
- }
-
- /* We want the file for the activation URI since we care
- * about the attributes for that, not for the original file.
- */
- actual_file = NULL;
- uri = nautilus_file_get_activation_uri (file);
- if (!(eel_str_has_prefix (uri, NAUTILUS_DESKTOP_COMMAND_SPECIFIER) ||
- eel_str_has_prefix (uri, NAUTILUS_COMMAND_SPECIFIER))) {
- actual_file = nautilus_file_get (uri);
- nautilus_file_unref (file);
- }
- g_free (uri);
-
- if (actual_file == NULL) {
- actual_file = file;
}
/* get the parameters for the actual file */
@@ -7576,14 +7713,11 @@ activate_activation_uri_ready_callback (
NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE |
NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI;
- parameters->file = actual_file;
parameters->callback = activate_callback;
-
- nautilus_file_call_when_ready
- (actual_file, attributes, activate_callback, parameters);
+ parameters->files_handle = nautilus_file_list_call_when_ready
+ (parameters->files, attributes, activate_callback, parameters);
}
-
/**
* fm_directory_view_activate_file:
*
@@ -7600,21 +7734,55 @@ fm_directory_view_activate_file (FMDirec
NautilusWindowOpenMode mode,
NautilusWindowOpenFlags flags)
{
+ GList *files;
+
+ g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
+ g_return_if_fail (NAUTILUS_IS_FILE (file));
+
+ files = g_list_prepend (NULL, file);
+ fm_directory_view_activate_files (view, files, mode, flags);
+ g_list_free (files);
+}
+
+
+/**
+ * fm_directory_view_activate_files:
+ *
+ * Activate a list of files. Each one might launch with an application or
+ * with a component. This is normally called only by subclasses.
+ * @view: FMDirectoryView in question.
+ * @files: A GList of NautilusFiles to activate.
+ *
+ **/
+void
+fm_directory_view_activate_files (FMDirectoryView *view,
+ GList *files,
+ NautilusWindowOpenMode mode,
+ NautilusWindowOpenFlags flags)
+{
+
+ GList *l;
ActivateParameters *parameters;
+ NautilusFile *file;
NautilusFileAttributes attributes;
char *file_name;
char *timed_wait_prompt;
+ int file_count;
g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
- g_return_if_fail (NAUTILUS_IS_FILE (file));
+ g_return_if_fail (files != NULL);
+
+ file_count = g_list_length (files);
/* link target info might be stale, re-read it */
- if (nautilus_file_is_symbolic_link (file)) {
- nautilus_file_invalidate_attributes
- (file, NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI);
- }
+ for (l = files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
- nautilus_file_ref (file);
+ if (nautilus_file_is_symbolic_link (file)) {
+ nautilus_file_invalidate_attributes
+ (file, NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI);
+ }
+ }
/* Might have to read some of the file to activate it. */
attributes = NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI |
@@ -7622,17 +7790,24 @@ fm_directory_view_activate_file (FMDirec
parameters = g_new (ActivateParameters, 1);
parameters->view = view;
- parameters->file = file;
+ parameters->files = nautilus_file_list_copy (files);
parameters->mode = mode;
parameters->flags = flags;
- parameters->callback = activate_activation_uri_ready_callback;
- parameters->mounted = FALSE;
- parameters->mounting = FALSE;
+ parameters->callback = activate_activation_uris_ready_callback;
+ parameters->mount_success = FALSE;
+ parameters->pending_mounts = 0;
parameters->cancelled = FALSE;
- file_name = nautilus_file_get_display_name (file);
- timed_wait_prompt = g_strdup_printf (_("Opening \"%s\"."), file_name);
- g_free (file_name);
+ if (file_count == 1) {
+ file_name = nautilus_file_get_display_name (files->data);
+ timed_wait_prompt = g_strdup_printf ("Opening \"%s\".", file_name);
+ g_free (file_name);
+ } else {
+ timed_wait_prompt = g_strdup_printf (ngettext ("Opening %d item.",
+ "Opening %d items.",
+ file_count),
+ file_count);
+ }
eel_timed_wait_start_with_duration
(DELAY_UNTIL_CANCEL_MSECS,
@@ -7645,56 +7820,8 @@ fm_directory_view_activate_file (FMDirec
g_object_weak_ref (G_OBJECT (view), activate_weak_notify, parameters);
- nautilus_file_call_when_ready
- (file, attributes, activate_activation_uri_ready_callback, parameters);
-}
-
-
-/**
- * fm_directory_view_activate_files:
- *
- * Activate a list of files. Each one might launch with an application or
- * with a component. This is normally called only by subclasses.
- * @view: FMDirectoryView in question.
- * @files: A GList of NautilusFiles to activate.
- *
- **/
-void
-fm_directory_view_activate_files (FMDirectoryView *view,
- GList *files,
- NautilusWindowOpenMode mode,
- NautilusWindowOpenFlags flags)
-{
- GList *node;
- int file_count;
- gboolean use_new_window;
-
- g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
-
- /* If there's a single file to activate, check user's preference whether
- * to open it in this window or a new window. If there is more than one
- * file to activate, open each one in a new window. Don't try to choose
- * one special one to replace the current window's contents; we tried this
- * but it proved mysterious in practice.
- */
- file_count = g_list_length (files);
- use_new_window = file_count > 1;
-
- if (use_new_window && mode == NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE) {
-#if !NEW_UI_COMPLETE
- /* Match the current window type */
- mode = NAUTILUS_WINDOW_OPEN_IN_SPATIAL;
-#endif
- }
-
- if (!use_new_window || fm_directory_view_confirm_multiple_windows (view, file_count)) {
- for (node = files; node != NULL; node = node->next) {
- /* The ui should ask for navigation or object windows
- * depending on what the current one is */
- fm_directory_view_activate_file
- (view, node->data, mode, flags);
- }
- }
+ parameters->files_handle = nautilus_file_list_call_when_ready
+ (parameters->files, attributes, activate_activation_uris_ready_callback, parameters);
}
static void
Attachment:
signature.asc
Description: This is a digitally signed message part