r30: When you open a menu with nothing selected, the item under the pointer
[rox-filer/dt.git] / ROX-Filer / src / menu.c
blobcf0e3c788171983a95a827a706724c06c2cda095
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 "support.h"
17 #include "gui_support.h"
18 #include "options.h"
19 #include "choices.h"
21 #define C_ "<control>"
23 #define MENU_MARGIN 32
25 GtkAccelGroup *filer_keys;
26 GtkAccelGroup *panel_keys;
28 /* Static prototypes */
29 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data);
30 static void menu_closed(GtkWidget *widget);
32 static void refresh(gpointer data, guint action, GtkWidget *widget);
33 static void mount(gpointer data, guint action, GtkWidget *widget);
34 static void delete(gpointer data, guint action, GtkWidget *widget);
35 static void show_options(gpointer data, guint action, GtkWidget *widget);
36 static void xterm_here(gpointer data, guint action, GtkWidget *widget);
37 static void open_parent(gpointer data, guint action, GtkWidget *widget);
39 static void open_as_dir(gpointer data, guint action, GtkWidget *widget);
40 static void close_panel(gpointer data, guint action, GtkWidget *widget);
42 static GtkWidget *filer_menu; /* The popup filer menu */
43 static GtkWidget *panel_menu; /* The popup panel menu */
45 static GtkItemFactoryEntry filer_menu_def[] = {
46 {"/Display", NULL, NULL, 0, "<Branch>"},
47 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
48 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
49 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
50 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
51 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
52 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
53 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
54 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
55 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
56 {"/Display/Show Hidden", C_"H", NULL, 0, "<ToggleItem>"},
57 {"/Display/Refresh", C_"L", refresh, 0, NULL},
58 {"/File", NULL, NULL, 0, "<Branch>"},
59 {"/File/Copy", NULL, NULL, 0, NULL},
60 {"/File/Rename", NULL, NULL, 0, NULL},
61 {"/File/Help", "F1", NULL, 0, NULL},
62 {"/File/Info", NULL, NULL, 0, NULL},
63 {"/File/Mount", C_"M", mount, 0, NULL},
64 {"/File/Separator", NULL, NULL, 0, "<Separator>"},
65 {"/File/Delete", C_"X", delete, 0, NULL},
66 {"/File/Disk Usage", C_"U", NULL, 0, NULL},
67 {"/File/Permissions", NULL, NULL, 0, NULL},
68 {"/File/Stamp", NULL, NULL, 0, NULL},
69 {"/File/Find", NULL, NULL, 0, NULL},
70 {"/Select All", C_"A", NULL, 0, NULL},
71 {"/Clear Selection", C_"Z", NULL, 0, NULL},
72 {"/Options...", NULL, show_options, 0, NULL},
73 {"/New directory", NULL, NULL, 0, NULL},
74 {"/Xterm here", NULL, xterm_here, 0, NULL},
75 {"/Open parent", NULL, open_parent, 0, NULL},
78 static GtkItemFactoryEntry panel_menu_def[] = {
79 {"/Display", NULL, NULL, 0, "<Branch>"},
80 {"/Display/Large Icons", NULL, NULL, 0, "<RadioItem>"},
81 {"/Display/Small Icons", NULL, NULL, 0, "/Display/Large Icons"},
82 {"/Display/Full Info", NULL, NULL, 0, "/Display/Large Icons"},
83 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
84 {"/Display/Sort by Name", NULL, NULL, 0, "<RadioItem>"},
85 {"/Display/Sort by Type", NULL, NULL, 0, "/Display/Sort by Name"},
86 {"/Display/Sort by Date", NULL, NULL, 0, "/Display/Sort by Name"},
87 {"/Display/Sort by Size", NULL, NULL, 0, "/Display/Sort by Name"},
88 {"/Display/Separator", NULL, NULL, 0, "<Separator>"},
89 {"/Display/Show Hidden", C_"H", NULL, 0, "<ToggleItem>"},
90 {"/Display/Refresh", C_"L", refresh, 0, NULL},
91 {"/File", NULL, NULL, 0, "<Branch>"},
92 {"/File/Delete", NULL, NULL, 0, NULL},
93 {"/Open as directory", NULL, open_as_dir, 0, NULL},
94 {"/Close panel", NULL, close_panel, 0, NULL},
98 void menu_init()
100 GtkItemFactory *item_factory;
101 char *menurc;
103 filer_keys = gtk_accel_group_new();
104 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
105 "<filer>",
106 filer_keys);
107 gtk_item_factory_create_items(item_factory,
108 sizeof(filer_menu_def) / sizeof(*filer_menu_def),
109 filer_menu_def,
110 NULL);
111 filer_menu = gtk_item_factory_get_widget(item_factory, "<filer>");
113 panel_keys = gtk_accel_group_new();
114 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,
115 "<panel>",
116 panel_keys);
117 gtk_item_factory_create_items(item_factory,
118 sizeof(panel_menu_def) / sizeof(*panel_menu_def),
119 panel_menu_def,
120 NULL);
121 panel_menu = gtk_item_factory_get_widget(item_factory, "<panel>");
123 menurc = choices_find_path_load("menus");
124 if (menurc)
125 gtk_item_factory_parse_rc(menurc);
127 gtk_signal_connect(GTK_OBJECT(panel_menu), "unmap_event",
128 GTK_SIGNAL_FUNC(menu_closed), NULL);
129 gtk_signal_connect(GTK_OBJECT(filer_menu), "unmap_event",
130 GTK_SIGNAL_FUNC(menu_closed), NULL);
132 gtk_accel_group_lock(panel_keys);
135 /* Save the keybindings... */
136 void menu_finish()
138 char *menurc;
140 menurc = choices_find_path_save("menus");
141 if (menurc)
142 gtk_item_factory_dump_rc(menurc, NULL, TRUE);
145 static void position_menu(GtkMenu *menu, gint *x, gint *y, gpointer data)
147 int *pos = (int *) data;
148 int swidth, sheight;
149 GtkRequisition requisition;
151 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth, &sheight);
153 gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
155 if (pos[0] == -1)
156 *x = swidth - MENU_MARGIN - requisition.width;
157 else if (pos[0] == -2)
158 *x = MENU_MARGIN;
159 else
160 *x = pos[0] - (requisition.width >> 2);
162 if (pos[1] == -1)
163 *y = sheight - MENU_MARGIN - requisition.height;
164 else if (pos[1] == -2)
165 *y = MENU_MARGIN;
166 else
167 *y = pos[1] - (requisition.height >> 2);
169 *x = CLAMP(*x, 0, swidth - requisition.width);
170 *y = CLAMP(*y, 0, sheight - requisition.height);
173 void show_filer_menu(FilerWindow *filer_window, GdkEventButton *event,
174 int item)
176 int pos[] = {event->x_root, event->y_root};
178 window_with_focus = filer_window;
180 if (filer_window->panel)
182 switch (filer_window->panel_side)
184 case TOP: pos[1] = -2; break;
185 case BOTTOM: pos[1] = -1; break;
186 case LEFT: pos[0] = -2; break;
187 case RIGHT: pos[0] = -1; break;
191 if (filer_window->panel)
192 collection_clear_selection(filer_window->collection);
193 if (filer_window->collection->number_selected == 0 && item >= 0)
195 collection_select_item(filer_window->collection, item);
196 filer_window->temp_item_selected = TRUE;
198 else
199 filer_window->temp_item_selected = FALSE;
201 gtk_menu_popup(filer_window->panel ? GTK_MENU(panel_menu)
202 : GTK_MENU(filer_menu),
203 NULL, NULL, position_menu,
204 (gpointer) pos, event->button, event->time);
207 static void menu_closed(GtkWidget *widget)
209 g_return_if_fail(window_with_focus != NULL);
211 if (window_with_focus->temp_item_selected)
213 collection_clear_selection(window_with_focus->collection);
214 window_with_focus->temp_item_selected = FALSE;
218 /* Actions */
220 static void refresh(gpointer data, guint action, GtkWidget *widget)
222 g_return_if_fail(window_with_focus != NULL);
224 scan_dir(window_with_focus);
227 static void delete(gpointer data, guint action, GtkWidget *widget)
229 const char *start_args[] = {"xterm", "-wf",
230 "-e", "rm", "-vir"};
231 int argc = sizeof(start_args) / sizeof(char *);
232 char **argv;
233 Collection *collection;
234 int i;
235 FileItem *item;
236 int child;
238 g_return_if_fail(window_with_focus != NULL);
240 collection = window_with_focus->collection;
242 if (collection->number_selected < 1)
244 report_error("ROX-Filer", "Nothing to delete!");
245 return;
248 argv = g_malloc(sizeof(start_args) +
249 sizeof(char *) * (collection->number_selected + 1));
250 memcpy(argv, start_args, sizeof(start_args));
252 for (i = 0; i < collection->number_of_items; i++)
253 if (collection->items[i].selected)
255 item = (FileItem *) collection->items[i].data;
256 argv[argc++] = g_strdup(make_path(
257 window_with_focus->path,
258 item->leafname)->str);
260 argv[argc] = NULL;
262 child = spawn(argv);
263 if (child)
264 g_hash_table_insert(child_to_filer,
265 (gpointer) child, window_with_focus);
266 else
267 report_error("ROX-Filer", "Failed to fork() child "
268 "process");
270 for (i = sizeof(start_args) / sizeof(char *); i < argc; i++)
271 g_free(argv[i]);
272 g_free(argv);
275 static void mount(gpointer data, guint action, GtkWidget *widget)
277 FileItem *item;
278 int i;
279 Collection *collection;
280 char *error = NULL;
282 g_return_if_fail(window_with_focus != NULL);
284 collection = window_with_focus->collection;
286 for (i = 0; i < collection->number_of_items; i++)
287 if (collection->items[i].selected)
289 item = (FileItem *) collection->items[i].data;
290 if (item->flags & ITEM_FLAG_MOUNT_POINT)
292 char *argv[] = {"mount", NULL, NULL};
293 int child;
295 if (item->flags & ITEM_FLAG_MOUNTED)
296 argv[0] = "umount";
297 argv[1] = make_path(window_with_focus->path,
298 item->leafname)->str;
299 child = spawn(argv);
300 if (child)
301 waitpid(child, NULL, 0);
302 else
303 error = "Failed to run mount/umount";
306 scan_dir(window_with_focus);
308 if (error)
309 report_error("ROX-Filer", error);
312 static void show_options(gpointer data, guint action, GtkWidget *widget)
314 g_return_if_fail(window_with_focus != NULL);
316 options_edit(window_with_focus);
319 static void xterm_here(gpointer data, guint action, GtkWidget *widget)
321 char *argv[] = {"gnome-terminal", NULL}; /* XXX: Bad default */
323 g_return_if_fail(window_with_focus != NULL);
325 if (!spawn_in(argv, window_with_focus->path))
326 report_error("ROX-Filer", "Failed to fork() child "
327 "process");
330 static void open_parent(gpointer data, guint action, GtkWidget *widget)
332 g_return_if_fail(window_with_focus != NULL);
334 filer_opendir(make_path(window_with_focus->path, "/..")->str,
335 FALSE, BOTTOM);
338 static void open_as_dir(gpointer data, guint action, GtkWidget *widget)
340 g_return_if_fail(window_with_focus != NULL);
342 filer_opendir(window_with_focus->path, FALSE, BOTTOM);
345 static void close_panel(gpointer data, guint action, GtkWidget *widget)
347 g_return_if_fail(window_with_focus != NULL);
349 gtk_widget_destroy(window_with_focus->window);