r87: Updated some of the icons to the NewerLook ones.
[rox-filer.git] / ROX-Filer / src / menu.c
blobf24f4df1c52c7af5dc35f6bcb0b61f054c4df52b
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>
19 #include <time.h>
21 #include <gdk/gdkx.h>
22 #include <gtk/gtk.h>
24 #include "apps.h"
25 #include "action.h"
26 #include "filer.h"
27 #include "type.h"
28 #include "support.h"
29 #include "gui_support.h"
30 #include "options.h"
31 #include "choices.h"
32 #include "savebox.h"
34 #define C_ "<control>"
36 #define MENU_MARGIN 32
38 GtkAccelGroup *filer_keys;
39 GtkAccelGroup *panel_keys;
41 /* Options */
42 static GtkWidget *xterm_here_entry;
43 static char *xterm_here_value;
45 /* Static prototypes */
46 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data);
47 static void menu_closed(GtkWidget *widget);
48 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state);
49 static char *load_xterm_here(char *data);
51 static void not_yet(gpointer data, guint action, GtkWidget *widget);
53 static void hidden(gpointer data, guint action, GtkWidget *widget);
54 static void refresh(gpointer data, guint action, GtkWidget *widget);
56 static void copy_item(gpointer data, guint action, GtkWidget *widget);
57 static void rename_item(gpointer data, guint action, GtkWidget *widget);
58 static void link_item(gpointer data, guint action, GtkWidget *widget);
59 static void help(gpointer data, guint action, GtkWidget *widget);
60 static void show_file_info(gpointer data, guint action, GtkWidget *widget);
61 static void mount(gpointer data, guint action, GtkWidget *widget);
62 static void delete(gpointer data, guint action, GtkWidget *widget);
64 static void select_all(gpointer data, guint action, GtkWidget *widget);
65 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
66 static void show_options(gpointer data, guint action, GtkWidget *widget);
67 static void new_directory(gpointer data, guint action, GtkWidget *widget);
68 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
69 static void open_parent(gpointer data, guint action, GtkWidget *widget);
71 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
72 static void close_panel(gpointer data, guint action, GtkWidget *widget);
74 static GtkWidget *create_options();
75 static void update_options();
76 static void set_options();
77 static void save_options();
79 static OptionsSection options =
81 "Menu options",
82 create_options,
83 update_options,
84 set_options,
85 save_options
89 static GtkWidget *filer_menu; /* The popup filer menu */
90 static GtkWidget *filer_file_item; /* The File '' label */
91 static GtkWidget *filer_file_menu; /* The File '' menu */
92 static GtkWidget *panel_menu; /* The popup panel menu */
93 static GtkWidget *panel_file_item; /* The File '' label */
94 static GtkWidget *panel_file_menu; /* The File '' menu */
96 static gint screen_width, screen_height;
98 static GtkItemFactoryEntry filer_menu_def[] = {
99 {"/Display", NULL, NULL, 0, "<Branch>"},
100 {"/Display/Large Icons", NULL, not_yet, 0, "<RadioItem>"},
101 {"/Display/Small Icons", NULL, not_yet, 0, "/Display/Large Icons"},
102 {"/Display/Full Info", NULL, not_yet, 0, "/Display/Large Icons"},
103 {"/Display/Separator", NULL, not_yet, 0, "<Separator>"},
104 {"/Display/Sort by Name", NULL, not_yet, 0, "<RadioItem>"},
105 {"/Display/Sort by Type", NULL, not_yet, 0, "/Display/Sort by Name"},
106 {"/Display/Sort by Date", NULL, not_yet, 0, "/Display/Sort by Name"},
107 {"/Display/Sort by Size", NULL, not_yet, 0, "/Display/Sort by Name"},
108 {"/Display/Sort by Owner", NULL, not_yet, 0, "/Display/Sort by Name"},
109 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
110 {"/Display/Show Hidden", C_"H", hidden, 0, "<ToggleItem>"},
111 {"/Display/Refresh", C_"L", refresh, 0, NULL},
112 {"/File", NULL, NULL, 0, "<Branch>"},
113 {"/File/Copy...", NULL, copy_item, 0, NULL},
114 {"/File/Rename...", NULL, rename_item, 0, NULL},
115 {"/File/Link...", NULL, link_item, 0, NULL},
116 {"/File/Help", "F1", help, 0, NULL},
117 {"/File/Info", "I", show_file_info, 0, NULL},
118 {"/File/Separator", NULL, NULL, 0, "<Separator>"},
119 {"/File/Mount", "M", mount, 0, NULL},
120 {"/File/Delete", C_"X", delete, 0, NULL},
121 {"/File/Disk Usage", C_"U", not_yet, 0, NULL},
122 {"/File/Permissions", NULL, not_yet, 0, NULL},
123 {"/File/Touch", NULL, not_yet, 0, NULL},
124 {"/File/Find", NULL, not_yet, 0, NULL},
125 {"/Select All", C_"A", select_all, 0, NULL},
126 {"/Clear Selection", C_"Z", clear_selection, 0, NULL},
127 {"/Options...", NULL, show_options, 0, NULL},
128 {"/New directory", NULL, new_directory, 0, NULL},
129 {"/Xterm here", NULL, xterm_here, 0, NULL},
130 {"/Open parent", NULL, open_parent, 0, NULL},
133 static GtkItemFactoryEntry panel_menu_def[] = {
134 {"/Display", NULL, NULL, 0, "<Branch>"},
135 {"/Display/Large Icons", NULL, not_yet, 0, "<RadioItem>"},
136 {"/Display/Small Icons", NULL, not_yet, 0, "/Display/Large Icons"},
137 {"/Display/Full Info", NULL, not_yet, 0, "/Display/Large Icons"},
138 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
139 {"/Display/Sort by Name", NULL, not_yet, 0, "<RadioItem>"},
140 {"/Display/Sort by Type", NULL, not_yet, 0, "/Display/Sort by Name"},
141 {"/Display/Sort by Date", NULL, not_yet, 0, "/Display/Sort by Name"},
142 {"/Display/Sort by Size", NULL, not_yet, 0, "/Display/Sort by Name"},
143 {"/Display/Sort by Owner", NULL, not_yet, 0, "/Display/Sort by Name"},
144 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
145 {"/Display/Show Hidden", NULL, hidden, 0, "<ToggleItem>"},
146 {"/Display/Refresh", NULL, refresh, 0, NULL},
147 {"/File", NULL, NULL, 0, "<Branch>"},
148 {"/File/Help", NULL, help, 0, NULL},
149 {"/File/Info", NULL, show_file_info, 0, NULL},
150 {"/File/Delete", NULL, delete, 0, NULL},
151 {"/Open as directory", NULL, open_as_dir, 0, NULL},
152 {"/Close panel", NULL, close_panel, 0, NULL},
155 void menu_init()
157 GtkItemFactory *item_factory;
158 char *menurc;
159 GList *items;
161 /* This call starts returning strange values after a while, so get
162 * the result here during init.
164 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width, &screen_height);
166 filer_keys = gtk_accel_group_new();
167 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
168 "<filer>",
169 filer_keys);
170 gtk_item_factory_create_items(item_factory,
171 sizeof(filer_menu_def) / sizeof(*filer_menu_def),
172 filer_menu_def,
173 NULL);
174 filer_menu = gtk_item_factory_get_widget(item_factory, "<filer>");
175 filer_file_menu = gtk_item_factory_get_widget(item_factory,
176 "<filer>/File");
177 items = gtk_container_children(GTK_CONTAINER(filer_menu));
178 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
179 g_list_free(items);
181 panel_keys = gtk_accel_group_new();
182 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
183 "<panel>",
184 panel_keys);
185 gtk_item_factory_create_items(item_factory,
186 sizeof(panel_menu_def) / sizeof(*panel_menu_def),
187 panel_menu_def,
188 NULL);
189 panel_menu = gtk_item_factory_get_widget(item_factory, "<panel>");
190 panel_file_menu = gtk_item_factory_get_widget(item_factory,
191 "<panel>/File");
192 items = gtk_container_children(GTK_CONTAINER(panel_menu));
193 panel_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
194 g_list_free(items);
196 menurc = choices_find_path_load("menus");
197 if (menurc)
198 gtk_item_factory_parse_rc(menurc);
200 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
201 GTK_SIGNAL_FUNC(menu_closed), NULL);
202 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
203 GTK_SIGNAL_FUNC(menu_closed), NULL);
205 gtk_accel_group_lock(panel_keys);
207 options_sections = g_slist_prepend(options_sections, &options);
208 xterm_here_value = g_strdup("xterm");
209 option_register("xterm_here", load_xterm_here);
212 /* Build up some option widgets to go in the options dialog, but don't
213 * fill them in yet.
215 static GtkWidget *create_options()
217 GtkWidget *table, *label;
219 table = gtk_table_new(2, 2, FALSE);
220 gtk_container_set_border_width(GTK_CONTAINER(table), 4);
222 label = gtk_label_new("To set the keyboard short-cuts you simply open "
223 "the menu over a filer window, move the pointer over "
224 "the item you want to use and press a key. The key "
225 "will appear next to the menu item and you can just "
226 "press that key without opening the menu in future. "
227 "To save the current menu short-cuts for next time, "
228 "click the Save button at the bottom of this window.");
229 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
230 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
232 label = gtk_label_new("'Xterm here' program:");
233 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
234 xterm_here_entry = gtk_entry_new();
235 gtk_table_attach_defaults(GTK_TABLE(table), xterm_here_entry,
236 1, 2, 1, 2);
238 return table;
241 static char *load_xterm_here(char *data)
243 g_free(xterm_here_value);
244 xterm_here_value = g_strdup(data);
245 return NULL;
248 static void update_options()
250 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry), xterm_here_value);
253 static void set_options()
255 g_free(xterm_here_value);
256 xterm_here_value = g_strdup(gtk_entry_get_text(
257 GTK_ENTRY(xterm_here_entry)));
260 static void save_options()
262 char *menurc;
264 menurc = choices_find_path_save("menus");
265 if (menurc)
266 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
268 option_write("xterm_here", xterm_here_value);
272 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state)
274 GList *items, *item;
276 items = gtk_container_children(GTK_CONTAINER(menu));
278 item = g_list_nth(items, from);
279 while (item && n--)
281 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
282 item = item->next;
285 g_list_free(items);
288 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
290 int *pos = (int *) data;
291 GtkRequisition requisition;
293 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
295 if (pos[0] == -1)
296 *x = screen_width - 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 = screen_height - 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, screen_width - requisition.width);
310 *y = CLAMP(*y, 0, screen_height - 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)
335 collection_clear_selection(filer_window->collection); /* ??? */
337 if (filer_window->collection->number_selected == 0 && item >= 0)
339 collection_select_item(filer_window->collection, item);
340 filer_window->temp_item_selected = TRUE;
342 else
343 filer_window->temp_item_selected = FALSE;
345 if (filer_window->panel)
347 file_label = panel_file_item;
348 file_menu = panel_file_menu;
350 else
352 file_label = filer_file_item;
353 file_menu = filer_file_menu;
356 buffer = g_string_new(NULL);
357 switch (filer_window->collection->number_selected)
359 case 0:
360 g_string_assign(buffer, "<nothing selected>");
361 items_sensitive(file_menu, 0, 5, FALSE);
362 items_sensitive(file_menu, 6, -1, FALSE);
363 gtk_widget_set_sensitive(file_label, FALSE);
364 break;
365 case 1:
366 items_sensitive(file_menu, 0, 5, TRUE);
367 items_sensitive(file_menu, 6, -1, TRUE);
368 gtk_widget_set_sensitive(file_label, TRUE);
369 file_item = selected_item(filer_window->collection);
370 g_string_sprintf(buffer, "%s '%s'",
371 basetype_name(file_item),
372 file_item->leafname);
373 break;
374 default:
375 items_sensitive(file_menu, 0, 5, FALSE);
376 items_sensitive(file_menu, 6, -1, TRUE);
377 gtk_widget_set_sensitive(file_label, TRUE);
378 g_string_sprintf(buffer, "%d items",
379 filer_window->collection->number_selected);
380 break;
383 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
385 g_string_free(buffer, TRUE);
387 gtk_menu_popup(filer_window->panel ? GTK_MENU(panel_menu)
388 : GTK_MENU(filer_menu),
389 NULL, NULL, position_menu,
390 (gpointer) pos, event->button, event->time);
393 static void menu_closed(GtkWidget *widget)
395 if (window_with_focus == NULL)
396 return; /* Close panel item chosen? */
398 if (window_with_focus->temp_item_selected)
400 collection_clear_selection(window_with_focus->collection);
401 window_with_focus->temp_item_selected = FALSE;
405 /* Actions */
407 /* Fake action to warn when a menu item does nothing */
408 static void not_yet(gpointer data, guint action, GtkWidget *widget)
410 delayed_error("ROX-Filer", "Sorry, that feature isn't implemented yet");
413 static void hidden(gpointer data, guint action, GtkWidget *widget)
415 g_return_if_fail(window_with_focus != NULL);
417 window_with_focus->show_hidden = !window_with_focus->show_hidden;
418 update_dir(window_with_focus);
421 static void refresh(gpointer data, guint action, GtkWidget *widget)
423 g_return_if_fail(window_with_focus != NULL);
425 update_dir(window_with_focus);
428 static void delete(gpointer data, guint action, GtkWidget *widget)
430 g_return_if_fail(window_with_focus != NULL);
432 action_delete(window_with_focus);
435 static gboolean copy_cb(char *initial, char *path)
437 char *new_dir, *slash;
438 int len;
439 GString *command;
440 gboolean retval = TRUE;
442 slash = strrchr(path, '/');
443 if (!slash)
445 report_error("ROX-Filer", "Missing '/' in new pathname");
446 return FALSE;
449 if (access(path, F_OK) == 0)
451 report_error("ROX-Filer",
452 "An item with this name already exists");
453 return FALSE;
456 len = slash - path;
457 new_dir = g_malloc(len + 1);
458 memcpy(new_dir, path, len);
459 new_dir[len] = '\0';
461 command = g_string_new(NULL);
462 g_string_sprintf(command, "cp -a %s %s", initial, path);
464 if (system(command->str))
466 g_string_append(command, " failed!");
467 report_error("ROX-Filer", command->str);
468 retval = FALSE;
471 g_string_free(command, TRUE);
473 refresh_dirs(new_dir);
474 return retval;
477 static void copy_item(gpointer data, guint action, GtkWidget *widget)
479 Collection *collection;
481 g_return_if_fail(window_with_focus != NULL);
483 collection = window_with_focus->collection;
484 if (collection->number_selected != 1)
485 report_error("ROX-Filer", "You must select a single "
486 "item to copy");
487 else
489 FileItem *item = selected_item(collection);
491 savebox_show(window_with_focus, "Copy",
492 window_with_focus->path, item->leafname,
493 item->image, copy_cb);
497 static gboolean rename_cb(char *initial, char *path)
499 if (rename(initial, path))
501 report_error("ROX-Filer: rename()", g_strerror(errno));
502 return FALSE;
504 return TRUE;
507 static void rename_item(gpointer data, guint action, GtkWidget *widget)
509 Collection *collection;
511 g_return_if_fail(window_with_focus != NULL);
513 collection = window_with_focus->collection;
514 if (collection->number_selected != 1)
515 report_error("ROX-Filer", "You must select a single "
516 "item to rename");
517 else
519 FileItem *item = selected_item(collection);
521 savebox_show(window_with_focus, "Rename",
522 window_with_focus->path, item->leafname,
523 item->image, rename_cb);
527 static gboolean link_cb(char *initial, char *path)
529 if (symlink(initial, path))
531 report_error("ROX-Filer: symlink()", g_strerror(errno));
532 return FALSE;
534 return TRUE;
537 static void link_item(gpointer data, guint action, GtkWidget *widget)
539 Collection *collection;
541 g_return_if_fail(window_with_focus != NULL);
543 collection = window_with_focus->collection;
544 if (collection->number_selected != 1)
545 report_error("ROX-Filer", "You must select a single "
546 "item to link");
547 else
549 FileItem *item = selected_item(collection);
551 savebox_show(window_with_focus, "Symlink",
552 window_with_focus->path, item->leafname,
553 item->image, link_cb);
557 static void show_file_info(gpointer data, guint action, GtkWidget *widget)
559 GtkWidget *window, *table, *label, *button, *frame;
560 GtkWidget *file_label;
561 GString *gstring;
562 char *string;
563 int file_data[2];
564 char *path;
565 char buffer[20];
566 char *argv[] = {"file", "-b", NULL, NULL};
567 int got;
568 Collection *collection;
569 FileItem *file;
570 struct stat info;
572 g_return_if_fail(window_with_focus != NULL);
574 collection = window_with_focus->collection;
575 if (collection->number_selected != 1)
577 report_error("ROX-Filer", "You must select a single "
578 "item before using Info");
579 return;
581 file = selected_item(collection);
582 path = make_path(window_with_focus->path, file->leafname)->str;
583 if (lstat(path, &info))
585 delayed_error("ROX-Filer", g_strerror(errno));
586 return;
589 gstring = g_string_new(NULL);
591 window = gtk_window_new(GTK_WINDOW_DIALOG);
592 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
593 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
594 gtk_window_set_title(GTK_WINDOW(window), path);
596 table = gtk_table_new(9, 2, FALSE);
597 gtk_container_add(GTK_CONTAINER(window), table);
598 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
599 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
601 label = gtk_label_new("Owner, group:");
602 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
603 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
604 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
605 g_string_sprintf(gstring, "%s, %s", user_name(info.st_uid),
606 group_name(info.st_gid));
607 label = gtk_label_new(gstring->str);
608 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
609 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
611 label = gtk_label_new("Size:");
612 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
613 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
614 g_string_sprintf(gstring, "%ld", info.st_size);
615 label = gtk_label_new(gstring->str);
616 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
617 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2);
619 label = gtk_label_new("Change time:");
620 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
621 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
622 g_string_sprintf(gstring, "%s", ctime(&info.st_ctime));
623 g_string_truncate(gstring, gstring->len - 1);
624 label = gtk_label_new(gstring->str);
625 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
626 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 2, 3);
628 label = gtk_label_new("Modify time:");
629 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
630 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
631 g_string_sprintf(gstring, "%s", ctime(&info.st_mtime));
632 g_string_truncate(gstring, gstring->len - 1);
633 label = gtk_label_new(gstring->str);
634 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
635 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 3, 4);
637 label = gtk_label_new("Access time:");
638 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
639 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5);
640 g_string_sprintf(gstring, "%s", ctime(&info.st_atime));
641 g_string_truncate(gstring, gstring->len - 1);
642 label = gtk_label_new(gstring->str);
643 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
644 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 4, 5);
646 label = gtk_label_new("Permissions:");
647 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
648 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 5, 6);
649 g_string_sprintf(gstring, "%o", info.st_mode);
650 label = gtk_label_new(gstring->str);
651 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
652 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 5, 6);
654 label = gtk_label_new("MIME type:");
655 gtk_misc_set_alignment(GTK_MISC(label), 1, .5);
656 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 6, 7);
657 if (file->mime_type)
659 string = g_strconcat(file->mime_type->media_type, "/",
660 file->mime_type->subtype, NULL);
661 label = gtk_label_new(string);
662 g_free(string);
664 else
665 label = gtk_label_new("-");
666 gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
667 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 6, 7);
669 frame = gtk_frame_new("file(1) says...");
670 gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 7, 8);
671 file_label = gtk_label_new("<nothing yet>");
672 gtk_misc_set_padding(GTK_MISC(file_label), 4, 4);
673 gtk_label_set_line_wrap(GTK_LABEL(file_label), TRUE);
674 gtk_container_add(GTK_CONTAINER(frame), file_label);
676 button = gtk_button_new_with_label("OK");
677 gtk_table_attach(GTK_TABLE(table), button, 0, 2, 8, 9,
678 GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 40, 4);
679 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
680 gtk_widget_destroy, GTK_OBJECT(window));
682 gtk_widget_show_all(window);
683 gdk_flush();
685 pipe(file_data);
686 switch (fork())
688 case -1:
689 close(file_data[0]);
690 close(file_data[1]);
691 gtk_label_set_text(GTK_LABEL(file_label),
692 "fork() error");
693 g_string_free(gstring, TRUE);
694 return;
695 case 0:
696 close(file_data[0]);
697 dup2(file_data[1], STDOUT_FILENO);
698 dup2(file_data[1], STDERR_FILENO);
699 argv[2] = path;
700 if (execvp(argv[0], argv))
701 fprintf(stderr, "execvp() error: %s\n",
702 g_strerror(errno));
703 _exit(0);
705 /* We are the parent... */
706 close(file_data[1]);
707 g_string_truncate(gstring, 0);
708 while (gtk_events_pending())
709 g_main_iteration(FALSE);
710 while ((got = read(file_data[0], buffer, sizeof(buffer) - 1)))
712 buffer[got] = '\0';
713 g_string_append(gstring, buffer);
715 close(file_data[0]);
716 gtk_label_set_text(GTK_LABEL(file_label), gstring->str);
717 g_string_free(gstring, TRUE);
720 static void help(gpointer data, guint action, GtkWidget *widget)
722 Collection *collection;
723 FileItem *item;
725 g_return_if_fail(window_with_focus != NULL);
727 collection = window_with_focus->collection;
728 if (collection->number_selected != 1)
730 report_error("ROX-Filer", "You must select a single "
731 "item to get help on");
732 return;
734 item = selected_item(collection);
735 switch (item->base_type)
737 case TYPE_FILE:
738 if (item->flags & ITEM_FLAG_EXEC_FILE)
739 report_error("Executable file",
740 "This is a file with an eXecute bit "
741 "set - it can be run as a program.");
742 else
743 report_error("File",
744 "This is a data file. Try using the "
745 "Info menu item to find out more...");
746 break;
747 case TYPE_DIRECTORY:
748 if (item->flags & ITEM_FLAG_APPDIR)
749 app_show_help(
750 make_path(window_with_focus->path,
751 item->leafname)->str);
752 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
753 report_error("Mount point",
754 "A mount point is a directory which another "
755 "filing system can be mounted on. Everything "
756 "on the mounted filesystem then appears to be "
757 "inside the directory.");
758 else
759 report_error("Directory",
760 "This is a directory. It contains an index to "
761 "other items - open it to see the list.");
762 break;
763 case TYPE_CHAR_DEVICE:
764 case TYPE_BLOCK_DEVICE:
765 report_error("Device file",
766 "Device files allow you to read from or write "
767 "to a device driver as though it was an "
768 "ordinary file.");
769 break;
770 case TYPE_PIPE:
771 report_error("Named pipe",
772 "Pipes allow different programs to "
773 "communicate. One program writes data to the "
774 "pipe while another one reads it out again.");
775 break;
776 case TYPE_SOCKET:
777 report_error("Socket",
778 "Sockets allow processes to communicate.");
779 break;
780 default:
781 report_error("Unknown type",
782 "I couldn't find out what kind of file this "
783 "is. Maybe it doesn't exist anymore or you "
784 "don't have search permission on the directory "
785 "it's in?");
786 break;
790 static void mount(gpointer data, guint action, GtkWidget *widget)
792 FileItem *item;
793 int i;
794 Collection *collection;
795 char *error = NULL;
796 int count = 0;
798 g_return_if_fail(window_with_focus != NULL);
800 collection = window_with_focus->collection;
802 for (i = 0; i < collection->number_of_items; i++)
803 if (collection->items[i].selected)
805 item = (FileItem *) collection->items[i].data;
806 if (item->flags & ITEM_FLAG_MOUNT_POINT)
808 char *argv[] = {"mount", NULL, NULL};
809 int child;
811 count++;
812 if (item->flags & ITEM_FLAG_MOUNTED)
813 argv[0] = "umount";
814 argv[1] = make_path(window_with_focus->path,
815 item->leafname)->str;
816 child = spawn(argv);
817 if (child)
818 waitpid(child, NULL, 0);
819 else
820 error = "Failed to run mount/umount";
823 if (count)
824 update_dir(window_with_focus);
825 else if (!error)
826 error = "You must select some mount points first!";
828 if (error)
829 report_error("ROX-Filer", error);
832 static void select_all(gpointer data, guint action, GtkWidget *widget)
834 g_return_if_fail(window_with_focus != NULL);
836 collection_select_all(window_with_focus->collection);
837 window_with_focus->temp_item_selected = FALSE;
840 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
842 g_return_if_fail(window_with_focus != NULL);
844 collection_clear_selection(window_with_focus->collection);
845 window_with_focus->temp_item_selected = FALSE;
848 static void show_options(gpointer data, guint action, GtkWidget *widget)
850 g_return_if_fail(window_with_focus != NULL);
852 options_show(window_with_focus);
855 static gboolean new_directory_cb(char *initial, char *path)
857 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO))
859 report_error("mkdir", g_strerror(errno));
860 return FALSE;
862 return TRUE;
865 static void new_directory(gpointer data, guint action, GtkWidget *widget)
867 g_return_if_fail(window_with_focus != NULL);
869 savebox_show(window_with_focus, "Create directory",
870 window_with_focus->path, "NewDir",
871 default_pixmap + TYPE_DIRECTORY, new_directory_cb);
874 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
876 char *argv[] = {xterm_here_value, NULL};
878 g_return_if_fail(window_with_focus != NULL);
880 if (!spawn_full(argv, window_with_focus->path, 0))
881 report_error("ROX-Filer", "Failed to fork() child "
882 "process");
885 static void open_parent(gpointer data, guint action, GtkWidget *widget)
887 g_return_if_fail(window_with_focus != NULL);
889 filer_opendir(make_path(window_with_focus->path, "/..")->str,
890 FALSE, BOTTOM);
893 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
895 g_return_if_fail(window_with_focus != NULL);
897 filer_opendir(window_with_focus->path, FALSE, BOTTOM);
900 static void close_panel(gpointer data, guint action, GtkWidget *widget)
902 g_return_if_fail(window_with_focus != NULL);
904 gtk_widget_destroy(window_with_focus->window);