r70: Removed some old code. Dragging now quotes the correct MIME type for files.
[rox-filer.git] / ROX-Filer / src / filer.c
blobf5bdef070e5030e0f09108ecf77ffe7982947a1e
1 /* vi: set cindent:
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * By Thomas Leonard, <tal197@ecs.soton.ac.uk>.
6 */
8 /* filer.c - code for handling filer windows */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <errno.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15 #include <time.h>
17 #include <gtk/gtk.h>
18 #include <gdk/gdkx.h>
19 #include <gdk/gdkprivate.h> /* XXX - find another way to do this */
20 #include <gdk/gdkkeysyms.h>
21 #include <collection.h>
23 #include "main.h"
24 #include "support.h"
25 #include "gui_support.h"
26 #include "filer.h"
27 #include "pixmaps.h"
28 #include "menu.h"
29 #include "dnd.h"
30 #include "apps.h"
31 #include "mount.h"
32 #include "type.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;
43 static FilerWindow *panel_with_timeout = NULL;
44 static gint panel_timeout;
46 /* Static prototypes */
47 static void filer_window_destroyed(GtkWidget *widget,
48 FilerWindow *filer_window);
49 static gboolean idle_scan_dir(gpointer data);
50 static void draw_item(GtkWidget *widget,
51 CollectionItem *item,
52 GdkRectangle *area);
53 void show_menu(Collection *collection, GdkEventButton *event,
54 int number_selected, gpointer user_data);
55 static int sort_by_name(const void *item1, const void *item2);
56 static void add_item(FilerWindow *filer_window, char *leafname);
57 static gboolean test_point(Collection *collection,
58 int point_x, int point_y,
59 CollectionItem *item,
60 int width, int height);
61 static void stop_scanning(FilerWindow *filer_window);
62 static gint focus_in(GtkWidget *widget,
63 GdkEventFocus *event,
64 FilerWindow *filer_window);
65 static gint focus_out(GtkWidget *widget,
66 GdkEventFocus *event,
67 FilerWindow *filer_window);
68 static void add_view(FilerWindow *filer_window);
69 static void remove_view(FilerWindow *filer_window);
71 static GdkAtom xa_string;
72 enum
74 TARGET_STRING,
75 TARGET_URI_LIST,
78 void filer_init()
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
88 * change.
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);
98 if (newlist != list)
99 g_hash_table_insert(path_to_window_list, filer_window->path,
100 newlist);
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);
114 if (newlist != list)
115 g_hash_table_insert(path_to_window_list, filer_window->path,
116 newlist);
119 /* Go though all the FileItems in a collection, freeing all the temp
120 * icons.
121 * TODO: Maybe we should cache icons?
123 static void free_temp_icons(FilerWindow *filer_window)
125 int i;
126 Collection *collection = filer_window->collection;
128 for (i = 0; i < collection->number_of_items; i++)
130 FileItem *item = (FileItem *) collection->items[i].data;
131 if (item->flags & ITEM_FLAG_TEMP_ICON)
133 gdk_pixmap_unref(item->image->pixmap);
134 gdk_pixmap_unref(item->image->mask);
135 g_free(item->image);
136 item->image = default_pixmap + TYPE_ERROR;
141 static void filer_window_destroyed(GtkWidget *widget,
142 FilerWindow *filer_window)
144 if (window_with_selection == filer_window)
145 window_with_selection = NULL;
146 if (window_with_focus == filer_window)
147 window_with_focus = NULL;
148 if (panel_with_timeout == filer_window)
150 /* Can this happen? */
151 panel_with_timeout = NULL;
152 gtk_timeout_remove(panel_timeout);
155 remove_view(filer_window);
157 free_temp_icons(filer_window);
158 if (filer_window->dir)
159 stop_scanning(filer_window);
160 g_free(filer_window->path);
161 g_free(filer_window);
163 if (--number_of_windows < 1)
164 gtk_main_quit();
167 static void stop_scanning(FilerWindow *filer_window)
169 g_return_if_fail(filer_window->dir != NULL);
171 closedir(filer_window->dir);
172 gtk_idle_remove(filer_window->idle_scan_id);
173 filer_window->dir = NULL;
176 /* This is called while we are scanning the directory */
177 static gboolean idle_scan_dir(gpointer data)
179 struct dirent *next;
180 FilerWindow *filer_window = (FilerWindow *) data;
184 next = readdir(filer_window->dir);
185 if (!next)
187 closedir(filer_window->dir);
188 filer_window->dir = NULL;
190 collection_set_item_size(filer_window->collection,
191 filer_window->scan_min_width,
192 filer_window->collection->item_height);
193 collection_qsort(filer_window->collection,
194 sort_by_name);
195 return FALSE; /* Finished */
198 add_item(filer_window, next->d_name);
199 } while (!gtk_events_pending());
201 return TRUE;
204 /* Add a single object to a directory display */
205 static void add_item(FilerWindow *filer_window, char *leafname)
207 FileItem *item;
208 int item_width;
209 struct stat info;
210 int base_type;
211 GString *path;
213 if (leafname[0] == '.')
215 if (filer_window->show_hidden == FALSE || leafname[1] == '\0'
216 || (leafname[1] == '.' && leafname[2] == '\0'))
217 return;
220 item = g_malloc(sizeof(FileItem));
221 item->leafname = g_strdup(leafname);
222 item->flags = 0;
224 path = make_path(filer_window->path, leafname);
225 if (lstat(path->str, &info))
226 base_type = TYPE_ERROR;
227 else
229 if (S_ISREG(info.st_mode))
230 base_type = TYPE_FILE;
231 else if (S_ISDIR(info.st_mode))
233 base_type = TYPE_DIRECTORY;
235 if (g_hash_table_lookup(mtab_mounts, path->str))
236 item->flags |= ITEM_FLAG_MOUNT_POINT
237 | ITEM_FLAG_MOUNTED;
238 else if (g_hash_table_lookup(fstab_mounts, path->str))
239 item->flags |= ITEM_FLAG_MOUNT_POINT;
241 else if (S_ISBLK(info.st_mode))
242 base_type = TYPE_BLOCK_DEVICE;
243 else if (S_ISCHR(info.st_mode))
244 base_type = TYPE_CHAR_DEVICE;
245 else if (S_ISFIFO(info.st_mode))
246 base_type = TYPE_PIPE;
247 else if (S_ISSOCK(info.st_mode))
248 base_type = TYPE_SOCKET;
249 else if (S_ISLNK(info.st_mode))
251 if (stat(path->str, &info))
253 base_type = TYPE_ERROR;
255 else
257 if (S_ISREG(info.st_mode))
258 base_type = TYPE_FILE;
259 else if (S_ISDIR(info.st_mode))
260 base_type = TYPE_DIRECTORY;
261 else if (S_ISBLK(info.st_mode))
262 base_type = TYPE_BLOCK_DEVICE;
263 else if (S_ISCHR(info.st_mode))
264 base_type = TYPE_CHAR_DEVICE;
265 else if (S_ISFIFO(info.st_mode))
266 base_type = TYPE_PIPE;
267 else if (S_ISSOCK(info.st_mode))
268 base_type = TYPE_SOCKET;
269 else
270 base_type = TYPE_UNKNOWN;
273 item->flags |= ITEM_FLAG_SYMLINK;
275 else
276 base_type = TYPE_UNKNOWN;
279 item->base_type = base_type;
280 item->mime_type = NULL;
282 if (base_type == TYPE_DIRECTORY)
284 /* Might be an application directory - better check... */
285 g_string_append(path, "/AppRun");
286 if (!stat(path->str, &info))
288 item->flags |= ITEM_FLAG_APPDIR;
292 if (item->flags & ITEM_FLAG_APPDIR) /* path still ends /AppRun */
294 MaskedPixmap *app_icon;
296 g_string_truncate(path, path->len - 3);
297 g_string_append(path, "Icon.xpm");
298 app_icon = load_pixmap_from(filer_window->window, path->str);
299 if (app_icon)
301 item->image = app_icon;
302 item->flags |= ITEM_FLAG_TEMP_ICON;
304 else
305 item->image = default_pixmap + TYPE_APPDIR;
307 else
309 if (base_type == TYPE_FILE &&
310 (info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
312 item->image = default_pixmap + TYPE_EXEC_FILE;
313 item->flags |= ITEM_FLAG_EXEC_FILE;
315 else if (base_type == TYPE_FILE)
317 item->mime_type = type_from_path(path->str);
318 item->image = type_to_icon(filer_window->window,
319 item->mime_type);
321 else
322 item->image = default_pixmap + base_type;
325 item->text_width = gdk_string_width(filer_window->window->style->font,
326 leafname);
328 /* XXX: Must be a better way... */
329 item->pix_width = ((GdkPixmapPrivate *) item->image->pixmap)->width;
330 item->pix_height = ((GdkPixmapPrivate *) item->image->pixmap)->height;
332 item_width = MAX(item->pix_width, item->text_width) + 4;
334 if (item_width > filer_window->scan_min_width)
335 filer_window->scan_min_width = item_width;
337 if (item_width > filer_window->collection->item_width)
338 collection_set_item_size(filer_window->collection,
339 item_width,
340 filer_window->collection->item_height);
342 collection_insert(filer_window->collection, item);
345 static gboolean test_point(Collection *collection,
346 int point_x, int point_y,
347 CollectionItem *colitem,
348 int width, int height)
350 FileItem *item = (FileItem *) colitem->data;
351 GdkFont *font = GTK_WIDGET(collection)->style->font;
352 int text_height = font->ascent + font->descent;
353 int x_off = ABS(point_x - (width >> 1));
354 int image_y = MAX(0, MAX_ICON_HEIGHT - item->pix_height);
356 if (x_off <= (item->pix_width >> 1) + 2 &&
357 point_y >= image_y && point_y <= image_y + item->pix_height)
358 return TRUE;
360 if (x_off <= (item->text_width >> 1) + 2 &&
361 point_y > height - text_height - 2)
362 return TRUE;
364 return FALSE;
367 static void draw_item(GtkWidget *widget,
368 CollectionItem *colitem,
369 GdkRectangle *area)
371 FileItem *item = (FileItem *) colitem->data;
372 GdkGC *gc = colitem->selected ? widget->style->white_gc
373 : widget->style->black_gc;
374 int image_x = area->x + ((area->width - item->pix_width) >> 1);
375 GdkFont *font = widget->style->font;
376 int text_x = area->x + ((area->width - item->text_width) >> 1);
377 int text_y = area->y + area->height - font->descent - 2;
378 int text_height = font->ascent + font->descent;
380 if (item->image)
382 int image_y;
384 gdk_gc_set_clip_mask(gc, item->image->mask);
386 image_y = MAX(0, MAX_ICON_HEIGHT - item->pix_height);
387 gdk_gc_set_clip_origin(gc, image_x, area->y + image_y);
388 gdk_draw_pixmap(widget->window, gc,
389 item->image->pixmap,
390 0, 0, /* Source x,y */
391 image_x, area->y + image_y, /* Dest x,y */
392 -1, MIN(item->pix_height, MAX_ICON_HEIGHT));
394 if (item->flags & ITEM_FLAG_SYMLINK)
396 gdk_gc_set_clip_origin(gc, image_x, area->y + 8);
397 gdk_gc_set_clip_mask(gc,
398 default_pixmap[TYPE_SYMLINK].mask);
399 gdk_draw_pixmap(widget->window, gc,
400 default_pixmap[TYPE_SYMLINK].pixmap,
401 0, 0, /* Source x,y */
402 image_x, area->y + 8, /* Dest x,y */
403 -1, -1);
405 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
407 int type = item->flags & ITEM_FLAG_MOUNTED
408 ? TYPE_MOUNTED
409 : TYPE_UNMOUNTED;
410 gdk_gc_set_clip_origin(gc, image_x, area->y + 8);
411 gdk_gc_set_clip_mask(gc,
412 default_pixmap[type].mask);
413 gdk_draw_pixmap(widget->window, gc,
414 default_pixmap[type].pixmap,
415 0, 0, /* Source x,y */
416 image_x, area->y + 8, /* Dest x,y */
417 -1, -1);
420 gdk_gc_set_clip_mask(gc, NULL);
421 gdk_gc_set_clip_origin(gc, 0, 0);
424 if (colitem->selected)
425 gtk_paint_flat_box(widget->style, widget->window,
426 GTK_STATE_SELECTED, GTK_SHADOW_NONE,
427 NULL, widget, "text",
428 text_x, text_y - font->ascent,
429 item->text_width,
430 text_height);
432 gdk_draw_text(widget->window,
433 widget->style->font,
434 colitem->selected ? widget->style->white_gc
435 : widget->style->black_gc,
436 text_x, text_y,
437 item->leafname, strlen(item->leafname));
440 void show_menu(Collection *collection, GdkEventButton *event,
441 int item, gpointer user_data)
443 show_filer_menu((FilerWindow *) user_data, event, item);
446 static void may_rescan(FilerWindow *filer_window)
448 struct stat info;
450 g_return_if_fail(filer_window != NULL);
452 if (stat(filer_window->path, &info))
454 delayed_error("ROX-Filer", "Directory deleted");
455 gtk_widget_destroy(filer_window->window);
457 else if (info.st_mtime > filer_window->m_time)
459 if (filer_window->dir)
460 filer_window->flags |= FILER_NEEDS_RESCAN;
461 else
462 scan_dir(filer_window);
466 void scan_dir(FilerWindow *filer_window)
468 struct stat info;
470 if (filer_window->dir)
471 stop_scanning(filer_window);
472 if (panel_with_timeout == filer_window)
474 panel_with_timeout = NULL;
475 gtk_timeout_remove(panel_timeout);
478 mount_update();
480 free_temp_icons(filer_window);
481 collection_clear(filer_window->collection);
482 gtk_window_set_title(GTK_WINDOW(filer_window->window),
483 filer_window->path);
485 if (stat(filer_window->path, &info))
487 report_error("Error statting directory", g_strerror(errno));
488 return;
490 filer_window->m_time = info.st_mtime;
492 filer_window->dir = opendir(filer_window->path);
493 if (!filer_window->dir)
495 report_error("Error scanning directory", g_strerror(errno));
496 return;
499 filer_window->scan_min_width = 64;
501 filer_window->idle_scan_id = gtk_idle_add(idle_scan_dir, filer_window);
504 /* Another app has grabbed the selection */
505 static gint collection_lose_selection(GtkWidget *widget,
506 GdkEventSelection *event)
508 if (window_with_selection &&
509 window_with_selection->collection == COLLECTION(widget))
511 FilerWindow *filer_window = window_with_selection;
512 window_with_selection = NULL;
513 collection_clear_selection(filer_window->collection);
516 return TRUE;
519 /* Someone wants us to send them the selection */
520 static void selection_get(GtkWidget *widget,
521 GtkSelectionData *selection_data,
522 guint info,
523 guint time,
524 gpointer data)
526 GString *reply, *header;
527 FilerWindow *filer_window;
528 int i;
529 Collection *collection;
531 filer_window = gtk_object_get_data(GTK_OBJECT(widget), "filer_window");
533 reply = g_string_new(NULL);
534 header = g_string_new(NULL);
536 switch (info)
538 case TARGET_STRING:
539 g_string_sprintf(header, " %s",
540 make_path(filer_window->path, "")->str);
541 break;
542 case TARGET_URI_LIST:
543 g_string_sprintf(header, " file://%s%s",
544 our_host_name(),
545 make_path(filer_window->path, "")->str);
546 break;
549 collection = filer_window->collection;
550 for (i = 0; i < collection->number_of_items; i++)
552 if (collection->items[i].selected)
554 FileItem *item =
555 (FileItem *) collection->items[i].data;
557 g_string_append(reply, header->str);
558 g_string_append(reply, item->leafname);
561 g_string_append_c(reply, ' ');
563 gtk_selection_data_set(selection_data, xa_string,
564 8, reply->str + 1, reply->len - 1);
565 g_string_free(reply, TRUE);
566 g_string_free(header, TRUE);
569 /* No items are now selected. This might be because another app claimed
570 * the selection or because the user unselected all the items.
572 static void lose_selection(Collection *collection,
573 guint time,
574 gpointer user_data)
576 FilerWindow *filer_window = (FilerWindow *) user_data;
578 if (window_with_selection == filer_window)
580 window_with_selection = NULL;
581 gtk_selection_owner_set(NULL,
582 GDK_SELECTION_PRIMARY,
583 time);
587 static void gain_selection(Collection *collection,
588 guint time,
589 gpointer user_data)
591 FilerWindow *filer_window = (FilerWindow *) user_data;
593 if (gtk_selection_owner_set(GTK_WIDGET(collection),
594 GDK_SELECTION_PRIMARY,
595 time))
597 window_with_selection = filer_window;
599 else
600 collection_clear_selection(filer_window->collection);
603 static int sort_by_name(const void *item1, const void *item2)
605 return strcmp((*((FileItem **)item1))->leafname,
606 (*((FileItem **)item2))->leafname);
609 static gint clear_panel_hilight(gpointer data)
611 collection_set_cursor_item(panel_with_timeout->collection, -1);
612 panel_with_timeout = NULL;
614 return FALSE;
617 /* It is possible to highlight an item briefly on a panel by calling this
618 * function.
620 void panel_set_timeout(FilerWindow *filer_window, gulong msec)
622 if (panel_with_timeout)
624 /* Can't have two timeouts at once */
625 gtk_timeout_remove(panel_timeout);
626 clear_panel_hilight(NULL);
629 if (filer_window)
631 panel_with_timeout = filer_window;
632 panel_timeout = gtk_timeout_add(msec,
633 clear_panel_hilight, NULL);
637 void open_item(Collection *collection,
638 gpointer item_data, int item_number,
639 gpointer user_data)
641 FilerWindow *filer_window = (FilerWindow *) user_data;
642 FileItem *item = (FileItem *) item_data;
643 GdkEventButton *event;
644 char *full_path;
645 GtkWidget *widget;
646 gboolean shift, adjust;
648 event = (GdkEventButton *) gtk_get_current_event();
649 full_path = make_path(filer_window->path, item->leafname)->str;
651 if (filer_window->panel)
653 panel_set_timeout(NULL, 0);
654 collection_set_cursor_item(collection, item_number);
655 gdk_flush();
656 panel_set_timeout(filer_window, 200);
659 if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_BUTTON_PRESS)
661 shift = event->state & GDK_SHIFT_MASK;
662 adjust = event->button != 1 || event->state & GDK_CONTROL_MASK;
664 else
666 shift = FALSE;
667 adjust = FALSE;
670 widget = filer_window->window;
672 switch (item->base_type)
674 case TYPE_DIRECTORY:
675 if (item->flags & ITEM_FLAG_APPDIR && !shift)
677 run_app(make_path(filer_window->path,
678 item->leafname)->str);
679 if (adjust && !filer_window->panel)
680 gtk_widget_destroy(widget);
681 break;
683 if (adjust || filer_window->panel)
684 filer_opendir(full_path, FALSE, BOTTOM);
685 else
687 remove_view(filer_window);
688 filer_window->path = pathdup(full_path);
689 add_view(filer_window);
690 scan_dir(filer_window);
692 break;
693 case TYPE_FILE:
694 if (item->flags & ITEM_FLAG_EXEC_FILE)
696 char *argv[] = {full_path, NULL};
698 if (spawn_full(argv, getenv("HOME"), 0))
700 if (adjust && !filer_window->panel)
701 gtk_widget_destroy(widget);
703 else
704 report_error("ROX-Filer",
705 "Failed to fork() child");
707 else
709 GString *message;
710 MIME_type *type = item->mime_type;
712 g_return_if_fail(type != NULL);
714 if (type_open(full_path, type))
716 if (adjust && !filer_window->panel)
717 gtk_widget_destroy(widget);
719 else
721 message = g_string_new(NULL);
722 g_string_sprintf(message, "No open "
723 "action specified for files of "
724 "this type (%s/%s)",
725 type->media_type,
726 type->subtype);
727 report_error("ROX-Filer", message->str);
728 g_string_free(message, TRUE);
731 break;
732 default:
733 report_error("open_item",
734 "I don't know how to open that");
735 break;
739 static gint pointer_in(GtkWidget *widget,
740 GdkEventCrossing *event,
741 FilerWindow *filer_window)
743 may_rescan(filer_window);
744 return FALSE;
747 static gint focus_in(GtkWidget *widget,
748 GdkEventFocus *event,
749 FilerWindow *filer_window)
751 window_with_focus = filer_window;
753 return FALSE;
756 static gint focus_out(GtkWidget *widget,
757 GdkEventFocus *event,
758 FilerWindow *filer_window)
760 /* TODO: Shade the cursor */
762 return FALSE;
765 /* Handle keys that can't be bound with the menu */
766 static gint key_press_event(GtkWidget *widget,
767 GdkEventKey *event,
768 FilerWindow *filer_window)
770 switch (event->keyval)
773 case GDK_Left:
774 move_cursor(-1, 0);
775 break;
776 case GDK_Right:
777 move_cursor(1, 0);
778 break;
779 case GDK_Up:
780 move_cursor(0, -1);
781 break;
782 case GDK_Down:
783 move_cursor(0, 1);
784 break;
785 case GDK_Return:
787 case GDK_BackSpace:
788 remove_view(filer_window);
789 filer_window->path = pathdup(make_path(
790 filer_window->path,
791 "..")->str);
792 add_view(filer_window);
793 scan_dir(filer_window);
794 return TRUE;
797 return FALSE;
800 FileItem *selected_item(Collection *collection)
802 int i;
804 g_return_val_if_fail(collection != NULL, NULL);
805 g_return_val_if_fail(IS_COLLECTION(collection), NULL);
806 g_return_val_if_fail(collection->number_selected == 1, NULL);
808 for (i = 0; i < collection->number_of_items; i++)
809 if (collection->items[i].selected)
810 return (FileItem *) collection->items[i].data;
812 g_warning("selected_item: number_selected is wrong\n");
814 return NULL;
817 /* Refresh all windows onto this directory */
818 void refresh_dirs(char *path)
820 char *real;
821 GList *list, *next;
823 real = pathdup(path);
824 list = g_hash_table_lookup(path_to_window_list, real);
825 g_free(real);
827 while (list)
829 next = list->next;
830 may_rescan((FilerWindow *) list->data);
831 list = next;
835 void filer_opendir(char *path, gboolean panel, Side panel_side)
837 GtkWidget *hbox, *scrollbar, *collection;
838 FilerWindow *filer_window;
839 GtkTargetEntry target_table[] =
841 {"text/uri-list", 0, TARGET_URI_LIST},
842 {"STRING", 0, TARGET_STRING},
845 filer_window = g_malloc(sizeof(FilerWindow));
846 filer_window->path = pathdup(path);
847 filer_window->dir = NULL; /* Not scanning */
848 filer_window->show_hidden = FALSE;
849 filer_window->panel = panel;
850 filer_window->panel_side = panel_side;
851 filer_window->temp_item_selected = FALSE;
853 filer_window->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
855 collection = collection_new(NULL);
856 gtk_object_set_data(GTK_OBJECT(collection),
857 "filer_window", filer_window);
858 filer_window->collection = COLLECTION(collection);
859 collection_set_item_size(filer_window->collection, 64, 64);
860 collection_set_functions(filer_window->collection,
861 draw_item, test_point);
863 gtk_widget_add_events(filer_window->window, GDK_ENTER_NOTIFY);
864 gtk_signal_connect(GTK_OBJECT(filer_window->window),
865 "enter-notify-event",
866 GTK_SIGNAL_FUNC(pointer_in), filer_window);
867 gtk_signal_connect(GTK_OBJECT(filer_window->window), "focus_in_event",
868 GTK_SIGNAL_FUNC(focus_in), filer_window);
869 gtk_signal_connect(GTK_OBJECT(filer_window->window), "focus_out_event",
870 GTK_SIGNAL_FUNC(focus_out), filer_window);
871 gtk_signal_connect(GTK_OBJECT(filer_window->window), "destroy",
872 filer_window_destroyed, filer_window);
874 gtk_signal_connect(GTK_OBJECT(filer_window->collection), "open_item",
875 open_item, filer_window);
876 gtk_signal_connect(GTK_OBJECT(collection), "show_menu",
877 show_menu, filer_window);
878 gtk_signal_connect(GTK_OBJECT(collection), "gain_selection",
879 gain_selection, filer_window);
880 gtk_signal_connect(GTK_OBJECT(collection), "lose_selection",
881 lose_selection, filer_window);
882 gtk_signal_connect(GTK_OBJECT(collection), "drag_selection",
883 drag_selection, filer_window);
884 gtk_signal_connect(GTK_OBJECT(collection), "drag_data_get",
885 drag_data_get, filer_window);
886 gtk_signal_connect(GTK_OBJECT(collection), "selection_clear_event",
887 GTK_SIGNAL_FUNC(collection_lose_selection), NULL);
888 gtk_signal_connect (GTK_OBJECT(collection), "selection_get",
889 GTK_SIGNAL_FUNC(selection_get), NULL);
890 gtk_selection_add_targets(collection, GDK_SELECTION_PRIMARY,
891 target_table,
892 sizeof(target_table) / sizeof(*target_table));
894 drag_set_dest(collection);
896 if (panel)
898 int swidth, sheight, iwidth, iheight;
899 GtkWidget *frame, *win = filer_window->window;
901 collection_set_panel(filer_window->collection, TRUE);
903 gdk_window_get_size(GDK_ROOT_PARENT(), &swidth, &sheight);
904 iwidth = filer_window->collection->item_width;
905 iheight = filer_window->collection->item_height;
907 if (panel_side == TOP || panel_side == BOTTOM)
909 int height = iheight + PANEL_BORDER;
910 int y = panel_side == TOP
911 ? -PANEL_BORDER
912 : sheight - height - PANEL_BORDER;
914 gtk_widget_set_usize(collection, swidth, height);
915 gtk_widget_set_uposition(win, 0, y);
917 else
919 int width = iwidth + PANEL_BORDER;
920 int x = panel_side == LEFT
921 ? -PANEL_BORDER
922 : swidth - width - PANEL_BORDER;
924 gtk_widget_set_usize(collection, width, sheight);
925 gtk_widget_set_uposition(win, x, 0);
928 frame = gtk_frame_new(NULL);
929 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
930 gtk_container_add(GTK_CONTAINER(frame), collection);
931 gtk_container_add(GTK_CONTAINER(win), frame);
933 gtk_widget_realize(win);
934 make_panel_window(win->window);
936 else
938 gtk_signal_connect(GTK_OBJECT(filer_window->window),
939 "key_press_event",
940 GTK_SIGNAL_FUNC(key_press_event), filer_window);
941 gtk_window_set_default_size(GTK_WINDOW(filer_window->window),
942 400, 200);
944 hbox = gtk_hbox_new(FALSE, 0);
945 gtk_container_add(GTK_CONTAINER(filer_window->window), hbox);
947 gtk_box_pack_start(GTK_BOX(hbox), collection, TRUE, TRUE, 0);
949 scrollbar = gtk_vscrollbar_new(COLLECTION(collection)->vadj);
950 gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, TRUE, 0);
951 gtk_accel_group_attach(filer_keys,
952 GTK_OBJECT(filer_window->window));
955 gtk_widget_show_all(filer_window->window);
956 number_of_windows++;
958 load_default_pixmaps(collection->window);
960 add_view(filer_window);
961 scan_dir(filer_window);