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