r340: Renaming now uses the action windows. This means that you can now
[rox-filer/ma.git] / ROX-Filer / src / menu.c
blob147faad29dc3606f78bb2394ababd7d5e721b4e5
1 /*
2 * $Id$
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)
10 * any later version.
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
15 * more details.
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
22 /* menu.c - code for handling the popup menu */
24 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/wait.h>
28 #include <sys/param.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
33 #include <gtk/gtk.h>
35 #include "global.h"
37 #include "menu.h"
38 #include "run.h"
39 #include "action.h"
40 #include "filer.h"
41 #include "pixmaps.h"
42 #include "type.h"
43 #include "support.h"
44 #include "gui_support.h"
45 #include "options.h"
46 #include "choices.h"
47 #include "gtksavebox.h"
48 #include "mount.h"
49 #include "minibuffer.h"
50 #include "i18n.h"
51 #include "main.h"
52 #include "pinboard.h"
53 #include "dir.h"
55 #define C_ "<control>"
57 #define MENU_MARGIN 32
59 typedef void (*ActionFn)(GSList *paths, char *dest_dir, char *leaf);
61 GtkAccelGroup *filer_keys;
62 GtkAccelGroup *panel_keys;
63 GtkAccelGroup *pinboard_keys;
65 GtkWidget *popup_menu = NULL; /* Currently open menu */
67 static gint updating_menu = 0; /* Non-zero => ignore activations */
69 /* Options */
70 static GtkWidget *xterm_here_entry;
71 static char *xterm_here_value;
73 /* TRUE if we selected an icon automatically when the menu was opened */
74 static gboolean pin_temp_item_selected;
76 /* Static prototypes */
78 static void save_menus(void);
79 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data);
80 static void pin_menu_closed(GtkWidget *widget);
81 static void menu_closed(GtkWidget *widget);
82 static void items_sensitive(gboolean state);
83 static char *load_xterm_here(char *data);
84 static void savebox_show(guchar *title, guchar *path, MaskedPixmap *image,
85 gboolean (*callback)(guchar *current, guchar *new));
86 static gint save_to_file(GtkSavebox *savebox, guchar *pathname);
87 static GList *list_paths(FilerWindow *filer_window);
88 static void free_paths(GList *paths);
89 static void mark_menus_unmodified(void);
90 static gboolean action_with_leaf(ActionFn action, guchar *current, guchar *new);
92 /* Note that for most of these callbacks none of the arguments are used. */
93 static void large(gpointer data, guint action, GtkWidget *widget);
94 static void small(gpointer data, guint action, GtkWidget *widget);
96 /* (action used in these two - (DetailsType) */
97 static void large_with(gpointer data, guint action, GtkWidget *widget);
98 static void small_with(gpointer data, guint action, GtkWidget *widget);
100 static void sort_name(gpointer data, guint action, GtkWidget *widget);
101 static void sort_type(gpointer data, guint action, GtkWidget *widget);
102 static void sort_size(gpointer data, guint action, GtkWidget *widget);
103 static void sort_date(gpointer data, guint action, GtkWidget *widget);
105 static void hidden(gpointer data, guint action, GtkWidget *widget);
106 static void refresh(gpointer data, guint action, GtkWidget *widget);
108 static void copy_item(gpointer data, guint action, GtkWidget *widget);
109 static void rename_item(gpointer data, guint action, GtkWidget *widget);
110 static void link_item(gpointer data, guint action, GtkWidget *widget);
111 static void open_file(gpointer data, guint action, GtkWidget *widget);
112 static void help(gpointer data, guint action, GtkWidget *widget);
113 static void show_file_info(gpointer data, guint action, GtkWidget *widget);
114 static void mount(gpointer data, guint action, GtkWidget *widget);
115 static void delete(gpointer data, guint action, GtkWidget *widget);
116 static void remove_link(gpointer data, guint action, GtkWidget *widget);
117 static void usage(gpointer data, guint action, GtkWidget *widget);
118 static void chmod_items(gpointer data, guint action, GtkWidget *widget);
119 static void find(gpointer data, guint action, GtkWidget *widget);
121 static void open_vfs_rpm(gpointer data, guint action, GtkWidget *widget);
122 static void open_vfs_utar(gpointer data, guint action, GtkWidget *widget);
123 static void open_vfs_uzip(gpointer data, guint action, GtkWidget *widget);
125 static void select_all(gpointer data, guint action, GtkWidget *widget);
126 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
127 static void show_options(gpointer data, guint action, GtkWidget *widget);
128 static void new_directory(gpointer data, guint action, GtkWidget *widget);
129 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
131 static void open_parent_same(gpointer data, guint action, GtkWidget *widget);
132 static void open_parent(gpointer data, guint action, GtkWidget *widget);
133 static void new_window(gpointer data, guint action, GtkWidget *widget);
134 static void close_window(gpointer data, guint action, GtkWidget *widget);
135 static void enter_path(gpointer data, guint action, GtkWidget *widget);
136 static void shell_command(gpointer data, guint action, GtkWidget *widget);
137 static void run_action(gpointer data, guint action, GtkWidget *widget);
138 static void select_if(gpointer data, guint action, GtkWidget *widget);
139 static void rox_help(gpointer data, guint action, GtkWidget *widget);
141 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
142 static void close_panel(gpointer data, guint action, GtkWidget *widget);
144 static void pin_help(gpointer data, guint action, GtkWidget *widget);
145 static void pin_remove(gpointer data, guint action, GtkWidget *widget);
147 static void set_items_shaded(GtkWidget *menu, gboolean shaded, int from, int n);
149 static GtkWidget *create_options();
150 static void update_options();
151 static void set_options();
152 static void save_options();
154 static OptionsSection options =
156 N_("Menu options"),
157 create_options,
158 update_options,
159 set_options,
160 save_options
164 static GtkWidget *filer_menu; /* The popup filer menu */
165 static GtkWidget *filer_file_item; /* The File '' label */
166 static GtkWidget *filer_file_menu; /* The File '' menu */
167 static GtkWidget *filer_vfs_menu; /* The Open VFS menu */
168 static GtkWidget *filer_hidden_menu; /* The Show Hidden item */
169 static GtkWidget *filer_new_window; /* The New Window item */
170 static GtkWidget *panel_menu; /* The popup panel menu */
171 static GtkWidget *panel_hidden_menu; /* The Show Hidden item */
172 static GtkWidget *pinboard_menu; /* The popup pinboard menu */
174 /* Used for Copy, etc */
175 static GtkWidget *savebox = NULL;
176 static guchar *current_path = NULL;
177 static gboolean (*current_savebox_callback)(guchar *current, guchar *new);
179 #undef N_
180 #define N_(x) x
182 static GtkItemFactoryEntry filer_menu_def[] = {
183 {N_("Display"), NULL, NULL, 0, "<Branch>"},
184 {">" N_("Large Icons"), NULL, large, 0, NULL},
185 {">" N_("Small Icons"), NULL, small, 0, NULL},
186 {">" N_("Large, With..."), NULL, NULL, 0, "<Branch>"},
187 {">>" N_("Summary"), NULL, large_with, DETAILS_SUMMARY, NULL},
188 {">>" N_("Sizes"), NULL, large_with, DETAILS_SIZE, NULL},
189 {">>" N_("Size Bars"), NULL, large_with, DETAILS_SIZE_BARS, NULL},
190 {">" N_("Small, With..."), NULL, NULL, 0, "<Branch>"},
191 {">>" N_("Summary"), NULL, small_with, DETAILS_SUMMARY, NULL},
192 {">>" N_("Sizes"), NULL, small_with, DETAILS_SIZE, NULL},
193 {">>" N_("Size Bars"), NULL, small_with, DETAILS_SIZE_BARS, NULL},
194 {">", NULL, NULL, 0, "<Separator>"},
195 {">" N_("Sort by Name"), NULL, sort_name, 0, NULL},
196 {">" N_("Sort by Type"), NULL, sort_type, 0, NULL},
197 {">" N_("Sort by Date"), NULL, sort_date, 0, NULL},
198 {">" N_("Sort by Size"), NULL, sort_size, 0, NULL},
199 {">", NULL, NULL, 0, "<Separator>"},
200 {">" N_("Show Hidden"), NULL, hidden, 0, "<ToggleItem>"},
201 {">" N_("Refresh"), NULL, refresh, 0, NULL},
202 {N_("File"), NULL, NULL, 0, "<Branch>"},
203 {">" N_("Copy..."), NULL, copy_item, 0, NULL},
204 {">" N_("Rename..."), NULL, rename_item, 0, NULL},
205 {">" N_("Link..."), NULL, link_item, 0, NULL},
206 {">" N_("Shift Open"), NULL, open_file, 0, NULL},
207 {">" N_("Help"), NULL, help, 0, NULL},
208 {">" N_("Info"), NULL, show_file_info, 0, NULL},
209 {">" N_("Open VFS"), NULL, NULL, 0, "<Branch>"},
210 {">>" N_("Unzip"), NULL, open_vfs_uzip, 0, NULL},
211 {">>" N_("Untar"), NULL, open_vfs_utar, 0, NULL},
212 {">>" N_("RPM"), NULL, open_vfs_rpm, 0, NULL},
213 {">", NULL, NULL, 0, "<Separator>"},
214 {">" N_("Mount"), NULL, mount, 0, NULL},
215 {">" N_("Delete"), NULL, delete, 0, NULL},
216 {">" N_("Disk Usage"), NULL, usage, 0, NULL},
217 {">" N_("Permissions"), NULL, chmod_items, 0, NULL},
218 {">" N_("Find"), NULL, find, 0, NULL},
219 {N_("Select All"), NULL, select_all, 0, NULL},
220 {N_("Clear Selection"), NULL, clear_selection, 0, NULL},
221 {N_("Options..."), NULL, show_options, 0, NULL},
222 {N_("New Directory..."), NULL, new_directory, 0, NULL},
223 {N_("Xterm Here"), NULL, xterm_here, 0, NULL},
224 {N_("Window"), NULL, NULL, 0, "<Branch>"},
225 {">" N_("Parent, New Window"), NULL, open_parent, 0, NULL},
226 {">" N_("Parent, Same Window"), NULL, open_parent_same, 0, NULL},
227 {">" N_("New Window"), NULL, new_window, 0, NULL},
228 {">" N_("Close Window"), NULL, close_window, 0, NULL},
229 {">", NULL, NULL, 0, "<Separator>"},
230 {">" N_("Enter Path..."), NULL, enter_path, 0, NULL},
231 {">" N_("Shell Command..."), NULL, shell_command, 0, NULL},
232 {">" N_("Set Run Action..."), NULL, run_action, 0, NULL},
233 {">" N_("Select If..."), NULL, select_if, 0, NULL},
234 {">", NULL, NULL, 0, "<Separator>"},
235 {">" N_("Show ROX-Filer Help"), NULL, rox_help, 0, NULL},
238 static GtkItemFactoryEntry panel_menu_def[] = {
239 {N_("Display"), NULL, NULL, 0, "<Branch>"},
240 {">" N_("Sort by Name"), NULL, sort_name, 0, NULL},
241 {">" N_("Sort by Type"), NULL, sort_type, 0, NULL},
242 {">" N_("Sort by Date"), NULL, sort_date, 0, NULL},
243 {">" N_("Sort by Size"), NULL, sort_size, 0, NULL},
244 {">", NULL, NULL, 0, "<Separator>"},
245 {">" N_("Show Hidden"), NULL, hidden, 0, "<ToggleItem>"},
246 {">" N_("Refresh"), NULL, refresh, 0, NULL},
247 {N_("Open Panel as Directory"), NULL, open_as_dir, 0, NULL},
248 {N_("Close Panel"), NULL, close_panel, 0, NULL},
249 {"", NULL, NULL, 0, "<Separator>"},
250 {N_("ROX-Filer Help"), NULL, rox_help, 0, NULL},
251 {N_("ROX-Filer Options..."), NULL, show_options, 0, NULL},
252 {"", NULL, NULL, 0, "<Separator>"},
253 {N_("Show Help"), NULL, help, 0, NULL},
254 {N_("Remove Item"), NULL, remove_link, 0, NULL},
257 static GtkItemFactoryEntry pinboard_menu_def[] = {
258 {N_("Show Help"), NULL, pin_help, 0, NULL},
259 {N_("Remove Item(s)"), NULL, pin_remove, 0, NULL},
260 {"", NULL, NULL, 0, "<Separator>"},
261 {N_("ROX-Filer Help"), NULL, rox_help, 0, NULL},
262 {N_("ROX-Filer Options..."), NULL, show_options, 0, NULL},
266 typedef struct _FileStatus FileStatus;
268 /* This is for the 'file(1) says...' thing */
269 struct _FileStatus
271 int fd; /* FD to read from, -1 if closed */
272 int input; /* Input watcher tag if fd valid */
273 GtkLabel *label; /* Widget to output to */
274 gboolean start; /* No output yet */
277 #define GET_MENU_ITEM(var, menu) \
278 var = gtk_item_factory_get_widget(item_factory, "<" menu ">");
280 #define GET_SMENU_ITEM(var, menu, sub) \
281 do { \
282 tmp = g_strdup_printf("<" menu ">/%s", _(sub)); \
283 var = gtk_item_factory_get_widget(item_factory, tmp); \
284 g_free(tmp); \
285 } while (0)
287 #define GET_SSMENU_ITEM(var, menu, sub, subsub) \
288 do { \
289 tmp = g_strdup_printf("<" menu ">/%s/%s", _(sub), _(subsub)); \
290 var = gtk_item_factory_get_widget(item_factory, tmp); \
291 g_free(tmp); \
292 } while (0)
294 /* Creates menu <name> from the <name>_menu_def array.
295 * The accel group <name>_keys must also have been created.
296 * All menu items are translated. Sets 'item_factory'.
298 #define MAKE_MENU(name) \
299 do { \
300 GtkItemFactoryEntry *translated; \
301 int n_entries; \
303 item_factory = gtk_item_factory_new(GTK_TYPE_MENU, \
304 "<" #name ">", name ## _keys); \
306 n_entries = sizeof(name ## _menu_def) / sizeof(*name ## _menu_def); \
307 translated = translate_entries(name ## _menu_def, n_entries); \
308 gtk_item_factory_create_items (item_factory, n_entries, \
309 translated, NULL); \
310 free_translated_entries(translated, n_entries); \
311 } while (0)
313 void menu_init()
315 char *menurc;
316 GList *items;
317 guchar *tmp;
318 GtkWidget *item;
319 GtkItemFactory *item_factory; \
321 filer_keys = gtk_accel_group_new();
322 MAKE_MENU(filer);
324 GET_MENU_ITEM(filer_menu, "filer");
325 GET_SMENU_ITEM(filer_file_menu, "filer", "File");
326 GET_SSMENU_ITEM(filer_vfs_menu, "filer", "File", "Open VFS");
327 GET_SSMENU_ITEM(filer_hidden_menu, "filer", "Display", "Show Hidden");
329 items = gtk_container_children(GTK_CONTAINER(filer_menu));
330 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
331 g_list_free(items);
333 GET_SSMENU_ITEM(item, "filer", "Window", "New Window");
334 filer_new_window = GTK_BIN(item)->child;
336 panel_keys = gtk_accel_group_new();
337 MAKE_MENU(panel);
339 GET_MENU_ITEM(panel_menu, "panel");
340 GET_SSMENU_ITEM(panel_hidden_menu, "panel", "Display", "Show Hidden");
342 menurc = choices_find_path_load("menus", PROJECT);
343 if (menurc)
345 gtk_item_factory_parse_rc(menurc);
346 mark_menus_unmodified();
349 gtk_accel_group_lock(panel_keys);
351 pinboard_keys = gtk_accel_group_new();
352 MAKE_MENU(pinboard);
353 gtk_accel_group_lock(pinboard_keys);
354 GET_MENU_ITEM(pinboard_menu, "pinboard");
356 gtk_signal_connect(GTK_OBJECT(pinboard_menu), "unmap_event",
357 GTK_SIGNAL_FUNC(pin_menu_closed), NULL);
358 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
359 GTK_SIGNAL_FUNC(menu_closed), NULL);
360 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
361 GTK_SIGNAL_FUNC(menu_closed), NULL);
362 gtk_signal_connect(GTK_OBJECT(filer_file_menu), "unmap_event",
363 GTK_SIGNAL_FUNC(menu_closed), NULL);
365 options_sections = g_slist_prepend(options_sections, &options);
366 xterm_here_value = g_strdup("xterm");
367 option_register("xterm_here", load_xterm_here);
369 savebox = gtk_savebox_new();
370 gtk_signal_connect_object(GTK_OBJECT(savebox), "save_to_file",
371 GTK_SIGNAL_FUNC(save_to_file), NULL);
372 gtk_signal_connect_object(GTK_OBJECT(savebox), "save_done",
373 GTK_SIGNAL_FUNC(gtk_widget_hide),
374 GTK_OBJECT(savebox));
376 atexit(save_menus);
379 /* Build up some option widgets to go in the options dialog, but don't
380 * fill them in yet.
382 static GtkWidget *create_options()
384 GtkWidget *table, *label;
386 table = gtk_table_new(2, 2, FALSE);
387 gtk_container_set_border_width(GTK_CONTAINER(table), 4);
389 label = gtk_label_new(
390 _("To set the keyboard short-cuts, simply open "
391 "the menu over a filer window, move the pointer over "
392 "the item you want to use and press a key. The key "
393 "will appear next to the menu item and you can just "
394 "press that key without opening the menu in future."));
395 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
396 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
398 label = gtk_label_new(_("'Xterm here' program:"));
399 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
400 xterm_here_entry = gtk_entry_new();
401 gtk_table_attach_defaults(GTK_TABLE(table), xterm_here_entry,
402 1, 2, 1, 2);
404 return table;
407 static char *load_xterm_here(char *data)
409 g_free(xterm_here_value);
410 xterm_here_value = g_strdup(data);
411 return NULL;
414 static void update_options()
416 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry), xterm_here_value);
419 static void set_options()
421 g_free(xterm_here_value);
422 xterm_here_value = g_strdup(gtk_entry_get_text(
423 GTK_ENTRY(xterm_here_entry)));
426 static void save_options()
428 save_menus();
429 option_write("xterm_here", xterm_here_value);
433 static void items_sensitive(gboolean state)
435 int n = 7;
436 GList *items, *item;
438 items = item = gtk_container_children(GTK_CONTAINER(filer_file_menu));
439 while (item && n--)
441 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
442 item = item->next;
444 g_list_free(items);
446 items = item = gtk_container_children(GTK_CONTAINER(filer_vfs_menu));
447 while (item)
449 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
450 item = item->next;
452 g_list_free(items);
455 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
457 int *pos = (int *) data;
458 GtkRequisition requisition;
460 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
462 if (pos[0] == -1)
463 *x = screen_width - MENU_MARGIN - requisition.width;
464 else if (pos[0] == -2)
465 *x = MENU_MARGIN;
466 else
467 *x = pos[0] - (requisition.width >> 2);
469 if (pos[1] == -1)
470 *y = screen_height - MENU_MARGIN - requisition.height;
471 else if (pos[1] == -2)
472 *y = MENU_MARGIN;
473 else
474 *y = pos[1] - (requisition.height >> 2);
476 *x = CLAMP(*x, 0, screen_width - requisition.width);
477 *y = CLAMP(*y, 0, screen_height - requisition.height);
480 /* Display the pinboard menu. Set icon to NULL if no particular icon
481 * was clicked.
483 void show_pinboard_menu(GdkEventButton *event, PinIcon *icon)
485 int pos[2];
486 GList *icons;
488 if (icon)
490 if (pinboard_is_selected(icon))
491 pin_temp_item_selected = FALSE;
492 else
494 pinboard_select_only(icon);
495 pin_temp_item_selected = TRUE;
499 icons = pinboard_get_selected();
501 pos[0] = event->x_root;
502 pos[1] = event->y_root;
504 if (icons)
506 set_items_shaded(pinboard_menu,
507 icons->next ? TRUE : FALSE , 0, 1);
509 set_items_shaded(pinboard_menu, FALSE, 1, 1);
511 else
512 set_items_shaded(pinboard_menu, TRUE, 0, 2);
514 gtk_menu_popup(GTK_MENU(pinboard_menu), NULL, NULL, position_menu,
515 (gpointer) pos, event->button, event->time);
518 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
519 int item)
521 DirItem *file_item;
522 int pos[2];
524 updating_menu++;
526 pos[0] = event->x_root;
527 pos[1] = event->y_root;
529 window_with_focus = filer_window;
531 switch (filer_window->panel_type)
533 case PANEL_TOP:
534 pos[1] = -2;
535 break;
536 case PANEL_BOTTOM:
537 pos[1] = -1;
538 break;
539 default:
540 break;
543 if (filer_window->panel_type)
544 collection_clear_selection(filer_window->collection); /* ??? */
546 if (filer_window->collection->number_selected == 0 && item >= 0)
548 collection_select_item(filer_window->collection, item);
549 filer_window->temp_item_selected = TRUE;
551 else
552 filer_window->temp_item_selected = FALSE;
554 if (filer_window->panel_type)
556 gtk_check_menu_item_set_active(
557 GTK_CHECK_MENU_ITEM(panel_hidden_menu),
558 filer_window->show_hidden);
560 else
562 GtkWidget *file_label, *file_menu;
563 Collection *collection = filer_window->collection;
564 GString *buffer;
566 file_label = filer_file_item;
567 file_menu = filer_file_menu;
568 gtk_check_menu_item_set_active(
569 GTK_CHECK_MENU_ITEM(filer_hidden_menu),
570 filer_window->show_hidden);
571 buffer = g_string_new(NULL);
572 switch (collection->number_selected)
574 case 0:
575 g_string_assign(buffer, _("Next Click"));
576 items_sensitive(TRUE);
577 break;
578 case 1:
579 items_sensitive(TRUE);
580 file_item = selected_item(
581 filer_window->collection);
582 g_string_sprintf(buffer, "%s '%s'",
583 basetype_name(file_item),
584 file_item->leafname);
585 break;
586 default:
587 items_sensitive(FALSE);
588 g_string_sprintf(buffer, _("%d items"),
589 collection->number_selected);
590 break;
592 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
593 g_string_free(buffer, TRUE);
597 gtk_widget_set_sensitive(filer_new_window, !o_unique_filer_windows);
599 if (filer_window->panel_type)
600 popup_menu = panel_menu;
601 else
602 popup_menu = (event->state & GDK_CONTROL_MASK)
603 ? filer_file_menu
604 : filer_menu;
606 updating_menu--;
608 gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, position_menu,
609 (gpointer) pos, event->button, event->time);
612 static void pin_menu_closed(GtkWidget *widget)
614 if (pin_temp_item_selected)
615 pinboard_clear_selection();
618 static void menu_closed(GtkWidget *widget)
620 if (window_with_focus == NULL || widget != popup_menu)
621 return; /* Close panel item chosen? */
623 popup_menu = NULL;
625 if (window_with_focus->temp_item_selected)
627 collection_clear_selection(window_with_focus->collection);
628 window_with_focus->temp_item_selected = FALSE;
632 void target_callback(Collection *collection, gint item, gpointer real_fn)
634 g_return_if_fail(window_with_focus != NULL);
635 g_return_if_fail(window_with_focus->collection == collection);
636 g_return_if_fail(real_fn != NULL);
638 collection_wink_item(collection, item);
639 collection_clear_selection(collection);
640 collection_select_item(collection, item);
641 ((CollectionTargetFunc)real_fn)(NULL, 0, collection);
642 if (item < collection->number_of_items)
643 collection_unselect_item(collection, item);
646 /* Actions */
648 static void large(gpointer data, guint action, GtkWidget *widget)
650 g_return_if_fail(window_with_focus != NULL);
652 display_set_layout(window_with_focus, "Large");
655 static void small(gpointer data, guint action, GtkWidget *widget)
657 g_return_if_fail(window_with_focus != NULL);
659 display_set_layout(window_with_focus, "Small");
662 static void set_layout(gboolean large, DetailsType details)
664 guchar *style;
666 g_return_if_fail(window_with_focus != NULL);
668 style = g_strdup_printf("%s+%s",
669 large ? "Large" : "Small",
670 details == DETAILS_SUMMARY ? "Summary" :
671 details == DETAILS_SIZE_BARS ? "SizeBars" :
672 "Sizes");
674 display_set_layout(window_with_focus, style);
675 g_free(style);
678 static void large_with(gpointer data, guint action, GtkWidget *widget)
680 set_layout(TRUE, (DetailsType) action);
683 static void small_with(gpointer data, guint action, GtkWidget *widget)
685 set_layout(FALSE, (DetailsType) action);
688 static void sort_name(gpointer data, guint action, GtkWidget *widget)
690 g_return_if_fail(window_with_focus != NULL);
692 display_set_sort_fn(window_with_focus, sort_by_name);
695 static void sort_type(gpointer data, guint action, GtkWidget *widget)
697 g_return_if_fail(window_with_focus != NULL);
699 display_set_sort_fn(window_with_focus, sort_by_type);
702 static void sort_date(gpointer data, guint action, GtkWidget *widget)
704 g_return_if_fail(window_with_focus != NULL);
706 display_set_sort_fn(window_with_focus, sort_by_date);
709 static void sort_size(gpointer data, guint action, GtkWidget *widget)
711 g_return_if_fail(window_with_focus != NULL);
713 display_set_sort_fn(window_with_focus, sort_by_size);
716 static void hidden(gpointer data, guint action, GtkWidget *widget)
718 if (updating_menu)
719 return;
721 g_return_if_fail(window_with_focus != NULL);
723 display_set_hidden(window_with_focus, !window_with_focus->show_hidden);
726 static void refresh(gpointer data, guint action, GtkWidget *widget)
728 g_return_if_fail(window_with_focus != NULL);
730 full_refresh();
731 filer_update_dir(window_with_focus, TRUE);
734 static void mount(gpointer data, guint action, GtkWidget *widget)
736 g_return_if_fail(window_with_focus != NULL);
738 if (window_with_focus->collection->number_selected == 0)
739 collection_target(window_with_focus->collection,
740 target_callback, mount);
741 else
743 GList *paths;
745 paths = list_paths(window_with_focus);
746 action_mount(paths);
747 free_paths(paths);
751 static void delete(gpointer data, guint action, GtkWidget *widget)
753 g_return_if_fail(window_with_focus != NULL);
755 if (window_with_focus->collection->number_selected == 0)
756 collection_target(window_with_focus->collection,
757 target_callback, delete);
758 else
759 action_delete(window_with_focus);
762 static void remove_link(gpointer data, guint action, GtkWidget *widget)
764 g_return_if_fail(window_with_focus != NULL);
766 if (window_with_focus->collection->number_selected > 1)
768 report_error(PROJECT,
769 _("You can only remove one link at a time"));
770 return;
772 else if (window_with_focus->collection->number_selected == 0)
773 collection_target(window_with_focus->collection,
774 target_callback, remove_link);
775 else
777 struct stat info;
778 DirItem *item;
779 guchar *path;
781 item = selected_item(window_with_focus->collection);
783 path = make_path(window_with_focus->path, item->leafname)->str;
784 if (lstat(path, &info))
785 report_error(PROJECT, g_strerror(errno));
786 else if (!S_ISLNK(info.st_mode))
787 report_error(PROJECT,
788 _("You can only remove symbolic links this way - "
789 "try the 'Open Panel as Directory' item."));
790 else if (unlink(path))
791 report_error(PROJECT, g_strerror(errno));
792 else
793 filer_update_dir(window_with_focus, TRUE);
797 static void usage(gpointer data, guint action, GtkWidget *widget)
799 g_return_if_fail(window_with_focus != NULL);
801 if (window_with_focus->collection->number_selected == 0)
802 collection_target(window_with_focus->collection,
803 target_callback, usage);
804 else
805 action_usage(window_with_focus);
808 static void chmod_items(gpointer data, guint action, GtkWidget *widget)
810 g_return_if_fail(window_with_focus != NULL);
812 if (window_with_focus->collection->number_selected == 0)
813 collection_target(window_with_focus->collection,
814 target_callback, chmod_items);
815 else
816 action_chmod(window_with_focus);
819 static void find(gpointer data, guint action, GtkWidget *widget)
821 g_return_if_fail(window_with_focus != NULL);
823 if (window_with_focus->collection->number_selected == 0)
824 collection_target(window_with_focus->collection,
825 target_callback, find);
826 else
827 action_find(window_with_focus);
830 /* This pops up our savebox widget, cancelling any currently open one,
831 * and allows the user to pick a new path for it.
832 * Once the new path has been picked, the callback will be called with
833 * both the current and new paths.
835 static void savebox_show(guchar *title, guchar *path, MaskedPixmap *image,
836 gboolean (*callback)(guchar *current, guchar *new))
838 if (GTK_WIDGET_VISIBLE(savebox))
839 gtk_widget_hide(savebox);
841 if (current_path)
842 g_free(current_path);
843 current_path = g_strdup(path);
844 current_savebox_callback = callback;
846 gtk_window_set_title(GTK_WINDOW(savebox), title);
847 gtk_savebox_set_pathname(GTK_SAVEBOX(savebox), current_path);
848 gtk_savebox_set_icon(GTK_SAVEBOX(savebox), image->pixmap, image->mask);
850 gtk_widget_grab_focus(GTK_SAVEBOX(savebox)->entry);
851 gtk_widget_show(savebox);
854 static gint save_to_file(GtkSavebox *savebox, guchar *pathname)
856 g_return_val_if_fail(current_savebox_callback != NULL,
857 GTK_XDS_SAVE_ERROR);
859 return current_savebox_callback(current_path, pathname)
860 ? GTK_XDS_SAVED : GTK_XDS_SAVE_ERROR;
863 static gboolean copy_cb(guchar *current, guchar *new)
865 return action_with_leaf(action_copy, current, new);
868 static gboolean action_with_leaf(ActionFn action, guchar *current, guchar *new)
870 char *new_dir, *leaf;
871 GSList *local_paths;
873 if (new[0] != '/')
875 report_error(PROJECT, _("New pathname is not absolute"));
876 return FALSE;
879 if (new[strlen(new) - 1] == '/')
881 new_dir = g_strdup(new);
882 leaf = NULL;
884 else
886 guchar *slash;
888 slash = strrchr(new, '/');
889 new_dir = g_strndup(new, slash - new);
890 leaf = slash + 1;
893 local_paths = g_slist_append(NULL, current);
894 action(local_paths, new_dir, leaf);
895 g_slist_free(local_paths);
897 g_free(new_dir);
899 return TRUE;
902 #define SHOW_SAVEBOX(title, callback) \
904 DirItem *item; \
905 guchar *path; \
906 item = selected_item(collection); \
907 path = make_path(window_with_focus->path, item->leafname)->str; \
908 savebox_show(title, path, item->image, callback); \
911 static void copy_item(gpointer data, guint action, GtkWidget *widget)
913 Collection *collection;
915 g_return_if_fail(window_with_focus != NULL);
917 collection = window_with_focus->collection;
918 if (collection->number_selected > 1)
920 report_error(PROJECT, _("You cannot do this to more than "
921 "one item at a time"));
922 return;
924 else if (collection->number_selected != 1)
925 collection_target(collection, target_callback, copy_item);
926 else
927 SHOW_SAVEBOX(_("Copy"), copy_cb);
930 static gboolean rename_cb(guchar *current, guchar *new)
932 return action_with_leaf(action_move, current, new);
935 static void rename_item(gpointer data, guint action, GtkWidget *widget)
937 Collection *collection;
939 g_return_if_fail(window_with_focus != NULL);
941 collection = window_with_focus->collection;
942 if (collection->number_selected > 1)
944 report_error(PROJECT, _("You cannot do this to more than "
945 "one item at a time"));
946 return;
948 else if (collection->number_selected != 1)
949 collection_target(collection, target_callback, rename_item);
950 else
951 SHOW_SAVEBOX(_("Rename"), rename_cb);
954 static gboolean link_cb(guchar *initial, guchar *path)
956 if (symlink(initial, path))
958 report_error("ROX-Filer: symlink()", g_strerror(errno));
959 return FALSE;
961 return TRUE;
964 static void link_item(gpointer data, guint action, GtkWidget *widget)
966 Collection *collection;
968 g_return_if_fail(window_with_focus != NULL);
970 collection = window_with_focus->collection;
971 if (collection->number_selected > 1)
973 report_error(PROJECT, _("You cannot do this to more than "
974 "one item at a time"));
975 return;
977 else if (collection->number_selected != 1)
978 collection_target(collection, target_callback, link_item);
979 else
980 SHOW_SAVEBOX(_("Symlink"), link_cb);
983 static void open_file(gpointer data, guint action, GtkWidget *widget)
985 Collection *collection;
987 g_return_if_fail(window_with_focus != NULL);
989 collection = window_with_focus->collection;
990 if (collection->number_selected > 1)
992 report_error(PROJECT, _("You cannot do this to more than "
993 "one item at a time"));
994 return;
996 else if (collection->number_selected != 1)
997 collection_target(collection, target_callback, open_file);
998 else
999 filer_openitem(window_with_focus,
1000 selected_item_number(collection),
1001 OPEN_SAME_WINDOW | OPEN_SHIFT);
1004 /* Got some data from file(1) - stick it in the window. */
1005 static void add_file_output(FileStatus *fs,
1006 gint source, GdkInputCondition condition)
1008 char buffer[20];
1009 char *str;
1010 int got;
1012 got = read(source, buffer, sizeof(buffer) - 1);
1013 if (got <= 0)
1015 int err = errno;
1016 gtk_input_remove(fs->input);
1017 close(source);
1018 fs->fd = -1;
1019 if (got < 0)
1020 delayed_error(_("ROX-Filer: file(1) says..."),
1021 g_strerror(err));
1022 return;
1024 buffer[got] = '\0';
1026 if (fs->start)
1028 str = "";
1029 fs->start = FALSE;
1031 else
1032 gtk_label_get(fs->label, &str);
1034 str = g_strconcat(str, buffer, NULL);
1035 gtk_label_set_text(fs->label, str);
1036 g_free(str);
1039 static void file_info_destroyed(GtkWidget *widget, FileStatus *fs)
1041 if (fs->fd != -1)
1043 gtk_input_remove(fs->input);
1044 close(fs->fd);
1047 g_free(fs);
1050 /* g_free() the result */
1051 guchar *pretty_type(DirItem *file, guchar *path)
1053 if (file->flags & ITEM_FLAG_SYMLINK)
1055 char p[MAXPATHLEN + 1];
1056 int got;
1057 got = readlink(path, p, MAXPATHLEN);
1058 if (got > 0 && got <= MAXPATHLEN)
1060 p[got] = '\0';
1061 return g_strconcat(_("Symbolic link to "), p, NULL);
1064 return g_strdup(_("Symbolic link"));
1067 if (file->flags & ITEM_FLAG_EXEC_FILE)
1068 return g_strdup(_("Executable file"));
1070 if (file->flags & ITEM_FLAG_APPDIR)
1071 return g_strdup(_("ROX application"));
1073 if (file->flags & ITEM_FLAG_MOUNT_POINT)
1075 MountPoint *mp;
1076 if ((file->flags & ITEM_FLAG_MOUNTED) &&
1077 (mp = g_hash_table_lookup(mtab_mounts, path)))
1078 return g_strconcat(_("Mount point for "),
1079 mp->name, NULL);
1081 return g_strdup(_("Mount point"));
1084 if (file->mime_type)
1085 return g_strconcat(file->mime_type->media_type, "/",
1086 file->mime_type->subtype, NULL);
1088 return g_strdup("-");
1091 #define LABEL(text, row) \
1092 label = gtk_label_new(text); \
1093 gtk_misc_set_alignment(GTK_MISC(label), 1, .5); \
1094 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); \
1095 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, row, row + 1);
1097 #define VALUE(label, row) \
1098 gtk_misc_set_alignment(GTK_MISC(label), 0, .5); \
1099 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, row, row + 1);
1101 static void show_file_info(gpointer data, guint action, GtkWidget *widget)
1103 GtkWidget *window, *table, *label, *button, *frame, *value;
1104 GtkWidget *file_label;
1105 GString *gstring;
1106 int file_data[2];
1107 guchar *path, *tmp;
1108 char *argv[] = {"file", "-b", NULL, NULL};
1109 Collection *collection;
1110 DirItem *file;
1111 struct stat info;
1112 FileStatus *fs = NULL;
1113 guint perm;
1115 g_return_if_fail(window_with_focus != NULL);
1117 collection = window_with_focus->collection;
1118 if (collection->number_selected > 1)
1120 report_error(PROJECT, _("You cannot do this to more than "
1121 "one item at a time"));
1122 return;
1124 else if (collection->number_selected != 1)
1126 collection_target(collection, target_callback, show_file_info);
1127 return;
1129 file = selected_item(collection);
1130 path = make_path(window_with_focus->path,
1131 file->leafname)->str;
1132 if (lstat(path, &info))
1134 delayed_error(PROJECT, g_strerror(errno));
1135 return;
1138 gstring = g_string_new(NULL);
1140 window = gtk_window_new(GTK_WINDOW_DIALOG);
1141 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
1142 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1143 gtk_window_set_title(GTK_WINDOW(window), path);
1145 table = gtk_table_new(10, 2, FALSE);
1146 gtk_container_add(GTK_CONTAINER(window), table);
1147 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
1148 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1150 value = gtk_label_new(file->leafname);
1151 LABEL(_("Name:"), 0);
1152 VALUE(value, 0);
1154 g_string_sprintf(gstring, "%s, %s", user_name(info.st_uid),
1155 group_name(info.st_gid));
1156 value = gtk_label_new(gstring->str);
1157 LABEL(_("Owner, Group:"), 1);
1158 VALUE(value, 1);
1160 if (info.st_size >= PRETTY_SIZE_LIMIT)
1162 g_string_sprintf(gstring, "%s (%ld %s)",
1163 format_size((unsigned long) info.st_size),
1164 (unsigned long) info.st_size, _("bytes"));
1166 else
1168 g_string_assign(gstring,
1169 format_size((unsigned long) info.st_size));
1171 value = gtk_label_new(gstring->str);
1172 LABEL(_("Size:"), 2);
1173 VALUE(value, 2);
1175 value = gtk_label_new(pretty_time(&info.st_ctime));
1176 LABEL(_("Change time:"), 3);
1177 VALUE(value, 3);
1179 value = gtk_label_new(pretty_time(&info.st_mtime));
1180 LABEL(_("Modify time:"), 4);
1181 VALUE(value, 4);
1183 value = gtk_label_new(pretty_time(&info.st_atime));
1184 LABEL(_("Access time:"), 5);
1185 VALUE(value, 5);
1187 value = gtk_label_new(pretty_permissions(info.st_mode));
1188 perm = applicable(info.st_uid, info.st_gid);
1189 gtk_label_set_pattern(GTK_LABEL(value),
1190 perm == 0 ? "___ " :
1191 perm == 1 ? " ___ " :
1192 " ___");
1193 gtk_widget_set_style(value, fixed_style);
1194 LABEL(_("Permissions:"), 6);
1195 VALUE(value, 6);
1197 tmp = pretty_type(file, path);
1198 value = gtk_label_new(tmp);
1199 g_free(tmp);
1200 LABEL(_("Type:"), 7);
1201 VALUE(value, 7);
1203 frame = gtk_frame_new(_("file(1) says..."));
1204 gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 8, 9);
1205 file_label = gtk_label_new(_("<nothing yet>"));
1206 gtk_misc_set_padding(GTK_MISC(file_label), 4, 4);
1207 gtk_label_set_line_wrap(GTK_LABEL(file_label), TRUE);
1208 gtk_container_add(GTK_CONTAINER(frame), file_label);
1210 button = gtk_button_new_with_label(_("OK"));
1211 gtk_window_set_focus(GTK_WINDOW(window), button);
1212 gtk_table_attach(GTK_TABLE(table), button, 0, 2, 10, 11,
1213 GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 40, 4);
1214 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1215 gtk_widget_destroy, GTK_OBJECT(window));
1217 gtk_widget_show_all(window);
1218 gdk_flush();
1220 if (pipe(file_data))
1222 g_string_sprintf(gstring, "pipe(): %s", g_strerror(errno));
1223 g_string_free(gstring, TRUE);
1224 return;
1226 switch (fork())
1228 case -1:
1229 g_string_sprintf(gstring, "fork(): %s",
1230 g_strerror(errno));
1231 gtk_label_set_text(GTK_LABEL(file_label), gstring->str);
1232 g_string_free(gstring, TRUE);
1233 close(file_data[0]);
1234 close(file_data[1]);
1235 break;
1236 case 0:
1237 /* We are the child */
1238 close(file_data[0]);
1239 dup2(file_data[1], STDOUT_FILENO);
1240 dup2(file_data[1], STDERR_FILENO);
1241 #ifdef FILE_B_FLAG
1242 argv[2] = path;
1243 #else
1244 argv[1] = file->leafname;
1245 chdir(window_with_focus->path);
1246 #endif
1247 if (execvp(argv[0], argv))
1248 fprintf(stderr, "execvp() error: %s\n",
1249 g_strerror(errno));
1250 _exit(0);
1251 default:
1252 /* We are the parent */
1253 close(file_data[1]);
1254 fs = g_new(FileStatus, 1);
1255 fs->label = GTK_LABEL(file_label);
1256 fs->fd = file_data[0];
1257 fs->start = TRUE;
1258 fs->input = gdk_input_add(fs->fd, GDK_INPUT_READ,
1259 (GdkInputFunction) add_file_output, fs);
1260 gtk_signal_connect(GTK_OBJECT(window), "destroy",
1261 GTK_SIGNAL_FUNC(file_info_destroyed), fs);
1262 g_string_free(gstring, TRUE);
1263 break;
1267 static void help(gpointer data, guint action, GtkWidget *widget)
1269 Collection *collection;
1270 DirItem *item;
1272 g_return_if_fail(window_with_focus != NULL);
1274 collection = window_with_focus->collection;
1275 if (collection->number_selected > 1)
1277 report_error(PROJECT, _("You cannot do this to more than "
1278 "one item at a time"));
1279 return;
1281 else if (collection->number_selected != 1)
1283 collection_target(collection, target_callback, help);
1284 return;
1286 item = selected_item(collection);
1288 show_item_help(make_path(window_with_focus->path, item->leafname)->str,
1289 item);
1292 #define OPEN_VFS(fs) \
1293 static void open_vfs_ ## fs (gpointer data, guint action, GtkWidget *widget) \
1295 Collection *collection; \
1297 g_return_if_fail(window_with_focus != NULL); \
1299 collection = window_with_focus->collection; \
1300 if (collection->number_selected < 1) \
1301 collection_target(collection, target_callback, \
1302 open_vfs_ ## fs); \
1303 else \
1304 real_vfs_open(#fs); \
1307 static void real_vfs_open(char *fs)
1309 gchar *path;
1310 DirItem *item;
1312 if (window_with_focus->collection->number_selected != 1)
1314 report_error(PROJECT, _("You must select a single file "
1315 "to open as a Virtual File System"));
1316 return;
1319 item = selected_item(window_with_focus->collection);
1321 path = g_strconcat(window_with_focus->path,
1322 "/",
1323 item->leafname,
1324 "#", fs, NULL);
1326 filer_change_to(window_with_focus, path, NULL);
1327 g_free(path);
1330 OPEN_VFS(rpm)
1331 OPEN_VFS(utar)
1332 OPEN_VFS(uzip)
1334 static void select_all(gpointer data, guint action, GtkWidget *widget)
1336 g_return_if_fail(window_with_focus != NULL);
1338 collection_select_all(window_with_focus->collection);
1339 window_with_focus->temp_item_selected = FALSE;
1342 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
1344 g_return_if_fail(window_with_focus != NULL);
1346 collection_clear_selection(window_with_focus->collection);
1347 window_with_focus->temp_item_selected = FALSE;
1350 static void show_options(gpointer data, guint action, GtkWidget *widget)
1352 options_show();
1355 static gboolean new_directory_cb(guchar *initial, guchar *path)
1357 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO))
1359 report_error("mkdir", g_strerror(errno));
1360 return FALSE;
1363 dir_check_this(path);
1364 return TRUE;
1367 static void new_directory(gpointer data, guint action, GtkWidget *widget)
1369 g_return_if_fail(window_with_focus != NULL);
1371 savebox_show(_("New Directory"),
1372 make_path(window_with_focus->path, _("NewDir"))->str,
1373 type_to_icon(&special_directory),
1374 new_directory_cb);
1377 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
1379 char *argv[] = {NULL, NULL};
1381 argv[0] = xterm_here_value;
1383 g_return_if_fail(window_with_focus != NULL);
1385 if (!spawn_full(argv, window_with_focus->path))
1386 report_error(PROJECT, "Failed to fork() child "
1387 "process");
1390 static void open_parent(gpointer data, guint action, GtkWidget *widget)
1392 g_return_if_fail(window_with_focus != NULL);
1394 filer_open_parent(window_with_focus);
1397 static void open_parent_same(gpointer data, guint action, GtkWidget *widget)
1399 g_return_if_fail(window_with_focus != NULL);
1401 change_to_parent(window_with_focus);
1404 static void new_window(gpointer data, guint action, GtkWidget *widget)
1406 g_return_if_fail(window_with_focus != NULL);
1408 if (o_unique_filer_windows)
1409 report_error(PROJECT, _("You can't open a second view onto "
1410 "this directory because the `Unique Windows' option "
1411 "is turned on in the Options window."));
1412 else
1413 filer_opendir(window_with_focus->path);
1416 static void close_window(gpointer data, guint action, GtkWidget *widget)
1418 g_return_if_fail(window_with_focus != NULL);
1420 gtk_widget_destroy(window_with_focus->window);
1423 static void enter_path(gpointer data, guint action, GtkWidget *widget)
1425 g_return_if_fail(window_with_focus != NULL);
1427 minibuffer_show(window_with_focus, MINI_PATH);
1430 static void shell_command(gpointer data, guint action, GtkWidget *widget)
1432 g_return_if_fail(window_with_focus != NULL);
1434 minibuffer_show(window_with_focus, MINI_SHELL);
1437 static void run_action(gpointer data, guint action, GtkWidget *widget)
1439 g_return_if_fail(window_with_focus != NULL);
1441 minibuffer_show(window_with_focus, MINI_RUN_ACTION);
1444 static void select_if(gpointer data, guint action, GtkWidget *widget)
1446 g_return_if_fail(window_with_focus != NULL);
1448 minibuffer_show(window_with_focus, MINI_SELECT_IF);
1451 void rox_help(gpointer data, guint action, GtkWidget *widget)
1453 filer_opendir(make_path(app_dir, "Help")->str);
1456 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
1458 g_return_if_fail(window_with_focus != NULL);
1460 filer_opendir(window_with_focus->path);
1463 static void close_panel(gpointer data, guint action, GtkWidget *widget)
1465 g_return_if_fail(window_with_focus != NULL);
1467 gtk_widget_destroy(window_with_focus->window);
1470 /* Return a list of full paths of all the selected items */
1471 static GList *list_paths(FilerWindow *filer_window)
1473 Collection *collection = filer_window->collection;
1474 GList *paths = NULL;
1475 int i;
1477 for (i = 0; i < collection->number_of_items; i++)
1479 CollectionItem *colitem = &collection->items[i];
1481 if (colitem->selected)
1483 DirItem *item = (DirItem *) colitem->data;
1485 paths = g_list_prepend(paths,
1486 g_strdup(make_path(filer_window->path,
1487 item->leafname)->str));
1491 return paths;
1494 static void free_paths(GList *paths)
1496 GList *next;
1498 if (!paths)
1499 return;
1501 for (next = paths; next; next = next->next)
1502 g_free(next->data);
1504 g_list_free(paths);
1507 static void pin_help(gpointer data, guint action, GtkWidget *widget)
1509 PinIcon *icon;
1511 icon = pinboard_selected_icon();
1513 if (icon)
1514 pinboard_show_help(icon);
1515 else
1516 delayed_error(PROJECT,
1517 _("You must first select a single pinned icon to get "
1518 "help on."));
1521 static void pin_remove(gpointer data, guint action, GtkWidget *widget)
1523 pinboard_unpin_selection();
1526 /* Set n items from position 'from' in 'menu' to the 'shaded' state */
1527 static void set_items_shaded(GtkWidget *menu, gboolean shaded, int from, int n)
1529 GList *items, *item;
1531 items = gtk_container_children(GTK_CONTAINER(menu));
1533 item = g_list_nth(items, from);
1534 while (item && n--)
1536 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, !shaded);
1537 item = item->next;
1539 g_list_free(items);
1542 /* This is called for every modified menu entry. We just use it to
1543 * find out if the menu has changed at all.
1545 static void set_mod(gboolean *mod, guchar *str)
1547 if (str && str[0] == '(')
1548 *mod = TRUE;
1551 static void save_menus(void)
1553 char *menurc;
1555 menurc = choices_find_path_save("menus", PROJECT, TRUE);
1556 if (menurc)
1558 gboolean mod = FALSE;
1560 /* Find out if anything changed... */
1561 gtk_item_factory_dump_items(NULL, TRUE,
1562 (GtkPrintFunc) set_mod, &mod);
1564 /* Dump out if so... */
1565 if (mod)
1566 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
1570 static void mark_unmodified(gpointer hash_key,
1571 gpointer value,
1572 gpointer user_data)
1574 GtkItemFactoryItem *item = (GtkItemFactoryItem *) value;
1576 item->modified = FALSE;
1579 /* Clear the 'modified' flag in all menu items. Messy... */
1580 static void mark_menus_unmodified(void)
1582 GtkItemFactoryClass *class;
1584 class = gtk_type_class(GTK_TYPE_ITEM_FACTORY);
1586 g_hash_table_foreach(class->item_ht, mark_unmodified, NULL);