nautilus/libnautilus-private/nautilus-mime-actions.c
Alexander Larsson 1e1c916f55 Add "interactive" argument to nautilus_file_mark_desktop_file_trusted.
2009-02-24  Alexander Larsson  <alexl@redhat.com>

        * libnautilus-private/nautilus-file-operations.c:
        * libnautilus-private/nautilus-file-operations.h:
        * libnautilus-private/nautilus-mime-actions.c:
        Add "interactive" argument to
	nautilus_file_mark_desktop_file_trusted.

        * src/nautilus-application.c:
	Mark all desktopfiles on the desktop trusted on first
	run.



svn path=/trunk/; revision=15009
2009-02-24 15:51:54 +00:00

2031 lines
55 KiB
C

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* nautilus-mime-actions.c - uri-specific versions of mime action functions
Copyright (C) 2000, 2001 Eazel, Inc.
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Maciej Stachowiak <mjs@eazel.com>
*/
#include <config.h>
#include "nautilus-mime-actions.h"
#include <eel/eel-glib-extensions.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-alert-dialog.h>
#include <eel/eel-string.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <gdk/gdkx.h>
#include "nautilus-file-attributes.h"
#include "nautilus-file.h"
#include "nautilus-autorun.h"
#include "nautilus-file-operations.h"
#include "nautilus-metadata.h"
#include "nautilus-program-choosing.h"
#include "nautilus-desktop-icon-file.h"
#include "nautilus-global-preferences.h"
#include "nautilus-debug-log.h"
typedef enum {
ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE,
ACTIVATION_ACTION_ASK,
ACTIVATION_ACTION_LAUNCH,
ACTIVATION_ACTION_LAUNCH_IN_TERMINAL,
ACTIVATION_ACTION_OPEN_IN_VIEW,
ACTIVATION_ACTION_OPEN_IN_APPLICATION,
ACTIVATION_ACTION_DO_NOTHING,
} ActivationAction;
typedef struct {
GAppInfo *application;
GList *files;
} ApplicationLaunchParameters;
typedef struct {
NautilusWindowSlotInfo *slot_info;
gpointer window_info;
GtkWindow *parent_window;
GCancellable *cancellable;
GList *files;
GList *mountables;
GList *not_mounted;
NautilusWindowOpenMode mode;
NautilusWindowOpenFlags flags;
char *timed_wait_prompt;
gboolean timed_wait_active;
NautilusFileListHandle *files_handle;
gboolean tried_mounting;
char *activation_directory;
gboolean user_confirmation;
} ActivateParameters;
/* Number of seconds until cancel dialog shows up */
#define DELAY_UNTIL_CANCEL_MSECS 5000
#define RESPONSE_RUN 1000
#define RESPONSE_DISPLAY 1001
#define RESPONSE_RUN_IN_TERMINAL 1002
#define RESPONSE_MARK_TRUSTED 1003
#define SILENT_WINDOW_OPEN_LIMIT 5
/* This number controls a maximum character count for a URL that is
* displayed as part of a dialog. It's fairly arbitrary -- big enough
* to allow most "normal" URIs to display in full, but small enough to
* prevent the dialog from getting insanely wide.
*/
#define MAX_URI_IN_DIALOG_LENGTH 60
static void cancel_activate_callback (gpointer callback_data);
static void activate_activation_uris_ready_callback (GList *files,
gpointer callback_data);
static void activation_mount_mountables (ActivateParameters *parameters);
static void activate_callback (GList *files,
gpointer callback_data);
static void activation_mount_not_mounted (ActivateParameters *parameters);
static ApplicationLaunchParameters *
application_launch_parameters_new (GAppInfo *application,
GList *files)
{
ApplicationLaunchParameters *result;
result = g_new0 (ApplicationLaunchParameters, 1);
result->application = g_object_ref (application);
result->files = nautilus_file_list_copy (files);
return result;
}
static void
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
{
g_object_unref (parameters->application);
nautilus_file_list_free (parameters->files);
g_free (parameters);
}
static GList*
filter_nautilus_handler (GList *apps)
{
GList *l, *next;
GAppInfo *application;
const char *id;
l = apps;
while (l != NULL) {
application = (GAppInfo *) l->data;
next = l->next;
id = g_app_info_get_id (application);
if (id != NULL &&
strcmp (id,
"nautilus-folder-handler.desktop") == 0) {
g_object_unref (application);
apps = g_list_delete_link (apps, l);
}
l = next;
}
return apps;
}
static GList*
filter_non_uri_apps (GList *apps)
{
GList *l, *next;
GAppInfo *app;
for (l = apps; l != NULL; l = next) {
app = l->data;
next = l->next;
if (!g_app_info_supports_uris (app)) {
apps = g_list_delete_link (apps, l);
g_object_unref (app);
}
}
return apps;
}
static gboolean
nautilus_mime_actions_check_if_required_attributes_ready (NautilusFile *file)
{
NautilusFileAttributes attributes;
gboolean ready;
attributes = nautilus_mime_actions_get_required_file_attributes ();
ready = nautilus_file_check_if_ready (file, attributes);
return ready;
}
NautilusFileAttributes
nautilus_mime_actions_get_required_file_attributes (void)
{
return NAUTILUS_FILE_ATTRIBUTE_INFO |
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO |
NAUTILUS_FILE_ATTRIBUTE_METADATA;
}
static gboolean
file_has_local_path (NautilusFile *file)
{
GFile *location;
char *path;
gboolean res;
/* Don't only check _is_native, because we want to support
using the fuse path */
location = nautilus_file_get_location (file);
if (g_file_is_native (location)) {
res = TRUE;
} else {
path = g_file_get_path (location);
res = path != NULL;
g_free (path);
}
g_object_unref (location);
return res;
}
GAppInfo *
nautilus_mime_get_default_application_for_file (NautilusFile *file)
{
GAppInfo *app;
char *mime_type;
char *uri_scheme;
if (!nautilus_mime_actions_check_if_required_attributes_ready (file)) {
return NULL;
}
mime_type = nautilus_file_get_mime_type (file);
app = g_app_info_get_default_for_type (mime_type, !file_has_local_path (file));
g_free (mime_type);
if (app == NULL) {
uri_scheme = nautilus_file_get_uri_scheme (file);
if (uri_scheme != NULL) {
app = g_app_info_get_default_for_uri_scheme (uri_scheme);
g_free (uri_scheme);
}
}
return app;
}
static int
file_compare_by_mime_type (NautilusFile *file_a,
NautilusFile *file_b)
{
char *mime_type_a, *mime_type_b;
int ret;
mime_type_a = nautilus_file_get_mime_type (file_a);
mime_type_b = nautilus_file_get_mime_type (file_b);
ret = strcmp (mime_type_a, mime_type_b);
g_free (mime_type_a);
g_free (mime_type_b);
return ret;
}
static int
file_compare_by_parent_uri (NautilusFile *file_a,
NautilusFile *file_b) {
char *parent_uri_a, *parent_uri_b;
int ret;
parent_uri_a = nautilus_file_get_parent_uri (file_a);
parent_uri_b = nautilus_file_get_parent_uri (file_b);
ret = strcmp (parent_uri_a, parent_uri_b);
g_free (parent_uri_a);
g_free (parent_uri_b);
return ret;
}
static int
application_compare_by_name (const GAppInfo *app_a,
const GAppInfo *app_b)
{
return g_utf8_collate (g_app_info_get_name ((GAppInfo *)app_a),
g_app_info_get_name ((GAppInfo *)app_b));
}
static int
application_compare_by_id (const GAppInfo *app_a,
const GAppInfo *app_b)
{
const char *id_a, *id_b;
id_a = g_app_info_get_id ((GAppInfo *)app_a);
id_b = g_app_info_get_id ((GAppInfo *)app_b);
if (id_a == NULL && id_b == NULL) {
if (g_app_info_equal ((GAppInfo *)app_a, (GAppInfo *)app_b)) {
return 0;
}
if ((gsize)app_a < (gsize) app_b) {
return -1;
}
return 1;
}
if (id_a == NULL) {
return -1;
}
if (id_b == NULL) {
return 1;
}
return strcmp (id_a, id_b);
}
GList *
nautilus_mime_get_applications_for_file (NautilusFile *file)
{
char *mime_type;
char *uri_scheme;
GList *result;
GAppInfo *uri_handler;
if (!nautilus_mime_actions_check_if_required_attributes_ready (file)) {
return NULL;
}
mime_type = nautilus_file_get_mime_type (file);
result = g_app_info_get_all_for_type (mime_type);
uri_scheme = nautilus_file_get_uri_scheme (file);
if (uri_scheme != NULL) {
uri_handler = g_app_info_get_default_for_uri_scheme (uri_scheme);
if (uri_handler) {
result = g_list_prepend (result, uri_handler);
}
g_free (uri_scheme);
}
if (!file_has_local_path (file)) {
/* Filter out non-uri supporting apps */
result = filter_non_uri_apps (result);
}
result = g_list_sort (result, (GCompareFunc) application_compare_by_name);
g_free (mime_type);
return filter_nautilus_handler (result);
}
gboolean
nautilus_mime_has_any_applications_for_file (NautilusFile *file)
{
GList *apps;
char *mime_type;
gboolean result;
char *uri_scheme;
GAppInfo *uri_handler;
mime_type = nautilus_file_get_mime_type (file);
apps = g_app_info_get_all_for_type (mime_type);
uri_scheme = nautilus_file_get_uri_scheme (file);
if (uri_scheme != NULL) {
uri_handler = g_app_info_get_default_for_uri_scheme (uri_scheme);
if (uri_handler) {
apps = g_list_prepend (apps, uri_handler);
}
g_free (uri_scheme);
}
if (!file_has_local_path (file)) {
/* Filter out non-uri supporting apps */
apps = filter_non_uri_apps (apps);
}
apps = filter_nautilus_handler (apps);
if (apps) {
result = TRUE;
eel_g_object_list_free (apps);
} else {
result = FALSE;
}
g_free (mime_type);
return result;
}
GAppInfo *
nautilus_mime_get_default_application_for_files (GList *files)
{
GList *l, *sorted_files;
NautilusFile *file;
GAppInfo *app, *one_app;
g_assert (files != NULL);
sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type);
app = NULL;
for (l = sorted_files; l != NULL; l = l->next) {
file = l->data;
if (l->prev &&
file_compare_by_mime_type (file, l->prev->data) == 0 &&
file_compare_by_parent_uri (file, l->prev->data) == 0) {
continue;
}
one_app = nautilus_mime_get_default_application_for_file (file);
if (one_app == NULL || (app != NULL && !g_app_info_equal (app, one_app))) {
if (app) {
g_object_unref (app);
}
if (one_app) {
g_object_unref (one_app);
}
app = NULL;
break;
}
if (app == NULL) {
app = one_app;
} else {
g_object_unref (one_app);
}
}
g_list_free (sorted_files);
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;
GAppInfo *a_app, *b_app;
int cmp;
ret = NULL;
l = a;
m = b;
while (l != NULL && m != NULL) {
a_app = (GAppInfo *) l->data;
b_app = (GAppInfo *) m->data;
cmp = application_compare_by_id (a_app, b_app);
if (cmp > 0) {
g_object_unref (b_app);
m = m->next;
} else if (cmp < 0) {
g_object_unref (a_app);
l = l->next;
} else {
g_object_unref (b_app);
ret = g_list_prepend (ret, a_app);
l = l->next;
m = m->next;
}
}
g_list_foreach (l, (GFunc) g_object_unref, NULL);
g_list_foreach (m, (GFunc) g_object_unref, NULL);
g_list_free (a);
g_list_free (b);
return g_list_reverse (ret);
}
GList *
nautilus_mime_get_applications_for_files (GList *files)
{
GList *l, *sorted_files;
NautilusFile *file;
GList *one_ret, *ret;
g_assert (files != NULL);
sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type);
ret = NULL;
for (l = sorted_files; l != NULL; l = l->next) {
file = l->data;
if (l->prev &&
file_compare_by_mime_type (file, l->prev->data) == 0 &&
file_compare_by_parent_uri (file, l->prev->data) == 0) {
continue;
}
one_ret = nautilus_mime_get_applications_for_file (file);
one_ret = g_list_sort (one_ret, (GCompareFunc) application_compare_by_id);
if (ret != NULL) {
ret = intersect_application_lists (ret, one_ret);
} else {
ret = one_ret;
}
if (ret == NULL) {
break;
}
}
g_list_free (sorted_files);
ret = g_list_sort (ret, (GCompareFunc) application_compare_by_name);
return ret;
}
gboolean
nautilus_mime_has_any_applications_for_files (GList *files)
{
GList *l, *sorted_files;
NautilusFile *file;
gboolean ret;
g_assert (files != NULL);
sorted_files = g_list_sort (g_list_copy (files), (GCompareFunc) file_compare_by_mime_type);
ret = TRUE;
for (l = sorted_files; l != NULL; l = l->next) {
file = NAUTILUS_FILE (l->data);
if (l->prev &&
file_compare_by_mime_type (file, l->prev->data) == 0 &&
file_compare_by_parent_uri (file, l->prev->data) == 0) {
continue;
}
if (!nautilus_mime_has_any_applications_for_file (file)) {
ret = FALSE;
break;
}
}
g_list_free (sorted_files);
return ret;
}
static void
trash_or_delete_files (GtkWindow *parent_window,
const GList *files,
gboolean delete_if_all_already_in_trash)
{
GList *locations;
const GList *node;
locations = NULL;
for (node = files; node != NULL; node = node->next) {
locations = g_list_prepend (locations,
nautilus_file_get_location ((NautilusFile *) node->data));
}
locations = g_list_reverse (locations);
nautilus_file_operations_trash_or_delete (locations,
parent_window,
NULL, NULL);
eel_g_object_list_free (locations);
}
static void
report_broken_symbolic_link (GtkWindow *parent_window, NautilusFile *file)
{
char *target_path;
char *display_name;
char *prompt;
char *detail;
GtkDialog *dialog;
GList file_as_list;
int response;
g_assert (nautilus_file_is_broken_symbolic_link (file));
display_name = nautilus_file_get_display_name (file);
if (nautilus_file_is_in_trash (file)) {
prompt = g_strdup_printf (_("The Link \"%s\" is Broken."), display_name);
} else {
prompt = g_strdup_printf (_("The Link \"%s\" is Broken. Move it to Trash?"), display_name);
}
g_free (display_name);
target_path = nautilus_file_get_symbolic_link_target_path (file);
if (target_path == NULL) {
detail = g_strdup (_("This link cannot be used, because it has no target."));
} else {
detail = g_strdup_printf (_("This link cannot be used, because its target "
"\"%s\" doesn't exist."), target_path);
}
if (nautilus_file_is_in_trash (file)) {
eel_run_simple_dialog (GTK_WIDGET (parent_window), FALSE, GTK_MESSAGE_WARNING,
prompt, detail, GTK_STOCK_CANCEL, NULL);
goto out;
}
dialog = eel_show_yes_no_dialog (prompt, detail, _("Mo_ve to Trash"), GTK_STOCK_CANCEL,
parent_window);
gtk_dialog_set_default_response (dialog, GTK_RESPONSE_YES);
/* Make this modal to avoid problems with reffing the view & file
* to keep them around in case the view changes, which would then
* cause the old view not to be destroyed, which would cause its
* merged Bonobo items not to be un-merged. Maybe we need to unmerge
* explicitly when disconnecting views instead of relying on the
* unmerge in Destroy. But since BonoboUIHandler is probably going
* to change wildly, I don't want to mess with this now.
*/
response = gtk_dialog_run (dialog);
gtk_object_destroy (GTK_OBJECT (dialog));
if (response == GTK_RESPONSE_YES) {
file_as_list.data = file;
file_as_list.next = NULL;
file_as_list.prev = NULL;
trash_or_delete_files (parent_window, &file_as_list, TRUE);
}
out:
g_free (prompt);
g_free (target_path);
g_free (detail);
}
static ActivationAction
get_executable_text_file_action (GtkWindow *parent_window, NautilusFile *file)
{
GtkDialog *dialog;
char *file_name;
char *prompt;
char *detail;
int preferences_value;
int response;
g_assert (nautilus_file_contains_text (file));
preferences_value = eel_preferences_get_enum
(NAUTILUS_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION);
switch (preferences_value) {
case NAUTILUS_EXECUTABLE_TEXT_LAUNCH:
return ACTIVATION_ACTION_LAUNCH;
case NAUTILUS_EXECUTABLE_TEXT_DISPLAY:
return ACTIVATION_ACTION_OPEN_IN_APPLICATION;
case NAUTILUS_EXECUTABLE_TEXT_ASK:
break;
default:
/* Complain non-fatally, since preference data can't be trusted */
g_warning ("Unknown value %d for NAUTILUS_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION",
preferences_value);
}
file_name = nautilus_file_get_display_name (file);
prompt = g_strdup_printf (_("Do you want to run \"%s\", or display its contents?"),
file_name);
detail = g_strdup_printf (_("\"%s\" is an executable text file."),
file_name);
g_free (file_name);
dialog = eel_create_question_dialog (prompt,
detail,
_("Run in _Terminal"), RESPONSE_RUN_IN_TERMINAL,
_("_Display"), RESPONSE_DISPLAY,
parent_window);
gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_add_button (dialog, _("_Run"), RESPONSE_RUN);
gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CANCEL);
gtk_widget_show (GTK_WIDGET (dialog));
g_free (prompt);
g_free (detail);
response = gtk_dialog_run (dialog);
gtk_object_destroy (GTK_OBJECT (dialog));
switch (response) {
case RESPONSE_RUN:
return ACTIVATION_ACTION_LAUNCH;
case RESPONSE_RUN_IN_TERMINAL:
return ACTIVATION_ACTION_LAUNCH_IN_TERMINAL;
case RESPONSE_DISPLAY:
return ACTIVATION_ACTION_OPEN_IN_APPLICATION;
default:
return ACTIVATION_ACTION_DO_NOTHING;
}
}
static ActivationAction
get_default_executable_text_file_action (void)
{
int preferences_value;
preferences_value = eel_preferences_get_enum
(NAUTILUS_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION);
switch (preferences_value) {
case NAUTILUS_EXECUTABLE_TEXT_LAUNCH:
return ACTIVATION_ACTION_LAUNCH;
case NAUTILUS_EXECUTABLE_TEXT_DISPLAY:
return ACTIVATION_ACTION_OPEN_IN_APPLICATION;
case NAUTILUS_EXECUTABLE_TEXT_ASK:
default:
return ACTIVATION_ACTION_ASK;
}
}
gboolean
nautilus_mime_file_opens_in_view (NautilusFile *file)
{
return (nautilus_file_is_directory (file) ||
NAUTILUS_IS_DESKTOP_ICON_FILE (file) ||
nautilus_file_is_nautilus_link (file));
}
static ActivationAction
get_activation_action (NautilusFile *file)
{
ActivationAction action;
char *activation_uri;
if (nautilus_file_is_launcher (file)) {
return ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE;
}
activation_uri = nautilus_file_get_activation_uri (file);
if (activation_uri == NULL) {
activation_uri = nautilus_file_get_uri (file);
}
action = ACTIVATION_ACTION_DO_NOTHING;
if (nautilus_file_is_launchable (file)) {
char *executable_path;
action = ACTIVATION_ACTION_LAUNCH;
executable_path = g_filename_from_uri (activation_uri, NULL, NULL);
if (!executable_path) {
action = ACTIVATION_ACTION_DO_NOTHING;
} else if (nautilus_file_contains_text (file)) {
action = get_default_executable_text_file_action ();
}
g_free (executable_path);
}
if (action == ACTIVATION_ACTION_DO_NOTHING) {
if (nautilus_mime_file_opens_in_view (file)) {
action = ACTIVATION_ACTION_OPEN_IN_VIEW;
} else {
action = ACTIVATION_ACTION_OPEN_IN_APPLICATION;
}
}
g_free (activation_uri);
return action;
}
gboolean
nautilus_mime_file_opens_in_external_app (NautilusFile *file)
{
ActivationAction activation_action;
activation_action = get_activation_action (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 *files,
GList **ret)
{
ApplicationLaunchParameters *parameters;
files = g_list_reverse (files);
parameters = application_launch_parameters_new
(application, files);
*ret = g_list_prepend (*ret, parameters);
}
/**
* 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;
GAppInfo *app, *old_app;
GHashTable *app_table;
ret = NULL;
*unhandled_files = 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 = 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_hash_table_steal (app_table, old_app);
app_files = g_list_prepend (app_files, file);
g_object_unref (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 gboolean
file_was_cancelled (NautilusFile *file)
{
GError *error;
error = nautilus_file_get_file_info_error (file);
return
error != NULL &&
error->domain == G_IO_ERROR &&
error->code == G_IO_ERROR_CANCELLED;
}
static gboolean
file_was_not_mounted (NautilusFile *file)
{
GError *error;
error = nautilus_file_get_file_info_error (file);
return
error != NULL &&
error->domain == G_IO_ERROR &&
error->code == G_IO_ERROR_NOT_MOUNTED;
}
static void
activation_parameters_free (ActivateParameters *parameters)
{
if (parameters->timed_wait_active) {
eel_timed_wait_stop (cancel_activate_callback, parameters);
}
if (parameters->slot_info) {
g_object_remove_weak_pointer (G_OBJECT (parameters->slot_info), (gpointer *)&parameters->slot_info);
}
if (parameters->parent_window) {
g_object_remove_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *)&parameters->parent_window);
}
g_object_unref (parameters->cancellable);
nautilus_file_list_free (parameters->files);
nautilus_file_list_free (parameters->mountables);
nautilus_file_list_free (parameters->not_mounted);
g_free (parameters->activation_directory);
g_free (parameters->timed_wait_prompt);
g_assert (parameters->files_handle == NULL);
g_free (parameters);
}
static void
cancel_activate_callback (gpointer callback_data)
{
ActivateParameters *parameters = callback_data;
parameters->timed_wait_active = FALSE;
g_cancellable_cancel (parameters->cancellable);
if (parameters->files_handle) {
nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
parameters->files_handle = NULL;
activation_parameters_free (parameters);
}
}
static void
activation_start_timed_cancel (ActivateParameters *parameters)
{
parameters->timed_wait_active = TRUE;
eel_timed_wait_start_with_duration
(DELAY_UNTIL_CANCEL_MSECS,
cancel_activate_callback,
parameters,
parameters->timed_wait_prompt,
parameters->parent_window);
}
static void
pause_activation_timed_cancel (ActivateParameters *parameters)
{
if (parameters->timed_wait_active) {
eel_timed_wait_stop (cancel_activate_callback, parameters);
parameters->timed_wait_active = FALSE;
}
}
static void
unpause_activation_timed_cancel (ActivateParameters *parameters)
{
if (!parameters->timed_wait_active) {
activation_start_timed_cancel (parameters);
}
}
static void
activate_mount_op_active (GtkMountOperation *operation,
GParamSpec *pspec,
ActivateParameters *parameters)
{
gboolean is_active;
g_object_get (operation, "is-showing", &is_active, NULL);
if (is_active) {
pause_activation_timed_cancel (parameters);
} else {
unpause_activation_timed_cancel (parameters);
}
}
static gboolean
confirm_multiple_windows (GtkWindow *parent_window,
int count,
gboolean use_tabs)
{
GtkDialog *dialog;
char *prompt;
char *detail;
int response;
if (count <= SILENT_WINDOW_OPEN_LIMIT) {
return TRUE;
}
prompt = _("Are you sure you want to open all files?");
if (use_tabs) {
detail = g_strdup_printf (ngettext("This will open %d separate tab.",
"This will open %d separate tabs.", count), count);
} else {
detail = g_strdup_printf (ngettext("This will open %d separate window.",
"This will open %d separate windows.", count), count);
}
dialog = eel_show_yes_no_dialog (prompt, detail,
GTK_STOCK_OK, GTK_STOCK_CANCEL,
parent_window);
g_free (detail);
response = gtk_dialog_run (dialog);
gtk_object_destroy (GTK_OBJECT (dialog));
return response == GTK_RESPONSE_YES;
}
typedef struct {
NautilusWindowSlotInfo *slot_info;
GtkWindow *parent_window;
NautilusFile *file;
GList *files;
NautilusWindowOpenMode mode;
NautilusWindowOpenFlags flags;
char *activation_directory;
gboolean user_confirmation;
} ActivateParametersInstall;
static void
activate_parameters_install_free (ActivateParametersInstall *parameters_install)
{
if (parameters_install->slot_info) {
g_object_remove_weak_pointer (G_OBJECT (parameters_install->slot_info), (gpointer *)&parameters_install->slot_info);
}
if (parameters_install->parent_window) {
g_object_remove_weak_pointer (G_OBJECT (parameters_install->parent_window), (gpointer *)&parameters_install->parent_window);
}
nautilus_file_unref (parameters_install->file);
nautilus_file_list_free (parameters_install->files);
g_free (parameters_install->activation_directory);
g_free (parameters_install);
}
static void
search_for_application_dbus_call_notify_cb (DBusGProxy *proxy, DBusGProxyCall *call, ActivateParametersInstall *parameters_install)
{
gboolean ret;
GError *error = NULL;
char *message;
const char *remote = NULL;
ret = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
if (!ret) {
if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) {
remote = dbus_g_error_get_name (error);
}
/* we already show an error in the installer if not found, just catch generic failure */
if (remote == NULL || strcmp (remote, "org.freedesktop.PackageKit.Modify.Failed") == 0) {
message = g_strdup_printf ("%s\n%s",
_("There was an internal error trying to search for applications:"),
error->message);
eel_show_error_dialog (_("Unable to search for application"), message,
parameters_install->parent_window);
g_free (message);
}
g_error_free (error);
return;
}
g_object_unref (proxy);
/* activate the file again */
nautilus_mime_activate_files (parameters_install->parent_window,
parameters_install->slot_info,
parameters_install->files,
parameters_install->activation_directory,
parameters_install->mode,
parameters_install->flags,
parameters_install->user_confirmation);
/* parameters_install freed by destroy notify */
}
static void
search_for_application_mime_type (ActivateParametersInstall *parameters_install, const gchar *mime_type)
{
DBusGConnection *connection;
DBusGProxy *proxy = NULL;
guint xid = 0;
GError *error = NULL;
DBusGProxyCall *call = NULL;
GtkWidget *dialog;
GdkWindow *window;
const char *mime_types[2];
/* get bus */
connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
if (connection == NULL) {
g_warning ("Could not connect to session bus: %s\n", error->message);
g_error_free (error);
goto out;
}
/* get proxy - native clients for for KDE and GNOME */
proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.PackageKit",
"/org/freedesktop/PackageKit",
"org.freedesktop.PackageKit.Modify");
if (proxy == NULL) {
g_warning ("Could not connect to PackageKit session service\n");
goto out;
}
/* get XID from parent window */
window = gtk_widget_get_window (GTK_WIDGET (parameters_install->parent_window));
if (window != NULL) {
xid = GDK_WINDOW_XID (window);
}
/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
/* invoke the method */
mime_types[0] = mime_type;
mime_types[1] = NULL;
call = dbus_g_proxy_begin_call (proxy, "InstallMimeTypes",
(DBusGProxyCallNotify) search_for_application_dbus_call_notify_cb,
parameters_install,
(GDestroyNotify) activate_parameters_install_free,
G_TYPE_UINT, xid,
G_TYPE_STRV, mime_types,
G_TYPE_STRING, "hide-confirm-search",
G_TYPE_INVALID);
if (call == NULL) {
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
_("Could not use system package installer"));
g_signal_connect (G_OBJECT (dialog), "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_widget_show (dialog);
goto out;
}
nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
"InstallMimeType method invoked for %s", mime_type);
out:
if (call == NULL) {
/* dbus method was not called, so we're not going to get the async dbus callback */
activate_parameters_install_free (parameters_install);
}
}
static void
application_unhandled_file_install (GtkDialog *dialog, gint response_id, ActivateParametersInstall *parameters_install)
{
char *mime_type;
gtk_widget_destroy (GTK_WIDGET (dialog));
if (response_id == GTK_RESPONSE_YES) {
mime_type = nautilus_file_get_mime_type (parameters_install->file);
search_for_application_mime_type (parameters_install, mime_type);
g_free (mime_type);
} else {
/* free as we're not going to get the async dbus callback */
activate_parameters_install_free (parameters_install);
}
}
static void
application_unhandled_file (ActivateParameters *parameters, NautilusFile *file)
{
GFile *location;
char *full_uri_for_display;
char *uri_for_display;
char *error_message;
gboolean show_install_mime;
GtkWidget *dialog;
char *mime_type;
char *text;
ActivateParametersInstall *parameters_install;
location = nautilus_file_get_location (file);
full_uri_for_display = g_file_get_parse_name (location);
g_object_unref (location);
/* Truncate the URI so it doesn't get insanely wide. Note that even
* though the dialog uses wrapped text, if the URI doesn't contain
* white space then the text-wrapping code is too stupid to wrap it.
*/
uri_for_display = eel_str_middle_truncate (full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
g_free (full_uri_for_display);
error_message = g_strdup_printf (_("Could not display \"%s\"."), uri_for_display);
g_free (uri_for_display);
mime_type = nautilus_file_get_mime_type (file);
#ifdef ENABLE_PACKAGEKIT
/* allow an admin to disable the PackageKit search functionality */
show_install_mime = eel_preferences_get_boolean (NAUTILUS_PREFERENCES_INSTALL_MIME_ACTIVATION);
#else
/* we have no install functionality */
show_install_mime = FALSE;
#endif
/* There is no use trying to look for handlers of application/octet-stream */
if (g_content_type_is_unknown (mime_type)) {
show_install_mime = FALSE;
}
if (!show_install_mime) {
/* show an unhelpful dialog */
if (g_content_type_is_unknown (mime_type)) {
eel_show_error_dialog (error_message,
_("The file is of an unknown type"),
parameters->parent_window);
} else {
text = g_strdup_printf (_("There is no application installed for %s files"), g_content_type_get_description (mime_type));
eel_show_error_dialog (error_message,
text,
parameters->parent_window);
g_free (text);
}
goto out;
}
/* use a custom dialog to prompt the user to install new software */
dialog = gtk_message_dialog_new (NULL, 0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_YES_NO,
"%s", error_message);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
_("There is no application installed for %s files.\nDo you want to search for an application to open this file?"),
g_content_type_get_description (mime_type));
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
/* copy the parts of parameters we are interested in as the orignal will be unref'd */
parameters_install = g_new0 (ActivateParametersInstall, 1);
parameters_install->slot_info = parameters->slot_info;
g_object_add_weak_pointer (G_OBJECT (parameters_install->slot_info), (gpointer *)&parameters_install->slot_info);
if (parameters->parent_window) {
parameters_install->parent_window = parameters->parent_window;
g_object_add_weak_pointer (G_OBJECT (parameters_install->parent_window), (gpointer *)&parameters_install->parent_window);
}
parameters_install->activation_directory = g_strdup (parameters->activation_directory);
parameters_install->file = nautilus_file_ref (file);
parameters_install->files = nautilus_file_list_copy (parameters->files);
parameters_install->mode = parameters->mode;
parameters_install->flags = parameters->flags;
parameters_install->user_confirmation = parameters->user_confirmation;
g_signal_connect (dialog, "response", G_CALLBACK (application_unhandled_file_install), parameters_install);
gtk_widget_show_all (dialog);
out:
g_free (mime_type);
g_free (error_message);
}
typedef struct {
GtkWindow *parent_window;
NautilusFile *file;
} ActivateParametersDesktop;
static void
activate_parameters_desktop_free (ActivateParametersDesktop *parameters_desktop)
{
if (parameters_desktop->parent_window) {
g_object_remove_weak_pointer (G_OBJECT (parameters_desktop->parent_window), (gpointer *)&parameters_desktop->parent_window);
}
nautilus_file_unref (parameters_desktop->file);
g_free (parameters_desktop);
}
static void
untrusted_launcher_response_callback (GtkDialog *dialog,
int response_id,
ActivateParametersDesktop *parameters)
{
GdkScreen *screen;
char *uri;
GFile *file;
switch (response_id) {
case RESPONSE_RUN:
screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window));
uri = nautilus_file_get_uri (parameters->file);
nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
"directory view activate_callback launch_desktop_file window=%p: %s",
parameters->parent_window, uri);
nautilus_launch_desktop_file (screen, uri, NULL,
parameters->parent_window);
g_free (uri);
break;
case RESPONSE_MARK_TRUSTED:
file = nautilus_file_get_location (parameters->file);
nautilus_file_mark_desktop_file_trusted (file,
parameters->parent_window,
TRUE,
NULL, NULL);
g_object_unref (file);
break;
default:
/* Just destroy dialog */
break;
}
gtk_widget_destroy (GTK_WIDGET (dialog));
activate_parameters_desktop_free (parameters);
}
static void
activate_desktop_file (ActivateParameters *parameters,
NautilusFile *file)
{
ActivateParametersDesktop *parameters_desktop;
char *primary, *secondary, *display_name;
GtkWidget *dialog;
GdkScreen *screen;
char *uri;
screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window));
if (!nautilus_file_is_trusted_link (file)) {
/* copy the parts of parameters we are interested in as the orignal will be freed */
parameters_desktop = g_new0 (ActivateParametersDesktop, 1);
if (parameters->parent_window) {
parameters_desktop->parent_window = parameters->parent_window;
g_object_add_weak_pointer (G_OBJECT (parameters_desktop->parent_window), (gpointer *)&parameters_desktop->parent_window);
}
parameters_desktop->file = nautilus_file_ref (file);
primary = _("Untrusted application launcher");
display_name = nautilus_file_get_display_name (file);
secondary =
g_strdup_printf (_("The application launcher \"%s\" has not been marked as trusted. "
"If you do not know the source of this file, launching it may be unsafe."
),
display_name);
dialog = eel_alert_dialog_new (parameters->parent_window,
0,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
primary,
secondary);
gtk_dialog_add_button (GTK_DIALOG (dialog),
_("_Launch Anyway"), RESPONSE_RUN);
if (nautilus_file_can_set_permissions (file)) {
gtk_dialog_add_button (GTK_DIALOG (dialog),
_("Mark as _Trusted"), RESPONSE_MARK_TRUSTED);
}
gtk_dialog_add_button (GTK_DIALOG (dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
g_signal_connect (dialog, "response",
G_CALLBACK (untrusted_launcher_response_callback),
parameters_desktop);
gtk_widget_show (dialog);
g_free (display_name);
g_free (secondary);
return;
}
uri = nautilus_file_get_uri (file);
nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
"directory view activate_callback launch_desktop_file window=%p: %s",
parameters->parent_window, uri);
nautilus_launch_desktop_file (screen, uri, NULL,
parameters->parent_window);
g_free (uri);
}
static void
activate_files (ActivateParameters *parameters)
{
NautilusWindowInfo *window_info;
NautilusWindowOpenFlags flags;
NautilusFile *file;
GList *launch_desktop_files;
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;
char *uri;
char *executable_path, *quoted_path, *name;
char *old_working_dir;
ActivationAction action;
GdkScreen *screen;
screen = gtk_widget_get_screen (GTK_WIDGET (parameters->parent_window));
launch_desktop_files = NULL;
launch_files = NULL;
launch_in_terminal_files = NULL;
open_in_app_files = NULL;
open_in_view_files = NULL;
for (l = parameters->files; l != NULL; l = l->next) {
file = NAUTILUS_FILE (l->data);
if (file_was_cancelled (file)) {
continue;
}
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.
*/
pause_activation_timed_cancel (parameters);
action = get_executable_text_file_action (parameters->parent_window, file);
unpause_activation_timed_cancel (parameters);
}
switch (action) {
case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE :
launch_desktop_files = g_list_prepend (launch_desktop_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;
}
}
launch_desktop_files = g_list_reverse (launch_desktop_files);
for (l = launch_desktop_files; l != NULL; l = l->next) {
file = NAUTILUS_FILE (l->data);
activate_desktop_file (parameters, file);
}
old_working_dir = NULL;
if (parameters->activation_directory &&
(launch_files != NULL || launch_in_terminal_files != NULL)) {
old_working_dir = g_get_current_dir ();
g_chdir (parameters->activation_directory);
}
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 = g_filename_from_uri (uri, NULL, NULL);
quoted_path = g_shell_quote (executable_path);
name = nautilus_file_get_name (file);
nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
"directory view activate_callback launch_file window=%p: %s",
parameters->parent_window, quoted_path);
nautilus_launch_application_from_command (screen, name, quoted_path, FALSE, NULL);
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 = g_filename_from_uri (uri, NULL, NULL);
quoted_path = g_shell_quote (executable_path);
name = nautilus_file_get_name (file);
nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
"directory view activate_callback launch_in_terminal window=%p: %s",
parameters->parent_window, quoted_path);
nautilus_launch_application_from_command (screen, name, quoted_path, TRUE, NULL);
g_free (name);
g_free (quoted_path);
g_free (executable_path);
g_free (uri);
}
if (old_working_dir != NULL) {
g_chdir (old_working_dir);
g_free (old_working_dir);
}
open_in_view_files = g_list_reverse (open_in_view_files);
count = g_list_length (open_in_view_files);
flags = parameters->flags;
if (count > 1) {
if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ENABLE_TABS) &&
(parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) {
flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
} else {
flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
}
}
if (parameters->slot_info != NULL &&
(!parameters->user_confirmation ||
confirm_multiple_windows (parameters->parent_window, count,
(flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0))) {
if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0 &&
eel_preferences_get_enum (NAUTILUS_PREFERENCES_NEW_TAB_POSITION) ==
NAUTILUS_NEW_TAB_POSITION_AFTER_CURRENT_TAB) {
/* When inserting N tabs after the current one,
* we first open tab N, then tab N-1, ..., then tab 0.
* Each of them is appended to the current tab, i.e.
* prepended to the list of tabs to open.
*/
open_in_view_files = g_list_reverse (open_in_view_files);
}
for (l = open_in_view_files; l != NULL; l = l->next) {
GFile *f;
/* 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);
f = g_file_new_for_uri (uri);
nautilus_window_slot_info_open_location (parameters->slot_info,
f, parameters->mode, flags, NULL);
g_object_unref (f);
g_free (uri);
}
}
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);
}
for (l = open_in_app_parameters; l != NULL; l = l->next) {
one_parameters = l->data;
nautilus_launch_application (one_parameters->application,
one_parameters->files,
parameters->parent_window);
application_launch_parameters_free (one_parameters);
}
for (l = unhandled_open_in_app_files; l != NULL; l = l->next) {
file = NAUTILUS_FILE (l->data);
/* this does not block */
application_unhandled_file (parameters, file);
}
window_info = NULL;
if (parameters->slot_info != NULL) {
window_info = nautilus_window_slot_info_get_window (parameters->slot_info);
}
if (open_in_app_parameters != NULL ||
unhandled_open_in_app_files != NULL) {
if ((parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0 &&
window_info != NULL &&
nautilus_window_info_get_window_type (window_info) == NAUTILUS_WINDOW_SPATIAL) {
nautilus_window_info_close (window_info);
}
}
g_list_free (launch_desktop_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_list_free (open_in_app_parameters);
g_list_free (unhandled_open_in_app_files);
activation_parameters_free (parameters);
}
static void
activation_mount_not_mounted_callback (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
ActivateParameters *parameters = user_data;
GError *error;
NautilusFile *file;
GFile *location;
file = parameters->not_mounted->data;
error = NULL;
if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) {
if (error->domain != G_IO_ERROR ||
(error->code != G_IO_ERROR_CANCELLED &&
error->code != G_IO_ERROR_FAILED_HANDLED &&
error->code != G_IO_ERROR_ALREADY_MOUNTED)) {
eel_show_error_dialog (_("Unable to mount location"),
error->message, NULL);
}
if (error->domain != G_IO_ERROR ||
error->code != G_IO_ERROR_ALREADY_MOUNTED) {
parameters->files = g_list_remove (parameters->files, file);
nautilus_file_unref (file);
}
g_error_free (error);
} else {
location = nautilus_file_get_location (file);
g_object_unref (G_OBJECT (location));
}
parameters->not_mounted = g_list_delete_link (parameters->not_mounted,
parameters->not_mounted);
nautilus_file_unref (file);
activation_mount_not_mounted (parameters);
}
static void
activation_mount_not_mounted (ActivateParameters *parameters)
{
NautilusFile *file;
GFile *location;
GMountOperation *mount_op;
GList *l, *next;
if (parameters->not_mounted != NULL) {
file = parameters->not_mounted->data;
mount_op = gtk_mount_operation_new (parameters->parent_window);
g_signal_connect (mount_op, "notify::is-showing",
G_CALLBACK (activate_mount_op_active), parameters);
location = nautilus_file_get_location (file);
g_file_mount_enclosing_volume (location, 0, mount_op, parameters->cancellable,
activation_mount_not_mounted_callback, parameters);
g_object_unref (location);
/* unref mount_op here - g_file_mount_enclosing_volume() does ref for itself */
g_object_unref (mount_op);
return;
}
parameters->tried_mounting = TRUE;
if (parameters->files == NULL) {
activation_parameters_free (parameters);
return;
}
/* once the mount is finished, refresh all attributes */
/* - fixes new windows not appearing after successful mount */
for (l = parameters->files; l != NULL; l = next) {
file = NAUTILUS_FILE (l->data);
next = l->next;
nautilus_file_invalidate_all_attributes (file);
}
nautilus_file_list_call_when_ready
(parameters->files,
nautilus_mime_actions_get_required_file_attributes () | NAUTILUS_FILE_ATTRIBUTE_LINK_INFO,
&parameters->files_handle,
activate_callback, parameters);
}
static void
activate_callback (GList *files, gpointer callback_data)
{
ActivateParameters *parameters = callback_data;
GList *l, *next;
NautilusFile *file;
parameters->files_handle = NULL;
for (l = parameters->files; l != NULL; l = next) {
file = NAUTILUS_FILE (l->data);
next = l->next;
if (file_was_cancelled (file)) {
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
continue;
}
if (file_was_not_mounted (file)) {
if (parameters->tried_mounting) {
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
} else {
parameters->not_mounted = g_list_prepend (parameters->not_mounted,
nautilus_file_ref (file));
}
continue;
}
}
if (parameters->not_mounted != NULL) {
activation_mount_not_mounted (parameters);
} else {
activate_files (parameters);
}
}
static void
activate_activation_uris_ready_callback (GList *files_ignore,
gpointer callback_data)
{
ActivateParameters *parameters = callback_data;
GList *l, *next;
NautilusFile *file;
parameters->files_handle = NULL;
for (l = parameters->files; l != NULL; l = next) {
file = NAUTILUS_FILE (l->data);
next = l->next;
if (file_was_cancelled (file)) {
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
continue;
}
if (nautilus_file_is_broken_symbolic_link (file)) {
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
report_broken_symbolic_link (parameters->parent_window, file);
continue;
}
if (nautilus_file_get_file_type (file) == G_FILE_TYPE_MOUNTABLE &&
!nautilus_file_has_activation_uri (file)) {
/* Don't launch these... There is nothing we
can do */
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
continue;
}
}
if (parameters->files == NULL) {
activation_parameters_free (parameters);
return;
}
/* Convert the files to the actual activation uri files */
for (l = parameters->files; l != NULL; l = l->next) {
char *uri;
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.
*/
uri = nautilus_file_get_activation_uri (file);
if (uri != NULL) {
NautilusFile *actual_file;
actual_file = nautilus_file_get_by_uri (uri);
if (actual_file != NULL) {
nautilus_file_unref (file);
l->data = actual_file;
}
}
g_free (uri);
}
/* get the parameters for the actual files */
nautilus_file_list_call_when_ready
(parameters->files,
nautilus_mime_actions_get_required_file_attributes () | NAUTILUS_FILE_ATTRIBUTE_LINK_INFO,
&parameters->files_handle,
activate_callback, parameters);
}
static void
activation_get_activation_uris (ActivateParameters *parameters)
{
GList *l;
NautilusFile *file;
/* link target info might be stale, re-read it */
for (l = parameters->files; l != NULL; l = l->next) {
file = NAUTILUS_FILE (l->data);
if (file_was_cancelled (file)) {
nautilus_file_unref (file);
parameters->files = g_list_delete_link (parameters->files, l);
continue;
}
if (nautilus_file_is_symbolic_link (file)) {
nautilus_file_invalidate_attributes
(file,
NAUTILUS_FILE_ATTRIBUTE_INFO |
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
}
}
if (parameters->files == NULL) {
activation_parameters_free (parameters);
return;
}
nautilus_file_list_call_when_ready
(parameters->files,
NAUTILUS_FILE_ATTRIBUTE_INFO |
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO,
&parameters->files_handle,
activate_activation_uris_ready_callback, parameters);
}
static void
activation_mountable_mounted (NautilusFile *file,
GFile *result_location,
GError *error,
gpointer callback_data)
{
ActivateParameters *parameters = callback_data;
NautilusFile *target_file;
int position;
/* Remove from list of files that have to be mounted */
parameters->mountables = g_list_remove (parameters->mountables, file);
nautilus_file_unref (file);
if (error == NULL) {
/* Replace file with the result of the mount */
target_file = nautilus_file_get (result_location);
position = g_list_index (parameters->files, file);
parameters->files = g_list_remove (parameters->files, file);
nautilus_file_unref (file);
parameters->files = g_list_insert (parameters->files,
target_file,
position);
} else {
/* Remove failed file */
if (error->domain != G_IO_ERROR ||
(error->code != G_IO_ERROR_FAILED_HANDLED &&
error->code != G_IO_ERROR_ALREADY_MOUNTED)) {
parameters->files = g_list_remove (parameters->files, file);
nautilus_file_unref (file);
}
if (error->domain != G_IO_ERROR ||
(error->code != G_IO_ERROR_CANCELLED &&
error->code != G_IO_ERROR_FAILED_HANDLED &&
error->code != G_IO_ERROR_ALREADY_MOUNTED)) {
eel_show_error_dialog (_("Unable to mount location"),
error->message, NULL);
}
if (error->code == G_IO_ERROR_CANCELLED) {
activation_parameters_free (parameters);
return;
}
}
/* Mount more mountables */
activation_mount_mountables (parameters);
}
static void
activation_mount_mountables (ActivateParameters *parameters)
{
NautilusFile *file;
GMountOperation *mount_op;
if (parameters->mountables != NULL) {
file = parameters->mountables->data;
mount_op = gtk_mount_operation_new (parameters->parent_window);
g_signal_connect (mount_op, "notify::is-showing",
G_CALLBACK (activate_mount_op_active), parameters);
nautilus_file_mount (file,
mount_op,
parameters->cancellable,
activation_mountable_mounted,
parameters);
g_object_unref (mount_op);
return;
}
activation_get_activation_uris (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
nautilus_mime_activate_files (GtkWindow *parent_window,
NautilusWindowSlotInfo *slot_info,
GList *files,
const char *launch_directory,
NautilusWindowOpenMode mode,
NautilusWindowOpenFlags flags,
gboolean user_confirmation)
{
ActivateParameters *parameters;
char *file_name;
int file_count;
GList *l, *next;
NautilusFile *file;
if (files == NULL) {
return;
}
nautilus_debug_log_with_file_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, files,
"fm_directory_view_activate_files window=%p",
parent_window);
parameters = g_new0 (ActivateParameters, 1);
parameters->slot_info = slot_info;
g_object_add_weak_pointer (G_OBJECT (parameters->slot_info), (gpointer *)&parameters->slot_info);
if (parent_window) {
parameters->parent_window = parent_window;
g_object_add_weak_pointer (G_OBJECT (parameters->parent_window), (gpointer *)&parameters->parent_window);
}
parameters->cancellable = g_cancellable_new ();
parameters->activation_directory = g_strdup (launch_directory);
parameters->files = nautilus_file_list_copy (files);
parameters->mode = mode;
parameters->flags = flags;
parameters->user_confirmation = user_confirmation;
file_count = g_list_length (files);
if (file_count == 1) {
file_name = nautilus_file_get_display_name (files->data);
parameters->timed_wait_prompt = g_strdup_printf (_("Opening \"%s\"."), file_name);
g_free (file_name);
} else {
parameters->timed_wait_prompt = g_strdup_printf (ngettext ("Opening %d item.",
"Opening %d items.",
file_count),
file_count);
}
for (l = parameters->files; l != NULL; l = next) {
file = NAUTILUS_FILE (l->data);
next = l->next;
if (nautilus_file_can_mount (file)) {
parameters->mountables = g_list_prepend (parameters->mountables,
nautilus_file_ref (file));
}
}
activation_start_timed_cancel (parameters);
activation_mount_mountables (parameters);
}
/**
* fm_directory_view_activate_file:
*
* Activate a file in this view. This might involve switching the displayed
* location for the current window, or launching an application.
* @view: FMDirectoryView in question.
* @file: A NautilusFile representing the file in this view to activate.
* @use_new_window: Should this item be opened in a new window?
*
**/
void
nautilus_mime_activate_file (GtkWindow *parent_window,
NautilusWindowSlotInfo *slot_info,
NautilusFile *file,
const char *launch_directory,
NautilusWindowOpenMode mode,
NautilusWindowOpenFlags flags)
{
GList *files;
g_return_if_fail (NAUTILUS_IS_FILE (file));
files = g_list_prepend (NULL, file);
nautilus_mime_activate_files (parent_window, slot_info, files, launch_directory, mode, flags, FALSE);
g_list_free (files);
}