diff --git a/0001-Revert-mime-actions-launch-default-uri-handlers-when.patch b/0001-Revert-mime-actions-launch-default-uri-handlers-when.patch new file mode 100644 index 0000000..3a9f241 --- /dev/null +++ b/0001-Revert-mime-actions-launch-default-uri-handlers-when.patch @@ -0,0 +1,601 @@ +From 759cbb3a7b6d633b55f367a913c1f7b5abb380bd Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Thu, 6 Feb 2020 15:04:31 +0100 +Subject: [PATCH] Revert "mime-actions: launch default uri handlers when + activating files" + +This reverts commit f5206a6daf0991d91e885a28bb66795a8ae12a41. +--- + src/nautilus-mime-actions.c | 268 +++++++++++++++++++++++--------- + src/nautilus-program-choosing.c | 190 +++------------------- + src/nautilus-program-choosing.h | 7 - + 3 files changed, 211 insertions(+), 254 deletions(-) + +diff --git a/src/nautilus-mime-actions.c b/src/nautilus-mime-actions.c +index 316066d4c..e629e60ee 100644 +--- a/src/nautilus-mime-actions.c ++++ b/src/nautilus-mime-actions.c +@@ -64,6 +64,12 @@ typedef struct + char *uri; + } LaunchLocation; + ++typedef struct ++{ ++ GAppInfo *application; ++ GList *uris; ++} ApplicationLaunchParameters; ++ + typedef struct + { + NautilusWindowSlot *slot; +@@ -83,13 +89,6 @@ typedef struct + gboolean user_confirmation; + } ActivateParameters; + +-typedef struct +-{ +- ActivateParameters *activation_params; +- GQueue *uris; +- GQueue *unhandled_uris; +-} ApplicationLaunchParameters; +- + /* Microsoft mime types at https://blogs.msdn.microsoft.com/vsofficedeveloper/2008/05/08/office-2007-file-format-mime-types-for-http-content-streaming-2/ */ + struct + { +@@ -348,19 +347,27 @@ launch_locations_from_file_list (GList *list) + } + + static ApplicationLaunchParameters * +-application_launch_parameters_new (ActivateParameters *activation_params, +- GQueue *uris) ++application_launch_parameters_new (GAppInfo *application, ++ GList *uris) + { + ApplicationLaunchParameters *result; + + result = g_new0 (ApplicationLaunchParameters, 1); +- result->activation_params = activation_params; +- result->uris = uris; +- result->unhandled_uris = g_queue_new (); ++ result->application = g_object_ref (application); ++ result->uris = g_list_copy_deep (uris, (GCopyFunc) g_strdup, NULL); + + return result; + } + ++static void ++application_launch_parameters_free (ApplicationLaunchParameters *parameters) ++{ ++ g_object_unref (parameters->application); ++ g_list_free_full (parameters->uris, g_free); ++ ++ g_free (parameters); ++} ++ + static gboolean + nautilus_mime_actions_check_if_required_attributes_ready (NautilusFile *file) + { +@@ -794,6 +801,114 @@ nautilus_mime_file_opens_in_external_app (NautilusFile *file) + return (activation_action == ACTIVATION_ACTION_OPEN_IN_APPLICATION); + } + ++ ++static unsigned int ++mime_application_hash (GAppInfo *app) ++{ ++ const char *id; ++ ++ id = g_app_info_get_id (app); ++ ++ if (id == NULL) ++ { ++ return GPOINTER_TO_UINT (app); ++ } ++ ++ return g_str_hash (id); ++} ++ ++static void ++list_to_parameters_foreach (GAppInfo *application, ++ GList *uris, ++ GList **ret) ++{ ++ ApplicationLaunchParameters *parameters; ++ ++ uris = g_list_reverse (uris); ++ ++ parameters = application_launch_parameters_new ++ (application, uris); ++ *ret = g_list_prepend (*ret, parameters); ++} ++ ++ ++/** ++ * 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 * ++make_activation_parameters (GList *uris, ++ GList **unhandled_uris) ++{ ++ GList *ret, *l, *app_uris; ++ NautilusFile *file; ++ GAppInfo *app, *old_app; ++ GHashTable *app_table; ++ char *uri; ++ ++ ret = NULL; ++ *unhandled_uris = NULL; ++ ++ app_table = g_hash_table_new_full ++ ((GHashFunc) mime_application_hash, ++ (GEqualFunc) g_app_info_equal, ++ (GDestroyNotify) g_object_unref, ++ (GDestroyNotify) g_list_free); ++ ++ for (l = uris; l != NULL; l = l->next) ++ { ++ uri = l->data; ++ file = nautilus_file_get_by_uri (uri); ++ ++ app = nautilus_mime_get_default_application_for_file (file); ++ if (app != NULL) ++ { ++ app_uris = NULL; ++ ++ if (g_hash_table_lookup_extended (app_table, app, ++ (gpointer *) &old_app, ++ (gpointer *) &app_uris)) ++ { ++ g_hash_table_steal (app_table, old_app); ++ ++ app_uris = g_list_prepend (app_uris, uri); ++ ++ g_object_unref (app); ++ app = old_app; ++ } ++ else ++ { ++ app_uris = g_list_prepend (NULL, uri); ++ } ++ ++ g_hash_table_insert (app_table, app, app_uris); ++ } ++ else ++ { ++ *unhandled_uris = g_list_prepend (*unhandled_uris, uri); ++ } ++ nautilus_file_unref (file); ++ } ++ ++ g_hash_table_foreach (app_table, ++ (GHFunc) list_to_parameters_foreach, ++ &ret); ++ ++ g_hash_table_destroy (app_table); ++ ++ *unhandled_uris = g_list_reverse (*unhandled_uris); ++ ++ return g_list_reverse (ret); ++} ++ + static gboolean + file_was_cancelled (NautilusFile *file) + { +@@ -845,16 +960,6 @@ activation_parameters_free (ActivateParameters *parameters) + g_free (parameters); + } + +-static void +-application_launch_parameters_free (ApplicationLaunchParameters *parameters) +-{ +- g_queue_free (parameters->unhandled_uris); +- g_queue_free (parameters->uris); +- activation_parameters_free (parameters->activation_params); +- +- g_free (parameters); +-} +- + static void + cancel_activate_callback (gpointer callback_data) + { +@@ -1384,55 +1489,22 @@ out: + show_unhandled_type_error (parameters_install); + } + +-static void +-on_launch_default_for_uri (GObject *source_object, +- GAsyncResult *res, +- gpointer user_data) +-{ +- ApplicationLaunchParameters *params; +- ActivateParameters *activation_params; +- char *uri; +- gboolean sandboxed; +- GError *error = NULL; +- +- params = user_data; +- activation_params = params->activation_params; +- uri = g_queue_pop_head (params->uris); +- sandboxed = g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS); +- +- nautilus_launch_default_for_uri_finish (res, &error); +- if (!sandboxed && error != NULL && error->code != G_IO_ERROR_CANCELLED) +- { +- g_queue_push_tail (params->unhandled_uris, uri); +- } +- +- if (!g_queue_is_empty (params->uris)) +- { +- nautilus_launch_default_for_uri_async (g_queue_peek_head (params->uris), +- activation_params->parent_window, +- activation_params->cancellable, +- on_launch_default_for_uri, +- params); +- } +- else +- { +- while ((uri = g_queue_pop_head (params->unhandled_uris)) != NULL) +- { +- application_unhandled_uri (activation_params, uri); +- } +- +- application_launch_parameters_free (params); +- } +-} +- + static void + activate_files (ActivateParameters *parameters) + { + NautilusFile *file; + NautilusWindowOpenFlags flags; ++ g_autoptr (GList) open_in_app_parameters = NULL; ++ g_autoptr (GList) unhandled_open_in_app_uris = NULL; ++ ApplicationLaunchParameters *one_parameters; + int count; + g_autofree char *old_working_dir = NULL; + GdkScreen *screen; ++ gint num_apps; ++ gint num_unhandled; ++ gint num_files; ++ gboolean open_files; ++ g_autoptr (GQueue) launch_desktop_files = NULL; + g_autoptr (GQueue) launch_files = NULL; + g_autoptr (GQueue) launch_in_terminal_files = NULL; + g_autoptr (GQueue) open_in_app_uris = NULL; +@@ -1627,26 +1699,68 @@ activate_files (ActivateParameters *parameters) + } + } + +- if (g_queue_is_empty (open_in_app_uris)) ++ if (open_in_app_uris != NULL) + { +- activation_parameters_free (parameters); ++ open_in_app_parameters = make_activation_parameters (g_queue_peek_head_link (open_in_app_uris), ++ &unhandled_open_in_app_uris); + } +- else ++ ++ num_apps = g_list_length (open_in_app_parameters); ++ num_unhandled = g_list_length (unhandled_open_in_app_uris); ++ num_files = g_queue_get_length (open_in_app_uris); ++ open_files = TRUE; ++ ++ if (g_queue_is_empty (open_in_app_uris) && ++ (!parameters->user_confirmation || ++ num_files + num_unhandled > SILENT_OPEN_LIMIT) && ++ num_apps > 1) + { +- const char *uri; +- ApplicationLaunchParameters *params; ++ GtkDialog *dialog; ++ char *prompt; ++ g_autofree char *detail = NULL; ++ int response; + +- uri = g_queue_peek_head (open_in_app_uris); +- params = application_launch_parameters_new (parameters, +- g_queue_copy (open_in_app_uris)); ++ pause_activation_timed_cancel (parameters); + +- gtk_recent_manager_add_item (gtk_recent_manager_get_default (), uri); +- nautilus_launch_default_for_uri_async (uri, +- parameters->parent_window, +- parameters->cancellable, +- on_launch_default_for_uri, +- params); ++ prompt = _("Are you sure you want to open all files?"); ++ detail = g_strdup_printf (ngettext ("This will open %d separate application.", ++ "This will open %d separate applications.", num_apps), num_apps); ++ dialog = eel_show_yes_no_dialog (prompt, detail, ++ _("_OK"), _("_Cancel"), ++ parameters->parent_window); ++ response = gtk_dialog_run (dialog); ++ gtk_widget_destroy (GTK_WIDGET (dialog)); ++ ++ unpause_activation_timed_cancel (parameters); ++ ++ if (response != GTK_RESPONSE_YES) ++ { ++ open_files = FALSE; ++ } ++ } ++ ++ if (open_files) ++ { ++ for (l = open_in_app_parameters; l != NULL; l = l->next) ++ { ++ one_parameters = l->data; ++ ++ nautilus_launch_application_by_uri (one_parameters->application, ++ one_parameters->uris, ++ parameters->parent_window); ++ application_launch_parameters_free (one_parameters); ++ } ++ ++ for (l = unhandled_open_in_app_uris; l != NULL; l = l->next) ++ { ++ char *uri = l->data; ++ ++ /* this does not block */ ++ application_unhandled_uri (parameters, uri); ++ } + } ++ ++ activation_parameters_free (parameters); + } + + static void +diff --git a/src/nautilus-program-choosing.c b/src/nautilus-program-choosing.c +index 047a78c2b..0b56c71bf 100644 +--- a/src/nautilus-program-choosing.c ++++ b/src/nautilus-program-choosing.c +@@ -126,32 +126,6 @@ nautilus_launch_application (GAppInfo *application, + g_list_free_full (uris, g_free); + } + +-static GdkAppLaunchContext * +-get_launch_context (GtkWindow *parent_window) +-{ +- GdkDisplay *display; +- GdkAppLaunchContext *launch_context; +- +- if (parent_window != NULL) +- { +- display = gtk_widget_get_display (GTK_WIDGET (parent_window)); +- } +- else +- { +- display = gdk_display_get_default (); +- } +- +- launch_context = gdk_display_get_app_launch_context (display); +- +- if (parent_window != NULL) +- { +- gdk_app_launch_context_set_screen (launch_context, +- gtk_window_get_screen (parent_window)); +- } +- +- return launch_context; +-} +- + void + nautilus_launch_application_by_uri (GAppInfo *application, + GList *uris, +@@ -163,7 +137,8 @@ nautilus_launch_application_by_uri (GAppInfo *application, + NautilusFile *file; + gboolean result; + GError *error; +- g_autoptr (GdkAppLaunchContext) launch_context = NULL; ++ GdkDisplay *display; ++ GdkAppLaunchContext *launch_context; + NautilusIconInfo *icon; + int count, total; + +@@ -186,7 +161,22 @@ nautilus_launch_application_by_uri (GAppInfo *application, + } + locations = g_list_reverse (locations); + +- launch_context = get_launch_context (parent_window); ++ if (parent_window != NULL) ++ { ++ display = gtk_widget_get_display (GTK_WIDGET (parent_window)); ++ } ++ else ++ { ++ display = gdk_display_get_default (); ++ } ++ ++ launch_context = gdk_display_get_app_launch_context (display); ++ ++ if (parent_window != NULL) ++ { ++ gdk_app_launch_context_set_screen (launch_context, ++ gtk_window_get_screen (parent_window)); ++ } + + file = nautilus_file_get_by_uri (uris->data); + icon = nautilus_file_get_icon (file, +@@ -222,6 +212,8 @@ nautilus_launch_application_by_uri (GAppInfo *application, + &error); + } + ++ g_object_unref (launch_context); ++ + if (result) + { + for (l = uris; l != NULL; l = l->next) +@@ -479,145 +471,3 @@ nautilus_launch_desktop_file (GdkScreen *screen, + g_object_unref (context); + g_object_unref (app_info); + } +- +-/* HAX +- * +- * TODO: remove everything below once it’s doable from GTK+. +- * +- * Context: https://bugzilla.gnome.org/show_bug.cgi?id=781132 and +- * https://bugzilla.gnome.org/show_bug.cgi?id=779312 +- * +- * In a sandboxed environment, this is needed to able to get the actual +- * result of the operation, since gtk_show_uri_on_window () neither blocks +- * nor returns a useful value. +- */ +- +-static void +-on_launch_default_for_uri (GObject *source, +- GAsyncResult *result, +- gpointer data) +-{ +- GTask *task; +- NautilusWindow *window; +- gboolean success; +- GError *error = NULL; +- +- task = data; +- window = g_task_get_source_object (task); +- +- success = g_app_info_launch_default_for_uri_finish (result, &error); +- +- if (window) +- { +- nautilus_window_unexport_handle (window); +- } +- +- if (success) +- { +- g_task_return_boolean (task, success); +- } +- else +- { +- g_task_return_error (task, error); +- } +- +- /* Reffed in the call to nautilus_window_export_handle */ +- g_object_unref (task); +-} +- +-static void +-on_window_handle_export (NautilusWindow *window, +- const char *handle_str, +- guint xid, +- gpointer user_data) +-{ +- GTask *task = user_data; +- GAppLaunchContext *context = g_task_get_task_data (task); +- const char *uri; +- +- uri = g_object_get_data (G_OBJECT (context), "uri"); +- +- g_app_launch_context_setenv (context, "PARENT_WINDOW_ID", handle_str); +- +- g_app_info_launch_default_for_uri_async (uri, +- context, +- g_task_get_cancellable (task), +- on_launch_default_for_uri, +- task); +-} +- +-static void +-launch_default_for_uri_thread_func (GTask *task, +- gpointer source_object, +- gpointer task_data, +- GCancellable *cancellable) +-{ +- GAppLaunchContext *launch_context; +- const char *uri; +- gboolean success; +- GError *error = NULL; +- +- launch_context = task_data; +- uri = g_object_get_data (G_OBJECT (launch_context), "uri"); +- success = g_app_info_launch_default_for_uri (uri, launch_context, &error); +- +- if (success) +- { +- g_task_return_boolean (task, success); +- } +- else +- { +- g_task_return_error (task, error); +- } +-} +- +-void +-nautilus_launch_default_for_uri_async (const char *uri, +- GtkWindow *parent_window, +- GCancellable *cancellable, +- GAsyncReadyCallback callback, +- gpointer callback_data) +-{ +- g_autoptr (GdkAppLaunchContext) launch_context = NULL; +- g_autoptr (GTask) task = NULL; +- +- g_return_if_fail (uri != NULL); +- +- launch_context = get_launch_context (parent_window); +- task = g_task_new (parent_window, cancellable, callback, callback_data); +- +- gdk_app_launch_context_set_timestamp (launch_context, GDK_CURRENT_TIME); +- +- g_object_set_data_full (G_OBJECT (launch_context), +- "uri", g_strdup (uri), g_free); +- g_task_set_task_data (task, +- g_object_ref (launch_context), g_object_unref); +- +- if (parent_window != NULL) +- { +- gboolean handle_exported; +- +- handle_exported = nautilus_window_export_handle (NAUTILUS_WINDOW (parent_window), +- on_window_handle_export, +- g_object_ref (task)); +- +- if (handle_exported) +- { +- /* Launching will now be handled from the callback */ +- return; +- } +- } +- +- g_task_run_in_thread (task, launch_default_for_uri_thread_func); +-} +- +-gboolean +-nautilus_launch_default_for_uri_finish (GAsyncResult *result, +- GError **error) +-{ +- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); +- +- return g_task_propagate_boolean (G_TASK (result), error); +-} +- +-/* END OF HAX */ +diff --git a/src/nautilus-program-choosing.h b/src/nautilus-program-choosing.h +index 51881ff17..a402b79a2 100644 +--- a/src/nautilus-program-choosing.h ++++ b/src/nautilus-program-choosing.h +@@ -51,10 +51,3 @@ void nautilus_launch_desktop_file (GdkScreen + const char *desktop_file_uri, + const GList *parameter_uris, + GtkWindow *parent_window); +-void nautilus_launch_default_for_uri_async (const char *uri, +- GtkWindow *parent_window, +- GCancellable *cancellable, +- GAsyncReadyCallback callback, +- gpointer callback_data); +-gboolean nautilus_launch_default_for_uri_finish (GAsyncResult *result, +- GError **error); +\ No newline at end of file +-- +2.24.1 + diff --git a/nautilus.spec b/nautilus.spec index 044fbc0..f238965 100644 --- a/nautilus.spec +++ b/nautilus.spec @@ -3,7 +3,7 @@ Name: nautilus Version: 3.35.90 -Release: 1%{?dist} +Release: 2%{?dist} Summary: File manager for GNOME License: GPLv3+ @@ -15,6 +15,7 @@ BuildRequires: gcc BuildRequires: gettext BuildRequires: gtk-doc BuildRequires: meson +BuildRequires: git BuildRequires: pkgconfig(gexiv2) BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version} BuildRequires: pkgconfig(gnome-autoar-0) @@ -44,6 +45,9 @@ Requires: tracker-miners # libtotem-properties-page.so was shipped in totem-nautilus before Conflicts: totem-nautilus < 1:3.31.91 +# https://gitlab.gnome.org/GNOME/nautilus/issues/117#note_496825 +Patch0: 0001-Revert-mime-actions-launch-default-uri-handlers-when.patch + %description Nautilus is the file manager and graphical shell for the GNOME desktop that makes it easy to manage your files and the rest of your system. @@ -69,7 +73,7 @@ This package provides libraries and header files needed for developing nautilus extensions. %prep -%autosetup -p1 +%autosetup -p1 -S git # Remove -Werror from compiler flags sed -i '/-Werror/d' meson.build @@ -132,6 +136,10 @@ desktop-file-validate $RPM_BUILD_ROOT%{_datadir}/applications/*.desktop %doc %{_datadir}/gtk-doc/html/libnautilus-extension/ %changelog +* Thu Feb 06 2020 Bastien Nocera - 3.35.90-2 ++ nautilus-3.35.90-2 +- Fix launching multiple files at once + * Sun Feb 02 2020 Kalev Lember - 3.35.90-1 - Update to 3.35.90