Since Alex really did a nice job with cleaning up my last patch, we're now ready for step 2: Implement actual multi-file activation. Proposed patch attached. I've optimized the intersection of the application handler lists for multiple files, using a Merge Sort-like algorithm. What probably still leaves much to desire is the performance for many files with the same MIME type and many handlers, since we don't yet peek what MIME types were already seen. A simple hash table should help here, I'll provide another patch for that later. -- Christian Neumair <chris gnome-de org>
Index: libnautilus-private/nautilus-mime-actions.c =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-mime-actions.c,v retrieving revision 1.119 diff -u -p -r1.119 nautilus-mime-actions.c --- libnautilus-private/nautilus-mime-actions.c 26 Oct 2005 09:04:40 -0000 1.119 +++ libnautilus-private/nautilus-mime-actions.c 25 Nov 2005 15:29:16 -0000 @@ -233,3 +233,154 @@ nautilus_mime_has_any_applications_for_f return result; } + +GnomeVFSMimeApplication * +nautilus_mime_get_default_application_for_files (GList *files) +{ + GList *l; + NautilusFile *file; + GnomeVFSMimeApplication *app, *one_app; + + g_assert (files != NULL); + + app = NULL; + for (l = files; l != NULL; l = l->next) { + file = l->data; + + one_app = nautilus_mime_get_default_application_for_file (file); + if (one_app == NULL || (app != NULL && !gnome_vfs_mime_application_equal (app, one_app))) { + gnome_vfs_mime_application_free (app); + gnome_vfs_mime_application_free (one_app); + app = NULL; + break; + } + + if (app == NULL) { + app = one_app; + } else { + gnome_vfs_mime_application_free (one_app); + } + } + + return app; +} + +/* returns an intersection of two mime application lists, + * and returns a new list, freeing a, b and all applications + * that are not in the intersection set. + * The lists are assumed to be pre-sorted by their IDs */ +static GList * +intersect_application_lists (GList *a, + GList *b) +{ + GList *l, *m; + GList *ret; + GnomeVFSMimeApplication *a_app, *b_app; + int cmp; + + ret = NULL; + + l = a; + m = b; + + while (l != NULL && m != NULL) { + a_app = (GnomeVFSMimeApplication *) l->data; + b_app = (GnomeVFSMimeApplication *) m->data; + + cmp = strcmp (a_app->id, b_app->id); + if (cmp > 0) { + gnome_vfs_mime_application_free (b_app); + m = m->next; + } else if (cmp < 0) { + gnome_vfs_mime_application_free (a_app); + l = l->next; + } else { + gnome_vfs_mime_application_free (b_app); + ret = g_list_prepend (ret, a_app); + l = l->next; + m = m->next; + } + } + + g_list_foreach (l, (GFunc) gnome_vfs_mime_application_free, NULL); + g_list_foreach (m, (GFunc) gnome_vfs_mime_application_free, NULL); + + g_list_free (a); + g_list_free (b); + + return g_list_reverse (ret); +} + +GList * +nautilus_mime_get_open_with_applications_for_files (GList *files) +{ + GList *l; + NautilusFile *file; + GList *one_ret, *ret; + + g_assert (files != NULL); + + ret = NULL; + for (l = files; l != NULL; l = l->next) { + file = l->data; + + one_ret = nautilus_mime_get_open_with_applications_for_file (file); + if (ret != NULL) { + ret = intersect_application_lists (ret, one_ret); + } else { + ret = one_ret; + } + + if (ret == NULL) { + break; + } + } + + return ret; +} + +GList * +nautilus_mime_get_applications_for_files (GList *files) +{ + GList *l; + NautilusFile *file; + GList *one_ret, *ret; + + g_assert (files != NULL); + + ret = NULL; + for (l = files; l != NULL; l = l->next) { + file = l->data; + + one_ret = nautilus_mime_get_applications_for_file (file); + if (ret != NULL) { + ret = intersect_application_lists (ret, one_ret); + } else { + ret = one_ret; + } + + if (ret == NULL) { + break; + } + } + + return ret; +} + +gboolean +nautilus_mime_has_any_applications_for_files (GList *files) +{ + GList *l; + NautilusFile *file; + + g_assert (files != NULL); + + for (l = files; l != NULL; l = l->next) { + file = NAUTILUS_FILE (l->data); + if (!nautilus_mime_has_any_applications_for_file (file)) { + return FALSE; + } + } + + return TRUE; +} Index: libnautilus-private/nautilus-mime-actions.h =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-mime-actions.h,v retrieving revision 1.33 diff -u -p -r1.33 nautilus-mime-actions.h --- libnautilus-private/nautilus-mime-actions.h 25 Nov 2004 14:13:37 -0000 1.33 +++ libnautilus-private/nautilus-mime-actions.h 25 Nov 2005 15:29:16 -0000 @@ -36,6 +36,11 @@ GnomeVFSMimeApplication *nautilus_mime_g GList * nautilus_mime_get_open_with_applications_for_file (NautilusFile *file); GList * nautilus_mime_get_applications_for_file (NautilusFile *file); +GnomeVFSMimeApplication *nautilus_mime_get_default_application_for_files (GList *files); +GList * nautilus_mime_get_open_with_applications_for_files (GList *files); +GList * nautilus_mime_get_applications_for_files (GList *file); + gboolean nautilus_mime_has_any_applications_for_file (NautilusFile *file); +gboolean nautilus_mime_has_any_applications_for_files (GList *files); #endif /* NAUTILUS_MIME_ACTIONS_H */ Index: libnautilus-private/nautilus-program-choosing.c =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-program-choosing.c,v retrieving revision 1.80 diff -u -p -r1.80 nautilus-program-choosing.c --- libnautilus-private/nautilus-program-choosing.c 20 Oct 2005 15:30:42 -0000 1.80 +++ libnautilus-private/nautilus-program-choosing.c 25 Nov 2005 15:29:16 -0000 @@ -665,18 +665,19 @@ void nautilus_launch_show_file (Nautilus * parameter. Provide a parent window for error dialogs. * * @application: The application to be launched. - * @file: The file whose location should be passed as a parameter to the application + * @files: The files whose locations should be passed as a parameter to the application. * @parent_window: A window to use as the parent for any error dialogs. */ void nautilus_launch_application (GnomeVFSMimeApplication *application, - NautilusFile *file, + GList *files, GtkWindow *parent_window) { GdkScreen *screen; char *uri; char *uri_scheme; - GList uris; + GList *uris, *l; + NautilusFile *file; char **envp; GnomeVFSResult result; #ifdef HAVE_STARTUP_NOTIFICATION @@ -684,19 +685,26 @@ nautilus_launch_application (GnomeVFSMim SnDisplay *sn_display; #endif - uri = NULL; - if (nautilus_file_is_nautilus_link (file)) { - uri = nautilus_file_get_activation_uri (file); - } - - if (uri == NULL) { - uri = nautilus_file_get_uri (file); + g_assert (files != NULL); + + uris = NULL; + for (l = files; l != NULL; l = l->next) { + file = NAUTILUS_FILE (l->data); + + uri = NULL; + + if (nautilus_file_is_nautilus_link (file)) { + uri = nautilus_file_get_activation_uri (file); + } + + if (uri == NULL) { + uri = nautilus_file_get_uri (file); + } + + uris = g_list_prepend (uris, uri); } + uris = g_list_reverse (uris); - uris.next = NULL; - uris.prev = NULL; - uris.data = uri; - screen = gtk_window_get_screen (parent_window); envp = my_gdk_spawn_make_environment_for_screen (screen, NULL); @@ -710,27 +718,44 @@ nautilus_launch_application (GnomeVFSMim if (gnome_vfs_mime_application_supports_startup_notification (application)) { char *name; + char *description; char *icon; + int files_count; + + file = NAUTILUS_FILE (files->data); sn_context = sn_launcher_context_new (sn_display, screen ? gdk_screen_get_number (screen) : DefaultScreen (gdk_display)); - - name = nautilus_file_get_display_name (file); - if (name != NULL) { - char *description; - - sn_launcher_context_set_name (sn_context, name); - + + files_count = g_list_length (files); + if (files_count == 1) { + name = nautilus_file_get_display_name (file); description = g_strdup_printf (_("Opening %s"), name); - - sn_launcher_context_set_description (sn_context, description); + } else { + name = NULL; + description = g_strdup_printf (ngettext ("Opening %d Item", + "Opening %d Items", + files_count), + files_count); + } + if (name != NULL) { + sn_launcher_context_set_name (sn_context, name); g_free (name); + } + + if (description != NULL) { + sn_launcher_context_set_description (sn_context, description); g_free (description); } icon = nautilus_icon_factory_get_icon_for_file (file, FALSE); + + if (icon == NULL) { + icon = g_strdup (gnome_vfs_mime_application_get_icon (application)); + } + if (icon != NULL) { sn_launcher_context_set_icon_name (sn_context, icon); g_free (icon); @@ -762,7 +787,7 @@ nautilus_launch_application (GnomeVFSMim } #endif /* HAVE_STARTUP_NOTIFICATION */ - result = gnome_vfs_mime_application_launch_with_env (application, &uris, envp); + result = gnome_vfs_mime_application_launch_with_env (application, uris, envp); #ifdef HAVE_STARTUP_NOTIFICATION if (sn_context != NULL) { @@ -784,7 +809,7 @@ nautilus_launch_application (GnomeVFSMim break; case GNOME_VFS_ERROR_NOT_SUPPORTED: - uri_scheme = nautilus_file_get_uri_scheme (file); + uri_scheme = nautilus_file_get_uri_scheme (NAUTILUS_FILE (files->data)); application_cannot_open_location (application, file, uri_scheme, @@ -801,8 +826,8 @@ nautilus_launch_application (GnomeVFSMim #endif break; } - - g_free (uri); + + eel_g_list_free_deep (uris); g_strfreev (envp); } Index: libnautilus-private/nautilus-program-choosing.h =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-program-choosing.h,v retrieving revision 1.19 diff -u -p -r1.19 nautilus-program-choosing.h --- libnautilus-private/nautilus-program-choosing.h 22 Nov 2004 15:24:36 -0000 1.19 +++ libnautilus-private/nautilus-program-choosing.h 25 Nov 2005 15:29:17 -0000 @@ -37,7 +37,7 @@ typedef void (*NautilusApplicationChoice gpointer callback_data); void nautilus_launch_application (GnomeVFSMimeApplication *application, - NautilusFile *file, + GList *files, GtkWindow *parent_window); void nautilus_launch_application_from_command (GdkScreen *screen, const char *name, Index: src/nautilus-information-panel.c =================================================================== RCS file: /cvs/gnome/nautilus/src/nautilus-information-panel.c,v retrieving revision 1.231 diff -u -p -r1.231 nautilus-information-panel.c --- src/nautilus-information-panel.c 15 Jul 2005 13:47:53 -0000 1.231 +++ src/nautilus-information-panel.c 25 Nov 2005 15:29:18 -0000 @@ -855,13 +855,17 @@ command_button_callback (GtkWidget *butt { NautilusInformationPanel *information_panel; GnomeVFSMimeApplication *application; + GList files; information_panel = NAUTILUS_INFORMATION_PANEL (g_object_get_data (G_OBJECT (button), "user_data")); application = gnome_vfs_mime_application_new_from_desktop_id (id_str); if (application != NULL) { - nautilus_launch_application (application, information_panel->details->file, + files.next = NULL; + files.prev = NULL; + files.data = information_panel->details->file; + nautilus_launch_application (application, &files, nautilus_information_panel_get_window (information_panel)); gnome_vfs_mime_application_free (application); Index: src/file-manager/fm-directory-view.c =================================================================== RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.c,v retrieving revision 1.722 diff -u -p -r1.722 fm-directory-view.c --- src/file-manager/fm-directory-view.c 24 Nov 2005 20:47:59 -0000 1.722 +++ src/file-manager/fm-directory-view.c 25 Nov 2005 15:29:25 -0000 @@ -420,7 +420,7 @@ EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_d typedef struct { GnomeVFSMimeApplication *application; - NautilusFile *file; + GList *files; FMDirectoryView *directory_view; } ApplicationLaunchParameters; @@ -437,17 +437,19 @@ typedef struct { static ApplicationLaunchParameters * application_launch_parameters_new (GnomeVFSMimeApplication *application, - NautilusFile *file, + GList *files, FMDirectoryView *directory_view) { ApplicationLaunchParameters *result; result = g_new0 (ApplicationLaunchParameters, 1); result->application = gnome_vfs_mime_application_copy (application); - g_object_ref (directory_view); - result->directory_view = directory_view; - nautilus_file_ref (file); - result->file = file; + result->files = nautilus_file_list_copy (files); + + if (directory_view != NULL) { + g_object_ref (directory_view); + result->directory_view = directory_view; + } return result; } @@ -456,8 +458,12 @@ static void application_launch_parameters_free (ApplicationLaunchParameters *parameters) { gnome_vfs_mime_application_free (parameters->application); - g_object_unref (parameters->directory_view); - nautilus_file_unref (parameters->file); + nautilus_file_list_free (parameters->files); + + if (parameters->directory_view != NULL) { + g_object_unref (parameters->directory_view); + } + g_free (parameters); } @@ -655,31 +661,37 @@ action_open_alternate_callback (GtkActio static void fm_directory_view_launch_application (GnomeVFSMimeApplication *application, - NautilusFile *file, + GList *files, FMDirectoryView *directory_view) { char *uri; GnomeVFSURI *vfs_uri; + NautilusFile *file; + GList *l; g_assert (application != NULL); - g_assert (NAUTILUS_IS_FILE (file)); + g_assert (NAUTILUS_IS_FILE (files->data)); g_assert (FM_IS_DIRECTORY_VIEW (directory_view)); nautilus_launch_application - (application, file, + (application, files, fm_directory_view_get_containing_window (directory_view)); - uri = nautilus_file_get_uri (file); + for (l = files; l != NULL; l = l->next) { + file = NAUTILUS_FILE (l->data); - /* Only add real gnome-vfs uris to recent. Not things like - trash:// and x-nautilus-desktop:// */ - vfs_uri = gnome_vfs_uri_new (uri); - if (vfs_uri != NULL) { - egg_recent_model_add (nautilus_recent_get_model (), uri); - gnome_vfs_uri_unref (vfs_uri); - } + uri = nautilus_file_get_uri (file); - g_free (uri); + /* Only add real gnome-vfs uris to recent. Not things like + trash:// and x-nautilus-desktop:// */ + vfs_uri = gnome_vfs_uri_new (uri); + if (vfs_uri != NULL) { + egg_recent_model_add (nautilus_recent_get_model (), uri); + gnome_vfs_uri_unref (vfs_uri); + } + + g_free (uri); + } } #if NEW_MIME_COMPLETE @@ -697,7 +709,7 @@ fm_directory_view_chose_application_call if (application != NULL) { fm_directory_view_launch_application (application, /* NOT the (empty) application in launch_parameters */ - launch_parameters->file, + launch_parameters->files, launch_parameters->directory_view); } @@ -738,12 +750,16 @@ application_selected_cb (EelOpenWithDial { FMDirectoryView *view; NautilusFile *file; + GList uri; view = FM_DIRECTORY_VIEW (user_data); file = g_object_get_data (G_OBJECT (dialog), "directory-view:file"); - fm_directory_view_launch_application (app, file, view); + uri.next = NULL; + uri.prev = NULL; + uri.data = file; + fm_directory_view_launch_application (app, &uri, view); } static void @@ -3877,7 +3893,7 @@ open_with_launch_application_callback (G launch_parameters = (ApplicationLaunchParameters *) callback_data; fm_directory_view_launch_application (launch_parameters->application, - launch_parameters->file, + launch_parameters->files, launch_parameters->directory_view); } @@ -4000,7 +4016,7 @@ add_submenu (GtkUIManager *ui_manager, static void add_application_to_open_with_menu (FMDirectoryView *view, GnomeVFSMimeApplication *application, - NautilusFile *file, + GList *files, int index, const char *menu_placeholder, const char *popup_placeholder) @@ -4013,10 +4029,13 @@ add_application_to_open_with_menu (FMDir GtkAction *action; launch_parameters = application_launch_parameters_new - (application, file, view); + (application, files, view); escaped_app = eel_str_double_underscores (application->name); label = g_strdup_printf (_("Open with \"%s\""), escaped_app); - tip = g_strdup_printf (_("Use \"%s\" to open the selected item"), escaped_app); + tip = g_strdup_printf (ngettext ("Use \"%s\" to open the selected item", + "Use \"%s\" to open the selected items", + g_list_length (files)), + escaped_app); g_free (escaped_app); action_name = g_strdup_printf ("open_with_%d", index); @@ -4196,14 +4215,15 @@ reset_open_with_menu (FMDirectoryView *v { GList *applications, *node; NautilusFile *file; - gboolean submenu_visible; - char *uri; + gboolean submenu_visible, filter_default; int num_applications; int index; gboolean other_applications_visible; GtkUIManager *ui_manager; GtkAction *action; - + GnomeVFSMimeApplication *default_app; + ActivationAction activation_action; + /* Clear any previous inserted items in the applications and viewers placeholders */ ui_manager = nautilus_window_info_get_ui_manager (view->details->window); @@ -4218,79 +4238,80 @@ reset_open_with_menu (FMDirectoryView *v num_applications = 0; - /* This menu is only displayed when there's one selected item. */ - if (!eel_g_list_exactly_one_item (selection)) { - submenu_visible = FALSE; - other_applications_visible = FALSE; - } else { - GnomeVFSMimeApplication *default_app; - ActivationAction action; - - file = NAUTILUS_FILE (selection->data); - - uri = nautilus_file_get_uri (file); + other_applications_visible = (selection != NULL); + filter_default = (selection != NULL); - other_applications_visible = - !can_use_component_for_file (file) || - nautilus_file_is_directory (file); + for (node = selection; node != NULL; node = node->next) { + file = NAUTILUS_FILE (node->data); + + other_applications_visible &= + (!can_use_component_for_file (file) || + nautilus_file_is_directory (file)); + + activation_action = get_activation_action (file); - action = get_activation_action (file); /* Only use the default app for open if there is not a mime mismatch, otherwise we can't use it in the open with menu */ - if (action == ACTIVATION_ACTION_OPEN_IN_APPLICATION && - can_show_default_app (view, file)) { - default_app = nautilus_mime_get_default_application_for_file (file); - } else { - default_app = NULL; + if (activation_action == ACTIVATION_ACTION_OPEN_IN_APPLICATION && + !can_show_default_app (view, file)) { + filter_default = TRUE; } - - applications = NULL; - if (other_applications_visible) { - applications = nautilus_mime_get_open_with_applications_for_file (NAUTILUS_FILE (selection->data)); + + if (filter_default && !other_applications_visible) { + break; } + } - num_applications = g_list_length (applications); - - for (node = applications, index = 0; node != NULL; node = node->next, index++) { - GnomeVFSMimeApplication *application; - char *menu_path; - char *popup_path; - - application = node->data; + default_app = NULL; + if (filter_default) { + default_app = nautilus_mime_get_default_application_for_files (selection); + } - if (default_app && gnome_vfs_mime_application_equal (default_app, application)) { - continue; - } + applications = NULL; + if (other_applications_visible) { + applications = nautilus_mime_get_open_with_applications_for_files (selection); + } - if (num_applications > 3) { - menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; - popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; - } else { - menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER; - popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER; - } + num_applications = g_list_length (applications); + + for (node = applications, index = 0; node != NULL; node = node->next, index++) { + GnomeVFSMimeApplication *application; + char *menu_path; + char *popup_path; + + application = node->data; - gtk_ui_manager_add_ui (nautilus_window_info_get_ui_manager (view->details->window), - view->details->open_with_merge_id, - menu_path, - "separator", - NULL, - GTK_UI_MANAGER_SEPARATOR, - FALSE); - - add_application_to_open_with_menu (view, - node->data, - file, - index, - menu_path, popup_path); + if (default_app != NULL && gnome_vfs_mime_application_equal (default_app, application)) { + continue; } - gnome_vfs_mime_application_list_free (applications); - gnome_vfs_mime_application_free (default_app); - g_free (uri); - submenu_visible = (num_applications > 3); + if (num_applications > 3) { + menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; + popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; + } else { + menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER; + popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER; + } + + gtk_ui_manager_add_ui (nautilus_window_info_get_ui_manager (view->details->window), + view->details->open_with_merge_id, + menu_path, + "separator", + NULL, + GTK_UI_MANAGER_SEPARATOR, + FALSE); + + add_application_to_open_with_menu (view, + node->data, + selection, + index, + menu_path, popup_path); } + gnome_vfs_mime_application_list_free (applications); + gnome_vfs_mime_application_free (default_app); + + submenu_visible = (num_applications > 3); if (submenu_visible) { action = gtk_action_group_get_action (view->details->dir_action_group, @@ -6833,7 +6854,7 @@ clipboard_changed_callback (NautilusClip static void real_update_menus (FMDirectoryView *view) { - GList *selection; + GList *selection, *l; gint selection_count; const char *tip, *label; char *label_with_underscore; @@ -6848,9 +6869,10 @@ real_update_menus (FMDirectoryView *view gboolean show_separate_delete_command; gboolean vfolder_directory; gboolean show_open_alternate; - gboolean can_open; + gboolean can_open, show_app; ActivationAction activation_action; GtkAction *action; + GnomeVFSMimeApplication *app; selection = fm_directory_view_get_selection (view); selection_count = g_list_length (selection); @@ -6884,13 +6906,13 @@ real_update_menus (FMDirectoryView *view action = gtk_action_group_get_action (view->details->dir_action_group, FM_ACTION_OPEN); - gtk_action_set_sensitive (action, selection_count != 0); + gtk_action_set_sensitive (action, selection_count != 0); - label_with_underscore = NULL; - can_open = TRUE; - if (selection_count == 1) { + can_open = show_app = selection_count != 0; + + for (l = selection; l != NULL; l = l->next) { NautilusFile *file; - + file = NAUTILUS_FILE (selection->data); activation_action = get_activation_action (file); @@ -6899,23 +6921,35 @@ real_update_menus (FMDirectoryView *view a mime mismatch, otherwise we can't use it in the open with menu */ if (activation_action == ACTIVATION_ACTION_OPEN_IN_APPLICATION && - can_show_default_app (view, file)) { - GnomeVFSMimeApplication *app; + !can_show_default_app (view, file)) { + can_open = FALSE; + } - app = nautilus_mime_get_default_application_for_file (file); - if (app) { - char *escaped_app; - escaped_app = eel_str_double_underscores (app->name); - label_with_underscore = g_strdup_printf (_("_Open with \"%s\""), - escaped_app); - g_free (escaped_app); - gnome_vfs_mime_application_free (app); - } else { - can_open = FALSE; - } + if (activation_action != ACTIVATION_ACTION_OPEN_IN_APPLICATION) { + show_app = FALSE; + } + + if (!can_open && !show_app) { + break; } } + label_with_underscore = NULL; + + app = NULL; + if (can_open && show_app) { + app = nautilus_mime_get_default_application_for_files (selection); + } + + if (app != NULL) { + char *escaped_app; + escaped_app = eel_str_double_underscores (app->name); + label_with_underscore = g_strdup_printf (_("_Open with \"%s\""), + escaped_app); + g_free (escaped_app); + gnome_vfs_mime_application_free (app); + } + g_object_set (action, "label", label_with_underscore ? label_with_underscore : _("_Open"), NULL); @@ -7386,6 +7420,93 @@ stop_activate (ActivateParameters *param } static void +list_to_parameters_foreach (GnomeVFSMimeApplication *application, + GList *files, + GList **ret) +{ + ApplicationLaunchParameters *parameters; + + files = g_list_reverse (files); + + parameters = application_launch_parameters_new + (application, files, NULL); + *ret = g_list_prepend (*ret, parameters); +} + +static unsigned int +mime_application_hash (GnomeVFSMimeApplication *app) +{ + return g_str_hash (app->id); +} + +/** + * fm_directory_view_make_activation_parameters + * + * Construct a list of ApplicationLaunchParameters from a list of NautilusFiles, + * where files that have the same default application are put into the same + * launch parameter, and others are put into the unhandled_files list. + * + * @files: Files to use for construction. + * @unhandled_files: Files without any default application will be put here. + * + * Return value: Newly allocated list of ApplicationLaunchParameters. + **/ +static GList * +fm_directory_view_make_activation_parameters (GList *files, + GList **unhandled_files) +{ + GList *ret, *l, *app_files; + NautilusFile *file; + GnomeVFSMimeApplication *app, *old_app; + GHashTable *app_table; + + ret = NULL; + *unhandled_files = NULL; + + app_table = g_hash_table_new_full + ((GHashFunc) mime_application_hash, + (GEqualFunc) gnome_vfs_mime_application_equal, + (GDestroyNotify) gnome_vfs_mime_application_free, + (GDestroyNotify) g_list_free); + + for (l = files; l != NULL; l = l->next) { + file = NAUTILUS_FILE (l->data); + + app = nautilus_mime_get_default_application_for_file (file); + if (app != NULL) { + app_files = NULL; + + if (g_hash_table_lookup_extended (app_table, app, + (gpointer *) &old_app, + (gpointer *) &app_files)) { + g_assert (g_hash_table_steal (app_table, old_app)); + + app_files = g_list_prepend (app_files, file); + + gnome_vfs_mime_application_free (app); + app = old_app; + } else { + app_files = g_list_prepend (NULL, file); + } + + g_hash_table_insert (app_table, app, app_files); + } else { + *unhandled_files = g_list_prepend (*unhandled_files, file); + } + } + + g_hash_table_foreach (app_table, + (GHFunc) list_to_parameters_foreach, + &ret); + + g_hash_table_destroy (app_table); + + *unhandled_files = g_list_reverse (*unhandled_files); + + return g_list_reverse (ret); +} + +static void activate_callback (GList *files, gpointer callback_data) { ActivateParameters *parameters; @@ -7396,6 +7517,9 @@ activate_callback (GList *files, gpointe GList *launch_files; GList *launch_in_terminal_files; GList *open_in_app_files; + GList *open_in_app_parameters; + GList *unhandled_open_in_app_files; + ApplicationLaunchParameters *one_parameters; GList *open_in_view_files; GList *l; int count; @@ -7548,19 +7672,40 @@ activate_callback (GList *files, gpointe } } - open_in_app_files = g_list_reverse (open_in_app_files); - for (l = open_in_app_files; l != NULL; l = l->next) { + open_in_app_parameters = NULL; + unhandled_open_in_app_files = NULL; + + if (open_in_app_files != NULL) { + open_in_app_files = g_list_reverse (open_in_app_files); + + open_in_app_parameters = fm_directory_view_make_activation_parameters + (open_in_app_files, &unhandled_open_in_app_files); + } + + if (open_in_app_parameters != NULL || + unhandled_open_in_app_files != NULL) { + if ((parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0 && + nautilus_window_info_get_window_type (view->details->window) == NAUTILUS_WINDOW_SPATIAL) { + nautilus_window_info_close (view->details->window); + } + } + + for (l = open_in_app_parameters; l != NULL; l = l->next) { + one_parameters = l->data; + + fm_directory_view_launch_application ( + one_parameters->application, + one_parameters->files, + view); + application_launch_parameters_free (one_parameters); + } + + for (l = unhandled_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); - } - } - /* We should not add trash and directory uris.*/ if ((!nautilus_file_is_in_trash (file)) && (!nautilus_file_is_directory (file))) { @@ -7576,6 +7721,8 @@ activate_callback (GList *files, gpointe g_list_free (launch_in_terminal_files); g_list_free (open_in_view_files); g_list_free (open_in_app_files); + g_list_free (open_in_app_parameters); + g_list_free (unhandled_open_in_app_files); nautilus_file_list_free (parameters->files); g_free (parameters);
Attachment:
signature.asc
Description: This is a digitally signed message part