Index: firmware/common/dircache.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/common/dircache.c,v
retrieving revision 1.16
diff -u -b -r1.16 dircache.c
--- firmware/common/dircache.c	16 Apr 2006 17:32:54 -0000	1.16
+++ firmware/common/dircache.c	23 Apr 2006 17:34:18 -0000
@@ -47,6 +47,8 @@
 #define MAX_OPEN_DIRS 8
 DIRCACHED opendirs[MAX_OPEN_DIRS];
 
+
+static struct deepcache_helpers deepcache_helpers;
 static struct dircache_entry *fd_bindings[MAX_OPEN_FILES];
 static struct dircache_entry *dircache_root;
 
@@ -210,7 +212,7 @@
         if (td->entry.attr & FAT_ATTR_DIRECTORY)
 #endif
         {
-            
+            td->ce->deepcache = DEEPCACHE_ANY;
             td->down_entry = dircache_gen_down(td->ce);
             if (td->down_entry == NULL)
                 return -2;
@@ -244,6 +246,15 @@
             return 1;
         }
         
+        DEEPCACHE d = deepcache_helpers.deepcache_of_filename(td->ce->d_name);
+        td->ce->deepcache = d;
+        if ((td->ce->d_name[0]!='.') &&
+             ! (td->ce->attribute & ATTR_HIDDEN))
+        {
+            if(td->ce->up && td->ce->up->deepcache < d)
+                td->ce->up->deepcache = d;
+        }
+        
         td->ce->down = NULL;
         td->ce = dircache_gen_next(td->ce);
         if (td->ce == NULL)
@@ -260,6 +271,16 @@
         
     }
 
+    struct dircache_entry *de = td->ce->up;
+    if (de &&
+        (de->d_name[0]!='.') &&
+        ! (de->attribute & ATTR_HIDDEN) &&
+        de->up &&
+        de->up->deepcache < de->deepcache)
+    {
+        de->up->deepcache = de->deepcache;
+    }
+
     return 0;
 }
 
@@ -287,6 +308,7 @@
             case 0: /* Leaving the current directory. */
                 /* Add the standard . and .. entries. */
                 ce = dir_recursion[depth].ce;
+                
                 ce->d_name = ".";
                 ce->name_len = 2;
 #ifdef SIMULATOR
@@ -664,8 +686,10 @@
  * Main initialization function that must be called before any other
  * operations within the dircache.
  */
-void dircache_init(void)
+void dircache_init(struct deepcache_helpers d_helpers)
 {
+    deepcache_helpers = d_helpers;
+
     int i;
     
     memset(opendirs, 0, sizeof(opendirs));
@@ -809,6 +833,19 @@
     return 0;
 }
 
+/* A folder has a deepcache value higher or equal to the maximum of those of its children. */
+static void deepcache_invariant(const struct dircache_entry* new_entry) {
+    while ((new_entry->d_name[0]!='.') &&
+            ! (new_entry->attribute & ATTR_HIDDEN))
+    {
+        if(new_entry->up && new_entry->up->deepcache < new_entry->deepcache)
+            new_entry->up->deepcache = new_entry->deepcache;
+        else
+            return ;
+        new_entry = new_entry->up;
+    }
+}
+
 static struct dircache_entry* dircache_new_entry(const char *path, int attribute)
 {
     struct dircache_entry *entry;
@@ -871,6 +908,9 @@
     {
         logf("gen_down");
         dircache_gen_down(entry);
+        entry->deepcache = DEEPCACHE_ANY;
+    } else {
+        entry->deepcache = deepcache_helpers.deepcache_of_filename(new);
     }
         
     reserve_used += dircache_size - last_cache_size;
@@ -1032,6 +1072,11 @@
     newentry->startcluster = oldentry.startcluster;
     newentry->wrttime = oldentry.wrttime;
     newentry->wrtdate = oldentry.wrtdate;
+    
+    if (newentry->attribute & ATTR_DIRECTORY) {
+        newentry->deepcache = oldentry.deepcache;
+    }
+    deepcache_invariant(entry);
 }
 
 void dircache_add_file(const char *path, long startcluster)
@@ -1047,6 +1092,7 @@
         return ;
     
     entry->startcluster = startcluster;
+    deepcache_invariant(entry);
 }
 
 DIRCACHED* opendir_cached(const char* name)
@@ -1119,6 +1165,15 @@
         dir->secondary_entry.wrtdate = regentry->wrtdate;
         dir->secondary_entry.next = NULL;
         
+        if (regentry->attribute & ATTR_DIRECTORY) {
+            /* we won't recurse here, deep filtering
+            requires dircache entries. */
+            dir->secondary_entry.deepcache = DEEPCACHE_PLAYLIST;
+        } else {
+            dir->secondary_entry.deepcache =
+                deepcache_helpers.deepcache_of_filename(regentry->d_name);
+        }
+        
         return &dir->secondary_entry;
     }
         
