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 */
33 #include <gdk/gdkkeysyms.h>
34 #include "collection.h"
38 #include "gui_support.h"
48 #define ROW_HEIGHT_LARGE 64
49 #define ROW_HEIGHT_FULL_INFO 44
50 #define MAX_ICON_HEIGHT 42
51 #define PANEL_BORDER 2
52 #define MIN_ITEM_WIDTH 64
54 FilerWindow
*window_with_focus
= NULL
;
55 GdkFont
*fixed_font
= NULL
;
57 static FilerWindow
*window_with_selection
= NULL
;
60 static GtkWidget
*create_options();
61 static void update_options();
62 static void set_options();
63 static void save_options();
64 static char *filer_ro_bindings(char *data
);
65 static char *filer_toolbar(char *data
);
67 static OptionsSection options
=
69 "Filer window options",
75 static gboolean o_toolbar
= TRUE
;
76 static GtkWidget
*toggle_toolbar
;
77 static gboolean o_ro_bindings
= FALSE
;
78 static GtkWidget
*toggle_ro_bindings
;
80 /* Static prototypes */
81 static void detach(FilerWindow
*filer_window
);
82 static void filer_window_destroyed(GtkWidget
*widget
,
83 FilerWindow
*filer_window
);
84 void show_menu(Collection
*collection
, GdkEventButton
*event
,
85 int number_selected
, gpointer user_data
);
86 static int sort_by_name(const void *item1
, const void *item2
);
87 static gint
focus_in(GtkWidget
*widget
,
89 FilerWindow
*filer_window
);
90 static gint
focus_out(GtkWidget
*widget
,
92 FilerWindow
*filer_window
);
93 static void add_item(FilerWindow
*filer_window
, DirItem
*item
);
94 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
95 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
);
96 static void add_button(GtkContainer
*box
, int pixmap
,
97 GtkSignalFunc cb
, gpointer data
);
98 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
);
99 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
100 FilerWindow
*window
);
101 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
);
102 static void draw_large_icon(GtkWidget
*widget
,
106 static void draw_string(GtkWidget
*widget
,
113 static void draw_item_large(GtkWidget
*widget
,
114 CollectionItem
*item
,
116 static void draw_item_full_info(GtkWidget
*widget
,
117 CollectionItem
*colitem
,
119 static gboolean
test_point_large(Collection
*collection
,
120 int point_x
, int point_y
,
121 CollectionItem
*item
,
122 int width
, int height
);
123 static gboolean
test_point_full_info(Collection
*collection
,
124 int point_x
, int point_y
,
125 CollectionItem
*item
,
126 int width
, int height
);
127 static void update_display(Directory
*dir
,
130 FilerWindow
*filer_window
);
131 void filer_change_to(FilerWindow
*filer_window
, char *path
);
132 static void shrink_width(FilerWindow
*filer_window
);
134 static GdkAtom xa_string
;
143 xa_string
= gdk_atom_intern("STRING", FALSE
);
145 options_sections
= g_slist_prepend(options_sections
, &options
);
146 option_register("filer_ro_bindings", filer_ro_bindings
);
147 option_register("filer_toolbar", filer_toolbar
);
149 fixed_font
= gdk_font_load("fixed");
152 static gboolean
if_deleted(gpointer item
, gpointer removed
)
154 int i
= ((GPtrArray
*) removed
)->len
;
155 DirItem
**r
= (DirItem
**) ((GPtrArray
*) removed
)->pdata
;
156 char *leafname
= ((DirItem
*) item
)->leafname
;
160 if (strcmp(leafname
, r
[i
]->leafname
) == 0)
167 static void update_item(FilerWindow
*filer_window
, DirItem
*item
)
171 i
= collection_find_item(filer_window
->collection
, item
, dir_item_cmp
);
172 collection_draw_item(filer_window
->collection
, i
, TRUE
);
175 static void update_display(Directory
*dir
,
178 FilerWindow
*filer_window
)
185 for (i
= 0; i
< items
->len
; i
++)
187 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
189 add_item(filer_window
, item
);
192 collection_qsort(filer_window
->collection
,
193 filer_window
->sort_fn
);
196 collection_delete_if(filer_window
->collection
,
201 if (filer_window
->window
->window
)
202 gdk_window_set_cursor(
203 filer_window
->window
->window
,
205 shrink_width(filer_window
);
208 for (i
= 0; i
< items
->len
; i
++)
210 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
212 update_item(filer_window
, item
);
218 static void detach(FilerWindow
*filer_window
)
220 g_return_if_fail(filer_window
->directory
!= NULL
);
222 dir_detach(filer_window
->directory
,
223 (DirCallback
) update_display
, filer_window
);
224 g_fscache_data_unref(dir_cache
, filer_window
->directory
);
225 filer_window
->directory
= NULL
;
228 static void filer_window_destroyed(GtkWidget
*widget
,
229 FilerWindow
*filer_window
)
231 if (window_with_selection
== filer_window
)
232 window_with_selection
= NULL
;
233 if (window_with_focus
== filer_window
)
234 window_with_focus
= NULL
;
236 if (filer_window
->directory
)
237 detach(filer_window
);
239 g_free(filer_window
->path
);
240 g_free(filer_window
);
242 if (--number_of_windows
< 1)
246 static int calc_width(FilerWindow
*filer_window
, DirItem
*item
)
248 int pix_width
= item
->image
->width
;
250 switch (filer_window
->display_style
)
253 return pix_width
+ item
->details_width
+ 12;
256 return MAX(pix_width
, item
->name_width
) + 4;
261 /* Add a single object to a directory display */
262 static void add_item(FilerWindow
*filer_window
, DirItem
*item
)
264 char *leafname
= item
->leafname
;
267 if (leafname
[0] == '.')
269 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
270 || (leafname
[1] == '.' && leafname
[2] == '\0'))
274 item_width
= calc_width(filer_window
, item
);
275 if (item_width
> filer_window
->collection
->item_width
)
276 collection_set_item_size(filer_window
->collection
,
278 filer_window
->collection
->item_height
);
279 collection_insert(filer_window
->collection
, item
);
282 /* Is a point inside an item? */
283 static gboolean
test_point_large(Collection
*collection
,
284 int point_x
, int point_y
,
285 CollectionItem
*colitem
,
286 int width
, int height
)
288 DirItem
*item
= (DirItem
*) colitem
->data
;
289 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
290 int text_height
= font
->ascent
+ font
->descent
;
291 MaskedPixmap
*image
= item
->image
;
292 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
293 int image_width
= (image
->width
>> 1) + 2;
294 int text_width
= (item
->name_width
>> 1) + 2;
297 if (point_y
< image_y
)
298 return FALSE
; /* Too high up (don't worry about too low) */
300 if (point_y
<= image_y
+ image
->height
+ 2)
301 x_limit
= image_width
;
302 else if (point_y
> height
- text_height
- 2)
303 x_limit
= text_width
;
305 x_limit
= MIN(image_width
, text_width
);
307 return ABS(point_x
- (width
>> 1)) < x_limit
;
310 static gboolean
test_point_full_info(Collection
*collection
,
311 int point_x
, int point_y
,
312 CollectionItem
*colitem
,
313 int width
, int height
)
315 DirItem
*item
= (DirItem
*) colitem
->data
;
316 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
317 MaskedPixmap
*image
= item
->image
;
318 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
320 if (point_x
< image
->width
+ 2)
321 return point_x
> 2 && point_y
> image_y
;
323 return point_x
> image
->width
+ 2 &&
324 point_y
> (height
>> 1) - font
->ascent
- font
->descent
&&
325 point_y
< (height
>> 1) + fixed_font
->ascent
+ fixed_font
->descent
;
328 static void draw_large_icon(GtkWidget
*widget
,
333 MaskedPixmap
*image
= item
->image
;
334 int image_x
= area
->x
+ ((area
->width
- image
->width
) >> 1);
336 GdkGC
*gc
= selected
? widget
->style
->white_gc
337 : widget
->style
->black_gc
;
341 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
343 image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
344 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
345 gdk_draw_pixmap(widget
->window
, gc
,
347 0, 0, /* Source x,y */
348 image_x
, area
->y
+ image_y
, /* Dest x,y */
349 -1, MIN(image
->height
, MAX_ICON_HEIGHT
));
353 gdk_gc_set_function(gc
, GDK_INVERT
);
354 gdk_draw_rectangle(widget
->window
,
356 TRUE
, image_x
, area
->y
+ image_y
,
357 image
->width
, image
->height
);
358 gdk_gc_set_function(gc
, GDK_COPY
);
361 if (item
->flags
& ITEM_FLAG_SYMLINK
)
363 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
364 gdk_gc_set_clip_mask(gc
,
365 default_pixmap
[TYPE_SYMLINK
].mask
);
366 gdk_draw_pixmap(widget
->window
, gc
,
367 default_pixmap
[TYPE_SYMLINK
].pixmap
,
368 0, 0, /* Source x,y */
369 image_x
, area
->y
+ 8, /* Dest x,y */
372 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
374 int type
= item
->flags
& ITEM_FLAG_MOUNTED
377 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
378 gdk_gc_set_clip_mask(gc
,
379 default_pixmap
[type
].mask
);
380 gdk_draw_pixmap(widget
->window
, gc
,
381 default_pixmap
[type
].pixmap
,
382 0, 0, /* Source x,y */
383 image_x
, area
->y
+ 8, /* Dest x,y */
387 gdk_gc_set_clip_mask(gc
, NULL
);
388 gdk_gc_set_clip_origin(gc
, 0, 0);
391 static void draw_string(GtkWidget
*widget
,
399 int text_height
= font
->ascent
+ font
->descent
;
402 gtk_paint_flat_box(widget
->style
, widget
->window
,
403 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
404 NULL
, widget
, "text",
409 gdk_draw_text(widget
->window
,
411 selected
? widget
->style
->white_gc
412 : widget
->style
->black_gc
,
414 string
, strlen(string
));
417 /* Return a string (valid until next call) giving details
420 char *details(DirItem
*item
)
422 mode_t m
= item
->mode
;
423 static GString
*buf
= NULL
;
426 buf
= g_string_new(NULL
);
428 g_string_sprintf(buf
, "%s, %c%c%c:%c%c%c:%c%c%c, %s",
430 S_ISCHR(m
) ? "Char" :
431 S_ISBLK(m
) ? "Blck" :
432 S_ISLNK(m
) ? "Link" :
433 S_ISSOCK(m
) ? "Sock" :
434 S_ISFIFO(m
) ? "Pipe" : "File",
436 m
& S_IRUSR
? 'r' : '-',
437 m
& S_IWUSR
? 'w' : '-',
440 m
& S_IRGRP
? 'r' : '-',
441 m
& S_IWGRP
? 'w' : '-',
444 m
& S_IROTH
? 'r' : '-',
445 m
& S_IWOTH
? 'w' : '-',
448 format_size(item
->size
));
453 static void draw_item_full_info(GtkWidget
*widget
,
454 CollectionItem
*colitem
,
457 DirItem
*item
= (DirItem
*) colitem
->data
;
458 MaskedPixmap
*image
= item
->image
;
459 GdkFont
*font
= widget
->style
->font
;
460 int text_x
= area
->x
+ image
->width
+ 8;
461 int mid_y
= area
->y
+ (area
->height
>> 1);
462 gboolean selected
= colitem
->selected
;
463 GdkRectangle pic_area
;
465 pic_area
.x
= area
->x
;
466 pic_area
.y
= area
->y
;
467 pic_area
.width
= image
->width
+ 8;
468 pic_area
.height
= area
->height
;
470 draw_large_icon(widget
, &pic_area
, item
, selected
);
475 text_x
, mid_y
- font
->descent
,
481 text_x
, mid_y
+ font
->ascent
,
486 static void draw_item_large(GtkWidget
*widget
,
487 CollectionItem
*colitem
,
490 DirItem
*item
= (DirItem
*) colitem
->data
;
491 GdkFont
*font
= widget
->style
->font
;
492 int text_x
= area
->x
+ ((area
->width
- item
->name_width
) >> 1);
493 int text_y
= area
->y
+ area
->height
- font
->descent
- 2;
494 gboolean selected
= colitem
->selected
;
496 draw_large_icon(widget
, area
, item
, selected
);
501 text_x
, text_y
, item
->name_width
,
505 void show_menu(Collection
*collection
, GdkEventButton
*event
,
506 int item
, gpointer user_data
)
508 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
511 static void may_rescan(FilerWindow
*filer_window
)
513 g_return_if_fail(filer_window
!= NULL
);
515 // XXX: g_fscache_data_update(dir_cache, filer_window->directory);
518 /* Callback to collection_delete_if() */
520 static gboolean
remove_deleted(gpointer item_data
, gpointer data
)
522 DirItem
*item
= (DirItem
*) item_data
;
524 if (item
->flags
& ITEM_FLAG_MAY_DELETE
)
534 /* Another app has grabbed the selection */
535 static gint
collection_lose_selection(GtkWidget
*widget
,
536 GdkEventSelection
*event
)
538 if (window_with_selection
&&
539 window_with_selection
->collection
== COLLECTION(widget
))
541 FilerWindow
*filer_window
= window_with_selection
;
542 window_with_selection
= NULL
;
543 collection_clear_selection(filer_window
->collection
);
549 /* Someone wants us to send them the selection */
550 static void selection_get(GtkWidget
*widget
,
551 GtkSelectionData
*selection_data
,
556 GString
*reply
, *header
;
557 FilerWindow
*filer_window
;
559 Collection
*collection
;
561 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
563 reply
= g_string_new(NULL
);
564 header
= g_string_new(NULL
);
569 g_string_sprintf(header
, " %s",
570 make_path(filer_window
->path
, "")->str
);
572 case TARGET_URI_LIST
:
573 g_string_sprintf(header
, " file://%s%s",
575 make_path(filer_window
->path
, "")->str
);
579 collection
= filer_window
->collection
;
580 for (i
= 0; i
< collection
->number_of_items
; i
++)
582 if (collection
->items
[i
].selected
)
585 (DirItem
*) collection
->items
[i
].data
;
587 g_string_append(reply
, header
->str
);
588 g_string_append(reply
, item
->leafname
);
591 /* This works, but I don't think I like it... */
592 /* g_string_append_c(reply, ' '); */
594 gtk_selection_data_set(selection_data
, xa_string
,
595 8, reply
->str
+ 1, reply
->len
- 1);
596 g_string_free(reply
, TRUE
);
597 g_string_free(header
, TRUE
);
600 /* No items are now selected. This might be because another app claimed
601 * the selection or because the user unselected all the items.
603 static void lose_selection(Collection
*collection
,
607 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
609 if (window_with_selection
== filer_window
)
611 window_with_selection
= NULL
;
612 gtk_selection_owner_set(NULL
,
613 GDK_SELECTION_PRIMARY
,
618 static void gain_selection(Collection
*collection
,
622 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
624 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
625 GDK_SELECTION_PRIMARY
,
628 window_with_selection
= filer_window
;
631 collection_clear_selection(filer_window
->collection
);
634 static int sort_by_name(const void *item1
, const void *item2
)
636 return strcmp((*((DirItem
**)item1
))->leafname
,
637 (*((DirItem
**)item2
))->leafname
);
640 static int sort_by_type(const void *item1
, const void *item2
)
642 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
643 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
646 int diff
= i1
->base_type
- i2
->base_type
;
649 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
650 - (i2
->flags
& ITEM_FLAG_APPDIR
);
652 return diff
> 0 ? 1 : -1;
659 diff
= strcmp(m1
->media_type
, m2
->media_type
);
661 diff
= strcmp(m1
->subtype
, m2
->subtype
);
669 return diff
> 0 ? 1 : -1;
671 return sort_by_name(item1
, item2
);
674 void open_item(Collection
*collection
,
675 gpointer item_data
, int item_number
,
678 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
679 DirItem
*item
= (DirItem
*) item_data
;
680 GdkEventButton
*event
;
684 gboolean adjust
; /* do alternative action */
686 event
= (GdkEventButton
*) gtk_get_current_event();
687 full_path
= make_path(filer_window
->path
,
688 item
->leafname
)->str
;
690 collection_wink_item(filer_window
->collection
, item_number
);
692 if (event
->type
== GDK_2BUTTON_PRESS
|| event
->type
== GDK_BUTTON_PRESS
)
694 shift
= event
->state
& GDK_SHIFT_MASK
;
695 adjust
= (event
->button
!= 1)
696 ^ ((event
->state
& GDK_CONTROL_MASK
) != 0);
704 widget
= filer_window
->window
;
706 switch (item
->base_type
)
709 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
711 run_app(make_path(filer_window
->path
,
712 item
->leafname
)->str
);
713 if (adjust
&& !filer_window
->panel
)
714 gtk_widget_destroy(widget
);
717 if ((adjust
^ o_ro_bindings
) || filer_window
->panel
)
718 filer_opendir(full_path
, FALSE
, BOTTOM
);
720 filer_change_to(filer_window
, full_path
);
723 if (item
->flags
& ITEM_FLAG_EXEC_FILE
726 char *argv
[] = {NULL
, NULL
};
730 if (spawn_full(argv
, getenv("HOME"), 0))
732 if (adjust
&& !filer_window
->panel
)
733 gtk_widget_destroy(widget
);
736 report_error("ROX-Filer",
737 "Failed to fork() child");
742 MIME_type
*type
= shift
? &text_plain
745 g_return_if_fail(type
!= NULL
);
747 if (type_open(full_path
, type
))
749 if (adjust
&& !filer_window
->panel
)
750 gtk_widget_destroy(widget
);
754 message
= g_string_new(NULL
);
755 g_string_sprintf(message
, "No open "
756 "action specified for files of "
760 report_error("ROX-Filer", message
->str
);
761 g_string_free(message
, TRUE
);
766 report_error("open_item",
767 "I don't know how to open that");
772 static gint
pointer_in(GtkWidget
*widget
,
773 GdkEventCrossing
*event
,
774 FilerWindow
*filer_window
)
776 may_rescan(filer_window
);
780 static gint
focus_in(GtkWidget
*widget
,
781 GdkEventFocus
*event
,
782 FilerWindow
*filer_window
)
784 window_with_focus
= filer_window
;
789 static gint
focus_out(GtkWidget
*widget
,
790 GdkEventFocus
*event
,
791 FilerWindow
*filer_window
)
793 /* TODO: Shade the cursor */
798 /* Handle keys that can't be bound with the menu */
799 static gint
key_press_event(GtkWidget
*widget
,
801 FilerWindow
*filer_window
)
803 switch (event
->keyval
)
821 change_to_parent(filer_window
);
828 static void toolbar_home_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
830 filer_change_to(filer_window
, getenv("HOME"));
833 static void toolbar_up_clicked(GtkWidget
*widget
, FilerWindow
*filer_window
)
835 change_to_parent(filer_window
);
838 void change_to_parent(FilerWindow
*filer_window
)
840 filer_change_to(filer_window
, make_path(filer_window
->path
, "..")->str
);
843 void filer_change_to(FilerWindow
*filer_window
, char *path
)
845 detach(filer_window
);
846 g_free(filer_window
->path
);
847 filer_window
->path
= pathdup(path
);
849 filer_window
->directory
= g_fscache_lookup(dir_cache
,
851 if (filer_window
->directory
)
853 collection_clear(filer_window
->collection
);
854 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
856 gdk_window_set_cursor(filer_window
->window
->window
,
857 gdk_cursor_new(GDK_WATCH
));
858 dir_attach(filer_window
->directory
,
859 (DirCallback
) update_display
,
866 error
= g_strdup_printf("Directory '%s' is not accessible.",
868 delayed_error("ROX-Filer", error
);
870 gtk_widget_destroy(filer_window
->window
);
874 DirItem
*selected_item(Collection
*collection
)
878 g_return_val_if_fail(collection
!= NULL
, NULL
);
879 g_return_val_if_fail(IS_COLLECTION(collection
), NULL
);
880 g_return_val_if_fail(collection
->number_selected
== 1, NULL
);
882 for (i
= 0; i
< collection
->number_of_items
; i
++)
883 if (collection
->items
[i
].selected
)
884 return (DirItem
*) collection
->items
[i
].data
;
886 g_warning("selected_item: number_selected is wrong\n");
891 static int filer_confirm_close(GtkWidget
*widget
, GdkEvent
*event
,
894 /* TODO: We can open lots of these - very irritating! */
895 return get_choice("Close panel?",
896 "You have tried to close a panel via the window "
897 "manager - I usually find that this is accidental... "
899 2, "Remove", "Cancel") != 0;
902 /* Make the items as narrow as possible */
903 static void shrink_width(FilerWindow
*filer_window
)
906 Collection
*col
= filer_window
->collection
;
907 int width
= MIN_ITEM_WIDTH
;
910 for (i
= 0; i
< col
->number_of_items
; i
++)
912 this_width
= calc_width(filer_window
,
913 (DirItem
*) col
->items
[i
].data
);
914 if (this_width
> width
)
918 collection_set_item_size(filer_window
->collection
,
920 filer_window
->display_style
== FULL_INFO
? ROW_HEIGHT_FULL_INFO
924 void filer_style_set(FilerWindow
*filer_window
, DisplayStyle style
)
926 if (filer_window
->display_style
== style
)
929 filer_window
->display_style
= style
;
933 collection_set_functions(filer_window
->collection
,
934 draw_item_full_info
, test_point_full_info
);
937 collection_set_functions(filer_window
->collection
,
938 draw_item_large
, test_point_large
);
942 shrink_width(filer_window
);
945 void filer_opendir(char *path
, gboolean panel
, Side panel_side
)
947 GtkWidget
*hbox
, *scrollbar
, *collection
;
948 FilerWindow
*filer_window
;
949 GtkTargetEntry target_table
[] =
951 {"text/uri-list", 0, TARGET_URI_LIST
},
952 {"STRING", 0, TARGET_STRING
},
955 filer_window
= g_new(FilerWindow
, 1);
956 filer_window
->path
= pathdup(path
);
958 filer_window
->directory
= g_fscache_lookup(dir_cache
, path
);
959 if (!filer_window
->directory
)
963 error
= g_strdup_printf("Directory '%s' not found.", path
);
964 delayed_error("ROX-Filer", error
);
966 g_free(filer_window
->path
);
967 g_free(filer_window
);
971 filer_window
->show_hidden
= FALSE
;
972 filer_window
->panel
= panel
;
973 filer_window
->panel_side
= panel_side
;
974 filer_window
->temp_item_selected
= FALSE
;
975 filer_window
->sort_fn
= sort_by_type
;
976 filer_window
->flags
= (FilerFlags
) 0;
977 filer_window
->display_style
= UNKNOWN_STYLE
;
979 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
980 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
983 collection
= collection_new(NULL
);
984 gtk_object_set_data(GTK_OBJECT(collection
),
985 "filer_window", filer_window
);
986 filer_window
->collection
= COLLECTION(collection
);
988 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
989 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
990 "enter-notify-event",
991 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
992 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
993 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
994 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
995 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
996 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
997 filer_window_destroyed
, filer_window
);
999 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
1000 open_item
, filer_window
);
1001 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
1002 show_menu
, filer_window
);
1003 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
1004 gain_selection
, filer_window
);
1005 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
1006 lose_selection
, filer_window
);
1007 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
1008 drag_selection
, filer_window
);
1009 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
1010 drag_data_get
, filer_window
);
1011 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
1012 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
1013 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
1014 GTK_SIGNAL_FUNC(selection_get
), NULL
);
1015 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
1017 sizeof(target_table
) / sizeof(*target_table
));
1019 filer_style_set(filer_window
, LARGE
);
1020 dir_attach(filer_window
->directory
, (DirCallback
) update_display
,
1022 drag_set_dest(collection
);
1026 int swidth
, sheight
, iwidth
, iheight
;
1027 GtkWidget
*frame
, *win
= filer_window
->window
;
1029 collection_set_panel(filer_window
->collection
, TRUE
);
1030 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1032 GTK_SIGNAL_FUNC(filer_confirm_close
),
1035 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
1036 iwidth
= filer_window
->collection
->item_width
;
1037 iheight
= filer_window
->collection
->item_height
;
1039 if (panel_side
== TOP
|| panel_side
== BOTTOM
)
1041 int height
= iheight
+ PANEL_BORDER
;
1042 int y
= panel_side
== TOP
1044 : sheight
- height
- PANEL_BORDER
;
1046 gtk_widget_set_usize(collection
, swidth
, height
);
1047 gtk_widget_set_uposition(win
, 0, y
);
1051 int width
= iwidth
+ PANEL_BORDER
;
1052 int x
= panel_side
== LEFT
1054 : swidth
- width
- PANEL_BORDER
;
1056 gtk_widget_set_usize(collection
, width
, sheight
);
1057 gtk_widget_set_uposition(win
, x
, 0);
1060 frame
= gtk_frame_new(NULL
);
1061 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1062 gtk_container_add(GTK_CONTAINER(frame
), collection
);
1063 gtk_container_add(GTK_CONTAINER(win
), frame
);
1065 gtk_widget_realize(win
);
1066 if (override_redirect
)
1067 gdk_window_set_override_redirect(win
->window
, TRUE
);
1068 make_panel_window(win
->window
);
1072 hbox
= gtk_hbox_new(FALSE
, 0);
1074 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1076 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
1077 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
1078 filer_window
->display_style
== LARGE
? 400 : 512,
1079 o_toolbar
? 220 : 200);
1081 gtk_container_add(GTK_CONTAINER(filer_window
->window
),
1085 GtkWidget
*vbox
, *toolbar
;
1088 vbox
= gtk_vbox_new(FALSE
, 0);
1089 gtk_box_pack_start(GTK_BOX(hbox
), vbox
,
1091 toolbar
= create_toolbar(filer_window
);
1092 gtk_box_pack_start(GTK_BOX(vbox
), toolbar
,
1095 gtk_box_pack_start(GTK_BOX(vbox
), collection
,
1099 gtk_box_pack_start(GTK_BOX(hbox
), collection
,
1102 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
1103 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
1104 gtk_accel_group_attach(filer_keys
,
1105 GTK_OBJECT(filer_window
->window
));
1108 gtk_widget_show_all(filer_window
->window
);
1109 number_of_windows
++;
1112 static GtkWidget
*create_toolbar(FilerWindow
*filer_window
)
1114 GtkWidget
*frame
, *box
;
1116 frame
= gtk_frame_new(NULL
);
1117 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1119 box
= gtk_hbutton_box_new();
1120 gtk_button_box_set_child_size_default(16, 16);
1121 gtk_hbutton_box_set_spacing_default(2);
1122 gtk_button_box_set_layout(GTK_BUTTON_BOX(box
), GTK_BUTTONBOX_START
);
1123 gtk_container_add(GTK_CONTAINER(frame
), box
);
1124 add_button(GTK_CONTAINER(box
), TOOLBAR_UP_ICON
,
1125 GTK_SIGNAL_FUNC(toolbar_up_clicked
),
1127 add_button(GTK_CONTAINER(box
), TOOLBAR_HOME_ICON
,
1128 GTK_SIGNAL_FUNC(toolbar_home_clicked
),
1134 static void add_button(GtkContainer
*box
, int pixmap
,
1135 GtkSignalFunc cb
, gpointer data
)
1137 GtkWidget
*button
, *icon
;
1139 button
= gtk_button_new();
1140 GTK_WIDGET_UNSET_FLAGS(button
, GTK_CAN_FOCUS
);
1141 gtk_container_add(box
, button
);
1143 icon
= gtk_pixmap_new(default_pixmap
[pixmap
].pixmap
,
1144 default_pixmap
[pixmap
].mask
);
1145 gtk_container_add(GTK_CONTAINER(button
), icon
);
1146 gtk_signal_connect(GTK_OBJECT(button
), "clicked", cb
, data
);
1149 /* Build up some option widgets to go in the options dialog, but don't
1152 static GtkWidget
*create_options()
1156 vbox
= gtk_vbox_new(FALSE
, 0);
1157 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
1159 toggle_ro_bindings
=
1160 gtk_check_button_new_with_label("Use RISC OS mouse bindings");
1161 gtk_box_pack_start(GTK_BOX(vbox
), toggle_ro_bindings
, FALSE
, TRUE
, 0);
1164 gtk_check_button_new_with_label("Show toolbar on new windows");
1165 gtk_box_pack_start(GTK_BOX(vbox
), toggle_toolbar
, FALSE
, TRUE
, 0);
1170 /* Reflect current state by changing the widgets in the options box */
1171 static void update_options()
1173 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_ro_bindings
),
1175 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_toolbar
),
1179 /* Set current values by reading the states of the widgets in the options box */
1180 static void set_options()
1182 o_ro_bindings
= gtk_toggle_button_get_active(
1183 GTK_TOGGLE_BUTTON(toggle_ro_bindings
));
1184 o_toolbar
= gtk_toggle_button_get_active(
1185 GTK_TOGGLE_BUTTON(toggle_toolbar
));
1188 static void save_options()
1190 option_write("filer_ro_bindings", o_ro_bindings
? "1" : "0");
1191 option_write("filer_toolbar", o_toolbar
? "1" : "0");
1194 static char *filer_ro_bindings(char *data
)
1196 o_ro_bindings
= atoi(data
) != 0;
1200 static char *filer_toolbar(char *data
)
1202 o_toolbar
= atoi(data
) != 0;
1206 void update_dir(FilerWindow
*filer_window
)
1208 dir_update(filer_window
->directory
, filer_window
->path
);