No issues found
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* nautilus-program-choosing.c - functions for selecting and activating
4 programs for opening/viewing particular files.
5
6 Copyright (C) 2000 Eazel, Inc.
7
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.
12
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.
17
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.
22
23 Author: John Sullivan <sullivan@eazel.com>
24 */
25
26 #include <config.h>
27 #include "nautilus-program-choosing.h"
28
29 #include "nautilus-global-preferences.h"
30 #include "nautilus-icon-info.h"
31 #include "nautilus-recent.h"
32 #include "nautilus-desktop-icon-file.h"
33 #include <eel/eel-gnome-extensions.h>
34 #include <eel/eel-stock-dialogs.h>
35 #include <gtk/gtk.h>
36 #include <glib/gi18n.h>
37 #include <gio/gio.h>
38 #include <gio/gdesktopappinfo.h>
39 #include <stdlib.h>
40
41 #include <gdk/gdk.h>
42 #include <gdk/gdkx.h>
43
44 void
45 nautilus_launch_application_for_mount (GAppInfo *app_info,
46 GMount *mount,
47 GtkWindow *parent_window)
48 {
49 GFile *root;
50 NautilusFile *file;
51 GList *files;
52
53 root = g_mount_get_root (mount);
54 file = nautilus_file_get (root);
55 g_object_unref (root);
56
57 files = g_list_append (NULL, file);
58 nautilus_launch_application (app_info,
59 files,
60 parent_window);
61
62 g_list_free_full (files, (GDestroyNotify) nautilus_file_unref);
63 }
64
65 /**
66 * nautilus_launch_application:
67 *
68 * Fork off a process to launch an application with a given file as a
69 * parameter. Provide a parent window for error dialogs.
70 *
71 * @application: The application to be launched.
72 * @uris: The files whose locations should be passed as a parameter to the application.
73 * @parent_window: A window to use as the parent for any error dialogs.
74 */
75 void
76 nautilus_launch_application (GAppInfo *application,
77 GList *files,
78 GtkWindow *parent_window)
79 {
80 GList *uris, *l;
81
82 uris = NULL;
83 for (l = files; l != NULL; l = l->next) {
84 uris = g_list_prepend (uris, nautilus_file_get_activation_uri (l->data));
85 }
86 uris = g_list_reverse (uris);
87 nautilus_launch_application_by_uri (application, uris,
88 parent_window);
89 g_list_free_full (uris, g_free);
90 }
91
92 void
93 nautilus_launch_application_by_uri (GAppInfo *application,
94 GList *uris,
95 GtkWindow *parent_window)
96 {
97 char *uri;
98 GList *locations, *l;
99 GFile *location;
100 NautilusFile *file;
101 gboolean result;
102 GError *error;
103 GdkDisplay *display;
104 GdkAppLaunchContext *launch_context;
105 NautilusIconInfo *icon;
106 int count, total;
107
108 g_assert (uris != NULL);
109
110 /* count the number of uris with local paths */
111 count = 0;
112 total = g_list_length (uris);
113 locations = NULL;
114 for (l = uris; l != NULL; l = l->next) {
115 uri = l->data;
116
117 location = g_file_new_for_uri (uri);
118 if (g_file_is_native (location)) {
119 count++;
120 }
121 locations = g_list_prepend (locations, location);
122 }
123 locations = g_list_reverse (locations);
124
125 if (parent_window != NULL) {
126 display = gtk_widget_get_display (GTK_WIDGET (parent_window));
127 } else {
128 display = gdk_display_get_default ();
129 }
130
131 launch_context = gdk_display_get_app_launch_context (display);
132
133 if (parent_window != NULL) {
134 gdk_app_launch_context_set_screen (launch_context,
135 gtk_window_get_screen (parent_window));
136 }
137
138 file = nautilus_file_get_by_uri (uris->data);
139 icon = nautilus_file_get_icon (file, 48, 0);
140 nautilus_file_unref (file);
141 if (icon) {
142 gdk_app_launch_context_set_icon_name (launch_context,
143 nautilus_icon_info_get_used_name (icon));
144 g_object_unref (icon);
145 }
146
147 error = NULL;
148
149 if (count == total) {
150 /* All files are local, so we can use g_app_info_launch () with
151 * the file list we constructed before.
152 */
153 result = g_app_info_launch (application,
154 locations,
155 G_APP_LAUNCH_CONTEXT (launch_context),
156 &error);
157 } else {
158 /* Some files are non local, better use g_app_info_launch_uris ().
159 */
160 result = g_app_info_launch_uris (application,
161 uris,
162 G_APP_LAUNCH_CONTEXT (launch_context),
163 &error);
164 }
165
166 g_object_unref (launch_context);
167
168 if (result) {
169 for (l = uris; l != NULL; l = l->next) {
170 file = nautilus_file_get_by_uri (l->data);
171 nautilus_recent_add_file (file, application);
172 nautilus_file_unref (file);
173 }
174 }
175
176 g_list_free_full (locations, g_object_unref);
177 }
178
179 static void
180 launch_application_from_command_internal (const gchar *full_command,
181 GdkScreen *screen,
182 gboolean use_terminal)
183 {
184 GAppInfo *app;
185 GdkAppLaunchContext *ctx;
186 GdkDisplay *display;
187
188 if (use_terminal) {
189 eel_gnome_open_terminal_on_screen (full_command, screen);
190 } else {
191 app = g_app_info_create_from_commandline (full_command, NULL, 0, NULL);
192
193 if (app != NULL) {
194 display = gdk_screen_get_display (screen);
195 ctx = gdk_display_get_app_launch_context (display);
196 gdk_app_launch_context_set_screen (ctx, screen);
197
198 g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (ctx), NULL);
199
200 g_object_unref (app);
201 g_object_unref (ctx);
202 }
203 }
204 }
205
206 /**
207 * nautilus_launch_application_from_command:
208 *
209 * Fork off a process to launch an application with a given uri as
210 * a parameter.
211 *
212 * @command_string: The application to be launched, with any desired
213 * command-line options.
214 * @...: Passed as parameters to the application after quoting each of them.
215 */
216 void
217 nautilus_launch_application_from_command (GdkScreen *screen,
218 const char *command_string,
219 gboolean use_terminal,
220 ...)
221 {
222 char *full_command, *tmp;
223 char *quoted_parameter;
224 char *parameter;
225 va_list ap;
226
227 full_command = g_strdup (command_string);
228
229 va_start (ap, use_terminal);
230
231 while ((parameter = va_arg (ap, char *)) != NULL) {
232 quoted_parameter = g_shell_quote (parameter);
233 tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
234 g_free (quoted_parameter);
235
236 g_free (full_command);
237 full_command = tmp;
238
239 }
240
241 va_end (ap);
242
243 launch_application_from_command_internal (full_command, screen, use_terminal);
244
245 g_free (full_command);
246 }
247
248 /**
249 * nautilus_launch_application_from_command:
250 *
251 * Fork off a process to launch an application with a given uri as
252 * a parameter.
253 *
254 * @command_string: The application to be launched, with any desired
255 * command-line options.
256 * @parameters: Passed as parameters to the application after quoting each of them.
257 */
258 void
259 nautilus_launch_application_from_command_array (GdkScreen *screen,
260 const char *command_string,
261 gboolean use_terminal,
262 const char * const * parameters)
263 {
264 char *full_command, *tmp;
265 char *quoted_parameter;
266 const char * const *p;
267
268 full_command = g_strdup (command_string);
269
270 if (parameters != NULL) {
271 for (p = parameters; *p != NULL; p++) {
272 quoted_parameter = g_shell_quote (*p);
273 tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
274 g_free (quoted_parameter);
275
276 g_free (full_command);
277 full_command = tmp;
278 }
279 }
280
281 launch_application_from_command_internal (full_command, screen, use_terminal);
282
283 g_free (full_command);
284 }
285
286 void
287 nautilus_launch_desktop_file (GdkScreen *screen,
288 const char *desktop_file_uri,
289 const GList *parameter_uris,
290 GtkWindow *parent_window)
291 {
292 GError *error;
293 char *message, *desktop_file_path;
294 const GList *p;
295 GList *files;
296 int total, count;
297 GFile *file, *desktop_file;
298 GDesktopAppInfo *app_info;
299 GdkAppLaunchContext *context;
300
301 /* Don't allow command execution from remote locations
302 * to partially mitigate the security
303 * risk of executing arbitrary commands.
304 */
305 desktop_file = g_file_new_for_uri (desktop_file_uri);
306 desktop_file_path = g_file_get_path (desktop_file);
307 if (!g_file_is_native (desktop_file)) {
308 g_free (desktop_file_path);
309 g_object_unref (desktop_file);
310 eel_show_error_dialog
311 (_("Sorry, but you cannot execute commands from "
312 "a remote site."),
313 _("This is disabled due to security considerations."),
314 parent_window);
315
316 return;
317 }
318 g_object_unref (desktop_file);
319
320 app_info = g_desktop_app_info_new_from_filename (desktop_file_path);
321 g_free (desktop_file_path);
322 if (app_info == NULL) {
323 eel_show_error_dialog
324 (_("There was an error launching the application."),
325 NULL,
326 parent_window);
327 return;
328 }
329
330 /* count the number of uris with local paths */
331 count = 0;
332 total = g_list_length ((GList *) parameter_uris);
333 files = NULL;
334 for (p = parameter_uris; p != NULL; p = p->next) {
335 file = g_file_new_for_uri ((const char *) p->data);
336 if (g_file_is_native (file)) {
337 count++;
338 }
339 files = g_list_prepend (files, file);
340 }
341
342 /* check if this app only supports local files */
343 if (g_app_info_supports_files (G_APP_INFO (app_info)) &&
344 !g_app_info_supports_uris (G_APP_INFO (app_info)) &&
345 parameter_uris != NULL) {
346 if (count == 0) {
347 /* all files are non-local */
348 eel_show_error_dialog
349 (_("This drop target only supports local files."),
350 _("To open non-local files copy them to a local folder and then"
351 " drop them again."),
352 parent_window);
353
354 g_list_free_full (files, g_object_unref);
355 g_object_unref (app_info);
356 return;
357 } else if (count != total) {
358 /* some files are non-local */
359 eel_show_warning_dialog
360 (_("This drop target only supports local files."),
361 _("To open non-local files copy them to a local folder and then"
362 " drop them again. The local files you dropped have already been opened."),
363 parent_window);
364 }
365 }
366
367 error = NULL;
368 context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (parent_window)));
369 /* TODO: Ideally we should accept a timestamp here instead of using GDK_CURRENT_TIME */
370 gdk_app_launch_context_set_timestamp (context, GDK_CURRENT_TIME);
371 gdk_app_launch_context_set_screen (context,
372 gtk_window_get_screen (parent_window));
373 if (count == total) {
374 /* All files are local, so we can use g_app_info_launch () with
375 * the file list we constructed before.
376 */
377 g_app_info_launch (G_APP_INFO (app_info),
378 files,
379 G_APP_LAUNCH_CONTEXT (context),
380 &error);
381 } else {
382 /* Some files are non local, better use g_app_info_launch_uris ().
383 */
384 g_app_info_launch_uris (G_APP_INFO (app_info),
385 (GList *) parameter_uris,
386 G_APP_LAUNCH_CONTEXT (context),
387 &error);
388 }
389 if (error != NULL) {
390 message = g_strconcat (_("Details: "), error->message, NULL);
391 eel_show_error_dialog
392 (_("There was an error launching the application."),
393 message,
394 parent_window);
395
396 g_error_free (error);
397 g_free (message);
398 }
399
400 g_list_free_full (files, g_object_unref);
401 g_object_unref (context);
402 g_object_unref (app_info);
403 }