Index: apps/metadata.c
===================================================================
RCS file: /cvsroot/rockbox/apps/metadata.c,v
retrieving revision 1.58
diff -u -r1.58 metadata.c
--- apps/metadata.c	10 Nov 2006 12:26:26 -0000	1.58
+++ apps/metadata.c	14 Nov 2006 21:37:30 -0000
@@ -31,6 +31,10 @@
 #include "debug.h"
 #include "system.h"
 
+#ifdef HAVE_LCD_BITMAP
+#include "gwps.h"
+#endif
+
 enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
 
 #define APETAG_HEADER_LENGTH        32
@@ -1806,11 +1810,164 @@
     return AFMT_UNKNOWN;
 }
 
+#ifdef HAVE_LCD_BITMAP
+/* Strip filename from a full path
+ *
+ * buf      - buffer to extract directory to.
+ * buf_size - size of buffer.
+ * fullpath - fullpath to extract from.
+ *
+ * Split the directory part of the given fullpath and store it in buf
+ *   (including last '/').
+ * The function return parameter is a pointer to the filename
+ *   inside the given fullpath.
+ */
+static char* strip_filename(char* buf, int buf_size, const char* fullpath)
+{
+    char* sep;
+    int   len;
+
+    if (!buf || buf_size <= 0 || !fullpath)
+        return NULL;
+
+    /* if 'fullpath' is only a filename return immediately */
+    sep = strrchr(fullpath, '/');
+    if (sep == NULL)
+    {
+        buf[0] = 0;
+        return (char*)fullpath;
+    }
+
+    len = MIN(sep - fullpath + 1, buf_size - 1);
+    strncpy(buf, fullpath, len);
+    buf[len] = 0;
+    return (sep + 1);
+}
+
+static char* strip_extension(char* buf, int buf_size, const char* file)
+{
+    char* sep;
+    int len;
+
+    if (!buf || buf_size <= 0 || !file)
+        return NULL;
+
+    buf[0] = 0;
+
+    sep = strrchr(file,'.');
+    if (sep == NULL)
+        return NULL;
+
+    len = MIN(sep - file, buf_size - 1);
+    strncpy(buf, file, len);
+    buf[len] = 0;
+    return buf;
+}
+
+static bool file_exists(char *file)
+{
+    int fd;
+
+    if (!file || strlen(file) <= 0)
+        return false;
+
+    fd = open(file, O_RDONLY);
+    if (fd<0)
+        return false;
+    close(fd);
+    return true;
+}
+
+/* Look for albumart bitmap in the same dir as the track and in its parent dir;
+ * stores the found filename in the track->albumart_path.
+ * Returns true if a bitmap was found, false otherwise */
+static bool find_albumart(struct track_info* track, const char* trackname)
+{
+    char path[MAX_PATH + 1];
+    char dir[MAX_PATH + 1];
+    bool found = false;
+
+    if (!track || !trackname)
+        return false;
+
+    strcpy(track->id3.albumart_path, "");
+
+    strip_filename(dir, sizeof(dir), trackname);
+
+    DEBUGF("Looking for album art for %s\n", trackname);
+
+    /* the first file we look for is one specific to the track playing */
+    strip_extension(path, sizeof(path) - 4, trackname);
+    strcat(path, ".bmp");
+    found = file_exists(path);
+    if (!found && track->id3.album && strlen(track->id3.album) > 0)
+    {   /* if it doesn't exist,
+         * we look for a file specific to the track's album name */
+        snprintf(path, sizeof(path) - 1,
+                "%s%s.bmp",
+                 (strlen(dir) >= 1) ? dir : "",
+                 track->id3.album);
+        path[sizeof(path) - 1] = 0;
+        found = file_exists(path);
+    }
+
+    if (!found)
+    {
+        /* if it still doesn't exist, we look for a generic file */
+        snprintf(path, sizeof(path)-1,
+                 "%scover.bmp",
+                 (strlen(dir) >= 1) ? dir : "");
+        path[sizeof(path)-1] = 0;
+        found = file_exists(path);
+    }
+
+    if (!found)
+    {
+        /* if it still doesn't exist,
+         * we continue to search in the parent directory */
+        char temp[MAX_PATH + 1];
+        strncpy(temp, dir, strlen(dir) - 1);
+        temp[strlen(dir) - 1] = 0;
+
+        strip_filename(dir, sizeof(dir), temp);
+    }
+
+    if (!found && track->id3.album && strlen(track->id3.album) > 0)
+    {
+        /* we look in the parent directory
+        ** for a file specific to the track's album name */
+        snprintf(path, sizeof(path)-1,
+                 "%s%s.bmp",
+                 (strlen(dir) >= 1) ? dir : "",
+                 track->id3.album);
+        found = file_exists(path);
+    }
+
+    if (!found)
+    {
+        /* if it still doesn't exist, we look in the parent directory
+         * for a generic file */
+        snprintf(path, sizeof(path)-1,
+                 "%scover.bmp",
+                 (strlen(dir) >= 1) ? dir : "");
+        path[sizeof(path)-1] = 0;
+        found = file_exists(path);
+    }
+
+    if (!found)
+        return false;
+
+    strcpy(track->id3.albumart_path, path);
+    DEBUGF("Album art found for %s : %s\n", trackname, path);
+    return true;
+}
+#endif
+
 /* Get metadata for track - return false if parsing showed problems with the
  * file that would prevent playback.
  */
 bool get_metadata(struct track_info* track, int fd, const char* trackname,
-                  bool v1first) 
+                  bool v1first, bool search_album_art)
 {
 #if CONFIG_CODEC == SWCODEC
     unsigned char* buf;
@@ -2318,6 +2475,11 @@
 
     /* We have successfully read the metadata from the file */
 
+#ifdef HAVE_LCD_BITMAP
+    if (search_album_art && gui_sync_wps_uses_albumart())
+        track->id3.albumart_found = find_albumart(track, trackname);
+#endif
+
 #ifndef __PCTOOL__
     if (cuesheet_is_enabled() && look_for_cuesheet_file(trackname))
     {
Index: apps/metadata.h
===================================================================
RCS file: /cvsroot/rockbox/apps/metadata.h,v
retrieving revision 1.4
diff -u -r1.4 metadata.h
--- apps/metadata.h	26 Mar 2006 11:33:41 -0000	1.4
+++ apps/metadata.h	14 Nov 2006 21:37:30 -0000
@@ -24,7 +24,7 @@
 
 unsigned int probe_file_format(const char *filename);
 bool get_metadata(struct track_info* track, int fd, const char* trackname,
-                  bool v1first);
+                  bool v1first, bool search_album_art);
 
 #endif
 
Index: apps/playback.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.c,v
retrieving revision 1.394
diff -u -r1.394 playback.c
--- apps/playback.c	14 Nov 2006 15:48:20 -0000	1.394
+++ apps/playback.c	14 Nov 2006 21:37:31 -0000
@@ -2599,7 +2599,7 @@
     /* Get track metadata if we don't already have it. */
     if (!tracks[track_widx].taginfo_ready) 
     {
-        if (get_metadata(&tracks[track_widx],current_fd,trackname,v1first)) 
+        if (get_metadata(&tracks[track_widx],current_fd,trackname,v1first,true)) 
         {
             if (start_play) 
             {
@@ -2722,7 +2722,7 @@
     if (fd < 0)
         return false;
 
-    status = get_metadata(&tracks[next_idx],fd,trackname,v1first);
+    status = get_metadata(&tracks[next_idx],fd,trackname,v1first,true);
     /* Preload the glyphs in the tags */
     if (status) 
     {
Index: apps/tagcache.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tagcache.c,v
retrieving revision 1.77
diff -u -r1.77 tagcache.c
--- apps/tagcache.c	10 Nov 2006 09:52:46 -0000	1.77
+++ apps/tagcache.c	14 Nov 2006 21:37:33 -0000
@@ -1495,7 +1495,7 @@
     memset(&track, 0, sizeof(struct track_info));
     memset(&entry, 0, sizeof(struct temp_file_entry));
     memset(&tracknumfix, 0, sizeof(tracknumfix));
-    ret = get_metadata(&track, fd, path, false);
+    ret = get_metadata(&track, fd, path, false, false);
     close(fd);
 
     if (!ret)
Index: apps/gui/gwps-common.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps-common.c,v
retrieving revision 1.65
diff -u -r1.65 gwps-common.c
--- apps/gui/gwps-common.c	13 Nov 2006 00:45:21 -0000	1.65
+++ apps/gui/gwps-common.c	14 Nov 2006 21:37:34 -0000
@@ -91,6 +91,387 @@
     else
         return -1;
 }
+
+/*
+ * parse the album cover definition tag (%Cl) and store the information;
+ * content starting at given tag position.
+ * returns true if definition is correct and could be stored 
+ * false otherwise */
+static bool wps_data_albumart_define(
+                              struct wps_data *data,
+                              const char *tag,
+                              unsigned char *tag_len)
+{
+    const char *start = tag;
+    const char *pos;
+    bool result = false;
+
+    if (!data || !tag)
+        return false;
+
+    *tag_len = 0;
+
+    if (*tag != '|')
+        return false;
+
+    pos = ++tag;
+
+    /* default max width and height are set to -1 (don't use it) */
+    data->albumart_max_width  = -1;
+    data->albumart_max_height = -1;
+    data->albumart_xalign     = -1;
+    data->albumart_yalign     = -1;
+
+    /* get x-position */
+    data->albumart_x = atoi(tag);
+    pos = strchr(pos, '|');
+    if (pos)
+    {
+        tag = ++pos;
+
+        /* get y-position */
+        data->albumart_y = atoi(tag);
+
+        pos = strchr(pos, '|');
+    }
+
+    if (pos)
+    {
+        pos++;
+        if (*pos != '|')
+        {
+            /* maxwidth has been given */
+            bool finished = false;
+
+            /* get x-alignment */
+            data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER;
+            while (!finished)
+            {
+                switch (*pos)
+                {
+                    /* right aligned */
+                    case '-':
+                    case 'r':
+                    case 'R':
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_LEFT;
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_CENTER;
+                        data->albumart_xalign |= WPS_ALBUMART_ALIGN_RIGHT;
+                        pos++;
+                    break;
+
+                    /* left aligned */
+                    case '+':
+                    case 'l':
+                    case 'L':
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_RIGHT;
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_CENTER;
+                        data->albumart_xalign |= WPS_ALBUMART_ALIGN_LEFT;
+                        pos++;
+                    break;
+
+                    /* align center (=default) */
+                    case 'c':
+                    case 'C':
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_LEFT;
+                        data->albumart_xalign &= ~WPS_ALBUMART_ALIGN_RIGHT;
+                        data->albumart_xalign |= WPS_ALBUMART_ALIGN_CENTER;
+                        pos++;
+                    break;
+
+                    /* decrease if larger */
+                    case 'd':
+                    case 'D':
+                        data->albumart_xalign |= WPS_ALBUMART_DECREASE;
+                        pos++;
+                    break;
+
+                    /* increase if smaller */
+                    case 'i':
+                    case 'I':
+                        data->albumart_xalign |= WPS_ALBUMART_INCREASE;
+                        pos++;
+                    break;
+
+                    /* increase of decrease if smaller or larger */
+                    case 's':
+                    case 'S':
+                        data->albumart_xalign |= WPS_ALBUMART_INCREASE;
+                        data->albumart_xalign |= WPS_ALBUMART_DECREASE;
+                        pos++;
+                    break;
+
+                    default:
+                        finished = true;
+                    break;
+                }
+            }
+
+            /* get maxwidth */
+            data->albumart_max_width = atoi(pos);
+            if (data->albumart_max_width > LCD_WIDTH)
+                data->albumart_max_width = LCD_WIDTH;
+            else
+            if (data->albumart_max_width <= 0)
+                data->albumart_max_width = -1;
+        }
+        tag = pos;
+
+        pos = strchr(pos, '|');
+    }
+
+    if (pos)
+    {
+        pos++;
+        if (*pos != '|')
+        {
+            /* maxheight has been given */
+            bool finished = false;
+
+            /* get y-alignment */
+            data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER;
+            while (!finished)
+            {
+                switch (*pos)
+                {
+                    /* top aligned */
+                    case '-':
+                    case 't':
+                    case 'T':
+                    case 'r':
+                    case 'R':
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_BOTTOM;
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_CENTER;
+                        data->albumart_yalign |= WPS_ALBUMART_ALIGN_TOP;
+                        pos++;
+                    break;
+
+                    /* bottom aligned */
+                    case '+':
+                    case 'b':
+                    case 'B':
+                    case 'l':
+                    case 'L':
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_TOP;
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_CENTER;
+                        data->albumart_yalign |= WPS_ALBUMART_ALIGN_BOTTOM;
+                        pos++;
+                    break;
+
+                    /* align center (=default) */
+                    case 'c':
+                    case 'C':
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_TOP;
+                        data->albumart_yalign &= ~WPS_ALBUMART_ALIGN_BOTTOM;
+                        data->albumart_yalign |= WPS_ALBUMART_ALIGN_CENTER;
+                        pos++;
+                    break;
+
+                    /* decrease if larger */
+                    case 'd':
+                    case 'D':
+                        data->albumart_yalign |= WPS_ALBUMART_DECREASE;
+                        pos++;
+                    break;
+
+                    /* increase if smaller */
+                    case 'i':
+                    case 'I':
+                        data->albumart_yalign |= WPS_ALBUMART_INCREASE;
+                        pos++;
+                    break;
+
+                    /* increase of decrease if smaller or larger */
+                    case 's':
+                    case 'S':
+                        data->albumart_yalign |= WPS_ALBUMART_INCREASE;
+                        data->albumart_yalign |= WPS_ALBUMART_DECREASE;
+                        pos++;
+                    break;
+
+                    default:
+                        finished = true;
+                    break;
+                }
+            }
+
+            /* get maxheight */
+            data->albumart_max_height = atoi(pos);
+            if (data->albumart_max_height > LCD_HEIGHT)
+                data->albumart_max_height = LCD_HEIGHT;
+            else
+            if (data->albumart_max_height <= 0)
+                data->albumart_max_height = -1;
+        }
+        tag = pos;
+
+        /* maxheight (end) */
+        pos = strchr(pos, '|');
+    }
+
+    if (pos)
+    {
+        tag = ++pos;
+        result = true;
+        data->wps_uses_albumart = true;
+    }
+
+    if (result)
+    {
+        (*tag_len) = tag - start;
+
+        data->wps_uses_albumart = WPS_ALBUMART_LOAD;
+
+        DEBUGF( "Preload: albumart tag found: tag_len=%u, x|y=%d|%d, w|h=%d|%d, wa|ha=%d|%d!\n",
+                (unsigned int)(*tag_len),
+                data->albumart_x, data->albumart_y,
+                data->albumart_max_width, data->albumart_max_height,
+                data->albumart_xalign, data->albumart_yalign,
+                result );
+    }
+
+    return result;
+}
+
+
+/*
+ * load the current album cover bitmap
+ * which was earlier defined by %Cl tag
+ * it will only be loaded if
+ *  - a %Cl WPS tag exists and
+ *  - if a bitmap file had been found by metadata and
+ *  - if the sizes fit the defined max sizes or
+ *  - if it could be resized (if wanted) */
+static bool wps_data_albumart_load(struct gui_wps *gwps)
+{
+    if (!gwps || !gwps->data)
+        return false;
+    if (gwps->data->wps_uses_albumart != WPS_ALBUMART_LOAD)
+        return false;
+    if (!gwps->state->id3->albumart_found)
+        return false;
+
+    struct wps_data *data = gwps->data;
+
+    if (strcasecmp(gwps->data->cur_displayed_albumart_path,
+                   gwps->state->id3->albumart_path) == 0)
+    {
+        gwps->state->id3->albumart_data = (fb_data*)data->img_buf_ptr;
+        gwps->state->id3->albumart_width = data->cur_displayed_albumart_width;
+        gwps->state->id3->albumart_height = data->cur_displayed_albumart_height;
+        DEBUGF("Skipped loading albumart bitmap '%s' (already loaded)\n",
+               data->cur_displayed_albumart_path);
+        return true;
+    }
+
+    int rc;
+    int mwidth, mwidth_resize;
+    int mheight, mheight_resize;
+    struct bitmap temp_bm;
+
+    temp_bm.data = data->img_buf_ptr;
+
+    mwidth = data->albumart_max_width;
+    mwidth_resize = BMP_RESIZE_NONE;
+    if (data->albumart_xalign & WPS_ALBUMART_INCREASE)
+        mwidth_resize |= BMP_RESIZE_INCREASE;
+    if (data->albumart_xalign & WPS_ALBUMART_DECREASE)
+        mwidth_resize |= BMP_RESIZE_DECREASE;
+    if (mwidth_resize == BMP_RESIZE_NONE)
+        mwidth = -1; /* don't resize */
+
+    mheight = data->albumart_max_height;
+    mheight_resize = BMP_RESIZE_NONE;
+    if (data->albumart_yalign & WPS_ALBUMART_INCREASE)
+        mheight_resize |= BMP_RESIZE_INCREASE;
+    if (data->albumart_yalign & WPS_ALBUMART_DECREASE)
+        mheight_resize |= BMP_RESIZE_DECREASE;
+    if (mheight_resize == BMP_RESIZE_NONE)
+        mheight = -1; /* don't resize */
+
+    DEBUGF( "loading albumart: w|h=%d|%d, wa|ha=%d|%d (%s)\n",
+            mwidth, mheight, mwidth_resize, mheight_resize,
+            gwps->state->id3->albumart_path );
+    rc = read_bmp_file(gwps->state->id3->albumart_path,
+                       &temp_bm, data->img_buf_free,
+                       FORMAT_ANY|FORMAT_TRANSPARENT,
+                       mwidth, mwidth_resize,
+                       mheight, mheight_resize);
+    if (rc <= 0) {
+        gwps->state->id3->albumart_data = NULL;
+        strcpy(data->cur_displayed_albumart_path, "");
+        DEBUGF("Loading albumart bitmap for '%s' failed\n",
+               gwps->state->id3->path);
+
+        return false;
+    }
+
+    gwps->state->id3->albumart_width = temp_bm.width;
+    data->cur_displayed_albumart_width = temp_bm.width;
+    gwps->state->id3->albumart_height = temp_bm.height;
+    data->cur_displayed_albumart_height = temp_bm.height;
+
+    gwps->state->id3->albumart_data = (fb_data *)data->img_buf_ptr;
+    strcpy(data->cur_displayed_albumart_path, gwps->state->id3->albumart_path);
+    DEBUGF("** Loaded albumart bitmap for '%s' (%d bytes)\n",
+           gwps->state->id3->path, rc);
+
+    return true;
+}
+
+/*
+ * display the album bitmap (tag %C) which has
+ * been defined by %Cl tag and loaded at track change */
+static void wps_data_albumart_display(struct gui_wps *gwps)
+{
+    if (!gwps || !gwps->data || !gwps->display)
+        return;
+    if (gwps->state->id3->albumart_data == NULL)
+        return;
+
+    struct wps_data *data = gwps->data;
+
+    /* coordinates where the cover will be drawn */
+    int x = data->albumart_x;
+    int y = data->albumart_y;
+
+    /* NOTE: There is no need to check the bitmap sizes here;
+     * (if they had wrong sizes, the bitmap haven't been loaded earlier) */
+
+    /* if a bounding box was defined,
+     *   position the cover art either centered, left or right
+     *     to the margins of the box
+     * otherwise, just draw at the normal coordinate */
+    if (data->albumart_max_width > 0)
+    {
+        if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
+            x += data->albumart_max_width - gwps->state->id3->albumart_width;
+        else
+        if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
+            x += (data->albumart_max_width - gwps->state->id3->albumart_width)/2;
+    }
+
+    if (data->albumart_max_height > 0)
+    {
+        if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
+            y += data->albumart_max_height - gwps->state->id3->albumart_height;
+        else
+        if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
+            y += (data->albumart_max_height - gwps->state->id3->albumart_height)/2;
+    }
+
+    /* display bitmap */
+    /* DEBUGF( "displaying albumart bitmap: x|y=%d|%d, w|h=%d|%d\n",
+            x, y, 
+            gwps->state->id3->albumart_width,
+            gwps->state->id3->albumart_height ); */
+
+    gwps->display->set_drawmode(DRMODE_FG);
+    gwps->display->bitmap((fb_data *)gwps->state->id3->albumart_data,
+                          x, y,
+                          gwps->state->id3->albumart_width,
+                          gwps->state->id3->albumart_height);
+    gwps->display->set_drawmode(DRMODE_SOLID);
+}
 #endif
     
 /*
@@ -100,11 +481,14 @@
  * %xl   -   preload image
  * %we   -   enable statusbar on wps regardless of the global setting
  * %wd   -   disable statusbar on wps regardless of the global setting
+ * %Cl   -   define cover bitmap dimensions, position and resize behaviour
  * and also for:
  * #     -   a comment line
  *
- * it returns true if one of these tags is found and handled
- * false otherwise
+ * it returns true if one of these tags is found and totally handled
+ *   (and therefore can be removed from further parsing)
+ * it returns false if no tag have been found or a tag has been found
+ *   but only partially handled and needs further parsing...
  */
 bool wps_data_preload_tags(struct wps_data *data, char *buf,
                             const char *bmpdir, size_t bmpdirlen)
@@ -132,7 +516,7 @@
         case 'w':
             /* 
              * if tag found then return because these two tags must be on 
-             * must be on their own line
+             * their own line
              */
             if(*(buf+1) == 'd' || *(buf+1) == 'e')
             {
@@ -344,6 +732,39 @@
         }
 
         break;
+
+        case 'C':
+            /* format: %Cl|x|y|[[l|c|r|d|i|s]mwidth]|[[t|c|b|d|i|s]mheight]|
+             * definition of album cover size, position and resize behaviour;
+             * display it later with %C tag */
+        {
+            if (*(buf+1) == 'l')
+            {
+                /* if the definition can be stored successfully and doesn't
+                 * need to be reparsed
+                 * -> return true so that the tag gets removed from wps_buffer */
+                unsigned char tag_len;
+                return wps_data_albumart_define(data, buf + 2, &tag_len);
+            }
+        }
+        break;
+
+        case '?':
+            /* check for album art conditional %?C[n]... */
+            /* (the existance of this tag needs to be set for get_metadata) */
+        {
+            if (*(buf+1) == 'C')
+            {
+                DEBUGF("Preload: conditional albumart tag found\n");
+                if (data->wps_uses_albumart == WPS_ALBUMART_NONE)
+                    data->wps_uses_albumart = WPS_ALBUMART_CHECK;
+            }
+
+            /* always return false; the tag has to be parsed again later... */
+            return false;
+        }
+        break;
+
 #endif
     }
     /* no of these tags found */
@@ -1084,6 +1505,20 @@
                 return buf;
             }
 #endif /* CONFIG_RTC */
+
+        case 'C':   /* Album cover */
+                    /* check existance of albumart bitmap */
+        {
+            *flags |= WPS_REFRESH_DYNAMIC;
+            if (tag[1] == 'n') /* next track */
+                id3 = nid3;
+
+            if (id3 && id3->albumart_found)
+                return "C";
+            else
+                return NULL;
+        } break;
+
 #if CONFIG_CODEC == SWCODEC
         case 'x':
             *flags |= WPS_REFRESH_DYNAMIC;
@@ -1339,6 +1774,16 @@
                 cur_align_start = buf;
                 ++fmt;
                 break;
+
+            case 'C': /* display album cover bitmap */
+                      /* (defined with %Cl earlier) */
+#ifdef HAVE_LCD_BITMAP
+                *flags |= WPS_REFRESH_DYNAMIC;
+                wps_data_albumart_display(gwps);
+#endif
+                fmt++;
+            break;
+
             case 's':
                 *flags |= WPS_REFRESH_SCROLL;
                 ++fmt;
@@ -2565,6 +3181,9 @@
         gwps->display->stop_scroll();
         gwps->state->id3 = audio_current_track();
 
+        /* track has changed : update the album art information */
+        wps_data_albumart_load(gwps);
+
         if (cuesheet_is_enabled() && gwps->state->id3->cuesheet_type
             && strcmp(gwps->state->id3->path, curr_cue->audio_filename))
         {
Index: apps/gui/gwps.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps.c,v
retrieving revision 1.54
diff -u -r1.54 gwps.c
--- apps/gui/gwps.c	13 Nov 2006 00:45:21 -0000	1.54
+++ apps/gui/gwps.c	14 Nov 2006 21:37:34 -0000
@@ -662,6 +662,10 @@
     data->wps_sb_tag = false;
     data->show_sb_on_wps = false;
     data->progressbar.have_bitmap_pb=false;
+
+    strcpy(data->cur_displayed_albumart_path, "\0");
+    data->cur_displayed_albumart_width = -1;
+    data->cur_displayed_albumart_height = -1;
 }
 #else
 #define wps_clear(a)
@@ -688,6 +692,7 @@
 static void wps_reset(struct wps_data *data)
 {
     data->wps_loaded = false;
+    data->wps_uses_albumart = WPS_ALBUMART_NONE;
     memset(&data->format_buffer, 0, sizeof data->format_buffer);
     wps_data_init(data);
 }
@@ -872,3 +877,20 @@
     unload_wps_backdrop();
 #endif
 }
+
+/*
+** returns true if at least one of the gui_wps screens
+**   has an albumart tag in its wps structure
+*/
+bool gui_sync_wps_uses_albumart(void)
+{
+    int  i;
+    FOR_NB_SCREENS(i) {
+        struct gui_wps *gwps = &gui_wps[i];
+        if (gwps->data && (gwps->data->wps_uses_albumart != WPS_ALBUMART_NONE))
+            return true;
+    }
+    return false;
+}
+
+/* vi: set ts=4 sts=4 sw=4 et ai: */
Index: apps/gui/gwps.h
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps.h,v
retrieving revision 1.39
diff -u -r1.39 gwps.h
--- apps/gui/gwps.h	10 Nov 2006 20:25:59 -0000	1.39
+++ apps/gui/gwps.h	14 Nov 2006 21:37:34 -0000
@@ -300,6 +299,19 @@
 #define WPS_ALIGN_CENTER 64
 #define WPS_ALIGN_LEFT 128
 
+/* albumart definitions */
+#define WPS_ALBUMART_NONE           0                   /* WPS does not contain AA tag */
+#define WPS_ALBUMART_CHECK          1                   /* WPS contains AA conditional tag */
+#define WPS_ALBUMART_LOAD           2                   /* WPS contains AA tag */
+
+#define WPS_ALBUMART_ALIGN_RIGHT    WPS_ALIGN_RIGHT     /* x align:   right */
+#define WPS_ALBUMART_ALIGN_CENTER   WPS_ALIGN_CENTER    /* x/y align: center */
+#define WPS_ALBUMART_ALIGN_LEFT     WPS_ALIGN_LEFT      /* x align:   left */
+#define WPS_ALBUMART_ALIGN_TOP      WPS_ALIGN_RIGHT     /* y align:   top */
+#define WPS_ALBUMART_ALIGN_BOTTOM   WPS_ALIGN_LEFT      /* y align:   bottom */
+#define WPS_ALBUMART_INCREASE       8                   /* increase if smaller */
+#define WPS_ALBUMART_DECREASE       16                  /* decrease if larger  */
+
 /* wps_data*/
 
 #ifdef HAVE_LCD_BITMAP
@@ -353,6 +365,26 @@
     int img_buf_free;
     bool wps_sb_tag;
     bool show_sb_on_wps;
+
+    /* albumart support */
+    unsigned short wps_uses_albumart; /* WPS_ALBUMART_NONE,
+                                         WPS_ALBUMART_CHECK, WPS_ALBUMART_LOAD */
+    int albumart_x;
+    int albumart_y;
+
+    unsigned short albumart_xalign;   /* WPS_ALBUMART_ALIGN_LEFT, ..._CENTER,
+                                         ..._RIGHT,
+                                         ..._INCREASE, ..._DECREASE */
+    unsigned short albumart_yalign;   /* WPS_ALBUMART_ALIGN_TOP,  ..._CENTER,
+                                         ..._BOTTOM,
+                                         ..._INCREASE, ..._DECREASE */
+
+    int albumart_max_width;
+    int albumart_max_height;
+
+    char cur_displayed_albumart_path[MAX_PATH]; /* Information about the */
+    int cur_displayed_albumart_width;           /* currently displayed   */
+    int cur_displayed_albumart_height;          /* album art bitmap      */
 #endif
 #ifdef HAVE_LCD_CHARCELLS
     unsigned char wps_progress_pat[8];
@@ -443,4 +475,7 @@
 void gui_sync_wps_init(void);
 void gui_sync_wps_screen_init(void);
 
+/* gives back if WPS contains an albumart tag */
+bool gui_sync_wps_uses_albumart(void);
+
 #endif
Index: firmware/export/id3.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/id3.h,v
retrieving revision 1.34
diff -u -r1.34 id3.h
--- firmware/export/id3.h	6 Nov 2006 19:49:03 -0000	1.34
+++ firmware/export/id3.h	14 Nov 2006 21:37:35 -0000
@@ -22,6 +22,8 @@
 #include <stdbool.h>
 #include "config.h"
 #include "file.h"
+#include "lcd.h"
+#include "system.h"
 
 /* Audio file types. */
 enum
@@ -215,6 +217,15 @@
 
     /* Cuesheet support */
     int cuesheet_type;      /* 0: none, 1: external, 2: embedded */
+
+#ifdef HAVE_LCD_BITMAP
+    /* album art support */
+    fb_data* albumart_data;
+    unsigned int albumart_width;
+    unsigned int albumart_height;
+    bool albumart_found;
+    char albumart_path[MAX_PATH];
+#endif
 };
 
 enum {
