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"
44 /* Static prototypes */
45 static void write_data(gpointer data
, gint fd
, GdkInputCondition cond
);
46 static gboolean
follow_symlink(char *full_path
, FilerWindow
*filer_window
);
47 static gboolean
open_file(guchar
*path
, MIME_type
*type
);
48 static void app_show_help(char *path
);
49 static void examine(guchar
*path
);
51 typedef struct _PipedData PipedData
;
62 /****************************************************************
63 * EXTERNAL INTERFACE *
64 ****************************************************************/
67 /* An application has been double-clicked (or run in some other way) */
68 void run_app(char *path
)
71 char *argv
[] = {NULL
, NULL
};
73 apprun
= g_string_new(path
);
74 argv
[0] = g_string_append(apprun
, "/AppRun")->str
;
76 if (!spawn_full(argv
, home_dir
))
77 report_error(PROJECT
, "Failed to fork() child process");
79 g_string_free(apprun
, TRUE
);
82 /* Execute this program, passing all the URIs in the list as arguments.
83 * URIs that are files on the local machine will be passed as simple
84 * pathnames. The uri_list should be freed after this function returns.
86 void run_with_files(char *path
, GSList
*uri_list
)
92 if (stat(path
, &info
))
94 delayed_error(PROJECT
, _("Program not found - deleted?"));
98 argv
= g_malloc(sizeof(char *) * (g_slist_length(uri_list
) + 2));
100 if (S_ISDIR(info
.st_mode
))
101 argv
[argc
++] = make_path(path
, "AppRun")->str
;
107 char *uri
= (char *) uri_list
->data
;
110 local
= get_local_path(uri
);
112 argv
[argc
++] = local
;
115 uri_list
= uri_list
->next
;
120 if (!spawn_full(argv
, home_dir
))
121 delayed_error(PROJECT
, _("Failed to fork() child process"));
124 /* Run the program as '<path> -', piping the data to it via stdin.
125 * You can g_free() the data as soon as this returns.
127 void run_with_data(char *path
, gpointer data
, gulong length
)
129 char *argv
[] = {NULL
, "-", NULL
};
134 if (stat(path
, &info
))
136 delayed_error(PROJECT
, _("Program not found - deleted?"));
140 if (S_ISDIR(info
.st_mode
))
141 argv
[0] = make_path(path
, "AppRun")->str
;
147 delayed_error("pipe() failed", g_strerror(errno
));
150 close_on_exec(fds
[1], TRUE
);
151 close_on_exec(fds
[0], TRUE
);
156 delayed_error("fork() failed", g_strerror(errno
));
160 /* We are the child */
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 (item
->flags
& ITEM_FLAG_SYMLINK
&& edit
)
203 return follow_symlink(full_path
, filer_window
);
205 switch (item
->base_type
)
208 if (item
->flags
& ITEM_FLAG_APPDIR
&& !edit
)
214 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& edit
)
218 paths
= g_list_prepend(NULL
, full_path
);
221 if (item
->flags
& ITEM_FLAG_MOUNTED
)
226 filer_change_to(filer_window
, full_path
, NULL
);
228 filer_opendir(full_path
);
231 if ((item
->mime_type
== &special_exec
) && !edit
)
233 char *argv
[] = {NULL
, NULL
};
234 guchar
*dir
= filer_window
? filer_window
->path
239 if (spawn_full(argv
, dir
))
243 report_error(PROJECT
,
244 _("Failed to fork() child"));
249 return open_file(full_path
, edit
? &text_plain
252 delayed_error(full_path
,
253 _("File doesn't exist, or I can't "
257 delayed_error(full_path
,
258 _("I don't know how to open that"));
263 /* Attempt to open this item */
264 gboolean
run_by_path(guchar
*full_path
)
269 /* XXX: Loads an image - wasteful */
270 dir_stat(full_path
, &item
, FALSE
);
271 retval
= run_diritem(full_path
, &item
, NULL
, FALSE
);
272 dir_item_clear(&item
);
277 void show_item_help(guchar
*path
, DirItem
*item
)
279 switch (item
->base_type
)
282 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
283 delayed_error(_("Executable file"),
284 _("This is a file with an eXecute bit "
285 "set - it can be run as a program."));
287 delayed_error(_("File"), _(
288 "This is a data file. Try using the "
289 "Info menu item to find out more..."));
292 if (item
->flags
& ITEM_FLAG_APPDIR
)
294 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
295 delayed_error(_("Mount point"), _(
296 "A mount point is a directory which another "
297 "filing system can be mounted on. Everything "
298 "on the mounted filesystem then appears to be "
299 "inside the directory."));
301 delayed_error(_("Directory"), _(
302 "This is a directory. It contains an index to "
303 "other items - open it to see the list."));
305 case TYPE_CHAR_DEVICE
:
306 case TYPE_BLOCK_DEVICE
:
307 delayed_error(_("Device file"), _(
308 "Device files allow you to read from or write "
309 "to a device driver as though it was an "
313 delayed_error(_("Named pipe"), _(
314 "Pipes allow different programs to "
315 "communicate. One program writes data to the "
316 "pipe while another one reads it out again."));
319 delayed_error(_("Socket"), _(
320 "Sockets allow processes to communicate."));
323 delayed_error(_("Unknown type"), _(
324 "I couldn't find out what kind of file this "
325 "is. Maybe it doesn't exist anymore or you "
326 "don't have search permission on the directory "
332 /* Runs each item in the list. Items may be files, directories,
333 * panels or pinboards.
335 * See main() for a description of 'to_open'.
337 void run_list(guchar
*to_open
)
341 /* TODO: Should escape < characters in case one really does
342 * appear in a filename!
350 g_return_if_fail(to_open
[0] == '<');
353 next
= strchr(to_open
+ 1, '<');
355 next
= to_open
+ strlen(to_open
);
357 g_return_if_fail(next
- to_open
> 2);
358 g_return_if_fail(to_open
[2] == '>');
360 value
= g_strndup(to_open
+ 3, next
- to_open
- 3);
369 pinboard_activate(value
);
375 filer_opendir(value
);
378 panel_new(value
, PANEL_TOP
);
381 panel_new(value
, PANEL_BOTTOM
);
384 panel_new(value
, PANEL_LEFT
);
387 panel_new(value
, PANEL_RIGHT
);
393 g_warning("Don't know how to handle '%s'",
403 /* Open a directory viewer showing this file, and wink it */
404 void open_to_show(guchar
*path
)
409 g_return_if_fail(path
!= NULL
);
411 dir
= g_strdup(path
);
412 slash
= strrchr(dir
, '/');
413 if (slash
== dir
|| !slash
)
415 /* Item in the root (or root itself!) */
416 new = filer_opendir("/");
418 display_set_autoselect(new, dir
+ 1);
424 new = filer_opendir(dir
);
426 display_set_autoselect(new, slash
+ 1);
432 /****************************************************************
433 * INTERNAL FUNCTIONS *
434 ****************************************************************/
437 static void write_data(gpointer data
, gint fd
, GdkInputCondition cond
)
439 PipedData
*pd
= (PipedData
*) data
;
441 while (pd
->sent
< pd
->length
)
445 sent
= write(fd
, pd
->data
+ pd
->sent
, pd
->length
- pd
->sent
);
451 delayed_error(_("ROX-Filer - Sending data to program"),
460 gdk_input_remove(pd
->tag
);
466 /* Follow the link 'full_path' and display it in filer_window, or a
467 * new window if that is NULL.
469 static gboolean
follow_symlink(char *full_path
, FilerWindow
*filer_window
)
473 char path
[MAXPATHLEN
+ 1];
476 got
= readlink(full_path
, path
, MAXPATHLEN
);
479 delayed_error(PROJECT
, g_strerror(errno
));
483 g_return_val_if_fail(got
<= MAXPATHLEN
, FALSE
);
486 /* Make a relative path absolute */
490 slash
= strrchr(full_path
, '/');
491 g_return_val_if_fail(slash
!= NULL
, FALSE
);
493 tmp
= g_strndup(full_path
, slash
- full_path
);
494 real
= pathdup(make_path(tmp
, path
)->str
);
495 /* NB: full_path may be invalid here... */
499 real
= pathdup(path
);
501 slash
= strrchr(real
, '/');
505 delayed_error(PROJECT
,
506 _("Broken symlink (or you don't have permission "
519 filer_change_to(filer_window
, new_dir
, slash
+ 1);
524 new = filer_opendir(new_dir
);
525 display_set_autoselect(new, slash
+ 1);
533 /* Load this file into an appropriate editor */
534 static gboolean
open_file(guchar
*path
, MIME_type
*type
)
538 g_return_val_if_fail(type
!= NULL
, FALSE
);
540 if (type_open(path
, type
))
543 message
= g_string_new(NULL
);
544 g_string_sprintf(message
,
545 _("No run action specified for files of this type (%s/%s) - "
546 "you can set a run action by choosing `Set Run Action' "
547 "from the File menu, or you can just drag the file to an "
551 report_error(PROJECT
, message
->str
);
552 g_string_free(message
, TRUE
);
557 static void app_show_help(char *path
)
562 help_dir
= g_strconcat(path
, "/Help", NULL
);
564 if (mc_stat(help_dir
, &info
))
565 delayed_error(_("Application"),
566 _("This is an application directory - you can "
567 "run it as a program, or open it (hold down "
568 "Shift while you open it). Most applications provide "
569 "their own help here, but this one doesn't."));
571 filer_opendir(help_dir
);
574 /* Invoked using -x, this indicates that the filesystem has been modified
575 * and we should look at this item again.
577 static void examine(guchar
*path
)
581 if (mc_stat(path
, &info
) != 0)
583 /* Deleted? Do a paranoid update of everything... */
584 filer_check_mounted(path
);
588 /* Update directory containing this item... */
589 dir_check_this(path
);
591 /* If this is itself directory then rescan its contents... */
594 /* If it's on the pinboard, update the icon... */
595 icons_may_update(path
);