2008-05-05 Paolo Borelli <pborelli@katamail.com>
[nautilus.git] / libnautilus-private / nautilus-program-choosing.c
blob4b3e47d62b77fcee0ff3030964ff80fb1366e44c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* nautilus-program-choosing.c - functions for selecting and activating
4 programs for opening/viewing particular files.
6 Copyright (C) 2000 Eazel, Inc.
8 The Gnome Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The Gnome Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with the Gnome Library; see the file COPYING.LIB. If not,
20 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
23 Author: John Sullivan <sullivan@eazel.com>
26 #include <config.h>
27 #include "nautilus-program-choosing.h"
29 #include "nautilus-mime-actions.h"
30 #include "nautilus-global-preferences.h"
31 #include "nautilus-icon-info.h"
32 #include "nautilus-recent.h"
33 #include "nautilus-desktop-icon-file.h"
34 #include <eel/eel-glib-extensions.h>
35 #include <eel/eel-gnome-extensions.h>
36 #include <eel/eel-stock-dialogs.h>
37 #include <eel/eel-preferences.h>
38 #include <eel/eel-string.h>
39 #include <eel/eel-app-launch-context.h>
40 #include <gtk/gtk.h>
41 #include <glib/gi18n.h>
42 #include <gio/gio.h>
43 #include <gio/gdesktopappinfo.h>
44 #include <stdlib.h>
46 #include <gdk/gdk.h>
47 #include <gdk/gdkx.h>
49 /**
50 * application_cannot_open_location
52 * Handle the case where an application has been selected to be launched,
53 * and it cannot handle the current uri scheme. This can happen
54 * because the default application for a file type may not be able
55 * to handle some kinds of locations. We want to tell users that their
56 * default application doesn't work here, rather than switching off to
57 * a different one without them noticing.
59 * @application: The application that was to be launched.
60 * @file: The file whose location was passed as a parameter to the application
61 * @parent_window: A window to use as the parent for any error dialogs.
62 * */
63 static void
64 application_cannot_open_location (GAppInfo *application,
65 NautilusFile *file,
66 const char *uri_scheme,
67 GtkWindow *parent_window)
69 #ifdef NEW_MIME_COMPLETE
70 GtkDialog *message_dialog;
71 LaunchParameters *launch_parameters;
72 char *prompt;
73 char *message;
74 char *file_name;
75 int response;
77 file_name = nautilus_file_get_display_name (file);
79 if (nautilus_mime_has_any_applications_for_file (file)) {
80 if (application != NULL) {
81 prompt = _("Open Failed, would you like to choose another application?");
82 message = g_strdup_printf (_("\"%s\" cannot open \"%s\" because \"%s\" cannot access files at \"%s\" "
83 "locations."),
84 g_app_info_get_name (application), file_name,
85 g_app_info_get_name (application), uri_scheme);
86 } else {
87 prompt = _("Open Failed, would you like to choose another action?");
88 message = g_strdup_printf (_("The default action cannot open \"%s\" because it cannot access files at \"%s\" "
89 "locations."),
90 file_name, uri_scheme);
93 message_dialog = eel_show_yes_no_dialog (prompt,
94 message,
95 GTK_STOCK_OK,
96 GTK_STOCK_CANCEL,
97 parent_window);
98 response = gtk_dialog_run (message_dialog);
99 gtk_object_destroy (GTK_OBJECT (message_dialog));
101 if (response == GTK_RESPONSE_YES) {
102 launch_parameters = launch_parameters_new (file, parent_window);
103 nautilus_choose_application_for_file
104 (file,
105 parent_window,
106 launch_application_callback,
107 launch_parameters);
110 g_free (message);
111 } else {
112 if (application != NULL) {
113 prompt = g_strdup_printf (_("\"%s\" cannot open \"%s\" because \"%s\" cannot access files at \"%s\" "
114 "locations."), g_app_info_get_name (application), file_name,
115 g_app_info_get_name (application), uri_scheme);
116 message = _("No other applications are available to view this file. "
117 "If you copy this file onto your computer, you may be able to open "
118 "it.");
119 } else {
120 prompt = g_strdup_printf (_("The default action cannot open \"%s\" because it cannot access files at \"%s\" "
121 "locations."), file_name, uri_scheme);
122 message = _("No other actions are available to view this file. "
123 "If you copy this file onto your computer, you may be able to open "
124 "it.");
127 eel_show_info_dialog (prompt, message, parent_window);
128 g_free (prompt);
131 g_free (file_name);
132 #endif
136 * nautilus_launch_application:
138 * Fork off a process to launch an application with a given file as a
139 * parameter. Provide a parent window for error dialogs.
141 * @application: The application to be launched.
142 * @files: The files whose locations should be passed as a parameter to the application.
143 * @parent_window: A window to use as the parent for any error dialogs.
145 void
146 nautilus_launch_application (GAppInfo *application,
147 GList *files,
148 GtkWindow *parent_window)
150 char *uri_scheme;
151 GList *locations, *l;
152 GFile *location;
153 NautilusFile *file;
154 gboolean result;
155 GError *error;
156 EelAppLaunchContext *launch_context;
157 NautilusIconInfo *icon;
159 g_assert (files != NULL);
161 locations = NULL;
162 for (l = files; l != NULL; l = l->next) {
163 file = NAUTILUS_FILE (l->data);
165 location = nautilus_file_get_activation_location (file);
167 locations = g_list_prepend (locations, location);
169 locations = g_list_reverse (locations);
171 launch_context = eel_app_launch_context_new ();
172 if (parent_window)
173 eel_app_launch_context_set_screen (launch_context,
174 gtk_window_get_screen (parent_window));
176 file = NAUTILUS_FILE (files->data);
177 icon = nautilus_file_get_icon (file, 48, 0);
178 if (icon) {
179 eel_app_launch_context_set_icon_name (launch_context,
180 nautilus_icon_info_get_used_name (icon));
181 g_object_unref (icon);
184 error = NULL;
185 result = g_app_info_launch (application,
186 locations,
187 G_APP_LAUNCH_CONTEXT (launch_context),
188 &error);
190 g_object_unref (launch_context);
192 if (!result) {
193 if (error->domain == G_IO_ERROR &&
194 error->code == G_IO_ERROR_NOT_SUPPORTED) {
195 uri_scheme = nautilus_file_get_uri_scheme (NAUTILUS_FILE (files->data));
196 application_cannot_open_location (application,
197 file,
198 uri_scheme,
199 parent_window);
200 g_free (uri_scheme);
201 } else {
202 #ifdef NEW_MIME_COMPLETE
203 nautilus_program_chooser_show_invalid_message
204 (GNOME_VFS_MIME_ACTION_TYPE_APPLICATION, file, parent_window);
205 #else
206 g_warning ("Cannot open app: %s\n", error->message);
207 #endif
209 } else {
210 for (l = files; l != NULL; l = l->next) {
211 file = NAUTILUS_FILE (l->data);
213 nautilus_recent_add_file (file, application);
217 eel_g_object_list_free (locations);
221 * nautilus_launch_application_from_command:
223 * Fork off a process to launch an application with a given uri as
224 * a parameter.
226 * @command_string: The application to be launched, with any desired
227 * command-line options.
228 * @parameter: Passed as a parameter to the application as is.
230 void
231 nautilus_launch_application_from_command (GdkScreen *screen,
232 const char *name,
233 const char *command_string,
234 const char *parameter,
235 gboolean use_terminal)
237 char *full_command;
238 char *quoted_parameter;
240 if (parameter != NULL) {
241 quoted_parameter = g_shell_quote (parameter);
242 full_command = g_strconcat (command_string, " ", quoted_parameter, NULL);
243 g_free (quoted_parameter);
244 } else {
245 full_command = g_strdup (command_string);
248 if (use_terminal) {
249 eel_gnome_open_terminal_on_screen (full_command, screen);
250 } else {
251 gdk_spawn_command_line_on_screen (screen, full_command, NULL);
254 g_free (full_command);
257 void
258 nautilus_launch_desktop_file (GdkScreen *screen,
259 const char *desktop_file_uri,
260 const GList *parameter_uris,
261 GtkWindow *parent_window)
263 GError *error;
264 char *message, *desktop_file_path;
265 const GList *p;
266 GList *files;
267 int total, count;
268 GFile *file, *desktop_file;
269 GDesktopAppInfo *app_info;
270 EelAppLaunchContext *context;
272 /* Don't allow command execution from remote locations
273 * to partially mitigate the security
274 * risk of executing arbitrary commands.
276 desktop_file = g_file_new_for_uri (desktop_file_uri);
277 desktop_file_path = g_file_get_path (desktop_file);
278 if (!g_file_is_native (desktop_file)) {
279 g_free (desktop_file_path);
280 g_object_unref (desktop_file);
281 eel_show_error_dialog
282 (_("Sorry, but you cannot execute commands from "
283 "a remote site."),
284 _("This is disabled due to security considerations."),
285 parent_window);
287 return;
289 g_object_unref (desktop_file);
291 app_info = g_desktop_app_info_new_from_filename (desktop_file_path);
292 g_free (desktop_file_path);
293 if (app_info == NULL) {
294 eel_show_error_dialog
295 (_("There was an error launching the application."),
296 NULL,
297 parent_window);
298 return;
301 /* count the number of uris with local paths */
302 count = 0;
303 total = g_list_length ((GList *) parameter_uris);
304 files = NULL;
305 for (p = parameter_uris; p != NULL; p = p->next) {
306 file = g_file_new_for_uri ((const char *) p->data);
307 if (g_file_is_native (file)) {
308 count++;
310 files = g_list_prepend (files, file);
313 /* check if this app only supports local files */
314 if (g_app_info_supports_files (G_APP_INFO (app_info)) &&
315 !g_app_info_supports_uris (G_APP_INFO (app_info)) &&
316 parameter_uris != NULL) {
317 if (count == 0) {
318 /* all files are non-local */
319 eel_show_error_dialog
320 (_("This drop target only supports local files."),
321 _("To open non-local files copy them to a local folder and then"
322 " drop them again."),
323 parent_window);
325 eel_g_object_list_free (files);
326 g_object_unref (app_info);
327 return;
328 } else if (count != total) {
329 /* some files are non-local */
330 eel_show_warning_dialog
331 (_("This drop target only supports local files."),
332 _("To open non-local files copy them to a local folder and then"
333 " drop them again. The local files you dropped have already been opened."),
334 parent_window);
338 error = NULL;
339 context = eel_app_launch_context_new ();
340 /* TODO: Ideally we should accept a timestamp here instead of using GDK_CURRENT_TIME */
341 eel_app_launch_context_set_timestamp (context, GDK_CURRENT_TIME);
342 eel_app_launch_context_set_screen (context,
343 gtk_window_get_screen (parent_window));
344 if (count == total) {
345 /* All files are local, so we can use g_app_info_launch () with
346 * the file list we constructed before.
348 g_app_info_launch (G_APP_INFO (app_info),
349 files,
350 G_APP_LAUNCH_CONTEXT (context),
351 &error);
352 } else {
353 /* Some files are non local, better use g_app_info_launch_uris ().
355 g_app_info_launch_uris (G_APP_INFO (app_info),
356 (GList *) parameter_uris,
357 G_APP_LAUNCH_CONTEXT (context),
358 &error);
360 if (error != NULL) {
361 message = g_strconcat (_("Details: "), error->message, NULL);
362 eel_show_error_dialog
363 (_("There was an error launching the application."),
364 message,
365 parent_window);
367 g_error_free (error);
368 g_free (message);
371 eel_g_object_list_free (files);
372 g_object_unref (context);
373 g_object_unref (app_info);