nautilus/0001-mime-actions-Group-files-depending-on-the-opening-ap.patch
2020-08-21 16:22:50 +02:00

622 lines
20 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 873939e8222a778e8f9855944483cb1ee1cb984b Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Thu, 6 Feb 2020 15:04:31 +0100
Subject: [PATCH] mime-actions: Group files depending on the opening app
Reinstate the old behaviour which used to look at the files to open,
group them by handling application, and pass a single call to each
application with all the files it could handle.
For the common case where it's a single application handling all the
files, as is usual for handling media files (images, videos, music,
etc.), it changes the launching behaviour from:
application.bin foo.mp3
application.bin foo2.mp3
application.bin foo3.mp3
to:
application.bin foo.mp3 foo2.mp3 foo3.mp3
This however impacts the behaviour of nautilus launching applications
when inside a Flatpak sandbox, as it cannot enumerate and launch
applications itself. As the Flatpak sandbox is a development tool, and
for the sake of expediency, we reverted to the old code path.
Revert "mime-actions: launch default uri handlers when activating files"
This reverts commit f5206a6daf0991d91e885a28bb66795a8ae12a41.
Closes: #117
---
src/nautilus-mime-actions.c | 268 +++++++++++++++++++++++---------
src/nautilus-program-choosing.c | 188 +++-------------------
src/nautilus-program-choosing.h | 7 -
3 files changed, 211 insertions(+), 252 deletions(-)
diff --git a/src/nautilus-mime-actions.c b/src/nautilus-mime-actions.c
index 26468c597..4a49828a8 100644
--- a/src/nautilus-mime-actions.c
+++ b/src/nautilus-mime-actions.c
@@ -61,6 +61,12 @@ typedef struct
char *uri;
} LaunchLocation;
+typedef struct
+{
+ GAppInfo *application;
+ GList *uris;
+} ApplicationLaunchParameters;
+
typedef struct
{
NautilusWindowSlot *slot;
@@ -80,13 +86,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
{
@@ -345,19 +344,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)
{
@@ -792,6 +799,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)
{
@@ -843,16 +958,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)
{
@@ -1369,55 +1474,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;
@@ -1612,26 +1684,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 47362a3f7..35a4ab73f 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)
@@ -480,144 +472,4 @@ nautilus_launch_desktop_file (GdkScreen *screen,
g_object_unref (app_info);
}
-/* HAX
- *
- * TODO: remove everything below once its 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
--
GitLab