Commit 01a32030 authored by Darin Adler's avatar Darin Adler

Finished task 174 (Use deferred calculation to compute directory counts).


	Finished task 174 (Use deferred calculation to compute directory
	counts).

	* libnautilus-extensions/Makefile.am:
	* libnautilus-extensions/nautilus-file-attributes.h:
	Added a header file for names of file attributes.

	* libnautilus-extensions/nautilus-directory-private.h:
	* libnautilus-extensions/nautilus-directory.c:
	* libnautilus-extensions/nautilus-directory.h:
	* libnautilus-extensions/nautilus-file-private.h:
	* libnautilus-extensions/nautilus-file.c:
	* libnautilus-extensions/nautilus-file.h:
	Added background computation of the "directory item count"
	attribute. This is serving as a test case for the API for
	requesting additional information.

	* src/file-manager/fm-directory-view.c:
	(display_selection_info): Changed to use the new interface that
	can sometimes return "I don't know" for the number of items in
	a particular directory.
	(stop_load), (done_loading), (display_pending_files),
	(fm_directory_view_stop): Fixed a mistake in the old code where
	we stopped monitoring once the files were discovered. We need to
	keep monitoring.
	(finish_loading_uri): Pass in an attribute that we want to monitor:
	NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT.
parent 71f8222e
2000-04-14 Darin Adler <darin@eazel.com>
Finished task 174 (Use deferred calculation to compute directory
counts).
* libnautilus-extensions/Makefile.am:
* libnautilus-extensions/nautilus-file-attributes.h:
Added a header file for names of file attributes.
* libnautilus-extensions/nautilus-directory-private.h:
* libnautilus-extensions/nautilus-directory.c:
* libnautilus-extensions/nautilus-directory.h:
* libnautilus-extensions/nautilus-file-private.h:
* libnautilus-extensions/nautilus-file.c:
* libnautilus-extensions/nautilus-file.h:
Added background computation of the "directory item count"
attribute. This is serving as a test case for the API for
requesting additional information.
* src/file-manager/fm-directory-view.c:
(display_selection_info): Changed to use the new interface that
can sometimes return "I don't know" for the number of items in
a particular directory.
(stop_load), (done_loading), (display_pending_files),
(fm_directory_view_stop): Fixed a mistake in the old code where
we stopped monitoring once the files were discovered. We need to
keep monitoring.
(finish_loading_uri): Pass in an attribute that we want to monitor:
NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT.
<Rebecka's ChangeLog entry goes here>
Fri Apr 14 16:35:32 2000 Raph Levien <raph@acm.org>
* librsvg/test-rsvg.c: Added a command line tester for rsvg, which
......
......@@ -34,8 +34,9 @@ libnautilus_extensionsinclude_HEADERS= \
nautilus-bonobo-extensions.h \
nautilus-bookmark.h \
nautilus-debug.h \
nautilus-directory.h \
nautilus-directory-background.h \
nautilus-directory.h \
nautilus-file-attributes.h \
nautilus-file-utilities.h \
nautilus-file.h \
nautilus-gdk-extensions.h \
......@@ -67,8 +68,8 @@ libnautilus_extensions_la_SOURCES = \
nautilus-debug.c \
nautilus-default-file-icon.c \
nautilus-default-file-icon.h \
nautilus-directory.c \
nautilus-directory-background.c \
nautilus-directory.c \
nautilus-file-utilities.c \
nautilus-file.c \
nautilus-gdk-extensions.c \
......
......@@ -55,7 +55,7 @@ struct NautilusDirectoryDetails
guint write_metafile_idle_id;
MetafileWriteState *write_state;
/* These list are going to be pretty short. If we think they
/* These lists are going to be pretty short. If we think they
* are going to get big, we can use hash tables instead.
*/
GList *metafile_callbacks;
......@@ -67,6 +67,9 @@ struct NautilusDirectoryDetails
GnomeVFSDirectoryListPosition directory_load_list_last_handled;
GList *pending_file_info;
guint dequeue_pending_idle_id;
GnomeVFSAsyncHandle *count_in_progress;
NautilusFile *count_file;
};
typedef struct {
......
......@@ -33,6 +33,7 @@
#include <parser.h>
#include <xmlmemory.h>
#include "nautilus-file-attributes.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-gtk-macros.h"
#include "nautilus-string.h"
......@@ -79,6 +80,11 @@ struct MetafileWriteState {
gboolean write_again;
};
typedef struct {
gconstpointer client;
gboolean monitor_directory_counts;
} FileMonitor;
#define READ_CHUNK_SIZE (4 * 1024)
static int compare_file_with_name (gconstpointer a,
......@@ -144,6 +150,7 @@ static GnomeVFSDirectoryListPosition nautilus_gnome_vfs_directory_list_get_next_
GnomeVFSDirectoryListPosition position);
static void nautilus_gnome_vfs_file_info_list_free (GList *list);
static void nautilus_gnome_vfs_file_info_list_unref (GList *list);
static void process_pending_file_attribute_requests (NautilusDirectory *directory);
static void schedule_dequeue_pending (NautilusDirectory *directory);
static void stop_monitoring_files (NautilusDirectory *directory);
......@@ -245,7 +252,7 @@ nautilus_directory_destroy (GtkObject *object)
if (directory->details->file_monitors != NULL) {
g_warning ("destroying a NautilusDirectory while it's being monitored");
stop_monitoring_files (directory);
g_list_free (directory->details->file_monitors);
nautilus_g_list_free_deep (directory->details->file_monitors);
}
g_hash_table_remove (directory_objects, directory->details->uri_text);
......@@ -876,22 +883,67 @@ nautilus_directory_new (const char* uri)
return directory;
}
static int
compare_file_monitor_with_client (gconstpointer a,
gconstpointer client)
{
const FileMonitor *monitor;
monitor = a;
if (monitor->client < client) {
return -1;
}
if (monitor->client > client) {
return +1;
}
return 0;
}
static GList *
find_file_monitor (NautilusDirectory *directory,
gconstpointer client)
{
return g_list_find_custom (directory->details->file_monitors,
(gpointer) client,
compare_file_monitor_with_client);
}
static void
remove_file_monitor (NautilusDirectory *directory,
gconstpointer client)
{
directory->details->file_monitors =
g_list_remove_link (directory->details->file_monitors,
find_file_monitor (directory, client));
}
void
nautilus_directory_file_monitor_add (NautilusDirectory *directory,
gpointer client,
gconstpointer client,
GList *attributes,
GList *metadata_keys,
NautilusFileListCallback callback,
gpointer callback_data)
{
gboolean first_file_monitor;
gboolean already_monitoring;
FileMonitor *file_monitor;
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (callback != NULL);
first_file_monitor = directory->details->file_monitors == NULL;
already_monitoring = directory->details->file_monitors != NULL;
remove_file_monitor (directory, client);
file_monitor = g_new (FileMonitor, 1);
file_monitor->client = client;
file_monitor->monitor_directory_counts = g_list_find_custom
(attributes,
NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT,
(GCompareFunc) nautilus_strcmp) != NULL;
directory->details->file_monitors =
g_list_prepend (directory->details->file_monitors, client);
g_list_prepend (directory->details->file_monitors, file_monitor);
nautilus_file_list_ref (directory->details->files);
......@@ -901,7 +953,11 @@ nautilus_directory_file_monitor_add (NautilusDirectory *directory,
callback_data);
}
if (!first_file_monitor) {
if (directory->details->directory_loaded) {
process_pending_file_attribute_requests (directory);
}
if (already_monitoring) {
nautilus_file_list_unref (directory->details->files);
return;
}
......@@ -1013,6 +1069,8 @@ nautilus_directory_load_done (NautilusDirectory *directory,
}
directory->details->directory_loaded = TRUE;
schedule_dequeue_pending (directory);
process_pending_file_attribute_requests (directory);
}
static GnomeVFSDirectoryListPosition
......@@ -1076,13 +1134,11 @@ stop_monitoring_files (NautilusDirectory *directory)
void
nautilus_directory_file_monitor_remove (NautilusDirectory *directory,
gpointer client)
gconstpointer client)
{
g_return_if_fail (NAUTILUS_IS_DIRECTORY (directory));
g_return_if_fail (g_list_find (directory->details->file_monitors, client) != NULL);
directory->details->file_monitors =
g_list_remove (directory->details->file_monitors, client);
remove_file_monitor (directory, client);
if (directory->details->file_monitors == NULL) {
stop_monitoring_files (directory);
}
......@@ -1565,6 +1621,96 @@ nautilus_directory_files_changed (NautilusDirectory *directory,
changed_files);
}
static void
directory_count_callback (GnomeVFSAsyncHandle *handle,
GnomeVFSResult result,
GnomeVFSDirectoryList *list,
guint entries_read,
gpointer callback_data)
{
NautilusDirectory *directory;
directory = NAUTILUS_DIRECTORY (callback_data);
g_assert (directory->details->count_in_progress == handle);
if (result == GNOME_VFS_OK) {
return;
}
/* Record either a failure or success. */
if (result != GNOME_VFS_ERROR_EOF) {
directory->details->count_file->details->directory_count_failed = TRUE;
} else {
directory->details->count_file->details->directory_count = entries_read;
directory->details->count_file->details->got_directory_count = TRUE;
nautilus_file_changed (directory->details->count_file);
}
/* Let go of this request. */
nautilus_file_unref (directory->details->count_file);
directory->details->count_in_progress = NULL;
/* Start up the next one. */
process_pending_file_attribute_requests (directory);
}
static void
process_pending_file_attribute_requests (NautilusDirectory *directory)
{
GList *p;
FileMonitor *monitor;
NautilusFile *file;
char *uri;
if (directory->details->count_in_progress != NULL) {
return;
}
/* Quick out if no one wants directory counts monitored. */
for (p = directory->details->file_monitors; p != NULL; p = p->next) {
monitor = p->data;
if (monitor->monitor_directory_counts) {
break;
}
}
if (p == NULL) {
return;
}
/* Search for a file that's a directory that needs a count. */
for (p = directory->details->files; p != NULL; p = p->next) {
file = p->data;
if (nautilus_file_is_directory (file)
&& !file->details->got_directory_count
&& !file->details->directory_count_failed) {
break;
}
}
if (p == NULL) {
return;
}
/* Start a load on the directory to count. */
nautilus_file_ref (file);
directory->details->count_file = file;
uri = nautilus_file_get_uri (file);
gnome_vfs_async_load_directory
(&directory->details->count_in_progress,
uri,
GNOME_VFS_FILE_INFO_DEFAULT,
NULL,
NULL,
FALSE,
GNOME_VFS_DIRECTORY_FILTER_NONE,
(GNOME_VFS_DIRECTORY_FILTER_NOSELFDIR
| GNOME_VFS_DIRECTORY_FILTER_NOPARENTDIR),
NULL,
G_MAXINT,
directory_count_callback,
directory);
g_free (uri);
}
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
static int data_dummy;
......
......@@ -118,13 +118,13 @@ void nautilus_directory_set_integer_metadata (NautilusDirectory
/* Monitor the files in a directory. */
void nautilus_directory_file_monitor_add (NautilusDirectory *directory,
gpointer client,
gconstpointer client,
GList *attributes,
GList *metadata_keys,
NautilusFileListCallback initial_files_callback,
gpointer callback_data);
void nautilus_directory_file_monitor_remove (NautilusDirectory *directory,
gpointer client);
gconstpointer client);
/* Return true if the directory has information about all the files.
* This will be false until the directory has been read at least once.
......
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
nautilus-file-attributes.h: #defines and other file-attribute-related info
Copyright (C) 2000 Eazel, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Author: Darin Adler <darin@eazel.com>
*/
#ifndef NAUTILUS_FILE_ATTRIBUTES_H
#define NAUTILUS_FILE_ATTRIBUTES_H
/* Names for NautilusFile attributes. These are used when registering interest
* in changes to the attributes.
*/
#define NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT "directory item count"
#endif /* NAUTILUS_FILE_ATTRIBUTES_H */
......@@ -29,6 +29,9 @@ struct NautilusFileDetails
{
NautilusDirectory *directory;
GnomeVFSFileInfo *info;
gboolean got_directory_count;
gboolean directory_count_failed;
guint directory_count;
gboolean is_gone;
};
......
......@@ -61,9 +61,6 @@ enum {
static guint signals[LAST_SIGNAL];
/* FIXME: This hack needs to die eventually. See comments with function */
static int get_directory_item_count_hack (NautilusFile *file,
gboolean ignore_invisible_items);
static void nautilus_file_initialize_class (NautilusFileClass *klass);
static void nautilus_file_initialize (NautilusFile *file);
static void destroy (GtkObject *object);
......@@ -391,12 +388,18 @@ nautilus_file_matches_uri (NautilusFile *file, const char *uri_string)
}
static int
nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFile *file_2)
nautilus_file_compare_directories_by_size (NautilusFile *file_1, NautilusFile *file_2)
{
gboolean is_directory_1;
gboolean is_directory_2;
int item_count_1;
int item_count_2;
/* Sort order:
* Directories with unkown # of items
* Directories with 0 items
* Directories with n items
* All files.
* The files are sorted by size in a separate pass.
*/
gboolean is_directory_1, is_directory_2;
gboolean count_known_1, count_known_2;
guint item_count_1, item_count_2;
is_directory_1 = nautilus_file_is_directory (file_1);
is_directory_2 = nautilus_file_is_directory (file_2);
......@@ -404,7 +407,6 @@ nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFi
if (is_directory_1 && !is_directory_2) {
return -1;
}
if (is_directory_2 && !is_directory_1) {
return +1;
}
......@@ -414,19 +416,22 @@ nautilus_file_compare_by_size_with_directories (NautilusFile *file_1, NautilusFi
}
/* Both are directories, compare by item count. */
/* FIXME: get_directory_item_count_hack is slow, and calling
* it for every pairwise comparison here is nasty. Need to
* change this to (not-yet-existent) architecture where the
* item count can be calculated once in a deferred way, and
* then stored or cached.
*/
item_count_1 = get_directory_item_count_hack (file_1, FALSE);
item_count_2 = get_directory_item_count_hack (file_2, FALSE);
if (item_count_1 < item_count_2) {
count_known_1 = nautilus_file_get_directory_item_count (file_1,
&item_count_1);
count_known_2 = nautilus_file_get_directory_item_count (file_2,
&item_count_2);
if (!count_known_1 && count_known_2) {
return -1;
}
if (count_known_1 && !count_known_2) {
return +1;
}
if (item_count_1 < item_count_2) {
return -1;
}
if (item_count_2 < item_count_1) {
return +1;
}
......@@ -578,7 +583,7 @@ nautilus_file_compare_for_sort_internal (NautilusFile *file_1,
/* Compare directory sizes ourselves, then if necessary
* use GnomeVFS to compare file sizes.
*/
compare = nautilus_file_compare_by_size_with_directories (file_1, file_2);
compare = nautilus_file_compare_directories_by_size (file_1, file_2);
if (compare != 0) {
return compare;
}
......@@ -800,18 +805,25 @@ nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type
* call this function on a file that is not a directory.
* @ignore_invisible_items: TRUE if invisible items should not be
* included in count.
* @count: Place to put count.
*
* Returns: item count for this directory.
* Returns: TRUE if count is available.
*
**/
guint
gboolean
nautilus_file_get_directory_item_count (NautilusFile *file,
gboolean ignore_invisible_items)
guint *count)
{
g_return_val_if_fail (NAUTILUS_IS_FILE (file), 0);
g_return_val_if_fail (nautilus_file_is_directory (file), 0);
g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
g_return_val_if_fail (nautilus_file_is_directory (file), FALSE);
g_return_val_if_fail (count != NULL, FALSE);
if (!file->details->got_directory_count) {
return FALSE;
}
return get_directory_item_count_hack (file, ignore_invisible_items);
*count = file->details->directory_count;
return TRUE;
}
/**
......@@ -952,56 +964,6 @@ nautilus_file_get_mime_type_as_string_attribute (NautilusFile *file)
return g_strdup ("unknown MIME type");
}
/* This #include is part of the following hack, and should be removed with it */
#include <dirent.h>
static int
get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_items)
{
/* Code borrowed from Gnomad and hacked into here for now */
char * uri;
char * path;
DIR* directory;
int count;
struct dirent * entry;
g_assert (nautilus_file_is_directory (file));
uri = nautilus_file_get_uri (file);
if (nautilus_str_has_prefix (uri, "file://")) {
path = uri + 7;
} else {
path = uri;
}
directory = opendir (path);
g_free (uri);
if (!directory) {
return 0;
}
count = 0;
while ((entry = readdir(directory)) != NULL) {
// Only count invisible items if requested.
if (!ignore_invisible_items || entry->d_name[0] != '.') {
count += 1;
}
}
closedir(directory);
/* This way of getting the count includes . and .., so we subtract those out */
if (!ignore_invisible_items) {
count -= 2;
}
return count;
}
/**
* nautilus_file_get_size_as_string:
*
......@@ -1016,26 +978,23 @@ get_directory_item_count_hack (NautilusFile *file, gboolean ignore_invisible_ite
static char *
nautilus_file_get_size_as_string (NautilusFile *file)
{
guint item_count;
g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
if (nautilus_file_is_directory (file)) {
/* FIXME: Since computing the item count is slow, we
* want to do it in a deferred way. However, that
* architecture doesn't exist yet, so we're hacking
* it in for now.
*/
int item_count;
item_count = get_directory_item_count_hack (file, FALSE);
if (!nautilus_file_get_directory_item_count (file, &item_count)) {
return g_strdup (_("--"));
}
if (item_count == 0) {
return g_strdup (_("0 items"));
} else if (item_count == 1) {
}
if (item_count == 1) {
return g_strdup (_("1 item"));
} else {
return g_strdup_printf (_("%d items"), item_count);
}
return g_strdup_printf (_("%u items"), item_count);
}
return gnome_vfs_file_size_to_string (file->details->info->size);
}
......
......@@ -72,11 +72,11 @@ void nautilus_file_delete (NautilusFile *
/* Monitor the file. */
void nautilus_file_monitor_add (NautilusFile *file,
gpointer client,
gconstpointer client,
GList *attributes,
GList *metadata_keys);
void nautilus_file_monitor_remove (NautilusFile *file,
gpointer client);
gconstpointer client);
/* Waiting for data that's read asynchronously.
* This interface currently works only for metadata, but could be expanded
......@@ -99,8 +99,8 @@ const char * nautilus_file_get_mime_type (NautilusFile *
gboolean nautilus_file_is_symbolic_link (NautilusFile *file);
gboolean nautilus_file_is_executable (NautilusFile *file);
gboolean nautilus_file_is_directory (NautilusFile *file);
guint nautilus_file_get_directory_item_count (NautilusFile *file,
gboolean ignore_invisible_items);
gboolean nautilus_file_get_directory_item_count (NautilusFile *file,
guint *count);
GList * nautilus_file_get_keywords (NautilusFile *file);
void nautilus_file_set_keywords (NautilusFile *file,
GList *keywords);
......
......@@ -34,8 +34,9 @@ libnautilus_extensionsinclude_HEADERS= \
nautilus-bonobo-extensions.h \
nautilus-bookmark.h \
nautilus-debug.h \
nautilus-directory.h \
nautilus-directory-background.h \
nautilus-directory.h \
nautilus-file-attributes.h \
nautilus-file-utilities.h \
nautilus-file.h \
nautilus-gdk-extensions.h \
......@@ -67,8 +68,8 @@ libnautilus_extensions_la_SOURCES = \
nautilus-debug.c \
nautilus-default-file-icon.c \
nautilus-default-file-icon.h \
nautilus-directory.c \
nautilus-directory-background.c \
nautilus-directory.c \
nautilus-file-utilities.c \
nautilus-file.c \
nautilus-gdk-extensions.c \
......
......@@ -55,7 +55,7 @@ struct NautilusDirectoryDetails
guint write_metafile_idle_id;
MetafileWriteState *write_state;
/* These list are going to be pretty short. If we think they
/* These lists are going to be pretty short. If we think they
* are going to get big, we can use hash tables instead.
*/
GList *metafile_callbacks;
......@@ -67,6 +67,9 @@ struct NautilusDirectoryDetails
GnomeVFSDirectoryListPosition directory_load_list_last_handled;
GList *pending_file_info;
guint dequeue_pending_idle_id;
GnomeVFSAsyncHandle *count_in_progress;
NautilusFile *count_file;
};
typedef struct {
......
......@@ -33,6 +33,7 @@
#include <parser.h>
#include <xmlmemory.h>
#include "nautilus-file-attributes.h"
#include "nautilus-glib-extensions.h"
#include "nautilus-gtk-macros.h"
#include "nautilus-string.h"
......@@ -79,6 +80,11 @@ struct MetafileWriteState {
gboolean write_again;
};
typedef struct {
gconstpointer client;
gboolean monitor_directory_counts;
} FileMonitor;
#define READ_CHUNK_SIZE (4 * 1024)
static int compare_file_with_name (gconstpointer a,
......@@ -144,6 +150,7 @@ static GnomeVFSDirectoryListPosition nautilus_gnome_vfs_directory_list_get_next_
GnomeVFSDirectoryListPosition position);
static void nautilus_gnome_vfs_file_info_list_free (GList *list);
static void nautilus_gnome_vfs_file_info_list_unref (GList *list);
static void process_pending_file_attribute_requests (NautilusDirectory *directory);
static void schedule_dequeue_pending (NautilusDirectory *directory);
static void stop_monitoring_files (NautilusDirectory *directory);
......@@ -245,7 +252,7 @@ nautilus_directory_destroy (GtkObject *object)
if (directory->details->file_monitors != NULL) {
g_warning ("destroying a NautilusDirectory while it's being monitored");
stop_monitoring_files (directory);
g_list_free (directory->details->file_monitors);
nautilus_g_list_free_deep (directory->details->file_monitors);
}
g_hash_table_remove (directory_objects, directory->details->uri_text);
......@@ -876,22 +883,67 @@ nautilus_directory_new (const char* uri)
return directory;
}
static int
compare_file_monitor_with_client (gconstpointer a,
gconstpointer client)
{
const FileMonitor *monitor;
monitor = a;
if (monitor->client < client) {
return -1;
}
if (monitor->client > client) {
return +1;
}
return 0;
}
static GList *
find_file_monitor (NautilusDirectory *directory,
gconstpointer client)
{
return g_list_find_custom (directory->details->file_monitors,
(gpointer) client,
compare_file_monitor_with_client);
}
static void
remove_file_monitor (NautilusDirectory *directory,