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)
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
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
29 #include <sys/param.h>
33 #include "gui_support.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
;
55 /****************************************************************
56 * EXTERNAL INTERFACE *
57 ****************************************************************/
60 /* An application has been double-clicked (or run in some other way) */
61 void run_app(char *path
)
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
)
85 if (stat(path
, &info
))
87 delayed_error(PROJECT
, _("Program not found - deleted?"));
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
;
100 char *uri
= (char *) uri_list
->data
;
103 local
= get_local_path(uri
);
105 argv
[argc
++] = local
;
108 uri_list
= uri_list
->next
;
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
};
127 if (stat(path
, &info
))
129 delayed_error(PROJECT
, _("Program not found - deleted?"));
133 if (S_ISDIR(info
.st_mode
))
134 argv
[0] = make_path(path
, "AppRun")->str
;
140 delayed_error("pipe() failed", g_strerror(errno
));
143 close_on_exec(fds
[1], TRUE
);
144 close_on_exec(fds
[0], TRUE
);
149 delayed_error("fork() failed", g_strerror(errno
));
153 /* We are the child */
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",
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
));
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
);
176 pd
->tag
= gdk_input_add(fds
[1], GDK_INPUT_WRITE
,
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
,
194 FilerWindow
*filer_window
,
197 if (filer_window
&& filer_window
->panel_type
)
200 if (item
->flags
& ITEM_FLAG_SYMLINK
&& edit
)
201 return follow_symlink(full_path
, filer_window
);
203 switch (item
->base_type
)
206 if (item
->flags
& ITEM_FLAG_APPDIR
&& !edit
)
212 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& edit
)
216 paths
= g_list_prepend(NULL
, full_path
);
219 if (item
->flags
& ITEM_FLAG_MOUNTED
)
224 filer_change_to(filer_window
, full_path
, NULL
);
226 filer_opendir(full_path
, PANEL_NO
);
229 if ((item
->flags
& ITEM_FLAG_EXEC_FILE
) && !edit
)
231 char *argv
[] = {NULL
, NULL
};
232 guchar
*dir
= filer_window
? filer_window
->path
237 if (spawn_full(argv
, dir
))
241 report_error(PROJECT
,
242 _("Failed to fork() child"));
247 return open_file(full_path
, edit
? &text_plain
250 report_error("open_item",
251 "I don't know how to open that");
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
)
270 sent
= write(fd
, pd
->data
+ pd
->sent
, pd
->length
- pd
->sent
);
276 delayed_error(_("ROX-Filer - Sending data to program"),
285 gdk_input_remove(pd
->tag
);
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
)
298 char path
[MAXPATHLEN
+ 1];
301 got
= readlink(full_path
, path
, MAXPATHLEN
);
304 delayed_error(PROJECT
, g_strerror(errno
));
308 g_return_val_if_fail(got
<= MAXPATHLEN
, FALSE
);
311 /* Make a relative path absolute */
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
);
323 real
= pathdup(path
);
325 slash
= strrchr(real
, '/');
329 delayed_error(PROJECT
,
330 _("Broken symlink (or you don't have permission "
343 filer_change_to(filer_window
, new_dir
, slash
+ 1);
348 new = filer_opendir(new_dir
, PANEL_NO
);
349 display_set_autoselect(new, slash
+ 1);
357 /* Load this file into an appropriate editor */
358 static gboolean
open_file(guchar
*path
, MIME_type
*type
)
362 g_return_val_if_fail(type
!= NULL
, FALSE
);
364 if (type_open(path
, type
))
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"),
374 report_error(PROJECT
, message
->str
);
375 g_string_free(message
, TRUE
);