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 /* Link paths to GLists of filer windows */
40 GHashTable
*path_to_window_list
= NULL
;
42 static FilerWindow
*window_with_selection
= NULL
;
44 /* Static prototypes */
45 static void filer_window_destroyed(GtkWidget
*widget
,
46 FilerWindow
*filer_window
);
47 static gboolean
idle_scan_dir(gpointer data
);
48 static void draw_item(GtkWidget
*widget
,
51 void show_menu(Collection
*collection
, GdkEventButton
*event
,
52 int number_selected
, gpointer user_data
);
53 static int sort_by_name(const void *item1
, const void *item2
);
54 static void add_item(FilerWindow
*filer_window
, char *leafname
);
55 static gboolean
test_point(Collection
*collection
,
56 int point_x
, int point_y
,
58 int width
, int height
);
59 static void stop_scanning(FilerWindow
*filer_window
);
60 static gint
focus_in(GtkWidget
*widget
,
62 FilerWindow
*filer_window
);
63 static gint
focus_out(GtkWidget
*widget
,
65 FilerWindow
*filer_window
);
66 static void add_view(FilerWindow
*filer_window
);
67 static void remove_view(FilerWindow
*filer_window
);
68 static void free_item(FileItem
*item
);
69 static gboolean
remove_deleted(gpointer item_data
, gpointer data
);
71 static GdkAtom xa_string
;
80 xa_string
= gdk_atom_intern("STRING", FALSE
);
82 path_to_window_list
= g_hash_table_new(g_str_hash
, g_str_equal
);
86 /* When a filer window shows a directory, use this function to add
87 * it to the list of directories to be updated when the contents
90 static void add_view(FilerWindow
*filer_window
)
92 GList
*list
, *newlist
;
94 g_return_if_fail(filer_window
!= NULL
);
96 list
= g_hash_table_lookup(path_to_window_list
, filer_window
->path
);
97 newlist
= g_list_prepend(list
, filer_window
);
99 g_hash_table_insert(path_to_window_list
, filer_window
->path
,
103 /* When a filer window no longer shows a directory, call this to reverse
104 * the effect of add_view().
106 static void remove_view(FilerWindow
*filer_window
)
108 GList
*list
, *newlist
;
110 g_return_if_fail(filer_window
!= NULL
);
112 list
= g_hash_table_lookup(path_to_window_list
, filer_window
->path
);
113 newlist
= g_list_remove(list
, filer_window
);
115 g_hash_table_insert(path_to_window_list
, filer_window
->path
,
119 /* Go though all the FileItems in a collection, freeing all items.
120 * TODO: Maybe we should cache icons?
122 static void free_items(FilerWindow
*filer_window
)
125 Collection
*collection
= filer_window
->collection
;
127 for (i
= 0; i
< collection
->number_of_items
; i
++)
129 free_item((FileItem
*) collection
->items
[i
].data
);
130 collection
->items
[i
].data
= NULL
;
134 /* Set one item in a collection to NULL, freeing all data for it */
135 static void free_item(FileItem
*item
)
137 if (item
->flags
& ITEM_FLAG_TEMP_ICON
)
139 gdk_pixmap_unref(item
->image
->pixmap
);
140 gdk_pixmap_unref(item
->image
->mask
);
142 item
->image
= default_pixmap
+ TYPE_ERROR
;
144 g_free(item
->leafname
);
148 static void filer_window_destroyed(GtkWidget
*widget
,
149 FilerWindow
*filer_window
)
151 if (window_with_selection
== filer_window
)
152 window_with_selection
= NULL
;
153 if (window_with_focus
== filer_window
)
154 window_with_focus
= NULL
;
156 remove_view(filer_window
);
158 free_items(filer_window
);
159 if (filer_window
->dir
)
160 stop_scanning(filer_window
);
161 g_free(filer_window
->path
);
162 g_free(filer_window
);
164 if (--number_of_windows
< 1)
168 static void stop_scanning(FilerWindow
*filer_window
)
170 g_return_if_fail(filer_window
->dir
!= NULL
);
172 closedir(filer_window
->dir
);
173 gtk_idle_remove(filer_window
->idle_scan_id
);
174 filer_window
->dir
= NULL
;
175 if (filer_window
->window
->window
)
176 gdk_window_set_cursor(filer_window
->window
->window
, NULL
);
179 /* This is called while we are scanning the directory */
180 static gboolean
idle_scan_dir(gpointer data
)
183 FilerWindow
*filer_window
= (FilerWindow
*) data
;
187 next
= readdir(filer_window
->dir
);
190 closedir(filer_window
->dir
);
191 filer_window
->dir
= NULL
;
192 gdk_window_set_cursor(filer_window
->window
->window
,
195 collection_set_item_size(filer_window
->collection
,
196 filer_window
->scan_min_width
,
197 filer_window
->collection
->item_height
);
198 collection_qsort(filer_window
->collection
,
199 filer_window
->sort_fn
);
200 if (filer_window
->flags
& FILER_UPDATING
)
202 collection_delete_if(filer_window
->collection
,
203 remove_deleted
, NULL
);
205 if (filer_window
->flags
& FILER_NEEDS_RESCAN
)
206 update_dir(filer_window
);
208 return FALSE
; /* Finished */
211 add_item(filer_window
, next
->d_name
);
212 } while (!gtk_events_pending());
217 /* Add a single object to a directory display */
218 static void add_item(FilerWindow
*filer_window
, char *leafname
)
227 if (leafname
[0] == '.')
229 if (filer_window
->show_hidden
== FALSE
|| leafname
[1] == '\0'
230 || (leafname
[1] == '.' && leafname
[2] == '\0'))
234 item
= g_malloc(sizeof(FileItem
));
235 item
->leafname
= g_strdup(leafname
);
236 item
->flags
= (ItemFlags
) 0;
238 path
= make_path(filer_window
->path
, leafname
);
239 if (lstat(path
->str
, &info
))
240 base_type
= TYPE_ERROR
;
243 if (S_ISREG(info
.st_mode
))
244 base_type
= TYPE_FILE
;
245 else if (S_ISDIR(info
.st_mode
))
247 base_type
= TYPE_DIRECTORY
;
249 if (g_hash_table_lookup(mtab_mounts
, path
->str
))
250 item
->flags
|= ITEM_FLAG_MOUNT_POINT
252 else if (g_hash_table_lookup(fstab_mounts
, path
->str
))
253 item
->flags
|= ITEM_FLAG_MOUNT_POINT
;
255 else if (S_ISBLK(info
.st_mode
))
256 base_type
= TYPE_BLOCK_DEVICE
;
257 else if (S_ISCHR(info
.st_mode
))
258 base_type
= TYPE_CHAR_DEVICE
;
259 else if (S_ISFIFO(info
.st_mode
))
260 base_type
= TYPE_PIPE
;
261 else if (S_ISSOCK(info
.st_mode
))
262 base_type
= TYPE_SOCKET
;
263 else if (S_ISLNK(info
.st_mode
))
265 if (stat(path
->str
, &info
))
267 base_type
= TYPE_ERROR
;
271 if (S_ISREG(info
.st_mode
))
272 base_type
= TYPE_FILE
;
273 else if (S_ISDIR(info
.st_mode
))
274 base_type
= TYPE_DIRECTORY
;
275 else if (S_ISBLK(info
.st_mode
))
276 base_type
= TYPE_BLOCK_DEVICE
;
277 else if (S_ISCHR(info
.st_mode
))
278 base_type
= TYPE_CHAR_DEVICE
;
279 else if (S_ISFIFO(info
.st_mode
))
280 base_type
= TYPE_PIPE
;
281 else if (S_ISSOCK(info
.st_mode
))
282 base_type
= TYPE_SOCKET
;
284 base_type
= TYPE_UNKNOWN
;
287 item
->flags
|= ITEM_FLAG_SYMLINK
;
290 base_type
= TYPE_UNKNOWN
;
293 item
->base_type
= base_type
;
294 item
->mime_type
= NULL
;
296 if (base_type
== TYPE_DIRECTORY
&&
297 !(item
->flags
& ITEM_FLAG_MOUNT_POINT
))
299 uid_t uid
= info
.st_uid
;
301 /* Might be an application directory - better check...
302 * AppRun must have the same owner as the directory
303 * (to stop people putting an AppRun in, eg, /tmp)
305 g_string_append(path
, "/AppRun");
306 if (!stat(path
->str
, &info
) && info
.st_uid
== uid
)
308 item
->flags
|= ITEM_FLAG_APPDIR
;
312 if (item
->flags
& ITEM_FLAG_APPDIR
) /* path still ends /AppRun */
314 MaskedPixmap
*app_icon
;
316 g_string_truncate(path
, path
->len
- 3);
317 g_string_append(path
, "Icon.xpm");
318 app_icon
= load_pixmap_from(filer_window
->window
, path
->str
);
321 item
->image
= app_icon
;
322 item
->flags
|= ITEM_FLAG_TEMP_ICON
;
325 item
->image
= default_pixmap
+ TYPE_APPDIR
;
329 if (base_type
== TYPE_FILE
&&
330 (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
332 item
->image
= default_pixmap
+ TYPE_EXEC_FILE
;
333 item
->flags
|= ITEM_FLAG_EXEC_FILE
;
335 else if (base_type
== TYPE_FILE
)
337 item
->mime_type
= type_from_path(path
->str
);
338 item
->image
= type_to_icon(filer_window
->window
,
342 item
->image
= default_pixmap
+ base_type
;
345 item
->text_width
= gdk_string_width(filer_window
->window
->style
->font
,
348 /* XXX: Must be a better way... */
349 item
->pix_width
= ((GdkPixmapPrivate
*) item
->image
->pixmap
)->width
;
350 item
->pix_height
= ((GdkPixmapPrivate
*) item
->image
->pixmap
)->height
;
352 item_width
= MAX(item
->pix_width
, item
->text_width
) + 4;
354 if (item_width
> filer_window
->scan_min_width
)
355 filer_window
->scan_min_width
= item_width
;
357 if (item_width
> filer_window
->collection
->item_width
)
358 collection_set_item_size(filer_window
->collection
,
360 filer_window
->collection
->item_height
);
362 old_item
= collection_find_item(filer_window
->collection
, item
,
367 CollectionItem
*old
=
368 &filer_window
->collection
->items
[old_item
];
370 free_item((FileItem
*) old
->data
);
372 collection_draw_item(filer_window
->collection
, old_item
, TRUE
);
375 collection_insert(filer_window
->collection
, item
);
378 /* Is a point inside an item? */
379 static gboolean
test_point(Collection
*collection
,
380 int point_x
, int point_y
,
381 CollectionItem
*colitem
,
382 int width
, int height
)
384 FileItem
*item
= (FileItem
*) colitem
->data
;
385 GdkFont
*font
= GTK_WIDGET(collection
)->style
->font
;
386 int text_height
= font
->ascent
+ font
->descent
;
387 int image_y
= MAX(0, MAX_ICON_HEIGHT
- item
->pix_height
);
388 int image_width
= (item
->pix_width
>> 1) + 2;
389 int text_width
= (item
->text_width
>> 1) + 2;
392 if (point_y
< image_y
)
393 return FALSE
; /* Too high up (don't worry about too low) */
395 if (point_y
<= image_y
+ item
->pix_height
+ 2)
396 x_limit
= image_width
;
397 else if (point_y
> height
- text_height
- 2)
398 x_limit
= text_width
;
400 x_limit
= MIN(image_width
, text_width
);
402 return ABS(point_x
- (width
>> 1)) < x_limit
;
405 static void draw_item(GtkWidget
*widget
,
406 CollectionItem
*colitem
,
409 FileItem
*item
= (FileItem
*) colitem
->data
;
410 GdkGC
*gc
= colitem
->selected
? widget
->style
->white_gc
411 : widget
->style
->black_gc
;
412 int image_x
= area
->x
+ ((area
->width
- item
->pix_width
) >> 1);
413 GdkFont
*font
= widget
->style
->font
;
414 int text_x
= area
->x
+ ((area
->width
- item
->text_width
) >> 1);
415 int text_y
= area
->y
+ area
->height
- font
->descent
- 2;
416 int text_height
= font
->ascent
+ font
->descent
;
422 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
424 image_y
= MAX(0, MAX_ICON_HEIGHT
- item
->pix_height
);
425 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
426 gdk_draw_pixmap(widget
->window
, gc
,
428 0, 0, /* Source x,y */
429 image_x
, area
->y
+ image_y
, /* Dest x,y */
430 -1, MIN(item
->pix_height
, MAX_ICON_HEIGHT
));
432 if (item
->flags
& ITEM_FLAG_SYMLINK
)
434 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
435 gdk_gc_set_clip_mask(gc
,
436 default_pixmap
[TYPE_SYMLINK
].mask
);
437 gdk_draw_pixmap(widget
->window
, gc
,
438 default_pixmap
[TYPE_SYMLINK
].pixmap
,
439 0, 0, /* Source x,y */
440 image_x
, area
->y
+ 8, /* Dest x,y */
443 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
445 int type
= item
->flags
& ITEM_FLAG_MOUNTED
448 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
449 gdk_gc_set_clip_mask(gc
,
450 default_pixmap
[type
].mask
);
451 gdk_draw_pixmap(widget
->window
, gc
,
452 default_pixmap
[type
].pixmap
,
453 0, 0, /* Source x,y */
454 image_x
, area
->y
+ 8, /* Dest x,y */
458 gdk_gc_set_clip_mask(gc
, NULL
);
459 gdk_gc_set_clip_origin(gc
, 0, 0);
462 if (colitem
->selected
)
463 gtk_paint_flat_box(widget
->style
, widget
->window
,
464 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
465 NULL
, widget
, "text",
466 text_x
, text_y
- font
->ascent
,
470 gdk_draw_text(widget
->window
,
472 colitem
->selected
? widget
->style
->white_gc
473 : widget
->style
->black_gc
,
475 item
->leafname
, strlen(item
->leafname
));
478 void show_menu(Collection
*collection
, GdkEventButton
*event
,
479 int item
, gpointer user_data
)
481 show_filer_menu((FilerWindow
*) user_data
, event
, item
);
484 static void may_rescan(FilerWindow
*filer_window
)
488 g_return_if_fail(filer_window
!= NULL
);
490 if (stat(filer_window
->path
, &info
))
492 delayed_error("ROX-Filer", "Directory deleted");
493 gtk_widget_destroy(filer_window
->window
);
495 else if (info
.st_mtime
> filer_window
->m_time
)
497 if (filer_window
->dir
)
498 filer_window
->flags
|= FILER_NEEDS_RESCAN
;
500 update_dir(filer_window
);
504 /* Callback to collection_delete_if() */
505 static gboolean
remove_deleted(gpointer item_data
, gpointer data
)
507 FileItem
*item
= (FileItem
*) item_data
;
509 if (item
->flags
& ITEM_FLAG_MAY_DELETE
)
518 /* Forget the old contents of a filer window and scan the directory
519 * from the start. If we are already scanning then rescan later.
521 void scan_dir(FilerWindow
*filer_window
)
523 if (filer_window
->dir
)
524 stop_scanning(filer_window
);
526 free_items(filer_window
);
527 collection_clear(filer_window
->collection
);
529 update_dir(filer_window
);
530 filer_window
->flags
&= ~FILER_UPDATING
;
532 gdk_window_set_cursor(filer_window
->window
->window
,
533 gdk_cursor_new(GDK_WATCH
));
536 /* Like scan_dir(), but assume new display will be similar to the old
537 * one (less flicker and doesn't lose the selection).
539 void update_dir(FilerWindow
*filer_window
)
541 Collection
*collection
= filer_window
->collection
;
545 if (filer_window
->dir
)
547 /* Already scanning - start again when we finish */
548 filer_window
->flags
|= FILER_NEEDS_RESCAN
;
551 filer_window
->flags
&= ~FILER_NEEDS_RESCAN
;
552 filer_window
->flags
|= FILER_UPDATING
;
554 for (i
= 0; i
< collection
->number_of_items
; i
++)
556 FileItem
*item
= (FileItem
*) collection
->items
[i
].data
;
557 item
->flags
|= ITEM_FLAG_MAY_DELETE
;
562 gtk_window_set_title(GTK_WINDOW(filer_window
->window
),
565 if (stat(filer_window
->path
, &info
))
567 report_error("Error statting directory", g_strerror(errno
));
570 filer_window
->m_time
= info
.st_mtime
;
572 filer_window
->dir
= opendir(filer_window
->path
);
573 if (!filer_window
->dir
)
575 report_error("Error scanning directory", g_strerror(errno
));
579 filer_window
->scan_min_width
= 64;
581 filer_window
->idle_scan_id
= gtk_idle_add(idle_scan_dir
, filer_window
);
584 /* Another app has grabbed the selection */
585 static gint
collection_lose_selection(GtkWidget
*widget
,
586 GdkEventSelection
*event
)
588 if (window_with_selection
&&
589 window_with_selection
->collection
== COLLECTION(widget
))
591 FilerWindow
*filer_window
= window_with_selection
;
592 window_with_selection
= NULL
;
593 collection_clear_selection(filer_window
->collection
);
599 /* Someone wants us to send them the selection */
600 static void selection_get(GtkWidget
*widget
,
601 GtkSelectionData
*selection_data
,
606 GString
*reply
, *header
;
607 FilerWindow
*filer_window
;
609 Collection
*collection
;
611 filer_window
= gtk_object_get_data(GTK_OBJECT(widget
), "filer_window");
613 reply
= g_string_new(NULL
);
614 header
= g_string_new(NULL
);
619 g_string_sprintf(header
, " %s",
620 make_path(filer_window
->path
, "")->str
);
622 case TARGET_URI_LIST
:
623 g_string_sprintf(header
, " file://%s%s",
625 make_path(filer_window
->path
, "")->str
);
629 collection
= filer_window
->collection
;
630 for (i
= 0; i
< collection
->number_of_items
; i
++)
632 if (collection
->items
[i
].selected
)
635 (FileItem
*) collection
->items
[i
].data
;
637 g_string_append(reply
, header
->str
);
638 g_string_append(reply
, item
->leafname
);
641 /* This works, but I don't think I like it... */
642 /* g_string_append_c(reply, ' '); */
644 gtk_selection_data_set(selection_data
, xa_string
,
645 8, reply
->str
+ 1, reply
->len
- 1);
646 g_string_free(reply
, TRUE
);
647 g_string_free(header
, TRUE
);
650 /* No items are now selected. This might be because another app claimed
651 * the selection or because the user unselected all the items.
653 static void lose_selection(Collection
*collection
,
657 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
659 if (window_with_selection
== filer_window
)
661 window_with_selection
= NULL
;
662 gtk_selection_owner_set(NULL
,
663 GDK_SELECTION_PRIMARY
,
668 static void gain_selection(Collection
*collection
,
672 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
674 if (gtk_selection_owner_set(GTK_WIDGET(collection
),
675 GDK_SELECTION_PRIMARY
,
678 window_with_selection
= filer_window
;
681 collection_clear_selection(filer_window
->collection
);
684 static int sort_by_name(const void *item1
, const void *item2
)
686 return strcmp((*((FileItem
**)item1
))->leafname
,
687 (*((FileItem
**)item2
))->leafname
);
690 static int sort_by_type(const void *item1
, const void *item2
)
692 const FileItem
*i1
= (FileItem
*) ((CollectionItem
*) item1
)->data
;
693 const FileItem
*i2
= (FileItem
*) ((CollectionItem
*) item2
)->data
;
696 int diff
= i1
->base_type
- i2
->base_type
;
699 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
700 - (i2
->flags
& ITEM_FLAG_APPDIR
);
702 return diff
> 0 ? 1 : -1;
709 diff
= strcmp(m1
->media_type
, m2
->media_type
);
711 diff
= strcmp(m1
->subtype
, m2
->subtype
);
719 return diff
> 0 ? 1 : -1;
721 return sort_by_name(item1
, item2
);
724 void open_item(Collection
*collection
,
725 gpointer item_data
, int item_number
,
728 FilerWindow
*filer_window
= (FilerWindow
*) user_data
;
729 FileItem
*item
= (FileItem
*) item_data
;
730 GdkEventButton
*event
;
733 gboolean shift
, adjust
;
735 event
= (GdkEventButton
*) gtk_get_current_event();
736 full_path
= make_path(filer_window
->path
, item
->leafname
)->str
;
738 collection_wink_item(filer_window
->collection
, item_number
);
740 if (event
->type
== GDK_2BUTTON_PRESS
|| event
->type
== GDK_BUTTON_PRESS
)
742 shift
= event
->state
& GDK_SHIFT_MASK
;
743 adjust
= event
->button
!= 1 || event
->state
& GDK_CONTROL_MASK
;
751 widget
= filer_window
->window
;
753 switch (item
->base_type
)
756 if (item
->flags
& ITEM_FLAG_APPDIR
&& !shift
)
758 run_app(make_path(filer_window
->path
,
759 item
->leafname
)->str
);
760 if (adjust
&& !filer_window
->panel
)
761 gtk_widget_destroy(widget
);
764 if (adjust
|| filer_window
->panel
)
765 filer_opendir(full_path
, FALSE
, BOTTOM
);
768 remove_view(filer_window
);
769 filer_window
->path
= pathdup(full_path
);
770 add_view(filer_window
);
771 scan_dir(filer_window
);
775 if (item
->flags
& ITEM_FLAG_EXEC_FILE
&& !shift
)
777 char *argv
[] = {NULL
, NULL
};
781 if (spawn_full(argv
, getenv("HOME"), 0))
783 if (adjust
&& !filer_window
->panel
)
784 gtk_widget_destroy(widget
);
787 report_error("ROX-Filer",
788 "Failed to fork() child");
793 MIME_type
*type
= shift
? &text_plain
796 g_return_if_fail(type
!= NULL
);
798 if (type_open(full_path
, type
))
800 if (adjust
&& !filer_window
->panel
)
801 gtk_widget_destroy(widget
);
805 message
= g_string_new(NULL
);
806 g_string_sprintf(message
, "No open "
807 "action specified for files of "
811 report_error("ROX-Filer", message
->str
);
812 g_string_free(message
, TRUE
);
817 report_error("open_item",
818 "I don't know how to open that");
823 static gint
pointer_in(GtkWidget
*widget
,
824 GdkEventCrossing
*event
,
825 FilerWindow
*filer_window
)
827 may_rescan(filer_window
);
831 static gint
focus_in(GtkWidget
*widget
,
832 GdkEventFocus
*event
,
833 FilerWindow
*filer_window
)
835 window_with_focus
= filer_window
;
840 static gint
focus_out(GtkWidget
*widget
,
841 GdkEventFocus
*event
,
842 FilerWindow
*filer_window
)
844 /* TODO: Shade the cursor */
849 /* Handle keys that can't be bound with the menu */
850 static gint
key_press_event(GtkWidget
*widget
,
852 FilerWindow
*filer_window
)
854 switch (event
->keyval
)
872 remove_view(filer_window
);
873 filer_window
->path
= pathdup(make_path(
876 add_view(filer_window
);
877 scan_dir(filer_window
);
884 FileItem
*selected_item(Collection
*collection
)
888 g_return_val_if_fail(collection
!= NULL
, NULL
);
889 g_return_val_if_fail(IS_COLLECTION(collection
), NULL
);
890 g_return_val_if_fail(collection
->number_selected
== 1, NULL
);
892 for (i
= 0; i
< collection
->number_of_items
; i
++)
893 if (collection
->items
[i
].selected
)
894 return (FileItem
*) collection
->items
[i
].data
;
896 g_warning("selected_item: number_selected is wrong\n");
901 /* Refresh all windows onto this directory */
902 void refresh_dirs(char *path
)
907 real
= pathdup(path
);
908 list
= g_hash_table_lookup(path_to_window_list
, real
);
914 update_dir((FilerWindow
*) list
->data
);
919 void filer_opendir(char *path
, gboolean panel
, Side panel_side
)
921 GtkWidget
*hbox
, *scrollbar
, *collection
;
922 FilerWindow
*filer_window
;
923 GtkTargetEntry target_table
[] =
925 {"text/uri-list", 0, TARGET_URI_LIST
},
926 {"STRING", 0, TARGET_STRING
},
929 filer_window
= g_malloc(sizeof(FilerWindow
));
930 filer_window
->path
= pathdup(path
);
931 filer_window
->dir
= NULL
; /* Not scanning */
932 filer_window
->show_hidden
= FALSE
;
933 filer_window
->panel
= panel
;
934 filer_window
->panel_side
= panel_side
;
935 filer_window
->temp_item_selected
= FALSE
;
936 filer_window
->sort_fn
= sort_by_type
;
937 filer_window
->flags
= (FilerFlags
) 0;
939 filer_window
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
941 collection
= collection_new(NULL
);
942 gtk_object_set_data(GTK_OBJECT(collection
),
943 "filer_window", filer_window
);
944 filer_window
->collection
= COLLECTION(collection
);
945 collection_set_item_size(filer_window
->collection
, 64, 64);
946 collection_set_functions(filer_window
->collection
,
947 draw_item
, test_point
);
949 gtk_widget_add_events(filer_window
->window
, GDK_ENTER_NOTIFY
);
950 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
951 "enter-notify-event",
952 GTK_SIGNAL_FUNC(pointer_in
), filer_window
);
953 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_in_event",
954 GTK_SIGNAL_FUNC(focus_in
), filer_window
);
955 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "focus_out_event",
956 GTK_SIGNAL_FUNC(focus_out
), filer_window
);
957 gtk_signal_connect(GTK_OBJECT(filer_window
->window
), "destroy",
958 filer_window_destroyed
, filer_window
);
960 gtk_signal_connect(GTK_OBJECT(filer_window
->collection
), "open_item",
961 open_item
, filer_window
);
962 gtk_signal_connect(GTK_OBJECT(collection
), "show_menu",
963 show_menu
, filer_window
);
964 gtk_signal_connect(GTK_OBJECT(collection
), "gain_selection",
965 gain_selection
, filer_window
);
966 gtk_signal_connect(GTK_OBJECT(collection
), "lose_selection",
967 lose_selection
, filer_window
);
968 gtk_signal_connect(GTK_OBJECT(collection
), "drag_selection",
969 drag_selection
, filer_window
);
970 gtk_signal_connect(GTK_OBJECT(collection
), "drag_data_get",
971 drag_data_get
, filer_window
);
972 gtk_signal_connect(GTK_OBJECT(collection
), "selection_clear_event",
973 GTK_SIGNAL_FUNC(collection_lose_selection
), NULL
);
974 gtk_signal_connect (GTK_OBJECT(collection
), "selection_get",
975 GTK_SIGNAL_FUNC(selection_get
), NULL
);
976 gtk_selection_add_targets(collection
, GDK_SELECTION_PRIMARY
,
978 sizeof(target_table
) / sizeof(*target_table
));
980 drag_set_dest(collection
);
984 int swidth
, sheight
, iwidth
, iheight
;
985 GtkWidget
*frame
, *win
= filer_window
->window
;
987 collection_set_panel(filer_window
->collection
, TRUE
);
989 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth
, &sheight
);
990 iwidth
= filer_window
->collection
->item_width
;
991 iheight
= filer_window
->collection
->item_height
;
993 if (panel_side
== TOP
|| panel_side
== BOTTOM
)
995 int height
= iheight
+ PANEL_BORDER
;
996 int y
= panel_side
== TOP
998 : sheight
- height
- PANEL_BORDER
;
1000 gtk_widget_set_usize(collection
, swidth
, height
);
1001 gtk_widget_set_uposition(win
, 0, y
);
1005 int width
= iwidth
+ PANEL_BORDER
;
1006 int x
= panel_side
== LEFT
1008 : swidth
- width
- PANEL_BORDER
;
1010 gtk_widget_set_usize(collection
, width
, sheight
);
1011 gtk_widget_set_uposition(win
, x
, 0);
1014 frame
= gtk_frame_new(NULL
);
1015 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_OUT
);
1016 gtk_container_add(GTK_CONTAINER(frame
), collection
);
1017 gtk_container_add(GTK_CONTAINER(win
), frame
);
1019 gtk_widget_realize(win
);
1020 make_panel_window(win
->window
);
1024 gtk_signal_connect(GTK_OBJECT(filer_window
->window
),
1026 GTK_SIGNAL_FUNC(key_press_event
), filer_window
);
1027 gtk_window_set_default_size(GTK_WINDOW(filer_window
->window
),
1030 hbox
= gtk_hbox_new(FALSE
, 0);
1031 gtk_container_add(GTK_CONTAINER(filer_window
->window
), hbox
);
1033 gtk_box_pack_start(GTK_BOX(hbox
), collection
, TRUE
, TRUE
, 0);
1035 scrollbar
= gtk_vscrollbar_new(COLLECTION(collection
)->vadj
);
1036 gtk_box_pack_start(GTK_BOX(hbox
), scrollbar
, FALSE
, TRUE
, 0);
1037 gtk_accel_group_attach(filer_keys
,
1038 GTK_OBJECT(filer_window
->window
));
1041 gtk_widget_show_all(filer_window
->window
);
1042 number_of_windows
++;
1044 load_default_pixmaps(collection
->window
);
1046 add_view(filer_window
);
1047 scan_dir(filer_window
);