r2525: Use stock icons in pinboard and panel menus.
[rox-filer.git] / ROX-Filer / src / dir.c
bloba9bc30b85ef0d6a35e52df8bfe2317b58af73f4e
1 /*
2 * $Id$
4 * Copyright (C) 2003, the ROX-Filer team.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* dir.c - directory scanning and caching */
23 /* How it works:
25 * A Directory contains a list DirItems, each having a name and some details
26 * (size, image, owner, etc).
28 * There is a list of file names that need to be rechecked. While this
29 * list is non-empty, items are taken from the list in an idle callback
30 * and checked. Missing items are removed from the Directory, new items are
31 * added and existing items are updated if they've changed.
33 * When a whole directory is to be rescanned:
35 * - A list of all filenames in the directory is fetched, without any
36 * of the extra details.
37 * - This list is compared to the current DirItems, removing any that are now
38 * missing.
39 * - The recheck list is replaced with this new list.
41 * This system is designed to get the number of items and their names quickly,
42 * so that the auto-sizer can make a good guess.
44 * To get the Directory object, use dir_cache, which will automatically
45 * trigger a rescan if needed.
47 * To get notified when the Directory changes, use the dir_attach() and
48 * dir_detach() functions.
51 #include "config.h"
53 #include <gtk/gtk.h>
54 #include <errno.h>
55 #include <stdio.h>
56 #include <string.h>
58 #include "global.h"
60 #include "dir.h"
61 #include "diritem.h"
62 #include "support.h"
63 #include "gui_support.h"
64 #include "dir.h"
65 #include "fscache.h"
66 #include "mount.h"
67 #include "pixmaps.h"
68 #include "type.h"
69 #include "usericons.h"
70 #include "main.h"
72 #ifdef USE_DNOTIFY
73 /* Newer Linux kernels can tell use when the directories we are watching
74 * change using the dnotify system.
76 static GHashTable *dnotify_fd_to_dir = NULL;
77 gboolean dnotify_wakeup_flag = FALSE;
78 static int dnotify_last_fd = -1;
79 #endif
81 GFSCache *dir_cache = NULL;
83 /* Static prototypes */
84 static void update(Directory *dir, gchar *pathname, gpointer data);
85 static void set_idle_callback(Directory *dir);
86 static DirItem *insert_item(Directory *dir, const guchar *leafname);
87 static void remove_missing(Directory *dir, GPtrArray *keep);
88 static void dir_recheck(Directory *dir,
89 const guchar *path, const guchar *leafname);
90 static GPtrArray *hash_to_array(GHashTable *hash);
91 static void dir_force_update_item(Directory *dir, const gchar *leaf);
92 static Directory *dir_new(const char *pathname);
93 static void dir_rescan(Directory *dir);
94 #ifdef USE_DNOTIFY
95 static void dnotify_handler(int sig, siginfo_t *si, void *data);
96 #endif
98 /****************************************************************
99 * EXTERNAL INTERFACE *
100 ****************************************************************/
102 void dir_init(void)
104 dir_cache = g_fscache_new((GFSLoadFunc) dir_new,
105 (GFSUpdateFunc) update, NULL);
107 /* Check for dnotify support in the kernel */
108 #ifdef USE_DNOTIFY
110 struct sigaction act;
112 act.sa_sigaction = dnotify_handler;
113 sigemptyset(&act.sa_mask);
114 act.sa_flags = SA_SIGINFO;
115 sigaction(SIGRTMIN, &act, NULL);
117 /* Sometimes we get this instead of SIGRTMIN.
118 * Don't know why :-( but don't crash...
120 act.sa_handler = SIG_IGN;
121 sigemptyset(&act.sa_mask);
122 act.sa_flags = 0;
123 sigaction(SIGIO, &act, NULL);
125 dnotify_fd_to_dir = g_hash_table_new(NULL, NULL);
127 #endif
130 /* Periodically calls callback to notify about changes to the contents
131 * of the directory.
132 * Before this function returns, it calls the callback once to add all
133 * the items currently in the directory (unless the dir is empty).
134 * If we are not scanning, it also calls update(DIR_END_SCAN).
136 void dir_attach(Directory *dir, DirCallback callback, gpointer data)
138 DirUser *user;
139 GPtrArray *items;
141 g_return_if_fail(dir != NULL);
142 g_return_if_fail(callback != NULL);
144 user = g_new(DirUser, 1);
145 user->callback = callback;
146 user->data = data;
148 #ifdef USE_DNOTIFY
149 if (!dir->users)
151 int fd;
153 if (dir->dnotify_fd != -1)
154 g_warning("dir_attach: dnotify error\n");
156 fd = open(dir->pathname, O_RDONLY);
157 g_return_if_fail(g_hash_table_lookup(dnotify_fd_to_dir,
158 GINT_TO_POINTER(fd)) == NULL);
159 if (fd != -1)
161 dir->dnotify_fd = fd;
162 g_hash_table_insert(dnotify_fd_to_dir,
163 GINT_TO_POINTER(fd), dir);
164 fcntl(fd, F_SETSIG, SIGRTMIN);
165 fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME |
166 DN_ATTRIB | DN_MULTISHOT);
169 #endif
171 dir->users = g_list_prepend(dir->users, user);
173 g_object_ref(dir);
175 items = hash_to_array(dir->known_items);
176 if (items->len)
177 callback(dir, DIR_ADD, items, data);
178 g_ptr_array_free(items, TRUE);
180 if (dir->needs_update && !dir->scanning)
181 dir_rescan(dir);
183 /* May start scanning if noone was watching before */
184 set_idle_callback(dir);
186 if (!dir->scanning)
187 callback(dir, DIR_END_SCAN, NULL, data);
190 /* Undo the effect of dir_attach */
191 void dir_detach(Directory *dir, DirCallback callback, gpointer data)
193 DirUser *user;
194 GList *list;
196 g_return_if_fail(dir != NULL);
197 g_return_if_fail(callback != NULL);
199 for (list = dir->users; list; list = list->next)
201 user = (DirUser *) list->data;
202 if (user->callback == callback && user->data == data)
204 g_free(user);
205 dir->users = g_list_remove(dir->users, user);
206 g_object_unref(dir);
208 /* May stop scanning if noone's watching */
209 set_idle_callback(dir);
211 #ifdef USE_DNOTIFY
212 if (!dir->users && dir->dnotify_fd != -1)
214 close(dir->dnotify_fd);
215 g_hash_table_remove(dnotify_fd_to_dir,
216 GINT_TO_POINTER(dir->dnotify_fd));
217 dir->dnotify_fd = -1;
219 #endif
220 return;
224 g_warning("dir_detach: Callback/data pair not attached!\n");
227 void dir_update(Directory *dir, gchar *pathname)
229 update(dir, pathname, NULL);
232 /* Rescan this directory */
233 void refresh_dirs(const char *path)
235 g_fscache_update(dir_cache, path);
238 /* When something has happened to a particular object, call this
239 * and all appropriate changes will be made.
241 void dir_check_this(const guchar *path)
243 guchar *real_path;
244 guchar *dir_path;
245 Directory *dir;
247 dir_path = g_path_get_dirname(path);
248 real_path = pathdup(dir_path);
249 g_free(dir_path);
251 dir = g_fscache_lookup_full(dir_cache, real_path,
252 FSCACHE_LOOKUP_PEEK, NULL);
253 if (dir)
255 dir_recheck(dir, real_path, g_basename(path));
256 g_object_unref(dir);
259 g_free(real_path);
262 #ifdef USE_DNOTIFY
263 static void drop_dnotify(gpointer key, gpointer value, gpointer data)
265 close(GPOINTER_TO_INT(key));
267 #endif
269 /* Used when we fork an action child, otherwise we can't delete or unmount
270 * any directory which we're watching!
272 void dir_drop_all_dnotifies(void)
274 #ifdef USE_DNOTIFY
275 g_hash_table_foreach(dnotify_fd_to_dir, drop_dnotify, NULL);
276 #endif
279 /* Tell watchers that this item has changed, but don't rescan.
280 * (used when thumbnail has been created for an item)
282 void dir_force_update_path(const gchar *path)
284 gchar *dir_path;
285 Directory *dir;
287 g_return_if_fail(path[0] == '/');
289 dir_path = g_path_get_dirname(path);
291 dir = g_fscache_lookup_full(dir_cache, dir_path, FSCACHE_LOOKUP_PEEK,
292 NULL);
293 if (dir)
295 dir_force_update_item(dir, g_basename(path));
296 g_object_unref(dir);
299 g_free(dir_path);
302 /* Ensure that 'leafname' is up-to-date. Returns the new/updated
303 * DirItem, or NULL if the file no longer exists.
305 DirItem *dir_update_item(Directory *dir, const gchar *leafname)
307 DirItem *item;
309 time(&diritem_recent_time);
310 item = insert_item(dir, leafname);
311 dir_merge_new(dir);
313 return item;
316 static int sort_names(const void *a, const void *b)
318 return strcmp(*((char **) a), *((char **) b));
321 static void free_recheck_list(Directory *dir)
323 destroy_glist(&dir->recheck_list);
326 /* If scanning state has changed then notify all filer windows */
327 static void dir_set_scanning(Directory *dir, gboolean scanning)
329 GList *next;
331 if (scanning == dir->scanning)
332 return;
334 dir->scanning = scanning;
336 for (next = dir->users; next; next = next->next)
338 DirUser *user = (DirUser *) next->data;
340 user->callback(dir,
341 scanning ? DIR_START_SCAN : DIR_END_SCAN,
342 NULL, user->data);
346 /* Notify everyone that the error status of the directory has changed */
347 static void dir_error_changed(Directory *dir)
349 GList *next;
351 for (next = dir->users; next; next = next->next)
353 DirUser *user = (DirUser *) next->data;
355 user->callback(dir, DIR_ERROR_CHANGED, NULL, user->data);
359 /* This is called in the background when there are items on the
360 * dir->recheck_list to process.
362 static gboolean recheck_callback(gpointer data)
364 Directory *dir = (Directory *) data;
365 GList *next;
366 guchar *leaf;
368 g_return_val_if_fail(dir != NULL, FALSE);
369 g_return_val_if_fail(dir->recheck_list != NULL, FALSE);
371 /* Remove the first name from the list */
372 next = dir->recheck_list;
373 dir->recheck_list = g_list_remove_link(dir->recheck_list, next);
374 leaf = (guchar *) next->data;
375 g_list_free_1(next);
377 /* usleep(800); */
379 insert_item(dir, leaf);
381 g_free(leaf);
383 if (dir->recheck_list)
384 return TRUE; /* Call again */
386 /* The recheck_list list empty. Stop scanning, unless
387 * needs_update, in which case we start scanning again.
390 dir_merge_new(dir);
392 dir->have_scanned = TRUE;
393 dir_set_scanning(dir, FALSE);
394 gtk_idle_remove(dir->idle_callback);
395 dir->idle_callback = 0;
397 if (dir->needs_update)
398 dir_rescan(dir);
400 return FALSE;
403 /* Add all the new items to the items array.
404 * Notify everyone who is watching us.
406 void dir_merge_new(Directory *dir)
408 GPtrArray *new = dir->new_items;
409 GPtrArray *up = dir->up_items;
410 GPtrArray *gone = dir->gone_items;
411 GList *list;
412 guint i;
414 for (list = dir->users; list; list = list->next)
416 DirUser *user = (DirUser *) list->data;
418 if (new->len)
419 user->callback(dir, DIR_ADD, new, user->data);
420 if (up->len)
421 user->callback(dir, DIR_UPDATE, up, user->data);
422 if (gone->len)
423 user->callback(dir, DIR_REMOVE, gone, user->data);
426 for (i = 0; i < new->len; i++)
428 DirItem *item = (DirItem *) new->pdata[i];
430 g_hash_table_insert(dir->known_items, item->leafname, item);
433 for (i = 0; i < gone->len; i++)
435 DirItem *item = (DirItem *) gone->pdata[i];
437 diritem_free(item);
440 g_ptr_array_set_size(gone, 0);
441 g_ptr_array_set_size(new, 0);
442 g_ptr_array_set_size(up, 0);
445 #ifdef USE_DNOTIFY
446 /* Called from the mainloop shortly after dnotify_handler */
447 void dnotify_wakeup(void)
449 Directory *dir;
451 dnotify_wakeup_flag = FALSE;
453 dir = g_hash_table_lookup(dnotify_fd_to_dir,
454 GINT_TO_POINTER(dnotify_last_fd));
456 if (!dir)
457 return;
459 if (dir->scanning)
460 dir->needs_update = TRUE;
461 else
462 dir_rescan(dir);
464 #endif
466 /****************************************************************
467 * INTERNAL FUNCTIONS *
468 ****************************************************************/
470 static void free_items_array(GPtrArray *array)
472 guint i;
474 for (i = 0; i < array->len; i++)
476 DirItem *item = (DirItem *) array->pdata[i];
478 diritem_free(item);
481 g_ptr_array_free(array, TRUE);
484 /* Tell everyone watching that these items have gone */
485 static void notify_deleted(Directory *dir, GPtrArray *deleted)
487 GList *next;
489 if (!deleted->len)
490 return;
492 for (next = dir->users; next; next = next->next)
494 DirUser *user = (DirUser *) next->data;
496 user->callback(dir, DIR_REMOVE, deleted, user->data);
500 static void mark_unused(gpointer key, gpointer value, gpointer data)
502 DirItem *item = (DirItem *) value;
504 item->may_delete = TRUE;
507 static void keep_deleted(gpointer key, gpointer value, gpointer data)
509 DirItem *item = (DirItem *) value;
510 GPtrArray *deleted = (GPtrArray *) data;
512 if (item->may_delete)
513 g_ptr_array_add(deleted, item);
516 static gboolean check_unused(gpointer key, gpointer value, gpointer data)
518 DirItem *item = (DirItem *) value;
520 return item->may_delete;
523 /* Remove all the old items that have gone.
524 * Notify everyone who is watching us of the removed items.
526 static void remove_missing(Directory *dir, GPtrArray *keep)
528 GPtrArray *deleted;
529 guint i;
531 deleted = g_ptr_array_new();
533 /* Mark all current items as may_delete */
534 g_hash_table_foreach(dir->known_items, mark_unused, NULL);
536 /* Unmark all items also in 'keep' */
537 for (i = 0; i < keep->len; i++)
539 guchar *leaf = (guchar *) keep->pdata[i];
540 DirItem *item;
542 item = g_hash_table_lookup(dir->known_items, leaf);
544 if (item)
545 item->may_delete = FALSE;
548 /* Add each item still marked to 'deleted' */
549 g_hash_table_foreach(dir->known_items, keep_deleted, deleted);
551 /* Remove all items still marked */
552 g_hash_table_foreach_remove(dir->known_items, check_unused, NULL);
554 notify_deleted(dir, deleted);
556 free_items_array(deleted);
559 static gint notify_timeout(gpointer data)
561 Directory *dir = (Directory *) data;
563 g_return_val_if_fail(dir->notify_active == TRUE, FALSE);
565 dir_merge_new(dir);
567 dir->notify_active = FALSE;
568 g_object_unref(dir);
570 return FALSE;
573 /* Call dir_merge_new() after a while. */
574 static void delayed_notify(Directory *dir)
576 if (dir->notify_active)
577 return;
578 g_object_ref(dir);
579 gtk_timeout_add(1500, notify_timeout, dir);
580 dir->notify_active = TRUE;
583 /* Stat this item and add, update or remove it.
584 * Returns the new/updated item, if any.
585 * (leafname may be from the current DirItem item)
586 * Ensure diritem_recent_time is reasonably up-to-date before calling this.
588 static DirItem *insert_item(Directory *dir, const guchar *leafname)
590 const gchar *full_path;
591 DirItem *item;
592 DirItem old;
593 gboolean do_compare = FALSE; /* (old is filled in) */
595 if (leafname[0] == '.' && (leafname[1] == '\n' ||
596 (leafname[1] == '.' && leafname[2] == '\n')))
597 return NULL; /* Ignore '.' and '..' */
599 full_path = make_path(dir->pathname, leafname);
600 item = g_hash_table_lookup(dir->known_items, leafname);
602 if (item)
604 if (item->base_type != TYPE_UNKNOWN)
606 /* Preserve the old details so we can compare */
607 old = *item;
608 if (old.image)
609 g_object_ref(old.image);
610 do_compare = TRUE;
612 diritem_restat(full_path, item, &dir->stat_info);
614 else
616 /* Item isn't already here. This won't normally happen,
617 * because blank items are added when scanning, before
618 * we get here.
620 item = diritem_new(leafname);
621 diritem_restat(full_path, item, &dir->stat_info);
622 if (item->base_type == TYPE_ERROR &&
623 item->lstat_errno == ENOENT)
625 diritem_free(item);
626 return NULL;
628 g_ptr_array_add(dir->new_items, item);
632 if (item->base_type == TYPE_ERROR && item->lstat_errno == ENOENT)
634 /* Item has been deleted */
635 g_hash_table_remove(dir->known_items, item->leafname);
636 g_ptr_array_add(dir->gone_items, item);
637 if (do_compare && old.image)
638 g_object_unref(old.image);
639 delayed_notify(dir);
640 return NULL;
643 if (do_compare)
645 if (item->lstat_errno == old.lstat_errno
646 && item->base_type == old.base_type
647 && item->flags == old.flags
648 && item->size == old.size
649 && item->mode == old.mode
650 && item->atime == old.atime
651 && item->ctime == old.ctime
652 && item->mtime == old.mtime
653 && item->uid == old.uid
654 && item->gid == old.gid
655 && item->image == old.image
656 && item->mime_type == old.mime_type)
658 if (old.image)
659 g_object_unref(old.image);
660 return item;
662 if (old.image)
663 g_object_unref(old.image);
666 g_ptr_array_add(dir->up_items, item);
667 delayed_notify(dir);
669 return item;
672 static void update(Directory *dir, gchar *pathname, gpointer data)
674 g_free(dir->pathname);
675 dir->pathname = pathdup(pathname);
677 if (dir->scanning)
678 dir->needs_update = TRUE;
679 else
680 dir_rescan(dir);
683 /* If there is work to do, set the idle callback.
684 * Otherwise, stop scanning and unset the idle callback.
686 static void set_idle_callback(Directory *dir)
688 if (dir->recheck_list && dir->users)
690 /* Work to do, and someone's watching */
691 dir_set_scanning(dir, TRUE);
692 if (dir->idle_callback)
693 return;
694 time(&diritem_recent_time);
695 dir->idle_callback = gtk_idle_add(recheck_callback, dir);
696 /* Do the first call now (will remove the callback itself) */
697 recheck_callback(dir);
699 else
701 dir_set_scanning(dir, FALSE);
702 if (dir->idle_callback)
704 gtk_idle_remove(dir->idle_callback);
705 dir->idle_callback = 0;
710 /* See dir_force_update_path() */
711 static void dir_force_update_item(Directory *dir, const gchar *leaf)
713 GList *list;
714 GPtrArray *items;
715 DirItem *item;
717 items = g_ptr_array_new();
719 item = g_hash_table_lookup(dir->known_items, leaf);
720 if (!item)
721 goto out;
723 g_ptr_array_add(items, item);
725 for (list = dir->users; list; list = list->next)
727 DirUser *user = (DirUser *) list->data;
729 user->callback(dir, DIR_UPDATE, items, user->data);
732 out:
733 g_ptr_array_free(items, TRUE);
736 static void dir_recheck(Directory *dir,
737 const guchar *path, const guchar *leafname)
739 guchar *old = dir->pathname;
741 dir->pathname = g_strdup(path);
742 g_free(old);
744 time(&diritem_recent_time);
745 insert_item(dir, leafname);
748 static void to_array(gpointer key, gpointer value, gpointer data)
750 GPtrArray *array = (GPtrArray *) data;
752 g_ptr_array_add(array, value);
755 /* Convert a hash table to an unsorted GPtrArray.
756 * g_ptr_array_free() the result.
758 static GPtrArray *hash_to_array(GHashTable *hash)
760 GPtrArray *array;
762 array = g_ptr_array_new();
764 g_hash_table_foreach(hash, to_array, array);
766 return array;
769 static gpointer parent_class;
771 /* Note: dir_cache is never purged, so this shouldn't get called */
772 static void dir_finialize(GObject *object)
774 GPtrArray *items;
775 Directory *dir = (Directory *) object;
777 g_return_if_fail(dir->users == NULL);
779 g_print("[ dir finalize ]\n");
781 free_recheck_list(dir);
782 set_idle_callback(dir);
784 dir_merge_new(dir); /* Ensures new, up and gone are empty */
786 g_ptr_array_free(dir->up_items, TRUE);
787 g_ptr_array_free(dir->new_items, TRUE);
788 g_ptr_array_free(dir->gone_items, TRUE);
790 items = hash_to_array(dir->known_items);
791 free_items_array(items);
792 g_hash_table_destroy(dir->known_items);
794 g_free(dir->error);
795 g_free(dir->pathname);
797 G_OBJECT_CLASS(parent_class)->finalize(object);
800 static void directory_class_init(gpointer gclass, gpointer data)
802 GObjectClass *object = (GObjectClass *) gclass;
804 parent_class = g_type_class_peek_parent(gclass);
806 object->finalize = dir_finialize;
809 static void directory_init(GTypeInstance *object, gpointer gclass)
811 Directory *dir = (Directory *) object;
813 dir->known_items = g_hash_table_new(g_str_hash, g_str_equal);
814 dir->recheck_list = NULL;
815 dir->idle_callback = 0;
816 dir->scanning = FALSE;
817 dir->have_scanned = FALSE;
819 dir->users = NULL;
820 dir->needs_update = TRUE;
821 dir->notify_active = FALSE;
822 dir->pathname = NULL;
823 dir->error = NULL;
824 #ifdef USE_DNOTIFY
825 dir->dnotify_fd = -1;
826 #endif
828 dir->new_items = g_ptr_array_new();
829 dir->up_items = g_ptr_array_new();
830 dir->gone_items = g_ptr_array_new();
833 static GType dir_get_type(void)
835 static GType type = 0;
837 if (!type)
839 static const GTypeInfo info =
841 sizeof (DirectoryClass),
842 NULL, /* base_init */
843 NULL, /* base_finalise */
844 directory_class_init,
845 NULL, /* class_finalise */
846 NULL, /* class_data */
847 sizeof(Directory),
848 0, /* n_preallocs */
849 directory_init
852 type = g_type_register_static(G_TYPE_OBJECT, "Directory",
853 &info, 0);
856 return type;
859 static Directory *dir_new(const char *pathname)
861 Directory *dir;
863 dir = g_object_new(dir_get_type(), NULL);
865 dir->pathname = g_strdup(pathname);
867 return dir;
870 /* Get the names of all files in the directory.
871 * Remove any DirItems that are no longer listed.
872 * Replace the recheck_list with the items found.
874 static void dir_rescan(Directory *dir)
876 GPtrArray *names;
877 DIR *d;
878 struct dirent *ent;
879 guint i;
880 const char *pathname;
881 int longest_len = -1;
882 GList *longest = NULL;
884 g_return_if_fail(dir != NULL);
886 pathname = dir->pathname;
888 dir->needs_update = FALSE;
890 names = g_ptr_array_new();
892 read_globicons();
893 mount_update(FALSE);
894 if (dir->error)
896 null_g_free(&dir->error);
897 dir_error_changed(dir);
900 /* Saves statting the parent for each item... */
901 if (mc_stat(pathname, &dir->stat_info))
903 dir->error = g_strdup_printf(_("Can't stat directory: %s"),
904 g_strerror(errno));
905 dir_error_changed(dir);
906 return; /* Report on attach */
909 d = mc_opendir(pathname);
910 if (!d)
912 dir->error = g_strdup_printf(_("Can't open directory: %s"),
913 g_strerror(errno));
914 dir_error_changed(dir);
915 return; /* Report on attach */
918 dir_set_scanning(dir, TRUE);
919 dir_merge_new(dir);
920 gdk_flush();
922 /* Make a list of all the names in the directory */
923 while ((ent = mc_readdir(d)))
925 if (ent->d_name[0] == '.')
927 if (ent->d_name[1] == '\0')
928 continue; /* Ignore '.' */
929 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
930 continue; /* Ignore '..' */
933 g_ptr_array_add(names, g_strdup(ent->d_name));
935 mc_closedir(d);
937 /* Sort, so the names are scanned in a sensible order */
938 qsort(names->pdata, names->len, sizeof(guchar *), sort_names);
940 /* Compare the list with the current DirItems, removing
941 * any that are missing.
943 remove_missing(dir, names);
945 free_recheck_list(dir);
947 /* For each name found, add it to the recheck_list.
948 * If the item is new, put a blank place-holder item in the directory.
950 for (i = 0; i < names->len; i++)
952 guchar *name = names->pdata[i];
953 int len = strlen(name);
955 dir->recheck_list = g_list_prepend(dir->recheck_list, name);
956 if (!g_hash_table_lookup(dir->known_items, name))
958 DirItem *new;
960 new = diritem_new(name);
961 g_ptr_array_add(dir->new_items, new);
964 if (name[0] != '.' && len > longest_len)
966 longest_len = len;
967 longest = dir->recheck_list;
971 dir_merge_new(dir);
973 dir->recheck_list = g_list_reverse(dir->recheck_list);
975 if (longest)
977 gpointer data = longest->data;
979 /* Move the longest item to the start. Helps with
980 * auto sizing.
982 dir->recheck_list = g_list_remove_link(dir->recheck_list,
983 longest);
984 dir->recheck_list = g_list_prepend(dir->recheck_list, data);
987 g_ptr_array_free(names, TRUE);
989 set_idle_callback(dir);
990 dir_merge_new(dir);
993 #ifdef USE_DNOTIFY
994 /* Signal handler - don't do anything dangerous here */
995 static void dnotify_handler(int sig, siginfo_t *si, void *data)
997 /* Note: there is currently only one place to store the fd,
998 * so we'll miss updates to several directories if they happen
999 * close together.
1001 dnotify_last_fd = si->si_fd;
1002 dnotify_wakeup_flag = TRUE;
1003 write(to_wakeup_pipe, "\0", 1); /* Wake up! */
1005 #endif