4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@users.sourceforge.net>.
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
28 #include <sys/param.h>
34 #include "gui_support.h"
43 /* Static prototypes */
44 static void write_data(gpointer data
, gint fd
, GdkInputCondition cond
);
45 static gboolean
follow_symlink(char *full_path
, FilerWindow
*filer_window
);
46 static gboolean
open_file(guchar
*path
, MIME_type
*type
);
47 static void app_show_help(char *path
);
49 typedef struct _PipedData PipedData
;
60 /****************************************************************
61 * EXTERNAL INTERFACE *
62 ****************************************************************/
65 /* An application has been double-clicked (or run in some other way) */
66 void run_app(char *path
)
69 char *argv
[] = {NULL
, NULL
};
71 apprun
= g_string_new(path
);
72 argv
[0] = g_string_append(apprun
, "/AppRun")->str
;
74 if (!spawn_full(argv
, home_dir
))
75 report_error(PROJECT
, "Failed to fork() child process");
77 g_string_free(apprun
, TRUE
);
80 /* Execute this program, passing all the URIs in the list as arguments.
81 * URIs that are files on the local machine will be passed as simple
82 * pathnames. The uri_list should be freed after this function returns.
84 void run_with_files(char *path
, GSList
*uri_list
)
90 if (stat(path
, &info
))
92 delayed_error(PROJECT
, _("Program not found - deleted?"));
96 argv
= g_malloc(sizeof(char *) * (g_slist_length(uri_list
) + 2));
98 if (S_ISDIR(info
.st_mode
))
99 argv
[argc
++] = make_path(path
, "AppRun")->str
;
105 char *uri
= (char *) uri_list
->data
;
108 local
= get_local_path(uri
);
110 argv
[argc
++] = local
;
113 uri_list
= uri_list
->next
;
118 if (!spawn_full(argv
, home_dir
))
119 delayed_error(PROJECT
, _("Failed to fork() child process"));
122 /* Run the program as '<path> -', piping the data to it via stdin.
123 * You can g_free() the data as soon as this returns.
125 void run_with_data(char *path
, gpointer data
, gulong length
)
127 char *argv
[] = {NULL
, "-", NULL
};
132 if (stat(path
, &info
))
134 delayed_error(PROJECT
, _("Program not found - deleted?"));
138 if (S_ISDIR(info
.st_mode
))
139 argv
[0] = make_path(path
, "AppRun")->str
;
145 delayed_error("pipe() failed", g_strerror(errno
));
148 close_on_exec(fds
[1], TRUE
);
149 close_on_exec(fds
[0], TRUE
);
154 delayed_error("fork() failed", g_strerror(errno
));
158 /* We are the child */
160 dup2(to_error_log
, STDERR_FILENO
);
161 close_on_exec(STDERR_FILENO
, FALSE
);
162 if (dup2(fds
[0], 0) == -1)
163 g_warning("dup2() failed: %s\n",
167 close_on_exec(0, FALSE
);
168 if (execv(argv
[0], argv
))
169 g_warning("execv(%s) failed: %s\n",
170 argv
[0], g_strerror(errno
));
174 /* We are the parent */
175 set_blocking(fds
[1], FALSE
);
176 pd
= g_new(PipedData
, 1);
177 pd
->data
= g_malloc(length
);
178 memcpy(pd
->data
, data
, length
);
181 pd
->tag
= gdk_input_add(fds
[1], GDK_INPUT_WRITE
,
189 /* Load a file, open a directory or run an application. Or, if 'edit' is set:
190 * edit a file, open an application, follow a symlink or mount a device.
192 * filer_window is the window to use for displaying a directory.
193 * NULL will always use a new directory when needed.
195 * Returns TRUE on success.
197 gboolean
run_diritem(guchar
*full_path
,
199 FilerWindow
*filer_window
,
202 if (filer_window
&& filer_window
->panel_type
)
205 if (item
->flags
& ITEM_FLAG_SYMLINK
&& edit
)
206 return follow_symlink(full_path
, filer_window
);
208 switch (item
->base_type
)
211 if (item
->flags
& ITEM_FLAG_APPDIR
&& !edit
)
217 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& edit
)
221 paths
= g_list_prepend(NULL
, full_path
);
224 if (item
->flags
& ITEM_FLAG_MOUNTED
)
229 filer_change_to(filer_window
, full_path
, NULL
);
231 filer_opendir(full_path
);
234 if ((item
->flags
& ITEM_FLAG_EXEC_FILE
) && !edit
)
236 char *argv
[] = {NULL
, NULL
};
237 guchar
*dir
= filer_window
? filer_window
->path
242 if (spawn_full(argv
, dir
))
246 report_error(PROJECT
,
247 _("Failed to fork() child"));
252 return open_file(full_path
, edit
? &text_plain
255 delayed_error(full_path
,
256 "I don't know how to open that");
261 /* Attempt to open this item */
262 gboolean
run_by_path(guchar
*full_path
)
267 /* XXX: Loads an image - wasteful */
268 dir_stat(full_path
, &item
);
269 retval
= run_diritem(full_path
, &item
, NULL
, FALSE
);
270 dir_item_clear(&item
);
275 void show_item_help(guchar
*path
, DirItem
*item
)
277 switch (item
->base_type
)
280 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
281 delayed_error(_("Executable file"),
282 _("This is a file with an eXecute bit "
283 "set - it can be run as a program."));
285 delayed_error(_("File"), _(
286 "This is a data file. Try using the "
287 "Info menu item to find out more..."));
290 if (item
->flags
& ITEM_FLAG_APPDIR
)
292 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
293 delayed_error(_("Mount point"), _(
294 "A mount point is a directory which another "
295 "filing system can be mounted on. Everything "
296 "on the mounted filesystem then appears to be "
297 "inside the directory."));
299 delayed_error(_("Directory"), _(
300 "This is a directory. It contains an index to "
301 "other items - open it to see the list."));
303 case TYPE_CHAR_DEVICE
:
304 case TYPE_BLOCK_DEVICE
:
305 delayed_error(_("Device file"), _(
306 "Device files allow you to read from or write "
307 "to a device driver as though it was an "
311 delayed_error(_("Named pipe"), _(
312 "Pipes allow different programs to "
313 "communicate. One program writes data to the "
314 "pipe while another one reads it out again."));
317 delayed_error(_("Socket"), _(
318 "Sockets allow processes to communicate."));
321 delayed_error(_("Unknown type"), _(
322 "I couldn't find out what kind of file this "
323 "is. Maybe it doesn't exist anymore or you "
324 "don't have search permission on the directory "
330 /* Runs each item in the list. Items may be files, directories,
331 * panels or pinboards.
333 * See main() for a description of 'to_open'.
335 void run_list(guchar
*to_open
)
339 /* TODO: Should escape < characters in case one really does
340 * appear in a filename!
348 g_return_if_fail(to_open
[0] == '<');
351 next
= strchr(to_open
+ 1, '<');
353 next
= to_open
+ strlen(to_open
);
355 g_return_if_fail(next
- to_open
> 2);
356 g_return_if_fail(to_open
[2] == '>');
358 value
= g_strndup(to_open
+ 3, next
- to_open
- 3);
367 pinboard_activate(value
);
370 filer_opendir(value
);
373 filer_openpanel(value
, PANEL_TOP
);
376 filer_openpanel(value
, PANEL_BOTTOM
);
379 g_warning("Don't know how to handle '%s'",
389 /****************************************************************
390 * INTERNAL FUNCTIONS *
391 ****************************************************************/
394 static void write_data(gpointer data
, gint fd
, GdkInputCondition cond
)
396 PipedData
*pd
= (PipedData
*) data
;
398 while (pd
->sent
< pd
->length
)
402 sent
= write(fd
, pd
->data
+ pd
->sent
, pd
->length
- pd
->sent
);
408 delayed_error(_("ROX-Filer - Sending data to program"),
417 gdk_input_remove(pd
->tag
);
423 /* Follow the link 'full_path' and display it in filer_window, or a
424 * new window if that is NULL.
426 static gboolean
follow_symlink(char *full_path
, FilerWindow
*filer_window
)
430 char path
[MAXPATHLEN
+ 1];
433 got
= readlink(full_path
, path
, MAXPATHLEN
);
436 delayed_error(PROJECT
, g_strerror(errno
));
440 g_return_val_if_fail(got
<= MAXPATHLEN
, FALSE
);
443 /* Make a relative path absolute */
447 slash
= strrchr(full_path
, '/');
448 g_return_val_if_fail(slash
!= NULL
, FALSE
);
450 tmp
= g_strndup(full_path
, slash
- full_path
);
451 real
= pathdup(make_path(tmp
, path
)->str
);
455 real
= pathdup(path
);
457 slash
= strrchr(real
, '/');
461 delayed_error(PROJECT
,
462 _("Broken symlink (or you don't have permission "
475 filer_change_to(filer_window
, new_dir
, slash
+ 1);
480 new = filer_opendir(new_dir
);
481 display_set_autoselect(new, slash
+ 1);
489 /* Load this file into an appropriate editor */
490 static gboolean
open_file(guchar
*path
, MIME_type
*type
)
494 g_return_val_if_fail(type
!= NULL
, FALSE
);
496 if (type_open(path
, type
))
499 message
= g_string_new(NULL
);
500 g_string_sprintf(message
,
501 _("No run action specified for files of this type (%s/%s) - "
502 "you can set a run action using by choosing `Set Run Action' "
503 "from the Window menu"),
506 report_error(PROJECT
, message
->str
);
507 g_string_free(message
, TRUE
);
512 static void app_show_help(char *path
)
517 help_dir
= g_strconcat(path
, "/Help", NULL
);
519 if (mc_stat(help_dir
, &info
))
520 delayed_error(_("Application"),
521 _("This is an application directory - you can "
522 "run it as a program, or open it (hold down "
523 "Shift while you open it). Most applications provide "
524 "their own help here, but this one doesn't."));
526 filer_opendir(help_dir
);