r70: Removed some old code. Dragging now quotes the correct MIME type for files.
[rox-filer.git] / ROX-Filer / src / menu.c
blobbd2c6601e0d0cba39a4198320da106c3c51ed27f
1 /* vi: set cindent:
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
6 */
8 /* menu.c - code for handling the popup menu */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <string.h>
20 #include <gdk/gdkx.h>
21 #include <gtk/gtk.h>
23 #include "apps.h"
24 #include "action.h"
25 #include "filer.h"
26 #include "type.h"
27 #include "support.h"
28 #include "gui_support.h"
29 #include "options.h"
30 #include "choices.h"
31 #include "savebox.h"
33 #define C_ "<control>"
35 #define MENU_MARGIN 32
37 GtkAccelGroup *filer_keys;
38 GtkAccelGroup *panel_keys;
40 /* Options */
41 static GtkWidget *xterm_here_entry;
42 static char *xterm_here_value;
44 /* Static prototypes */
45 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data);
46 static void menu_closed(GtkWidget *widget);
47 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state);
48 static char *load_xterm_here(char *data);
50 static void not_yet(gpointer data, guint action, GtkWidget *widget);
52 static void hidden(gpointer data, guint action, GtkWidget *widget);
53 static void refresh(gpointer data, guint action, GtkWidget *widget);
55 static void copy_item(gpointer data, guint action, GtkWidget *widget);
56 static void rename_item(gpointer data, guint action, GtkWidget *widget);
57 static void link_item(gpointer data, guint action, GtkWidget *widget);
58 static void help(gpointer data, guint action, GtkWidget *widget);
59 static void show_file_info(gpointer data, guint action, GtkWidget *widget);
60 static void mount(gpointer data, guint action, GtkWidget *widget);
61 static void delete(gpointer data, guint action, GtkWidget *widget);
63 static void select_all(gpointer data, guint action, GtkWidget *widget);
64 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
65 static void show_options(gpointer data, guint action, GtkWidget *widget);
66 static void new_directory(gpointer data, guint action, GtkWidget *widget);
67 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
68 static void open_parent(gpointer data, guint action, GtkWidget *widget);
70 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
71 static void close_panel(gpointer data, guint action, GtkWidget *widget);
73 static GtkWidget *create_options();
74 static void update_options();
75 static void set_options();
76 static void save_options();
78 static OptionsSection options =
80 "Menu options",
81 create_options,
82 update_options,
83 set_options,
84 save_options
88 static GtkWidget *filer_menu; /* The popup filer menu */
89 static GtkWidget *filer_file_item; /* The File '' label */
90 static GtkWidget *filer_file_menu; /* The File '' menu */
91 static GtkWidget *panel_menu; /* The popup panel menu */
92 static GtkWidget *panel_file_item; /* The File '' label */
93 static GtkWidget *panel_file_menu; /* The File '' menu */
95 static gint screen_width, screen_height;
97 static GtkItemFactoryEntry filer_menu_def[] = {
98 {"/Display", NULL, NULL, 0, "<Branch>"},
99 {"/Display/Large Icons", NULL, not_yet, 0, "<RadioItem>"},
100 {"/Display/Small Icons", NULL, not_yet, 0, "/Display/Large Icons"},
101 {"/Display/Full Info", NULL, not_yet, 0, "/Display/Large Icons"},
102 {"/Display/Separator", NULL, not_yet, 0, "<Separator>"},
103 {"/Display/Sort by Name", NULL, not_yet, 0, "<RadioItem>"},
104 {"/Display/Sort by Type", NULL, not_yet, 0, "/Display/Sort by Name"},
105 {"/Display/Sort by Date", NULL, not_yet, 0, "/Display/Sort by Name"},
106 {"/Display/Sort by Size", NULL, not_yet, 0, "/Display/Sort by Name"},
107 {"/Display/Sort by Owner", NULL, not_yet, 0, "/Display/Sort by Name"},
108 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
109 {"/Display/Show Hidden", C_"H", hidden, 0, "<ToggleItem>"},
110 {"/Display/Refresh", C_"L", refresh, 0, NULL},
111 {"/File", NULL, NULL, 0, "<Branch>"},
112 {"/File/Copy...", NULL, copy_item, 0, NULL},
113 {"/File/Rename...", NULL, rename_item, 0, NULL},
114 {"/File/Link...", NULL, link_item, 0, NULL},
115 {"/File/Help", "F1", help, 0, NULL},
116 {"/File/Info", "I", show_file_info, 0, NULL},
117 {"/File/Separator", NULL, NULL, 0, "<Separator>"},
118 {"/File/Mount", C_"M", mount, 0, NULL},
119 {"/File/Delete", C_"X", delete, 0, NULL},
120 {"/File/Disk Usage", C_"U", not_yet, 0, NULL},
121 {"/File/Permissions", NULL, not_yet, 0, NULL},
122 {"/File/Touch", NULL, not_yet, 0, NULL},
123 {"/File/Find", NULL, not_yet, 0, NULL},
124 {"/Select All", C_"A", select_all, 0, NULL},
125 {"/Clear Selection", C_"Z", clear_selection, 0, NULL},
126 {"/Options...", NULL, show_options, 0, NULL},
127 {"/New directory", NULL, new_directory, 0, NULL},
128 {"/Xterm here", NULL, xterm_here, 0, NULL},
129 {"/Open parent", NULL, open_parent, 0, NULL},
132 static GtkItemFactoryEntry panel_menu_def[] = {
133 {"/Display", NULL, NULL, 0, "<Branch>"},
134 {"/Display/Large Icons", NULL, not_yet, 0, "<RadioItem>"},
135 {"/Display/Small Icons", NULL, not_yet, 0, "/Display/Large Icons"},
136 {"/Display/Full Info", NULL, not_yet, 0, "/Display/Large Icons"},
137 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
138 {"/Display/Sort by Name", NULL, not_yet, 0, "<RadioItem>"},
139 {"/Display/Sort by Type", NULL, not_yet, 0, "/Display/Sort by Name"},
140 {"/Display/Sort by Date", NULL, not_yet, 0, "/Display/Sort by Name"},
141 {"/Display/Sort by Size", NULL, not_yet, 0, "/Display/Sort by Name"},
142 {"/Display/Sort by Owner", NULL, not_yet, 0, "/Display/Sort by Name"},
143 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
144 {"/Display/Show Hidden", NULL, hidden, 0, "<ToggleItem>"},
145 {"/Display/Refresh", NULL, refresh, 0, NULL},
146 {"/File", NULL, NULL, 0, "<Branch>"},
147 {"/File/Help", NULL, help, 0, NULL},
148 {"/File/Info", NULL, show_file_info, 0, NULL},
149 {"/File/Delete", NULL, delete, 0, NULL},
150 {"/Open as directory", NULL, open_as_dir, 0, NULL},
151 {"/Close panel", NULL, close_panel, 0, NULL},
154 void menu_init()
156 GtkItemFactory *item_factory;
157 char *menurc;
158 GList *items;
160 /* This call starts returning strange values after a while, so get
161 * the result here during init.
163 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width, &screen_height);
165 filer_keys = gtk_accel_group_new();
166 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
167 "<filer>",
168 filer_keys);
169 gtk_item_factory_create_items(item_factory,
170 sizeof(filer_menu_def) / sizeof(*filer_menu_def),
171 filer_menu_def,
172 NULL);
173 filer_menu = gtk_item_factory_get_widget(item_factory, "<filer>");
174 filer_file_menu = gtk_item_factory_get_widget(item_factory,
175 "<filer>/File");
176 items = gtk_container_children(GTK_CONTAINER(filer_menu));
177 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
178 g_list_free(items);
180 panel_keys = gtk_accel_group_new();
181 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
182 "<panel>",
183 panel_keys);
184 gtk_item_factory_create_items(item_factory,
185 sizeof(panel_menu_def) / sizeof(*panel_menu_def),
186 panel_menu_def,
187 NULL);
188 panel_menu = gtk_item_factory_get_widget(item_factory, "<panel>");
189 panel_file_menu = gtk_item_factory_get_widget(item_factory,
190 "<panel>/File");
191 items = gtk_container_children(GTK_CONTAINER(panel_menu));
192 panel_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
193 g_list_free(items);
195 menurc = choices_find_path_load("menus");
196 if (menurc)
197 gtk_item_factory_parse_rc(menurc);
199 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
200 GTK_SIGNAL_FUNC(menu_closed), NULL);
201 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
202 GTK_SIGNAL_FUNC(menu_closed), NULL);
204 gtk_accel_group_lock(panel_keys);
206 options_sections = g_slist_prepend(options_sections, &options);
207 xterm_here_value = g_strdup("xterm");
208 option_register("xterm_here", load_xterm_here);
211 /* Build up some option widgets to go in the options dialog, but don't
212 * fill them in yet.
214 static GtkWidget *create_options()
216 GtkWidget *table, *label;
218 table = gtk_table_new(2, 2, FALSE);
219 gtk_container_set_border_width(GTK_CONTAINER(table), 4);
221 label = gtk_label_new("To set the keyboard short-cuts you simply open "
222 "the menu over a filer window, move the pointer over "
223 "the item you want to use and press a key. The key "
224 "will appear next to the menu item and you can just "
225 "press that key without opening the menu in future. "
226 "To save the current menu short-cuts for next time, "
227 "click the Save button at the bottom of this window.");
228 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
229 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
231 label = gtk_label_new("'Xterm here' program:");
232 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
233 xterm_here_entry = gtk_entry_new();
234 gtk_table_attach_defaults(GTK_TABLE(table), xterm_here_entry,
235 1, 2, 1, 2);
237 return table;
240 static char *load_xterm_here(char *data)
242 g_free(xterm_here_value);
243 xterm_here_value = g_strdup(data);
244 return NULL;
247 static void update_options()
249 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry), xterm_here_value);
252 static void set_options()
254 g_free(xterm_here_value);
255 xterm_here_value = g_strdup(gtk_entry_get_text(
256 GTK_ENTRY(xterm_here_entry)));
259 static void save_options()
261 char *menurc;
263 menurc = choices_find_path_save("menus");
264 if (menurc)
265 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
267 option_write("xterm_here", xterm_here_value);
271 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state)
273 GList *items, *item;
275 items = gtk_container_children(GTK_CONTAINER(menu));
277 item = g_list_nth(items, from);
278 while (item && n--)
280 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
281 item = item->next;
284 g_list_free(items);
287 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
289 int *pos = (int *) data;
290 GtkRequisition requisition;
292 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
294 if (pos[0] == -1)
295 *x = screen_width - MENU_MARGIN - requisition.width;
296 else if (pos[0] == -2)
297 *x = MENU_MARGIN;
298 else
299 *x = pos[0] - (requisition.width >> 2);
301 if (pos[1] == -1)
302 *y = screen_height - MENU_MARGIN - requisition.height;
303 else if (pos[1] == -2)
304 *y = MENU_MARGIN;
305 else
306 *y = pos[1] - (requisition.height >> 2);
308 *x = CLAMP(*x, 0, screen_width - requisition.width);
309 *y = CLAMP(*y, 0, screen_height - requisition.height);
312 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
313 int item)
315 GString *buffer;
316 GtkWidget *file_label, *file_menu;
317 FileItem *file_item;
318 int pos[] = {event->x_root, event->y_root};
320 window_with_focus = filer_window;
322 if (filer_window->panel)
324 switch (filer_window->panel_side)
326 case TOP: pos[1] = -2; break;
327 case BOTTOM: pos[1] = -1; break;
328 case LEFT: pos[0] = -2; break;
329 case RIGHT: pos[0] = -1; break;
333 if (filer_window->panel)
335 collection_clear_selection(filer_window->collection);
336 panel_set_timeout(NULL, 0);
339 if (filer_window->collection->number_selected == 0 && item >= 0)
341 collection_select_item(filer_window->collection, item);
342 filer_window->temp_item_selected = TRUE;
344 else
345 filer_window->temp_item_selected = FALSE;
347 if (filer_window->panel)
349 file_label = panel_file_item;
350 file_menu = panel_file_menu;
352 else
354 file_label = filer_file_item;
355 file_menu = filer_file_menu;
358 buffer = g_string_new(NULL);
359 switch (filer_window->collection->number_selected)
361 case 0:
362 g_string_assign(buffer, "<nothing selected>");
363 items_sensitive(file_menu, 0, 5, FALSE);
364 items_sensitive(file_menu, 6, -1, FALSE);
365 gtk_widget_set_sensitive(file_label, FALSE);
366 break;
367 case 1:
368 items_sensitive(file_menu, 0, 5, TRUE);
369 items_sensitive(file_menu, 6, -1, TRUE);
370 gtk_widget_set_sensitive(file_label, TRUE);
371 file_item = selected_item(filer_window->collection);
372 g_string_sprintf(buffer, "%s '%s'",
373 basetype_name(file_item),
374 file_item->leafname);
375 break;
376 default:
377 items_sensitive(file_menu, 0, 5, FALSE);
378 items_sensitive(file_menu, 6, -1, TRUE);
379 gtk_widget_set_sensitive(file_label, TRUE);
380 g_string_sprintf(buffer, "%d items",
381 filer_window->collection->number_selected);
382 break;
385 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
387 g_string_free(buffer, TRUE);
389 gtk_menu_popup(filer_window->panel ? GTK_MENU(panel_menu)
390 : GTK_MENU(filer_menu),
391 NULL, NULL, position_menu,
392 (gpointer) pos, event->button, event->time);
395 static void menu_closed(GtkWidget *widget)
397 if (window_with_focus == NULL)
398 return; /* Close panel item chosen? */
400 if (window_with_focus->temp_item_selected)
402 collection_clear_selection(window_with_focus->collection);
403 window_with_focus->temp_item_selected = FALSE;
407 /* Actions */
409 /* Fake action to warn when a menu item does nothing */
410 static void not_yet(gpointer data, guint action, GtkWidget *widget)
412 delayed_error("ROX-Filer", "Sorry, that feature isn't implemented yet");
415 static void hidden(gpointer data, guint action, GtkWidget *widget)
417 g_return_if_fail(window_with_focus != NULL);
419 window_with_focus->show_hidden = !window_with_focus->show_hidden;
420 scan_dir(window_with_focus);
423 static void refresh(gpointer data, guint action, GtkWidget *widget)
425 g_return_if_fail(window_with_focus != NULL);
427 scan_dir(window_with_focus);
430 static void delete(gpointer data, guint action, GtkWidget *widget)
432 g_return_if_fail(window_with_focus != NULL);
434 action_delete(window_with_focus);
437 static gboolean copy_cb(char *initial, char *path)
439 char *new_dir, *slash;
440 int len;
441 GString *command;
442 gboolean retval = TRUE;
444 slash = strrchr(path, '/');
445 if (!slash)
447 report_error("ROX-Filer", "Missing '/' in new pathname");
448 return FALSE;
451 if (access(path, F_OK) == 0)
453 report_error("ROX-Filer",
454 "An item with this name already exists");
455 return FALSE;
458 len = slash - path;
459 new_dir = g_malloc(len + 1);
460 memcpy(new_dir, path, len);
461 new_dir[len] = '\0';
463 command = g_string_new(NULL);
464 g_string_sprintf(command, "cp -a %s %s", initial, path);
466 if (system(command->str))
468 g_string_append(command, " failed!");
469 report_error("ROX-Filer", command->str);
470 retval = FALSE;
473 g_string_free(command, TRUE);
475 refresh_dirs(new_dir);
476 return retval;
479 static void copy_item(gpointer data, guint action, GtkWidget *widget)
481 Collection *collection;
483 g_return_if_fail(window_with_focus != NULL);
485 collection = window_with_focus->collection;
486 if (collection->number_selected != 1)
487 report_error("ROX-Filer", "You must select a single "
488 "item to copy");
489 else
491 FileItem *item = selected_item(collection);
493 savebox_show(window_with_focus, "Copy",
494 window_with_focus->path, item->leafname,
495 item->image, copy_cb);
499 static gboolean rename_cb(char *initial, char *path)
501 if (rename(initial, path))
503 report_error("ROX-Filer: rename()", g_strerror(errno));
504 return FALSE;
506 return TRUE;
509 static void rename_item(gpointer data, guint action, GtkWidget *widget)
511 Collection *collection;
513 g_return_if_fail(window_with_focus != NULL);
515 collection = window_with_focus->collection;
516 if (collection->number_selected != 1)
517 report_error("ROX-Filer", "You must select a single "
518 "item to rename");
519 else
521 FileItem *item = selected_item(collection);
523 savebox_show(window_with_focus, "Rename",
524 window_with_focus->path, item->leafname,
525 item->image, rename_cb);
529 static gboolean link_cb(char *initial, char *path)
531 if (symlink(initial, path))
533 report_error("ROX-Filer: symlink()", g_strerror(errno));
534 return FALSE;
536 return TRUE;
539 static void link_item(gpointer data, guint action, GtkWidget *widget)
541 Collection *collection;
543 g_return_if_fail(window_with_focus != NULL);
545 collection = window_with_focus->collection;
546 if (collection->number_selected != 1)
547 report_error("ROX-Filer", "You must select a single "
548 "item to link");
549 else
551 FileItem *item = selected_item(collection);
553 savebox_show(window_with_focus, "Symlink",
554 window_with_focus->path, item->leafname,
555 item->image, link_cb);
559 static void show_file_info(gpointer data, guint action, GtkWidget *widget)
561 GtkWidget *window, *table, *label, *button, *frame;
562 GtkWidget *file_label;
563 GString *gstring;
564 char *string;
565 int file_data[2];
566 char *path;
567 char buffer[20];
568 char *argv[] = {"file", "-b", NULL, NULL};
569 int got;
570 Collection *collection;
571 FileItem *file;
572 struct stat info;
574 g_return_if_fail(window_with_focus != NULL);
576 collection = window_with_focus->collection;
577 if (collection->number_selected != 1)
579 report_error("ROX-Filer", "You must select a single "
580 "item before using Info");
581 return;
583 file = selected_item(collection);
584 path = make_path(window_with_focus->path, file->leafname)->str;
585 if (lstat(path, &info))
587 delayed_error("ROX-Filer", g_strerror(errno));
588 return;
591 gstring = g_string_new(NULL);
593 window = gtk_window_new(GTK_WINDOW_DIALOG);
594 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
595 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
596 gtk_window_set_title(GTK_WINDOW(window), path);
598 table = gtk_table_new(4, 2, FALSE);
599 gtk_container_add(GTK_CONTAINER(window), table);
600 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
601 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
603 label = gtk_label_new("Owner, group:");
604 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
605 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
606 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
607 g_string_sprintf(gstring, "%s, %s", user_name(info.st_uid),
608 group_name(info.st_gid));
609 label = gtk_label_new(gstring->str);
610 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
612 label = gtk_label_new("Permissions:");
613 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
614 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
615 g_string_sprintf(gstring, "%o", info.st_mode);
616 label = gtk_label_new(gstring->str);
617 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
619 label = gtk_label_new("MIME type:");
620 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
621 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
622 if (file->mime_type)
624 string = g_strconcat(file->mime_type->media_type, "/",
625 file->mime_type->subtype, NULL);
626 label = gtk_label_new(string);
627 g_free(string);
629 else
630 label = gtk_label_new("-");
631 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
633 frame = gtk_frame_new("file(1) says...");
634 gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 3, 4);
635 file_label = gtk_label_new("<nothing yet>");
636 gtk_misc_set_padding(GTK_MISC(file_label), 4, 4);
637 gtk_label_set_line_wrap(GTK_LABEL(file_label), TRUE);
638 gtk_container_add(GTK_CONTAINER(frame), file_label);
640 button = gtk_button_new_with_label("OK");
641 gtk_table_attach(GTK_TABLE(table), button, 0, 2, 4, 5,
642 GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 40, 4);
643 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
644 gtk_widget_destroy, GTK_OBJECT(window));
646 gtk_widget_show_all(window);
647 gdk_flush();
649 pipe(file_data);
650 switch (fork())
652 case -1:
653 close(file_data[0]);
654 close(file_data[1]);
655 gtk_label_set_text(GTK_LABEL(file_label),
656 "fork() error");
657 g_string_free(gstring, TRUE);
658 return;
659 case 0:
660 close(file_data[0]);
661 dup2(file_data[1], STDOUT_FILENO);
662 dup2(file_data[1], STDERR_FILENO);
663 argv[2] = path;
664 if (execvp(argv[0], argv))
665 fprintf(stderr, "execvp() error: %s\n",
666 g_strerror(errno));
667 _exit(0);
669 /* We are the parent... */
670 close(file_data[1]);
671 g_string_truncate(gstring, 0);
672 while (gtk_events_pending())
673 g_main_iteration(FALSE);
674 while ((got = read(file_data[0], buffer, sizeof(buffer) - 1)))
676 buffer[got] = '\0';
677 g_string_append(gstring, buffer);
679 close(file_data[0]);
680 gtk_label_set_text(GTK_LABEL(file_label), gstring->str);
681 g_string_free(gstring, TRUE);
684 static void help(gpointer data, guint action, GtkWidget *widget)
686 Collection *collection;
687 FileItem *item;
689 g_return_if_fail(window_with_focus != NULL);
691 collection = window_with_focus->collection;
692 if (collection->number_selected != 1)
694 report_error("ROX-Filer", "You must select a single "
695 "item to get help on");
696 return;
698 item = selected_item(collection);
699 switch (item->base_type)
701 case TYPE_FILE:
702 if (item->flags & ITEM_FLAG_EXEC_FILE)
703 report_error("Executable file",
704 "This is a file with an eXecute bit "
705 "set - it can be run as a program.");
706 else
707 report_error("File",
708 "This is a data file. Try using the "
709 "Info menu item to find out more...");
710 break;
711 case TYPE_DIRECTORY:
712 if (item->flags & ITEM_FLAG_APPDIR)
713 app_show_help(
714 make_path(window_with_focus->path,
715 item->leafname)->str);
716 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
717 report_error("Mount point",
718 "A mount point is a directory which another "
719 "filing system can be mounted on. Everything "
720 "on the mounted filesystem then appears to be "
721 "inside the directory.");
722 else
723 report_error("Directory",
724 "This is a directory. It contains an index to "
725 "other items - open it to see the list.");
726 break;
727 case TYPE_CHAR_DEVICE:
728 case TYPE_BLOCK_DEVICE:
729 report_error("Device file",
730 "Device files allow you to read from or write "
731 "to a device driver as though it was an "
732 "ordinary file.");
733 break;
734 case TYPE_PIPE:
735 report_error("Named pipe",
736 "Pipes allow different programs to "
737 "communicate. One program writes data to the "
738 "pipe while another one reads it out again.");
739 break;
740 case TYPE_SOCKET:
741 report_error("Socket",
742 "Sockets allow processes to communicate.");
743 break;
744 default:
745 report_error("Unknown type",
746 "I couldn't find out what kind of file this "
747 "is. Maybe it doesn't exist anymore or you "
748 "don't have search permission on the directory "
749 "it's in?");
750 break;
754 static void mount(gpointer data, guint action, GtkWidget *widget)
756 FileItem *item;
757 int i;
758 Collection *collection;
759 char *error = NULL;
760 int count = 0;
762 g_return_if_fail(window_with_focus != NULL);
764 collection = window_with_focus->collection;
766 for (i = 0; i < collection->number_of_items; i++)
767 if (collection->items[i].selected)
769 item = (FileItem *) collection->items[i].data;
770 if (item->flags & ITEM_FLAG_MOUNT_POINT)
772 char *argv[] = {"mount", NULL, NULL};
773 int child;
775 count++;
776 if (item->flags & ITEM_FLAG_MOUNTED)
777 argv[0] = "umount";
778 argv[1] = make_path(window_with_focus->path,
779 item->leafname)->str;
780 child = spawn(argv);
781 if (child)
782 waitpid(child, NULL, 0);
783 else
784 error = "Failed to run mount/umount";
787 if (count)
788 scan_dir(window_with_focus);
789 else if (!error)
790 error = "You must select some mount points first!";
792 if (error)
793 report_error("ROX-Filer", error);
796 static void select_all(gpointer data, guint action, GtkWidget *widget)
798 g_return_if_fail(window_with_focus != NULL);
800 collection_select_all(window_with_focus->collection);
801 window_with_focus->temp_item_selected = FALSE;
804 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
806 g_return_if_fail(window_with_focus != NULL);
808 collection_clear_selection(window_with_focus->collection);
809 window_with_focus->temp_item_selected = FALSE;
812 static void show_options(gpointer data, guint action, GtkWidget *widget)
814 g_return_if_fail(window_with_focus != NULL);
816 options_show(window_with_focus);
819 static gboolean new_directory_cb(char *initial, char *path)
821 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO))
823 report_error("mkdir", g_strerror(errno));
824 return FALSE;
826 return TRUE;
829 static void new_directory(gpointer data, guint action, GtkWidget *widget)
831 g_return_if_fail(window_with_focus != NULL);
833 savebox_show(window_with_focus, "Create directory",
834 window_with_focus->path, "NewDir",
835 default_pixmap + TYPE_DIRECTORY, new_directory_cb);
838 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
840 char *argv[] = {xterm_here_value, NULL};
842 g_return_if_fail(window_with_focus != NULL);
844 if (!spawn_full(argv, window_with_focus->path, 0))
845 report_error("ROX-Filer", "Failed to fork() child "
846 "process");
849 static void open_parent(gpointer data, guint action, GtkWidget *widget)
851 g_return_if_fail(window_with_focus != NULL);
853 filer_opendir(make_path(window_with_focus->path, "/..")->str,
854 FALSE, BOTTOM);
857 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
859 g_return_if_fail(window_with_focus != NULL);
861 filer_opendir(window_with_focus->path, FALSE, BOTTOM);
864 static void close_panel(gpointer data, guint action, GtkWidget *widget)
866 g_return_if_fail(window_with_focus != NULL);
868 gtk_widget_destroy(window_with_focus->window);