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"
49 #include "minibuffer.h"
51 #define C_ "<control>"
53 #define MENU_MARGIN 32
55 GtkAccelGroup
*filer_keys
;
56 GtkAccelGroup
*panel_keys
;
58 static GtkWidget
*popup_menu
= NULL
; /* Currently open menu */
60 static gint updating_menu
= 0; /* Non-zero => ignore activations */
63 static GtkWidget
*xterm_here_entry
;
64 static char *xterm_here_value
;
66 /* Static prototypes */
68 static void position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
, gpointer data
);
69 static void menu_closed(GtkWidget
*widget
);
70 static void items_sensitive(GtkWidget
*menu
, int from
, int n
, gboolean state
);
71 static char *load_xterm_here(char *data
);
73 /* Note that for these callbacks none of the arguments are used. */
74 static void not_yet(gpointer data
, guint action
, GtkWidget
*widget
);
76 static void large(gpointer data
, guint action
, GtkWidget
*widget
);
77 static void small(gpointer data
, guint action
, GtkWidget
*widget
);
78 static void full_info(gpointer data
, guint action
, GtkWidget
*widget
);
80 static void sort_name(gpointer data
, guint action
, GtkWidget
*widget
);
81 static void sort_type(gpointer data
, guint action
, GtkWidget
*widget
);
82 static void sort_size(gpointer data
, guint action
, GtkWidget
*widget
);
83 static void sort_date(gpointer data
, guint action
, GtkWidget
*widget
);
85 static void hidden(gpointer data
, guint action
, GtkWidget
*widget
);
86 static void refresh(gpointer data
, guint action
, GtkWidget
*widget
);
88 static void copy_item(gpointer data
, guint action
, GtkWidget
*widget
);
89 static void rename_item(gpointer data
, guint action
, GtkWidget
*widget
);
90 static void link_item(gpointer data
, guint action
, GtkWidget
*widget
);
91 static void open_file(gpointer data
, guint action
, GtkWidget
*widget
);
92 static void help(gpointer data
, guint action
, GtkWidget
*widget
);
93 static void show_file_info(gpointer data
, guint action
, GtkWidget
*widget
);
94 static void mount(gpointer data
, guint action
, GtkWidget
*widget
);
95 static void delete(gpointer data
, guint action
, GtkWidget
*widget
);
96 static void usage(gpointer data
, guint action
, GtkWidget
*widget
);
98 static void select_all(gpointer data
, guint action
, GtkWidget
*widget
);
99 static void clear_selection(gpointer data
, guint action
, GtkWidget
*widget
);
100 static void show_options(gpointer data
, guint action
, GtkWidget
*widget
);
101 static void new_directory(gpointer data
, guint action
, GtkWidget
*widget
);
102 static void xterm_here(gpointer data
, guint action
, GtkWidget
*widget
);
104 static void open_parent_same(gpointer data
, guint action
, GtkWidget
*widget
);
105 static void open_parent(gpointer data
, guint action
, GtkWidget
*widget
);
106 static void new_window(gpointer data
, guint action
, GtkWidget
*widget
);
107 static void close_window(gpointer data
, guint action
, GtkWidget
*widget
);
108 static void enter_path(gpointer data
, guint action
, GtkWidget
*widget
);
109 static void rox_help(gpointer data
, guint action
, GtkWidget
*widget
);
111 static void open_as_dir(gpointer data
, guint action
, GtkWidget
*widget
);
112 static void close_panel(gpointer data
, guint action
, GtkWidget
*widget
);
114 static GtkWidget
*create_options();
115 static void update_options();
116 static void set_options();
117 static void save_options();
119 static OptionsSection options
=
129 static GtkWidget
*filer_menu
; /* The popup filer menu */
130 static GtkWidget
*filer_file_item
; /* The File '' label */
131 static GtkWidget
*filer_file_menu
; /* The File '' menu */
132 static GtkWidget
*filer_hidden_menu
; /* The Show Hidden item */
133 static GtkWidget
*panel_menu
; /* The popup panel menu */
134 static GtkWidget
*panel_file_item
; /* The File '' label */
135 static GtkWidget
*panel_file_menu
; /* The File '' menu */
136 static GtkWidget
*panel_hidden_menu
; /* The Show Hidden item */
138 static gint screen_width
, screen_height
;
140 static GtkItemFactoryEntry filer_menu_def
[] = {
141 {"/Display", NULL
, NULL
, 0, "<Branch>"},
142 {"/Display/Large Icons", NULL
, large
, 0, NULL
},
143 {"/Display/Small Icons", NULL
, small
, 0, NULL
},
144 {"/Display/Full Info", NULL
, full_info
, 0, NULL
},
145 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
146 {"/Display/Sort by Name", NULL
, sort_name
, 0, NULL
},
147 {"/Display/Sort by Type", NULL
, sort_type
, 0, NULL
},
148 {"/Display/Sort by Date", NULL
, sort_date
, 0, NULL
},
149 {"/Display/Sort by Size", NULL
, sort_size
, 0, NULL
},
150 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
151 {"/Display/Show Hidden", C_
"H", hidden
, 0, "<ToggleItem>"},
152 {"/Display/Refresh", C_
"L", refresh
, 0, NULL
},
153 {"/File", NULL
, NULL
, 0, "<Branch>"},
154 {"/File/Copy...", NULL
, copy_item
, 0, NULL
},
155 {"/File/Rename...", NULL
, rename_item
, 0, NULL
},
156 {"/File/Link...", NULL
, link_item
, 0, NULL
},
157 {"/File/Shift Open", NULL
, open_file
, 0, NULL
},
158 {"/File/Help", "F1", help
, 0, NULL
},
159 {"/File/Info", "I", show_file_info
, 0, NULL
},
160 {"/File/Separator", NULL
, NULL
, 0, "<Separator>"},
161 {"/File/Mount", "M", mount
, 0, NULL
},
162 {"/File/Delete", C_
"X", delete, 0, NULL
},
163 {"/File/Disk Usage", "U", usage
, 0, NULL
},
164 {"/File/Permissions", NULL
, not_yet
, 0, NULL
},
165 {"/File/Touch", NULL
, not_yet
, 0, NULL
},
166 {"/File/Find", NULL
, not_yet
, 0, NULL
},
167 {"/Select All", C_
"A", select_all
, 0, NULL
},
168 {"/Clear Selection", C_
"Z", clear_selection
, 0, NULL
},
169 {"/Options...", NULL
, show_options
, 0, NULL
},
170 {"/New Directory...", NULL
, new_directory
, 0, NULL
},
171 {"/Xterm Here", NULL
, xterm_here
, 0, NULL
},
172 {"/Window", NULL
, NULL
, 0, "<Branch>"},
173 {"/Window/Parent, New Window", NULL
, open_parent
, 0, NULL
},
174 {"/Window/Parent, Same Window", NULL
, open_parent_same
, 0, NULL
},
175 {"/Window/New Window", NULL
, new_window
, 0, NULL
},
176 {"/Window/Close Window", C_
"Q", close_window
, 0, NULL
},
177 {"/Window/Enter Path", NULL
, enter_path
, 0, NULL
},
178 {"/Window/Separator", NULL
, NULL
, 0, "<Separator>"},
179 {"/Window/Show ROX-Filer help", NULL
, rox_help
, 0, NULL
},
182 static GtkItemFactoryEntry panel_menu_def
[] = {
183 {"/Display", NULL
, NULL
, 0, "<Branch>"},
184 {"/Display/Sort by Name", NULL
, sort_name
, 0, NULL
},
185 {"/Display/Sort by Type", NULL
, sort_type
, 0, NULL
},
186 {"/Display/Sort by Date", NULL
, sort_date
, 0, NULL
},
187 {"/Display/Sort by Size", NULL
, sort_size
, 0, NULL
},
188 {"/Display/Separator", NULL
, NULL
, 0, "<Separator>"},
189 {"/Display/Show Hidden", NULL
, hidden
, 0, "<ToggleItem>"},
190 {"/Display/Refresh", NULL
, refresh
, 0, NULL
},
191 {"/File", NULL
, NULL
, 0, "<Branch>"},
192 {"/File/Help", NULL
, help
, 0, NULL
},
193 {"/File/Info", NULL
, show_file_info
, 0, NULL
},
194 {"/File/Delete", NULL
, delete, 0, NULL
},
195 {"/Open as directory", NULL
, open_as_dir
, 0, NULL
},
196 {"/Options...", NULL
, show_options
, 0, NULL
},
197 {"/Close panel", NULL
, close_panel
, 0, NULL
},
198 {"/Separator", NULL
, NULL
, 0, "<Separator>"},
199 {"/Show ROX-Filer help", NULL
, rox_help
, 0, NULL
},
202 typedef struct _FileStatus FileStatus
;
204 /* This is for the 'file(1) says...' thing */
207 int fd
; /* FD to read from, -1 if closed */
208 int input
; /* Input watcher tag if fd valid */
209 GtkLabel
*label
; /* Widget to output to */
210 gboolean start
; /* No output yet */
215 GtkItemFactory
*item_factory
;
219 /* This call starts returning strange values after a while, so get
220 * the result here during init.
222 gdk_window_get_size(GDK_ROOT_PARENT(), &screen_width
, &screen_height
);
224 filer_keys
= gtk_accel_group_new();
225 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
228 gtk_item_factory_create_items(item_factory
,
229 sizeof(filer_menu_def
) / sizeof(*filer_menu_def
),
232 filer_menu
= gtk_item_factory_get_widget(item_factory
, "<filer>");
233 filer_file_menu
= gtk_item_factory_get_widget(item_factory
,
235 filer_hidden_menu
= gtk_item_factory_get_widget(item_factory
,
236 "<filer>/Display/Show Hidden");
237 items
= gtk_container_children(GTK_CONTAINER(filer_menu
));
238 filer_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
241 panel_keys
= gtk_accel_group_new();
242 item_factory
= gtk_item_factory_new(GTK_TYPE_MENU
,
245 gtk_item_factory_create_items(item_factory
,
246 sizeof(panel_menu_def
) / sizeof(*panel_menu_def
),
249 panel_menu
= gtk_item_factory_get_widget(item_factory
, "<panel>");
250 panel_file_menu
= gtk_item_factory_get_widget(item_factory
,
252 panel_hidden_menu
= gtk_item_factory_get_widget(item_factory
,
253 "<panel>/Display/Show Hidden");
254 items
= gtk_container_children(GTK_CONTAINER(panel_menu
));
255 panel_file_item
= GTK_BIN(g_list_nth(items
, 1)->data
)->child
;
258 menurc
= choices_find_path_load("menus");
260 gtk_item_factory_parse_rc(menurc
);
262 gtk_accel_group_lock(panel_keys
);
264 gtk_signal_connect(GTK_OBJECT(filer_menu
), "unmap_event",
265 GTK_SIGNAL_FUNC(menu_closed
), NULL
);
266 gtk_signal_connect(GTK_OBJECT(panel_menu
), "unmap_event",
267 GTK_SIGNAL_FUNC(menu_closed
), NULL
);
268 gtk_signal_connect(GTK_OBJECT(filer_file_menu
), "unmap_event",
269 GTK_SIGNAL_FUNC(menu_closed
), NULL
);
271 options_sections
= g_slist_prepend(options_sections
, &options
);
272 xterm_here_value
= g_strdup("xterm");
273 option_register("xterm_here", load_xterm_here
);
276 /* Build up some option widgets to go in the options dialog, but don't
279 static GtkWidget
*create_options()
281 GtkWidget
*table
, *label
;
283 table
= gtk_table_new(2, 2, FALSE
);
284 gtk_container_set_border_width(GTK_CONTAINER(table
), 4);
286 label
= gtk_label_new("To set the keyboard short-cuts you simply open "
287 "the menu over a filer window, move the pointer over "
288 "the item you want to use and press a key. The key "
289 "will appear next to the menu item and you can just "
290 "press that key without opening the menu in future. "
291 "To save the current menu short-cuts for next time, "
292 "click the Save button at the bottom of this window.");
293 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
294 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 2, 0, 1);
296 label
= gtk_label_new("'Xterm here' program:");
297 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 1, 2);
298 xterm_here_entry
= gtk_entry_new();
299 gtk_table_attach_defaults(GTK_TABLE(table
), xterm_here_entry
,
305 static char *load_xterm_here(char *data
)
307 g_free(xterm_here_value
);
308 xterm_here_value
= g_strdup(data
);
312 static void update_options()
314 gtk_entry_set_text(GTK_ENTRY(xterm_here_entry
), xterm_here_value
);
317 static void set_options()
319 g_free(xterm_here_value
);
320 xterm_here_value
= g_strdup(gtk_entry_get_text(
321 GTK_ENTRY(xterm_here_entry
)));
324 static void save_options()
328 menurc
= choices_find_path_save("menus", TRUE
);
330 gtk_item_factory_dump_rc(menurc
, NULL
, TRUE
);
332 option_write("xterm_here", xterm_here_value
);
336 static void items_sensitive(GtkWidget
*menu
, int from
, int n
, gboolean state
)
340 items
= gtk_container_children(GTK_CONTAINER(menu
));
342 item
= g_list_nth(items
, from
);
345 gtk_widget_set_sensitive(GTK_BIN(item
->data
)->child
, state
);
352 static void position_menu(GtkMenu
*menu
, gint
*x
, gint
*y
, gpointer data
)
354 int *pos
= (int *) data
;
355 GtkRequisition requisition
;
357 gtk_widget_size_request(GTK_WIDGET(menu
), &requisition
);
360 *x
= screen_width
- MENU_MARGIN
- requisition
.width
;
361 else if (pos
[0] == -2)
364 *x
= pos
[0] - (requisition
.width
>> 2);
367 *y
= screen_height
- MENU_MARGIN
- requisition
.height
;
368 else if (pos
[1] == -2)
371 *y
= pos
[1] - (requisition
.height
>> 2);
373 *x
= CLAMP(*x
, 0, screen_width
- requisition
.width
);
374 *y
= CLAMP(*y
, 0, screen_height
- requisition
.height
);
377 void show_filer_menu(FilerWindow
*filer_window
, GdkEventButton
*event
,
381 GtkWidget
*file_label
, *file_menu
;
387 pos
[0] = event
->x_root
;
388 pos
[1] = event
->y_root
;
390 window_with_focus
= filer_window
;
392 switch (filer_window
->panel_type
)
404 if (filer_window
->panel_type
)
405 collection_clear_selection(filer_window
->collection
); /* ??? */
407 if (filer_window
->collection
->number_selected
== 0 && item
>= 0)
409 collection_select_item(filer_window
->collection
, item
);
410 filer_window
->temp_item_selected
= TRUE
;
413 filer_window
->temp_item_selected
= FALSE
;
415 if (filer_window
->panel_type
)
417 file_label
= panel_file_item
;
418 file_menu
= panel_file_menu
;
419 gtk_check_menu_item_set_active(
420 GTK_CHECK_MENU_ITEM(panel_hidden_menu
),
421 filer_window
->show_hidden
);
425 file_label
= filer_file_item
;
426 file_menu
= filer_file_menu
;
427 gtk_check_menu_item_set_active(
428 GTK_CHECK_MENU_ITEM(filer_hidden_menu
),
429 filer_window
->show_hidden
);
432 buffer
= g_string_new(NULL
);
433 switch (filer_window
->collection
->number_selected
)
436 g_string_assign(buffer
, "Next Click");
437 items_sensitive(file_menu
, 0, 6, TRUE
);
440 items_sensitive(file_menu
, 0, 6, TRUE
);
441 file_item
= selected_item(filer_window
->collection
);
442 g_string_sprintf(buffer
, "%s '%s'",
443 basetype_name(file_item
),
444 file_item
->leafname
);
447 items_sensitive(file_menu
, 0, 6, FALSE
);
448 g_string_sprintf(buffer
, "%d items",
449 filer_window
->collection
->number_selected
);
453 gtk_label_set_text(GTK_LABEL(file_label
), buffer
->str
);
455 g_string_free(buffer
, TRUE
);
457 if (filer_window
->panel_type
)
458 popup_menu
= panel_menu
;
460 popup_menu
= (event
->state
& GDK_CONTROL_MASK
)
466 gtk_menu_popup(GTK_MENU(popup_menu
), NULL
, NULL
, position_menu
,
467 (gpointer
) pos
, event
->button
, event
->time
);
470 static void menu_closed(GtkWidget
*widget
)
472 if (window_with_focus
== NULL
|| widget
!= popup_menu
)
473 return; /* Close panel item chosen? */
475 if (window_with_focus
->temp_item_selected
)
477 collection_clear_selection(window_with_focus
->collection
);
478 window_with_focus
->temp_item_selected
= FALSE
;
482 void target_callback(Collection
*collection
, gint item
, gpointer real_fn
)
484 g_return_if_fail(window_with_focus
!= NULL
);
485 g_return_if_fail(window_with_focus
->collection
== collection
);
486 g_return_if_fail(real_fn
!= NULL
);
488 collection_wink_item(collection
, item
);
489 collection_clear_selection(collection
);
490 collection_select_item(collection
, item
);
491 ((CollectionTargetFunc
)real_fn
)(NULL
, 0, collection
);
492 if (item
< collection
->number_of_items
)
493 collection_unselect_item(collection
, item
);
498 /* Fake action to warn when a menu item does nothing */
499 static void not_yet(gpointer data
, guint action
, GtkWidget
*widget
)
501 delayed_error("ROX-Filer", "Sorry, that feature isn't implemented yet");
504 static void large(gpointer data
, guint action
, GtkWidget
*widget
)
506 g_return_if_fail(window_with_focus
!= NULL
);
508 filer_style_set(window_with_focus
, LARGE_ICONS
);
511 static void small(gpointer data
, guint action
, GtkWidget
*widget
)
513 g_return_if_fail(window_with_focus
!= NULL
);
515 filer_style_set(window_with_focus
, SMALL_ICONS
);
518 static void full_info(gpointer data
, guint action
, GtkWidget
*widget
)
520 g_return_if_fail(window_with_focus
!= NULL
);
522 filer_style_set(window_with_focus
, FULL_INFO
);
525 static void sort_name(gpointer data
, guint action
, GtkWidget
*widget
)
527 g_return_if_fail(window_with_focus
!= NULL
);
529 filer_set_sort_fn(window_with_focus
, sort_by_name
);
532 static void sort_type(gpointer data
, guint action
, GtkWidget
*widget
)
534 g_return_if_fail(window_with_focus
!= NULL
);
536 filer_set_sort_fn(window_with_focus
, sort_by_type
);
539 static void sort_date(gpointer data
, guint action
, GtkWidget
*widget
)
541 g_return_if_fail(window_with_focus
!= NULL
);
543 filer_set_sort_fn(window_with_focus
, sort_by_date
);
546 static void sort_size(gpointer data
, guint action
, GtkWidget
*widget
)
548 g_return_if_fail(window_with_focus
!= NULL
);
550 filer_set_sort_fn(window_with_focus
, sort_by_size
);
553 static void hidden(gpointer data
, guint action
, GtkWidget
*widget
)
558 g_return_if_fail(window_with_focus
!= NULL
);
560 filer_set_hidden(window_with_focus
, !window_with_focus
->show_hidden
);
563 static void refresh(gpointer data
, guint action
, GtkWidget
*widget
)
565 g_return_if_fail(window_with_focus
!= NULL
);
568 update_dir(window_with_focus
, TRUE
);
571 static void mount(gpointer data
, guint action
, GtkWidget
*widget
)
573 g_return_if_fail(window_with_focus
!= NULL
);
575 if (window_with_focus
->collection
->number_selected
== 0)
576 collection_target(window_with_focus
->collection
,
577 target_callback
, mount
);
579 action_mount(window_with_focus
, NULL
);
582 static void delete(gpointer data
, guint action
, GtkWidget
*widget
)
584 g_return_if_fail(window_with_focus
!= NULL
);
586 if (window_with_focus
->collection
->number_selected
== 0)
587 collection_target(window_with_focus
->collection
,
588 target_callback
, delete);
590 action_delete(window_with_focus
);
593 static void usage(gpointer data
, guint action
, GtkWidget
*widget
)
595 g_return_if_fail(window_with_focus
!= NULL
);
597 if (window_with_focus
->collection
->number_selected
== 0)
598 collection_target(window_with_focus
->collection
,
599 target_callback
, usage
);
601 action_usage(window_with_focus
);
604 static gboolean
copy_cb(char *initial
, char *path
)
606 char *new_dir
, *slash
;
609 gboolean retval
= TRUE
;
611 slash
= strrchr(path
, '/');
614 report_error("ROX-Filer", "Missing '/' in new pathname");
618 if (access(path
, F_OK
) == 0)
620 report_error("ROX-Filer",
621 "An item with this name already exists");
626 new_dir
= g_malloc(len
+ 1);
627 memcpy(new_dir
, path
, len
);
630 command
= g_string_new(NULL
);
631 g_string_sprintf(command
, "cp -a %s %s", initial
, path
);
632 /* XXX: Use system. In fact, use action! */
634 if (system(command
->str
))
636 g_string_append(command
, " failed!");
637 report_error("ROX-Filer", command
->str
);
641 g_string_free(command
, TRUE
);
643 refresh_dirs(new_dir
);
647 static void copy_item(gpointer data
, guint action
, GtkWidget
*widget
)
649 Collection
*collection
;
651 g_return_if_fail(window_with_focus
!= NULL
);
653 collection
= window_with_focus
->collection
;
654 if (collection
->number_selected
> 1)
656 report_error("ROX-Filer", "You cannot do this to more than "
657 "one item at a time");
660 else if (collection
->number_selected
!= 1)
661 collection_target(collection
, target_callback
, copy_item
);
664 DirItem
*item
= selected_item(collection
);
666 savebox_show(window_with_focus
, "Copy",
667 window_with_focus
->path
,
669 item
->image
, copy_cb
);
673 static gboolean
rename_cb(char *initial
, char *path
)
675 if (rename(initial
, path
))
677 report_error("ROX-Filer: rename()", g_strerror(errno
));
683 static void rename_item(gpointer data
, guint action
, GtkWidget
*widget
)
685 Collection
*collection
;
687 g_return_if_fail(window_with_focus
!= NULL
);
689 collection
= window_with_focus
->collection
;
690 if (collection
->number_selected
> 1)
692 report_error("ROX-Filer", "You cannot do this to more than "
693 "one item at a time");
696 else if (collection
->number_selected
!= 1)
697 collection_target(collection
, target_callback
, rename_item
);
700 DirItem
*item
= selected_item(collection
);
702 savebox_show(window_with_focus
, "Rename",
703 window_with_focus
->path
,
705 item
->image
, rename_cb
);
709 static gboolean
link_cb(char *initial
, char *path
)
711 if (symlink(initial
, path
))
713 report_error("ROX-Filer: symlink()", g_strerror(errno
));
719 static void link_item(gpointer data
, guint action
, GtkWidget
*widget
)
721 Collection
*collection
;
723 g_return_if_fail(window_with_focus
!= NULL
);
725 collection
= window_with_focus
->collection
;
726 if (collection
->number_selected
> 1)
728 report_error("ROX-Filer", "You cannot do this to more than "
729 "one item at a time");
732 else if (collection
->number_selected
!= 1)
733 collection_target(collection
, target_callback
, link_item
);
736 DirItem
*item
= selected_item(collection
);
738 savebox_show(window_with_focus
, "Symlink",
739 window_with_focus
->path
,
741 item
->image
, link_cb
);
745 static void open_file(gpointer data
, guint action
, GtkWidget
*widget
)
747 Collection
*collection
;
749 g_return_if_fail(window_with_focus
!= NULL
);
751 collection
= window_with_focus
->collection
;
752 if (collection
->number_selected
> 1)
754 report_error("ROX-Filer", "You cannot do this to more than "
755 "one item at a time");
758 else if (collection
->number_selected
!= 1)
759 collection_target(collection
, target_callback
, open_file
);
761 filer_openitem(window_with_focus
,
762 selected_item_number(collection
),
763 OPEN_SAME_WINDOW
| OPEN_SHIFT
);
766 /* Got some data from file(1) - stick it in the window. */
767 static void add_file_output(FileStatus
*fs
,
768 gint source
, GdkInputCondition condition
)
774 got
= read(source
, buffer
, sizeof(buffer
) - 1);
778 gtk_input_remove(fs
->input
);
782 delayed_error("ROX-Filer: file(1) says...",
794 gtk_label_get(fs
->label
, &str
);
796 str
= g_strconcat(str
, buffer
, NULL
);
797 gtk_label_set_text(fs
->label
, str
);
801 static void file_info_destroyed(GtkWidget
*widget
, FileStatus
*fs
)
805 gtk_input_remove(fs
->input
);
812 static void show_file_info(gpointer data
, guint action
, GtkWidget
*widget
)
814 GtkWidget
*window
, *table
, *label
, *button
, *frame
;
815 GtkWidget
*file_label
;
820 char *argv
[] = {"file", "-b", NULL
, NULL
};
821 Collection
*collection
;
824 FileStatus
*fs
= NULL
;
827 g_return_if_fail(window_with_focus
!= NULL
);
829 collection
= window_with_focus
->collection
;
830 if (collection
->number_selected
> 1)
832 report_error("ROX-Filer", "You cannot do this to more than "
833 "one item at a time");
836 else if (collection
->number_selected
!= 1)
838 collection_target(collection
, target_callback
, show_file_info
);
841 file
= selected_item(collection
);
842 path
= make_path(window_with_focus
->path
,
843 file
->leafname
)->str
;
844 if (lstat(path
, &info
))
846 delayed_error("ROX-Filer", g_strerror(errno
));
850 gstring
= g_string_new(NULL
);
852 window
= gtk_window_new(GTK_WINDOW_DIALOG
);
853 gtk_window_set_position(GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
854 gtk_container_set_border_width(GTK_CONTAINER(window
), 4);
855 gtk_window_set_title(GTK_WINDOW(window
), path
);
857 table
= gtk_table_new(9, 2, FALSE
);
858 gtk_container_add(GTK_CONTAINER(window
), table
);
859 gtk_table_set_row_spacings(GTK_TABLE(table
), 8);
860 gtk_table_set_col_spacings(GTK_TABLE(table
), 4);
862 label
= gtk_label_new("Owner, group:");
863 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
864 gtk_label_set_justify(GTK_LABEL(label
), GTK_JUSTIFY_RIGHT
);
865 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 0, 1);
866 g_string_sprintf(gstring
, "%s, %s", user_name(info
.st_uid
),
867 group_name(info
.st_gid
));
868 label
= gtk_label_new(gstring
->str
);
869 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
870 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 0, 1);
872 label
= gtk_label_new("Size:");
873 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
874 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 1, 2);
875 if (info
.st_size
>= PRETTY_SIZE_LIMIT
)
877 g_string_sprintf(gstring
, "%s (%ld bytes)",
878 format_size((unsigned long) info
.st_size
),
879 (unsigned long) info
.st_size
);
883 g_string_sprintf(gstring
, "%ld bytes",
884 (unsigned long) info
.st_size
);
886 label
= gtk_label_new(gstring
->str
);
887 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
888 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 1, 2);
890 label
= gtk_label_new("Change time:");
891 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
892 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 2, 3);
893 g_string_sprintf(gstring
, "%s", ctime(&info
.st_ctime
));
894 g_string_truncate(gstring
, gstring
->len
- 1);
895 label
= gtk_label_new(gstring
->str
);
896 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
897 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 2, 3);
899 label
= gtk_label_new("Modify time:");
900 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
901 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 3, 4);
902 g_string_sprintf(gstring
, "%s", ctime(&info
.st_mtime
));
903 g_string_truncate(gstring
, gstring
->len
- 1);
904 label
= gtk_label_new(gstring
->str
);
905 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
906 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 3, 4);
908 label
= gtk_label_new("Access time:");
909 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
910 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 4, 5);
911 g_string_sprintf(gstring
, "%s", ctime(&info
.st_atime
));
912 g_string_truncate(gstring
, gstring
->len
- 1);
913 label
= gtk_label_new(gstring
->str
);
914 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
915 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 4, 5);
917 label
= gtk_label_new("Permissions:");
918 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
919 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 5, 6);
920 label
= gtk_label_new(pretty_permissions(info
.st_mode
));
921 perm
= applicable(info
.st_uid
, info
.st_gid
);
922 gtk_label_set_pattern(GTK_LABEL(label
),
924 perm
== 1 ? " ___ " :
926 gtk_widget_set_style(label
, fixed_style
);
927 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
928 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 5, 6);
930 label
= gtk_label_new("MIME type:");
931 gtk_misc_set_alignment(GTK_MISC(label
), 1, .5);
932 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 0, 1, 6, 7);
935 string
= g_strconcat(file
->mime_type
->media_type
, "/",
936 file
->mime_type
->subtype
, NULL
);
937 label
= gtk_label_new(string
);
941 label
= gtk_label_new("-");
942 gtk_misc_set_alignment(GTK_MISC(label
), 0, .5);
943 gtk_table_attach_defaults(GTK_TABLE(table
), label
, 1, 2, 6, 7);
945 frame
= gtk_frame_new("file(1) says...");
946 gtk_table_attach_defaults(GTK_TABLE(table
), frame
, 0, 2, 7, 8);
947 file_label
= gtk_label_new("<nothing yet>");
948 gtk_misc_set_padding(GTK_MISC(file_label
), 4, 4);
949 gtk_label_set_line_wrap(GTK_LABEL(file_label
), TRUE
);
950 gtk_container_add(GTK_CONTAINER(frame
), file_label
);
952 button
= gtk_button_new_with_label("OK");
953 gtk_window_set_focus(GTK_WINDOW(window
), button
);
954 gtk_table_attach(GTK_TABLE(table
), button
, 0, 2, 8, 9,
955 GTK_EXPAND
| GTK_FILL
| GTK_SHRINK
, 0, 40, 4);
956 gtk_signal_connect_object(GTK_OBJECT(button
), "clicked",
957 gtk_widget_destroy
, GTK_OBJECT(window
));
959 gtk_widget_show_all(window
);
964 g_string_sprintf(gstring
, "pipe(): %s", g_strerror(errno
));
965 g_string_free(gstring
, TRUE
);
971 g_string_sprintf(gstring
, "fork(): %s",
973 gtk_label_set_text(GTK_LABEL(file_label
), gstring
->str
);
974 g_string_free(gstring
, TRUE
);
979 /* We are the child */
981 dup2(file_data
[1], STDOUT_FILENO
);
982 dup2(file_data
[1], STDERR_FILENO
);
988 if (execvp(argv
[0], argv
))
989 fprintf(stderr
, "execvp() error: %s\n",
993 /* We are the parent */
995 fs
= g_new(FileStatus
, 1);
996 fs
->label
= GTK_LABEL(file_label
);
997 fs
->fd
= file_data
[0];
999 fs
->input
= gdk_input_add(fs
->fd
, GDK_INPUT_READ
,
1000 (GdkInputFunction
) add_file_output
, fs
);
1001 gtk_signal_connect(GTK_OBJECT(window
), "destroy",
1002 GTK_SIGNAL_FUNC(file_info_destroyed
), fs
);
1003 g_string_free(gstring
, TRUE
);
1008 static void app_show_help(char *path
)
1013 help_dir
= g_strconcat(path
, "/Help", NULL
);
1015 if (stat(help_dir
, &info
))
1016 delayed_error("Application",
1017 "This is an application directory - you can "
1018 "run it as a program, or open it (hold down "
1019 "Shift while you open it). Most applications provide "
1020 "their own help here, but this one doesn't.");
1022 filer_opendir(help_dir
, PANEL_NO
);
1025 static void help(gpointer data
, guint action
, GtkWidget
*widget
)
1027 Collection
*collection
;
1030 g_return_if_fail(window_with_focus
!= NULL
);
1032 collection
= window_with_focus
->collection
;
1033 if (collection
->number_selected
> 1)
1035 report_error("ROX-Filer", "You cannot do this to more than "
1036 "one item at a time");
1039 else if (collection
->number_selected
!= 1)
1041 collection_target(collection
, target_callback
, help
);
1044 item
= selected_item(collection
);
1045 switch (item
->base_type
)
1048 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
1049 delayed_error("Executable file",
1050 "This is a file with an eXecute bit "
1051 "set - it can be run as a program.");
1053 delayed_error("File",
1054 "This is a data file. Try using the "
1055 "Info menu item to find out more...");
1057 case TYPE_DIRECTORY
:
1058 if (item
->flags
& ITEM_FLAG_APPDIR
)
1060 make_path(window_with_focus
->path
,
1061 item
->leafname
)->str
);
1062 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
1063 delayed_error("Mount point",
1064 "A mount point is a directory which another "
1065 "filing system can be mounted on. Everything "
1066 "on the mounted filesystem then appears to be "
1067 "inside the directory.");
1069 delayed_error("Directory",
1070 "This is a directory. It contains an index to "
1071 "other items - open it to see the list.");
1073 case TYPE_CHAR_DEVICE
:
1074 case TYPE_BLOCK_DEVICE
:
1075 delayed_error("Device file",
1076 "Device files allow you to read from or write "
1077 "to a device driver as though it was an "
1081 delayed_error("Named pipe",
1082 "Pipes allow different programs to "
1083 "communicate. One program writes data to the "
1084 "pipe while another one reads it out again.");
1087 delayed_error("Socket",
1088 "Sockets allow processes to communicate.");
1091 delayed_error("Unknown type",
1092 "I couldn't find out what kind of file this "
1093 "is. Maybe it doesn't exist anymore or you "
1094 "don't have search permission on the directory "
1100 static void select_all(gpointer data
, guint action
, GtkWidget
*widget
)
1102 g_return_if_fail(window_with_focus
!= NULL
);
1104 collection_select_all(window_with_focus
->collection
);
1105 window_with_focus
->temp_item_selected
= FALSE
;
1108 static void clear_selection(gpointer data
, guint action
, GtkWidget
*widget
)
1110 g_return_if_fail(window_with_focus
!= NULL
);
1112 collection_clear_selection(window_with_focus
->collection
);
1113 window_with_focus
->temp_item_selected
= FALSE
;
1116 static void show_options(gpointer data
, guint action
, GtkWidget
*widget
)
1118 g_return_if_fail(window_with_focus
!= NULL
);
1120 options_show(window_with_focus
);
1123 static gboolean
new_directory_cb(char *initial
, char *path
)
1125 if (mkdir(path
, S_IRWXU
| S_IRWXG
| S_IRWXO
))
1127 report_error("mkdir", g_strerror(errno
));
1133 static void new_directory(gpointer data
, guint action
, GtkWidget
*widget
)
1135 g_return_if_fail(window_with_focus
!= NULL
);
1137 savebox_show(window_with_focus
, "Create directory",
1138 window_with_focus
->path
, "NewDir",
1139 default_pixmap
+ TYPE_DIRECTORY
, new_directory_cb
);
1142 static void xterm_here(gpointer data
, guint action
, GtkWidget
*widget
)
1144 char *argv
[] = {NULL
, NULL
};
1146 argv
[0] = xterm_here_value
;
1148 g_return_if_fail(window_with_focus
!= NULL
);
1150 if (!spawn_full(argv
, window_with_focus
->path
))
1151 report_error("ROX-Filer", "Failed to fork() child "
1155 static void open_parent(gpointer data
, guint action
, GtkWidget
*widget
)
1157 g_return_if_fail(window_with_focus
!= NULL
);
1159 filer_opendir(make_path(window_with_focus
->path
, "/..")->str
,
1163 static void open_parent_same(gpointer data
, guint action
, GtkWidget
*widget
)
1165 g_return_if_fail(window_with_focus
!= NULL
);
1167 change_to_parent(window_with_focus
);
1170 static void new_window(gpointer data
, guint action
, GtkWidget
*widget
)
1172 g_return_if_fail(window_with_focus
!= NULL
);
1174 filer_opendir(window_with_focus
->path
, PANEL_NO
);
1177 static void close_window(gpointer data
, guint action
, GtkWidget
*widget
)
1179 g_return_if_fail(window_with_focus
!= NULL
);
1181 gtk_widget_destroy(window_with_focus
->window
);
1184 static void enter_path(gpointer data
, guint action
, GtkWidget
*widget
)
1186 g_return_if_fail(window_with_focus
!= NULL
);
1188 minibuffer_show(window_with_focus
);
1191 static void rox_help(gpointer data
, guint action
, GtkWidget
*widget
)
1193 g_return_if_fail(window_with_focus
!= NULL
);
1195 filer_opendir(make_path(getenv("APP_DIR"), "Help")->str
, PANEL_NO
);
1198 static void open_as_dir(gpointer data
, guint action
, GtkWidget
*widget
)
1200 g_return_if_fail(window_with_focus
!= NULL
);
1202 filer_opendir(window_with_focus
->path
, PANEL_NO
);
1205 static void close_panel(gpointer data
, guint action
, GtkWidget
*widget
)
1207 g_return_if_fail(window_with_focus
!= NULL
);
1209 gtk_widget_destroy(window_with_focus
->window
);