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 FilerWindow
*window_with_selection
= NULL
;
71 static GtkWidget
*create_options();
72 static void update_options();
73 static void set_options();
74 static void save_options();
75 static char *filer_single_click(char *data
);
76 static char *filer_menu_on_2(char *data
);
77 static char *filer_new_window_on_1(char *data
);
78 static char *filer_toolbar(char *data
);
80 static OptionsSection options
=
82 "Filer window options",
89 /* The values correspond to the menu indexes in the option widget */
95 static ToolbarType o_toolbar
= TOOLBAR_NORMAL
;
96 static GtkWidget
*menu_toolbar
;
98 static gboolean o_single_click
= FALSE
;
99 static GtkWidget
*toggle_single_click
;
100 static gboolean o_new_window_on_1
= FALSE
; /* Button 1 => New window */
101 static GtkWidget
*toggle_new_window_on_1
;
102 static GtkWidget
*toggle_menu_on_2
;
104 /* Static prototypes */
105 static void attach(FilerWindow
*filer_window
);
106 static void detach(FilerWindow
*filer_window
);
107 static void filer_window_destroyed(GtkWidget
*widget
,
108 FilerWindow
*filer_window
);
109 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
110 int number_selected
, gpointer user_data
);
111 static gint
focus_in(GtkWidget
*widget
,
112 GdkEventFocus
*event
,
113 FilerWindow
*filer_window
);
114 static gint
focus_out(GtkWidget
*widget
,
115 GdkEventFocus
*event
,
116 FilerWindow
*filer_window
);
117 static void add_item(FilerWindow
*filer_window
, DirItem
*item
);
118 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
119 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
120 static void add_button(GtkWidget
*box
, int pixmap
,
121 GtkSignalFunc cb
, FilerWindow
*filer_window
,
122 char *label
, char *tip
);
123 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
);
124 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
125 FilerWindow
*window
);
126 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
);
127 static void draw_large_icon(GtkWidget
*widget
,
131 static void draw_string(GtkWidget
*widget
,
138 static void draw_item_large(GtkWidget
*widget
,
139 CollectionItem
*item
,
141 static void draw_item_small(GtkWidget
*widget
,
142 CollectionItem
*item
,
144 static void draw_item_full_info(GtkWidget
*widget
,
145 CollectionItem
*colitem
,
147 static gboolean
test_point_large(Collection
*collection
,
148 int point_x
, int point_y
,
149 CollectionItem
*item
,
150 int width
, int height
);
151 static gboolean
test_point_small(Collection
*collection
,
152 int point_x
, int point_y
,
153 CollectionItem
*item
,
154 int width
, int height
);
155 static gboolean
test_point_full_info(Collection
*collection
,
156 int point_x
, int point_y
,
157 CollectionItem
*item
,
158 int width
, int height
);
159 static void update_display(Directory
*dir
,
162 FilerWindow
*filer_window
);
163 static void shrink_width(FilerWindow
*filer_window
);
164 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
);
165 static void open_item(Collection
*collection
,
166 gpointer item_data
, int item_number
,
168 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
);
169 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
);
171 static GdkAtom xa_string
;
178 static GdkCursor
*busy_cursor
= NULL
;
179 static GtkTooltips
*tooltips
= NULL
;
183 xa_string
= gdk_atom_intern("STRING", FALSE
);
185 options_sections
= g_slist_prepend(options_sections
, &options
);
186 option_register("filer_new_window_on_1", filer_new_window_on_1
);
187 option_register("filer_menu_on_2", filer_menu_on_2
);
188 option_register("filer_single_click", filer_single_click
);
189 option_register("filer_toolbar", filer_toolbar
);
191 busy_cursor
= gdk_cursor_new(GDK_WATCH
);
193 tooltips
= gtk_tooltips_new();
196 static gboolean
if_deleted(gpointer item
, gpointer removed
)
198 int i
= ((GPtrArray
*) removed
)->len
;
199 DirItem
**r
= (DirItem
**) ((GPtrArray
*) removed
)->pdata
;
200 char *leafname
= ((DirItem
*) item
)->leafname
;
204 if (strcmp(leafname
, r
[i
]->leafname
) == 0)
211 static void update_item(FilerWindow
*filer_window
, DirItem
*item
)
214 char *leafname
= item
->leafname
;
216 if (leafname
[0] == '.')
218 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
219 || (leafname
[1] == '.' && leafname
[2] == '\0'))
223 i
= collection_find_item(filer_window
->collection
, item
, dir_item_cmp
);
226 collection_draw_item(filer_window
->collection
, i
, TRUE
);
228 g_warning("Failed to find '%s'\n", item
->leafname
);
231 static void update_display(Directory
*dir
,
234 FilerWindow
*filer_window
)
237 int cursor
= filer_window
->collection
->cursor_item
;
239 Collection
*collection
= filer_window
->collection
;
244 as
= filer_window
->auto_select
;
246 for (i
= 0; i
< items
->len
; i
++)
248 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
250 add_item(filer_window
, item
);
252 if (cursor
!= -1 || !as
)
255 if (strcmp(as
, item
->leafname
) != 0)
258 cursor
= collection
->number_of_items
- 1;
259 if (filer_window
->had_cursor
)
261 collection_set_cursor_item(collection
,
263 filer_window
->mini_cursor_base
= cursor
;
266 collection_wink_item(collection
,
270 collection_qsort(filer_window
->collection
,
271 filer_window
->sort_fn
);
274 collection_delete_if(filer_window
->collection
,
279 if (filer_window
->window
->window
)
280 gdk_window_set_cursor(
281 filer_window
->window
->window
,
283 shrink_width(filer_window
);
284 if (filer_window
->had_cursor
&&
285 collection
->cursor_item
== -1)
287 collection_set_cursor_item(collection
, 0);
288 filer_window
->had_cursor
= FALSE
;
292 for (i
= 0; i
< items
->len
; i
++)
294 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
296 update_item(filer_window
, item
);
298 collection_qsort(filer_window
->collection
,
299 filer_window
->sort_fn
);
304 static void attach(FilerWindow
*filer_window
)
306 gdk_window_set_cursor(filer_window
->window
->window
, busy_cursor
);
307 collection_clear(filer_window
->collection
);
308 dir_attach(filer_window
->directory
, (DirCallback
) update_display
,
312 static void detach(FilerWindow
*filer_window
)
314 g_return_if_fail(filer_window
->directory
!= NULL
);
316 dir_detach(filer_window
->directory
,
317 (DirCallback
) update_display
, filer_window
);
318 g_fscache_data_unref(dir_cache
, filer_window
->directory
);
319 filer_window
->directory
= NULL
;
322 static void filer_window_destroyed(GtkWidget
*widget
,
323 FilerWindow
*filer_window
)
325 all_filer_windows
= g_list_remove(all_filer_windows
, filer_window
);
327 if (window_with_selection
== filer_window
)
328 window_with_selection
= NULL
;
329 if (window_with_focus
== filer_window
)
330 window_with_focus
= NULL
;
332 if (filer_window
->directory
)
333 detach(filer_window
);
335 g_free(filer_window
->auto_select
);
336 g_free(filer_window
->path
);
337 g_free(filer_window
);
339 if (--number_of_windows
< 1)
343 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
)
345 int pix_width
= item
->image
->width
;
347 switch (filer_window
->display_style
)
350 return MAX_ICON_WIDTH
+ 12 +
351 MAX(item
->details_width
, item
->name_width
);
353 return SMALL_ICON_WIDTH
+ 12 + item
->name_width
;
355 return MAX(pix_width
, item
->name_width
) + 4;
359 /* Add a single object to a directory display */
360 static void add_item(FilerWindow
*filer_window
, DirItem
*item
)
362 char *leafname
= item
->leafname
;
365 if (leafname
[0] == '.')
367 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
368 || (leafname
[1] == '.' && leafname
[2] == '\0'))
372 item_width
= calc_width(filer_window
, item
);
373 if (item_width
> filer_window
->collection
->item_width
)
374 collection_set_item_size(filer_window
->collection
,
376 filer_window
->collection
->item_height
);
377 collection_insert(filer_window
->collection
, item
);
380 /* Is a point inside an item? */
381 static gboolean
test_point_large(Collection
*collection
,
382 int point_x
, int point_y
,
383 CollectionItem
*colitem
,
384 int width
, int height
)
386 DirItem
*item
= (DirItem
*) colitem
->data
;
387 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
388 int text_height
= font
->ascent
+ font
->descent
;
389 MaskedPixmap
*image
= item
->image
;
390 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
391 int image_width
= (image
->width
>> 1) + 2;
392 int text_width
= (item
->name_width
>> 1) + 2;
395 if (point_y
< image_y
)
396 return FALSE
; /* Too high up (don't worry about too low) */
398 if (point_y
<= image_y
+ image
->height
+ 2)
399 x_limit
= image_width
;
400 else if (point_y
> height
- text_height
- 2)
401 x_limit
= text_width
;
403 x_limit
= MIN(image_width
, text_width
);
405 return ABS(point_x
- (width
>> 1)) < x_limit
;
408 static gboolean
test_point_full_info(Collection
*collection
,
409 int point_x
, int point_y
,
410 CollectionItem
*colitem
,
411 int width
, int height
)
413 DirItem
*item
= (DirItem
*) colitem
->data
;
414 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
415 MaskedPixmap
*image
= item
->image
;
416 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
418 - fixed_font
->descent
- 2 - fixed_font
->ascent
;
420 if (point_x
< image
->width
+ 2)
421 return point_x
> 2 && point_y
> image_y
;
423 point_x
-= MAX_ICON_WIDTH
+ 8;
425 if (point_y
>= low_top
)
426 return point_x
< item
->details_width
;
427 if (point_y
>= low_top
- font
->ascent
- font
->descent
)
428 return point_x
< item
->name_width
;
432 static gboolean
test_point_small(Collection
*collection
,
433 int point_x
, int point_y
,
434 CollectionItem
*colitem
,
435 int width
, int height
)
437 DirItem
*item
= (DirItem
*) colitem
->data
;
438 MaskedPixmap
*image
= item
->image
;
439 int image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
440 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
442 - fixed_font
->descent
- 2 - font
->ascent
;
443 int iwidth
= MIN(SMALL_ICON_WIDTH
, image
->width
);
445 if (point_x
< iwidth
+ 2)
446 return point_x
> 2 && point_y
> image_y
;
448 point_x
-= SMALL_ICON_WIDTH
+ 4;
450 if (point_y
>= low_top
)
451 return point_x
< item
->name_width
;
455 static void draw_small_icon(GtkWidget
*widget
,
460 MaskedPixmap
*image
= item
->image
;
461 int width
= MIN(image
->width
, SMALL_ICON_WIDTH
);
462 int height
= MIN(image
->height
, SMALL_ICON_HEIGHT
);
463 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
465 GdkGC
*gc
= selected
? widget
->style
->white_gc
466 : widget
->style
->black_gc
;
470 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
472 image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
473 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
474 gdk_draw_pixmap(widget
->window
, gc
,
476 0, 0, /* Source x,y */
477 image_x
, area
->y
+ image_y
, /* Dest x,y */
482 gdk_gc_set_function(gc
, GDK_INVERT
);
483 gdk_draw_rectangle(widget
->window
,
485 TRUE
, image_x
, area
->y
+ image_y
,
487 gdk_gc_set_function(gc
, GDK_COPY
);
490 if (item
->flags
& ITEM_FLAG_SYMLINK
)
492 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
493 gdk_gc_set_clip_mask(gc
,
494 default_pixmap
[TYPE_SYMLINK
].mask
);
495 gdk_draw_pixmap(widget
->window
, gc
,
496 default_pixmap
[TYPE_SYMLINK
].pixmap
,
497 0, 0, /* Source x,y */
498 image_x
, area
->y
+ 8, /* Dest x,y */
501 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
503 int type
= item
->flags
& ITEM_FLAG_MOUNTED
506 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
507 gdk_gc_set_clip_mask(gc
,
508 default_pixmap
[type
].mask
);
509 gdk_draw_pixmap(widget
->window
, gc
,
510 default_pixmap
[type
].pixmap
,
511 0, 0, /* Source x,y */
512 image_x
, area
->y
+ 8, /* Dest x,y */
516 gdk_gc_set_clip_mask(gc
, NULL
);
517 gdk_gc_set_clip_origin(gc
, 0, 0);
520 static void draw_large_icon(GtkWidget
*widget
,
525 MaskedPixmap
*image
= item
->image
;
526 int width
= MIN(image
->width
, MAX_ICON_WIDTH
);
527 int height
= MIN(image
->height
, MAX_ICON_WIDTH
);
528 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
530 GdkGC
*gc
= selected
? widget
->style
->white_gc
531 : widget
->style
->black_gc
;
533 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
535 image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
536 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
537 gdk_draw_pixmap(widget
->window
, gc
,
539 0, 0, /* Source x,y */
540 image_x
, area
->y
+ image_y
, /* Dest x,y */
545 gdk_gc_set_function(gc
, GDK_INVERT
);
546 gdk_draw_rectangle(widget
->window
,
548 TRUE
, image_x
, area
->y
+ image_y
,
550 gdk_gc_set_function(gc
, GDK_COPY
);
553 if (item
->flags
& ITEM_FLAG_SYMLINK
)
555 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
556 gdk_gc_set_clip_mask(gc
,
557 default_pixmap
[TYPE_SYMLINK
].mask
);
558 gdk_draw_pixmap(widget
->window
, gc
,
559 default_pixmap
[TYPE_SYMLINK
].pixmap
,
560 0, 0, /* Source x,y */
561 image_x
, area
->y
+ 8, /* Dest x,y */
564 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
566 int type
= item
->flags
& ITEM_FLAG_MOUNTED
569 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
570 gdk_gc_set_clip_mask(gc
,
571 default_pixmap
[type
].mask
);
572 gdk_draw_pixmap(widget
->window
, gc
,
573 default_pixmap
[type
].pixmap
,
574 0, 0, /* Source x,y */
575 image_x
, area
->y
+ 8, /* Dest x,y */
579 gdk_gc_set_clip_mask(gc
, NULL
);
580 gdk_gc_set_clip_origin(gc
, 0, 0);
583 static void draw_string(GtkWidget
*widget
,
591 int text_height
= font
->ascent
+ font
->descent
;
594 gtk_paint_flat_box(widget
->style
, widget
->window
,
595 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
596 NULL
, widget
, "text",
601 gdk_draw_text(widget
->window
,
603 selected
? widget
->style
->white_gc
604 : widget
->style
->black_gc
,
606 string
, strlen(string
));
609 /* Return a string (valid until next call) giving details
612 char *details(DirItem
*item
)
614 mode_t m
= item
->mode
;
615 static GString
*buf
= NULL
;
618 buf
= g_string_new(NULL
);
620 g_string_sprintf(buf
, "%s, %s, %s",
622 S_ISCHR(m
) ? "Char" :
623 S_ISBLK(m
) ? "Blck" :
624 S_ISLNK(m
) ? "Link" :
625 S_ISSOCK(m
) ? "Sock" :
626 S_ISFIFO(m
) ? "Pipe" : "File",
627 pretty_permissions(item
->uid
, item
->gid
, m
),
628 format_size(item
->size
));
632 static void draw_item_full_info(GtkWidget
*widget
,
633 CollectionItem
*colitem
,
636 DirItem
*item
= (DirItem
*) colitem
->data
;
637 MaskedPixmap
*image
= item
->image
;
638 GdkFont
*font
= widget
->style
->font
;
639 int text_x
= area
->x
+ MAX_ICON_WIDTH
+ 8;
640 int low_text_y
= area
->y
+ area
->height
- fixed_font
->descent
- 2;
641 gboolean selected
= colitem
->selected
;
642 GdkRectangle pic_area
;
644 pic_area
.x
= area
->x
;
645 pic_area
.y
= area
->y
;
646 pic_area
.width
= image
->width
+ 8;
647 pic_area
.height
= area
->height
;
649 draw_large_icon(widget
, &pic_area
, item
, selected
);
655 low_text_y
- font
->descent
- fixed_font
->ascent
,
666 static void draw_item_small(GtkWidget
*widget
,
667 CollectionItem
*colitem
,
670 DirItem
*item
= (DirItem
*) colitem
->data
;
671 GdkFont
*font
= widget
->style
->font
;
672 int text_x
= area
->x
+ SMALL_ICON_WIDTH
+ 4;
673 int low_text_y
= area
->y
+ area
->height
- font
->descent
- 2;
674 gboolean selected
= colitem
->selected
;
675 GdkRectangle pic_area
;
677 pic_area
.x
= area
->x
;
678 pic_area
.y
= area
->y
;
679 pic_area
.width
= SMALL_ICON_WIDTH
;
680 pic_area
.height
= SMALL_ICON_HEIGHT
;
682 draw_small_icon(widget
, &pic_area
, item
, selected
);
693 static void draw_item_large(GtkWidget
*widget
,
694 CollectionItem
*colitem
,
697 DirItem
*item
= (DirItem
*) colitem
->data
;
698 GdkFont
*font
= widget
->style
->font
;
699 int text_x
= area
->x
+ ((area
->width
- item
->name_width
) >> 1);
700 int text_y
= area
->y
+ area
->height
- font
->descent
- 2;
701 gboolean selected
= colitem
->selected
;
703 draw_large_icon(widget
, area
, item
, selected
);
708 text_x
, text_y
, item
->name_width
,
712 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
713 int item
, gpointer user_data
)
715 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
718 /* Returns TRUE iff the directory still exits. */
719 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
)
723 g_return_val_if_fail(filer_window
!= NULL
, FALSE
);
725 /* We do a fresh lookup (rather than update) because the inode may
728 dir
= g_fscache_lookup(dir_cache
, filer_window
->path
);
732 delayed_error("ROX-Filer", "Directory missing/deleted");
733 gtk_widget_destroy(filer_window
->window
);
736 if (dir
== filer_window
->directory
)
737 g_fscache_data_unref(dir_cache
, dir
);
740 detach(filer_window
);
741 filer_window
->directory
= dir
;
742 attach(filer_window
);
748 /* Another app has grabbed the selection */
749 static gint
collection_lose_selection(GtkWidget
*widget
,
750 GdkEventSelection
*event
)
752 if (window_with_selection
&&
753 window_with_selection
->collection
== COLLECTION(widget
))
755 FilerWindow
*filer_window
= window_with_selection
;
756 window_with_selection
= NULL
;
757 collection_clear_selection(filer_window
->collection
);
763 /* Someone wants us to send them the selection */
764 static void selection_get(GtkWidget
*widget
,
765 GtkSelectionData
*selection_data
,
770 GString
*reply
, *header
;
771 FilerWindow
*filer_window
;
773 Collection
*collection
;
775 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
777 reply
= g_string_new(NULL
);
778 header
= g_string_new(NULL
);
783 g_string_sprintf(header
, " %s",
784 make_path(filer_window
->path
, "")->str
);
786 case TARGET_URI_LIST
:
787 g_string_sprintf(header
, " file://%s%s",
789 make_path(filer_window
->path
, "")->str
);
793 collection
= filer_window
->collection
;
794 for (i
= 0; i
< collection
->number_of_items
; i
++)
796 if (collection
->items
[i
].selected
)
799 (DirItem
*) collection
->items
[i
].data
;
801 g_string_append(reply
, header
->str
);
802 g_string_append(reply
, item
->leafname
);
805 /* This works, but I don't think I like it... */
806 /* g_string_append_c(reply, ' '); */
808 gtk_selection_data_set(selection_data
, xa_string
,
809 8, reply
->str
+ 1, reply
->len
- 1);
810 g_string_free(reply
, TRUE
);
811 g_string_free(header
, TRUE
);
814 /* No items are now selected. This might be because another app claimed
815 * the selection or because the user unselected all the items.
817 static void lose_selection(Collection
*collection
,
821 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
823 if (window_with_selection
== filer_window
)
825 window_with_selection
= NULL
;
826 gtk_selection_owner_set(NULL
,
827 GDK_SELECTION_PRIMARY
,
832 static void gain_selection(Collection
*collection
,
836 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
838 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
839 GDK_SELECTION_PRIMARY
,
842 window_with_selection
= filer_window
;
845 collection_clear_selection(filer_window
->collection
);
848 int sort_by_name(const void *item1
, const void *item2
)
850 return strcmp((*((DirItem
**)item1
))->leafname
,
851 (*((DirItem
**)item2
))->leafname
);
854 int sort_by_type(const void *item1
, const void *item2
)
856 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
857 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
860 int diff
= i1
->base_type
- i2
->base_type
;
863 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
864 - (i2
->flags
& ITEM_FLAG_APPDIR
);
866 return diff
> 0 ? 1 : -1;
873 diff
= strcmp(m1
->media_type
, m2
->media_type
);
875 diff
= strcmp(m1
->subtype
, m2
->subtype
);
883 return diff
> 0 ? 1 : -1;
885 return sort_by_name(item1
, item2
);
888 int sort_by_date(const void *item1
, const void *item2
)
890 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
891 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
893 return i1
->mtime
> i2
->mtime
? -1 :
894 i1
->mtime
< i2
->mtime
? 1 :
895 sort_by_name(item1
, item2
);
898 int sort_by_size(const void *item1
, const void *item2
)
900 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
901 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
903 return i1
->size
> i2
->size
? -1 :
904 i1
->size
< i2
->size
? 1 :
905 sort_by_name(item1
, item2
);
908 static void open_item(Collection
*collection
,
909 gpointer item_data
, int item_number
,
912 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
914 GdkEventButton
*bevent
;
918 event
= (GdkEvent
*) gtk_get_current_event();
920 bevent
= (GdkEventButton
*) event
;
921 kevent
= (GdkEventKey
*) event
;
925 case GDK_2BUTTON_PRESS
:
926 case GDK_BUTTON_PRESS
:
927 case GDK_BUTTON_RELEASE
:
928 if (bevent
->state
& GDK_SHIFT_MASK
)
931 if (o_new_window_on_1
^ (bevent
->button
== 1))
932 flags
|= OPEN_SAME_WINDOW
;
934 if (bevent
->button
!= 1)
935 flags
|= OPEN_CLOSE_WINDOW
;
937 if (o_single_click
== FALSE
&&
938 (bevent
->state
& GDK_CONTROL_MASK
) != 0)
939 flags
^= OPEN_SAME_WINDOW
| OPEN_CLOSE_WINDOW
;
942 flags
|= OPEN_SAME_WINDOW
;
943 if (kevent
->state
& GDK_SHIFT_MASK
)
950 filer_openitem(filer_window
, item_number
, flags
);
953 /* Return the full path to the directory containing object 'path'.
954 * Relative paths are resolved from the filerwindow's path.
956 static void follow_symlink(FilerWindow
*filer_window
, char *path
,
957 gboolean same_window
)
963 path
= make_path(filer_window
->path
, path
)->str
;
965 real
= pathdup(path
);
966 slash
= strrchr(real
, '/');
970 delayed_error("ROX-Filer",
971 "Broken symlink (or you don't have permission "
983 if (filer_window
->panel
|| !same_window
)
987 new = filer_opendir(new_dir
, FALSE
, BOTTOM
);
988 set_autoselect(new, slash
+ 1);
991 filer_change_to(filer_window
, new_dir
, slash
+ 1);
996 void filer_openitem(FilerWindow
*filer_window
, int item_number
, OpenFlags flags
)
998 gboolean shift
= (flags
& OPEN_SHIFT
) != 0;
999 gboolean close_mini
= flags
& OPEN_FROM_MINI
;
1000 gboolean same_window
= (flags
& OPEN_SAME_WINDOW
) != 0
1001 && !filer_window
->panel
;
1002 gboolean close_window
= (flags
& OPEN_CLOSE_WINDOW
) != 0
1003 && !filer_window
->panel
;
1006 DirItem
*item
= (DirItem
*)
1007 filer_window
->collection
->items
[item_number
].data
;
1008 gboolean wink
= TRUE
, destroy
= FALSE
;
1010 widget
= filer_window
->window
;
1011 full_path
= make_path(filer_window
->path
,
1012 item
->leafname
)->str
;
1014 if (item
->flags
& ITEM_FLAG_SYMLINK
&& shift
)
1016 char path
[MAXPATHLEN
+ 1];
1019 got
= readlink(make_path(filer_window
->path
,
1020 item
->leafname
)->str
,
1023 delayed_error("ROX-Filer", g_strerror(errno
));
1026 g_return_if_fail(got
<= MAXPATHLEN
);
1029 follow_symlink(filer_window
, path
,
1030 flags
& OPEN_SAME_WINDOW
);
1035 switch (item
->base_type
)
1037 case TYPE_DIRECTORY
:
1038 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
1040 run_app(make_path(filer_window
->path
,
1041 item
->leafname
)->str
);
1047 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& shift
)
1049 action_mount(filer_window
, item
);
1050 if (item
->flags
& ITEM_FLAG_MOUNTED
)
1057 filer_change_to(filer_window
, full_path
, NULL
);
1061 filer_opendir(full_path
, FALSE
, BOTTOM
);
1064 if ((item
->flags
& ITEM_FLAG_EXEC_FILE
) && !shift
)
1066 char *argv
[] = {NULL
, NULL
};
1068 argv
[0] = full_path
;
1070 if (spawn_full(argv
, getenv("HOME")))
1076 report_error("ROX-Filer",
1077 "Failed to fork() child");
1082 MIME_type
*type
= shift
? &text_plain
1085 g_return_if_fail(type
!= NULL
);
1087 if (type_open(full_path
, type
))
1094 message
= g_string_new(NULL
);
1095 g_string_sprintf(message
, "No open "
1096 "action specified for files of "
1097 "this type (%s/%s)",
1100 report_error("ROX-Filer", message
->str
);
1101 g_string_free(message
, TRUE
);
1106 report_error("open_item",
1107 "I don't know how to open that");
1112 gtk_widget_destroy(filer_window
->window
);
1116 collection_wink_item(filer_window
->collection
,
1119 minibuffer_hide(filer_window
);
1123 static gint
pointer_in(GtkWidget
*widget
,
1124 GdkEventCrossing
*event
,
1125 FilerWindow
*filer_window
)
1127 may_rescan(filer_window
, TRUE
);
1131 static gint
focus_in(GtkWidget
*widget
,
1132 GdkEventFocus
*event
,
1133 FilerWindow
*filer_window
)
1135 window_with_focus
= filer_window
;
1140 static gint
focus_out(GtkWidget
*widget
,
1141 GdkEventFocus
*event
,
1142 FilerWindow
*filer_window
)
1144 /* TODO: Shade the cursor */
1149 /* Handle keys that can't be bound with the menu */
1150 static gint
key_press_event(GtkWidget
*widget
,
1152 FilerWindow
*filer_window
)
1154 switch (event
->keyval
)
1157 change_to_parent(filer_window
);
1166 static void toolbar_refresh_clicked(GtkWidget
*widget
,
1167 FilerWindow
*filer_window
)
1170 update_dir(filer_window
, TRUE
);
1173 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1175 filer_change_to(filer_window
, getenv("HOME"), NULL
);
1178 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1180 change_to_parent(filer_window
);
1183 void change_to_parent(FilerWindow
*filer_window
)
1188 if (filer_window
->path
[0] == '/' && filer_window
->path
[1] == '\0')
1189 return; /* Already in the root */
1191 copy
= g_strdup(filer_window
->path
);
1192 slash
= strrchr(copy
, '/');
1197 filer_change_to(filer_window
,
1202 g_warning("No / in directory path!\n");
1208 /* Make filer_window display path. When finished, highlight item 'from', or
1209 * the first item if from is NULL. If there is currently no cursor then
1210 * simply wink 'from' (if not NULL).
1212 void filer_change_to(FilerWindow
*filer_window
, char *path
, char *from
)
1216 from_dup
= from
&& *from
? g_strdup(from
) : NULL
;
1218 detach(filer_window
);
1219 g_free(filer_window
->path
);
1220 filer_window
->path
= pathdup(path
);
1222 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1223 filer_window
->path
);
1224 if (filer_window
->directory
)
1226 g_free(filer_window
->auto_select
);
1227 filer_window
->had_cursor
=
1228 filer_window
->collection
->cursor_item
!= -1
1229 || filer_window
->had_cursor
;
1230 filer_window
->auto_select
= from_dup
;
1232 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
1233 filer_window
->path
);
1234 collection_set_cursor_item(filer_window
->collection
, -1);
1235 attach(filer_window
);
1237 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer
))
1238 gtk_idle_add((GtkFunction
) minibuffer_show_cb
,
1246 error
= g_strdup_printf("Directory '%s' is not accessible.",
1248 delayed_error("ROX-Filer", error
);
1250 gtk_widget_destroy(filer_window
->window
);
1254 int selected_item_number(Collection
*collection
)
1258 g_return_val_if_fail(collection
!= NULL
, -1);
1259 g_return_val_if_fail(IS_COLLECTION(collection
), -1);
1260 g_return_val_if_fail(collection
->number_selected
== 1, -1);
1262 for (i
= 0; i
< collection
->number_of_items
; i
++)
1263 if (collection
->items
[i
].selected
)
1266 g_warning("selected_item: number_selected is wrong\n");
1271 DirItem
*selected_item(Collection
*collection
)
1275 item
= selected_item_number(collection
);
1278 return (DirItem
*) collection
->items
[item
].data
;
1282 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
1283 FilerWindow
*window
)
1285 /* TODO: We can open lots of these - very irritating! */
1286 return get_choice("Close panel?",
1287 "You have tried to close a panel via the window "
1288 "manager - I usually find that this is accidental... "
1290 2, "Remove", "Cancel") != 0;
1293 /* Make the items as narrow as possible */
1294 static void shrink_width(FilerWindow
*filer_window
)
1297 Collection
*col
= filer_window
->collection
;
1298 int width
= MIN_ITEM_WIDTH
;
1300 DisplayStyle style
= filer_window
->display_style
;
1304 font
= gtk_widget_get_default_style()->font
;
1305 text_height
= font
->ascent
+ font
->descent
;
1307 for (i
= 0; i
< col
->number_of_items
; i
++)
1309 this_width
= calc_width(filer_window
,
1310 (DirItem
*) col
->items
[i
].data
);
1311 if (this_width
> width
)
1315 collection_set_item_size(filer_window
->collection
,
1317 style
== FULL_INFO
? MAX_ICON_HEIGHT
+ 4 :
1318 style
== SMALL_ICONS
? MAX(text_height
, SMALL_ICON_HEIGHT
) + 4
1319 : text_height
+ MAX_ICON_HEIGHT
+ 8);
1322 void filer_set_sort_fn(FilerWindow
*filer_window
,
1323 int (*fn
)(const void *a
, const void *b
))
1325 if (filer_window
->sort_fn
== fn
)
1328 filer_window
->sort_fn
= fn
;
1329 collection_qsort(filer_window
->collection
,
1330 filer_window
->sort_fn
);
1333 void filer_style_set(FilerWindow
*filer_window
, DisplayStyle style
)
1335 if (filer_window
->display_style
== style
)
1338 filer_window
->display_style
= style
;
1342 collection_set_functions(filer_window
->collection
,
1343 draw_item_small
, test_point_small
);
1346 collection_set_functions(filer_window
->collection
,
1347 draw_item_full_info
, test_point_full_info
);
1350 collection_set_functions(filer_window
->collection
,
1351 draw_item_large
, test_point_large
);
1355 shrink_width(filer_window
);
1358 FilerWindow
*filer_opendir(char *path
, gboolean panel
, Side panel_side
)
1360 GtkWidget
*hbox
, *scrollbar
, *collection
;
1361 FilerWindow
*filer_window
;
1362 GtkTargetEntry target_table
[] =
1364 {"text/uri-list", 0, TARGET_URI_LIST
},
1365 {"STRING", 0, TARGET_STRING
},
1368 filer_window
= g_new(FilerWindow
, 1);
1369 filer_window
->minibuffer
= NULL
;
1370 filer_window
->path
= pathdup(path
);
1371 filer_window
->had_cursor
= FALSE
;
1372 filer_window
->auto_select
= NULL
;
1374 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1375 filer_window
->path
);
1376 if (!filer_window
->directory
)
1380 error
= g_strdup_printf("Directory '%s' not found.", path
);
1381 delayed_error("ROX-Filer", error
);
1383 g_free(filer_window
->path
);
1384 g_free(filer_window
);
1388 filer_window
->show_hidden
= FALSE
;
1389 filer_window
->panel
= panel
;
1390 filer_window
->panel_side
= panel_side
;
1391 filer_window
->temp_item_selected
= FALSE
;
1392 filer_window
->sort_fn
= sort_by_type
;
1393 filer_window
->flags
= (FilerFlags
) 0;
1394 filer_window
->display_style
= UNKNOWN_STYLE
;
1396 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
1397 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
1398 filer_window
->path
);
1400 collection
= collection_new(NULL
);
1401 gtk_object_set_data(GTK_OBJECT(collection
),
1402 "filer_window", filer_window
);
1403 filer_window
->collection
= COLLECTION(collection
);
1405 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
1406 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1407 "enter-notify-event",
1408 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
1409 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
1410 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
1411 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
1412 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
1413 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
1414 filer_window_destroyed
, filer_window
);
1416 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
1417 open_item
, filer_window
);
1418 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
1419 show_menu
, filer_window
);
1420 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
1421 gain_selection
, filer_window
);
1422 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
1423 lose_selection
, filer_window
);
1424 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
1425 drag_selection
, filer_window
);
1426 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
1427 drag_data_get
, filer_window
);
1428 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
1429 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
1430 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
1431 GTK_SIGNAL_FUNC(selection_get
), NULL
);
1432 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
1434 sizeof(target_table
) / sizeof(*target_table
));
1436 filer_style_set(filer_window
, LARGE_ICONS
);
1437 drag_set_dest(collection
);
1441 int swidth
, sheight
, iwidth
, iheight
;
1442 GtkWidget
*frame
, *win
= filer_window
->window
;
1444 gtk_window_set_wmclass(GTK_WINDOW(win
), "ROX-Panel",
1446 collection_set_panel(filer_window
->collection
, TRUE
);
1447 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1449 GTK_SIGNAL_FUNC(filer_confirm_close
),
1452 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
1453 iwidth
= filer_window
->collection
->item_width
;
1454 iheight
= filer_window
->collection
->item_height
;
1456 if (panel_side
== TOP
|| panel_side
== BOTTOM
)
1458 int height
= iheight
+ PANEL_BORDER
;
1459 int y
= panel_side
== TOP
1461 : sheight
- height
- PANEL_BORDER
;
1463 gtk_widget_set_usize(collection
, swidth
, height
);
1464 gtk_widget_set_uposition(win
, 0, y
);
1468 int width
= iwidth
+ PANEL_BORDER
;
1469 int x
= panel_side
== LEFT
1471 : swidth
- width
- PANEL_BORDER
;
1473 gtk_widget_set_usize(collection
, width
, sheight
);
1474 gtk_widget_set_uposition(win
, x
, 0);
1477 frame
= gtk_frame_new(NULL
);
1478 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1479 gtk_container_add(GTK_CONTAINER(frame
), collection
);
1480 gtk_container_add(GTK_CONTAINER(win
), frame
);
1482 gtk_widget_show_all(frame
);
1483 gtk_widget_realize(win
);
1484 if (override_redirect
)
1485 gdk_window_set_override_redirect(win
->window
, TRUE
);
1486 make_panel_window(win
->window
);
1491 int col_height
= ROW_HEIGHT_LARGE
* 3;
1493 gtk_signal_connect(GTK_OBJECT(collection
),
1495 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
1496 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
1497 filer_window
->display_style
== LARGE_ICONS
? 400 : 512,
1498 o_toolbar
== TOOLBAR_NONE
? col_height
:
1499 o_toolbar
== TOOLBAR_NORMAL
? col_height
+ 24 :
1502 hbox
= gtk_hbox_new(FALSE
, 0);
1503 gtk_container_add(GTK_CONTAINER(filer_window
->window
),
1506 vbox
= gtk_vbox_new(FALSE
, 0);
1507 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, TRUE
, TRUE
, 0);
1509 if (o_toolbar
!= TOOLBAR_NONE
)
1513 toolbar
= create_toolbar(filer_window
);
1514 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
,
1516 gtk_widget_show_all(toolbar
);
1519 gtk_box_pack_start(GTK_BOX(vbox
), collection
, TRUE
, TRUE
, 0);
1521 filer_window
->minibuffer
= create_minibuffer(filer_window
);
1522 gtk_box_pack_start(GTK_BOX(vbox
), filer_window
->minibuffer
,
1525 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
1526 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
1527 gtk_accel_group_attach(filer_keys
,
1528 GTK_OBJECT(filer_window
->window
));
1529 gtk_window_set_focus(GTK_WINDOW(filer_window
->window
),
1532 gtk_widget_show(hbox
);
1533 gtk_widget_show(vbox
);
1534 gtk_widget_show(scrollbar
);
1535 gtk_widget_show(collection
);
1538 number_of_windows
++;
1539 gtk_widget_show(filer_window
->window
);
1540 attach(filer_window
);
1542 all_filer_windows
= g_list_prepend(all_filer_windows
, filer_window
);
1544 return filer_window
;
1547 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
)
1549 GtkWidget
*frame
, *box
;
1551 if (o_toolbar
== TOOLBAR_GNOME
)
1553 frame
= gtk_handle_box_new();
1554 box
= gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL
,
1556 gtk_container_set_border_width(GTK_CONTAINER(box
), 2);
1557 gtk_toolbar_set_space_style(GTK_TOOLBAR(box
),
1558 GTK_TOOLBAR_SPACE_LINE
);
1559 gtk_toolbar_set_button_relief(GTK_TOOLBAR(box
),
1564 frame
= gtk_frame_new(NULL
);
1565 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1567 box
= gtk_hbutton_box_new();
1568 gtk_button_box_set_child_size_default(16, 16);
1569 gtk_hbutton_box_set_spacing_default(2);
1570 gtk_button_box_set_layout(GTK_BUTTON_BOX(box
),
1571 GTK_BUTTONBOX_START
);
1574 gtk_container_add(GTK_CONTAINER(frame
), box
);
1576 add_button(box
, TOOLBAR_UP_ICON
,
1577 GTK_SIGNAL_FUNC(toolbar_up_clicked
),
1579 "Up", "Change to parent directory");
1580 add_button(box
, TOOLBAR_HOME_ICON
,
1581 GTK_SIGNAL_FUNC(toolbar_home_clicked
),
1583 "Home", "Change to home directory");
1584 add_button(box
, TOOLBAR_REFRESH_ICON
,
1585 GTK_SIGNAL_FUNC(toolbar_refresh_clicked
),
1587 "Rescan", "Rescan directory contents");
1592 static void add_button(GtkWidget
*box
, int pixmap
,
1593 GtkSignalFunc cb
, FilerWindow
*filer_window
,
1594 char *label
, char *tip
)
1596 GtkWidget
*button
, *icon
;
1598 icon
= gtk_pixmap_new(default_pixmap
[pixmap
].pixmap
,
1599 default_pixmap
[pixmap
].mask
);
1601 if (o_toolbar
== TOOLBAR_GNOME
)
1603 gtk_toolbar_append_element(GTK_TOOLBAR(box
),
1604 GTK_TOOLBAR_CHILD_BUTTON
,
1613 button
= gtk_button_new();
1614 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
1616 gtk_container_add(GTK_CONTAINER(button
), icon
);
1617 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1620 gtk_tooltips_set_tip(tooltips
, button
, tip
, NULL
);
1622 gtk_container_add(GTK_CONTAINER(box
), button
);
1626 /* Build up some option widgets to go in the options dialog, but don't
1629 static GtkWidget
*create_options()
1631 GtkWidget
*vbox
, *menu
, *hbox
;
1633 vbox
= gtk_vbox_new(FALSE
, 0);
1634 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
1636 toggle_new_window_on_1
=
1637 gtk_check_button_new_with_label("New window on button 1 "
1639 gtk_box_pack_start(GTK_BOX(vbox
), toggle_new_window_on_1
,
1643 gtk_check_button_new_with_label("Menu on button 2 "
1645 gtk_box_pack_start(GTK_BOX(vbox
), toggle_menu_on_2
, FALSE
, TRUE
, 0);
1647 toggle_single_click
=
1648 gtk_check_button_new_with_label("Single-click nagivation");
1649 gtk_box_pack_start(GTK_BOX(vbox
), toggle_single_click
, FALSE
, TRUE
, 0);
1651 hbox
= gtk_hbox_new(FALSE
, 4);
1652 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
1654 gtk_box_pack_start(GTK_BOX(hbox
),
1655 gtk_label_new("Toolbar type for new windows"),
1657 menu_toolbar
= gtk_option_menu_new();
1658 menu
= gtk_menu_new();
1659 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("None"));
1660 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("Normal"));
1661 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("GNOME"));
1662 gtk_option_menu_set_menu(GTK_OPTION_MENU(menu_toolbar
), menu
);
1663 gtk_box_pack_start(GTK_BOX(hbox
), menu_toolbar
, TRUE
, TRUE
, 0);
1668 /* Reflect current state by changing the widgets in the options box */
1669 static void update_options()
1671 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_new_window_on_1
),
1673 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_menu_on_2
),
1674 collection_menu_button
== 2 ? 1 : 0);
1675 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_single_click
),
1677 gtk_option_menu_set_history(GTK_OPTION_MENU(menu_toolbar
), o_toolbar
);
1680 /* Set current values by reading the states of the widgets in the options box */
1681 static void set_options()
1683 GtkWidget
*item
, *menu
;
1686 o_new_window_on_1
= gtk_toggle_button_get_active(
1687 GTK_TOGGLE_BUTTON(toggle_new_window_on_1
));
1689 collection_menu_button
= gtk_toggle_button_get_active(
1690 GTK_TOGGLE_BUTTON(toggle_menu_on_2
)) ? 2 : 3;
1692 o_single_click
= gtk_toggle_button_get_active(
1693 GTK_TOGGLE_BUTTON(toggle_single_click
));
1694 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1696 menu
= gtk_option_menu_get_menu(GTK_OPTION_MENU(menu_toolbar
));
1697 item
= gtk_menu_get_active(GTK_MENU(menu
));
1698 list
= gtk_container_children(GTK_CONTAINER(menu
));
1699 o_toolbar
= (ToolbarType
) g_list_index(list
, item
);
1704 static void save_options()
1706 option_write("filer_new_window_on_1", o_new_window_on_1
? "1" : "0");
1707 option_write("filer_menu_on_2",
1708 collection_menu_button
== 2 ? "1" : "0");
1709 option_write("filer_single_click", o_single_click
? "1" : "0");
1710 option_write("filer_toolbar", o_toolbar
== TOOLBAR_NONE
? "None" :
1711 o_toolbar
== TOOLBAR_NORMAL
? "Normal" :
1712 o_toolbar
== TOOLBAR_GNOME
? "GNOME" :
1716 static char *filer_new_window_on_1(char *data
)
1718 o_new_window_on_1
= atoi(data
) != 0;
1722 static char *filer_menu_on_2(char *data
)
1724 collection_menu_button
= atoi(data
) != 0 ? 2 : 3;
1728 static char *filer_single_click(char *data
)
1730 o_single_click
= atoi(data
) != 0;
1731 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1735 static char *filer_toolbar(char *data
)
1737 if (g_strcasecmp(data
, "None") == 0)
1738 o_toolbar
= TOOLBAR_NONE
;
1739 else if (g_strcasecmp(data
, "Normal") == 0)
1740 o_toolbar
= TOOLBAR_NORMAL
;
1741 else if (g_strcasecmp(data
, "GNOME") == 0)
1742 o_toolbar
= TOOLBAR_GNOME
;
1744 return "Unknown toolbar type";
1749 /* Note that filer_window may not exist after this call. */
1750 void update_dir(FilerWindow
*filer_window
, gboolean warning
)
1752 if (may_rescan(filer_window
, warning
))
1753 dir_update(filer_window
->directory
, filer_window
->path
);
1756 void filer_set_hidden(FilerWindow
*filer_window
, gboolean hidden
)
1758 Directory
*dir
= filer_window
->directory
;
1760 if (filer_window
->show_hidden
== hidden
)
1763 filer_window
->show_hidden
= hidden
;
1765 g_fscache_data_ref(dir_cache
, dir
);
1766 detach(filer_window
);
1767 filer_window
->directory
= dir
;
1768 attach(filer_window
);
1771 /* Refresh the various caches even if we don't think we need to */
1772 void full_refresh(void)
1777 /* This path has been mounted/umounted - update all dirs */
1778 void filer_check_mounted(char *path
)
1780 GList
*next
= all_filer_windows
;
1787 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
1791 if (strncmp(path
, filer_window
->path
, len
) == 0)
1793 char s
= filer_window
->path
[len
];
1795 if (s
== '/' || s
== '\0')
1796 update_dir(filer_window
, FALSE
);
1801 /* Like minibuffer_show(), except that:
1802 * - It returns FALSE (to be used from an idle callback)
1803 * - It checks that the filer window still exists.
1805 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
)
1807 GList
*next
= all_filer_windows
;
1811 FilerWindow
*fw
= (FilerWindow
*) next
->data
;
1814 if (fw
== filer_window
)
1816 minibuffer_show(filer_window
);
1826 /* Highlight (wink or cursor) this item in the filer window. If the item
1827 * isn't already there but we're scanning then highlight it if it
1830 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
)
1832 Collection
*col
= filer_window
->collection
;
1835 g_free(filer_window
->auto_select
);
1836 filer_window
->auto_select
= NULL
;
1838 for (i
= 0; i
< col
->number_of_items
; i
++)
1840 DirItem
*item
= (DirItem
*) col
->items
[i
].data
;
1842 if (strcmp(item
->leafname
, leaf
) == 0)
1844 if (col
->cursor_item
!= -1)
1845 collection_set_cursor_item(col
, i
);
1847 collection_wink_item(col
, i
);
1852 filer_window
->auto_select
= g_strdup(leaf
);