4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
8 /* menu.c - code for handling the popup menu */
18 #include "gui_support.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
},
110 GtkItemFactory
*item_factory
;
114 filer_keys
= gtk_accel_group_new();
115 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
118 gtk_item_factory_create_items(item_factory
,
119 sizeof(filer_menu_def
) / sizeof(*filer_menu_def
),
122 filer_menu
= gtk_item_factory_get_widget(item_factory
, "<filer>");
123 filer_file_menu
= gtk_item_factory_get_widget(item_factory
,
125 items
= gtk_container_children(GTK_CONTAINER(filer_menu
));
126 filer_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
129 panel_keys
= gtk_accel_group_new();
130 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
133 gtk_item_factory_create_items(item_factory
,
134 sizeof(panel_menu_def
) / sizeof(*panel_menu_def
),
137 panel_menu
= gtk_item_factory_get_widget(item_factory
, "<panel>");
138 panel_file_menu
= gtk_item_factory_get_widget(item_factory
,
140 items
= gtk_container_children(GTK_CONTAINER(panel_menu
));
141 panel_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
144 menurc
= choices_find_path_load("menus");
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
)
160 items
= gtk_container_children(GTK_CONTAINER(menu
));
162 item
= g_list_nth(items
, from
);
165 gtk_widget_set_sensitive(GTK_WIDGET(item
->data
), state
);
172 /* Save the keybindings... */
177 menurc
= choices_find_path_save("menus");
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
;
186 GtkRequisition requisition
;
188 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
190 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
193 *x
= swidth
- MENU_MARGIN
- requisition
.width
;
194 else if (pos
[0] == -2)
197 *x
= pos
[0] - (requisition
.width
>> 2);
200 *y
= sheight
- MENU_MARGIN
- requisition
.height
;
201 else if (pos
[1] == -2)
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
,
214 GtkWidget
*file_label
, *file_menu
;
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
;
243 filer_window
->temp_item_selected
= FALSE
;
245 if (filer_window
->panel
)
247 file_label
= panel_file_item
;
248 file_menu
= panel_file_menu
;
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
)
260 g_string_assign(buffer
, "<nothing selected>");
261 items_sensitive(file_menu
, 0, -1, FALSE
);
262 gtk_widget_set_sensitive(file_label
, FALSE
);
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
);
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
);
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
;
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",
316 int argc
= sizeof(start_args
) / sizeof(char *);
318 Collection
*collection
;
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!");
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
);
349 g_hash_table_insert(child_to_filer
,
350 (gpointer
) child
, window_with_focus
);
352 report_error("ROX-Filer", "Failed to fork() child "
355 for (i
= sizeof(start_args
) / sizeof(char *); i
< argc
; i
++)
360 static void mount(gpointer data
, guint action
, GtkWidget
*widget
)
364 Collection
*collection
;
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
};
380 if (item
->flags
& ITEM_FLAG_MOUNTED
)
382 argv
[1] = make_path(window_with_focus
->path
,
383 item
->leafname
)->str
;
386 waitpid(child
, NULL
, 0);
388 error
= "Failed to run mount/umount";
391 scan_dir(window_with_focus
);
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 "
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
,
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
);