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 /* filer.c - code for handling filer windows */
28 #include <sys/param.h>
35 #include <gdk/gdkkeysyms.h>
36 #include "collection.h"
40 #include "gui_support.h"
50 #include "minibuffer.h"
52 #define ROW_HEIGHT_LARGE 64
53 #define ROW_HEIGHT_SMALL 32
54 #define ROW_HEIGHT_FULL_INFO 44
55 #define SMALL_ICON_HEIGHT 20
56 #define SMALL_ICON_WIDTH 48
57 #define MAX_ICON_HEIGHT 42
58 #define MAX_ICON_WIDTH 48
59 #define PANEL_BORDER 2
60 #define MIN_ITEM_WIDTH 64
62 extern int collection_menu_button
;
63 extern gboolean collection_single_click
;
65 FilerWindow
*window_with_focus
= NULL
;
66 GList
*all_filer_windows
= NULL
;
68 static DisplayStyle last_display_style
= LARGE_ICONS
;
69 static gboolean last_show_hidden
= FALSE
;
70 static int (*last_sort_fn
)(const void *a
, const void *b
) = sort_by_type
;
72 static FilerWindow
*window_with_selection
= NULL
;
75 static guchar
*style_to_name(void);
76 static guchar
*sort_fn_to_name(void);
77 static void update_options_label(void);
79 static GtkWidget
*create_options();
80 static void update_options();
81 static void set_options();
82 static void save_options();
83 static char *filer_single_click(char *data
);
84 static char *filer_menu_on_2(char *data
);
85 static char *filer_new_window_on_1(char *data
);
86 static char *filer_toolbar(char *data
);
87 static char *filer_display_style(char *data
);
88 static char *filer_sort_by(char *data
);
90 static OptionsSection options
=
92 "Filer window options",
99 /* The values correspond to the menu indexes in the option widget */
105 static ToolbarType o_toolbar
= TOOLBAR_NORMAL
;
106 static GtkWidget
*menu_toolbar
;
108 static GtkWidget
*display_label
;
110 static gboolean o_single_click
= FALSE
;
111 static GtkWidget
*toggle_single_click
;
112 static gboolean o_new_window_on_1
= FALSE
; /* Button 1 => New window */
113 static GtkWidget
*toggle_new_window_on_1
;
114 static GtkWidget
*toggle_menu_on_2
;
116 /* Static prototypes */
117 static void attach(FilerWindow
*filer_window
);
118 static void detach(FilerWindow
*filer_window
);
119 static void filer_window_destroyed(GtkWidget
*widget
,
120 FilerWindow
*filer_window
);
121 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
122 int number_selected
, gpointer user_data
);
123 static gint
focus_in(GtkWidget
*widget
,
124 GdkEventFocus
*event
,
125 FilerWindow
*filer_window
);
126 static gint
focus_out(GtkWidget
*widget
,
127 GdkEventFocus
*event
,
128 FilerWindow
*filer_window
);
129 static void add_item(FilerWindow
*filer_window
, DirItem
*item
);
130 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
131 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
132 static void add_button(GtkWidget
*box
, int pixmap
,
133 GtkSignalFunc cb
, FilerWindow
*filer_window
,
134 char *label
, char *tip
);
135 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
);
136 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
137 FilerWindow
*window
);
138 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
);
139 static void draw_large_icon(GtkWidget
*widget
,
143 static void draw_string(GtkWidget
*widget
,
150 static void draw_item_large(GtkWidget
*widget
,
151 CollectionItem
*item
,
153 static void draw_item_small(GtkWidget
*widget
,
154 CollectionItem
*item
,
156 static void draw_item_full_info(GtkWidget
*widget
,
157 CollectionItem
*colitem
,
159 static gboolean
test_point_large(Collection
*collection
,
160 int point_x
, int point_y
,
161 CollectionItem
*item
,
162 int width
, int height
);
163 static gboolean
test_point_small(Collection
*collection
,
164 int point_x
, int point_y
,
165 CollectionItem
*item
,
166 int width
, int height
);
167 static gboolean
test_point_full_info(Collection
*collection
,
168 int point_x
, int point_y
,
169 CollectionItem
*item
,
170 int width
, int height
);
171 static void update_display(Directory
*dir
,
174 FilerWindow
*filer_window
);
175 static void shrink_width(FilerWindow
*filer_window
);
176 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
);
177 static void open_item(Collection
*collection
,
178 gpointer item_data
, int item_number
,
180 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
);
181 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
);
183 static GdkAtom xa_string
;
190 static GdkCursor
*busy_cursor
= NULL
;
191 static GtkTooltips
*tooltips
= NULL
;
195 xa_string
= gdk_atom_intern("STRING", FALSE
);
197 options_sections
= g_slist_prepend(options_sections
, &options
);
198 option_register("filer_new_window_on_1", filer_new_window_on_1
);
199 option_register("filer_menu_on_2", filer_menu_on_2
);
200 option_register("filer_single_click", filer_single_click
);
201 option_register("filer_toolbar", filer_toolbar
);
202 option_register("filer_display_style", filer_display_style
);
203 option_register("filer_sort_by", filer_sort_by
);
205 busy_cursor
= gdk_cursor_new(GDK_WATCH
);
207 tooltips
= gtk_tooltips_new();
210 static gboolean
if_deleted(gpointer item
, gpointer removed
)
212 int i
= ((GPtrArray
*) removed
)->len
;
213 DirItem
**r
= (DirItem
**) ((GPtrArray
*) removed
)->pdata
;
214 char *leafname
= ((DirItem
*) item
)->leafname
;
218 if (strcmp(leafname
, r
[i
]->leafname
) == 0)
225 static void update_item(FilerWindow
*filer_window
, DirItem
*item
)
228 char *leafname
= item
->leafname
;
230 if (leafname
[0] == '.')
232 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
233 || (leafname
[1] == '.' && leafname
[2] == '\0'))
237 i
= collection_find_item(filer_window
->collection
, item
, dir_item_cmp
);
240 collection_draw_item(filer_window
->collection
, i
, TRUE
);
242 g_warning("Failed to find '%s'\n", item
->leafname
);
245 static void update_display(Directory
*dir
,
248 FilerWindow
*filer_window
)
251 int cursor
= filer_window
->collection
->cursor_item
;
253 Collection
*collection
= filer_window
->collection
;
258 as
= filer_window
->auto_select
;
260 for (i
= 0; i
< items
->len
; i
++)
262 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
264 add_item(filer_window
, item
);
266 if (cursor
!= -1 || !as
)
269 if (strcmp(as
, item
->leafname
) != 0)
272 cursor
= collection
->number_of_items
- 1;
273 if (filer_window
->had_cursor
)
275 collection_set_cursor_item(collection
,
277 filer_window
->mini_cursor_base
= cursor
;
280 collection_wink_item(collection
,
284 collection_qsort(filer_window
->collection
,
285 filer_window
->sort_fn
);
288 collection_delete_if(filer_window
->collection
,
293 if (filer_window
->window
->window
)
294 gdk_window_set_cursor(
295 filer_window
->window
->window
,
297 shrink_width(filer_window
);
298 if (filer_window
->had_cursor
&&
299 collection
->cursor_item
== -1)
301 collection_set_cursor_item(collection
, 0);
302 filer_window
->had_cursor
= FALSE
;
306 for (i
= 0; i
< items
->len
; i
++)
308 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
310 update_item(filer_window
, item
);
312 collection_qsort(filer_window
->collection
,
313 filer_window
->sort_fn
);
318 static void attach(FilerWindow
*filer_window
)
320 gdk_window_set_cursor(filer_window
->window
->window
, busy_cursor
);
321 collection_clear(filer_window
->collection
);
322 dir_attach(filer_window
->directory
, (DirCallback
) update_display
,
326 static void detach(FilerWindow
*filer_window
)
328 g_return_if_fail(filer_window
->directory
!= NULL
);
330 dir_detach(filer_window
->directory
,
331 (DirCallback
) update_display
, filer_window
);
332 g_fscache_data_unref(dir_cache
, filer_window
->directory
);
333 filer_window
->directory
= NULL
;
336 static void filer_window_destroyed(GtkWidget
*widget
,
337 FilerWindow
*filer_window
)
339 all_filer_windows
= g_list_remove(all_filer_windows
, filer_window
);
341 if (window_with_selection
== filer_window
)
342 window_with_selection
= NULL
;
343 if (window_with_focus
== filer_window
)
344 window_with_focus
= NULL
;
346 if (filer_window
->directory
)
347 detach(filer_window
);
349 g_free(filer_window
->auto_select
);
350 g_free(filer_window
->path
);
351 g_free(filer_window
);
353 if (--number_of_windows
< 1)
357 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
)
359 int pix_width
= item
->image
->width
;
361 switch (filer_window
->display_style
)
364 return MAX_ICON_WIDTH
+ 12 +
365 MAX(item
->details_width
, item
->name_width
);
367 return SMALL_ICON_WIDTH
+ 12 + item
->name_width
;
369 return MAX(pix_width
, item
->name_width
) + 4;
373 /* Add a single object to a directory display */
374 static void add_item(FilerWindow
*filer_window
, DirItem
*item
)
376 char *leafname
= item
->leafname
;
379 if (leafname
[0] == '.')
381 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
382 || (leafname
[1] == '.' && leafname
[2] == '\0'))
386 item_width
= calc_width(filer_window
, item
);
387 if (item_width
> filer_window
->collection
->item_width
)
388 collection_set_item_size(filer_window
->collection
,
390 filer_window
->collection
->item_height
);
391 collection_insert(filer_window
->collection
, item
);
394 /* Is a point inside an item? */
395 static gboolean
test_point_large(Collection
*collection
,
396 int point_x
, int point_y
,
397 CollectionItem
*colitem
,
398 int width
, int height
)
400 DirItem
*item
= (DirItem
*) colitem
->data
;
401 int text_height
= item_font
->ascent
+ item_font
->descent
;
402 MaskedPixmap
*image
= item
->image
;
403 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
404 int image_width
= (image
->width
>> 1) + 2;
405 int text_width
= (item
->name_width
>> 1) + 2;
408 if (point_y
< image_y
)
409 return FALSE
; /* Too high up (don't worry about too low) */
411 if (point_y
<= image_y
+ image
->height
+ 2)
412 x_limit
= image_width
;
413 else if (point_y
> height
- text_height
- 2)
414 x_limit
= text_width
;
416 x_limit
= MIN(image_width
, text_width
);
418 return ABS(point_x
- (width
>> 1)) < x_limit
;
421 static gboolean
test_point_full_info(Collection
*collection
,
422 int point_x
, int point_y
,
423 CollectionItem
*colitem
,
424 int width
, int height
)
426 DirItem
*item
= (DirItem
*) colitem
->data
;
427 MaskedPixmap
*image
= item
->image
;
428 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
430 - fixed_font
->descent
- 2 - fixed_font
->ascent
;
432 if (point_x
< image
->width
+ 2)
433 return point_x
> 2 && point_y
> image_y
;
435 point_x
-= MAX_ICON_WIDTH
+ 8;
437 if (point_y
>= low_top
)
438 return point_x
< item
->details_width
;
439 if (point_y
>= low_top
- item_font
->ascent
- item_font
->descent
)
440 return point_x
< item
->name_width
;
444 static gboolean
test_point_small(Collection
*collection
,
445 int point_x
, int point_y
,
446 CollectionItem
*colitem
,
447 int width
, int height
)
449 DirItem
*item
= (DirItem
*) colitem
->data
;
450 MaskedPixmap
*image
= item
->image
;
451 int image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
453 - fixed_font
->descent
- 2 - item_font
->ascent
;
454 int iwidth
= MIN(SMALL_ICON_WIDTH
, image
->width
);
456 if (point_x
< iwidth
+ 2)
457 return point_x
> 2 && point_y
> image_y
;
459 point_x
-= SMALL_ICON_WIDTH
+ 4;
461 if (point_y
>= low_top
)
462 return point_x
< item
->name_width
;
466 static void draw_small_icon(GtkWidget
*widget
,
471 MaskedPixmap
*image
= item
->image
;
472 int width
= MIN(image
->width
, SMALL_ICON_WIDTH
);
473 int height
= MIN(image
->height
, SMALL_ICON_HEIGHT
);
474 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
476 GdkGC
*gc
= selected
? widget
->style
->white_gc
477 : widget
->style
->black_gc
;
481 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
483 image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
484 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
485 gdk_draw_pixmap(widget
->window
, gc
,
487 0, 0, /* Source x,y */
488 image_x
, area
->y
+ image_y
, /* Dest x,y */
493 gdk_gc_set_function(gc
, GDK_INVERT
);
494 gdk_draw_rectangle(widget
->window
,
496 TRUE
, image_x
, area
->y
+ image_y
,
498 gdk_gc_set_function(gc
, GDK_COPY
);
501 if (item
->flags
& ITEM_FLAG_SYMLINK
)
503 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
504 gdk_gc_set_clip_mask(gc
,
505 default_pixmap
[TYPE_SYMLINK
].mask
);
506 gdk_draw_pixmap(widget
->window
, gc
,
507 default_pixmap
[TYPE_SYMLINK
].pixmap
,
508 0, 0, /* Source x,y */
509 image_x
, area
->y
+ 8, /* Dest x,y */
512 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
514 int type
= item
->flags
& ITEM_FLAG_MOUNTED
517 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
518 gdk_gc_set_clip_mask(gc
,
519 default_pixmap
[type
].mask
);
520 gdk_draw_pixmap(widget
->window
, gc
,
521 default_pixmap
[type
].pixmap
,
522 0, 0, /* Source x,y */
523 image_x
, area
->y
+ 8, /* Dest x,y */
527 gdk_gc_set_clip_mask(gc
, NULL
);
528 gdk_gc_set_clip_origin(gc
, 0, 0);
531 static void draw_large_icon(GtkWidget
*widget
,
536 MaskedPixmap
*image
= item
->image
;
537 int width
= MIN(image
->width
, MAX_ICON_WIDTH
);
538 int height
= MIN(image
->height
, MAX_ICON_WIDTH
);
539 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
541 GdkGC
*gc
= selected
? widget
->style
->white_gc
542 : widget
->style
->black_gc
;
544 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
546 image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
547 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
548 gdk_draw_pixmap(widget
->window
, gc
,
550 0, 0, /* Source x,y */
551 image_x
, area
->y
+ image_y
, /* Dest x,y */
556 gdk_gc_set_function(gc
, GDK_INVERT
);
557 gdk_draw_rectangle(widget
->window
,
559 TRUE
, image_x
, area
->y
+ image_y
,
561 gdk_gc_set_function(gc
, GDK_COPY
);
564 if (item
->flags
& ITEM_FLAG_SYMLINK
)
566 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
567 gdk_gc_set_clip_mask(gc
,
568 default_pixmap
[TYPE_SYMLINK
].mask
);
569 gdk_draw_pixmap(widget
->window
, gc
,
570 default_pixmap
[TYPE_SYMLINK
].pixmap
,
571 0, 0, /* Source x,y */
572 image_x
, area
->y
+ 8, /* Dest x,y */
575 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
577 int type
= item
->flags
& ITEM_FLAG_MOUNTED
580 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
581 gdk_gc_set_clip_mask(gc
,
582 default_pixmap
[type
].mask
);
583 gdk_draw_pixmap(widget
->window
, gc
,
584 default_pixmap
[type
].pixmap
,
585 0, 0, /* Source x,y */
586 image_x
, area
->y
+ 8, /* Dest x,y */
590 gdk_gc_set_clip_mask(gc
, NULL
);
591 gdk_gc_set_clip_origin(gc
, 0, 0);
594 static void draw_string(GtkWidget
*widget
,
602 int text_height
= font
->ascent
+ font
->descent
;
605 gtk_paint_flat_box(widget
->style
, widget
->window
,
606 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
607 NULL
, widget
, "text",
612 gdk_draw_text(widget
->window
,
614 selected
? widget
->style
->white_gc
615 : widget
->style
->black_gc
,
617 string
, strlen(string
));
620 /* Return a string (valid until next call) giving details
623 char *details(DirItem
*item
)
625 mode_t m
= item
->mode
;
626 static GString
*buf
= NULL
;
627 static char time_buf
[32];
629 buf
= g_string_new(NULL
);
631 if (strftime(time_buf
, sizeof(time_buf
),
632 "%d-%b-%Y %T", localtime(&item
->mtime
)) == 0)
635 g_string_sprintf(buf
, "%s%s %s %s",
636 item
->flags
& ITEM_FLAG_APPDIR
? "App " :
637 S_ISDIR(m
) ? "Dir " :
638 S_ISCHR(m
) ? "Char " :
639 S_ISBLK(m
) ? "Blck " :
640 S_ISLNK(m
) ? "Link " :
641 S_ISSOCK(m
) ? "Sock " :
642 S_ISFIFO(m
) ? "Pipe " : "File ",
643 pretty_permissions(m
),
644 format_size_aligned(item
->size
),
649 static void draw_item_full_info(GtkWidget
*widget
,
650 CollectionItem
*colitem
,
653 DirItem
*item
= (DirItem
*) colitem
->data
;
654 MaskedPixmap
*image
= item
->image
;
655 int text_x
= area
->x
+ MAX_ICON_WIDTH
+ 8;
656 int low_text_y
= area
->y
+ area
->height
- fixed_font
->descent
- 2;
657 gboolean selected
= colitem
->selected
;
658 GdkRectangle pic_area
;
660 pic_area
.x
= area
->x
;
661 pic_area
.y
= area
->y
;
662 pic_area
.width
= image
->width
+ 8;
663 pic_area
.height
= area
->height
;
665 draw_large_icon(widget
, &pic_area
, item
, selected
);
671 low_text_y
- item_font
->descent
- fixed_font
->ascent
,
680 gdk_draw_rectangle(widget
->window
,
681 selected
? widget
->style
->white_gc
682 : widget
->style
->black_gc
,
684 text_x
- 1 + fixed_width
*
685 (5 + 4 * applicable(item
->uid
, item
->gid
)),
686 low_text_y
+ fixed_font
->descent
- 1,
687 fixed_width
* 3 + 1, 1);
690 static void draw_item_small(GtkWidget
*widget
,
691 CollectionItem
*colitem
,
694 DirItem
*item
= (DirItem
*) colitem
->data
;
695 int text_x
= area
->x
+ SMALL_ICON_WIDTH
+ 4;
696 int low_text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
697 gboolean selected
= colitem
->selected
;
698 GdkRectangle pic_area
;
700 pic_area
.x
= area
->x
;
701 pic_area
.y
= area
->y
;
702 pic_area
.width
= SMALL_ICON_WIDTH
;
703 pic_area
.height
= SMALL_ICON_HEIGHT
;
705 draw_small_icon(widget
, &pic_area
, item
, selected
);
716 static void draw_item_large(GtkWidget
*widget
,
717 CollectionItem
*colitem
,
720 DirItem
*item
= (DirItem
*) colitem
->data
;
721 int text_x
= area
->x
+ ((area
->width
- item
->name_width
) >> 1);
722 int text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
723 gboolean selected
= colitem
->selected
;
725 draw_large_icon(widget
, area
, item
, selected
);
730 text_x
, text_y
, item
->name_width
,
734 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
735 int item
, gpointer user_data
)
737 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
740 /* Returns TRUE iff the directory still exits. */
741 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
)
745 g_return_val_if_fail(filer_window
!= NULL
, FALSE
);
747 /* We do a fresh lookup (rather than update) because the inode may
750 dir
= g_fscache_lookup(dir_cache
, filer_window
->path
);
754 delayed_error("ROX-Filer", "Directory missing/deleted");
755 gtk_widget_destroy(filer_window
->window
);
758 if (dir
== filer_window
->directory
)
759 g_fscache_data_unref(dir_cache
, dir
);
762 detach(filer_window
);
763 filer_window
->directory
= dir
;
764 attach(filer_window
);
770 /* Another app has grabbed the selection */
771 static gint
collection_lose_selection(GtkWidget
*widget
,
772 GdkEventSelection
*event
)
774 if (window_with_selection
&&
775 window_with_selection
->collection
== COLLECTION(widget
))
777 FilerWindow
*filer_window
= window_with_selection
;
778 window_with_selection
= NULL
;
779 collection_clear_selection(filer_window
->collection
);
785 /* Someone wants us to send them the selection */
786 static void selection_get(GtkWidget
*widget
,
787 GtkSelectionData
*selection_data
,
792 GString
*reply
, *header
;
793 FilerWindow
*filer_window
;
795 Collection
*collection
;
797 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
799 reply
= g_string_new(NULL
);
800 header
= g_string_new(NULL
);
805 g_string_sprintf(header
, " %s",
806 make_path(filer_window
->path
, "")->str
);
808 case TARGET_URI_LIST
:
809 g_string_sprintf(header
, " file://%s%s",
811 make_path(filer_window
->path
, "")->str
);
815 collection
= filer_window
->collection
;
816 for (i
= 0; i
< collection
->number_of_items
; i
++)
818 if (collection
->items
[i
].selected
)
821 (DirItem
*) collection
->items
[i
].data
;
823 g_string_append(reply
, header
->str
);
824 g_string_append(reply
, item
->leafname
);
827 /* This works, but I don't think I like it... */
828 /* g_string_append_c(reply, ' '); */
830 gtk_selection_data_set(selection_data
, xa_string
,
831 8, reply
->str
+ 1, reply
->len
- 1);
832 g_string_free(reply
, TRUE
);
833 g_string_free(header
, TRUE
);
836 /* No items are now selected. This might be because another app claimed
837 * the selection or because the user unselected all the items.
839 static void lose_selection(Collection
*collection
,
843 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
845 if (window_with_selection
== filer_window
)
847 window_with_selection
= NULL
;
848 gtk_selection_owner_set(NULL
,
849 GDK_SELECTION_PRIMARY
,
854 static void gain_selection(Collection
*collection
,
858 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
860 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
861 GDK_SELECTION_PRIMARY
,
864 window_with_selection
= filer_window
;
867 collection_clear_selection(filer_window
->collection
);
870 int sort_by_name(const void *item1
, const void *item2
)
872 return strcmp((*((DirItem
**)item1
))->leafname
,
873 (*((DirItem
**)item2
))->leafname
);
876 int sort_by_type(const void *item1
, const void *item2
)
878 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
879 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
882 int diff
= i1
->base_type
- i2
->base_type
;
885 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
886 - (i2
->flags
& ITEM_FLAG_APPDIR
);
888 return diff
> 0 ? 1 : -1;
895 diff
= strcmp(m1
->media_type
, m2
->media_type
);
897 diff
= strcmp(m1
->subtype
, m2
->subtype
);
905 return diff
> 0 ? 1 : -1;
907 return sort_by_name(item1
, item2
);
910 int sort_by_date(const void *item1
, const void *item2
)
912 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
913 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
915 return i1
->mtime
> i2
->mtime
? -1 :
916 i1
->mtime
< i2
->mtime
? 1 :
917 sort_by_name(item1
, item2
);
920 int sort_by_size(const void *item1
, const void *item2
)
922 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
923 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
925 return i1
->size
> i2
->size
? -1 :
926 i1
->size
< i2
->size
? 1 :
927 sort_by_name(item1
, item2
);
930 static void open_item(Collection
*collection
,
931 gpointer item_data
, int item_number
,
934 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
936 GdkEventButton
*bevent
;
940 event
= (GdkEvent
*) gtk_get_current_event();
942 bevent
= (GdkEventButton
*) event
;
943 kevent
= (GdkEventKey
*) event
;
947 case GDK_2BUTTON_PRESS
:
948 case GDK_BUTTON_PRESS
:
949 case GDK_BUTTON_RELEASE
:
950 if (bevent
->state
& GDK_SHIFT_MASK
)
953 if (o_new_window_on_1
^ (bevent
->button
== 1))
954 flags
|= OPEN_SAME_WINDOW
;
956 if (bevent
->button
!= 1)
957 flags
|= OPEN_CLOSE_WINDOW
;
959 if (o_single_click
== FALSE
&&
960 (bevent
->state
& GDK_CONTROL_MASK
) != 0)
961 flags
^= OPEN_SAME_WINDOW
| OPEN_CLOSE_WINDOW
;
964 flags
|= OPEN_SAME_WINDOW
;
965 if (kevent
->state
& GDK_SHIFT_MASK
)
972 filer_openitem(filer_window
, item_number
, flags
);
975 /* Return the full path to the directory containing object 'path'.
976 * Relative paths are resolved from the filerwindow's path.
978 static void follow_symlink(FilerWindow
*filer_window
, char *path
,
979 gboolean same_window
)
985 path
= make_path(filer_window
->path
, path
)->str
;
987 real
= pathdup(path
);
988 slash
= strrchr(real
, '/');
992 delayed_error("ROX-Filer",
993 "Broken symlink (or you don't have permission "
1005 if (filer_window
->panel_type
|| !same_window
)
1009 new = filer_opendir(new_dir
, PANEL_NO
);
1010 set_autoselect(new, slash
+ 1);
1013 filer_change_to(filer_window
, new_dir
, slash
+ 1);
1018 void filer_openitem(FilerWindow
*filer_window
, int item_number
, OpenFlags flags
)
1020 gboolean shift
= (flags
& OPEN_SHIFT
) != 0;
1021 gboolean close_mini
= flags
& OPEN_FROM_MINI
;
1022 gboolean same_window
= (flags
& OPEN_SAME_WINDOW
) != 0
1023 && !filer_window
->panel_type
;
1024 gboolean close_window
= (flags
& OPEN_CLOSE_WINDOW
) != 0
1025 && !filer_window
->panel_type
;
1028 DirItem
*item
= (DirItem
*)
1029 filer_window
->collection
->items
[item_number
].data
;
1030 gboolean wink
= TRUE
, destroy
= FALSE
;
1032 widget
= filer_window
->window
;
1033 full_path
= make_path(filer_window
->path
,
1034 item
->leafname
)->str
;
1036 if (item
->flags
& ITEM_FLAG_SYMLINK
&& shift
)
1038 char path
[MAXPATHLEN
+ 1];
1041 got
= readlink(make_path(filer_window
->path
,
1042 item
->leafname
)->str
,
1045 delayed_error("ROX-Filer", g_strerror(errno
));
1048 g_return_if_fail(got
<= MAXPATHLEN
);
1051 follow_symlink(filer_window
, path
,
1052 flags
& OPEN_SAME_WINDOW
);
1057 switch (item
->base_type
)
1059 case TYPE_DIRECTORY
:
1060 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
1062 run_app(make_path(filer_window
->path
,
1063 item
->leafname
)->str
);
1069 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& shift
)
1071 action_mount(filer_window
, item
);
1072 if (item
->flags
& ITEM_FLAG_MOUNTED
)
1079 filer_change_to(filer_window
, full_path
, NULL
);
1083 filer_opendir(full_path
, PANEL_NO
);
1086 if ((item
->flags
& ITEM_FLAG_EXEC_FILE
) && !shift
)
1088 char *argv
[] = {NULL
, NULL
};
1090 argv
[0] = full_path
;
1092 if (spawn_full(argv
, filer_window
->path
))
1098 report_error("ROX-Filer",
1099 "Failed to fork() child");
1104 MIME_type
*type
= shift
? &text_plain
1107 g_return_if_fail(type
!= NULL
);
1109 if (type_open(full_path
, type
))
1116 message
= g_string_new(NULL
);
1117 g_string_sprintf(message
, "No open "
1118 "action specified for files of "
1119 "this type (%s/%s)",
1122 report_error("ROX-Filer", message
->str
);
1123 g_string_free(message
, TRUE
);
1128 report_error("open_item",
1129 "I don't know how to open that");
1134 gtk_widget_destroy(filer_window
->window
);
1138 collection_wink_item(filer_window
->collection
,
1141 minibuffer_hide(filer_window
);
1145 static gint
pointer_in(GtkWidget
*widget
,
1146 GdkEventCrossing
*event
,
1147 FilerWindow
*filer_window
)
1149 may_rescan(filer_window
, TRUE
);
1153 static gint
focus_in(GtkWidget
*widget
,
1154 GdkEventFocus
*event
,
1155 FilerWindow
*filer_window
)
1157 window_with_focus
= filer_window
;
1162 static gint
focus_out(GtkWidget
*widget
,
1163 GdkEventFocus
*event
,
1164 FilerWindow
*filer_window
)
1166 /* TODO: Shade the cursor */
1171 /* Handle keys that can't be bound with the menu */
1172 static gint
key_press_event(GtkWidget
*widget
,
1174 FilerWindow
*filer_window
)
1176 switch (event
->keyval
)
1179 change_to_parent(filer_window
);
1188 static void toolbar_refresh_clicked(GtkWidget
*widget
,
1189 FilerWindow
*filer_window
)
1192 update_dir(filer_window
, TRUE
);
1195 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1197 filer_change_to(filer_window
, getenv("HOME"), NULL
);
1200 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1202 change_to_parent(filer_window
);
1205 void change_to_parent(FilerWindow
*filer_window
)
1210 if (filer_window
->path
[0] == '/' && filer_window
->path
[1] == '\0')
1211 return; /* Already in the root */
1213 copy
= g_strdup(filer_window
->path
);
1214 slash
= strrchr(copy
, '/');
1219 filer_change_to(filer_window
,
1224 g_warning("No / in directory path!\n");
1230 /* Make filer_window display path. When finished, highlight item 'from', or
1231 * the first item if from is NULL. If there is currently no cursor then
1232 * simply wink 'from' (if not NULL).
1234 void filer_change_to(FilerWindow
*filer_window
, char *path
, char *from
)
1238 from_dup
= from
&& *from
? g_strdup(from
) : NULL
;
1240 detach(filer_window
);
1241 g_free(filer_window
->path
);
1242 filer_window
->path
= pathdup(path
);
1244 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1245 filer_window
->path
);
1246 if (filer_window
->directory
)
1248 g_free(filer_window
->auto_select
);
1249 filer_window
->had_cursor
=
1250 filer_window
->collection
->cursor_item
!= -1
1251 || filer_window
->had_cursor
;
1252 filer_window
->auto_select
= from_dup
;
1254 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
1255 filer_window
->path
);
1256 collection_set_cursor_item(filer_window
->collection
, -1);
1257 attach(filer_window
);
1259 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer
))
1260 gtk_idle_add((GtkFunction
) minibuffer_show_cb
,
1268 error
= g_strdup_printf("Directory '%s' is not accessible.",
1270 delayed_error("ROX-Filer", error
);
1272 gtk_widget_destroy(filer_window
->window
);
1276 int selected_item_number(Collection
*collection
)
1280 g_return_val_if_fail(collection
!= NULL
, -1);
1281 g_return_val_if_fail(IS_COLLECTION(collection
), -1);
1282 g_return_val_if_fail(collection
->number_selected
== 1, -1);
1284 for (i
= 0; i
< collection
->number_of_items
; i
++)
1285 if (collection
->items
[i
].selected
)
1288 g_warning("selected_item: number_selected is wrong\n");
1293 DirItem
*selected_item(Collection
*collection
)
1297 item
= selected_item_number(collection
);
1300 return (DirItem
*) collection
->items
[item
].data
;
1304 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
1305 FilerWindow
*window
)
1307 /* TODO: We can open lots of these - very irritating! */
1308 return get_choice("Close panel?",
1309 "You have tried to close a panel via the window "
1310 "manager - I usually find that this is accidental... "
1312 2, "Remove", "Cancel") != 0;
1315 /* Make the items as narrow as possible */
1316 static void shrink_width(FilerWindow
*filer_window
)
1319 Collection
*col
= filer_window
->collection
;
1320 int width
= MIN_ITEM_WIDTH
;
1322 DisplayStyle style
= filer_window
->display_style
;
1325 text_height
= item_font
->ascent
+ item_font
->descent
;
1327 for (i
= 0; i
< col
->number_of_items
; i
++)
1329 this_width
= calc_width(filer_window
,
1330 (DirItem
*) col
->items
[i
].data
);
1331 if (this_width
> width
)
1335 collection_set_item_size(filer_window
->collection
,
1337 style
== FULL_INFO
? MAX_ICON_HEIGHT
+ 4 :
1338 style
== SMALL_ICONS
? MAX(text_height
, SMALL_ICON_HEIGHT
) + 4
1339 : text_height
+ MAX_ICON_HEIGHT
+ 8);
1342 void filer_set_sort_fn(FilerWindow
*filer_window
,
1343 int (*fn
)(const void *a
, const void *b
))
1345 if (filer_window
->sort_fn
== fn
)
1348 filer_window
->sort_fn
= fn
;
1351 collection_qsort(filer_window
->collection
,
1352 filer_window
->sort_fn
);
1354 update_options_label();
1357 void filer_style_set(FilerWindow
*filer_window
, DisplayStyle style
)
1359 if (filer_window
->display_style
== style
)
1362 if (filer_window
->panel_type
)
1363 style
= LARGE_ICONS
;
1365 last_display_style
= style
;
1367 filer_window
->display_style
= style
;
1372 collection_set_functions(filer_window
->collection
,
1373 draw_item_small
, test_point_small
);
1376 collection_set_functions(filer_window
->collection
,
1377 draw_item_full_info
, test_point_full_info
);
1380 collection_set_functions(filer_window
->collection
,
1381 draw_item_large
, test_point_large
);
1385 shrink_width(filer_window
);
1387 update_options_label();
1390 FilerWindow
*filer_opendir(char *path
, PanelType panel_type
)
1392 GtkWidget
*hbox
, *scrollbar
, *collection
;
1393 FilerWindow
*filer_window
;
1394 GtkTargetEntry target_table
[] =
1396 {"text/uri-list", 0, TARGET_URI_LIST
},
1397 {"STRING", 0, TARGET_STRING
},
1400 filer_window
= g_new(FilerWindow
, 1);
1401 filer_window
->minibuffer
= NULL
;
1402 filer_window
->path
= pathdup(path
);
1403 filer_window
->had_cursor
= FALSE
;
1404 filer_window
->auto_select
= NULL
;
1406 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1407 filer_window
->path
);
1408 if (!filer_window
->directory
)
1412 error
= g_strdup_printf("Directory '%s' not found.", path
);
1413 delayed_error("ROX-Filer", error
);
1415 g_free(filer_window
->path
);
1416 g_free(filer_window
);
1420 filer_window
->show_hidden
= last_show_hidden
;
1421 filer_window
->panel_type
= panel_type
;
1422 filer_window
->temp_item_selected
= FALSE
;
1423 filer_window
->sort_fn
= last_sort_fn
;
1424 filer_window
->flags
= (FilerFlags
) 0;
1425 filer_window
->display_style
= UNKNOWN_STYLE
;
1427 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
1428 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
1429 filer_window
->path
);
1431 collection
= collection_new(NULL
);
1432 gtk_object_set_data(GTK_OBJECT(collection
),
1433 "filer_window", filer_window
);
1434 filer_window
->collection
= COLLECTION(collection
);
1436 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
1437 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1438 "enter-notify-event",
1439 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
1440 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
1441 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
1442 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
1443 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
1444 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
1445 filer_window_destroyed
, filer_window
);
1447 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
1448 open_item
, filer_window
);
1449 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
1450 show_menu
, filer_window
);
1451 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
1452 gain_selection
, filer_window
);
1453 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
1454 lose_selection
, filer_window
);
1455 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
1456 drag_selection
, filer_window
);
1457 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
1458 drag_data_get
, filer_window
);
1459 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
1460 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
1461 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
1462 GTK_SIGNAL_FUNC(selection_get
), NULL
);
1463 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
1465 sizeof(target_table
) / sizeof(*target_table
));
1467 filer_style_set(filer_window
, last_display_style
);
1468 drag_set_dest(collection
);
1472 int swidth
, sheight
, iwidth
, iheight
;
1473 GtkWidget
*frame
, *win
= filer_window
->window
;
1475 gtk_window_set_wmclass(GTK_WINDOW(win
), "ROX-Panel",
1477 collection_set_panel(filer_window
->collection
, TRUE
);
1478 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1480 GTK_SIGNAL_FUNC(filer_confirm_close
),
1483 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
1484 iwidth
= filer_window
->collection
->item_width
;
1485 iheight
= filer_window
->collection
->item_height
;
1488 int height
= iheight
+ PANEL_BORDER
;
1489 int y
= panel_type
== PANEL_TOP
1491 : sheight
- height
- PANEL_BORDER
;
1493 gtk_widget_set_usize(collection
, swidth
, height
);
1494 gtk_widget_set_uposition(win
, 0, y
);
1497 frame
= gtk_frame_new(NULL
);
1498 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1499 gtk_container_add(GTK_CONTAINER(frame
), collection
);
1500 gtk_container_add(GTK_CONTAINER(win
), frame
);
1502 gtk_widget_show_all(frame
);
1503 gtk_widget_realize(win
);
1504 if (override_redirect
)
1505 gdk_window_set_override_redirect(win
->window
, TRUE
);
1506 make_panel_window(win
->window
);
1511 int col_height
= ROW_HEIGHT_LARGE
* 3;
1513 gtk_signal_connect(GTK_OBJECT(collection
),
1515 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
1516 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
1517 filer_window
->display_style
== LARGE_ICONS
? 400 : 512,
1518 o_toolbar
== TOOLBAR_NONE
? col_height
:
1519 o_toolbar
== TOOLBAR_NORMAL
? col_height
+ 24 :
1522 hbox
= gtk_hbox_new(FALSE
, 0);
1523 gtk_container_add(GTK_CONTAINER(filer_window
->window
),
1526 vbox
= gtk_vbox_new(FALSE
, 0);
1527 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, TRUE
, TRUE
, 0);
1529 if (o_toolbar
!= TOOLBAR_NONE
)
1533 toolbar
= create_toolbar(filer_window
);
1534 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
,
1536 gtk_widget_show_all(toolbar
);
1539 gtk_box_pack_start(GTK_BOX(vbox
), collection
, TRUE
, TRUE
, 0);
1541 filer_window
->minibuffer
= create_minibuffer(filer_window
);
1542 gtk_box_pack_start(GTK_BOX(vbox
), filer_window
->minibuffer
,
1545 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
1546 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
1547 gtk_accel_group_attach(filer_keys
,
1548 GTK_OBJECT(filer_window
->window
));
1549 gtk_window_set_focus(GTK_WINDOW(filer_window
->window
),
1552 gtk_widget_show(hbox
);
1553 gtk_widget_show(vbox
);
1554 gtk_widget_show(scrollbar
);
1555 gtk_widget_show(collection
);
1558 number_of_windows
++;
1559 gtk_widget_show(filer_window
->window
);
1560 attach(filer_window
);
1562 all_filer_windows
= g_list_prepend(all_filer_windows
, filer_window
);
1564 return filer_window
;
1567 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
)
1569 GtkWidget
*frame
, *box
;
1571 if (o_toolbar
== TOOLBAR_GNOME
)
1573 frame
= gtk_handle_box_new();
1574 box
= gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL
,
1576 gtk_container_set_border_width(GTK_CONTAINER(box
), 2);
1577 gtk_toolbar_set_space_style(GTK_TOOLBAR(box
),
1578 GTK_TOOLBAR_SPACE_LINE
);
1579 gtk_toolbar_set_button_relief(GTK_TOOLBAR(box
),
1584 frame
= gtk_frame_new(NULL
);
1585 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1587 box
= gtk_hbutton_box_new();
1588 gtk_button_box_set_child_size_default(16, 16);
1589 gtk_hbutton_box_set_spacing_default(2);
1590 gtk_button_box_set_layout(GTK_BUTTON_BOX(box
),
1591 GTK_BUTTONBOX_START
);
1594 gtk_container_add(GTK_CONTAINER(frame
), box
);
1596 add_button(box
, TOOLBAR_UP_ICON
,
1597 GTK_SIGNAL_FUNC(toolbar_up_clicked
),
1599 "Up", "Change to parent directory");
1600 add_button(box
, TOOLBAR_HOME_ICON
,
1601 GTK_SIGNAL_FUNC(toolbar_home_clicked
),
1603 "Home", "Change to home directory");
1604 add_button(box
, TOOLBAR_REFRESH_ICON
,
1605 GTK_SIGNAL_FUNC(toolbar_refresh_clicked
),
1607 "Rescan", "Rescan directory contents");
1612 static void add_button(GtkWidget
*box
, int pixmap
,
1613 GtkSignalFunc cb
, FilerWindow
*filer_window
,
1614 char *label
, char *tip
)
1616 GtkWidget
*button
, *icon
;
1618 icon
= gtk_pixmap_new(default_pixmap
[pixmap
].pixmap
,
1619 default_pixmap
[pixmap
].mask
);
1621 if (o_toolbar
== TOOLBAR_GNOME
)
1623 gtk_toolbar_append_element(GTK_TOOLBAR(box
),
1624 GTK_TOOLBAR_CHILD_BUTTON
,
1633 button
= gtk_button_new();
1634 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
1636 gtk_container_add(GTK_CONTAINER(button
), icon
);
1637 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1640 gtk_tooltips_set_tip(tooltips
, button
, tip
, NULL
);
1642 gtk_container_add(GTK_CONTAINER(box
), button
);
1646 /* Build up some option widgets to go in the options dialog, but don't
1649 static GtkWidget
*create_options()
1651 GtkWidget
*vbox
, *menu
, *hbox
;
1653 vbox
= gtk_vbox_new(FALSE
, 0);
1654 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
1656 display_label
= gtk_label_new("<>");
1657 gtk_label_set_line_wrap(GTK_LABEL(display_label
), TRUE
);
1658 gtk_box_pack_start(GTK_BOX(vbox
), display_label
, FALSE
, TRUE
, 0);
1660 toggle_new_window_on_1
=
1661 gtk_check_button_new_with_label("New window on button 1 "
1663 gtk_box_pack_start(GTK_BOX(vbox
), toggle_new_window_on_1
,
1667 gtk_check_button_new_with_label("Menu on button 2 "
1669 gtk_box_pack_start(GTK_BOX(vbox
), toggle_menu_on_2
, FALSE
, TRUE
, 0);
1671 toggle_single_click
=
1672 gtk_check_button_new_with_label("Single-click nagivation");
1673 gtk_box_pack_start(GTK_BOX(vbox
), toggle_single_click
, FALSE
, TRUE
, 0);
1675 hbox
= gtk_hbox_new(FALSE
, 4);
1676 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
1678 gtk_box_pack_start(GTK_BOX(hbox
),
1679 gtk_label_new("Toolbar type for new windows"),
1681 menu_toolbar
= gtk_option_menu_new();
1682 menu
= gtk_menu_new();
1683 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("None"));
1684 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("Normal"));
1685 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("GNOME"));
1686 gtk_option_menu_set_menu(GTK_OPTION_MENU(menu_toolbar
), menu
);
1687 gtk_box_pack_start(GTK_BOX(hbox
), menu_toolbar
, TRUE
, TRUE
, 0);
1692 static void update_options_label(void)
1696 str
= g_strdup_printf("The last used display style (%s) and sort "
1697 "function (Sort By %s) will be saved if you click on "
1698 "Save.", style_to_name(), sort_fn_to_name());
1699 gtk_label_set_text(GTK_LABEL(display_label
), str
);
1703 /* Reflect current state by changing the widgets in the options box */
1704 static void update_options()
1706 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_new_window_on_1
),
1708 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_menu_on_2
),
1709 collection_menu_button
== 2 ? 1 : 0);
1710 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_single_click
),
1712 gtk_option_menu_set_history(GTK_OPTION_MENU(menu_toolbar
), o_toolbar
);
1714 update_options_label();
1717 /* Set current values by reading the states of the widgets in the options box */
1718 static void set_options()
1720 GtkWidget
*item
, *menu
;
1723 o_new_window_on_1
= gtk_toggle_button_get_active(
1724 GTK_TOGGLE_BUTTON(toggle_new_window_on_1
));
1726 collection_menu_button
= gtk_toggle_button_get_active(
1727 GTK_TOGGLE_BUTTON(toggle_menu_on_2
)) ? 2 : 3;
1729 o_single_click
= gtk_toggle_button_get_active(
1730 GTK_TOGGLE_BUTTON(toggle_single_click
));
1731 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1733 menu
= gtk_option_menu_get_menu(GTK_OPTION_MENU(menu_toolbar
));
1734 item
= gtk_menu_get_active(GTK_MENU(menu
));
1735 list
= gtk_container_children(GTK_CONTAINER(menu
));
1736 o_toolbar
= (ToolbarType
) g_list_index(list
, item
);
1741 static guchar
*style_to_name(void)
1743 return last_display_style
== LARGE_ICONS
? "Large Icons" :
1744 last_display_style
== SMALL_ICONS
? "Small Icons" :
1748 static guchar
*sort_fn_to_name(void)
1750 return last_sort_fn
== sort_by_name
? "Name" :
1751 last_sort_fn
== sort_by_type
? "Type" :
1752 last_sort_fn
== sort_by_date
? "Date" :
1756 static void save_options()
1758 option_write("filer_new_window_on_1", o_new_window_on_1
? "1" : "0");
1759 option_write("filer_menu_on_2",
1760 collection_menu_button
== 2 ? "1" : "0");
1761 option_write("filer_single_click", o_single_click
? "1" : "0");
1762 option_write("filer_display_style", style_to_name());
1763 option_write("filer_sort_by", sort_fn_to_name());
1764 option_write("filer_toolbar", o_toolbar
== TOOLBAR_NONE
? "None" :
1765 o_toolbar
== TOOLBAR_NORMAL
? "Normal" :
1766 o_toolbar
== TOOLBAR_GNOME
? "GNOME" :
1770 static char *filer_new_window_on_1(char *data
)
1772 o_new_window_on_1
= atoi(data
) != 0;
1776 static char *filer_menu_on_2(char *data
)
1778 collection_menu_button
= atoi(data
) != 0 ? 2 : 3;
1782 static char *filer_single_click(char *data
)
1784 o_single_click
= atoi(data
) != 0;
1785 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1789 static char *filer_display_style(char *data
)
1791 if (g_strcasecmp(data
, "Large Icons") == 0)
1792 last_display_style
= LARGE_ICONS
;
1793 else if (g_strcasecmp(data
, "Small Icons") == 0)
1794 last_display_style
= SMALL_ICONS
;
1795 else if (g_strcasecmp(data
, "Full Info") == 0)
1796 last_display_style
= FULL_INFO
;
1798 return "Unknown display style";
1803 static char *filer_sort_by(char *data
)
1805 if (g_strcasecmp(data
, "Name") == 0)
1806 last_sort_fn
= sort_by_name
;
1807 else if (g_strcasecmp(data
, "Type") == 0)
1808 last_sort_fn
= sort_by_type
;
1809 else if (g_strcasecmp(data
, "Date") == 0)
1810 last_sort_fn
= sort_by_date
;
1811 else if (g_strcasecmp(data
, "Size") == 0)
1812 last_sort_fn
= sort_by_size
;
1814 return "Unknown sort type";
1819 static char *filer_toolbar(char *data
)
1821 if (g_strcasecmp(data
, "None") == 0)
1822 o_toolbar
= TOOLBAR_NONE
;
1823 else if (g_strcasecmp(data
, "Normal") == 0)
1824 o_toolbar
= TOOLBAR_NORMAL
;
1825 else if (g_strcasecmp(data
, "GNOME") == 0)
1826 o_toolbar
= TOOLBAR_GNOME
;
1828 return "Unknown toolbar type";
1833 /* Note that filer_window may not exist after this call. */
1834 void update_dir(FilerWindow
*filer_window
, gboolean warning
)
1836 if (may_rescan(filer_window
, warning
))
1837 dir_update(filer_window
->directory
, filer_window
->path
);
1840 void filer_set_hidden(FilerWindow
*filer_window
, gboolean hidden
)
1842 Directory
*dir
= filer_window
->directory
;
1844 if (filer_window
->show_hidden
== hidden
)
1847 filer_window
->show_hidden
= hidden
;
1848 last_show_hidden
= hidden
;
1850 g_fscache_data_ref(dir_cache
, dir
);
1851 detach(filer_window
);
1852 filer_window
->directory
= dir
;
1853 attach(filer_window
);
1856 /* Refresh the various caches even if we don't think we need to */
1857 void full_refresh(void)
1862 /* This path has been mounted/umounted - update all dirs */
1863 void filer_check_mounted(char *path
)
1865 GList
*next
= all_filer_windows
;
1872 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
1876 if (strncmp(path
, filer_window
->path
, len
) == 0)
1878 char s
= filer_window
->path
[len
];
1880 if (s
== '/' || s
== '\0')
1881 update_dir(filer_window
, FALSE
);
1886 /* Like minibuffer_show(), except that:
1887 * - It returns FALSE (to be used from an idle callback)
1888 * - It checks that the filer window still exists.
1890 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
)
1892 GList
*next
= all_filer_windows
;
1896 FilerWindow
*fw
= (FilerWindow
*) next
->data
;
1899 if (fw
== filer_window
)
1901 minibuffer_show(filer_window
);
1911 /* Highlight (wink or cursor) this item in the filer window. If the item
1912 * isn't already there but we're scanning then highlight it if it
1915 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
)
1917 Collection
*col
= filer_window
->collection
;
1920 g_free(filer_window
->auto_select
);
1921 filer_window
->auto_select
= NULL
;
1923 for (i
= 0; i
< col
->number_of_items
; i
++)
1925 DirItem
*item
= (DirItem
*) col
->items
[i
].data
;
1927 if (strcmp(item
->leafname
, leaf
) == 0)
1929 if (col
->cursor_item
!= -1)
1930 collection_set_cursor_item(col
, i
);
1932 collection_wink_item(col
, i
);
1937 filer_window
->auto_select
= g_strdup(leaf
);