@@ -1139,6 +1194,7 @@
     dir->secondary_entry.size = ce->size;
     dir->secondary_entry.startcluster = ce->startcluster;
     dir->secondary_entry.attribute = ce->attribute;
+    dir->secondary_entry.deepcache = ce->deepcache;
     dir->secondary_entry.wrttime = ce->wrttime;
     dir->secondary_entry.wrtdate = ce->wrtdate;
     dir->secondary_entry.next = NULL;
Index: firmware/include/deepcache.h
===================================================================
RCS file: firmware/include/deepcache.h
diff -N firmware/include/deepcache.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ firmware/include/deepcache.h	23 Apr 2006 17:34:18 -0000
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: deepcache.h,v 1.0 2006-04-17 12:28:00 g2p Exp $
+ *
+ * Copyright (C) 2006 by Gabriel de Perthuis
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+ 
+ 
+/*
+    Keep info about what is below a dircache entry.
+    struct dircache_entry has a field of type DEEPCACHE.
+    This allows filetree.c to hide dirs that have no useful content.
+*/ 
+ 
+#ifndef _DEEPCACHE_H
+#define _DEEPCACHE_H
+
+
+
+
+/*
+    Possible strategies are:
+    COUNT:
+    Count how many children are of each type
+    (music, supported, unsupported, possibly playlist)
+    UNION:
+    Tell wether there are children of each type, in an OR of all their values.
+    DISABLE:
+    Don't use deepcache.
+    
+    The COUNT strategy needs a few more bytes, but is able to efficiently
+    update the cache on a delete or a move.
+*/
+
+/* If the entry is a file, this contains its attributes.
+    If it is a dir, this contains a function of its children's attributes.
+    Relevant attributes are
+        TREE_ATTR_M3U
+        TREE_ATTR_MPA
+    An attribute for supported files (filetype_supported in filetypes.h)
+    may be too costly.
+ */
+
+
+/*
+    PLAYLIST implies MUSIC implies SUPPORTED implies ANY.
+    The function to merge directory contents is: MAX
+*/
+enum deepcache_maximum {
+    DEEPCACHE_ANY = 0,
+    DEEPCACHE_SUPPORTED,
+    DEEPCACHE_MUSIC,
+    DEEPCACHE_PLAYLIST,
+    DEEPCACHE_MAX = DEEPCACHE_PLAYLIST,
+};
+typedef enum deepcache_maximum DEEPCACHE;
+
+
+struct deepcache_helpers {
+    DEEPCACHE (*deepcache_of_filename) (const char* filename);
+};
+
+
+#endif
Index: firmware/include/dircache.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/include/dircache.h,v
retrieving revision 1.11
diff -u -b -r1.11 dircache.h
--- firmware/include/dircache.h	16 Apr 2006 17:32:54 -0000	1.11
+++ firmware/include/dircache.h	23 Apr 2006 17:34:18 -0000
@@ -22,6 +22,7 @@
 #include "dir.h"
 
 #ifdef HAVE_DIRCACHE
+#include "deepcache.h"
 
 #define DIRCACHE_RESERVE  (1024*64)
 #define DIRCACHE_LIMIT    (1024*1024*6)
@@ -63,6 +64,7 @@
     struct dircache_entry *up;
     struct dircache_entry *down;
     int attribute;
+    DEEPCACHE deepcache;
     long size;
     long startcluster;
     unsigned short wrtdate;
@@ -79,7 +81,7 @@
     DIR *regulardir;
 } DIRCACHED;
 
-void dircache_init(void);
+void dircache_init(struct deepcache_helpers d_helpers);
 int dircache_load(const char *path);
 int dircache_save(const char *path);
 int dircache_build(int last_size);
@@ -111,7 +113,6 @@
 # define opendir_cached opendir
 # define closedir_cached closedir
 # define readdir_cached readdir
-# define closedir_cached closedir
 #endif /* !HAVE_DIRCACHE */
 
 #endif
