4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 1999, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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)
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
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 */
28 #include <sys/types.h>
44 #include "gui_support.h"
50 #define C_ "<control>"
52 #define MENU_MARGIN 32
54 GtkAccelGroup
*filer_keys
;
55 GtkAccelGroup
*panel_keys
;
58 static GtkWidget
*xterm_here_entry
;
59 static char *xterm_here_value
;
61 /* Static prototypes */
62 static void position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
, gpointer data
);
63 static void menu_closed(GtkWidget
*widget
);
64 static void items_sensitive(GtkWidget
*menu
, int from
, int n
, gboolean state
);
65 static char *load_xterm_here(char *data
);
67 static void not_yet(gpointer data
, guint action
, GtkWidget
*widget
);
69 static void large(gpointer data
, guint action
, GtkWidget
*widget
);
70 static void small(gpointer data
, guint action
, GtkWidget
*widget
);
71 static void full_info(gpointer data
, guint action
, GtkWidget
*widget
);
73 static void sort_name(gpointer data
, guint action
, GtkWidget
*widget
);
74 static void sort_type(gpointer data
, guint action
, GtkWidget
*widget
);
75 static void sort_size(gpointer data
, guint action
, GtkWidget
*widget
);
76 static void sort_date(gpointer data
, guint action
, GtkWidget
*widget
);
78 static void hidden(gpointer data
, guint action
, GtkWidget
*widget
);
79 static void refresh(gpointer data
, guint action
, GtkWidget
*widget
);
81 static void copy_item(gpointer data
, guint action
, GtkWidget
*widget
);
82 static void rename_item(gpointer data
, guint action
, GtkWidget
*widget
);
83 static void link_item(gpointer data
, guint action
, GtkWidget
*widget
);
84 static void help(gpointer data
, guint action
, GtkWidget
*widget
);
85 static void show_file_info(gpointer data
, guint action
, GtkWidget
*widget
);
86 static void mount(gpointer data
, guint action
, GtkWidget
*widget
);
87 static void delete(gpointer data
, guint action
, GtkWidget
*widget
);
88 static void usage(gpointer data
, guint action
, GtkWidget
*widget
);
90 static void select_all(gpointer data
, guint action
, GtkWidget
*widget
);
91 static void clear_selection(gpointer data
, guint action
, GtkWidget
*widget
);
92 static void show_options(gpointer data
, guint action
, GtkWidget
*widget
);
93 static void new_directory(gpointer data
, guint action
, GtkWidget
*widget
);
94 static void xterm_here(gpointer data
, guint action
, GtkWidget
*widget
);
96 static void open_parent_same(gpointer data
, guint action
, GtkWidget
*widget
);
97 static void open_parent(gpointer data
, guint action
, GtkWidget
*widget
);
98 static void new_window(gpointer data
, guint action
, GtkWidget
*widget
);
99 static void close_window(gpointer data
, guint action
, GtkWidget
*widget
);
101 static void open_as_dir(gpointer data
, guint action
, GtkWidget
*widget
);
102 static void close_panel(gpointer data
, guint action
, GtkWidget
*widget
);
104 static GtkWidget
*create_options();
105 static void update_options();
106 static void set_options();
107 static void save_options();
109 static OptionsSection options
=
119 static GtkWidget
*filer_menu
; /* The popup filer menu */
120 static GtkWidget
*filer_file_item
; /* The File '' label */
121 static GtkWidget
*filer_file_menu
; /* The File '' menu */
122 static GtkWidget
*filer_hidden_menu
; /* The Show Hidden item */
123 static GtkWidget
*panel_menu
; /* The popup panel menu */
124 static GtkWidget
*panel_file_item
; /* The File '' label */
125 static GtkWidget
*panel_file_menu
; /* The File '' menu */
126 static GtkWidget
*panel_hidden_menu
; /* The Show Hidden item */
128 static gint screen_width
, screen_height
;
130 static GtkItemFactoryEntry filer_menu_def
[] = {
131 {"/Display", NULL
, NULL
, 0, "<Branch>"},
132 {"/Display/Large Icons", NULL
, large
, 0, "<RadioItem>"},
133 {"/Display/Small Icons", NULL
, small
, 0, "/Display/Large Icons"},
134 {"/Display/Full Info", NULL
, full_info
, 0, "/Display/Large Icons"},
135 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
136 {"/Display/Sort by Name", NULL
, sort_name
, 0, "<RadioItem>"},
137 {"/Display/Sort by Type", NULL
, sort_type
, 0, "/Display/Sort by Name"},
138 {"/Display/Sort by Date", NULL
, sort_date
, 0, "/Display/Sort by Name"},
139 {"/Display/Sort by Size", NULL
, sort_size
, 0, "/Display/Sort by Name"},
140 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
141 {"/Display/Show Hidden", C_
"H", hidden
, 0, "<ToggleItem>"},
142 {"/Display/Refresh", C_
"L", refresh
, 0, NULL
},
143 {"/File", NULL
, NULL
, 0, "<Branch>"},
144 {"/File/Copy...", NULL
, copy_item
, 0, NULL
},
145 {"/File/Rename...", NULL
, rename_item
, 0, NULL
},
146 {"/File/Link...", NULL
, link_item
, 0, NULL
},
147 {"/File/Help", "F1", help
, 0, NULL
},
148 {"/File/Info", "I", show_file_info
, 0, NULL
},
149 {"/File/Separator", NULL
, NULL
, 0, "<Separator>"},
150 {"/File/Mount", "M", mount
, 0, NULL
},
151 {"/File/Delete", C_
"X", delete, 0, NULL
},
152 {"/File/Disk Usage", "U", usage
, 0, NULL
},
153 {"/File/Permissions", NULL
, not_yet
, 0, NULL
},
154 {"/File/Touch", NULL
, not_yet
, 0, NULL
},
155 {"/File/Find", NULL
, not_yet
, 0, NULL
},
156 {"/Select All", C_
"A", select_all
, 0, NULL
},
157 {"/Clear Selection", C_
"Z", clear_selection
, 0, NULL
},
158 {"/Options...", NULL
, show_options
, 0, NULL
},
159 {"/New directory", NULL
, new_directory
, 0, NULL
},
160 {"/Xterm here", NULL
, xterm_here
, 0, NULL
},
161 {"/Window", NULL
, NULL
, 0, "<Branch>"},
162 {"/Window/Parent, new window", NULL
, open_parent
, 0, NULL
},
163 {"/Window/Parent, same window", NULL
, open_parent_same
, 0, NULL
},
164 {"/Window/New window", NULL
, new_window
, 0, NULL
},
165 {"/Window/Close window", C_
"Q", close_window
, 0, NULL
},
168 static GtkItemFactoryEntry panel_menu_def
[] = {
169 {"/Display", NULL
, NULL
, 0, "<Branch>"},
170 {"/Display/Large Icons", NULL
, large
, 0, "<RadioItem>"},
171 {"/Display/Small Icons", NULL
, small
, 0, "/Display/Large Icons"},
172 {"/Display/Full Info", NULL
, full_info
, 0, "/Display/Large Icons"},
173 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
174 {"/Display/Sort by Name", NULL
, sort_name
, 0, "<RadioItem>"},
175 {"/Display/Sort by Type", NULL
, sort_type
, 0, "/Display/Sort by Name"},
176 {"/Display/Sort by Date", NULL
, sort_date
, 0, "/Display/Sort by Name"},
177 {"/Display/Sort by Size", NULL
, sort_size
, 0, "/Display/Sort by Name"},
178 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
179 {"/Display/Show Hidden", NULL
, hidden
, 0, "<ToggleItem>"},
180 {"/Display/Refresh", NULL
, refresh
, 0, NULL
},
181 {"/File", NULL
, NULL
, 0, "<Branch>"},
182 {"/File/Help", NULL
, help
, 0, NULL
},
183 {"/File/Info", NULL
, show_file_info
, 0, NULL
},
184 {"/File/Delete", NULL
, delete, 0, NULL
},
185 {"/Open as directory", NULL
, open_as_dir
, 0, NULL
},
186 {"/Close panel", NULL
, close_panel
, 0, NULL
},
191 GtkItemFactory
*item_factory
;
195 /* This call starts returning strange values after a while, so get
196 * the result here during init.
198 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width
, &screen_height
);
200 filer_keys
= gtk_accel_group_new();
201 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
204 gtk_item_factory_create_items(item_factory
,
205 sizeof(filer_menu_def
) / sizeof(*filer_menu_def
),
208 filer_menu
= gtk_item_factory_get_widget(item_factory
, "<filer>");
209 filer_file_menu
= gtk_item_factory_get_widget(item_factory
,
211 filer_hidden_menu
= gtk_item_factory_get_widget(item_factory
,
212 "<filer>/Display/Show Hidden");
213 items
= gtk_container_children(GTK_CONTAINER(filer_menu
));
214 filer_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
217 panel_keys
= gtk_accel_group_new();
218 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
221 gtk_item_factory_create_items(item_factory
,
222 sizeof(panel_menu_def
) / sizeof(*panel_menu_def
),
225 panel_menu
= gtk_item_factory_get_widget(item_factory
, "<panel>");
226 panel_file_menu
= gtk_item_factory_get_widget(item_factory
,
228 panel_hidden_menu
= gtk_item_factory_get_widget(item_factory
,
229 "<panel>/Display/Show Hidden");
230 items
= gtk_container_children(GTK_CONTAINER(panel_menu
));
231 panel_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
234 menurc
= choices_find_path_load("menus");
236 gtk_item_factory_parse_rc(menurc
);
238 gtk_signal_connect(GTK_OBJECT(panel_menu
), "unmap_event",
239 GTK_SIGNAL_FUNC(menu_closed
), NULL
);
240 gtk_signal_connect(GTK_OBJECT(filer_menu
), "unmap_event",
241 GTK_SIGNAL_FUNC(menu_closed
), NULL
);
243 gtk_accel_group_lock(panel_keys
);
245 options_sections
= g_slist_prepend(options_sections
, &options
);
246 xterm_here_value
= g_strdup("xterm");
247 option_register("xterm_here", load_xterm_here
);
250 /* Build up some option widgets to go in the options dialog, but don't
253 static GtkWidget
*create_options()
255 GtkWidget
*table
, *label
;
257 table
= gtk_table_new(2, 2, FALSE
);
258 gtk_container_set_border_width(GTK_CONTAINER(table
), 4);
260 label
= gtk_label_new("To set the keyboard short-cuts you simply open "
261 "the menu over a filer window, move the pointer over "
262 "the item you want to use and press a key. The key "
263 "will appear next to the menu item and you can just "
264 "press that key without opening the menu in future. "
265 "To save the current menu short-cuts for next time, "
266 "click the Save button at the bottom of this window.");
267 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
268 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 2, 0, 1);
270 label
= gtk_label_new("'Xterm here' program:");
271 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 1, 2);
272 xterm_here_entry
= gtk_entry_new();
273 gtk_table_attach_defaults(GTK_TABLE(table
), xterm_here_entry
,
279 static char *load_xterm_here(char *data
)
281 g_free(xterm_here_value
);
282 xterm_here_value
= g_strdup(data
);
286 static void update_options()
288 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry
), xterm_here_value
);
291 static void set_options()
293 g_free(xterm_here_value
);
294 xterm_here_value
= g_strdup(gtk_entry_get_text(
295 GTK_ENTRY(xterm_here_entry
)));
298 static void save_options()
302 menurc
= choices_find_path_save("menus");
304 gtk_item_factory_dump_rc(menurc
, NULL
, TRUE
);
306 option_write("xterm_here", xterm_here_value
);
310 static void items_sensitive(GtkWidget
*menu
, int from
, int n
, gboolean state
)
314 items
= gtk_container_children(GTK_CONTAINER(menu
));
316 item
= g_list_nth(items
, from
);
319 gtk_widget_set_sensitive(GTK_BIN(item
->data
)->child
, state
);
326 static void position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
, gpointer data
)
328 int *pos
= (int *) data
;
329 GtkRequisition requisition
;
331 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
334 *x
= screen_width
- MENU_MARGIN
- requisition
.width
;
335 else if (pos
[0] == -2)
338 *x
= pos
[0] - (requisition
.width
>> 2);
341 *y
= screen_height
- MENU_MARGIN
- requisition
.height
;
342 else if (pos
[1] == -2)
345 *y
= pos
[1] - (requisition
.height
>> 2);
347 *x
= CLAMP(*x
, 0, screen_width
- requisition
.width
);
348 *y
= CLAMP(*y
, 0, screen_height
- requisition
.height
);
351 void show_filer_menu(FilerWindow
*filer_window
, GdkEventButton
*event
,
355 GtkWidget
*file_label
, *file_menu
;
359 pos
[0] = event
->x_root
;
360 pos
[1] = event
->y_root
;
362 window_with_focus
= filer_window
;
364 if (filer_window
->panel
)
366 switch (filer_window
->panel_side
)
368 case TOP
: pos
[1] = -2; break;
369 case BOTTOM
: pos
[1] = -1; break;
370 case LEFT
: pos
[0] = -2; break;
371 case RIGHT
: pos
[0] = -1; break;
375 if (filer_window
->panel
)
376 collection_clear_selection(filer_window
->collection
); /* ??? */
378 if (filer_window
->collection
->number_selected
== 0 && item
>= 0)
380 collection_select_item(filer_window
->collection
, item
);
381 filer_window
->temp_item_selected
= TRUE
;
384 filer_window
->temp_item_selected
= FALSE
;
386 if (filer_window
->panel
)
388 file_label
= panel_file_item
;
389 file_menu
= panel_file_menu
;
391 gtk_check_menu_item_set_active(
392 GTK_CHECK_MENU_ITEM(panel_hidden_menu
),
393 filer_window
->show_hidden
);
397 file_label
= filer_file_item
;
398 file_menu
= filer_file_menu
;
400 gtk_check_menu_item_set_active(
401 GTK_CHECK_MENU_ITEM(filer_hidden_menu
),
402 filer_window
->show_hidden
);
405 buffer
= g_string_new(NULL
);
406 switch (filer_window
->collection
->number_selected
)
409 g_string_assign(buffer
, "<nothing selected>");
410 items_sensitive(file_menu
, 0, 5, FALSE
);
411 items_sensitive(file_menu
, 6, -1, FALSE
);
412 gtk_widget_set_sensitive(file_label
, FALSE
);
415 items_sensitive(file_menu
, 0, 5, TRUE
);
416 items_sensitive(file_menu
, 6, -1, TRUE
);
417 gtk_widget_set_sensitive(file_label
, TRUE
);
418 file_item
= selected_item(filer_window
->collection
);
419 g_string_sprintf(buffer
, "%s '%s'",
420 basetype_name(file_item
),
421 file_item
->leafname
);
424 items_sensitive(file_menu
, 0, 5, FALSE
);
425 items_sensitive(file_menu
, 6, -1, TRUE
);
426 gtk_widget_set_sensitive(file_label
, TRUE
);
427 g_string_sprintf(buffer
, "%d items",
428 filer_window
->collection
->number_selected
);
432 gtk_label_set_text(GTK_LABEL(file_label
), buffer
->str
);
434 g_string_free(buffer
, TRUE
);
436 gtk_menu_popup(filer_window
->panel
? GTK_MENU(panel_menu
)
437 : GTK_MENU(filer_menu
),
438 NULL
, NULL
, position_menu
,
439 (gpointer
) pos
, event
->button
, event
->time
);
442 static void menu_closed(GtkWidget
*widget
)
444 if (window_with_focus
== NULL
)
445 return; /* Close panel item chosen? */
447 if (window_with_focus
->temp_item_selected
)
449 collection_clear_selection(window_with_focus
->collection
);
450 window_with_focus
->temp_item_selected
= FALSE
;
456 /* Fake action to warn when a menu item does nothing */
457 static void not_yet(gpointer data
, guint action
, GtkWidget
*widget
)
459 delayed_error("ROX-Filer", "Sorry, that feature isn't implemented yet");
462 static void large(gpointer data
, guint action
, GtkWidget
*widget
)
464 g_return_if_fail(window_with_focus
!= NULL
);
466 filer_style_set(window_with_focus
, LARGE_ICONS
);
469 static void small(gpointer data
, guint action
, GtkWidget
*widget
)
471 g_return_if_fail(window_with_focus
!= NULL
);
473 filer_style_set(window_with_focus
, SMALL_ICONS
);
476 static void full_info(gpointer data
, guint action
, GtkWidget
*widget
)
478 g_return_if_fail(window_with_focus
!= NULL
);
480 filer_style_set(window_with_focus
, FULL_INFO
);
483 static void sort_name(gpointer data
, guint action
, GtkWidget
*widget
)
485 g_return_if_fail(window_with_focus
!= NULL
);
487 filer_set_sort_fn(window_with_focus
, sort_by_name
);
490 static void sort_type(gpointer data
, guint action
, GtkWidget
*widget
)
492 g_return_if_fail(window_with_focus
!= NULL
);
494 filer_set_sort_fn(window_with_focus
, sort_by_type
);
497 static void sort_date(gpointer data
, guint action
, GtkWidget
*widget
)
499 g_return_if_fail(window_with_focus
!= NULL
);
501 filer_set_sort_fn(window_with_focus
, sort_by_date
);
504 static void sort_size(gpointer data
, guint action
, GtkWidget
*widget
)
506 g_return_if_fail(window_with_focus
!= NULL
);
508 filer_set_sort_fn(window_with_focus
, sort_by_size
);
511 static void hidden(gpointer data
, guint action
, GtkWidget
*widget
)
516 g_return_if_fail(window_with_focus
!= NULL
);
518 item
= window_with_focus
->panel
? panel_hidden_menu
: filer_hidden_menu
;
519 new = GTK_CHECK_MENU_ITEM(item
)->active
;
521 filer_set_hidden(window_with_focus
, new);
524 static void refresh(gpointer data
, guint action
, GtkWidget
*widget
)
526 g_return_if_fail(window_with_focus
!= NULL
);
529 update_dir(window_with_focus
);
532 static void mount(gpointer data
, guint action
, GtkWidget
*widget
)
534 g_return_if_fail(window_with_focus
!= NULL
);
536 action_mount(window_with_focus
);
539 static void delete(gpointer data
, guint action
, GtkWidget
*widget
)
541 g_return_if_fail(window_with_focus
!= NULL
);
543 action_delete(window_with_focus
);
546 static void usage(gpointer data
, guint action
, GtkWidget
*widget
)
548 g_return_if_fail(window_with_focus
!= NULL
);
550 action_usage(window_with_focus
);
553 static gboolean
copy_cb(char *initial
, char *path
)
555 char *new_dir
, *slash
;
558 gboolean retval
= TRUE
;
560 slash
= strrchr(path
, '/');
563 report_error("ROX-Filer", "Missing '/' in new pathname");
567 if (access(path
, F_OK
) == 0)
569 report_error("ROX-Filer",
570 "An item with this name already exists");
575 new_dir
= g_malloc(len
+ 1);
576 memcpy(new_dir
, path
, len
);
579 command
= g_string_new(NULL
);
580 g_string_sprintf(command
, "cp -a %s %s", initial
, path
);
582 if (system(command
->str
))
584 g_string_append(command
, " failed!");
585 report_error("ROX-Filer", command
->str
);
589 g_string_free(command
, TRUE
);
591 refresh_dirs(new_dir
);
595 static void copy_item(gpointer data
, guint action
, GtkWidget
*widget
)
597 Collection
*collection
;
599 g_return_if_fail(window_with_focus
!= NULL
);
601 collection
= window_with_focus
->collection
;
602 if (collection
->number_selected
!= 1)
603 report_error("ROX-Filer", "You must select a single "
607 DirItem
*item
= selected_item(collection
);
609 savebox_show(window_with_focus
, "Copy",
610 window_with_focus
->path
,
612 item
->image
, copy_cb
);
616 static gboolean
rename_cb(char *initial
, char *path
)
618 if (rename(initial
, path
))
620 report_error("ROX-Filer: rename()", g_strerror(errno
));
626 static void rename_item(gpointer data
, guint action
, GtkWidget
*widget
)
628 Collection
*collection
;
630 g_return_if_fail(window_with_focus
!= NULL
);
632 collection
= window_with_focus
->collection
;
633 if (collection
->number_selected
!= 1)
634 report_error("ROX-Filer", "You must select a single "
638 DirItem
*item
= selected_item(collection
);
640 savebox_show(window_with_focus
, "Rename",
641 window_with_focus
->path
,
643 item
->image
, rename_cb
);
647 static gboolean
link_cb(char *initial
, char *path
)
649 if (symlink(initial
, path
))
651 report_error("ROX-Filer: symlink()", g_strerror(errno
));
657 static void link_item(gpointer data
, guint action
, GtkWidget
*widget
)
659 Collection
*collection
;
661 g_return_if_fail(window_with_focus
!= NULL
);
663 collection
= window_with_focus
->collection
;
664 if (collection
->number_selected
!= 1)
665 report_error("ROX-Filer", "You must select a single "
669 DirItem
*item
= selected_item(collection
);
671 savebox_show(window_with_focus
, "Symlink",
672 window_with_focus
->path
,
674 item
->image
, link_cb
);
678 static void show_file_info(gpointer data
, guint action
, GtkWidget
*widget
)
680 GtkWidget
*window
, *table
, *label
, *button
, *frame
;
681 GtkWidget
*file_label
;
687 char *argv
[] = {"file", "-b", NULL
, NULL
};
689 Collection
*collection
;
693 g_return_if_fail(window_with_focus
!= NULL
);
695 collection
= window_with_focus
->collection
;
696 if (collection
->number_selected
!= 1)
698 report_error("ROX-Filer", "You must select a single "
699 "item before using Info");
702 file
= selected_item(collection
);
703 path
= make_path(window_with_focus
->path
,
704 file
->leafname
)->str
;
705 if (lstat(path
, &info
))
707 delayed_error("ROX-Filer", g_strerror(errno
));
711 gstring
= g_string_new(NULL
);
713 window
= gtk_window_new(GTK_WINDOW_DIALOG
);
714 gtk_window_set_position(GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
715 gtk_container_set_border_width(GTK_CONTAINER(window
), 4);
716 gtk_window_set_title(GTK_WINDOW(window
), path
);
718 table
= gtk_table_new(9, 2, FALSE
);
719 gtk_container_add(GTK_CONTAINER(window
), table
);
720 gtk_table_set_row_spacings(GTK_TABLE(table
), 8);
721 gtk_table_set_col_spacings(GTK_TABLE(table
), 4);
723 label
= gtk_label_new("Owner, group:");
724 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
725 gtk_label_set_justify(GTK_LABEL(label
), GTK_JUSTIFY_RIGHT
);
726 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 0, 1);
727 g_string_sprintf(gstring
, "%s, %s", user_name(info
.st_uid
),
728 group_name(info
.st_gid
));
729 label
= gtk_label_new(gstring
->str
);
730 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
731 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 0, 1);
733 label
= gtk_label_new("Size:");
734 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
735 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 1, 2);
736 if (info
.st_size
>=2048)
738 g_string_sprintf(gstring
, "%s (%ld bytes)",
739 format_size((unsigned long) info
.st_size
),
740 (unsigned long) info
.st_size
);
744 g_string_sprintf(gstring
, "%ld bytes",
745 (unsigned long) info
.st_size
);
747 label
= gtk_label_new(gstring
->str
);
748 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
749 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 1, 2);
751 label
= gtk_label_new("Change time:");
752 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
753 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 2, 3);
754 g_string_sprintf(gstring
, "%s", ctime(&info
.st_ctime
));
755 g_string_truncate(gstring
, gstring
->len
- 1);
756 label
= gtk_label_new(gstring
->str
);
757 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
758 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 2, 3);
760 label
= gtk_label_new("Modify time:");
761 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
762 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 3, 4);
763 g_string_sprintf(gstring
, "%s", ctime(&info
.st_mtime
));
764 g_string_truncate(gstring
, gstring
->len
- 1);
765 label
= gtk_label_new(gstring
->str
);
766 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
767 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 3, 4);
769 label
= gtk_label_new("Access time:");
770 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
771 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 4, 5);
772 g_string_sprintf(gstring
, "%s", ctime(&info
.st_atime
));
773 g_string_truncate(gstring
, gstring
->len
- 1);
774 label
= gtk_label_new(gstring
->str
);
775 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
776 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 4, 5);
778 label
= gtk_label_new("Permissions:");
779 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
780 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 5, 6);
781 g_string_sprintf(gstring
, "%o", (unsigned int) info
.st_mode
);
782 label
= gtk_label_new(gstring
->str
);
783 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
784 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 5, 6);
786 label
= gtk_label_new("MIME type:");
787 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
788 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 6, 7);
791 string
= g_strconcat(file
->mime_type
->media_type
, "/",
792 file
->mime_type
->subtype
, NULL
);
793 label
= gtk_label_new(string
);
797 label
= gtk_label_new("-");
798 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
799 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 6, 7);
801 frame
= gtk_frame_new("file(1) says...");
802 gtk_table_attach_defaults(GTK_TABLE(table
), frame
, 0, 2, 7, 8);
803 file_label
= gtk_label_new("<nothing yet>");
804 gtk_misc_set_padding(GTK_MISC(file_label
), 4, 4);
805 gtk_label_set_line_wrap(GTK_LABEL(file_label
), TRUE
);
806 gtk_container_add(GTK_CONTAINER(frame
), file_label
);
808 button
= gtk_button_new_with_label("OK");
809 gtk_table_attach(GTK_TABLE(table
), button
, 0, 2, 8, 9,
810 GTK_EXPAND
| GTK_FILL
| GTK_SHRINK
, 0, 40, 4);
811 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
812 gtk_widget_destroy
, GTK_OBJECT(window
));
814 gtk_widget_show_all(window
);
819 g_string_sprintf(gstring
, "pipe(): %s", g_strerror(errno
));
827 g_string_sprintf(gstring
, "fork(): %s",
832 dup2(file_data
[1], STDOUT_FILENO
);
833 dup2(file_data
[1], STDERR_FILENO
);
839 if (execvp(argv
[0], argv
))
840 fprintf(stderr
, "execvp() error: %s\n",
844 /* We are the parent... */
846 g_string_truncate(gstring
, 0);
847 while (gtk_events_pending())
848 g_main_iteration(FALSE
);
849 while ((got
= read(file_data
[0], buffer
, sizeof(buffer
) - 1)) > 0)
852 g_string_append(gstring
, buffer
);
856 gtk_label_set_text(GTK_LABEL(file_label
), gstring
->str
);
857 g_string_free(gstring
, TRUE
);
860 static void help(gpointer data
, guint action
, GtkWidget
*widget
)
862 Collection
*collection
;
865 g_return_if_fail(window_with_focus
!= NULL
);
867 collection
= window_with_focus
->collection
;
868 if (collection
->number_selected
!= 1)
870 report_error("ROX-Filer", "You must select a single "
871 "item to get help on");
874 item
= selected_item(collection
);
875 switch (item
->base_type
)
878 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
879 report_error("Executable file",
880 "This is a file with an eXecute bit "
881 "set - it can be run as a program.");
884 "This is a data file. Try using the "
885 "Info menu item to find out more...");
888 if (item
->flags
& ITEM_FLAG_APPDIR
)
890 make_path(window_with_focus
->path
,
891 item
->leafname
)->str
);
892 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
893 report_error("Mount point",
894 "A mount point is a directory which another "
895 "filing system can be mounted on. Everything "
896 "on the mounted filesystem then appears to be "
897 "inside the directory.");
899 report_error("Directory",
900 "This is a directory. It contains an index to "
901 "other items - open it to see the list.");
903 case TYPE_CHAR_DEVICE
:
904 case TYPE_BLOCK_DEVICE
:
905 report_error("Device file",
906 "Device files allow you to read from or write "
907 "to a device driver as though it was an "
911 report_error("Named pipe",
912 "Pipes allow different programs to "
913 "communicate. One program writes data to the "
914 "pipe while another one reads it out again.");
917 report_error("Socket",
918 "Sockets allow processes to communicate.");
921 report_error("Unknown type",
922 "I couldn't find out what kind of file this "
923 "is. Maybe it doesn't exist anymore or you "
924 "don't have search permission on the directory "
930 static void select_all(gpointer data
, guint action
, GtkWidget
*widget
)
932 g_return_if_fail(window_with_focus
!= NULL
);
934 collection_select_all(window_with_focus
->collection
);
935 window_with_focus
->temp_item_selected
= FALSE
;
938 static void clear_selection(gpointer data
, guint action
, GtkWidget
*widget
)
940 g_return_if_fail(window_with_focus
!= NULL
);
942 collection_clear_selection(window_with_focus
->collection
);
943 window_with_focus
->temp_item_selected
= FALSE
;
946 static void show_options(gpointer data
, guint action
, GtkWidget
*widget
)
948 g_return_if_fail(window_with_focus
!= NULL
);
950 options_show(window_with_focus
);
953 static gboolean
new_directory_cb(char *initial
, char *path
)
955 if (mkdir(path
, S_IRWXU
| S_IRWXG
| S_IRWXO
))
957 report_error("mkdir", g_strerror(errno
));
963 static void new_directory(gpointer data
, guint action
, GtkWidget
*widget
)
965 g_return_if_fail(window_with_focus
!= NULL
);
967 savebox_show(window_with_focus
, "Create directory",
968 window_with_focus
->path
, "NewDir",
969 default_pixmap
+ TYPE_DIRECTORY
, new_directory_cb
);
972 static void xterm_here(gpointer data
, guint action
, GtkWidget
*widget
)
974 char *argv
[] = {NULL
, NULL
};
976 argv
[0] = xterm_here_value
;
978 g_return_if_fail(window_with_focus
!= NULL
);
980 if (!spawn_full(argv
, window_with_focus
->path
, 0))
981 report_error("ROX-Filer", "Failed to fork() child "
985 static void open_parent(gpointer data
, guint action
, GtkWidget
*widget
)
987 g_return_if_fail(window_with_focus
!= NULL
);
989 filer_opendir(make_path(window_with_focus
->path
, "/..")->str
,
993 static void open_parent_same(gpointer data
, guint action
, GtkWidget
*widget
)
995 g_return_if_fail(window_with_focus
!= NULL
);
997 change_to_parent(window_with_focus
);
1000 static void new_window(gpointer data
, guint action
, GtkWidget
*widget
)
1002 g_return_if_fail(window_with_focus
!= NULL
);
1004 filer_opendir(window_with_focus
->path
, FALSE
, BOTTOM
);
1007 static void close_window(gpointer data
, guint action
, GtkWidget
*widget
)
1009 g_return_if_fail(window_with_focus
!= NULL
);
1011 gtk_widget_destroy(window_with_focus
->window
);
1014 static void open_as_dir(gpointer data
, guint action
, GtkWidget
*widget
)
1016 g_return_if_fail(window_with_focus
!= NULL
);
1018 filer_opendir(window_with_focus
->path
, FALSE
, BOTTOM
);
1021 static void close_panel(gpointer data
, guint action
, GtkWidget
*widget
)
1023 g_return_if_fail(window_with_focus
!= NULL
);
1025 gtk_widget_destroy(window_with_focus
->window
);