4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, 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 */
30 #include <sys/param.h>
37 #include <gdk/gdkkeysyms.h>
38 #include "collection.h"
42 #include "gui_support.h"
52 #include "minibuffer.h"
54 #define ROW_HEIGHT_LARGE 64
55 #define ROW_HEIGHT_SMALL 32
56 #define ROW_HEIGHT_FULL_INFO 44
57 #define SMALL_ICON_HEIGHT 20
58 #define SMALL_ICON_WIDTH 48
59 #define MAX_ICON_HEIGHT 42
60 #define MAX_ICON_WIDTH 48
61 #define PANEL_BORDER 2
62 #define MIN_ITEM_WIDTH 64
64 extern int collection_menu_button
;
65 extern gboolean collection_single_click
;
67 FilerWindow
*window_with_focus
= NULL
;
68 GList
*all_filer_windows
= NULL
;
70 static DisplayStyle last_display_style
= LARGE_ICONS
;
71 static gboolean last_show_hidden
= FALSE
;
72 static int (*last_sort_fn
)(const void *a
, const void *b
) = sort_by_type
;
74 static FilerWindow
*window_with_selection
= NULL
;
77 static guchar
*style_to_name(void);
78 static guchar
*sort_fn_to_name(void);
79 static void update_options_label(void);
81 static GtkWidget
*create_options();
82 static void update_options();
83 static void set_options();
84 static void save_options();
85 static char *filer_single_click(char *data
);
86 static char *filer_unique_windows(char *data
);
87 static char *filer_menu_on_2(char *data
);
88 static char *filer_new_window_on_1(char *data
);
89 static char *filer_toolbar(char *data
);
90 static char *filer_display_style(char *data
);
91 static char *filer_sort_by(char *data
);
93 static OptionsSection options
=
95 "Filer window options",
102 /* The values correspond to the menu indexes in the option widget */
108 static ToolbarType o_toolbar
= TOOLBAR_NORMAL
;
109 static GtkWidget
*menu_toolbar
;
111 static GtkWidget
*display_label
;
113 static gboolean o_single_click
= FALSE
;
114 static GtkWidget
*toggle_single_click
;
115 static gboolean o_new_window_on_1
= FALSE
; /* Button 1 => New window */
116 static GtkWidget
*toggle_new_window_on_1
;
117 static GtkWidget
*toggle_menu_on_2
;
118 static GtkWidget
*toggle_unique_filer_windows
;
119 gboolean o_unique_filer_windows
= FALSE
;
121 /* Static prototypes */
122 static void attach(FilerWindow
*filer_window
);
123 static void detach(FilerWindow
*filer_window
);
124 static void filer_window_destroyed(GtkWidget
*widget
,
125 FilerWindow
*filer_window
);
126 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
127 int number_selected
, gpointer user_data
);
128 static gint
focus_in(GtkWidget
*widget
,
129 GdkEventFocus
*event
,
130 FilerWindow
*filer_window
);
131 static gint
focus_out(GtkWidget
*widget
,
132 GdkEventFocus
*event
,
133 FilerWindow
*filer_window
);
134 static void add_item(FilerWindow
*filer_window
, DirItem
*item
);
135 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
136 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
137 static void add_button(GtkWidget
*box
, int pixmap
,
138 GtkSignalFunc cb
, FilerWindow
*filer_window
,
139 char *label
, char *tip
);
140 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
);
141 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
142 FilerWindow
*window
);
143 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
);
144 static void draw_large_icon(GtkWidget
*widget
,
148 static void draw_string(GtkWidget
*widget
,
155 static void draw_item_large(GtkWidget
*widget
,
156 CollectionItem
*item
,
158 static void draw_item_small(GtkWidget
*widget
,
159 CollectionItem
*item
,
161 static void draw_item_full_info(GtkWidget
*widget
,
162 CollectionItem
*colitem
,
164 static gboolean
test_point_large(Collection
*collection
,
165 int point_x
, int point_y
,
166 CollectionItem
*item
,
167 int width
, int height
);
168 static gboolean
test_point_small(Collection
*collection
,
169 int point_x
, int point_y
,
170 CollectionItem
*item
,
171 int width
, int height
);
172 static gboolean
test_point_full_info(Collection
*collection
,
173 int point_x
, int point_y
,
174 CollectionItem
*item
,
175 int width
, int height
);
176 static void update_display(Directory
*dir
,
179 FilerWindow
*filer_window
);
180 static void set_scanning_display(FilerWindow
*filer_window
, gboolean scanning
);
181 static void shrink_width(FilerWindow
*filer_window
);
182 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
);
183 static void open_item(Collection
*collection
,
184 gpointer item_data
, int item_number
,
186 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
);
187 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
);
188 static FilerWindow
*find_filer_window(char *path
, FilerWindow
*diff
);
189 static void filer_set_title(FilerWindow
*filer_window
);
190 static gboolean
exists(FilerWindow
*filer_window
);
192 static GdkAtom xa_string
;
199 static GdkCursor
*busy_cursor
= NULL
;
200 static GtkTooltips
*tooltips
= NULL
;
204 xa_string
= gdk_atom_intern("STRING", FALSE
);
206 options_sections
= g_slist_prepend(options_sections
, &options
);
207 option_register("filer_new_window_on_1", filer_new_window_on_1
);
208 option_register("filer_menu_on_2", filer_menu_on_2
);
209 option_register("filer_single_click", filer_single_click
);
210 option_register("filer_unique_windows", filer_unique_windows
);
211 option_register("filer_toolbar", filer_toolbar
);
212 option_register("filer_display_style", filer_display_style
);
213 option_register("filer_sort_by", filer_sort_by
);
215 busy_cursor
= gdk_cursor_new(GDK_WATCH
);
217 tooltips
= gtk_tooltips_new();
220 static gboolean
if_deleted(gpointer item
, gpointer removed
)
222 int i
= ((GPtrArray
*) removed
)->len
;
223 DirItem
**r
= (DirItem
**) ((GPtrArray
*) removed
)->pdata
;
224 char *leafname
= ((DirItem
*) item
)->leafname
;
228 if (strcmp(leafname
, r
[i
]->leafname
) == 0)
235 static void update_item(FilerWindow
*filer_window
, DirItem
*item
)
238 char *leafname
= item
->leafname
;
240 if (leafname
[0] == '.')
242 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
243 || (leafname
[1] == '.' && leafname
[2] == '\0'))
247 i
= collection_find_item(filer_window
->collection
, item
, dir_item_cmp
);
250 collection_draw_item(filer_window
->collection
, i
, TRUE
);
252 g_warning("Failed to find '%s'\n", item
->leafname
);
255 static void update_display(Directory
*dir
,
258 FilerWindow
*filer_window
)
261 int cursor
= filer_window
->collection
->cursor_item
;
263 Collection
*collection
= filer_window
->collection
;
268 as
= filer_window
->auto_select
;
270 for (i
= 0; i
< items
->len
; i
++)
272 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
274 add_item(filer_window
, item
);
276 if (cursor
!= -1 || !as
)
279 if (strcmp(as
, item
->leafname
) != 0)
282 cursor
= collection
->number_of_items
- 1;
283 if (filer_window
->had_cursor
)
285 collection_set_cursor_item(collection
,
287 filer_window
->mini_cursor_base
= cursor
;
290 collection_wink_item(collection
,
294 collection_qsort(filer_window
->collection
,
295 filer_window
->sort_fn
);
298 collection_delete_if(filer_window
->collection
,
303 set_scanning_display(filer_window
, TRUE
);
306 if (filer_window
->window
->window
)
307 gdk_window_set_cursor(
308 filer_window
->window
->window
,
310 shrink_width(filer_window
);
311 if (filer_window
->had_cursor
&&
312 collection
->cursor_item
== -1)
314 collection_set_cursor_item(collection
, 0);
315 filer_window
->had_cursor
= FALSE
;
317 set_scanning_display(filer_window
, FALSE
);
320 for (i
= 0; i
< items
->len
; i
++)
322 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
324 update_item(filer_window
, item
);
326 collection_qsort(filer_window
->collection
,
327 filer_window
->sort_fn
);
332 static void attach(FilerWindow
*filer_window
)
334 gdk_window_set_cursor(filer_window
->window
->window
, busy_cursor
);
335 collection_clear(filer_window
->collection
);
336 filer_window
->scanning
= TRUE
;
337 dir_attach(filer_window
->directory
, (DirCallback
) update_display
,
339 filer_set_title(filer_window
);
342 static void detach(FilerWindow
*filer_window
)
344 g_return_if_fail(filer_window
->directory
!= NULL
);
346 dir_detach(filer_window
->directory
,
347 (DirCallback
) update_display
, filer_window
);
348 g_fscache_data_unref(dir_cache
, filer_window
->directory
);
349 filer_window
->directory
= NULL
;
352 static void filer_window_destroyed(GtkWidget
*widget
,
353 FilerWindow
*filer_window
)
355 all_filer_windows
= g_list_remove(all_filer_windows
, filer_window
);
357 if (window_with_selection
== filer_window
)
358 window_with_selection
= NULL
;
359 if (window_with_focus
== filer_window
)
360 window_with_focus
= NULL
;
362 if (filer_window
->directory
)
363 detach(filer_window
);
365 g_free(filer_window
->auto_select
);
366 g_free(filer_window
->path
);
367 g_free(filer_window
);
369 if (--number_of_windows
< 1)
373 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
)
375 int pix_width
= item
->image
->width
;
377 switch (filer_window
->display_style
)
380 return MAX_ICON_WIDTH
+ 12 +
381 MAX(item
->details_width
, item
->name_width
);
383 return SMALL_ICON_WIDTH
+ 12 + item
->name_width
;
385 return MAX(pix_width
, item
->name_width
) + 4;
389 /* Add a single object to a directory display */
390 static void add_item(FilerWindow
*filer_window
, DirItem
*item
)
392 char *leafname
= item
->leafname
;
395 if (leafname
[0] == '.')
397 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
398 || (leafname
[1] == '.' && leafname
[2] == '\0'))
402 item_width
= calc_width(filer_window
, item
);
403 if (item_width
> filer_window
->collection
->item_width
)
404 collection_set_item_size(filer_window
->collection
,
406 filer_window
->collection
->item_height
);
407 collection_insert(filer_window
->collection
, item
);
410 /* Is a point inside an item? */
411 static gboolean
test_point_large(Collection
*collection
,
412 int point_x
, int point_y
,
413 CollectionItem
*colitem
,
414 int width
, int height
)
416 DirItem
*item
= (DirItem
*) colitem
->data
;
417 int text_height
= item_font
->ascent
+ item_font
->descent
;
418 MaskedPixmap
*image
= item
->image
;
419 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
420 int image_width
= (image
->width
>> 1) + 2;
421 int text_width
= (item
->name_width
>> 1) + 2;
424 if (point_y
< image_y
)
425 return FALSE
; /* Too high up (don't worry about too low) */
427 if (point_y
<= image_y
+ image
->height
+ 2)
428 x_limit
= image_width
;
429 else if (point_y
> height
- text_height
- 2)
430 x_limit
= text_width
;
432 x_limit
= MIN(image_width
, text_width
);
434 return ABS(point_x
- (width
>> 1)) < x_limit
;
437 static gboolean
test_point_full_info(Collection
*collection
,
438 int point_x
, int point_y
,
439 CollectionItem
*colitem
,
440 int width
, int height
)
442 DirItem
*item
= (DirItem
*) colitem
->data
;
443 MaskedPixmap
*image
= item
->image
;
444 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
446 - fixed_font
->descent
- 2 - fixed_font
->ascent
;
448 if (point_x
< image
->width
+ 2)
449 return point_x
> 2 && point_y
> image_y
;
451 point_x
-= MAX_ICON_WIDTH
+ 8;
453 if (point_y
>= low_top
)
454 return point_x
< item
->details_width
;
455 if (point_y
>= low_top
- item_font
->ascent
- item_font
->descent
)
456 return point_x
< item
->name_width
;
460 static gboolean
test_point_small(Collection
*collection
,
461 int point_x
, int point_y
,
462 CollectionItem
*colitem
,
463 int width
, int height
)
465 DirItem
*item
= (DirItem
*) colitem
->data
;
466 MaskedPixmap
*image
= item
->image
;
467 int image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
469 - fixed_font
->descent
- 2 - item_font
->ascent
;
470 int iwidth
= MIN(SMALL_ICON_WIDTH
, image
->width
);
472 if (point_x
< iwidth
+ 2)
473 return point_x
> 2 && point_y
> image_y
;
475 point_x
-= SMALL_ICON_WIDTH
+ 4;
477 if (point_y
>= low_top
)
478 return point_x
< item
->name_width
;
482 static void draw_small_icon(GtkWidget
*widget
,
487 MaskedPixmap
*image
= item
->image
;
488 int width
= MIN(image
->width
, SMALL_ICON_WIDTH
);
489 int height
= MIN(image
->height
, SMALL_ICON_HEIGHT
);
490 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
492 GdkGC
*gc
= selected
? widget
->style
->white_gc
493 : widget
->style
->black_gc
;
497 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
499 image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
500 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
501 gdk_draw_pixmap(widget
->window
, gc
,
503 0, 0, /* Source x,y */
504 image_x
, area
->y
+ image_y
, /* Dest x,y */
509 gdk_gc_set_function(gc
, GDK_INVERT
);
510 gdk_draw_rectangle(widget
->window
,
512 TRUE
, image_x
, area
->y
+ image_y
,
514 gdk_gc_set_function(gc
, GDK_COPY
);
517 if (item
->flags
& ITEM_FLAG_SYMLINK
)
519 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
520 gdk_gc_set_clip_mask(gc
,
521 default_pixmap
[TYPE_SYMLINK
].mask
);
522 gdk_draw_pixmap(widget
->window
, gc
,
523 default_pixmap
[TYPE_SYMLINK
].pixmap
,
524 0, 0, /* Source x,y */
525 image_x
, area
->y
+ 8, /* Dest x,y */
528 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
530 int type
= item
->flags
& ITEM_FLAG_MOUNTED
533 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
534 gdk_gc_set_clip_mask(gc
,
535 default_pixmap
[type
].mask
);
536 gdk_draw_pixmap(widget
->window
, gc
,
537 default_pixmap
[type
].pixmap
,
538 0, 0, /* Source x,y */
539 image_x
, area
->y
+ 8, /* Dest x,y */
543 gdk_gc_set_clip_mask(gc
, NULL
);
544 gdk_gc_set_clip_origin(gc
, 0, 0);
547 static void draw_large_icon(GtkWidget
*widget
,
552 MaskedPixmap
*image
= item
->image
;
553 int width
= MIN(image
->width
, MAX_ICON_WIDTH
);
554 int height
= MIN(image
->height
, MAX_ICON_WIDTH
);
555 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
557 GdkGC
*gc
= selected
? widget
->style
->white_gc
558 : widget
->style
->black_gc
;
560 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
562 image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
563 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
564 gdk_draw_pixmap(widget
->window
, gc
,
566 0, 0, /* Source x,y */
567 image_x
, area
->y
+ image_y
, /* Dest x,y */
572 gdk_gc_set_function(gc
, GDK_INVERT
);
573 gdk_draw_rectangle(widget
->window
,
575 TRUE
, image_x
, area
->y
+ image_y
,
577 gdk_gc_set_function(gc
, GDK_COPY
);
580 if (item
->flags
& ITEM_FLAG_SYMLINK
)
582 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
583 gdk_gc_set_clip_mask(gc
,
584 default_pixmap
[TYPE_SYMLINK
].mask
);
585 gdk_draw_pixmap(widget
->window
, gc
,
586 default_pixmap
[TYPE_SYMLINK
].pixmap
,
587 0, 0, /* Source x,y */
588 image_x
, area
->y
+ 8, /* Dest x,y */
591 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
593 int type
= item
->flags
& ITEM_FLAG_MOUNTED
596 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
597 gdk_gc_set_clip_mask(gc
,
598 default_pixmap
[type
].mask
);
599 gdk_draw_pixmap(widget
->window
, gc
,
600 default_pixmap
[type
].pixmap
,
601 0, 0, /* Source x,y */
602 image_x
, area
->y
+ 8, /* Dest x,y */
606 gdk_gc_set_clip_mask(gc
, NULL
);
607 gdk_gc_set_clip_origin(gc
, 0, 0);
610 static void draw_string(GtkWidget
*widget
,
618 int text_height
= font
->ascent
+ font
->descent
;
621 gtk_paint_flat_box(widget
->style
, widget
->window
,
622 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
623 NULL
, widget
, "text",
628 gdk_draw_text(widget
->window
,
630 selected
? widget
->style
->white_gc
631 : widget
->style
->black_gc
,
633 string
, strlen(string
));
636 /* Return a string (valid until next call) giving details
639 char *details(DirItem
*item
)
641 mode_t m
= item
->mode
;
642 static GString
*buf
= NULL
;
645 buf
= g_string_new(NULL
);
647 g_string_sprintf(buf
, "%s %s %-8.8s %-8.8s %s %s",
648 item
->flags
& ITEM_FLAG_APPDIR
? "App " :
649 S_ISDIR(m
) ? "Dir " :
650 S_ISCHR(m
) ? "Char" :
651 S_ISBLK(m
) ? "Blck" :
652 S_ISLNK(m
) ? "Link" :
653 S_ISSOCK(m
) ? "Sock" :
654 S_ISFIFO(m
) ? "Pipe" : "File",
655 pretty_permissions(m
),
656 user_name(item
->uid
),
657 group_name(item
->gid
),
658 format_size_aligned(item
->size
),
659 pretty_time(&item
->mtime
));
663 static void draw_item_full_info(GtkWidget
*widget
,
664 CollectionItem
*colitem
,
667 DirItem
*item
= (DirItem
*) colitem
->data
;
668 MaskedPixmap
*image
= item
->image
;
669 int text_x
= area
->x
+ MAX_ICON_WIDTH
+ 8;
670 int low_text_y
= area
->y
+ area
->height
- fixed_font
->descent
- 2;
671 gboolean selected
= colitem
->selected
;
672 GdkRectangle pic_area
;
674 pic_area
.x
= area
->x
;
675 pic_area
.y
= area
->y
;
676 pic_area
.width
= image
->width
+ 8;
677 pic_area
.height
= area
->height
;
679 draw_large_icon(widget
, &pic_area
, item
, selected
);
685 low_text_y
- item_font
->descent
- fixed_font
->ascent
,
694 gdk_draw_rectangle(widget
->window
,
695 selected
? widget
->style
->white_gc
696 : widget
->style
->black_gc
,
698 text_x
- 1 + fixed_width
*
699 (5 + 4 * applicable(item
->uid
, item
->gid
)),
700 low_text_y
+ fixed_font
->descent
- 1,
701 fixed_width
* 3 + 1, 1);
704 static void draw_item_small(GtkWidget
*widget
,
705 CollectionItem
*colitem
,
708 DirItem
*item
= (DirItem
*) colitem
->data
;
709 int text_x
= area
->x
+ SMALL_ICON_WIDTH
+ 4;
710 int low_text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
711 gboolean selected
= colitem
->selected
;
712 GdkRectangle pic_area
;
714 pic_area
.x
= area
->x
;
715 pic_area
.y
= area
->y
;
716 pic_area
.width
= SMALL_ICON_WIDTH
;
717 pic_area
.height
= SMALL_ICON_HEIGHT
;
719 draw_small_icon(widget
, &pic_area
, item
, selected
);
730 static void draw_item_large(GtkWidget
*widget
,
731 CollectionItem
*colitem
,
734 DirItem
*item
= (DirItem
*) colitem
->data
;
735 int text_x
= area
->x
+ ((area
->width
- item
->name_width
) >> 1);
736 int text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
737 gboolean selected
= colitem
->selected
;
739 draw_large_icon(widget
, area
, item
, selected
);
744 text_x
, text_y
, item
->name_width
,
748 static void show_menu(Collection
*collection
, GdkEventButton
*event
,
749 int item
, gpointer user_data
)
751 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
754 /* Returns TRUE iff the directory still exists. */
755 static gboolean
may_rescan(FilerWindow
*filer_window
, gboolean warning
)
759 g_return_val_if_fail(filer_window
!= NULL
, FALSE
);
761 /* We do a fresh lookup (rather than update) because the inode may
764 dir
= g_fscache_lookup(dir_cache
, filer_window
->path
);
768 delayed_error("ROX-Filer", "Directory missing/deleted");
769 gtk_widget_destroy(filer_window
->window
);
772 if (dir
== filer_window
->directory
)
773 g_fscache_data_unref(dir_cache
, dir
);
776 detach(filer_window
);
777 filer_window
->directory
= dir
;
778 attach(filer_window
);
784 /* Another app has grabbed the selection */
785 static gint
collection_lose_selection(GtkWidget
*widget
,
786 GdkEventSelection
*event
)
788 if (window_with_selection
&&
789 window_with_selection
->collection
== COLLECTION(widget
))
791 FilerWindow
*filer_window
= window_with_selection
;
792 window_with_selection
= NULL
;
793 collection_clear_selection(filer_window
->collection
);
799 /* Someone wants us to send them the selection */
800 static void selection_get(GtkWidget
*widget
,
801 GtkSelectionData
*selection_data
,
806 GString
*reply
, *header
;
807 FilerWindow
*filer_window
;
809 Collection
*collection
;
811 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
813 reply
= g_string_new(NULL
);
814 header
= g_string_new(NULL
);
819 g_string_sprintf(header
, " %s",
820 make_path(filer_window
->path
, "")->str
);
822 case TARGET_URI_LIST
:
823 g_string_sprintf(header
, " file://%s%s",
825 make_path(filer_window
->path
, "")->str
);
829 collection
= filer_window
->collection
;
830 for (i
= 0; i
< collection
->number_of_items
; i
++)
832 if (collection
->items
[i
].selected
)
835 (DirItem
*) collection
->items
[i
].data
;
837 g_string_append(reply
, header
->str
);
838 g_string_append(reply
, item
->leafname
);
841 /* This works, but I don't think I like it... */
842 /* g_string_append_c(reply, ' '); */
844 gtk_selection_data_set(selection_data
, xa_string
,
845 8, reply
->str
+ 1, reply
->len
- 1);
846 g_string_free(reply
, TRUE
);
847 g_string_free(header
, TRUE
);
850 /* No items are now selected. This might be because another app claimed
851 * the selection or because the user unselected all the items.
853 static void lose_selection(Collection
*collection
,
857 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
859 if (window_with_selection
== filer_window
)
861 window_with_selection
= NULL
;
862 gtk_selection_owner_set(NULL
,
863 GDK_SELECTION_PRIMARY
,
868 static void gain_selection(Collection
*collection
,
872 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
874 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
875 GDK_SELECTION_PRIMARY
,
878 window_with_selection
= filer_window
;
881 collection_clear_selection(filer_window
->collection
);
884 int sort_by_name(const void *item1
, const void *item2
)
886 return strcmp((*((DirItem
**)item1
))->leafname
,
887 (*((DirItem
**)item2
))->leafname
);
890 int sort_by_type(const void *item1
, const void *item2
)
892 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
893 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
896 int diff
= i1
->base_type
- i2
->base_type
;
899 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
900 - (i2
->flags
& ITEM_FLAG_APPDIR
);
902 return diff
> 0 ? 1 : -1;
909 diff
= strcmp(m1
->media_type
, m2
->media_type
);
911 diff
= strcmp(m1
->subtype
, m2
->subtype
);
919 return diff
> 0 ? 1 : -1;
921 return sort_by_name(item1
, item2
);
924 int sort_by_date(const void *item1
, const void *item2
)
926 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
927 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
929 return i1
->mtime
> i2
->mtime
? -1 :
930 i1
->mtime
< i2
->mtime
? 1 :
931 sort_by_name(item1
, item2
);
934 int sort_by_size(const void *item1
, const void *item2
)
936 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
937 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
939 return i1
->size
> i2
->size
? -1 :
940 i1
->size
< i2
->size
? 1 :
941 sort_by_name(item1
, item2
);
944 static void open_item(Collection
*collection
,
945 gpointer item_data
, int item_number
,
948 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
950 GdkEventButton
*bevent
;
954 event
= (GdkEvent
*) gtk_get_current_event();
956 bevent
= (GdkEventButton
*) event
;
957 kevent
= (GdkEventKey
*) event
;
961 case GDK_2BUTTON_PRESS
:
962 case GDK_BUTTON_PRESS
:
963 case GDK_BUTTON_RELEASE
:
964 if (bevent
->state
& GDK_SHIFT_MASK
)
967 if (o_new_window_on_1
^ (bevent
->button
== 1))
968 flags
|= OPEN_SAME_WINDOW
;
970 if (bevent
->button
!= 1)
971 flags
|= OPEN_CLOSE_WINDOW
;
973 if (o_single_click
== FALSE
&&
974 (bevent
->state
& GDK_CONTROL_MASK
) != 0)
975 flags
^= OPEN_SAME_WINDOW
| OPEN_CLOSE_WINDOW
;
978 flags
|= OPEN_SAME_WINDOW
;
979 if (kevent
->state
& GDK_SHIFT_MASK
)
986 filer_openitem(filer_window
, item_number
, flags
);
989 /* Return the full path to the directory containing object 'path'.
990 * Relative paths are resolved from the filerwindow's path.
992 static void follow_symlink(FilerWindow
*filer_window
, char *path
,
993 gboolean same_window
)
999 path
= make_path(filer_window
->path
, path
)->str
;
1001 real
= pathdup(path
);
1002 slash
= strrchr(real
, '/');
1006 delayed_error("ROX-Filer",
1007 "Broken symlink (or you don't have permission "
1019 if (filer_window
->panel_type
|| !same_window
)
1023 new = filer_opendir(new_dir
, PANEL_NO
);
1024 set_autoselect(new, slash
+ 1);
1027 filer_change_to(filer_window
, new_dir
, slash
+ 1);
1032 void filer_openitem(FilerWindow
*filer_window
, int item_number
, OpenFlags flags
)
1034 gboolean shift
= (flags
& OPEN_SHIFT
) != 0;
1035 gboolean close_mini
= flags
& OPEN_FROM_MINI
;
1036 gboolean same_window
= (flags
& OPEN_SAME_WINDOW
) != 0
1037 && !filer_window
->panel_type
;
1038 gboolean close_window
= (flags
& OPEN_CLOSE_WINDOW
) != 0
1039 && !filer_window
->panel_type
;
1042 DirItem
*item
= (DirItem
*)
1043 filer_window
->collection
->items
[item_number
].data
;
1044 gboolean wink
= TRUE
, destroy
= FALSE
;
1046 widget
= filer_window
->window
;
1047 full_path
= make_path(filer_window
->path
,
1048 item
->leafname
)->str
;
1050 if (item
->flags
& ITEM_FLAG_SYMLINK
&& shift
)
1052 char path
[MAXPATHLEN
+ 1];
1055 got
= readlink(make_path(filer_window
->path
,
1056 item
->leafname
)->str
,
1059 delayed_error("ROX-Filer", g_strerror(errno
));
1062 g_return_if_fail(got
<= MAXPATHLEN
);
1065 follow_symlink(filer_window
, path
,
1066 flags
& OPEN_SAME_WINDOW
);
1071 switch (item
->base_type
)
1073 case TYPE_DIRECTORY
:
1074 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
1076 run_app(make_path(filer_window
->path
,
1077 item
->leafname
)->str
);
1083 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
&& shift
)
1085 action_mount(filer_window
, item
);
1086 if (item
->flags
& ITEM_FLAG_MOUNTED
)
1093 filer_change_to(filer_window
, full_path
, NULL
);
1097 filer_opendir(full_path
, PANEL_NO
);
1100 if ((item
->flags
& ITEM_FLAG_EXEC_FILE
) && !shift
)
1102 char *argv
[] = {NULL
, NULL
};
1104 argv
[0] = full_path
;
1106 if (spawn_full(argv
, filer_window
->path
))
1112 report_error("ROX-Filer",
1113 "Failed to fork() child");
1118 MIME_type
*type
= shift
? &text_plain
1121 g_return_if_fail(type
!= NULL
);
1123 if (type_open(full_path
, type
))
1130 message
= g_string_new(NULL
);
1131 g_string_sprintf(message
, "No open "
1132 "action specified for files of "
1133 "this type (%s/%s)",
1136 report_error("ROX-Filer", message
->str
);
1137 g_string_free(message
, TRUE
);
1142 report_error("open_item",
1143 "I don't know how to open that");
1148 gtk_widget_destroy(filer_window
->window
);
1152 collection_wink_item(filer_window
->collection
,
1155 minibuffer_hide(filer_window
);
1159 static gint
pointer_in(GtkWidget
*widget
,
1160 GdkEventCrossing
*event
,
1161 FilerWindow
*filer_window
)
1163 may_rescan(filer_window
, TRUE
);
1167 static gint
focus_in(GtkWidget
*widget
,
1168 GdkEventFocus
*event
,
1169 FilerWindow
*filer_window
)
1171 window_with_focus
= filer_window
;
1176 static gint
focus_out(GtkWidget
*widget
,
1177 GdkEventFocus
*event
,
1178 FilerWindow
*filer_window
)
1180 /* TODO: Shade the cursor */
1185 /* Handle keys that can't be bound with the menu */
1186 static gint
key_press_event(GtkWidget
*widget
,
1188 FilerWindow
*filer_window
)
1190 switch (event
->keyval
)
1193 change_to_parent(filer_window
);
1202 static void toolbar_refresh_clicked(GtkWidget
*widget
,
1203 FilerWindow
*filer_window
)
1206 update_dir(filer_window
, TRUE
);
1209 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1211 filer_change_to(filer_window
, home_dir
, NULL
);
1214 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
1216 change_to_parent(filer_window
);
1219 void change_to_parent(FilerWindow
*filer_window
)
1224 if (filer_window
->path
[0] == '/' && filer_window
->path
[1] == '\0')
1225 return; /* Already in the root */
1227 copy
= g_strdup(filer_window
->path
);
1228 slash
= strrchr(copy
, '/');
1233 filer_change_to(filer_window
,
1238 g_warning("No / in directory path!\n");
1244 /* Make filer_window display path. When finished, highlight item 'from', or
1245 * the first item if from is NULL. If there is currently no cursor then
1246 * simply wink 'from' (if not NULL).
1248 void filer_change_to(FilerWindow
*filer_window
, char *path
, char *from
)
1251 char *real_path
= pathdup(path
);
1253 if (o_unique_filer_windows
)
1257 fw
= find_filer_window(real_path
, filer_window
);
1259 gtk_widget_destroy(fw
->window
);
1262 from_dup
= from
&& *from
? g_strdup(from
) : NULL
;
1264 detach(filer_window
);
1265 g_free(filer_window
->path
);
1266 filer_window
->path
= real_path
;
1268 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1269 filer_window
->path
);
1270 if (filer_window
->directory
)
1272 g_free(filer_window
->auto_select
);
1273 filer_window
->had_cursor
=
1274 filer_window
->collection
->cursor_item
!= -1
1275 || filer_window
->had_cursor
;
1276 filer_window
->auto_select
= from_dup
;
1278 filer_set_title(filer_window
);
1279 collection_set_cursor_item(filer_window
->collection
, -1);
1280 attach(filer_window
);
1282 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer
))
1283 gtk_idle_add((GtkFunction
) minibuffer_show_cb
,
1291 error
= g_strdup_printf("Directory '%s' is not accessible.",
1293 delayed_error("ROX-Filer", error
);
1295 gtk_widget_destroy(filer_window
->window
);
1299 int selected_item_number(Collection
*collection
)
1303 g_return_val_if_fail(collection
!= NULL
, -1);
1304 g_return_val_if_fail(IS_COLLECTION(collection
), -1);
1305 g_return_val_if_fail(collection
->number_selected
== 1, -1);
1307 for (i
= 0; i
< collection
->number_of_items
; i
++)
1308 if (collection
->items
[i
].selected
)
1311 g_warning("selected_item: number_selected is wrong\n");
1316 DirItem
*selected_item(Collection
*collection
)
1320 item
= selected_item_number(collection
);
1323 return (DirItem
*) collection
->items
[item
].data
;
1327 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
1328 FilerWindow
*window
)
1330 /* TODO: We can open lots of these - very irritating! */
1331 return get_choice("Close panel?",
1332 "You have tried to close a panel via the window "
1333 "manager - I usually find that this is accidental... "
1335 2, "Remove", "Cancel") != 0;
1338 /* Make the items as narrow as possible */
1339 static void shrink_width(FilerWindow
*filer_window
)
1342 Collection
*col
= filer_window
->collection
;
1343 int width
= MIN_ITEM_WIDTH
;
1345 DisplayStyle style
= filer_window
->display_style
;
1348 text_height
= item_font
->ascent
+ item_font
->descent
;
1350 for (i
= 0; i
< col
->number_of_items
; i
++)
1352 this_width
= calc_width(filer_window
,
1353 (DirItem
*) col
->items
[i
].data
);
1354 if (this_width
> width
)
1358 collection_set_item_size(filer_window
->collection
,
1360 style
== FULL_INFO
? MAX_ICON_HEIGHT
+ 4 :
1361 style
== SMALL_ICONS
? MAX(text_height
, SMALL_ICON_HEIGHT
) + 4
1362 : text_height
+ MAX_ICON_HEIGHT
+ 8);
1365 void filer_set_sort_fn(FilerWindow
*filer_window
,
1366 int (*fn
)(const void *a
, const void *b
))
1368 if (filer_window
->sort_fn
== fn
)
1371 filer_window
->sort_fn
= fn
;
1374 collection_qsort(filer_window
->collection
,
1375 filer_window
->sort_fn
);
1377 update_options_label();
1380 void filer_style_set(FilerWindow
*filer_window
, DisplayStyle style
)
1382 if (filer_window
->display_style
== style
)
1385 if (filer_window
->panel_type
)
1386 style
= LARGE_ICONS
;
1388 last_display_style
= style
;
1390 filer_window
->display_style
= style
;
1395 collection_set_functions(filer_window
->collection
,
1396 draw_item_small
, test_point_small
);
1399 collection_set_functions(filer_window
->collection
,
1400 draw_item_full_info
, test_point_full_info
);
1403 collection_set_functions(filer_window
->collection
,
1404 draw_item_large
, test_point_large
);
1408 shrink_width(filer_window
);
1410 update_options_label();
1413 FilerWindow
*filer_opendir(char *path
, PanelType panel_type
)
1415 GtkWidget
*hbox
, *scrollbar
, *collection
;
1416 FilerWindow
*filer_window
;
1417 GtkTargetEntry target_table
[] =
1419 {"text/uri-list", 0, TARGET_URI_LIST
},
1420 {"STRING", 0, TARGET_STRING
},
1424 real_path
= pathdup(path
);
1426 if (o_unique_filer_windows
&& panel_type
== PANEL_NO
)
1430 fw
= find_filer_window(real_path
, NULL
);
1434 /* TODO: this should bring the window to the front
1435 * at the same coordinates.
1437 gtk_widget_hide(fw
->window
);
1438 gtk_widget_show(fw
->window
);
1444 filer_window
= g_new(FilerWindow
, 1);
1445 filer_window
->minibuffer
= NULL
;
1446 filer_window
->path
= real_path
;
1447 filer_window
->scanning
= FALSE
;
1448 filer_window
->had_cursor
= FALSE
;
1449 filer_window
->auto_select
= NULL
;
1451 filer_window
->directory
= g_fscache_lookup(dir_cache
,
1452 filer_window
->path
);
1453 if (!filer_window
->directory
)
1457 error
= g_strdup_printf("Directory '%s' not found.", path
);
1458 delayed_error("ROX-Filer", error
);
1460 g_free(filer_window
->path
);
1461 g_free(filer_window
);
1465 filer_window
->show_hidden
= last_show_hidden
;
1466 filer_window
->panel_type
= panel_type
;
1467 filer_window
->temp_item_selected
= FALSE
;
1468 filer_window
->sort_fn
= last_sort_fn
;
1469 filer_window
->flags
= (FilerFlags
) 0;
1470 filer_window
->display_style
= UNKNOWN_STYLE
;
1472 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
1473 filer_set_title(filer_window
);
1475 collection
= collection_new(NULL
);
1476 gtk_object_set_data(GTK_OBJECT(collection
),
1477 "filer_window", filer_window
);
1478 filer_window
->collection
= COLLECTION(collection
);
1480 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
1481 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1482 "enter-notify-event",
1483 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
1484 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
1485 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
1486 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
1487 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
1488 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
1489 filer_window_destroyed
, filer_window
);
1491 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
1492 open_item
, filer_window
);
1493 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
1494 show_menu
, filer_window
);
1495 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
1496 gain_selection
, filer_window
);
1497 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
1498 lose_selection
, filer_window
);
1499 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
1500 drag_selection
, filer_window
);
1501 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
1502 drag_data_get
, filer_window
);
1503 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
1504 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
1505 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
1506 GTK_SIGNAL_FUNC(selection_get
), NULL
);
1507 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
1509 sizeof(target_table
) / sizeof(*target_table
));
1511 filer_style_set(filer_window
, last_display_style
);
1512 drag_set_dest(filer_window
);
1516 int swidth
, sheight
, iwidth
, iheight
;
1517 GtkWidget
*frame
, *win
= filer_window
->window
;
1519 gtk_window_set_wmclass(GTK_WINDOW(win
), "ROX-Panel",
1521 collection_set_panel(filer_window
->collection
, TRUE
);
1522 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1524 GTK_SIGNAL_FUNC(filer_confirm_close
),
1527 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
1528 iwidth
= filer_window
->collection
->item_width
;
1529 iheight
= filer_window
->collection
->item_height
;
1532 int height
= iheight
+ PANEL_BORDER
;
1533 int y
= panel_type
== PANEL_TOP
1535 : sheight
- height
- PANEL_BORDER
;
1537 gtk_widget_set_usize(collection
, swidth
, height
);
1538 gtk_widget_set_uposition(win
, 0, y
);
1541 frame
= gtk_frame_new(NULL
);
1542 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1543 gtk_container_add(GTK_CONTAINER(frame
), collection
);
1544 gtk_container_add(GTK_CONTAINER(win
), frame
);
1546 gtk_widget_show_all(frame
);
1547 gtk_widget_realize(win
);
1548 if (override_redirect
)
1549 gdk_window_set_override_redirect(win
->window
, TRUE
);
1550 make_panel_window(win
->window
);
1555 int col_height
= ROW_HEIGHT_LARGE
* 3;
1557 gtk_signal_connect(GTK_OBJECT(collection
),
1559 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
1560 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
1561 filer_window
->display_style
== LARGE_ICONS
? 400 : 512,
1562 o_toolbar
== TOOLBAR_NONE
? col_height
:
1563 o_toolbar
== TOOLBAR_NORMAL
? col_height
+ 24 :
1566 hbox
= gtk_hbox_new(FALSE
, 0);
1567 gtk_container_add(GTK_CONTAINER(filer_window
->window
),
1570 vbox
= gtk_vbox_new(FALSE
, 0);
1571 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, TRUE
, TRUE
, 0);
1573 if (o_toolbar
!= TOOLBAR_NONE
)
1577 toolbar
= create_toolbar(filer_window
);
1578 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
,
1580 gtk_widget_show_all(toolbar
);
1583 gtk_box_pack_start(GTK_BOX(vbox
), collection
, TRUE
, TRUE
, 0);
1585 filer_window
->minibuffer
= create_minibuffer(filer_window
);
1586 gtk_box_pack_start(GTK_BOX(vbox
), filer_window
->minibuffer
,
1589 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
1590 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
1591 gtk_accel_group_attach(filer_keys
,
1592 GTK_OBJECT(filer_window
->window
));
1593 gtk_window_set_focus(GTK_WINDOW(filer_window
->window
),
1596 gtk_widget_show(hbox
);
1597 gtk_widget_show(vbox
);
1598 gtk_widget_show(scrollbar
);
1599 gtk_widget_show(collection
);
1602 number_of_windows
++;
1603 gtk_widget_show(filer_window
->window
);
1604 attach(filer_window
);
1606 all_filer_windows
= g_list_prepend(all_filer_windows
, filer_window
);
1608 return filer_window
;
1611 static gint
clear_scanning_display(FilerWindow
*filer_window
)
1613 if (exists(filer_window
))
1614 filer_set_title(filer_window
);
1618 static void set_scanning_display(FilerWindow
*filer_window
, gboolean scanning
)
1620 if (scanning
== filer_window
->scanning
)
1622 filer_window
->scanning
= scanning
;
1625 filer_set_title(filer_window
);
1627 gtk_timeout_add(300, (GtkFunction
) clear_scanning_display
,
1631 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
)
1633 GtkWidget
*frame
, *box
;
1635 if (o_toolbar
== TOOLBAR_GNOME
)
1637 frame
= gtk_handle_box_new();
1638 box
= gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL
,
1640 gtk_container_set_border_width(GTK_CONTAINER(box
), 2);
1641 gtk_toolbar_set_space_style(GTK_TOOLBAR(box
),
1642 GTK_TOOLBAR_SPACE_LINE
);
1643 gtk_toolbar_set_button_relief(GTK_TOOLBAR(box
),
1648 frame
= gtk_frame_new(NULL
);
1649 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1651 box
= gtk_hbutton_box_new();
1652 gtk_button_box_set_child_size_default(16, 16);
1653 gtk_hbutton_box_set_spacing_default(2);
1654 gtk_button_box_set_layout(GTK_BUTTON_BOX(box
),
1655 GTK_BUTTONBOX_START
);
1658 gtk_container_add(GTK_CONTAINER(frame
), box
);
1660 add_button(box
, TOOLBAR_UP_ICON
,
1661 GTK_SIGNAL_FUNC(toolbar_up_clicked
),
1663 "Up", "Change to parent directory");
1664 add_button(box
, TOOLBAR_HOME_ICON
,
1665 GTK_SIGNAL_FUNC(toolbar_home_clicked
),
1667 "Home", "Change to home directory");
1668 add_button(box
, TOOLBAR_REFRESH_ICON
,
1669 GTK_SIGNAL_FUNC(toolbar_refresh_clicked
),
1671 "Rescan", "Rescan directory contents");
1676 static void add_button(GtkWidget
*box
, int pixmap
,
1677 GtkSignalFunc cb
, FilerWindow
*filer_window
,
1678 char *label
, char *tip
)
1680 GtkWidget
*button
, *icon
;
1682 icon
= gtk_pixmap_new(default_pixmap
[pixmap
].pixmap
,
1683 default_pixmap
[pixmap
].mask
);
1685 if (o_toolbar
== TOOLBAR_GNOME
)
1687 gtk_toolbar_append_element(GTK_TOOLBAR(box
),
1688 GTK_TOOLBAR_CHILD_BUTTON
,
1697 button
= gtk_button_new();
1698 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
1700 gtk_container_add(GTK_CONTAINER(button
), icon
);
1701 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1704 gtk_tooltips_set_tip(tooltips
, button
, tip
, NULL
);
1706 gtk_container_add(GTK_CONTAINER(box
), button
);
1710 /* Build up some option widgets to go in the options dialog, but don't
1713 static GtkWidget
*create_options()
1715 GtkWidget
*vbox
, *menu
, *hbox
;
1717 vbox
= gtk_vbox_new(FALSE
, 0);
1718 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
1720 display_label
= gtk_label_new("<>");
1721 gtk_label_set_line_wrap(GTK_LABEL(display_label
), TRUE
);
1722 gtk_box_pack_start(GTK_BOX(vbox
), display_label
, FALSE
, TRUE
, 0);
1724 toggle_new_window_on_1
=
1725 gtk_check_button_new_with_label("New window on button 1 "
1727 gtk_box_pack_start(GTK_BOX(vbox
), toggle_new_window_on_1
,
1731 gtk_check_button_new_with_label("Menu on button 2 "
1733 gtk_box_pack_start(GTK_BOX(vbox
), toggle_menu_on_2
, FALSE
, TRUE
, 0);
1735 toggle_single_click
=
1736 gtk_check_button_new_with_label("Single-click nagivation");
1737 gtk_box_pack_start(GTK_BOX(vbox
), toggle_single_click
, FALSE
, TRUE
, 0);
1739 toggle_unique_filer_windows
=
1740 gtk_check_button_new_with_label("Unique windows");
1741 gtk_box_pack_start(GTK_BOX(vbox
), toggle_unique_filer_windows
, FALSE
, TRUE
, 0);
1743 hbox
= gtk_hbox_new(FALSE
, 4);
1744 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
1746 gtk_box_pack_start(GTK_BOX(hbox
),
1747 gtk_label_new("Toolbar type for new windows"),
1749 menu_toolbar
= gtk_option_menu_new();
1750 menu
= gtk_menu_new();
1751 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("None"));
1752 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("Normal"));
1753 gtk_menu_append(GTK_MENU(menu
), gtk_menu_item_new_with_label("GNOME"));
1754 gtk_option_menu_set_menu(GTK_OPTION_MENU(menu_toolbar
), menu
);
1755 gtk_box_pack_start(GTK_BOX(hbox
), menu_toolbar
, TRUE
, TRUE
, 0);
1760 static void update_options_label(void)
1764 str
= g_strdup_printf("The last used display style (%s) and sort "
1765 "function (Sort By %s) will be saved if you click on "
1766 "Save.", style_to_name(), sort_fn_to_name());
1767 gtk_label_set_text(GTK_LABEL(display_label
), str
);
1771 /* Reflect current state by changing the widgets in the options box */
1772 static void update_options()
1774 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_new_window_on_1
),
1776 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_menu_on_2
),
1777 collection_menu_button
== 2 ? 1 : 0);
1778 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_single_click
),
1780 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_unique_filer_windows
),
1781 o_unique_filer_windows
);
1782 gtk_option_menu_set_history(GTK_OPTION_MENU(menu_toolbar
), o_toolbar
);
1784 update_options_label();
1787 /* Set current values by reading the states of the widgets in the options box */
1788 static void set_options()
1790 GtkWidget
*item
, *menu
;
1793 o_new_window_on_1
= gtk_toggle_button_get_active(
1794 GTK_TOGGLE_BUTTON(toggle_new_window_on_1
));
1796 collection_menu_button
= gtk_toggle_button_get_active(
1797 GTK_TOGGLE_BUTTON(toggle_menu_on_2
)) ? 2 : 3;
1799 o_single_click
= gtk_toggle_button_get_active(
1800 GTK_TOGGLE_BUTTON(toggle_single_click
));
1802 o_unique_filer_windows
= gtk_toggle_button_get_active(
1803 GTK_TOGGLE_BUTTON(toggle_unique_filer_windows
));
1805 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1807 menu
= gtk_option_menu_get_menu(GTK_OPTION_MENU(menu_toolbar
));
1808 item
= gtk_menu_get_active(GTK_MENU(menu
));
1809 list
= gtk_container_children(GTK_CONTAINER(menu
));
1810 o_toolbar
= (ToolbarType
) g_list_index(list
, item
);
1815 static guchar
*style_to_name(void)
1817 return last_display_style
== LARGE_ICONS
? "Large Icons" :
1818 last_display_style
== SMALL_ICONS
? "Small Icons" :
1822 static guchar
*sort_fn_to_name(void)
1824 return last_sort_fn
== sort_by_name
? "Name" :
1825 last_sort_fn
== sort_by_type
? "Type" :
1826 last_sort_fn
== sort_by_date
? "Date" :
1830 static void save_options()
1832 option_write("filer_new_window_on_1", o_new_window_on_1
? "1" : "0");
1833 option_write("filer_menu_on_2",
1834 collection_menu_button
== 2 ? "1" : "0");
1835 option_write("filer_single_click", o_single_click
? "1" : "0");
1836 option_write("filer_unique_windows", o_unique_filer_windows
? "1" : "0");
1837 option_write("filer_display_style", style_to_name());
1838 option_write("filer_sort_by", sort_fn_to_name());
1839 option_write("filer_toolbar", o_toolbar
== TOOLBAR_NONE
? "None" :
1840 o_toolbar
== TOOLBAR_NORMAL
? "Normal" :
1841 o_toolbar
== TOOLBAR_GNOME
? "GNOME" :
1845 static char *filer_new_window_on_1(char *data
)
1847 o_new_window_on_1
= atoi(data
) != 0;
1851 static char *filer_menu_on_2(char *data
)
1853 collection_menu_button
= atoi(data
) != 0 ? 2 : 3;
1857 static char *filer_single_click(char *data
)
1859 o_single_click
= atoi(data
) != 0;
1860 collection_single_click
= o_single_click
? TRUE
: FALSE
;
1864 static char *filer_unique_windows(char *data
)
1866 o_unique_filer_windows
= atoi(data
) != 0;
1870 static char *filer_display_style(char *data
)
1872 if (g_strcasecmp(data
, "Large Icons") == 0)
1873 last_display_style
= LARGE_ICONS
;
1874 else if (g_strcasecmp(data
, "Small Icons") == 0)
1875 last_display_style
= SMALL_ICONS
;
1876 else if (g_strcasecmp(data
, "Full Info") == 0)
1877 last_display_style
= FULL_INFO
;
1879 return "Unknown display style";
1884 static char *filer_sort_by(char *data
)
1886 if (g_strcasecmp(data
, "Name") == 0)
1887 last_sort_fn
= sort_by_name
;
1888 else if (g_strcasecmp(data
, "Type") == 0)
1889 last_sort_fn
= sort_by_type
;
1890 else if (g_strcasecmp(data
, "Date") == 0)
1891 last_sort_fn
= sort_by_date
;
1892 else if (g_strcasecmp(data
, "Size") == 0)
1893 last_sort_fn
= sort_by_size
;
1895 return "Unknown sort type";
1900 static char *filer_toolbar(char *data
)
1902 if (g_strcasecmp(data
, "None") == 0)
1903 o_toolbar
= TOOLBAR_NONE
;
1904 else if (g_strcasecmp(data
, "Normal") == 0)
1905 o_toolbar
= TOOLBAR_NORMAL
;
1906 else if (g_strcasecmp(data
, "GNOME") == 0)
1907 o_toolbar
= TOOLBAR_GNOME
;
1909 return "Unknown toolbar type";
1914 /* Note that filer_window may not exist after this call. */
1915 void update_dir(FilerWindow
*filer_window
, gboolean warning
)
1917 if (may_rescan(filer_window
, warning
))
1918 dir_update(filer_window
->directory
, filer_window
->path
);
1921 void filer_set_hidden(FilerWindow
*filer_window
, gboolean hidden
)
1923 Directory
*dir
= filer_window
->directory
;
1925 if (filer_window
->show_hidden
== hidden
)
1928 filer_window
->show_hidden
= hidden
;
1929 last_show_hidden
= hidden
;
1931 g_fscache_data_ref(dir_cache
, dir
);
1932 detach(filer_window
);
1933 filer_window
->directory
= dir
;
1934 attach(filer_window
);
1937 /* Refresh the various caches even if we don't think we need to */
1938 void full_refresh(void)
1943 /* See whether a filer window with a given path already exists
1944 * and is different from diff.
1946 static FilerWindow
*find_filer_window(char *path
, FilerWindow
*diff
)
1948 GList
*next
= all_filer_windows
;
1952 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
1954 if (filer_window
->panel_type
== PANEL_NO
&&
1955 filer_window
!= diff
&&
1956 strcmp(path
, filer_window
->path
) == 0)
1958 return filer_window
;
1967 /* This path has been mounted/umounted/deleted some files - update all dirs */
1968 void filer_check_mounted(char *path
)
1970 GList
*next
= all_filer_windows
;
1977 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
1981 if (strncmp(path
, filer_window
->path
, len
) == 0)
1983 char s
= filer_window
->path
[len
];
1985 if (s
== '/' || s
== '\0')
1986 update_dir(filer_window
, FALSE
);
1991 /* Like minibuffer_show(), except that:
1992 * - It returns FALSE (to be used from an idle callback)
1993 * - It checks that the filer window still exists.
1995 static gboolean
minibuffer_show_cb(FilerWindow
*filer_window
)
1997 if (exists(filer_window
))
1998 minibuffer_show(filer_window
);
2002 static gboolean
exists(FilerWindow
*filer_window
)
2006 for (next
= all_filer_windows
; next
; next
= next
->next
)
2008 FilerWindow
*fw
= (FilerWindow
*) next
->data
;
2010 if (fw
== filer_window
)
2017 /* Highlight (wink or cursor) this item in the filer window. If the item
2018 * isn't already there but we're scanning then highlight it if it
2021 static void set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
)
2023 Collection
*col
= filer_window
->collection
;
2026 g_free(filer_window
->auto_select
);
2027 filer_window
->auto_select
= NULL
;
2029 for (i
= 0; i
< col
->number_of_items
; i
++)
2031 DirItem
*item
= (DirItem
*) col
->items
[i
].data
;
2033 if (strcmp(item
->leafname
, leaf
) == 0)
2035 if (col
->cursor_item
!= -1)
2036 collection_set_cursor_item(col
, i
);
2038 collection_wink_item(col
, i
);
2043 filer_window
->auto_select
= g_strdup(leaf
);
2046 static void filer_set_title(FilerWindow
*filer_window
)
2048 if (filer_window
->scanning
)
2052 title
= g_strdup_printf("%s (Scanning)", filer_window
->path
);
2053 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
2058 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
2059 filer_window
->path
);