From 4c6fef14d8db8b5d35672968dc78425a4f4663bf Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Tue, 12 Jan 1999 05:55:12 +0000 Subject: [PATCH] Export access to the treestore Make gtkdtree use the treestore cache. Next step: store the ->scanned attribute of tree_entry (otherwise, no speedup will be noticed at all). It is a 10 minute hack, but I will go have dinner now. Miguel. --- ChangeLog | 4 ++ gnome/ChangeLog | 10 ++++ gnome/gtkdtree.c | 112 ++++++++++++++++++++-------------- gnome/gtkdtree.h | 2 + src/dir.c | 4 +- src/main.c | 24 ++++++++ src/tree.c | 6 +- src/treestore.c | 152 ++++++++++++++++++++++++++++++++++++++++------- src/treestore.h | 45 +++++++++----- 9 files changed, 274 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 79c8e9c74..4e64a793d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +1999-01-10 Ilya Zakharevich + + * gtkedit/edit.c (edit_load_file): Off-by-one error disabled editing. + 1999-01-11 Miguel de Icaza * configure.in (REGEX_O): Always include regex.o as the code we diff --git a/gnome/ChangeLog b/gnome/ChangeLog index 1b781a32a..94f08e1f6 100644 --- a/gnome/ChangeLog +++ b/gnome/ChangeLog @@ -1,3 +1,13 @@ +1999-01-12 Miguel de Icaza + + * gtkdtree.c: Now it uses the treestore code. + + * treestore.c: Provide _opendir, _readdir, _closedir operations + for the tree cache. + + Next step: load/save the tree_entry->scanned flag (without this, + you wont notice a big speedup). + 1999-01-10 Miguel de Icaza * gutil.c (my_system_get_child_pid): Acknowledge new EXECUTE_WAIT diff --git a/gnome/gtkdtree.c b/gnome/gtkdtree.c index 9fde903d9..7c12f9f3f 100644 --- a/gnome/gtkdtree.c +++ b/gnome/gtkdtree.c @@ -7,6 +7,8 @@ * */ #include +#include "util.h" +#include "treestore.h" #include #include "gtkdtree.h" @@ -14,7 +16,6 @@ #include #include #include -#include "../vfs/vfs.h" #include "dir-open.xpm" #include "dir-close.xpm" @@ -101,46 +102,26 @@ gtk_dtree_contains (GtkDTree *dtree, GtkCTreeNode *parent, char *text) static gboolean gtk_dtree_load_path (GtkDTree *dtree, char *path, GtkCTreeNode *parent, int level) { - DIR *dir; - struct dirent *dirent; + tree_scan *dir; + tree_entry *dirent; g_assert (path); g_assert (parent); g_assert (dtree); - dir = mc_opendir (path); + dir = tree_store_opendir (path); if (!dir) return FALSE; - for (; (dirent = mc_readdir (dir)) != NULL; ){ + for (; (dirent = tree_store_readdir (dir)) != NULL; ){ GtkCTreeNode *sibling; struct stat s; - char *full_name; char *text [1]; int res; - if (dirent->d_name [0] == '.'){ - if (dirent->d_name [1] == '.'){ - if (dirent->d_name [2] == 0) - continue; - } else if (dirent->d_name [1] == 0) - continue; - } + res = mc_stat (dirent->name, &s); - full_name = g_concat_dir_and_file (path, dirent->d_name); - res = mc_stat (full_name, &s); - - if (res == -1){ - g_free (full_name); - continue; - } - - if (!S_ISDIR (s.st_mode)){ - g_free (full_name); - continue; - } - - text [0] = dirent->d_name; + text [0] = x_basename (dirent->name); /* Do not insert duplicates */ sibling = gtk_dtree_contains (dtree, parent, text [0]); @@ -158,15 +139,13 @@ gtk_dtree_load_path (GtkDTree *dtree, char *path, GtkCTreeNode *parent, int leve } if (level) - gtk_dtree_load_path (dtree, full_name, sibling, level-1); - - g_free (full_name); + gtk_dtree_load_path (dtree, dirent->name, sibling, level-1); if (!level) break; } - mc_closedir (dir); + tree_store_closedir (dir); return TRUE; } @@ -195,7 +174,8 @@ gtk_dtree_select_row (GtkCTree *ctree, GtkCTreeNode *row, gint column) dtree->current_path = path; - gtk_signal_emit (GTK_OBJECT (ctree), gtk_dtree_signals [DIRECTORY_CHANGED], path); + if (!dtree->internal) + gtk_signal_emit (GTK_OBJECT (ctree), gtk_dtree_signals [DIRECTORY_CHANGED], path); gtk_dtree_load_path (dtree, path, row, 1); #if 0 @@ -248,7 +228,8 @@ gtk_dtree_do_select_dir (GtkDTree *dtree, char *path) { GtkCTreeNode *current_node; char *s, *current, *npath; - + char *request; + g_return_val_if_fail (dtree != NULL, FALSE); g_return_val_if_fail (GTK_IS_DTREE (dtree), FALSE); g_return_val_if_fail (path != NULL, FALSE); @@ -256,7 +237,7 @@ gtk_dtree_do_select_dir (GtkDTree *dtree, char *path) if (dtree->current_path && (strcmp (path, dtree->current_path) == 0)) return TRUE; - + s = alloca (strlen (path)+1); strcpy (s, path); current_node = dtree->root_node; @@ -264,6 +245,7 @@ gtk_dtree_do_select_dir (GtkDTree *dtree, char *path) s++; npath = g_strdup ("/"); + dtree->internal = 1; while ((current = strtok (s, "/")) != NULL){ char *full_path; GtkCTreeNode *node; @@ -282,14 +264,12 @@ gtk_dtree_do_select_dir (GtkDTree *dtree, char *path) if (node){ gtk_ctree_expand (GTK_CTREE (dtree), node); - while (gtk_events_pending ()) - gtk_main_iteration (); current_node = node; } else break; } g_free (npath); - + if (current_node){ if (!gtk_ctree_node_is_visible (GTK_CTREE (dtree), current_node)){ gtk_ctree_node_moveto (GTK_CTREE (dtree), current_node, 0, 0.5, 0.0); @@ -306,6 +286,8 @@ gtk_dtree_do_select_dir (GtkDTree *dtree, char *path) dtree->requested_path = NULL; } + dtree->internal = 0; + return TRUE; } @@ -331,10 +313,9 @@ gtk_dtree_select_dir (GtkDTree *dtree, char *path) if (dtree->visible) gtk_dtree_do_select_dir (dtree, path); else { - if (dtree->requested_path){ + if (dtree->requested_path) g_free (dtree->requested_path); - dtree->requested_path = g_strdup (path); - } + dtree->requested_path = g_strdup (path); } return TRUE; @@ -344,7 +325,8 @@ static void gtk_dtree_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkDTree *dtree = GTK_DTREE (widget); - + char *request; + GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); if (allocation->width != 0 && allocation->height != 0) dtree->visible = TRUE; @@ -353,11 +335,23 @@ gtk_dtree_size_allocate (GtkWidget *widget, GtkAllocation *allocation) if (!(dtree->visible && dtree->requested_path)) return; - - if (strcmp (dtree->current_path, dtree->requested_path) != 0) + + if (!dtree->visible) return; - gtk_dtree_do_select_dir (dtree, dtree->requested_path); + if (!dtree->requested_path) + return; + + if (strcmp (dtree->current_path, dtree->requested_path) == 0){ + g_free (dtree->requested_path); + dtree->requested_path = NULL; + return; + } + + request = dtree->requested_path; + dtree->requested_path = NULL; + gtk_dtree_do_select_dir (dtree, request); + g_free (request); } static void @@ -481,11 +475,41 @@ gdk_dtree_load_pixmaps (GtkDTree *dtree) &dtree->pixmap_close, &dtree->bitmap_close); } +static int dirty_tag = -1; + +static int +gtk_dtree_save_tree (void) +{ + dirty_tag = -1; + mc_tree_store_save (); + return FALSE; +} + +static void +gtk_dtree_dirty_notify (int state) +{ + if (dirty_tag != -1){ + if (state) + return; + else { + gtk_timeout_remove (dirty_tag); + dirty_tag = -1; + } + } + + if (state) + dirty_tag = gtk_timeout_add (1000, (GtkFunction) gtk_dtree_save_tree, NULL); +} + static void gtk_dtree_init (GtkDTree *dtree) { + static int tree_inited; + dtree->current_path = NULL; dtree->auto_expanded_nodes = NULL; + + tree_store_dirty_notify = gtk_dtree_dirty_notify; } void diff --git a/gnome/gtkdtree.h b/gnome/gtkdtree.h index 3542f36c9..34ccb0049 100644 --- a/gnome/gtkdtree.h +++ b/gnome/gtkdtree.h @@ -30,6 +30,8 @@ typedef struct { /* Masks */ GdkBitmap *bitmap_open; GdkBitmap *bitmap_close; + + int internal; } GtkDTree; typedef struct { diff --git a/src/dir.c b/src/dir.c index 2f70fad47..fdd9f845a 100644 --- a/src/dir.c +++ b/src/dir.c @@ -455,7 +455,7 @@ int do_load_dir(dir_list *list, sortfn *sort, int reverse, int case_sensitive, c struct stat buf; int dotdot_found = 0; - tree_store_start_check (); + tree_store_start_check_cwd (); dirp = mc_opendir ("."); if (!dirp){ @@ -551,7 +551,7 @@ int do_reload_dir (dir_list *list, sortfn *sort, int count, int rev, int tmp_len; /* For optimisation */ int dotdot_found = 0; - tree_store_start_check (); + tree_store_start_check_cwd (); dirp = mc_opendir ("."); if (!dirp) { clean_dir (list, count); diff --git a/src/main.c b/src/main.c index 24ea42199..3da1a2581 100644 --- a/src/main.c +++ b/src/main.c @@ -2810,6 +2810,28 @@ compatibility_move_mc_files (void) } #endif +void +mc_tree_store_load () +{ + char *tree_file; + + tree_file = concat_dir_and_file (home_dir, MC_TREE); + tree_store_init (); + tree_store_load (tree_file); + free (tree_file); +} + +void +mc_tree_store_save () +{ + char *tree_file; + + printf ("Saving tree!\n"); + tree_file = concat_dir_and_file (home_dir, MC_TREE); + tree_store_save (tree_file); + free (tree_file); +} + int main (int argc, char *argv []) { /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */ @@ -2857,6 +2879,8 @@ int main (int argc, char *argv []) handle_args(argc, argv); + mc_tree_store_load (); + session_management_setup (argv [0]); probably_finish_program (); #endif diff --git a/src/tree.c b/src/tree.c index 74838b20b..128350542 100644 --- a/src/tree.c +++ b/src/tree.c @@ -187,11 +187,7 @@ void load_tree (WTree *tree) tree->selected_ptr = tree->store->tree_first; - if (!v){ - tree_store_add_entry (home_dir); - tree_chdir (tree, home_dir); - tree_store_rescan (home_dir); - } + tree_chdir (tree, home_dir); } /* Save the .mc.tree file */ diff --git a/src/treestore.c b/src/treestore.c index 9a29c4f9c..5bc5699e7 100644 --- a/src/treestore.c +++ b/src/treestore.c @@ -53,6 +53,17 @@ static TreeStore ts; +void (*tree_store_dirty_notify)(int state) = NULL; + +void +tree_store_dirty (int state) +{ + ts.dirty = state; + + if (tree_store_dirty_notify) + (*tree_store_dirty_notify)(state); +} + /* Returns number of common characters */ static int str_common (char *s1, char *s2) { @@ -240,6 +251,7 @@ tree_store_load (char *name) if (!ts.tree_first){ tree_store_add_entry (PATH_SEP_STR); tree_store_rescan (PATH_SEP_STR); + ts.loaded = TRUE; } return TRUE; @@ -314,6 +326,7 @@ tree_store_save (char *name) } current = current->next; } + tree_store_dirty (FALSE); fclose (file); return 0; @@ -411,7 +424,8 @@ tree_store_add_entry (char *name) } free (parent); } - + + tree_store_dirty (TRUE); return new; } @@ -481,6 +495,7 @@ tree_store_remove_entry (char *name) remove_entry (old); } remove_entry (base); + tree_store_dirty (TRUE); return; } @@ -531,24 +546,37 @@ tree_store_mark_checked (const char *subname) } /* Mark the subdirectories of the current directory for delete */ -void -tree_store_start_check (void) +tree_entry * +tree_store_start_check (char *path) { - tree_entry *current; + tree_entry *current, *retval; int len; if (!ts.loaded) - return; + return NULL; - /* Search for the start of subdirectories */ - mc_get_current_wd (ts.check_name, MC_MAXPATHLEN); ts.check_start = NULL; - current = tree_store_whereis (ts.check_name); + + /* Search for the start of subdirectories */ + current = tree_store_whereis (path); if (!current){ - /* Cwd doesn't exist -> add it */ - current = tree_store_add_entry (ts.check_name); - return; + struct stat s; + + if (stat (path, &s) == -1) + return NULL; + + if (!S_ISDIR (s.st_mode)) + return NULL; + + current = tree_store_add_entry (path); + ts.check_name = strdup (path); + + return current; } + + ts.check_name = strdup (path); + + retval = current; /* Mark old subdirectories for delete */ ts.check_start = current->next; @@ -561,6 +589,17 @@ tree_store_start_check (void) current->mark = 1; current = current->next; } + + return retval; +} + +tree_entry * +tree_store_start_check_cwd (void) +{ + char buffer [MC_MAXPATHLEN]; + + mc_get_current_wd (buffer, MC_MAXPATHLEN); + return tree_store_start_check (buffer); } /* Delete subdirectories which still have the deletion mark */ @@ -585,27 +624,45 @@ tree_store_end_check (void) if (old->mark) remove_entry (old); } + + free (ts.check_name); } -void +tree_entry * tree_store_rescan (char *dir) { DIR *dirp; struct dirent *dp; struct stat buf; + tree_entry *entry; + + entry = tree_store_start_check (dir); - tree_store_start_check (); - - dirp = opendir (dir); + if (!entry) + return NULL; + + dirp = mc_opendir (dir); if (dirp){ - for (dp = readdir (dirp); dp; dp = readdir (dirp)){ - lstat (dp->d_name, &buf); - if (S_ISDIR (buf.st_mode)) - tree_store_mark_checked (dp->d_name); + for (dp = mc_readdir (dirp); dp; dp = mc_readdir (dirp)){ + char *full_name; + + if (dp->d_name [0] == '.' && + dp->d_name [1] == 0 || (dp->d_name [1] == '.' && dp->d_name [2] == 0)) + continue; + + full_name = concat_dir_and_file (dir, dp->d_name); + if (lstat (full_name, &buf) != -1){ + if (S_ISDIR (buf.st_mode)) + tree_store_mark_checked (dp->d_name); + } + free (full_name); } - closedir (dirp); + mc_closedir (dirp); } tree_store_end_check (); + entry->scanned = 1; + + return entry; } static Hook *remove_entry_hooks; @@ -629,3 +686,58 @@ tree_store_notify_remove (tree_entry *entry) p = p->next; } } + +tree_scan * +tree_store_opendir (char *path) +{ + tree_entry *entry; + tree_scan *scan; + + entry = tree_store_whereis (path); + if (!entry || (entry && !entry->scanned)){ + entry = tree_store_rescan (path); + + if (!entry) + return NULL; + } + + scan = xmalloc (sizeof (tree_scan), ""); + scan->base = entry; + scan->current = entry->next; + scan->sublevel = entry->next->sublevel; + + scan->base_dir_len = strlen (path); + return scan; +} + +tree_entry * +tree_store_readdir (tree_scan *scan) +{ + tree_entry *entry; + int len; + + g_assert (scan != NULL); + + len = scan->base_dir_len; + entry = scan->current; + while (entry && + (strncmp (entry->name, scan->base->name, len) == 0) && + (entry->name [len] == 0 || entry->name [len] == PATH_SEP || len == 1)){ + + if (entry->sublevel == scan->sublevel){ + scan->current = entry->next; + return entry; + } + entry = entry->next; + } + + return NULL; +} + +void +tree_store_closedir (tree_scan *scanner) +{ + g_assert (scanner != NULL); + + free (scanner); +} diff --git a/src/treestore.h b/src/treestore.h index 38fbf0b5a..f5fe24006 100644 --- a/src/treestore.h +++ b/src/treestore.h @@ -6,33 +6,50 @@ typedef struct tree_entry { int sublevel; /* Number of parent directories (slashes) */ long submask; /* Bitmask of existing sublevels after this entry */ char *subname; /* The last part of name (the actual name) */ - int mark; /* Flag: Is this entry marked (e. g. for delete)? */ + unsigned int mark:1; /* Flag: Is this entry marked (e. g. for delete)? */ + unsigned int scanned:1; /* Flag: childs scanned or not */ struct tree_entry *next; /* Next item in the list */ struct tree_entry *prev; /* Previous item in the list */ } tree_entry; +typedef struct { + struct tree_entry *base; + struct tree_entry *current; + int base_dir_len; + int sublevel; +} tree_scan; + typedef struct { int refcount; tree_entry *tree_first; /* First entry in the list */ tree_entry *tree_last; /* Last entry in the list */ tree_entry *check_start; /* Start of checked subdirectories */ - char check_name [MC_MAXPATHLEN];/* Directory which is been checked */ - int loaded; + char *check_name; /* Directory which is been checked */ + unsigned int loaded : 1; + unsigned int dirty : 1; } TreeStore; -TreeStore *tree_store_init (void); -int tree_store_load (char *name); -int tree_store_save (char *name); -tree_entry *tree_store_add_entry (char *name); -void tree_store_remove_entry (char *name); -void tree_store_destroy (void); -void tree_store_start_check (void); -void tree_store_mark_checked (const char *subname); -void tree_store_end_check (void); -tree_entry *tree_store_whereis (char *name); -void tree_store_rescan (char *dir); +extern void (*tree_store_dirty_notify)(int state); + +TreeStore *tree_store_init (void); +int tree_store_load (char *name); +int tree_store_save (char *name); +tree_entry *tree_store_add_entry (char *name); +void tree_store_remove_entry (char *name); +void tree_store_destroy (void); +tree_entry *tree_store_start_check (char *path); +void tree_store_mark_checked (const char *subname); +void tree_store_end_check (void); +tree_entry *tree_store_whereis (char *name); +tree_entry *tree_store_rescan (char *dir); typedef void (*tree_store_remove_fn)(tree_entry *tree, void *data); void tree_store_add_entry_remove_hook (tree_store_remove_fn callback, void *data); +void tree_store_notify_remove (tree_entry *entry); + +tree_scan *tree_store_opendir (char *path); +tree_entry *tree_store_readdir (tree_scan *scanner); +void tree_store_closedir (tree_scan *scanner); + #endif