r69: Tidied up the options system a bit. Added drag-and-drop section (with
[rox-filer.git] / ROX-Filer / src / menu.c
blobc31118da5413ab9c4701cf07ade9f92831a16200
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 hidden(gpointer data, guint action, GtkWidget *widget);
51 static void refresh(gpointer data, guint action, GtkWidget *widget);
53 static void copy_item(gpointer data, guint action, GtkWidget *widget);
54 static void rename_item(gpointer data, guint action, GtkWidget *widget);
55 static void link_item(gpointer data, guint action, GtkWidget *widget);
56 static void help(gpointer data, guint action, GtkWidget *widget);
57 static void show_file_info(gpointer data, guint action, GtkWidget *widget);
58 static void mount(gpointer data, guint action, GtkWidget *widget);
59 static void delete(gpointer data, guint action, GtkWidget *widget);
61 static void select_all(gpointer data, guint action, GtkWidget *widget);
62 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
63 static void show_options(gpointer data, guint action, GtkWidget *widget);
64 static void new_directory(gpointer data, guint action, GtkWidget *widget);
65 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
66 static void open_parent(gpointer data, guint action, GtkWidget *widget);
68 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
69 static void close_panel(gpointer data, guint action, GtkWidget *widget);
71 static GtkWidget *create_options();
72 static void update_options();
73 static void set_options();
74 static void save_options();
76 static OptionsSection options =
78 "Menu options",
79 create_options,
80 update_options,
81 set_options,
82 save_options
86 static GtkWidget *filer_menu; /* The popup filer menu */
87 static GtkWidget *filer_file_item; /* The File '' label */
88 static GtkWidget *filer_file_menu; /* The File '' menu */
89 static GtkWidget *panel_menu; /* The popup panel menu */
90 static GtkWidget *panel_file_item; /* The File '' label */
91 static GtkWidget *panel_file_menu; /* The File '' menu */
93 static GtkItemFactoryEntry filer_menu_def[] = {
94 {"/Display", NULL, NULL, 0, "<Branch>"},
95 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
96 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
97 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
98 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
99 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
100 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
101 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
102 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
103 {"/Display/Sort by Owner", NULL, NULL, 0, "/Display/Sort by Name"},
104 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
105 {"/Display/Show Hidden", C_"H", hidden, 0, "<ToggleItem>"},
106 {"/Display/Refresh", C_"L", refresh, 0, NULL},
107 {"/File", NULL, NULL, 0, "<Branch>"},
108 {"/File/Copy...", NULL, copy_item, 0, NULL},
109 {"/File/Rename...", NULL, rename_item, 0, NULL},
110 {"/File/Link...", NULL, link_item, 0, NULL},
111 {"/File/Help", "F1", help, 0, NULL},
112 {"/File/Info", "I", show_file_info, 0, NULL},
113 {"/File/Separator", NULL, NULL, 0, "<Separator>"},
114 {"/File/Mount", C_"M", mount, 0, NULL},
115 {"/File/Delete", C_"X", delete, 0, NULL},
116 {"/File/Disk Usage", C_"U", NULL, 0, NULL},
117 {"/File/Permissions", NULL, NULL, 0, NULL},
118 {"/File/Touch", NULL, NULL, 0, NULL},
119 {"/File/Find", NULL, NULL, 0, NULL},
120 {"/Select All", C_"A", select_all, 0, NULL},
121 {"/Clear Selection", C_"Z", clear_selection, 0, NULL},
122 {"/Options...", NULL, show_options, 0, NULL},
123 {"/New directory", NULL, new_directory, 0, NULL},
124 {"/Xterm here", NULL, xterm_here, 0, NULL},
125 {"/Open parent", NULL, open_parent, 0, NULL},
128 static GtkItemFactoryEntry panel_menu_def[] = {
129 {"/Display", NULL, NULL, 0, "<Branch>"},
130 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
131 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
132 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
133 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
134 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
135 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
136 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
137 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
138 {"/Display/Sort by Owner", NULL, NULL, 0, "/Display/Sort by Name"},
139 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
140 {"/Display/Show Hidden", NULL, hidden, 0, "<ToggleItem>"},
141 {"/Display/Refresh", NULL, refresh, 0, NULL},
142 {"/File", NULL, NULL, 0, "<Branch>"},
143 {"/File/Help", NULL, help, 0, NULL},
144 {"/File/Info", NULL, show_file_info, 0, NULL},
145 {"/File/Delete", NULL, delete, 0, NULL},
146 {"/Open as directory", NULL, open_as_dir, 0, NULL},
147 {"/Close panel", NULL, close_panel, 0, NULL},
150 void menu_init()
152 GtkItemFactory *item_factory;
153 char *menurc;
154 GList *items;
156 filer_keys = gtk_accel_group_new();
157 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
158 "<filer>",
159 filer_keys);
160 gtk_item_factory_create_items(item_factory,
161 sizeof(filer_menu_def) / sizeof(*filer_menu_def),
162 filer_menu_def,
163 NULL);
164 filer_menu = gtk_item_factory_get_widget(item_factory, "<filer>");
165 filer_file_menu = gtk_item_factory_get_widget(item_factory,
166 "<filer>/File");
167 items = gtk_container_children(GTK_CONTAINER(filer_menu));
168 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
169 g_list_free(items);
171 panel_keys = gtk_accel_group_new();
172 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
173 "<panel>",
174 panel_keys);
175 gtk_item_factory_create_items(item_factory,
176 sizeof(panel_menu_def) / sizeof(*panel_menu_def),
177 panel_menu_def,
178 NULL);
179 panel_menu = gtk_item_factory_get_widget(item_factory, "<panel>");
180 panel_file_menu = gtk_item_factory_get_widget(item_factory,
181 "<panel>/File");
182 items = gtk_container_children(GTK_CONTAINER(panel_menu));
183 panel_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
184 g_list_free(items);
186 menurc = choices_find_path_load("menus");
187 if (menurc)
188 gtk_item_factory_parse_rc(menurc);
190 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
191 GTK_SIGNAL_FUNC(menu_closed), NULL);
192 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
193 GTK_SIGNAL_FUNC(menu_closed), NULL);
195 gtk_accel_group_lock(panel_keys);
197 options_sections = g_slist_prepend(options_sections, &options);
198 xterm_here_value = g_strdup("xterm");
199 option_register("xterm_here", load_xterm_here);
202 /* Build up some option widgets to go in the options dialog, but don't
203 * fill them in yet.
205 static GtkWidget *create_options()
207 GtkWidget *table, *label;
209 table = gtk_table_new(2, 2, FALSE);
210 gtk_container_set_border_width(GTK_CONTAINER(table), 4);
212 label = gtk_label_new("To set the keyboard short-cuts you simply open "
213 "the menu over a filer window, move the pointer over "
214 "the item you want to use and press a key. The key "
215 "will appear next to the menu item and you can just "
216 "press that key without opening the menu in future. "
217 "To save the current menu short-cuts for next time, "
218 "click the Save button at the bottom of this window.");
219 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
220 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
222 label = gtk_label_new("'Xterm here' program:");
223 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
224 xterm_here_entry = gtk_entry_new();
225 gtk_table_attach_defaults(GTK_TABLE(table), xterm_here_entry,
226 1, 2, 1, 2);
228 return table;
231 static char *load_xterm_here(char *data)
233 g_free(xterm_here_value);
234 xterm_here_value = g_strdup(data);
235 return NULL;
238 static void update_options()
240 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry), xterm_here_value);
243 static void set_options()
245 g_free(xterm_here_value);
246 xterm_here_value = g_strdup(gtk_entry_get_text(
247 GTK_ENTRY(xterm_here_entry)));
250 static void save_options()
252 char *menurc;
254 menurc = choices_find_path_save("menus");
255 if (menurc)
256 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
258 option_write("xterm_here", xterm_here_value);
262 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state)
264 GList *items, *item;
266 items = gtk_container_children(GTK_CONTAINER(menu));
268 item = g_list_nth(items, from);
269 while (item && n--)
271 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
272 item = item->next;
275 g_list_free(items);
278 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
280 int *pos = (int *) data;
281 int swidth, sheight;
282 GtkRequisition requisition;
284 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth, &sheight);
285 /* XXX: GDK sometimes seems to get the height wrong... */
286 if (sheight < 2)
288 g_print("ROX-Filer: Root window height reported as %d\n",
289 sheight);
290 sheight = 768;
293 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
295 if (pos[0] == -1)
296 *x = swidth - MENU_MARGIN - requisition.width;
297 else if (pos[0] == -2)
298 *x = MENU_MARGIN;
299 else
300 *x = pos[0] - (requisition.width >> 2);
302 if (pos[1] == -1)
303 *y = sheight - MENU_MARGIN - requisition.height;
304 else if (pos[1] == -2)
305 *y = MENU_MARGIN;
306 else
307 *y = pos[1] - (requisition.height >> 2);
309 *x = CLAMP(*x, 0, swidth - requisition.width);
310 *y = CLAMP(*y, 0, sheight - requisition.height);
313 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
314 int item)
316 GString *buffer;
317 GtkWidget *file_label, *file_menu;
318 FileItem *file_item;
319 int pos[] = {event->x_root, event->y_root};
321 window_with_focus = filer_window;
323 if (filer_window->panel)
325 switch (filer_window->panel_side)
327 case TOP: pos[1] = -2; break;
328 case BOTTOM: pos[1] = -1; break;
329 case LEFT: pos[0] = -2; break;
330 case RIGHT: pos[0] = -1; break;
334 if (filer_window->panel)
336 collection_clear_selection(filer_window->collection);
337 panel_set_timeout(NULL, 0);
340 if (filer_window->collection->number_selected == 0 && item >= 0)
342 collection_select_item(filer_window->collection, item);
343 filer_window->temp_item_selected = TRUE;
345 else
346 filer_window->temp_item_selected = FALSE;
348 if (filer_window->panel)
350 file_label = panel_file_item;
351 file_menu = panel_file_menu;
353 else
355 file_label = filer_file_item;
356 file_menu = filer_file_menu;
359 buffer = g_string_new(NULL);
360 switch (filer_window->collection->number_selected)
362 case 0:
363 g_string_assign(buffer, "<nothing selected>");
364 items_sensitive(file_menu, 0, 5, FALSE);
365 items_sensitive(file_menu, 6, -1, FALSE);
366 gtk_widget_set_sensitive(file_label, FALSE);
367 break;
368 case 1:
369 items_sensitive(file_menu, 0, 5, TRUE);
370 items_sensitive(file_menu, 6, -1, TRUE);
371 gtk_widget_set_sensitive(file_label, TRUE);
372 file_item = selected_item(filer_window->collection);
373 g_string_sprintf(buffer, "%s '%s'",
374 basetype_name(file_item),
375 file_item->leafname);
376 break;
377 default:
378 items_sensitive(file_menu, 0, 5, FALSE);
379 items_sensitive(file_menu, 6, -1, TRUE);
380 gtk_widget_set_sensitive(file_label, TRUE);
381 g_string_sprintf(buffer, "%d items",
382 filer_window->collection->number_selected);
383 break;
386 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
388 g_string_free(buffer, TRUE);
390 gtk_menu_popup(filer_window->panel ? GTK_MENU(panel_menu)
391 : GTK_MENU(filer_menu),
392 NULL, NULL, position_menu,
393 (gpointer) pos, event->button, event->time);
396 static void menu_closed(GtkWidget *widget)
398 if (window_with_focus == NULL)
399 return; /* Close panel item chosen? */
401 if (window_with_focus->temp_item_selected)
403 collection_clear_selection(window_with_focus->collection);
404 window_with_focus->temp_item_selected = FALSE;
408 /* Actions */
410 static void hidden(gpointer data, guint action, GtkWidget *widget)
412 g_return_if_fail(window_with_focus != NULL);
414 window_with_focus->show_hidden = !window_with_focus->show_hidden;
415 scan_dir(window_with_focus);
418 static void refresh(gpointer data, guint action, GtkWidget *widget)
420 g_return_if_fail(window_with_focus != NULL);
422 scan_dir(window_with_focus);
425 static void delete(gpointer data, guint action, GtkWidget *widget)
427 g_return_if_fail(window_with_focus != NULL);
429 action_delete(window_with_focus);
432 static gboolean copy_cb(char *initial, char *path)
434 char *new_dir, *slash;
435 int len;
436 GString *command;
437 gboolean retval = TRUE;
439 slash = strrchr(path, '/');
440 if (!slash)
442 report_error("ROX-Filer", "Missing '/' in new pathname");
443 return FALSE;
446 if (access(path, F_OK) == 0)
448 report_error("ROX-Filer",
449 "An item with this name already exists");
450 return FALSE;
453 len = slash - path;
454 new_dir = g_malloc(len + 1);
455 memcpy(new_dir, path, len);
456 new_dir[len] = '\0';
458 command = g_string_new(NULL);
459 g_string_sprintf(command, "cp -a %s %s", initial, path);
461 if (system(command->str))
463 g_string_append(command, " failed!");
464 report_error("ROX-Filer", command->str);
465 retval = FALSE;
468 g_string_free(command, TRUE);
470 refresh_dirs(new_dir);
471 return retval;
474 static void copy_item(gpointer data, guint action, GtkWidget *widget)
476 Collection *collection;
478 g_return_if_fail(window_with_focus != NULL);
480 collection = window_with_focus->collection;
481 if (collection->number_selected != 1)
482 report_error("ROX-Filer", "You must select a single "
483 "item to copy");
484 else
486 FileItem *item = selected_item(collection);
488 savebox_show(window_with_focus, "Copy",
489 window_with_focus->path, item->leafname,
490 item->image, copy_cb);
494 static gboolean rename_cb(char *initial, char *path)
496 if (rename(initial, path))
498 report_error("ROX-Filer: rename()", g_strerror(errno));
499 return FALSE;
501 return TRUE;
504 static void rename_item(gpointer data, guint action, GtkWidget *widget)
506 Collection *collection;
508 g_return_if_fail(window_with_focus != NULL);
510 collection = window_with_focus->collection;
511 if (collection->number_selected != 1)
512 report_error("ROX-Filer", "You must select a single "
513 "item to rename");
514 else
516 FileItem *item = selected_item(collection);
518 savebox_show(window_with_focus, "Rename",
519 window_with_focus->path, item->leafname,
520 item->image, rename_cb);
524 static gboolean link_cb(char *initial, char *path)
526 if (symlink(initial, path))
528 report_error("ROX-Filer: symlink()", g_strerror(errno));
529 return FALSE;
531 return TRUE;
534 static void link_item(gpointer data, guint action, GtkWidget *widget)
536 Collection *collection;
538 g_return_if_fail(window_with_focus != NULL);
540 collection = window_with_focus->collection;
541 if (collection->number_selected != 1)
542 report_error("ROX-Filer", "You must select a single "
543 "item to link");
544 else
546 FileItem *item = selected_item(collection);
548 savebox_show(window_with_focus, "Symlink",
549 window_with_focus->path, item->leafname,
550 item->image, link_cb);
554 static void show_file_info(gpointer data, guint action, GtkWidget *widget)
556 GtkWidget *window, *table, *label, *button, *frame;
557 GtkWidget *file_label;
558 GString *gstring;
559 char *string;
560 int file_data[2];
561 char *path;
562 char buffer[20];
563 char *argv[] = {"file", "-b", NULL, NULL};
564 int got;
565 Collection *collection;
566 FileItem *file;
567 struct stat info;
569 g_return_if_fail(window_with_focus != NULL);
571 collection = window_with_focus->collection;
572 if (collection->number_selected != 1)
574 report_error("ROX-Filer", "You must select a single "
575 "item before using Info");
576 return;
578 file = selected_item(collection);
579 path = make_path(window_with_focus->path, file->leafname)->str;
580 if (lstat(path, &info))
582 delayed_error("ROX-Filer", g_strerror(errno));
583 return;
586 gstring = g_string_new(NULL);
588 window = gtk_window_new(GTK_WINDOW_DIALOG);
589 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
590 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
591 gtk_window_set_title(GTK_WINDOW(window), path);
593 table = gtk_table_new(4, 2, FALSE);
594 gtk_container_add(GTK_CONTAINER(window), table);
595 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
596 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
598 label = gtk_label_new("Owner, group:");
599 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
600 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
601 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
602 g_string_sprintf(gstring, "%s, %s", user_name(info.st_uid),
603 group_name(info.st_gid));
604 label = gtk_label_new(gstring->str);
605 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
607 label = gtk_label_new("Permissions:");
608 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
609 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
610 g_string_sprintf(gstring, "%o", info.st_mode);
611 label = gtk_label_new(gstring->str);
612 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
614 label = gtk_label_new("MIME type:");
615 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
616 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
617 if (file->base_type == TYPE_FILE &&
618 !(file->flags & ITEM_FLAG_EXEC_FILE))
620 string = g_strconcat(file->mime_type->media_type, "/",
621 file->mime_type->subtype, NULL);
622 label = gtk_label_new(string);
623 g_free(string);
625 else
626 label = gtk_label_new("-");
627 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
629 frame = gtk_frame_new("file(1) says...");
630 gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 3, 4);
631 file_label = gtk_label_new("<nothing yet>");
632 gtk_misc_set_padding(GTK_MISC(file_label), 4, 4);
633 gtk_label_set_line_wrap(GTK_LABEL(file_label), TRUE);
634 gtk_container_add(GTK_CONTAINER(frame), file_label);
636 button = gtk_button_new_with_label("OK");
637 gtk_table_attach(GTK_TABLE(table), button, 0, 2, 4, 5,
638 GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 40, 4);
639 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
640 gtk_widget_destroy, GTK_OBJECT(window));
642 gtk_widget_show_all(window);
643 gdk_flush();
645 pipe(file_data);
646 switch (fork())
648 case -1:
649 close(file_data[0]);
650 close(file_data[1]);
651 gtk_label_set_text(GTK_LABEL(file_label),
652 "fork() error");
653 g_string_free(gstring, TRUE);
654 return;
655 case 0:
656 close(file_data[0]);
657 dup2(file_data[1], STDOUT_FILENO);
658 dup2(file_data[1], STDERR_FILENO);
659 argv[2] = path;
660 if (execvp(argv[0], argv))
661 fprintf(stderr, "execvp() error: %s\n",
662 g_strerror(errno));
663 _exit(0);
665 /* We are the parent... */
666 close(file_data[1]);
667 g_string_truncate(gstring, 0);
668 while (gtk_events_pending())
669 g_main_iteration(FALSE);
670 while ((got = read(file_data[0], buffer, sizeof(buffer) - 1)))
672 buffer[got] = '\0';
673 g_string_append(gstring, buffer);
675 close(file_data[0]);
676 gtk_label_set_text(GTK_LABEL(file_label), gstring->str);
677 g_string_free(gstring, TRUE);
680 static void help(gpointer data, guint action, GtkWidget *widget)
682 Collection *collection;
683 FileItem *item;
685 g_return_if_fail(window_with_focus != NULL);
687 collection = window_with_focus->collection;
688 if (collection->number_selected != 1)
690 report_error("ROX-Filer", "You must select a single "
691 "item to get help on");
692 return;
694 item = selected_item(collection);
695 switch (item->base_type)
697 case TYPE_FILE:
698 if (item->flags & ITEM_FLAG_EXEC_FILE)
699 report_error("Executable file",
700 "This is a file with an eXecute bit "
701 "set - it can be run as a program.");
702 else
703 report_error("File",
704 "This is a data file. Try using the "
705 "Info menu item to find out more...");
706 break;
707 case TYPE_DIRECTORY:
708 if (item->flags & ITEM_FLAG_APPDIR)
709 app_show_help(
710 make_path(window_with_focus->path,
711 item->leafname)->str);
712 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
713 report_error("Mount point",
714 "A mount point is a directory which another "
715 "filing system can be mounted on. Everything "
716 "on the mounted filesystem then appears to be "
717 "inside the directory.");
718 else
719 report_error("Directory",
720 "This is a directory. It contains an index to "
721 "other items - open it to see the list.");
722 break;
723 case TYPE_CHAR_DEVICE:
724 case TYPE_BLOCK_DEVICE:
725 report_error("Device file",
726 "Device files allow you to read from or write "
727 "to a device driver as though it was an "
728 "ordinary file.");
729 break;
730 case TYPE_PIPE:
731 report_error("Named pipe",
732 "Pipes allow different programs to "
733 "communicate. One program writes data to the "
734 "pipe while another one reads it out again.");
735 break;
736 case TYPE_SOCKET:
737 report_error("Socket",
738 "Sockets allow processes to communicate.");
739 break;
740 default:
741 report_error("Unknown type",
742 "I couldn't find out what kind of file this "
743 "is. Maybe it doesn't exist anymore or you "
744 "don't have search permission on the directory "
745 "it's in?");
746 break;
750 static void mount(gpointer data, guint action, GtkWidget *widget)
752 FileItem *item;
753 int i;
754 Collection *collection;
755 char *error = NULL;
756 int count = 0;
758 g_return_if_fail(window_with_focus != NULL);
760 collection = window_with_focus->collection;
762 for (i = 0; i < collection->number_of_items; i++)
763 if (collection->items[i].selected)
765 item = (FileItem *) collection->items[i].data;
766 if (item->flags & ITEM_FLAG_MOUNT_POINT)
768 char *argv[] = {"mount", NULL, NULL};
769 int child;
771 count++;
772 if (item->flags & ITEM_FLAG_MOUNTED)
773 argv[0] = "umount";
774 argv[1] = make_path(window_with_focus->path,
775 item->leafname)->str;
776 child = spawn(argv);
777 if (child)
778 waitpid(child, NULL, 0);
779 else
780 error = "Failed to run mount/umount";
783 if (count)
784 scan_dir(window_with_focus);
785 else if (!error)
786 error = "You must select some mount points first!";
788 if (error)
789 report_error("ROX-Filer", error);
792 static void select_all(gpointer data, guint action, GtkWidget *widget)
794 g_return_if_fail(window_with_focus != NULL);
796 collection_select_all(window_with_focus->collection);
797 window_with_focus->temp_item_selected = FALSE;
800 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
802 g_return_if_fail(window_with_focus != NULL);
804 collection_clear_selection(window_with_focus->collection);
805 window_with_focus->temp_item_selected = FALSE;
808 static void show_options(gpointer data, guint action, GtkWidget *widget)
810 g_return_if_fail(window_with_focus != NULL);
812 options_show(window_with_focus);
815 static gboolean new_directory_cb(char *initial, char *path)
817 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO))
819 report_error("mkdir", g_strerror(errno));
820 return FALSE;
822 return TRUE;
825 static void new_directory(gpointer data, guint action, GtkWidget *widget)
827 g_return_if_fail(window_with_focus != NULL);
829 savebox_show(window_with_focus, "Create directory",
830 window_with_focus->path, "NewDir",
831 default_pixmap + TYPE_DIRECTORY, new_directory_cb);
834 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
836 char *argv[] = {xterm_here_value, NULL};
838 g_return_if_fail(window_with_focus != NULL);
840 if (!spawn_full(argv, window_with_focus->path, 0))
841 report_error("ROX-Filer", "Failed to fork() child "
842 "process");
845 static void open_parent(gpointer data, guint action, GtkWidget *widget)
847 g_return_if_fail(window_with_focus != NULL);
849 filer_opendir(make_path(window_with_focus->path, "/..")->str,
850 FALSE, BOTTOM);
853 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
855 g_return_if_fail(window_with_focus != NULL);
857 filer_opendir(window_with_focus->path, FALSE, BOTTOM);
860 static void close_panel(gpointer data, guint action, GtkWidget *widget)
862 g_return_if_fail(window_with_focus != NULL);
864 gtk_widget_destroy(window_with_focus->window);