4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
8 /* filer.c - code for handling filer windows */
19 #include <gdk/gdkprivate.h> /* XXX - find another way to do this */
20 #include <gdk/gdkkeysyms.h>
21 #include <collection.h>
25 #include "gui_support.h"
34 #define MAX_ICON_HEIGHT 42
35 #define PANEL_BORDER 2
37 FilerWindow
*window_with_focus
= NULL
;
39 /* When a child process that changes a directory dies we need to know
40 * which filer window to update. Use this table.
42 GHashTable
*child_to_filer
= NULL
;
44 /* Link paths to GLists of filer windows */
45 GHashTable
*path_to_window_list
= NULL
;
47 static FilerWindow
*window_with_selection
= NULL
;
48 static FilerWindow
*panel_with_timeout
= NULL
;
49 static gint panel_timeout
;
51 /* Static prototypes */
52 static void filer_window_destroyed(GtkWidget
*widget
,
53 FilerWindow
*filer_window
);
54 static gboolean
idle_scan_dir(gpointer data
);
55 static void draw_item(GtkWidget
*widget
,
58 void show_menu(Collection
*collection
, GdkEventButton
*event
,
59 int number_selected
, gpointer user_data
);
60 static int sort_by_name(const void *item1
, const void *item2
);
61 static void add_item(FilerWindow
*filer_window
, char *leafname
);
62 static gboolean
test_point(Collection
*collection
,
63 int point_x
, int point_y
,
65 int width
, int height
);
66 static void stop_scanning(FilerWindow
*filer_window
);
67 static gint
focus_in(GtkWidget
*widget
,
69 FilerWindow
*filer_window
);
70 static gint
focus_out(GtkWidget
*widget
,
72 FilerWindow
*filer_window
);
73 static void add_view(FilerWindow
*filer_window
);
74 static void remove_view(FilerWindow
*filer_window
);
76 static GdkAtom xa_string
;
85 xa_string
= gdk_atom_intern("STRING", FALSE
);
87 child_to_filer
= g_hash_table_new(NULL
, NULL
);
88 path_to_window_list
= g_hash_table_new(g_str_hash
, g_str_equal
);
92 /* When a filer window shows a directory, use this function to add
93 * it to the list of directories to be updated when the contents
96 static void add_view(FilerWindow
*filer_window
)
98 GList
*list
, *newlist
;
100 g_return_if_fail(filer_window
!= NULL
);
102 list
= g_hash_table_lookup(path_to_window_list
, filer_window
->path
);
103 newlist
= g_list_prepend(list
, filer_window
);
105 g_hash_table_insert(path_to_window_list
, filer_window
->path
,
109 /* When a filer window no longer shows a directory, call this to reverse
110 * the effect of add_view().
112 static void remove_view(FilerWindow
*filer_window
)
114 GList
*list
, *newlist
;
116 g_return_if_fail(filer_window
!= NULL
);
118 list
= g_hash_table_lookup(path_to_window_list
, filer_window
->path
);
119 newlist
= g_list_remove(list
, filer_window
);
121 g_hash_table_insert(path_to_window_list
, filer_window
->path
,
125 /* When a filer window is destroyed we call this for each entry in the
126 * child_to_filer hash table to remove old entries.
128 static gboolean
child_eq(gpointer key
, gpointer data
, gpointer filer_window
)
130 return data
== filer_window
;
133 /* Go though all the FileItems in a collection, freeing all the temp
135 * TODO: Maybe we should cache icons?
137 static void free_temp_icons(FilerWindow
*filer_window
)
140 Collection
*collection
= filer_window
->collection
;
142 for (i
= 0; i
< collection
->number_of_items
; i
++)
144 FileItem
*item
= (FileItem
*) collection
->items
[i
].data
;
145 if (item
->flags
& ITEM_FLAG_TEMP_ICON
)
147 gdk_pixmap_unref(item
->image
->pixmap
);
148 gdk_pixmap_unref(item
->image
->mask
);
150 item
->image
= default_pixmap
+ TYPE_ERROR
;
155 static void filer_window_destroyed(GtkWidget
*widget
,
156 FilerWindow
*filer_window
)
158 if (window_with_selection
== filer_window
)
159 window_with_selection
= NULL
;
160 if (window_with_focus
== filer_window
)
161 window_with_focus
= NULL
;
162 if (panel_with_timeout
== filer_window
)
164 /* Can this happen? */
165 panel_with_timeout
= NULL
;
166 gtk_timeout_remove(panel_timeout
);
169 remove_view(filer_window
);
170 g_hash_table_foreach_remove(child_to_filer
, child_eq
, filer_window
);
172 free_temp_icons(filer_window
);
173 if (filer_window
->dir
)
174 stop_scanning(filer_window
);
175 g_free(filer_window
->path
);
176 g_free(filer_window
);
178 if (--number_of_windows
< 1)
182 static void stop_scanning(FilerWindow
*filer_window
)
184 g_return_if_fail(filer_window
->dir
!= NULL
);
186 closedir(filer_window
->dir
);
187 gtk_idle_remove(filer_window
->idle_scan_id
);
188 filer_window
->dir
= NULL
;
191 /* This is called while we are scanning the directory */
192 static gboolean
idle_scan_dir(gpointer data
)
195 FilerWindow
*filer_window
= (FilerWindow
*) data
;
199 next
= readdir(filer_window
->dir
);
202 closedir(filer_window
->dir
);
203 filer_window
->dir
= NULL
;
205 collection_set_item_size(filer_window
->collection
,
206 filer_window
->scan_min_width
,
207 filer_window
->collection
->item_height
);
208 collection_qsort(filer_window
->collection
,
210 return FALSE
; /* Finished */
213 add_item(filer_window
, next
->d_name
);
214 } while (!gtk_events_pending());
219 /* Add a single object to a directory display */
220 static void add_item(FilerWindow
*filer_window
, char *leafname
)
228 if (leafname
[0] == '.')
230 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
231 || (leafname
[1] == '.' && leafname
[2] == '\0'))
235 item
= g_malloc(sizeof(FileItem
));
236 item
->leafname
= g_strdup(leafname
);
239 path
= make_path(filer_window
->path
, leafname
);
240 if (lstat(path
->str
, &info
))
241 base_type
= TYPE_ERROR
;
244 if (S_ISREG(info
.st_mode
))
245 base_type
= TYPE_FILE
;
246 else if (S_ISDIR(info
.st_mode
))
248 base_type
= TYPE_DIRECTORY
;
250 if (g_hash_table_lookup(mtab_mounts
, path
->str
))
251 item
->flags
|= ITEM_FLAG_MOUNT_POINT
253 else if (g_hash_table_lookup(fstab_mounts
, path
->str
))
254 item
->flags
|= ITEM_FLAG_MOUNT_POINT
;
256 else if (S_ISBLK(info
.st_mode
))
257 base_type
= TYPE_BLOCK_DEVICE
;
258 else if (S_ISCHR(info
.st_mode
))
259 base_type
= TYPE_CHAR_DEVICE
;
260 else if (S_ISFIFO(info
.st_mode
))
261 base_type
= TYPE_PIPE
;
262 else if (S_ISSOCK(info
.st_mode
))
263 base_type
= TYPE_SOCKET
;
264 else if (S_ISLNK(info
.st_mode
))
266 if (stat(path
->str
, &info
))
268 base_type
= TYPE_ERROR
;
272 if (S_ISREG(info
.st_mode
))
273 base_type
= TYPE_FILE
;
274 else if (S_ISDIR(info
.st_mode
))
275 base_type
= TYPE_DIRECTORY
;
276 else if (S_ISBLK(info
.st_mode
))
277 base_type
= TYPE_BLOCK_DEVICE
;
278 else if (S_ISCHR(info
.st_mode
))
279 base_type
= TYPE_CHAR_DEVICE
;
280 else if (S_ISFIFO(info
.st_mode
))
281 base_type
= TYPE_PIPE
;
282 else if (S_ISSOCK(info
.st_mode
))
283 base_type
= TYPE_SOCKET
;
285 base_type
= TYPE_UNKNOWN
;
288 item
->flags
|= ITEM_FLAG_SYMLINK
;
291 base_type
= TYPE_UNKNOWN
;
294 item
->base_type
= base_type
;
296 item
->mime_type
= type_from_path(path
->str
);
298 if (base_type
== TYPE_DIRECTORY
)
300 /* Might be an application directory - better check... */
301 g_string_append(path
, "/AppRun");
302 if (!stat(path
->str
, &info
))
304 item
->flags
|= ITEM_FLAG_APPDIR
;
308 if (item
->flags
& ITEM_FLAG_APPDIR
) /* path still ends /AppRun */
310 MaskedPixmap
*app_icon
;
312 g_string_truncate(path
, path
->len
- 3);
313 g_string_append(path
, "Icon.xpm");
314 app_icon
= load_pixmap_from(filer_window
->window
, path
->str
);
317 item
->image
= app_icon
;
318 item
->flags
|= ITEM_FLAG_TEMP_ICON
;
321 item
->image
= default_pixmap
+ TYPE_APPDIR
;
325 if (base_type
== TYPE_FILE
&&
326 (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
328 item
->image
= default_pixmap
+ TYPE_EXEC_FILE
;
329 item
->flags
|= ITEM_FLAG_EXEC_FILE
;
331 else if (base_type
== TYPE_FILE
)
333 item
->image
= type_to_icon(filer_window
->window
,
337 item
->image
= default_pixmap
+ base_type
;
340 item
->text_width
= gdk_string_width(filer_window
->window
->style
->font
,
343 /* XXX: Must be a better way... */
344 item
->pix_width
= ((GdkPixmapPrivate
*) item
->image
->pixmap
)->width
;
345 item
->pix_height
= ((GdkPixmapPrivate
*) item
->image
->pixmap
)->height
;
347 item_width
= MAX(item
->pix_width
, item
->text_width
) + 4;
349 if (item_width
> filer_window
->scan_min_width
)
350 filer_window
->scan_min_width
= item_width
;
352 if (item_width
> filer_window
->collection
->item_width
)
353 collection_set_item_size(filer_window
->collection
,
355 filer_window
->collection
->item_height
);
357 collection_insert(filer_window
->collection
, item
);
360 static gboolean
test_point(Collection
*collection
,
361 int point_x
, int point_y
,
362 CollectionItem
*colitem
,
363 int width
, int height
)
365 FileItem
*item
= (FileItem
*) colitem
->data
;
366 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
367 int text_height
= font
->ascent
+ font
->descent
;
368 int x_off
= ABS(point_x
- (width
>> 1));
369 int image_y
= MAX(0, MAX_ICON_HEIGHT
- item
->pix_height
);
371 if (x_off
<= (item
->pix_width
>> 1) + 2 &&
372 point_y
>= image_y
&& point_y
<= image_y
+ item
->pix_height
)
375 if (x_off
<= (item
->text_width
>> 1) + 2 &&
376 point_y
> height
- text_height
- 2)
382 static void draw_item(GtkWidget
*widget
,
383 CollectionItem
*colitem
,
386 FileItem
*item
= (FileItem
*) colitem
->data
;
387 GdkGC
*gc
= colitem
->selected
? widget
->style
->white_gc
388 : widget
->style
->black_gc
;
389 int image_x
= area
->x
+ ((area
->width
- item
->pix_width
) >> 1);
390 GdkFont
*font
= widget
->style
->font
;
391 int text_x
= area
->x
+ ((area
->width
- item
->text_width
) >> 1);
392 int text_y
= area
->y
+ area
->height
- font
->descent
- 2;
393 int text_height
= font
->ascent
+ font
->descent
;
399 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
401 image_y
= MAX(0, MAX_ICON_HEIGHT
- item
->pix_height
);
402 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
403 gdk_draw_pixmap(widget
->window
, gc
,
405 0, 0, /* Source x,y */
406 image_x
, area
->y
+ image_y
, /* Dest x,y */
407 -1, MIN(item
->pix_height
, MAX_ICON_HEIGHT
));
409 if (item
->flags
& ITEM_FLAG_SYMLINK
)
411 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
412 gdk_gc_set_clip_mask(gc
,
413 default_pixmap
[TYPE_SYMLINK
].mask
);
414 gdk_draw_pixmap(widget
->window
, gc
,
415 default_pixmap
[TYPE_SYMLINK
].pixmap
,
416 0, 0, /* Source x,y */
417 image_x
, area
->y
+ 8, /* Dest x,y */
420 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
422 int type
= item
->flags
& ITEM_FLAG_MOUNTED
425 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
426 gdk_gc_set_clip_mask(gc
,
427 default_pixmap
[type
].mask
);
428 gdk_draw_pixmap(widget
->window
, gc
,
429 default_pixmap
[type
].pixmap
,
430 0, 0, /* Source x,y */
431 image_x
, area
->y
+ 8, /* Dest x,y */
435 gdk_gc_set_clip_mask(gc
, NULL
);
436 gdk_gc_set_clip_origin(gc
, 0, 0);
439 if (colitem
->selected
)
440 gtk_paint_flat_box(widget
->style
, widget
->window
,
441 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
442 NULL
, widget
, "text",
443 text_x
, text_y
- font
->ascent
,
447 gdk_draw_text(widget
->window
,
449 colitem
->selected
? widget
->style
->white_gc
450 : widget
->style
->black_gc
,
452 item
->leafname
, strlen(item
->leafname
));
455 void show_menu(Collection
*collection
, GdkEventButton
*event
,
456 int item
, gpointer user_data
)
458 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
461 static void may_rescan(FilerWindow
*filer_window
)
465 g_return_if_fail(filer_window
!= NULL
);
467 if (stat(filer_window
->path
, &info
))
469 delayed_error("ROX-Filer", "Directory deleted");
470 gtk_widget_destroy(filer_window
->window
);
472 else if (info
.st_mtime
> filer_window
->m_time
)
474 if (filer_window
->dir
)
475 filer_window
->flags
|= FILER_NEEDS_RESCAN
;
477 scan_dir(filer_window
);
481 void scan_dir(FilerWindow
*filer_window
)
485 if (filer_window
->dir
)
486 stop_scanning(filer_window
);
487 if (panel_with_timeout
== filer_window
)
489 panel_with_timeout
= NULL
;
490 gtk_timeout_remove(panel_timeout
);
495 free_temp_icons(filer_window
);
496 collection_clear(filer_window
->collection
);
497 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
500 if (stat(filer_window
->path
, &info
))
502 report_error("Error statting directory", g_strerror(errno
));
505 filer_window
->m_time
= info
.st_mtime
;
507 filer_window
->dir
= opendir(filer_window
->path
);
508 if (!filer_window
->dir
)
510 report_error("Error scanning directory", g_strerror(errno
));
514 filer_window
->scan_min_width
= 64;
516 filer_window
->idle_scan_id
= gtk_idle_add(idle_scan_dir
, filer_window
);
519 /* Another app has grabbed the selection */
520 static gint
collection_lose_selection(GtkWidget
*widget
,
521 GdkEventSelection
*event
)
523 if (window_with_selection
&&
524 window_with_selection
->collection
== COLLECTION(widget
))
526 FilerWindow
*filer_window
= window_with_selection
;
527 window_with_selection
= NULL
;
528 collection_clear_selection(filer_window
->collection
);
534 /* Someone wants us to send them the selection */
535 static void selection_get(GtkWidget
*widget
,
536 GtkSelectionData
*selection_data
,
541 GString
*reply
, *header
;
542 FilerWindow
*filer_window
;
544 Collection
*collection
;
546 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
548 reply
= g_string_new(NULL
);
549 header
= g_string_new(NULL
);
554 g_string_sprintf(header
, " %s",
555 make_path(filer_window
->path
, "")->str
);
557 case TARGET_URI_LIST
:
558 g_string_sprintf(header
, " file://%s%s",
560 make_path(filer_window
->path
, "")->str
);
564 collection
= filer_window
->collection
;
565 for (i
= 0; i
< collection
->number_of_items
; i
++)
567 if (collection
->items
[i
].selected
)
570 (FileItem
*) collection
->items
[i
].data
;
572 g_string_append(reply
, header
->str
);
573 g_string_append(reply
, item
->leafname
);
576 g_string_append_c(reply
, ' ');
578 gtk_selection_data_set(selection_data
, xa_string
,
579 8, reply
->str
+ 1, reply
->len
- 1);
580 g_string_free(reply
, TRUE
);
581 g_string_free(header
, TRUE
);
584 /* No items are now selected. This might be because another app claimed
585 * the selection or because the user unselected all the items.
587 static void lose_selection(Collection
*collection
,
591 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
593 if (window_with_selection
== filer_window
)
595 window_with_selection
= NULL
;
596 gtk_selection_owner_set(NULL
,
597 GDK_SELECTION_PRIMARY
,
602 static void gain_selection(Collection
*collection
,
606 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
608 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
609 GDK_SELECTION_PRIMARY
,
612 window_with_selection
= filer_window
;
615 collection_clear_selection(filer_window
->collection
);
618 static int sort_by_name(const void *item1
, const void *item2
)
620 return strcmp((*((FileItem
**)item1
))->leafname
,
621 (*((FileItem
**)item2
))->leafname
);
624 static gint
clear_panel_hilight(gpointer data
)
626 collection_set_cursor_item(panel_with_timeout
->collection
, -1);
627 panel_with_timeout
= NULL
;
632 /* It is possible to highlight an item briefly on a panel by calling this
635 void panel_set_timeout(FilerWindow
*filer_window
, gulong msec
)
637 if (panel_with_timeout
)
639 /* Can't have two timeouts at once */
640 gtk_timeout_remove(panel_timeout
);
641 clear_panel_hilight(NULL
);
646 panel_with_timeout
= filer_window
;
647 panel_timeout
= gtk_timeout_add(msec
,
648 clear_panel_hilight
, NULL
);
652 void open_item(Collection
*collection
,
653 gpointer item_data
, int item_number
,
656 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
657 FileItem
*item
= (FileItem
*) item_data
;
658 GdkEventButton
*event
;
661 gboolean shift
, adjust
;
663 event
= (GdkEventButton
*) gtk_get_current_event();
664 full_path
= make_path(filer_window
->path
, item
->leafname
)->str
;
666 if (filer_window
->panel
)
668 panel_set_timeout(NULL
, 0);
669 collection_set_cursor_item(collection
, item_number
);
671 panel_set_timeout(filer_window
, 200);
674 if (event
->type
== GDK_2BUTTON_PRESS
|| event
->type
== GDK_BUTTON_PRESS
)
676 shift
= event
->state
& GDK_SHIFT_MASK
;
677 adjust
= event
->button
!= 1 || event
->state
& GDK_CONTROL_MASK
;
685 widget
= filer_window
->window
;
687 switch (item
->base_type
)
690 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
692 run_app(make_path(filer_window
->path
,
693 item
->leafname
)->str
);
694 if (adjust
&& !filer_window
->panel
)
695 gtk_widget_destroy(widget
);
698 if (adjust
|| filer_window
->panel
)
699 filer_opendir(full_path
, FALSE
, BOTTOM
);
702 remove_view(filer_window
);
703 filer_window
->path
= pathdup(full_path
);
704 add_view(filer_window
);
705 scan_dir(filer_window
);
709 if (item
->flags
& ITEM_FLAG_EXEC_FILE
)
711 char *argv
[] = {full_path
, NULL
};
713 if (spawn_full(argv
, getenv("HOME"), 0))
715 if (adjust
&& !filer_window
->panel
)
716 gtk_widget_destroy(widget
);
719 report_error("ROX-Filer",
720 "Failed to fork() child");
725 MIME_type
*type
= item
->mime_type
;
727 if (type
&& type_open(full_path
, type
))
729 if (adjust
&& !filer_window
->panel
)
730 gtk_widget_destroy(widget
);
734 message
= g_string_new(NULL
);
735 g_string_sprintf(message
, "No open "
736 "action specified for files of "
740 report_error("ROX-Filer", message
->str
);
741 g_string_free(message
, TRUE
);
746 report_error("open_item",
747 "I don't know how to open that");
752 static gint
pointer_in(GtkWidget
*widget
,
753 GdkEventCrossing
*event
,
754 FilerWindow
*filer_window
)
756 may_rescan(filer_window
);
760 static gint
focus_in(GtkWidget
*widget
,
761 GdkEventFocus
*event
,
762 FilerWindow
*filer_window
)
764 window_with_focus
= filer_window
;
769 static gint
focus_out(GtkWidget
*widget
,
770 GdkEventFocus
*event
,
771 FilerWindow
*filer_window
)
773 /* TODO: Shade the cursor */
778 /* Handle keys that can't be bound with the menu */
779 static gint
key_press_event(GtkWidget
*widget
,
781 FilerWindow
*filer_window
)
783 switch (event
->keyval
)
801 remove_view(filer_window
);
802 filer_window
->path
= pathdup(make_path(
805 add_view(filer_window
);
806 scan_dir(filer_window
);
813 FileItem
*selected_item(Collection
*collection
)
817 g_return_val_if_fail(collection
!= NULL
, NULL
);
818 g_return_val_if_fail(IS_COLLECTION(collection
), NULL
);
819 g_return_val_if_fail(collection
->number_selected
== 1, NULL
);
821 for (i
= 0; i
< collection
->number_of_items
; i
++)
822 if (collection
->items
[i
].selected
)
823 return (FileItem
*) collection
->items
[i
].data
;
825 g_warning("selected_item: number_selected is wrong\n");
830 /* Refresh all windows onto this directory */
831 void refresh_dirs(char *path
)
836 real
= pathdup(path
);
837 list
= g_hash_table_lookup(path_to_window_list
, real
);
843 may_rescan((FilerWindow
*) list
->data
);
848 void filer_opendir(char *path
, gboolean panel
, Side panel_side
)
850 GtkWidget
*hbox
, *scrollbar
, *collection
;
851 FilerWindow
*filer_window
;
852 GtkTargetEntry target_table
[] =
854 {"text/uri-list", 0, TARGET_URI_LIST
},
855 {"STRING", 0, TARGET_STRING
},
858 filer_window
= g_malloc(sizeof(FilerWindow
));
859 filer_window
->path
= pathdup(path
);
860 filer_window
->dir
= NULL
; /* Not scanning */
861 filer_window
->show_hidden
= FALSE
;
862 filer_window
->panel
= panel
;
863 filer_window
->panel_side
= panel_side
;
864 filer_window
->temp_item_selected
= FALSE
;
866 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
868 collection
= collection_new(NULL
);
869 gtk_object_set_data(GTK_OBJECT(collection
),
870 "filer_window", filer_window
);
871 filer_window
->collection
= COLLECTION(collection
);
872 collection_set_item_size(filer_window
->collection
, 64, 64);
873 collection_set_functions(filer_window
->collection
,
874 draw_item
, test_point
);
876 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
877 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
878 "enter-notify-event",
879 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
880 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
881 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
882 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
883 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
884 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
885 filer_window_destroyed
, filer_window
);
887 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
888 open_item
, filer_window
);
889 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
890 show_menu
, filer_window
);
891 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
892 gain_selection
, filer_window
);
893 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
894 lose_selection
, filer_window
);
895 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
896 drag_selection
, filer_window
);
897 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
898 drag_data_get
, filer_window
);
899 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
900 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
901 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
902 GTK_SIGNAL_FUNC(selection_get
), NULL
);
903 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
905 sizeof(target_table
) / sizeof(*target_table
));
907 drag_set_dest(collection
);
911 int swidth
, sheight
, iwidth
, iheight
;
912 GtkWidget
*frame
, *win
= filer_window
->window
;
914 collection_set_panel(filer_window
->collection
, TRUE
);
916 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
917 iwidth
= filer_window
->collection
->item_width
;
918 iheight
= filer_window
->collection
->item_height
;
920 if (panel_side
== TOP
|| panel_side
== BOTTOM
)
922 int height
= iheight
+ PANEL_BORDER
;
923 int y
= panel_side
== TOP
925 : sheight
- height
- PANEL_BORDER
;
927 gtk_widget_set_usize(collection
, swidth
, height
);
928 gtk_widget_set_uposition(win
, 0, y
);
932 int width
= iwidth
+ PANEL_BORDER
;
933 int x
= panel_side
== LEFT
935 : swidth
- width
- PANEL_BORDER
;
937 gtk_widget_set_usize(collection
, width
, sheight
);
938 gtk_widget_set_uposition(win
, x
, 0);
941 frame
= gtk_frame_new(NULL
);
942 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
943 gtk_container_add(GTK_CONTAINER(frame
), collection
);
944 gtk_container_add(GTK_CONTAINER(win
), frame
);
946 gtk_widget_realize(win
);
947 make_panel_window(win
->window
);
951 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
953 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
954 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
957 hbox
= gtk_hbox_new(FALSE
, 0);
958 gtk_container_add(GTK_CONTAINER(filer_window
->window
), hbox
);
960 gtk_box_pack_start(GTK_BOX(hbox
), collection
, TRUE
, TRUE
, 0);
962 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
963 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
964 gtk_accel_group_attach(filer_keys
,
965 GTK_OBJECT(filer_window
->window
));
968 gtk_widget_show_all(filer_window
->window
);
971 load_default_pixmaps(collection
->window
);
973 add_view(filer_window
);
974 scan_dir(filer_window
);