summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntónio Fernandes <antoniof@gnome.org>2020-12-30 15:54:59 +0000
committerAntónio Fernandes <antoniojpfernandes@gmail.com>2021-03-12 15:47:05 +0000
commit080f83385ff79a8be54ee31e7a45422138226f1f (patch)
treedb840a8684fd02a67b570591899ff96c2192bd0e
parente771411670e304dee6288e9278b6bf98da561014 (diff)
downloadnautilus-080f83385ff79a8be54ee31e7a45422138226f1f.tar.gz
mime-actions: Open files as groups if not sandboxed
While sandboxed, we open files using the OpenURI portal, and we don't know which app is the default handler app for each file. As such, we have given up group-launching files with the same default handler when adapting nautilus to being sandboxed.[0] But this resulted in a feature regression in the non-sandboxed case, which is still the common case in production. Reinstate the code for the old behaviour[1], but keep the current behaviour when running in inside a flatpak sandbox. Closes https://gitlab.gnome.org/GNOME/nautilus/-/issues/117 [0] f5206a6daf0991d91e885a28bb66795a8ae12a41 [1] based on revert patch with revert conflicts resolved by hadess
-rw-r--r--src/nautilus-mime-actions.c238
1 files changed, 215 insertions, 23 deletions
diff --git a/src/nautilus-mime-actions.c b/src/nautilus-mime-actions.c
index 1a3abff38..206949435 100644
--- a/src/nautilus-mime-actions.c
+++ b/src/nautilus-mime-actions.c
@@ -62,6 +62,12 @@ typedef struct
typedef struct
{
+ GAppInfo *application;
+ GList *uris;
+} ApplicationLaunchParameters;
+
+typedef struct
+{
NautilusWindowSlot *slot;
gpointer window;
GtkWindow *parent_window;
@@ -84,7 +90,7 @@ typedef struct
ActivateParameters *activation_params;
GQueue *uris;
GQueue *unhandled_uris;
-} ApplicationLaunchParameters;
+} ApplicationLaunchAsyncParameters;
/* 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
@@ -340,19 +346,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)
{
@@ -684,6 +698,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)
{
@@ -736,7 +858,7 @@ activation_parameters_free (ActivateParameters *parameters)
}
static void
-application_launch_parameters_free (ApplicationLaunchParameters *parameters)
+application_launch_async_parameters_free (ApplicationLaunchAsyncParameters *parameters)
{
g_queue_free (parameters->unhandled_uris);
g_queue_free (parameters->uris);
@@ -1262,11 +1384,11 @@ out:
}
static void
-on_launch_default_for_uri (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+launch_default_for_uris_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
- ApplicationLaunchParameters *params;
+ ApplicationLaunchAsyncParameters *params;
ActivateParameters *activation_params;
char *uri;
gboolean sandboxed;
@@ -1288,7 +1410,7 @@ on_launch_default_for_uri (GObject *source_object,
nautilus_launch_default_for_uri_async (g_queue_peek_head (params->uris),
activation_params->parent_window,
activation_params->cancellable,
- on_launch_default_for_uri,
+ launch_default_for_uris_callback,
params);
}
else
@@ -1298,7 +1420,7 @@ on_launch_default_for_uri (GObject *source_object,
application_unhandled_uri (activation_params, uri);
}
- application_launch_parameters_free (params);
+ application_launch_async_parameters_free (params);
}
}
@@ -1307,9 +1429,16 @@ 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_files = NULL;
g_autoptr (GQueue) launch_in_terminal_files = NULL;
g_autoptr (GQueue) open_in_app_uris = NULL;
@@ -1489,26 +1618,89 @@ activate_files (ActivateParameters *parameters)
}
}
- if (g_queue_is_empty (open_in_app_uris))
- {
- activation_parameters_free (parameters);
- }
- else
+ if (!g_queue_is_empty (open_in_app_uris) &&
+ g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS))
{
const char *uri;
- ApplicationLaunchParameters *params;
+ ApplicationLaunchAsyncParameters *async_params;
uri = g_queue_peek_head (open_in_app_uris);
- params = application_launch_parameters_new (parameters,
- g_queue_copy (open_in_app_uris));
+
+ async_params = g_new0 (ApplicationLaunchAsyncParameters, 1);
+ async_params->activation_params = parameters;
+ async_params->uris = g_steal_pointer (&open_in_app_uris);
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);
+ launch_default_for_uris_callback,
+ async_params);
+ return;
+ }
+
+ if (open_in_app_uris != NULL)
+ {
+ open_in_app_parameters = make_activation_parameters (g_queue_peek_head_link (open_in_app_uris),
+ &unhandled_open_in_app_uris);
}
+
+ 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)
+ {
+ GtkDialog *dialog;
+ char *prompt;
+ g_autofree char *detail = NULL;
+ int response;
+
+ pause_activation_timed_cancel (parameters);
+
+ 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