r40: Changed MIME system slightly - now uses MIME-open, MIME-icons, etc.
[rox-filer.git] / ROX-Filer / src / menu.c
blob13fc15eceebe6e91f9629b7574a5571e52635444
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 <sys/wait.h>
12 #include <gdk/gdkx.h>
13 #include <gtk/gtk.h>
15 #include "filer.h"
16 #include "type.h"
17 #include "support.h"
18 #include "gui_support.h"
19 #include "options.h"
20 #include "choices.h"
21 #include "newdir.h"
23 #define C_ "<control>"
25 #define MENU_MARGIN 32
27 GtkAccelGroup *filer_keys;
28 GtkAccelGroup *panel_keys;
30 /* Static prototypes */
31 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data);
32 static void menu_closed(GtkWidget *widget);
33 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state);
35 static void refresh(gpointer data, guint action, GtkWidget *widget);
36 static void mount(gpointer data, guint action, GtkWidget *widget);
37 static void delete(gpointer data, guint action, GtkWidget *widget);
38 static void select_all(gpointer data, guint action, GtkWidget *widget);
39 static void clear_selection(gpointer data, guint action, GtkWidget *widget);
40 static void show_options(gpointer data, guint action, GtkWidget *widget);
41 static void new_directory(gpointer data, guint action, GtkWidget *widget);
42 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
43 static void open_parent(gpointer data, guint action, GtkWidget *widget);
45 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
46 static void close_panel(gpointer data, guint action, GtkWidget *widget);
48 static GtkWidget *filer_menu; /* The popup filer menu */
49 static GtkWidget *filer_file_item; /* The File '' label */
50 static GtkWidget *filer_file_menu; /* The File '' menu */
51 static GtkWidget *panel_menu; /* The popup panel menu */
52 static GtkWidget *panel_file_item; /* The File '' label */
53 static GtkWidget *panel_file_menu; /* The File '' menu */
55 static GtkItemFactoryEntry filer_menu_def[] = {
56 {"/Display", NULL, NULL, 0, "<Branch>"},
57 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
58 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
59 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
60 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
61 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
62 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
63 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
64 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
65 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
66 {"/Display/Show Hidden", C_"H", NULL, 0, "<ToggleItem>"},
67 {"/Display/Refresh", C_"L", refresh, 0, NULL},
68 {"/File", NULL, NULL, 0, "<Branch>"},
69 {"/File/Copy", NULL, NULL, 0, NULL},
70 {"/File/Rename", NULL, NULL, 0, NULL},
71 {"/File/Help", "F1", NULL, 0, NULL},
72 {"/File/Info", NULL, NULL, 0, NULL},
73 {"/File/Separator", NULL, NULL, 0, "<Separator>"},
74 {"/File/Mount", C_"M", mount, 0, NULL},
75 {"/File/Delete", C_"X", delete, 0, NULL},
76 {"/File/Disk Usage", C_"U", NULL, 0, NULL},
77 {"/File/Permissions", NULL, NULL, 0, NULL},
78 {"/File/Stamp", NULL, NULL, 0, NULL},
79 {"/File/Find", NULL, NULL, 0, NULL},
80 {"/Select All", C_"A", select_all, 0, NULL},
81 {"/Clear Selection", C_"Z", clear_selection, 0, NULL},
82 {"/Options...", NULL, show_options, 0, NULL},
83 {"/New directory", NULL, new_directory, 0, NULL},
84 {"/Xterm here", NULL, xterm_here, 0, NULL},
85 {"/Open parent", NULL, open_parent, 0, NULL},
88 static GtkItemFactoryEntry panel_menu_def[] = {
89 {"/Display", NULL, NULL, 0, "<Branch>"},
90 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
91 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
92 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
93 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
94 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
95 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
96 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
97 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
98 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
99 {"/Display/Show Hidden", NULL, NULL, 0, "<ToggleItem>"},
100 {"/Display/Refresh", NULL, refresh, 0, NULL},
101 {"/File", NULL, NULL, 0, "<Branch>"},
102 {"/File/Delete", NULL, NULL, 0, NULL},
103 {"/Open as directory", NULL, open_as_dir, 0, NULL},
104 {"/Close panel", NULL, close_panel, 0, NULL},
108 void menu_init()
110 GtkItemFactory *item_factory;
111 char *menurc;
112 GList *items;
114 filer_keys = gtk_accel_group_new();
115 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
116 "<filer>",
117 filer_keys);
118 gtk_item_factory_create_items(item_factory,
119 sizeof(filer_menu_def) / sizeof(*filer_menu_def),
120 filer_menu_def,
121 NULL);
122 filer_menu = gtk_item_factory_get_widget(item_factory, "<filer>");
123 filer_file_menu = gtk_item_factory_get_widget(item_factory,
124 "<filer>/File");
125 items = gtk_container_children(GTK_CONTAINER(filer_menu));
126 filer_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
127 g_list_free(items);
129 panel_keys = gtk_accel_group_new();
130 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
131 "<panel>",
132 panel_keys);
133 gtk_item_factory_create_items(item_factory,
134 sizeof(panel_menu_def) / sizeof(*panel_menu_def),
135 panel_menu_def,
136 NULL);
137 panel_menu = gtk_item_factory_get_widget(item_factory, "<panel>");
138 panel_file_menu = gtk_item_factory_get_widget(item_factory,
139 "<panel>/File");
140 items = gtk_container_children(GTK_CONTAINER(panel_menu));
141 panel_file_item = GTK_BIN(g_list_nth(items, 1)->data)->child;
142 g_list_free(items);
144 menurc = choices_find_path_load("menus");
145 if (menurc)
146 gtk_item_factory_parse_rc(menurc);
148 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
149 GTK_SIGNAL_FUNC(menu_closed), NULL);
150 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
151 GTK_SIGNAL_FUNC(menu_closed), NULL);
153 gtk_accel_group_lock(panel_keys);
156 static void items_sensitive(GtkWidget *menu, int from, int n, gboolean state)
158 GList *items, *item;
160 items = gtk_container_children(GTK_CONTAINER(menu));
162 item = g_list_nth(items, from);
163 while (item && n--)
165 gtk_widget_set_sensitive(GTK_WIDGET(item->data), state);
166 item = item->next;
169 g_list_free(items);
172 /* Save the keybindings... */
173 void menu_save()
175 char *menurc;
177 menurc = choices_find_path_save("menus");
178 if (menurc)
179 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
182 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
184 int *pos = (int *) data;
185 int swidth, sheight;
186 GtkRequisition requisition;
188 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth, &sheight);
190 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
192 if (pos[0] == -1)
193 *x = swidth - MENU_MARGIN - requisition.width;
194 else if (pos[0] == -2)
195 *x = MENU_MARGIN;
196 else
197 *x = pos[0] - (requisition.width >> 2);
199 if (pos[1] == -1)
200 *y = sheight - MENU_MARGIN - requisition.height;
201 else if (pos[1] == -2)
202 *y = MENU_MARGIN;
203 else
204 *y = pos[1] - (requisition.height >> 2);
206 *x = CLAMP(*x, 0, swidth - requisition.width);
207 *y = CLAMP(*y, 0, sheight - requisition.height);
210 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
211 int item)
213 GString *buffer;
214 GtkWidget *file_label, *file_menu;
215 FileItem *file_item;
216 int pos[] = {event->x_root, event->y_root};
218 window_with_focus = filer_window;
220 if (filer_window->panel)
222 switch (filer_window->panel_side)
224 case TOP: pos[1] = -2; break;
225 case BOTTOM: pos[1] = -1; break;
226 case LEFT: pos[0] = -2; break;
227 case RIGHT: pos[0] = -1; break;
231 if (filer_window->panel)
233 collection_clear_selection(filer_window->collection);
234 panel_set_timeout(NULL, 0);
237 if (filer_window->collection->number_selected == 0 && item >= 0)
239 collection_select_item(filer_window->collection, item);
240 filer_window->temp_item_selected = TRUE;
242 else
243 filer_window->temp_item_selected = FALSE;
245 if (filer_window->panel)
247 file_label = panel_file_item;
248 file_menu = panel_file_menu;
250 else
252 file_label = filer_file_item;
253 file_menu = filer_file_menu;
256 buffer = g_string_new(NULL);
257 switch (filer_window->collection->number_selected)
259 case 0:
260 g_string_assign(buffer, "<nothing selected>");
261 items_sensitive(file_menu, 0, -1, FALSE);
262 gtk_widget_set_sensitive(file_label, FALSE);
263 break;
264 case 1:
265 items_sensitive(file_menu, 0, -1, TRUE);
266 gtk_widget_set_sensitive(file_label, TRUE);
267 file_item = selected_item(filer_window->collection);
268 g_string_sprintf(buffer, "%s '%s'",
269 basetype_name(file_item),
270 file_item->leafname);
271 break;
272 default:
273 items_sensitive(file_menu, 0, 4, FALSE);
274 items_sensitive(file_menu, 4, -1, TRUE);
275 gtk_widget_set_sensitive(file_label, TRUE);
276 g_string_sprintf(buffer, "%d items",
277 filer_window->collection->number_selected);
278 break;
281 gtk_label_set_text(GTK_LABEL(file_label), buffer->str);
283 g_string_free(buffer, TRUE);
285 gtk_menu_popup(filer_window->panel ? GTK_MENU(panel_menu)
286 : GTK_MENU(filer_menu),
287 NULL, NULL, position_menu,
288 (gpointer) pos, event->button, event->time);
291 static void menu_closed(GtkWidget *widget)
293 if (window_with_focus == NULL)
294 return; /* Close panel item chosen? */
296 if (window_with_focus->temp_item_selected)
298 collection_clear_selection(window_with_focus->collection);
299 window_with_focus->temp_item_selected = FALSE;
303 /* Actions */
305 static void refresh(gpointer data, guint action, GtkWidget *widget)
307 g_return_if_fail(window_with_focus != NULL);
309 scan_dir(window_with_focus);
312 static void delete(gpointer data, guint action, GtkWidget *widget)
314 const char *start_args[] = {"xterm", "-wf",
315 "-e", "rm", "-vir"};
316 int argc = sizeof(start_args) / sizeof(char *);
317 char **argv;
318 Collection *collection;
319 int i;
320 FileItem *item;
321 int child;
323 g_return_if_fail(window_with_focus != NULL);
325 collection = window_with_focus->collection;
327 if (collection->number_selected < 1)
329 report_error("ROX-Filer", "Nothing to delete!");
330 return;
333 argv = g_malloc(sizeof(start_args) +
334 sizeof(char *) * (collection->number_selected + 1));
335 memcpy(argv, start_args, sizeof(start_args));
337 for (i = 0; i < collection->number_of_items; i++)
338 if (collection->items[i].selected)
340 item = (FileItem *) collection->items[i].data;
341 argv[argc++] = g_strdup(make_path(
342 window_with_focus->path,
343 item->leafname)->str);
345 argv[argc] = NULL;
347 child = spawn(argv);
348 if (child)
349 g_hash_table_insert(child_to_filer,
350 (gpointer) child, window_with_focus);
351 else
352 report_error("ROX-Filer", "Failed to fork() child "
353 "process");
355 for (i = sizeof(start_args) / sizeof(char *); i < argc; i++)
356 g_free(argv[i]);
357 g_free(argv);
360 static void mount(gpointer data, guint action, GtkWidget *widget)
362 FileItem *item;
363 int i;
364 Collection *collection;
365 char *error = NULL;
367 g_return_if_fail(window_with_focus != NULL);
369 collection = window_with_focus->collection;
371 for (i = 0; i < collection->number_of_items; i++)
372 if (collection->items[i].selected)
374 item = (FileItem *) collection->items[i].data;
375 if (item->flags & ITEM_FLAG_MOUNT_POINT)
377 char *argv[] = {"mount", NULL, NULL};
378 int child;
380 if (item->flags & ITEM_FLAG_MOUNTED)
381 argv[0] = "umount";
382 argv[1] = make_path(window_with_focus->path,
383 item->leafname)->str;
384 child = spawn(argv);
385 if (child)
386 waitpid(child, NULL, 0);
387 else
388 error = "Failed to run mount/umount";
391 scan_dir(window_with_focus);
393 if (error)
394 report_error("ROX-Filer", error);
397 static void select_all(gpointer data, guint action, GtkWidget *widget)
399 g_return_if_fail(window_with_focus != NULL);
401 collection_select_all(window_with_focus->collection);
404 static void clear_selection(gpointer data, guint action, GtkWidget *widget)
406 g_return_if_fail(window_with_focus != NULL);
408 collection_clear_selection(window_with_focus->collection);
411 static void show_options(gpointer data, guint action, GtkWidget *widget)
413 g_return_if_fail(window_with_focus != NULL);
415 options_show(window_with_focus);
418 static void new_directory(gpointer data, guint action, GtkWidget *widget)
420 g_return_if_fail(window_with_focus != NULL);
422 newdir_show(window_with_focus);
425 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
427 char *argv[] = {"gnome-terminal", NULL}; /* XXX: Bad default */
429 g_return_if_fail(window_with_focus != NULL);
431 if (!spawn_in(argv, window_with_focus->path))
432 report_error("ROX-Filer", "Failed to fork() child "
433 "process");
436 static void open_parent(gpointer data, guint action, GtkWidget *widget)
438 g_return_if_fail(window_with_focus != NULL);
440 filer_opendir(make_path(window_with_focus->path, "/..")->str,
441 FALSE, BOTTOM);
444 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
446 g_return_if_fail(window_with_focus != NULL);
448 filer_opendir(window_with_focus->path, FALSE, BOTTOM);
451 static void close_panel(gpointer data, guint action, GtkWidget *widget)
453 g_return_if_fail(window_with_focus != NULL);
455 gtk_widget_destroy(window_with_focus->window);