summaryrefslogtreecommitdiff
path: root/libcaja-private/caja-program-choosing.c
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-12-01 22:24:23 -0300
committerPerberos <[email protected]>2011-12-01 22:24:23 -0300
commit0e004c696b0e68b2cff37a4c3315b022a35eaf43 (patch)
tree43261e815529cb9518ed7be37af13b846af8b26b /libcaja-private/caja-program-choosing.c
downloadcaja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.bz2
caja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.xz
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'libcaja-private/caja-program-choosing.c')
-rw-r--r--libcaja-private/caja-program-choosing.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/libcaja-private/caja-program-choosing.c b/libcaja-private/caja-program-choosing.c
new file mode 100644
index 00000000..0a4b7f24
--- /dev/null
+++ b/libcaja-private/caja-program-choosing.c
@@ -0,0 +1,509 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* caja-program-choosing.c - functions for selecting and activating
+ programs for opening/viewing particular files.
+
+ Copyright (C) 2000 Eazel, Inc.
+
+ The Mate 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 Mate 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 Mate 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.
+
+ Author: John Sullivan <[email protected]>
+*/
+
+#include <config.h>
+#include "caja-program-choosing.h"
+
+#include "caja-mime-actions.h"
+#include "caja-global-preferences.h"
+#include "caja-icon-info.h"
+#include "caja-recent.h"
+#include "caja-desktop-icon-file.h"
+#include <eel/eel-glib-extensions.h>
+#include <eel/eel-mate-extensions.h>
+#include <eel/eel-stock-dialogs.h>
+#include <eel/eel-preferences.h>
+#include <eel/eel-string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <stdlib.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+/**
+ * application_cannot_open_location
+ *
+ * Handle the case where an application has been selected to be launched,
+ * and it cannot handle the current uri scheme. This can happen
+ * because the default application for a file type may not be able
+ * to handle some kinds of locations. We want to tell users that their
+ * default application doesn't work here, rather than switching off to
+ * a different one without them noticing.
+ *
+ * @application: The application that was to be launched.
+ * @file: The file whose location was passed as a parameter to the application
+ * @parent_window: A window to use as the parent for any error dialogs.
+ * */
+static void
+application_cannot_open_location (GAppInfo *application,
+ CajaFile *file,
+ const char *uri_scheme,
+ GtkWindow *parent_window)
+{
+#ifdef NEW_MIME_COMPLETE
+ GtkDialog *message_dialog;
+ LaunchParameters *launch_parameters;
+ char *prompt;
+ char *message;
+ char *file_name;
+ int response;
+
+ file_name = caja_file_get_display_name (file);
+
+ if (caja_mime_has_any_applications_for_file (file))
+ {
+ if (application != NULL)
+ {
+ prompt = _("Open Failed, would you like to choose another application?");
+ message = g_strdup_printf (_("\"%s\" cannot open \"%s\" because \"%s\" cannot access files at \"%s\" "
+ "locations."),
+ g_app_info_get_display_name (application), file_name,
+ g_app_info_get_display_name (application), uri_scheme);
+ }
+ else
+ {
+ prompt = _("Open Failed, would you like to choose another action?");
+ message = g_strdup_printf (_("The default action cannot open \"%s\" because it cannot access files at \"%s\" "
+ "locations."),
+ file_name, uri_scheme);
+ }
+
+ message_dialog = eel_show_yes_no_dialog (prompt,
+ message,
+ GTK_STOCK_OK,
+ GTK_STOCK_CANCEL,
+ parent_window);
+ response = gtk_dialog_run (message_dialog);
+ gtk_object_destroy (GTK_OBJECT (message_dialog));
+
+ if (response == GTK_RESPONSE_YES)
+ {
+ launch_parameters = launch_parameters_new (file, parent_window);
+ caja_choose_application_for_file
+ (file,
+ parent_window,
+ launch_application_callback,
+ launch_parameters);
+
+ }
+ g_free (message);
+ }
+ else
+ {
+ if (application != NULL)
+ {
+ prompt = g_strdup_printf (_("\"%s\" cannot open \"%s\" because \"%s\" cannot access files at \"%s\" "
+ "locations."), g_app_info_get_display_name (application), file_name,
+ g_app_info_get_display_name (application), uri_scheme);
+ message = _("No other applications are available to view this file. "
+ "If you copy this file onto your computer, you may be able to open "
+ "it.");
+ }
+ else
+ {
+ prompt = g_strdup_printf (_("The default action cannot open \"%s\" because it cannot access files at \"%s\" "
+ "locations."), file_name, uri_scheme);
+ message = _("No other actions are available to view this file. "
+ "If you copy this file onto your computer, you may be able to open "
+ "it.");
+ }
+
+ eel_show_info_dialog (prompt, message, parent_window);
+ g_free (prompt);
+ }
+
+ g_free (file_name);
+#endif
+}
+
+/**
+ * caja_launch_application:
+ *
+ * Fork off a process to launch an application with a given file as a
+ * parameter. Provide a parent window for error dialogs.
+ *
+ * @application: The application to be launched.
+ * @uris: The files whose locations should be passed as a parameter to the application.
+ * @parent_window: A window to use as the parent for any error dialogs.
+ */
+void
+caja_launch_application (GAppInfo *application,
+ GList *files,
+ GtkWindow *parent_window)
+{
+ GList *uris, *l;
+
+ uris = NULL;
+ for (l = files; l != NULL; l = l->next)
+ {
+ uris = g_list_prepend (uris, caja_file_get_activation_uri (l->data));
+ }
+ uris = g_list_reverse (uris);
+ caja_launch_application_by_uri (application, uris,
+ parent_window);
+ eel_g_list_free_deep (uris);
+}
+
+void
+caja_launch_application_by_uri (GAppInfo *application,
+ GList *uris,
+ GtkWindow *parent_window)
+{
+ char *uri, *uri_scheme;
+ GList *locations, *l;
+ GFile *location;
+ CajaFile *file;
+ gboolean result;
+ GError *error;
+ GdkAppLaunchContext *launch_context;
+ CajaIconInfo *icon;
+ int count, total;
+
+ g_assert (uris != NULL);
+
+ /* count the number of uris with local paths */
+ count = 0;
+ total = g_list_length (uris);
+ locations = NULL;
+ for (l = uris; l != NULL; l = l->next)
+ {
+ uri = l->data;
+
+ location = g_file_new_for_uri (uri);
+ if (g_file_is_native (location))
+ {
+ count++;
+ }
+ locations = g_list_prepend (locations, location);
+ }
+ locations = g_list_reverse (locations);
+
+ launch_context = gdk_app_launch_context_new ();
+ if (parent_window)
+ gdk_app_launch_context_set_screen (launch_context,
+ gtk_window_get_screen (parent_window));
+
+ file = caja_file_get_by_uri (uris->data);
+ icon = caja_file_get_icon (file, 48, 0);
+ caja_file_unref (file);
+ if (icon)
+ {
+ gdk_app_launch_context_set_icon_name (launch_context,
+ caja_icon_info_get_used_name (icon));
+ g_object_unref (icon);
+ }
+
+ error = NULL;
+
+ if (count == total)
+ {
+ /* All files are local, so we can use g_app_info_launch () with
+ * the file list we constructed before.
+ */
+ result = g_app_info_launch (application,
+ locations,
+ G_APP_LAUNCH_CONTEXT (launch_context),
+ &error);
+ }
+ else
+ {
+ /* Some files are non local, better use g_app_info_launch_uris ().
+ */
+ result = g_app_info_launch_uris (application,
+ uris,
+ G_APP_LAUNCH_CONTEXT (launch_context),
+ &error);
+ }
+
+ g_object_unref (launch_context);
+
+ if (!result)
+ {
+ if (error->domain == G_IO_ERROR &&
+ error->code == G_IO_ERROR_NOT_SUPPORTED)
+ {
+ uri_scheme = g_uri_parse_scheme (uris->data);
+ application_cannot_open_location (application,
+ file,
+ uri_scheme,
+ parent_window);
+ g_free (uri_scheme);
+ }
+ else
+ {
+#ifdef NEW_MIME_COMPLETE
+ caja_program_chooser_show_invalid_message
+ (MATE_VFS_MIME_ACTION_TYPE_APPLICATION, file, parent_window);
+#else
+ g_warning ("Cannot open app: %s\n", error->message);
+#endif
+ }
+ g_error_free (error);
+ }
+ else
+ {
+ for (l = uris; l != NULL; l = l->next)
+ {
+ file = caja_file_get_by_uri (l->data);
+ caja_recent_add_file (file, application);
+ caja_file_unref (file);
+ }
+ }
+
+ eel_g_object_list_free (locations);
+}
+
+/**
+ * caja_launch_application_from_command:
+ *
+ * Fork off a process to launch an application with a given uri as
+ * a parameter.
+ *
+ * @command_string: The application to be launched, with any desired
+ * command-line options.
+ * @...: Passed as parameters to the application after quoting each of them.
+ */
+void
+caja_launch_application_from_command (GdkScreen *screen,
+ const char *name,
+ const char *command_string,
+ gboolean use_terminal,
+ ...)
+{
+ char *full_command, *tmp;
+ char *quoted_parameter;
+ char *parameter;
+ va_list ap;
+
+ full_command = g_strdup (command_string);
+
+ va_start (ap, use_terminal);
+
+ while ((parameter = va_arg (ap, char *)) != NULL)
+ {
+ quoted_parameter = g_shell_quote (parameter);
+ tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
+ g_free (quoted_parameter);
+
+ g_free (full_command);
+ full_command = tmp;
+
+ }
+
+ va_end (ap);
+
+ if (use_terminal)
+ {
+ eel_mate_open_terminal_on_screen (full_command, screen);
+ }
+ else
+ {
+ gdk_spawn_command_line_on_screen (screen, full_command, NULL);
+ }
+
+ g_free (full_command);
+}
+
+/**
+ * caja_launch_application_from_command:
+ *
+ * Fork off a process to launch an application with a given uri as
+ * a parameter.
+ *
+ * @command_string: The application to be launched, with any desired
+ * command-line options.
+ * @parameters: Passed as parameters to the application after quoting each of them.
+ */
+void
+caja_launch_application_from_command_array (GdkScreen *screen,
+ const char *name,
+ const char *command_string,
+ gboolean use_terminal,
+ const char * const * parameters)
+{
+ char *full_command, *tmp;
+ char *quoted_parameter;
+ const char * const *p;
+
+ full_command = g_strdup (command_string);
+
+ if (parameters != NULL)
+ {
+ for (p = parameters; *p != NULL; p++)
+ {
+ quoted_parameter = g_shell_quote (*p);
+ tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
+ g_free (quoted_parameter);
+
+ g_free (full_command);
+ full_command = tmp;
+ }
+ }
+
+ if (use_terminal)
+ {
+ eel_mate_open_terminal_on_screen (full_command, screen);
+ }
+ else
+ {
+ gdk_spawn_command_line_on_screen (screen, full_command, NULL);
+ }
+
+ g_free (full_command);
+}
+
+void
+caja_launch_desktop_file (GdkScreen *screen,
+ const char *desktop_file_uri,
+ const GList *parameter_uris,
+ GtkWindow *parent_window)
+{
+ GError *error;
+ char *message, *desktop_file_path;
+ const GList *p;
+ GList *files;
+ int total, count;
+ GFile *file, *desktop_file;
+ GDesktopAppInfo *app_info;
+ GdkAppLaunchContext *context;
+
+ /* Don't allow command execution from remote locations
+ * to partially mitigate the security
+ * risk of executing arbitrary commands.
+ */
+ desktop_file = g_file_new_for_uri (desktop_file_uri);
+ desktop_file_path = g_file_get_path (desktop_file);
+ if (!g_file_is_native (desktop_file))
+ {
+ g_free (desktop_file_path);
+ g_object_unref (desktop_file);
+ eel_show_error_dialog
+ (_("Sorry, but you cannot execute commands from "
+ "a remote site."),
+ _("This is disabled due to security considerations."),
+ parent_window);
+
+ return;
+ }
+ g_object_unref (desktop_file);
+
+ app_info = g_desktop_app_info_new_from_filename (desktop_file_path);
+ g_free (desktop_file_path);
+ if (app_info == NULL)
+ {
+ eel_show_error_dialog
+ (_("There was an error launching the application."),
+ NULL,
+ parent_window);
+ return;
+ }
+
+ /* count the number of uris with local paths */
+ count = 0;
+ total = g_list_length ((GList *) parameter_uris);
+ files = NULL;
+ for (p = parameter_uris; p != NULL; p = p->next)
+ {
+ file = g_file_new_for_uri ((const char *) p->data);
+ if (g_file_is_native (file))
+ {
+ count++;
+ }
+ files = g_list_prepend (files, file);
+ }
+
+ /* check if this app only supports local files */
+ if (g_app_info_supports_files (G_APP_INFO (app_info)) &&
+ !g_app_info_supports_uris (G_APP_INFO (app_info)) &&
+ parameter_uris != NULL)
+ {
+ if (count == 0)
+ {
+ /* all files are non-local */
+ eel_show_error_dialog
+ (_("This drop target only supports local files."),
+ _("To open non-local files copy them to a local folder and then"
+ " drop them again."),
+ parent_window);
+
+ eel_g_object_list_free (files);
+ g_object_unref (app_info);
+ return;
+ }
+ else if (count != total)
+ {
+ /* some files are non-local */
+ eel_show_warning_dialog
+ (_("This drop target only supports local files."),
+ _("To open non-local files copy them to a local folder and then"
+ " drop them again. The local files you dropped have already been opened."),
+ parent_window);
+ }
+ }
+
+ error = NULL;
+ context = gdk_app_launch_context_new ();
+ /* TODO: Ideally we should accept a timestamp here instead of using GDK_CURRENT_TIME */
+ gdk_app_launch_context_set_timestamp (context, GDK_CURRENT_TIME);
+ gdk_app_launch_context_set_screen (context,
+ gtk_window_get_screen (parent_window));
+ if (count == total)
+ {
+ /* All files are local, so we can use g_app_info_launch () with
+ * the file list we constructed before.
+ */
+ g_app_info_launch (G_APP_INFO (app_info),
+ files,
+ G_APP_LAUNCH_CONTEXT (context),
+ &error);
+ }
+ else
+ {
+ /* Some files are non local, better use g_app_info_launch_uris ().
+ */
+ g_app_info_launch_uris (G_APP_INFO (app_info),
+ (GList *) parameter_uris,
+ G_APP_LAUNCH_CONTEXT (context),
+ &error);
+ }
+ if (error != NULL)
+ {
+ message = g_strconcat (_("Details: "), error->message, NULL);
+ eel_show_error_dialog
+ (_("There was an error launching the application."),
+ message,
+ parent_window);
+
+ g_error_free (error);
+ g_free (message);
+ }
+
+ eel_g_object_list_free (files);
+ g_object_unref (context);
+ g_object_unref (app_info);
+}