r327: Files can now be dragged to pinboard icons, and they highlight nicely too!
[rox-filer/ma.git] / ROX-Filer / src / run.c
blobc476cb9d977f328ac84f3183c95f818901058e99
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* run.c */
24 #include "config.h"
26 #include <sys/stat.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <sys/param.h>
31 #include "stdlib.h"
32 #include "support.h"
33 #include "gui_support.h"
34 #include "filer.h"
35 #include "menu.h"
36 #include "main.h"
37 #include "action.h"
39 /* Static prototypes */
40 static void write_data(gpointer data, gint fd, GdkInputCondition cond);
41 static gboolean follow_symlink(char *full_path, FilerWindow *filer_window);
42 static gboolean open_file(guchar *path, MIME_type *type);
44 typedef struct _PipedData PipedData;
46 struct _PipedData
48 guchar *data;
49 gint tag;
50 gulong sent;
51 gulong length;
55 /****************************************************************
56 * EXTERNAL INTERFACE *
57 ****************************************************************/
60 /* An application has been double-clicked (or run in some other way) */
61 void run_app(char *path)
63 GString *apprun;
64 char *argv[] = {NULL, NULL};
66 apprun = g_string_new(path);
67 argv[0] = g_string_append(apprun, "/AppRun")->str;
69 if (!spawn_full(argv, home_dir))
70 report_error(PROJECT, "Failed to fork() child process");
72 g_string_free(apprun, TRUE);
75 /* Execute this program, passing all the URIs in the list as arguments.
76 * URIs that are files on the local machine will be passed as simple
77 * pathnames. The uri_list should be freed after this function returns.
79 void run_with_files(char *path, GSList *uri_list)
81 char **argv;
82 int argc = 0;
83 struct stat info;
85 if (stat(path, &info))
87 delayed_error(PROJECT, _("Program not found - deleted?"));
88 return;
91 argv = g_malloc(sizeof(char *) * (g_slist_length(uri_list) + 2));
93 if (S_ISDIR(info.st_mode))
94 argv[argc++] = make_path(path, "AppRun")->str;
95 else
96 argv[argc++] = path;
98 while (uri_list)
100 char *uri = (char *) uri_list->data;
101 char *local;
103 local = get_local_path(uri);
104 if (local)
105 argv[argc++] = local;
106 else
107 argv[argc++] = uri;
108 uri_list = uri_list->next;
111 argv[argc++] = NULL;
113 if (!spawn_full(argv, home_dir))
114 delayed_error(PROJECT, _("Failed to fork() child process"));
117 /* Run the program as '<path> -', piping the data to it via stdin.
118 * You can g_free() the data as soon as this returns.
120 void run_with_data(char *path, gpointer data, gulong length)
122 char *argv[] = {NULL, "-", NULL};
123 struct stat info;
124 int fds[2];
125 PipedData *pd;
127 if (stat(path, &info))
129 delayed_error(PROJECT, _("Program not found - deleted?"));
130 return;
133 if (S_ISDIR(info.st_mode))
134 argv[0] = make_path(path, "AppRun")->str;
135 else
136 argv[0] = path;
138 if (pipe(fds))
140 delayed_error("pipe() failed", g_strerror(errno));
141 return;
143 close_on_exec(fds[1], TRUE);
144 close_on_exec(fds[0], TRUE);
146 switch (fork())
148 case -1:
149 delayed_error("fork() failed", g_strerror(errno));
150 close(fds[1]);
151 break;
152 case 0:
153 /* We are the child */
154 chdir(home_dir);
155 dup2(to_error_log, STDERR_FILENO);
156 close_on_exec(STDERR_FILENO, FALSE);
157 if (dup2(fds[0], 0) == -1)
158 g_warning("dup2() failed: %s\n",
159 g_strerror(errno));
160 else
162 close_on_exec(0, FALSE);
163 if (execv(argv[0], argv))
164 g_warning("execv(%s) failed: %s\n",
165 argv[0], g_strerror(errno));
167 _exit(1);
168 default:
169 /* We are the parent */
170 set_blocking(fds[1], FALSE);
171 pd = g_new(PipedData, 1);
172 pd->data = g_malloc(length);
173 memcpy(pd->data, data, length);
174 pd->length = length;
175 pd->sent = 0;
176 pd->tag = gdk_input_add(fds[1], GDK_INPUT_WRITE,
177 write_data, pd);
178 break;
181 close(fds[0]);
184 /* Load a file, open a directory or run an application. Or, if 'edit' is set:
185 * edit a file, open an application, follow a symlink or mount a device.
187 * filer_window is the window to use for displaying a directory.
188 * NULL will always use a new directory when needed.
190 * Returns TRUE on success.
192 gboolean run_diritem(guchar *full_path,
193 DirItem *item,
194 FilerWindow *filer_window,
195 gboolean edit)
197 if (filer_window && filer_window->panel_type)
198 filer_window = NULL;
200 if (item->flags & ITEM_FLAG_SYMLINK && edit)
201 return follow_symlink(full_path, filer_window);
203 switch (item->base_type)
205 case TYPE_DIRECTORY:
206 if (item->flags & ITEM_FLAG_APPDIR && !edit)
208 run_app(full_path);
209 return TRUE;
212 if (item->flags & ITEM_FLAG_MOUNT_POINT && edit)
214 GList *paths;
216 paths = g_list_prepend(NULL, full_path);
217 action_mount(paths);
218 g_list_free(paths);
219 if (item->flags & ITEM_FLAG_MOUNTED)
220 return TRUE;
223 if (filer_window)
224 filer_change_to(filer_window, full_path, NULL);
225 else
226 filer_opendir(full_path, PANEL_NO);
227 return TRUE;
228 case TYPE_FILE:
229 if ((item->flags & ITEM_FLAG_EXEC_FILE) && !edit)
231 char *argv[] = {NULL, NULL};
232 guchar *dir = filer_window ? filer_window->path
233 : NULL;
235 argv[0] = full_path;
237 if (spawn_full(argv, dir))
238 return TRUE;
239 else
241 report_error(PROJECT,
242 _("Failed to fork() child"));
243 return FALSE;
247 return open_file(full_path, edit ? &text_plain
248 : item->mime_type);
249 default:
250 report_error("open_item",
251 "I don't know how to open that");
252 return FALSE;
257 /****************************************************************
258 * INTERNAL FUNCTIONS *
259 ****************************************************************/
262 static void write_data(gpointer data, gint fd, GdkInputCondition cond)
264 PipedData *pd = (PipedData *) data;
266 while (pd->sent < pd->length)
268 int sent;
270 sent = write(fd, pd->data + pd->sent, pd->length - pd->sent);
272 if (sent < 0)
274 if (errno == EAGAIN)
275 return;
276 delayed_error(_("ROX-Filer - Sending data to program"),
277 g_strerror(errno));
278 goto finish;
281 pd->sent += sent;
284 finish:
285 gdk_input_remove(pd->tag);
286 g_free(pd->data);
287 g_free(pd);
288 close(fd);
291 /* Follow the link 'full_path' and display it in filer_window, or a
292 * new window if that is NULL.
294 static gboolean follow_symlink(char *full_path, FilerWindow *filer_window)
296 char *real, *slash;
297 char *new_dir;
298 char path[MAXPATHLEN + 1];
299 int got;
301 got = readlink(full_path, path, MAXPATHLEN);
302 if (got < 0)
304 delayed_error(PROJECT, g_strerror(errno));
305 return FALSE;
308 g_return_val_if_fail(got <= MAXPATHLEN, FALSE);
309 path[got] = '\0';
311 /* Make a relative path absolute */
312 if (path[0] != '/')
314 guchar *tmp;
315 slash = strrchr(full_path, '/');
316 g_return_val_if_fail(slash != NULL, FALSE);
318 tmp = g_strndup(full_path, slash - full_path);
319 real = pathdup(make_path(tmp, path)->str);
320 g_free(tmp);
322 else
323 real = pathdup(path);
325 slash = strrchr(real, '/');
326 if (!slash)
328 g_free(real);
329 delayed_error(PROJECT,
330 _("Broken symlink (or you don't have permission "
331 "to follow it)."));
332 return FALSE;
335 *slash = '\0';
337 if (*real)
338 new_dir = real;
339 else
340 new_dir = "/";
342 if (filer_window)
343 filer_change_to(filer_window, new_dir, slash + 1);
344 else
346 FilerWindow *new;
348 new = filer_opendir(new_dir, PANEL_NO);
349 display_set_autoselect(new, slash + 1);
352 g_free(real);
354 return TRUE;
357 /* Load this file into an appropriate editor */
358 static gboolean open_file(guchar *path, MIME_type *type)
360 GString *message;
362 g_return_val_if_fail(type != NULL, FALSE);
364 if (type_open(path, type))
365 return TRUE;
367 message = g_string_new(NULL);
368 g_string_sprintf(message,
369 _("No run action specified for files of this type (%s/%s) - "
370 "you can set a run action using by choosing `Set Run Action' "
371 "from the Window menu"),
372 type->media_type,
373 type->subtype);
374 report_error(PROJECT, message->str);
375 g_string_free(message, TRUE);
377 return FALSE;