r569: New display style 'Huge Icons' to make viewing thumbnails easier.
[rox-filer.git] / ROX-Filer / src / menu.c
blobee61947583c27f79c4aa1f092dc2a36e0ca65ea5
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, the ROX-Filer team.
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"
54 #include "appmenu.h"
55 #include "usericons.h"
57 #define C_ "<control>"
59 typedef void (*ActionFn)(GSList *paths, char *dest_dir, char *leaf);
61 GtkAccelGroup *filer_keys;
62 GtkAccelGroup *pinboard_keys;
64 GtkWidget *popup_menu = NULL; /* Currently open menu */
66 static gint updating_menu = 0; /* Non-zero => ignore activations */
68 /* Static prototypes */
70 static void save_menus(void);
71 static void menu_closed(GtkWidget *widget);
72 static void items_sensitive(gboolean state);
73 static void savebox_show(guchar *title, guchar *path, MaskedPixmap *image,
74 gboolean (*callback)(guchar *current, guchar *new));
75 static gint save_to_file(GtkSavebox *savebox, guchar *pathname);
76 static void mark_menus_modified(gboolean mod);
77 static gboolean action_with_leaf(ActionFn action, guchar *current, guchar *new);
78 static gboolean can_set_run_action(DirItem *item);
80 /* Note that for most of these callbacks none of the arguments are used. */
82 /* (action used in these two - DetailsType) */
83 static void huge_icons(gpointer data, guint action, GtkWidget *widget);
84 static void large_with(gpointer data, guint action, GtkWidget *widget);
85 static void small_with(gpointer data, guint action, GtkWidget *widget);
87 static void sort_name(gpointer data, guint action, GtkWidget *widget);
88 static void sort_type(gpointer data, guint action, GtkWidget *widget);
89 static void sort_size(gpointer data, guint action, GtkWidget *widget);
90 static void sort_date(gpointer data, guint action, GtkWidget *widget);
92 static void hidden(gpointer data, guint action, GtkWidget *widget);
93 static void refresh(gpointer data, guint action, GtkWidget *widget);
94 static void create_thumbs(gpointer data, guint action, GtkWidget *widget);
96 static void copy_item(gpointer data, guint action, GtkWidget *widget);
97 static void rename_item(gpointer data, guint action, GtkWidget *widget);
98 static void link_item(gpointer data, guint action, GtkWidget *widget);
99 static void open_file(gpointer data, guint action, GtkWidget *widget);
100 static void help(gpointer data, guint action, GtkWidget *widget);
101 static void show_file_info(gpointer data, guint action, GtkWidget *widget);
102 static void delete(gpointer data, guint action, GtkWidget *widget);
103 static void usage(gpointer data, guint action, GtkWidget *widget);
104 static void chmod_items(gpointer data, guint action, GtkWidget *widget);
105 static void find(gpointer data, guint action, GtkWidget *widget);
107 static void open_vfs_rpm(gpointer data, guint action, GtkWidget *widget);
108 static void open_vfs_utar(gpointer data, guint action, GtkWidget *widget);
109 static void open_vfs_uzip(gpointer data, guint action, GtkWidget *widget);
110 static void open_vfs_deb(gpointer data, guint action, GtkWidget *widget);
112 static void select_all(gpointer data, guint action, GtkWidget *widget);
113 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
114 static void new_directory(gpointer data, guint action, GtkWidget *widget);
115 static void new_file(gpointer data, guint action, GtkWidget *widget);
116 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
118 static void open_parent_same(gpointer data, guint action, GtkWidget *widget);
119 static void open_parent(gpointer data, guint action, GtkWidget *widget);
120 static void home_directory(gpointer data, guint action, GtkWidget *widget);
121 static void new_window(gpointer data, guint action, GtkWidget *widget);
122 /* static void new_user(gpointer data, guint action, GtkWidget *widget); */
123 static void close_window(gpointer data, guint action, GtkWidget *widget);
124 static void enter_path(gpointer data, guint action, GtkWidget *widget);
125 static void shell_command(gpointer data, guint action, GtkWidget *widget);
126 static void run_action(gpointer data, guint action, GtkWidget *widget);
127 static void set_icon(gpointer data, guint action, GtkWidget *widget);
128 static void select_if(gpointer data, guint action, GtkWidget *widget);
129 static void resize(gpointer data, guint action, GtkWidget *widget);
132 static GtkWidget *filer_menu; /* The popup filer menu */
133 static GtkWidget *filer_file_item; /* The File '' label */
134 static GtkWidget *filer_file_menu; /* The File '' menu */
135 static GtkWidget *file_shift_item; /* Shift Open label */
136 GtkWidget *display_large_menu; /* Display->Large With... */
137 GtkWidget *display_small_menu; /* Display->Small With... */
138 static GtkWidget *filer_vfs_menu; /* The Open VFS menu */
139 static GtkWidget *filer_hidden_menu; /* The Show Hidden item */
140 static GtkWidget *filer_new_window; /* The New Window item */
142 /* Used for Copy, etc */
143 static GtkWidget *savebox = NULL;
144 static guchar *current_path = NULL;
145 static gboolean (*current_savebox_callback)(guchar *current, guchar *new);
147 #undef N_
148 #define N_(x) x
150 static GtkItemFactoryEntry filer_menu_def[] = {
151 {N_("Display"), NULL, NULL, 0, "<Branch>"},
152 {">" N_("Huge Icons"), NULL, huge_icons, 0, NULL},
153 {">" N_("Large Icons"), NULL, large_with, DETAILS_NONE, NULL},
154 {">" N_("Small Icons"), NULL, small_with, DETAILS_NONE, NULL},
155 {">" N_("Large, With..."), NULL, NULL, 0, "<Branch>"},
156 {">>" N_("Summary"), NULL, large_with, DETAILS_SUMMARY, NULL},
157 {">>" N_("Sizes"), NULL, large_with, DETAILS_SIZE, NULL},
158 {">>" N_("Permissions"), NULL, large_with, DETAILS_PERMISSIONS, NULL},
159 {">>" N_("Type"), NULL, large_with, DETAILS_TYPE, NULL},
160 {">>" N_("Times"), NULL, large_with, DETAILS_TIMES, NULL},
161 {">" N_("Small, With..."), NULL, NULL, 0, "<Branch>"},
162 {">>" N_("Summary"), NULL, small_with, DETAILS_SUMMARY, NULL},
163 {">>" N_("Sizes"), NULL, small_with, DETAILS_SIZE, NULL},
164 {">>" N_("Permissions"), NULL, small_with, DETAILS_PERMISSIONS, NULL},
165 {">>" N_("Type"), NULL, small_with, DETAILS_TYPE, NULL},
166 {">>" N_("Times"), NULL, small_with, DETAILS_TIMES, NULL},
167 {">", NULL, NULL, 0, "<Separator>"},
168 {">" N_("Sort by Name"), NULL, sort_name, 0, NULL},
169 {">" N_("Sort by Type"), NULL, sort_type, 0, NULL},
170 {">" N_("Sort by Date"), NULL, sort_date, 0, NULL},
171 {">" N_("Sort by Size"), NULL, sort_size, 0, NULL},
172 {">", NULL, NULL, 0, "<Separator>"},
173 {">" N_("Show Hidden"), NULL, hidden, 0, "<ToggleItem>"},
174 {">" N_("Refresh"), NULL, refresh, 0, NULL},
175 {">" N_("Create Thumbs"), NULL, create_thumbs, 0, NULL},
176 {N_("File"), NULL, NULL, 0, "<Branch>"},
177 {">" N_("Copy..."), NULL, copy_item, 0, NULL},
178 {">" N_("Rename..."), NULL, rename_item, 0, NULL},
179 {">" N_("Link..."), NULL, link_item, 0, NULL},
180 {">" N_("Shift Open"), NULL, open_file, 0, NULL},
181 {">" N_("Help"), NULL, help, 0, NULL},
182 {">" N_("Info"), NULL, show_file_info, 0, NULL},
183 {">" N_("Set Run Action..."), NULL, run_action, 0, NULL},
184 {">" N_("Set Icon..."), NULL, set_icon, 0, NULL},
185 {">" N_("Open VFS"), NULL, NULL, 0, "<Branch>"},
186 {">>" N_("Unzip"), NULL, open_vfs_uzip, 0, NULL},
187 {">>" N_("Untar"), NULL, open_vfs_utar, 0, NULL},
188 {">>" N_("Deb"), NULL, open_vfs_deb, 0, NULL},
189 {">>" N_("RPM"), NULL, open_vfs_rpm, 0, NULL},
190 {">", NULL, NULL, 0, "<Separator>"},
191 {">" N_("Delete"), NULL, delete, 0, NULL},
192 {">" N_("Disk Usage"), NULL, usage, 0, NULL},
193 {">" N_("Permissions"), NULL, chmod_items, 0, NULL},
194 {">" N_("Find"), NULL, find, 0, NULL},
195 {N_("Select All"), NULL, select_all, 0, NULL},
196 {N_("Clear Selection"), NULL, clear_selection, 0, NULL},
197 {N_("Options..."), NULL, menu_show_options, 0, NULL},
198 {N_("New Directory..."), NULL, new_directory, 0, NULL},
199 {N_("New File..."), NULL, new_file, 0, NULL},
200 {N_("Xterm Here"), NULL, xterm_here, 0, NULL},
201 {N_("Window"), NULL, NULL, 0, "<Branch>"},
202 {">" N_("Parent, New Window"), NULL, open_parent, 0, NULL},
203 {">" N_("Parent, Same Window"), NULL, open_parent_same, 0, NULL},
204 {">" N_("New Window"), NULL, new_window, 0, NULL},
205 {">" N_("Home Directory"), NULL, home_directory, 0, NULL},
206 {">" N_("Resize Window"), NULL, resize, 0, NULL},
207 /* {">" N_("New, As User..."), NULL, new_user, 0, NULL}, */
209 {">" N_("Close Window"), NULL, close_window, 0, NULL},
210 {">", NULL, NULL, 0, "<Separator>"},
211 {">" N_("Enter Path..."), NULL, enter_path, 0, NULL},
212 {">" N_("Shell Command..."), NULL, shell_command, 0, NULL},
213 {">" N_("Select If..."), NULL, select_if, 0, NULL},
214 {">", NULL, NULL, 0, "<Separator>"},
215 {">" N_("Show ROX-Filer Help"), NULL, menu_rox_help, 0, NULL},
219 typedef struct _FileStatus FileStatus;
221 /* This is for the 'file(1) says...' thing */
222 struct _FileStatus
224 int fd; /* FD to read from, -1 if closed */
225 int input; /* Input watcher tag if fd valid */
226 GtkLabel *label; /* Widget to output to */
227 gboolean start; /* No output yet */
230 #define GET_MENU_ITEM(var, menu) \
231 var = gtk_item_factory_get_widget(item_factory, "<" menu ">");
233 #define GET_SMENU_ITEM(var, menu, sub) \
234 do { \
235 tmp = g_strdup_printf("<" menu ">/%s", _(sub)); \
236 var = gtk_item_factory_get_widget(item_factory, tmp); \
237 g_free(tmp); \
238 } while (0)
240 #define GET_SSMENU_ITEM(var, menu, sub, subsub) \
241 do { \
242 tmp = g_strdup_printf("<" menu ">/%s/%s", _(sub), _(subsub)); \
243 var = gtk_item_factory_get_widget(item_factory, tmp); \
244 g_free(tmp); \
245 } while (0)
247 /* Creates menu <name> from the <name>_menu_def array.
248 * The accel group <name>_keys must also have been created.
249 * All menu items are translated. Sets 'item_factory'.
251 #define MAKE_MENU(name) \
252 do { \
253 GtkItemFactoryEntry *translated; \
254 int n_entries; \
256 item_factory = gtk_item_factory_new(GTK_TYPE_MENU, \
257 "<" #name ">", name ## _keys); \
259 n_entries = sizeof(name ## _menu_def) / sizeof(*name ## _menu_def); \
260 translated = translate_entries(name ## _menu_def, n_entries); \
261 gtk_item_factory_create_items(item_factory, n_entries, \
262 translated, NULL); \
263 free_translated_entries(translated, n_entries); \
264 } while (0)
266 void menu_init(void)
268 char *menurc;
269 GList *items;
270 guchar *tmp;
271 GtkWidget *item;
272 GtkItemFactory *item_factory;
274 filer_keys = gtk_accel_group_new();
275 MAKE_MENU(filer);
277 GET_MENU_ITEM(filer_menu, "filer");
278 GET_SMENU_ITEM(filer_file_menu, "filer", "File");
279 GET_SSMENU_ITEM(filer_vfs_menu, "filer", "File", "Open VFS");
280 GET_SSMENU_ITEM(filer_hidden_menu, "filer", "Display", "Show Hidden");
282 GET_SSMENU_ITEM(display_large_menu, "filer",
283 "Display", "Large, With...");
284 GET_SSMENU_ITEM(display_small_menu, "filer",
285 "Display", "Small, With...");
287 /* File '' label... */
288 items = gtk_container_children(GTK_CONTAINER(filer_menu));
289 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
290 g_list_free(items);
292 /* Shift Open... label */
293 items = gtk_container_children(GTK_CONTAINER(filer_file_menu));
294 file_shift_item = GTK_BIN(g_list_nth(items, 3)->data)->child;
295 g_list_free(items);
297 GET_SSMENU_ITEM(item, "filer", "Window", "New Window");
298 filer_new_window = GTK_BIN(item)->child;
300 menurc = choices_find_path_load("menus", PROJECT);
301 if (menurc)
303 gtk_item_factory_parse_rc(menurc);
304 mark_menus_modified(FALSE);
305 g_free(menurc);
308 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
309 GTK_SIGNAL_FUNC(menu_closed), NULL);
310 gtk_signal_connect(GTK_OBJECT(filer_file_menu), "unmap_event",
311 GTK_SIGNAL_FUNC(menu_closed), NULL);
313 option_add_string("menu_xterm", "xterm", NULL);
314 option_add_saver(save_menus);
316 savebox = gtk_savebox_new();
317 gtk_signal_connect_object(GTK_OBJECT(savebox), "save_to_file",
318 GTK_SIGNAL_FUNC(save_to_file), NULL);
319 gtk_signal_connect_object(GTK_OBJECT(savebox), "save_done",
320 GTK_SIGNAL_FUNC(gtk_widget_hide),
321 GTK_OBJECT(savebox));
323 atexit(save_menus);
326 /* Name is in the form "<panel>" */
327 GtkWidget *menu_create(GtkItemFactoryEntry *def, int n_entries, guchar *name)
329 GtkItemFactory *item_factory;
330 GtkItemFactoryEntry *translated;
331 GtkAccelGroup *keys;
332 GtkWidget *menu;
334 keys = gtk_accel_group_new();
336 item_factory = gtk_item_factory_new(GTK_TYPE_MENU, name, keys);
338 translated = translate_entries(def, n_entries);
339 gtk_item_factory_create_items(item_factory, n_entries,
340 translated, NULL);
341 free_translated_entries(translated, n_entries);
343 menu = gtk_item_factory_get_widget(item_factory, name);
345 gtk_accel_group_lock(keys);
347 return menu;
350 static void items_sensitive(gboolean state)
352 int n = 8;
353 GList *items, *item;
355 items = item = gtk_container_children(GTK_CONTAINER(filer_file_menu));
356 while (item && n--)
358 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
359 item = item->next;
361 g_list_free(items);
363 items = item = gtk_container_children(GTK_CONTAINER(filer_vfs_menu));
364 while (item)
366 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, state);
367 item = item->next;
369 g_list_free(items);
372 void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
374 int *pos = (int *) data;
375 GtkRequisition requisition;
377 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
379 *x = pos[0] - (requisition.width >> 2);
380 *y = pos[1] - (requisition.height >> 2);
382 *x = CLAMP(*x, 0, screen_width - requisition.width);
383 *y = CLAMP(*y, 0, screen_height - requisition.height);
386 /* Used when you menu-click on the Large or Small toolbar tools */
387 void show_style_menu(FilerWindow *filer_window,
388 GdkEventButton *event,
389 GtkWidget *menu)
391 int pos[2];
393 pos[0] = event->x_root;
394 pos[1] = event->y_root;
396 window_with_focus = filer_window;
398 popup_menu = menu;
400 gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, position_menu,
401 (gpointer) pos, event->button, event->time);
404 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
405 int item)
407 DirItem *file_item = NULL;
408 int pos[2];
409 guchar *shift_action;
411 updating_menu++;
413 /* Remove previous AppMenu, if any */
414 appmenu_remove();
416 pos[0] = event->x_root;
417 pos[1] = event->y_root;
419 window_with_focus = filer_window;
421 if (filer_window->collection->number_selected == 0 && item >= 0)
423 collection_select_item(filer_window->collection, item);
424 filer_window->temp_item_selected = TRUE;
426 else
428 filer_window->temp_item_selected = FALSE;
432 GtkWidget *file_label, *file_menu;
433 Collection *collection = filer_window->collection;
434 GString *buffer;
436 file_label = filer_file_item;
437 file_menu = filer_file_menu;
438 gtk_check_menu_item_set_active(
439 GTK_CHECK_MENU_ITEM(filer_hidden_menu),
440 filer_window->show_hidden);
441 buffer = g_string_new(NULL);
442 switch (collection->number_selected)
444 case 0:
445 g_string_assign(buffer, _("Next Click"));
446 items_sensitive(TRUE);
447 break;
448 case 1:
449 items_sensitive(TRUE);
450 file_item = selected_item(
451 filer_window->collection);
452 g_string_sprintf(buffer, "%s '%s'",
453 basetype_name(file_item),
454 file_item->leafname);
455 if (!can_set_run_action(file_item))
456 menu_set_items_shaded(filer_file_menu,
457 TRUE, 6, 1);
458 break;
459 default:
460 items_sensitive(FALSE);
461 g_string_sprintf(buffer, _("%d items"),
462 collection->number_selected);
463 break;
465 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
466 g_string_free(buffer, TRUE);
468 shift_action = NULL;
469 if (collection->number_selected == 1)
471 if (file_item->flags & ITEM_FLAG_MOUNT_POINT)
473 if (file_item->flags & ITEM_FLAG_MOUNTED)
474 shift_action = N_("Unmount");
475 else
476 shift_action = N_("Mount");
478 else if (file_item->flags & ITEM_FLAG_SYMLINK)
480 shift_action = N_("Show Target");
481 appmenu_add(make_path(filer_window->path,
482 file_item->leafname)->str,
483 file_item,
484 filer_file_menu);
486 else if (file_item->base_type == TYPE_DIRECTORY)
488 shift_action = N_("Look Inside");
489 appmenu_add(make_path(filer_window->path,
490 file_item->leafname)->str,
491 file_item,
492 filer_file_menu);
494 else if (file_item->base_type == TYPE_FILE)
495 shift_action = N_("Open As Text");
497 gtk_widget_set_sensitive(file_shift_item,
498 shift_action != NULL ||
499 collection->number_selected == 0);
500 gtk_label_set_text(GTK_LABEL(file_shift_item),
501 shift_action ? _(shift_action)
502 : _("Shift Open"));
505 gtk_widget_set_sensitive(filer_new_window, !o_unique_filer_windows);
507 popup_menu = (event->state & GDK_CONTROL_MASK)
508 ? filer_file_menu
509 : filer_menu;
511 updating_menu--;
513 gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, position_menu,
514 (gpointer) pos, event->button, event->time);
517 static void menu_closed(GtkWidget *widget)
519 if (window_with_focus == NULL || widget != popup_menu)
520 return; /* Close panel item chosen? */
522 popup_menu = NULL;
524 if (window_with_focus->temp_item_selected)
526 collection_clear_selection(window_with_focus->collection);
527 window_with_focus->temp_item_selected = FALSE;
531 void target_callback(FilerWindow *filer_window,
532 gint item,
533 gpointer real_fn)
535 Collection *collection = filer_window->collection;
537 g_return_if_fail(window_with_focus != NULL);
538 g_return_if_fail(window_with_focus == filer_window);
539 g_return_if_fail(real_fn != NULL);
541 collection_wink_item(collection, item);
542 collection_clear_selection(collection);
543 collection_select_item(collection, item);
544 ((GtkItemFactoryCallback1) real_fn)(NULL, 0, GTK_WIDGET(collection));
545 if (item < collection->number_of_items)
546 collection_unselect_item(collection, item);
549 /* Actions */
551 static void huge_icons(gpointer data, guint action, GtkWidget *widget)
553 display_set_layout(window_with_focus, HUGE_ICONS, DETAILS_NONE);
556 static void large_with(gpointer data, guint action, GtkWidget *widget)
558 display_set_layout(window_with_focus, LARGE_ICONS, action);
561 static void small_with(gpointer data, guint action, GtkWidget *widget)
563 display_set_layout(window_with_focus, SMALL_ICONS, action);
566 static void sort_name(gpointer data, guint action, GtkWidget *widget)
568 g_return_if_fail(window_with_focus != NULL);
570 display_set_sort_fn(window_with_focus, sort_by_name);
573 static void sort_type(gpointer data, guint action, GtkWidget *widget)
575 g_return_if_fail(window_with_focus != NULL);
577 display_set_sort_fn(window_with_focus, sort_by_type);
580 static void sort_date(gpointer data, guint action, GtkWidget *widget)
582 g_return_if_fail(window_with_focus != NULL);
584 display_set_sort_fn(window_with_focus, sort_by_date);
587 static void sort_size(gpointer data, guint action, GtkWidget *widget)
589 g_return_if_fail(window_with_focus != NULL);
591 display_set_sort_fn(window_with_focus, sort_by_size);
594 static void hidden(gpointer data, guint action, GtkWidget *widget)
596 if (updating_menu)
597 return;
599 g_return_if_fail(window_with_focus != NULL);
601 display_set_hidden(window_with_focus, !window_with_focus->show_hidden);
604 static void refresh(gpointer data, guint action, GtkWidget *widget)
606 g_return_if_fail(window_with_focus != NULL);
608 full_refresh();
609 filer_update_dir(window_with_focus, TRUE);
612 static void create_thumbs(gpointer data, guint action, GtkWidget *widget)
614 g_return_if_fail(window_with_focus != NULL);
616 dir_rescan_with_thumbs(window_with_focus->directory,
617 window_with_focus->path);
620 static void delete(gpointer data, guint action, GtkWidget *widget)
622 g_return_if_fail(window_with_focus != NULL);
624 if (window_with_focus->collection->number_selected == 0)
625 filer_target_mode(window_with_focus,
626 target_callback, delete,
627 _("DELETE ... ?"));
628 else
629 action_delete(window_with_focus);
632 static void usage(gpointer data, guint action, GtkWidget *widget)
634 g_return_if_fail(window_with_focus != NULL);
636 if (window_with_focus->collection->number_selected == 0)
637 filer_target_mode(window_with_focus,
638 target_callback, usage,
639 _("Count the size of ... ?"));
640 else
641 action_usage(window_with_focus);
644 static void chmod_items(gpointer data, guint action, GtkWidget *widget)
646 g_return_if_fail(window_with_focus != NULL);
648 if (window_with_focus->collection->number_selected == 0)
649 filer_target_mode(window_with_focus,
650 target_callback, chmod_items,
651 _("Set permissions on ... ?"));
652 else
653 action_chmod(window_with_focus);
656 static void find(gpointer data, guint action, GtkWidget *widget)
658 g_return_if_fail(window_with_focus != NULL);
660 if (window_with_focus->collection->number_selected == 0)
661 filer_target_mode(window_with_focus,
662 target_callback, find,
663 _("Search inside ... ?"));
664 else
665 action_find(window_with_focus);
668 /* This pops up our savebox widget, cancelling any currently open one,
669 * and allows the user to pick a new path for it.
670 * Once the new path has been picked, the callback will be called with
671 * both the current and new paths.
673 static void savebox_show(guchar *title, guchar *path, MaskedPixmap *image,
674 gboolean (*callback)(guchar *current, guchar *new))
676 if (GTK_WIDGET_VISIBLE(savebox))
677 gtk_widget_hide(savebox);
679 if (current_path)
680 g_free(current_path);
681 current_path = g_strdup(path);
682 current_savebox_callback = callback;
684 gtk_window_set_title(GTK_WINDOW(savebox), title);
685 gtk_savebox_set_pathname(GTK_SAVEBOX(savebox), current_path);
686 gtk_savebox_set_icon(GTK_SAVEBOX(savebox), image->pixmap, image->mask);
688 gtk_widget_grab_focus(GTK_SAVEBOX(savebox)->entry);
689 gtk_widget_show(savebox);
692 static gint save_to_file(GtkSavebox *savebox, guchar *pathname)
694 g_return_val_if_fail(current_savebox_callback != NULL,
695 GTK_XDS_SAVE_ERROR);
697 return current_savebox_callback(current_path, pathname)
698 ? GTK_XDS_SAVED : GTK_XDS_SAVE_ERROR;
701 static gboolean copy_cb(guchar *current, guchar *new)
703 return action_with_leaf(action_copy, current, new);
706 static gboolean action_with_leaf(ActionFn action, guchar *current, guchar *new)
708 char *new_dir, *leaf;
709 GSList *local_paths;
711 if (new[0] != '/')
713 report_error(PROJECT, _("New pathname is not absolute"));
714 return FALSE;
717 if (new[strlen(new) - 1] == '/')
719 new_dir = g_strdup(new);
720 leaf = NULL;
722 else
724 guchar *slash;
726 slash = strrchr(new, '/');
727 new_dir = g_strndup(new, slash - new);
728 leaf = slash + 1;
731 local_paths = g_slist_append(NULL, current);
732 action(local_paths, new_dir, leaf);
733 g_slist_free(local_paths);
735 g_free(new_dir);
737 return TRUE;
740 #define SHOW_SAVEBOX(title, callback) \
742 DirItem *item; \
743 guchar *path; \
744 item = selected_item(collection); \
745 path = make_path(window_with_focus->path, item->leafname)->str; \
746 savebox_show(title, path, item->image, callback); \
749 static void copy_item(gpointer data, guint action, GtkWidget *widget)
751 Collection *collection;
753 g_return_if_fail(window_with_focus != NULL);
755 collection = window_with_focus->collection;
756 if (collection->number_selected > 1)
758 report_error(PROJECT, _("You cannot do this to more than "
759 "one item at a time"));
760 return;
762 else if (collection->number_selected != 1)
763 filer_target_mode(window_with_focus,
764 target_callback, copy_item,
765 _("Copy ... ?"));
766 else
767 SHOW_SAVEBOX(_("Copy"), copy_cb);
770 static gboolean rename_cb(guchar *current, guchar *new)
772 return action_with_leaf(action_move, current, new);
775 static void rename_item(gpointer data, guint action, GtkWidget *widget)
777 Collection *collection;
779 g_return_if_fail(window_with_focus != NULL);
781 collection = window_with_focus->collection;
782 if (collection->number_selected > 1)
784 report_error(PROJECT, _("You cannot do this to more than "
785 "one item at a time"));
786 return;
788 else if (collection->number_selected != 1)
789 filer_target_mode(window_with_focus,
790 target_callback, rename_item,
791 _("Rename ... ?"));
792 else
793 SHOW_SAVEBOX(_("Rename"), rename_cb);
796 static gboolean link_cb(guchar *initial, guchar *path)
798 if (symlink(initial, path))
800 report_error("ROX-Filer: symlink()", g_strerror(errno));
801 return FALSE;
803 return TRUE;
806 static void link_item(gpointer data, guint action, GtkWidget *widget)
808 Collection *collection;
810 g_return_if_fail(window_with_focus != NULL);
812 collection = window_with_focus->collection;
813 if (collection->number_selected > 1)
815 report_error(PROJECT, _("You cannot do this to more than "
816 "one item at a time"));
817 return;
819 else if (collection->number_selected != 1)
820 filer_target_mode(window_with_focus,
821 target_callback, link_item,
822 _("Symlink ... ?"));
823 else
824 SHOW_SAVEBOX(_("Symlink"), link_cb);
827 static void open_file(gpointer data, guint action, GtkWidget *widget)
829 Collection *collection;
831 g_return_if_fail(window_with_focus != NULL);
833 collection = window_with_focus->collection;
834 if (collection->number_selected > 1)
836 report_error(PROJECT, _("You cannot do this to more than "
837 "one item at a time"));
838 return;
840 else if (collection->number_selected != 1)
841 filer_target_mode(window_with_focus,
842 target_callback, open_file,
843 _("Shift Open ... ?"));
844 else
845 filer_openitem(window_with_focus,
846 selected_item_number(collection),
847 OPEN_SAME_WINDOW | OPEN_SHIFT);
850 static void run_action(gpointer data, guint action, GtkWidget *widget)
852 Collection *collection;
854 g_return_if_fail(window_with_focus != NULL);
856 collection = window_with_focus->collection;
857 if (collection->number_selected > 1)
859 report_error(PROJECT, _("You cannot do this to more than "
860 "one item at a time"));
861 return;
863 else if (collection->number_selected != 1)
864 filer_target_mode(window_with_focus,
865 target_callback, run_action,
866 _("Set run action for ... ?"));
867 else
869 DirItem *item;
871 item = selected_item(collection);
872 g_return_if_fail(item != NULL);
874 if (can_set_run_action(item))
875 type_set_handler_dialog(item->mime_type);
876 else
877 report_error(PROJECT,
878 _("You can only set the run action for a "
879 "regular file"));
883 static void set_icon(gpointer data, guint action, GtkWidget *widget)
885 Collection *collection;
887 g_return_if_fail(window_with_focus != NULL);
889 collection = window_with_focus->collection;
890 if (collection->number_selected > 1)
892 report_error(PROJECT, _("You cannot do this to more than "
893 "one item at a time"));
894 return;
896 else if (collection->number_selected != 1)
897 filer_target_mode(window_with_focus,
898 target_callback, set_icon,
899 _("Set icon for ... ?"));
900 else
902 DirItem *item;
903 guchar *path;
905 item = selected_item(collection);
906 g_return_if_fail(item != NULL);
908 path = make_path(window_with_focus->path, item->leafname)->str;
910 icon_set_handler_dialog(item, path);
914 /* Got some data from file(1) - stick it in the window. */
915 static void add_file_output(FileStatus *fs,
916 gint source, GdkInputCondition condition)
918 char buffer[20];
919 char *str;
920 int got;
922 got = read(source, buffer, sizeof(buffer) - 1);
923 if (got <= 0)
925 int err = errno;
926 gtk_input_remove(fs->input);
927 close(source);
928 fs->fd = -1;
929 if (got < 0)
930 delayed_error(_("ROX-Filer: file(1) says..."),
931 g_strerror(err));
932 return;
934 buffer[got] = '\0';
936 if (fs->start)
938 str = "";
939 fs->start = FALSE;
941 else
942 gtk_label_get(fs->label, &str);
944 str = g_strconcat(str, buffer, NULL);
945 gtk_label_set_text(fs->label, str);
946 g_free(str);
949 static void file_info_destroyed(GtkWidget *widget, FileStatus *fs)
951 if (fs->fd != -1)
953 gtk_input_remove(fs->input);
954 close(fs->fd);
957 g_free(fs);
960 /* g_free() the result */
961 guchar *pretty_type(DirItem *file, guchar *path)
963 if (file->flags & ITEM_FLAG_SYMLINK)
965 char p[MAXPATHLEN + 1];
966 int got;
967 got = readlink(path, p, MAXPATHLEN);
968 if (got > 0 && got <= MAXPATHLEN)
970 p[got] = '\0';
971 return g_strconcat(_("Symbolic link to "), p, NULL);
974 return g_strdup(_("Symbolic link"));
977 if (file->flags & ITEM_FLAG_APPDIR)
978 return g_strdup(_("ROX application"));
980 if (file->flags & ITEM_FLAG_MOUNT_POINT)
981 return g_strdup(_("Mount point"));
983 if (file->mime_type)
984 return g_strconcat(file->mime_type->media_type, "/",
985 file->mime_type->subtype, NULL);
987 return g_strdup("-");
990 #define LABEL(text, row) \
991 label = gtk_label_new(text); \
992 gtk_misc_set_alignment(GTK_MISC(label), 1, .5); \
993 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); \
994 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, row, row + 1);
996 #define VALUE(label, row) \
997 gtk_misc_set_alignment(GTK_MISC(label), 0, .5); \
998 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, row, row + 1);
1000 static void show_file_info(gpointer data, guint action, GtkWidget *widget)
1002 GtkWidget *window, *table, *label, *button, *frame, *value;
1003 GtkWidget *file_label;
1004 GString *gstring;
1005 int file_data[2];
1006 guchar *path, *tmp;
1007 char *argv[] = {"file", "-b", NULL, NULL};
1008 Collection *collection;
1009 DirItem *file;
1010 struct stat info;
1011 FileStatus *fs = NULL;
1012 guint perm;
1014 g_return_if_fail(window_with_focus != NULL);
1016 collection = window_with_focus->collection;
1017 if (collection->number_selected > 1)
1019 report_error(PROJECT, _("You cannot do this to more than "
1020 "one item at a time"));
1021 return;
1023 else if (collection->number_selected != 1)
1025 filer_target_mode(window_with_focus,
1026 target_callback, show_file_info,
1027 _("Examine ... ?"));
1028 return;
1030 file = selected_item(collection);
1031 path = make_path(window_with_focus->path,
1032 file->leafname)->str;
1033 if (lstat(path, &info))
1035 delayed_error(PROJECT, g_strerror(errno));
1036 return;
1039 gstring = g_string_new(NULL);
1041 window = gtk_window_new(GTK_WINDOW_DIALOG);
1042 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);
1043 gtk_container_set_border_width(GTK_CONTAINER(window), 4);
1044 gtk_window_set_title(GTK_WINDOW(window), path);
1046 table = gtk_table_new(10, 2, FALSE);
1047 gtk_container_add(GTK_CONTAINER(window), table);
1048 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
1049 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1051 value = gtk_label_new(file->leafname);
1052 LABEL(_("Name:"), 0);
1053 VALUE(value, 0);
1055 g_string_sprintf(gstring, "%s, %s", user_name(info.st_uid),
1056 group_name(info.st_gid));
1057 value = gtk_label_new(gstring->str);
1058 LABEL(_("Owner, Group:"), 1);
1059 VALUE(value, 1);
1061 if (info.st_size >= PRETTY_SIZE_LIMIT)
1063 g_string_sprintf(gstring, "%s (%ld %s)",
1064 format_size((unsigned long) info.st_size),
1065 (unsigned long) info.st_size, _("bytes"));
1067 else
1069 g_string_assign(gstring,
1070 format_size((unsigned long) info.st_size));
1072 value = gtk_label_new(gstring->str);
1073 LABEL(_("Size:"), 2);
1074 VALUE(value, 2);
1076 value = gtk_label_new(pretty_time(&info.st_ctime));
1077 LABEL(_("Change time:"), 3);
1078 VALUE(value, 3);
1080 value = gtk_label_new(pretty_time(&info.st_mtime));
1081 LABEL(_("Modify time:"), 4);
1082 VALUE(value, 4);
1084 value = gtk_label_new(pretty_time(&info.st_atime));
1085 LABEL(_("Access time:"), 5);
1086 VALUE(value, 5);
1088 value = gtk_label_new(pretty_permissions(info.st_mode));
1089 perm = applicable(info.st_uid, info.st_gid);
1090 gtk_label_set_pattern(GTK_LABEL(value),
1091 perm == 0 ? "___ " :
1092 perm == 1 ? " ___ " :
1093 " ___");
1094 gtk_widget_set_style(value, fixed_style);
1095 LABEL(_("Permissions:"), 6);
1096 VALUE(value, 6);
1098 tmp = pretty_type(file, path);
1099 value = gtk_label_new(tmp);
1100 g_free(tmp);
1101 LABEL(_("Type:"), 7);
1102 VALUE(value, 7);
1104 frame = gtk_frame_new(_("file(1) says..."));
1105 gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 8, 9);
1106 file_label = gtk_label_new(_("<nothing yet>"));
1107 gtk_misc_set_padding(GTK_MISC(file_label), 4, 4);
1108 gtk_label_set_line_wrap(GTK_LABEL(file_label), TRUE);
1109 gtk_container_add(GTK_CONTAINER(frame), file_label);
1111 button = gtk_button_new_with_label(_("OK"));
1112 gtk_window_set_focus(GTK_WINDOW(window), button);
1113 gtk_table_attach(GTK_TABLE(table), button, 0, 2, 10, 11,
1114 GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 40, 4);
1115 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1116 gtk_widget_destroy, GTK_OBJECT(window));
1118 gtk_widget_show_all(window);
1119 gdk_flush();
1121 if (pipe(file_data))
1123 g_string_sprintf(gstring, "pipe(): %s", g_strerror(errno));
1124 g_string_free(gstring, TRUE);
1125 return;
1127 switch (fork())
1129 case -1:
1130 g_string_sprintf(gstring, "fork(): %s",
1131 g_strerror(errno));
1132 gtk_label_set_text(GTK_LABEL(file_label), gstring->str);
1133 g_string_free(gstring, TRUE);
1134 close(file_data[0]);
1135 close(file_data[1]);
1136 break;
1137 case 0:
1138 /* We are the child */
1139 close(file_data[0]);
1140 dup2(file_data[1], STDOUT_FILENO);
1141 dup2(file_data[1], STDERR_FILENO);
1142 #ifdef FILE_B_FLAG
1143 argv[2] = path;
1144 #else
1145 argv[1] = file->leafname;
1146 chdir(window_with_focus->path);
1147 #endif
1148 if (execvp(argv[0], argv))
1149 fprintf(stderr, "execvp() error: %s\n",
1150 g_strerror(errno));
1151 _exit(0);
1152 default:
1153 /* We are the parent */
1154 close(file_data[1]);
1155 fs = g_new(FileStatus, 1);
1156 fs->label = GTK_LABEL(file_label);
1157 fs->fd = file_data[0];
1158 fs->start = TRUE;
1159 fs->input = gdk_input_add(fs->fd, GDK_INPUT_READ,
1160 (GdkInputFunction) add_file_output, fs);
1161 gtk_signal_connect(GTK_OBJECT(window), "destroy",
1162 GTK_SIGNAL_FUNC(file_info_destroyed), fs);
1163 g_string_free(gstring, TRUE);
1164 break;
1168 void open_home(gpointer data, guint action, GtkWidget *widget)
1170 filer_opendir(home_dir);
1173 static void help(gpointer data, guint action, GtkWidget *widget)
1175 Collection *collection;
1176 DirItem *item;
1178 g_return_if_fail(window_with_focus != NULL);
1180 collection = window_with_focus->collection;
1181 if (collection->number_selected > 1)
1183 report_error(PROJECT, _("You cannot do this to more than "
1184 "one item at a time"));
1185 return;
1187 else if (collection->number_selected != 1)
1189 filer_target_mode(window_with_focus, target_callback, help,
1190 _("Help about ... ?"));
1191 return;
1193 item = selected_item(collection);
1195 show_item_help(make_path(window_with_focus->path, item->leafname)->str,
1196 item);
1199 #define OPEN_VFS(fs) \
1200 static void open_vfs_ ## fs (gpointer data, guint action, GtkWidget *widget) \
1202 Collection *collection; \
1204 g_return_if_fail(window_with_focus != NULL); \
1206 collection = window_with_focus->collection; \
1207 if (collection->number_selected < 1) \
1208 filer_target_mode(window_with_focus, target_callback, \
1209 open_vfs_ ## fs, \
1210 _("Look inside ... ?")); \
1211 else \
1212 real_vfs_open(#fs); \
1215 static void real_vfs_open(char *fs)
1217 gchar *path;
1218 DirItem *item;
1220 if (window_with_focus->collection->number_selected != 1)
1222 report_error(PROJECT, _("You must select a single file "
1223 "to open as a Virtual File System"));
1224 return;
1227 item = selected_item(window_with_focus->collection);
1229 path = g_strconcat(window_with_focus->path,
1230 "/",
1231 item->leafname,
1232 "#", fs, NULL);
1234 filer_change_to(window_with_focus, path, NULL);
1235 g_free(path);
1238 OPEN_VFS(rpm)
1239 OPEN_VFS(utar)
1240 OPEN_VFS(uzip)
1241 OPEN_VFS(deb)
1243 static void select_all(gpointer data, guint action, GtkWidget *widget)
1245 g_return_if_fail(window_with_focus != NULL);
1247 collection_select_all(window_with_focus->collection);
1248 window_with_focus->temp_item_selected = FALSE;
1251 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
1253 g_return_if_fail(window_with_focus != NULL);
1255 collection_clear_selection(window_with_focus->collection);
1256 window_with_focus->temp_item_selected = FALSE;
1259 void menu_show_options(gpointer data, guint action, GtkWidget *widget)
1261 options_show();
1264 static gboolean new_directory_cb(guchar *initial, guchar *path)
1266 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO))
1268 report_error("mkdir", g_strerror(errno));
1269 return FALSE;
1272 dir_check_this(path);
1273 return TRUE;
1276 static void new_directory(gpointer data, guint action, GtkWidget *widget)
1278 g_return_if_fail(window_with_focus != NULL);
1280 savebox_show(_("New Directory"),
1281 make_path(window_with_focus->path, _("NewDir"))->str,
1282 type_to_icon(&special_directory),
1283 new_directory_cb);
1286 static gboolean new_file_cb(guchar *initial, guchar *path)
1288 int fd;
1290 fd = open(path, O_CREAT | O_EXCL, 0666);
1292 if (fd == -1)
1294 report_error(_("Error creating file"), g_strerror(errno));
1295 return FALSE;
1298 if (close(fd))
1299 report_error(_("Error creating file"), g_strerror(errno));
1301 dir_check_this(path);
1303 return TRUE;
1306 static void new_file(gpointer data, guint action, GtkWidget *widget)
1308 g_return_if_fail(window_with_focus != NULL);
1310 savebox_show(_("New File"),
1311 make_path(window_with_focus->path, _("NewFile"))->str,
1312 type_to_icon(&text_plain),
1313 new_file_cb);
1316 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
1318 char *argv[] = {NULL, NULL};
1320 argv[0] = option_get_static_string("menu_xterm");
1322 g_return_if_fail(window_with_focus != NULL);
1324 if (!spawn_full(argv, window_with_focus->path))
1325 report_error(PROJECT, _("Failed to fork() child process"));
1328 static void home_directory(gpointer data, guint action, GtkWidget *widget)
1330 g_return_if_fail(window_with_focus != NULL);
1332 filer_change_to(window_with_focus, home_dir, NULL);
1335 static void open_parent(gpointer data, guint action, GtkWidget *widget)
1337 g_return_if_fail(window_with_focus != NULL);
1339 filer_open_parent(window_with_focus);
1342 static void open_parent_same(gpointer data, guint action, GtkWidget *widget)
1344 g_return_if_fail(window_with_focus != NULL);
1346 change_to_parent(window_with_focus);
1349 static void resize(gpointer data, guint action, GtkWidget *widget)
1351 g_return_if_fail(window_with_focus != NULL);
1353 filer_window_autosize(window_with_focus, TRUE);
1356 static void new_window(gpointer data, guint action, GtkWidget *widget)
1358 g_return_if_fail(window_with_focus != NULL);
1360 if (o_unique_filer_windows)
1362 report_error(PROJECT, _("You can't open a second view onto "
1363 "this directory because the `Unique Windows' option "
1364 "is turned on in the Options window."));
1366 else
1367 filer_opendir(window_with_focus->path);
1370 #if 0
1371 static void su_to_user(GtkWidget *dialog)
1373 char *argv[] = {
1374 "xterm", "-e", "su_rox", "USER", "APP_RUN", "DIR", NULL};
1375 GtkEntry *user;
1376 guchar *path;
1378 g_return_if_fail(dialog != NULL);
1380 path = gtk_object_get_data(GTK_OBJECT(dialog), "dir_path");
1381 user = gtk_object_get_data(GTK_OBJECT(dialog), "user_name");
1383 g_return_if_fail(user != NULL && path != NULL);
1385 argv[2] = g_strconcat(app_dir, "/su_rox", NULL);
1386 argv[3] = gtk_entry_get_text(user);
1387 argv[4] = g_strconcat(app_dir, "/AppRun", NULL);
1388 argv[5] = path;
1390 if (!spawn(argv))
1391 report_error(_("fork() failed"), g_strerror(errno));
1393 g_free(argv[2]);
1394 g_free(argv[4]);
1396 gtk_widget_destroy(dialog);
1399 static void new_user(gpointer data, guint action, GtkWidget *widget)
1401 GtkWidget *dialog, *vbox, *hbox, *entry, *button;
1403 g_return_if_fail(window_with_focus != NULL);
1405 dialog = gtk_window_new(GTK_WINDOW_DIALOG);
1406 gtk_window_set_title(GTK_WINDOW(dialog), _("New window, as user..."));
1407 gtk_container_set_border_width(GTK_CONTAINER(dialog), 4);
1408 gtk_object_set_data_full(GTK_OBJECT(dialog), "dir_path",
1409 g_strdup(window_with_focus->path), g_free);
1411 vbox = gtk_vbox_new(FALSE, 4);
1412 gtk_container_add(GTK_CONTAINER(dialog), vbox);
1413 gtk_box_pack_start(GTK_BOX(vbox),
1414 gtk_label_new(_("Browse as which user?")),
1415 TRUE, TRUE, 2);
1417 hbox = gtk_hbox_new(FALSE, 4);
1418 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
1420 gtk_box_pack_start(GTK_BOX(hbox),
1421 gtk_label_new(_("User:")), FALSE, TRUE, 2);
1423 entry = gtk_entry_new();
1424 gtk_entry_set_text(GTK_ENTRY(entry), "root");
1425 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
1426 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
1427 gtk_widget_grab_focus(entry);
1428 gtk_object_set_data(GTK_OBJECT(dialog), "user_name", entry);
1429 gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
1430 GTK_SIGNAL_FUNC(su_to_user), GTK_OBJECT(dialog));
1432 hbox = gtk_hbox_new(TRUE, 0);
1433 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
1435 button = gtk_button_new_with_label(_("OK"));
1436 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1437 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1438 gtk_window_set_default(GTK_WINDOW(dialog), button);
1439 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1440 GTK_SIGNAL_FUNC(su_to_user), GTK_OBJECT(dialog));
1442 button = gtk_button_new_with_label(_("Cancel"));
1443 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1444 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1445 gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
1446 GTK_SIGNAL_FUNC(gtk_widget_destroy),
1447 GTK_OBJECT(dialog));
1449 gtk_widget_show_all(dialog);
1451 #endif
1453 static void close_window(gpointer data, guint action, GtkWidget *widget)
1455 g_return_if_fail(window_with_focus != NULL);
1457 gtk_widget_destroy(window_with_focus->window);
1460 static void enter_path(gpointer data, guint action, GtkWidget *widget)
1462 g_return_if_fail(window_with_focus != NULL);
1464 minibuffer_show(window_with_focus, MINI_PATH);
1467 static void shell_command(gpointer data, guint action, GtkWidget *widget)
1469 g_return_if_fail(window_with_focus != NULL);
1471 minibuffer_show(window_with_focus, MINI_SHELL);
1474 static void select_if(gpointer data, guint action, GtkWidget *widget)
1476 g_return_if_fail(window_with_focus != NULL);
1478 minibuffer_show(window_with_focus, MINI_SELECT_IF);
1481 void menu_rox_help(gpointer data, guint action, GtkWidget *widget)
1483 filer_opendir(make_path(app_dir, "Help")->str);
1486 /* Set n items from position 'from' in 'menu' to the 'shaded' state */
1487 void menu_set_items_shaded(GtkWidget *menu, gboolean shaded, int from, int n)
1489 GList *items, *item;
1491 items = gtk_container_children(GTK_CONTAINER(menu));
1493 item = g_list_nth(items, from);
1494 while (item && n--)
1496 gtk_widget_set_sensitive(GTK_BIN(item->data)->child, !shaded);
1497 item = item->next;
1499 g_list_free(items);
1502 /* This is called for every modified menu entry. We just use it to
1503 * find out if the menu has changed at all.
1505 static void set_mod(gboolean *mod, guchar *str)
1507 if (str && str[0] == '(')
1508 *mod = TRUE;
1511 static void save_menus(void)
1513 char *menurc;
1515 menurc = choices_find_path_save("menus", PROJECT, FALSE);
1516 if (menurc)
1518 gboolean mod = FALSE;
1520 g_free(menurc);
1522 /* Find out if anything changed... */
1523 gtk_item_factory_dump_items(NULL, TRUE,
1524 (GtkPrintFunc) set_mod, &mod);
1526 /* Dump out if so... */
1527 if (mod)
1529 menurc = choices_find_path_save("menus", PROJECT, TRUE);
1530 g_return_if_fail(menurc != NULL);
1531 mark_menus_modified(TRUE);
1532 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
1533 mark_menus_modified(FALSE);
1534 g_free(menurc);
1539 static void mark_modified(gpointer hash_key,
1540 gpointer value,
1541 gpointer user_data)
1543 GtkItemFactoryItem *item = (GtkItemFactoryItem *) value;
1545 item->modified = (gboolean) GPOINTER_TO_INT(user_data);
1548 /* Set or clear the 'modified' flag in all menu items. Messy... */
1549 static void mark_menus_modified(gboolean mod)
1551 GtkItemFactoryClass *class;
1553 class = gtk_type_class(GTK_TYPE_ITEM_FACTORY);
1555 g_hash_table_foreach(class->item_ht, mark_modified,
1556 GINT_TO_POINTER(mod));
1560 /* Returns TRUE is this is something that is run by looking up its type
1561 * in MIME-types and, hence, can have its run action set.
1563 static gboolean can_set_run_action(DirItem *item)
1565 g_return_val_if_fail(item != NULL, FALSE);
1567 return item->base_type == TYPE_FILE &&
1568 !(item->mime_type == &special_exec);