Index: apps/filetree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/filetree.c,v
retrieving revision 1.34
diff -u -b -r1.34 filetree.c
--- apps/filetree.c	15 Apr 2006 06:23:34 -0000	1.34
+++ apps/filetree.c	23 Apr 2006 17:34:19 -0000
@@ -222,6 +222,7 @@
     for ( i=0; i < global_settings.max_files_in_dir; i++ ) {
         int len;
         struct dircache_entry *entry = readdir_cached(dir);
+        
         struct entry* dptr =
             (struct entry*)(c->dircache + i * sizeof(struct entry));
         if (!entry)
@@ -271,13 +272,12 @@
 #endif
 
         /* filter out non-visible files */
-        if ((!(dptr->attr & ATTR_DIRECTORY) && (
+        if (
             (*c->dirfilter == SHOW_PLAYLIST &&
-             (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_M3U) ||
-            ((*c->dirfilter == SHOW_MUSIC &&
-             (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MPA) &&
-             (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_M3U) ||
-            (*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
+             entry->deepcache < DEEPCACHE_PLAYLIST) ||
+            (*c->dirfilter == SHOW_MUSIC &&
+             entry->deepcache < DEEPCACHE_MUSIC) ||
+            (*c->dirfilter == SHOW_SUPPORTED && entry->deepcache < DEEPCACHE_SUPPORTED) ||
             (*c->dirfilter == SHOW_WPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_WPS) ||
 #ifdef HAVE_REMOTE_LCD
             (*c->dirfilter == SHOW_RWPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_RWPS) ||
@@ -289,7 +289,7 @@
             (*c->dirfilter == SHOW_LNG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_LNG) ||
             (*c->dirfilter == SHOW_MOD && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MOD) ||
             (*c->dirfilter == SHOW_FONT && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_FONT) ||
-            (*c->dirfilter == SHOW_PLUGINS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_ROCK))
+            (*c->dirfilter == SHOW_PLUGINS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_ROCK)  )
         {
             i--;
             continue;
Index: apps/filetypes.c
===================================================================
RCS file: /cvsroot/rockbox/apps/filetypes.c,v
retrieving revision 1.26
diff -u -b -r1.26 filetypes.c
--- apps/filetypes.c	2 Apr 2006 11:58:25 -0000	1.26
+++ apps/filetypes.c	23 Apr 2006 17:34:19 -0000
@@ -93,7 +93,7 @@
 static void   rm_whitespaces(char*);
 static void   scan_plugins(void);
 
-/* initialize dynamic filetypes (called at boot from tree.c) */
+/* initialize dynamic filetypes (called at boot from main.c) */
 void filetype_init(void)
 {
     int cnt,i,ix;
Index: apps/main.c
===================================================================
RCS file: /cvsroot/rockbox/apps/main.c,v
retrieving revision 1.169
diff -u -b -r1.169 main.c
--- apps/main.c	13 Apr 2006 21:20:13 -0000	1.169
+++ apps/main.c	23 Apr 2006 17:34:19 -0000
@@ -59,6 +59,7 @@
 #include "plugin.h"
 #include "misc.h"
 #include "database.h"
+#include "filetypes.h"
 #include "dircache.h"
 #include "tagcache.h"
 #include "tagtree.h"
@@ -100,6 +101,22 @@
     browse_root();
 }
 
+//XXX non-static?
+DEEPCACHE deepcache_of_filename (const char* filename) {
+    
+    int type_attr = filetype_get_attr(filename);
+    
+    /* This mirrors the filtering in ft_load in filetree.c */
+    if (type_attr == TREE_ATTR_M3U)
+        return DEEPCACHE_PLAYLIST;
+    else if (type_attr == TREE_ATTR_MPA)
+        return DEEPCACHE_MUSIC;
+    else if (filetype_supported(type_attr))
+        return DEEPCACHE_SUPPORTED;
+    else
+        return DEEPCACHE_ANY;
+}
+
 #ifdef HAVE_DIRCACHE
 void init_dircache(void)
 {
@@ -107,7 +124,10 @@
     int result;
     char buf[32];
     
-    dircache_init();
+    struct deepcache_helpers d_helpers;
+    d_helpers.deepcache_of_filename = deepcache_of_filename;
+    dircache_init(d_helpers);
+    
     if (global_settings.dircache)
     {
         /* Print "Scanning disk..." to the display. */
@@ -205,6 +225,7 @@
     settings_load(SETTINGS_ALL);
     gui_sync_wps_init();
     settings_apply();
+    filetype_init();
     init_dircache();
     init_tagcache();
     sleep(HZ/2);
@@ -394,6 +415,7 @@
         settings_load(SETTINGS_ALL);
 
     
+    filetype_init();
     init_dircache();
     gui_sync_wps_init();
     settings_apply();
Index: apps/tree.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tree.c,v
retrieving revision 1.399
diff -u -b -r1.399 tree.c
--- apps/tree.c	15 Apr 2006 13:57:15 -0000	1.399
+++ apps/tree.c	23 Apr 2006 17:34:20 -0000
@@ -228,7 +228,6 @@
 {
     gui_sync_wps_screen_init();
 
-    filetype_init();
     check_rockboxdir();
 
     strcpy(tc.currdir, "/");
Index: apps/tree.h
===================================================================
RCS file: /cvsroot/rockbox/apps/tree.h,v
retrieving revision 1.73
diff -u -b -r1.73 tree.h
--- apps/tree.h	10 Apr 2006 03:51:17 -0000	1.73
+++ apps/tree.h	23 Apr 2006 17:34:21 -0000
@@ -227,7 +227,7 @@
 /* (this also reflects the sort order if by type) */
 #define TREE_ATTR_BMARK 0x0100 /* book mark file */
 #define TREE_ATTR_M3U   0x0200 /* playlist */
-#define TREE_ATTR_MPA   0x0300 /* mpeg audio file */
+#define TREE_ATTR_MPA   0x0300 /* any audio file */
 #define TREE_ATTR_CFG   0x0400 /* config file */
 #define TREE_ATTR_WPS   0x0500 /* wps config file */
 #define TREE_ATTR_FONT  0x0600 /* font file */
