skin rework (FS#10922) notable changes:
- simplify the setting/skin relationship. settings are used as the fallback if it's not specified in the skin
- backdrop buffers are now in the skin buffer (which has also increased slightly to accomodate 1 backdrop for each skin and 2 full colour screens for bmps (up for 1.5))
- if no %X is specified in a skin then the backdrop setting will be used. use %Xd to explicitly disable a skin from displaying a backdrop
- the base skin can now specify a backdrop.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24366 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 78bbb77..8557083 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -40,7 +40,6 @@
 #include "yesno.h"
 #include "list.h"
 #include "plugin.h"
-#include "backdrop.h"
 #include "file.h"
 #include "filefuncs.h"
 
@@ -165,7 +164,6 @@
     char*  bookmark;
     if (!system_check())
         return false;
-    int i;
 
     audio_pause();    /* first pause playback */
     bookmark = create_bookmark();
@@ -193,12 +191,6 @@
                             str(LANG_CONFIRM_WITH_BUTTON)};
     const struct text_message message={lines, 2};
 #endif
-    FOR_NB_SCREENS(i)
-    {
-#if LCD_DEPTH > 1
-        screens[i].backdrop_show(BACKDROP_MAIN);
-#endif
-    }
 
     if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
     {
diff --git a/apps/filetree.c b/apps/filetree.c
index ccf4c2b..6062080 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -52,7 +52,6 @@
 #include "radio.h"
 #endif
 #include "wps.h"
-#include "backdrop.h"
 
 static int compare_sort_dir; /* qsort key for sorting directories */
 
@@ -503,9 +502,6 @@
                 /* wps config file */
             case FILE_ATTR_WPS:
                 splash(0, ID2P(LANG_WAIT));
-#if LCD_DEPTH > 1
-                backdrop_unload(BACKDROP_SKIN_WPS);
-#endif
                 set_file(buf, (char *)global_settings.wps_file,
                          MAX_FILENAME);
                 settings_apply_skins();
@@ -515,9 +511,6 @@
                 /* remote-wps config file */
             case FILE_ATTR_RWPS:
                 splash(0, ID2P(LANG_WAIT));
-#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
-                remote_backdrop_unload(BACKDROP_SKIN_WPS);
-#endif
                 set_file(buf, (char *)global_settings.rwps_file,
                          MAX_FILENAME);
                 settings_apply_skins();
diff --git a/apps/gui/backdrop.c b/apps/gui/backdrop.c
index 058eaa5..e460b87 100644
--- a/apps/gui/backdrop.c
+++ b/apps/gui/backdrop.c
@@ -27,213 +27,53 @@
 #endif
 #include "backdrop.h"
 
-static fb_data main_backdrop[LCD_FBHEIGHT][LCD_FBWIDTH]
-                __attribute__ ((aligned (16)));
-static fb_data skin_backdrop[LCD_FBHEIGHT][LCD_FBWIDTH]
-                __attribute__ ((aligned (16)));
-
-#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
-static fb_remote_data
-remote_skin_backdrop[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH];
-static bool remote_skin_backdrop_valid = false;
-#endif
-
-static bool main_backdrop_valid = false;
-static bool skin_backdrop_valid = false;
-
-/* load a backdrop into a buffer */
-static bool load_backdrop(const char* filename, fb_data* backdrop_buffer)
+bool backdrop_load(const char* filename, char *backdrop_buffer)
 {
     struct bitmap bm;
     int ret;
 
     /* load the image */
-    bm.data=(char*)backdrop_buffer;
-    ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
+    bm.data = backdrop_buffer;
+    ret = read_bmp_file(filename, &bm, LCD_BACKDROP_BYTES,
                         FORMAT_NATIVE | FORMAT_DITHER, NULL);
 
     return ((ret > 0)
             && (bm.width == LCD_WIDTH) && (bm.height == LCD_HEIGHT));
 }
-
-static bool load_main_backdrop(const char* filename)
+  
+  
+void backdrop_show(char *backdrop_buffer)
 {
-    main_backdrop_valid = load_backdrop(filename, &main_backdrop[0][0]);
-    return main_backdrop_valid;
+    lcd_set_backdrop((fb_data*)backdrop_buffer);
 }
+  
 
-static inline bool load_skin_backdrop(const char* filename)
-{
-    skin_backdrop_valid = load_backdrop(filename, &skin_backdrop[0][0]);
-    return skin_backdrop_valid;
-}
+#if defined(HAVE_REMOTE_LCD)
 
-static inline void unload_main_backdrop(void)
-{
-    main_backdrop_valid = false;
-}
-
-static inline void unload_skin_backdrop(void)
-{
-    skin_backdrop_valid = false;
-}
-
-static inline void show_main_backdrop(void)
-{
-    lcd_set_backdrop(main_backdrop_valid ? &main_backdrop[0][0] : NULL);
-}
-
-static void show_skin_backdrop(void)
-{
-    /* if no wps backdrop, fall back to main backdrop */
-    if(skin_backdrop_valid)
-    {
-        lcd_set_backdrop(&skin_backdrop[0][0]);
-    }
-    else
-    {
-        show_main_backdrop();
-    }
-}
-
+#if LCD_REMOTE_DEPTH > 1
 /* api functions */
-
-bool backdrop_load(enum backdrop_type bdrop, const char* filename)
-{
-    if (bdrop == BACKDROP_MAIN)
-        return load_main_backdrop(filename);
-    else if (bdrop == BACKDROP_SKIN_WPS)
-        return load_skin_backdrop(filename);
-    else
-        return false;
-}
-
-void backdrop_unload(enum backdrop_type bdrop)
-{
-    if (bdrop == BACKDROP_MAIN)
-        unload_main_backdrop();
-    else if (bdrop == BACKDROP_SKIN_WPS)
-        unload_skin_backdrop();
-}
-
-void backdrop_show(enum backdrop_type bdrop)
-{
-    if (bdrop == BACKDROP_MAIN)
-        show_main_backdrop();
-    else if (bdrop == BACKDROP_SKIN_WPS)
-        show_skin_backdrop();
-}
-
-void backdrop_hide(void)
-{
-    lcd_set_backdrop(NULL);
-}
-
-    
-
-#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
-
-static bool load_remote_backdrop(const char* filename,
-            fb_remote_data* backdrop_buffer)
+bool remote_backdrop_load(const char *filename, char* backdrop_buffer)
 {
     struct bitmap bm;
     int ret;
 
     /* load the image */
-    bm.data=(char*)backdrop_buffer;
-    ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
+    bm.data = backdrop_buffer;
+    ret = read_bmp_file(filename, &bm, REMOTE_LCD_BACKDROP_BYTES,
                         FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE, NULL);
-
     return ((ret > 0)
-            && (bm.width == LCD_REMOTE_WIDTH)
-            && (bm.height == LCD_REMOTE_HEIGHT));
+            && (bm.width == REMOTE_LCD_WIDTH) && (bm.height == REMOTE_LCD_HEIGHT));
 }
+#else /* needs stubs */
 
-static inline bool load_remote_skin_backdrop(const char* filename)
+bool remote_backdrop_load(const char *filename, char* backdrop_buffer)
 {
-    remote_skin_backdrop_valid =
-            load_remote_backdrop(filename, &remote_skin_backdrop[0][0]);
-    return remote_skin_backdrop_valid;
+    (void)filename; (void) backdrop_buffer;
+    return false;
 }
-
-static inline void unload_remote_skin_backdrop(void)
+void remote_backdrop_show(char* backdrop_buffer)
 {
-    remote_skin_backdrop_valid = false;
-}
-
-static inline void show_remote_main_backdrop(void)
-{
-    lcd_remote_set_backdrop(NULL);
-}
-
-static inline void show_remote_skin_backdrop(void)
-{
-    /* if no wps backdrop, fall back to main backdrop */
-    if(remote_skin_backdrop_valid)
-    {
-        lcd_remote_set_backdrop(&remote_skin_backdrop[0][0]);
-    }
-    else
-    {
-        show_remote_main_backdrop();
-    }
-}
-
-
-/* api functions */
-bool remote_backdrop_load(enum backdrop_type bdrop,
-                                const char *filename)
-{
-    if (bdrop == BACKDROP_SKIN_WPS)
-        return load_remote_skin_backdrop(filename);
-    else if (bdrop == BACKDROP_MAIN)
-        return true;
-    else
-        return false;
-}
-
-void remote_backdrop_show(enum backdrop_type bdrop)
-{
-    if (bdrop == BACKDROP_MAIN)
-        show_remote_main_backdrop();
-    else if (bdrop == BACKDROP_SKIN_WPS)
-        show_remote_skin_backdrop();
-}
-
-void remote_backdrop_unload(enum backdrop_type bdrop)
-{
-    if (bdrop != BACKDROP_MAIN)
-        unload_remote_skin_backdrop();
-}
-
-
-void remote_backdrop_hide(void)
-{
-        lcd_remote_set_backdrop(NULL);
-}
-#else
-/* api functions */
-bool remote_backdrop_load(enum backdrop_type bdrop,
-                                const char *filename)
-{
-    (void)bdrop; (void)filename;
-    return true;
-}
-
-void remote_backdrop_show(enum backdrop_type bdrop)
-{
-    (void)bdrop;
-}
-
-void remote_backdrop_unload(enum backdrop_type bdrop)
-{
-    (void)bdrop;
-}
-
-
-void remote_backdrop_hide(void)
-{
+    (void)backdrop_buffer;
 }
 #endif
-
-    
+#endif
diff --git a/apps/gui/backdrop.h b/apps/gui/backdrop.h
index 3b873fd..735a884 100644
--- a/apps/gui/backdrop.h
+++ b/apps/gui/backdrop.h
@@ -22,29 +22,29 @@
 #ifndef _BACKDROP_H
 #define _BACKDROP_H
 
-enum backdrop_type {
-    BACKDROP_MAIN,
-    BACKDROP_SKIN_WPS,
-};
-
 #if LCD_DEPTH > 1 && !defined(__PCTOOL__)
 
 #include "lcd.h"
 #include "bmp.h"
 
-bool backdrop_load(enum backdrop_type bdrop, const char*);
-void backdrop_unload(enum backdrop_type bdrop);
-void backdrop_show(enum backdrop_type bdrop);
-void backdrop_hide(void);
+#define LCD_BACKDROP_BYTES (LCD_FBHEIGHT*LCD_FBWIDTH*sizeof(fb_data))
+#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+#define REMOTE_LCD_BACKDROP_BYTES \
+            (LCD_REMOTE_FBHEIGHT*LCD_REMOTE_FBWIDTH*sizeof(fb_remote_data))
+#else
+#define REMOTE_LCD_BACKDROP_BYTES 0
+#endif
 
+bool backdrop_load(const char *filename, char* backdrop_buffer);
+void backdrop_show(char* backdrop_buffer);
+
+#else
+#define LCD_BACKDROP_BYTES 0
 #endif
 
 #if defined(HAVE_REMOTE_LCD)
-/* no main backdrop, stubs! */
-bool remote_backdrop_load(enum backdrop_type bdrop,const char* filename);
-void remote_backdrop_unload(enum backdrop_type bdrop);
-void remote_backdrop_show(enum backdrop_type bdrop);
-void remote_backdrop_hide(void);
+bool remote_backdrop_load(const char *filename, char* backdrop_buffer);
+void remote_backdrop_show(char* backdrop_buffer);
 #endif
 
 #endif /* _BACKDROP_H */
diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c
index e647fc3..a15ad10 100644
--- a/apps/gui/skin_engine/skin_buffer.c
+++ b/apps/gui/skin_engine/skin_buffer.c
@@ -27,6 +27,7 @@
 #include "buffer.h"
 #include "settings.h"
 #include "screen_access.h"
+#include "skin_engine.h"
 #include "wps_internals.h"
 #include "skin_tokens.h"
 #include "skin_buffer.h"
@@ -46,7 +47,7 @@
  * items with unknown sizes get allocated from the start (0->)      (data)
  * items with known sizes get allocated from the end (<-buf_size)   (tokens)
  * After loading 2 skins the buffer will look like this:
- *  |tokens skin1|images skin2|---SPACE---|data skin2|data skin1|
+ *  |tokens skin1|images skin1|tokens s2|images s2|---SPACE---|data skin2|data skin1|
  * Make sure to never start allocating from the beginning before letting us know
  * how much was used. and RESPECT THE buf_free RETURN VALUES!
  *
@@ -54,12 +55,12 @@
 
 
 #ifdef HAVE_LCD_BITMAP
-#define MAIN_BUFFER ((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
-                            + (2*LCD_HEIGHT*LCD_WIDTH/8))
+#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
+                    + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
 
 #if (NB_SCREENS > 1)
-#define REMOTE_BUFFER ((LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
-                            + (2*LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH/8))
+#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
+                      + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
 #else
 #define REMOTE_BUFFER 0
 #endif
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index e90ac4c..1a05629 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -1011,6 +1011,10 @@
     {
         struct skin_line *line;
         struct skin_viewport *skin_viewport = find_viewport(VP_DEFAULT_LABEL, data);
+        
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
+        display->backdrop_show(data->backdrop);
+#endif
 
         if (!(skin_viewport->hidden_flags & VP_NEVER_VISIBLE))
         {
diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h
index 5216e93..c5afe3e 100644
--- a/apps/gui/skin_engine/skin_engine.h
+++ b/apps/gui/skin_engine/skin_engine.h
@@ -27,6 +27,15 @@
 
 #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
 
+enum skinnable_screens {
+    CUSTOM_STATUSBAR,
+    WPS,
+    
+    
+    SKINNABLE_SCREENS_COUNT
+};
+
+
 #ifdef HAVE_TOUCHSCREEN
 int wps_get_touchaction(struct wps_data *data);
 #endif
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index c70a975..4655bf0 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -62,6 +62,7 @@
 #endif
 
 #include "backdrop.h"
+#include "statusbar-skinned.h"
 
 #define WPS_ERROR_INVALID_PARAM         -1
 
@@ -92,22 +93,6 @@
 
 static int follow_lang_direction = 0;
 
-#ifdef HAVE_LCD_BITMAP
-
-#if LCD_DEPTH > 1
-#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */
-#else
-#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */
-#endif
-
-#define PROGRESSBAR_BMP MAX_IMAGES
-#define BACKDROP_BMP    (MAX_BITMAPS-1)
-
-/* pointers to the bitmap filenames in the WPS source */
-static const char *bmp_names[MAX_BITMAPS];
-
-#endif /* HAVE_LCD_BITMAP */
-
 #if defined(DEBUG) || defined(SIMULATOR)
 /* debugging function */
 extern void print_debug_info(struct wps_data *data, int fail, int line);
@@ -925,20 +910,29 @@
     (void)token;
     const char *pos = NULL;
     const char *newline;
+    bool error = false;
 
     pos = strchr(wps_bufptr + 1, '|');
     newline = strchr(wps_bufptr, '\n');
+    
+    error = (pos > newline);
+        
 
-    if (pos > newline)
-        return WPS_ERROR_INVALID_PARAM;
 #if LCD_DEPTH > 1
     if (token->type == WPS_TOKEN_IMAGE_BACKDROP)
     {
-        /* format: %X|filename.bmp| */
-        bmp_names[BACKDROP_BMP] = wps_bufptr + 1;
+        /* format: %X|filename.bmp| or %Xd */
+        if (*(wps_bufptr) == 'd')
+        {
+            wps_data->backdrop = NULL;
+            return skip_end_of_line(wps_bufptr);
+        }
+        else if (!error)
+            wps_data->backdrop = (char*)wps_bufptr + 1;
     }
 #endif
-
+    if (error)
+        return WPS_ERROR_INVALID_PARAM;
     /* Skip the rest of the line */
     return skip_end_of_line(wps_bufptr);
 }
@@ -1657,6 +1651,14 @@
         return false;
     skin_buffer_increment(max_tokens * sizeof(struct wps_token), false);
     data->num_tokens = 0;
+    
+#if LCD_DEPTH > 1
+    /* Backdrop defaults to the setting unless %X is used, so set it now */
+    if (global_settings.backdrop_file[0])
+    {
+        data->backdrop = "-";
+    }
+#endif
 
     while (*wps_bufptr && !fail)
     {
@@ -1899,6 +1901,9 @@
     wps_data->images = NULL;
     wps_data->progressbars = NULL;
 #endif
+#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+    wps_data->backdrop = NULL;
+#endif
 #ifdef HAVE_TOUCHSCREEN
     wps_data->touchregions = NULL;
 #endif
@@ -1996,12 +2001,51 @@
     }
 
 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
-    if (bmp_names[BACKDROP_BMP])
+    /* Backdrop load scheme:
+     * 1) %X|filename|
+     * 2) load the backdrop from settings
+     */
+    if (wps_data->backdrop)
     {
         char img_path[MAX_PATH];
-        get_image_filename(bmp_names[BACKDROP_BMP], bmpdir,
-                            img_path, sizeof(img_path));
-        screens[curr_screen].backdrop_load(BACKDROP_SKIN_WPS, img_path);
+        bool loaded = false;
+        size_t buf_size;
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+        if (curr_screen == SCREEN_REMOTE)
+            buf_size = REMOTE_LCD_BACKDROP_BYTES;
+        else
+#endif
+            buf_size = LCD_BACKDROP_BYTES;
+        if (wps_data->backdrop[0] == '-')
+        {
+#if NB_SCREENS > 1
+            if (curr_screen == SCREEN_REMOTE)
+            {
+                wps_data->backdrop = NULL;
+                return true;
+            }
+            else
+#endif
+            {
+                if (!global_settings.backdrop_file[0])
+                {
+                    wps_data->backdrop = NULL;
+                    return true;
+                }
+                snprintf(img_path, sizeof(img_path), "%s/%s.bmp",
+                         BACKDROP_DIR, global_settings.backdrop_file);
+            }
+        }
+        else
+        {
+            get_image_filename(wps_data->backdrop, bmpdir,
+                              img_path, sizeof(img_path));
+        }
+        char *buffer = skin_buffer_alloc(buf_size);
+        if (!buffer)
+            return false;
+        loaded = screens[curr_screen].backdrop_load(img_path, buffer);
+        wps_data->backdrop = loaded ? buffer : NULL;
     }
 #endif /* has backdrop support */
 
@@ -2059,7 +2103,18 @@
 
     if (!isfile)
     {
-        return wps_parse(wps_data, buf, false);
+        if (wps_parse(wps_data, buf, false))
+        {
+#ifdef HAVE_LCD_BITMAP
+            /* load the backdrop */
+            if (!load_skin_bitmaps(wps_data, BACKDROP_DIR)) {
+                skin_data_reset(wps_data);
+                return false;
+            }
+#endif
+            return true;
+        }
+        return false;
     }
     else
     {
@@ -2093,11 +2148,6 @@
         if (start <= 0)
             return false;
 
-#ifdef HAVE_LCD_BITMAP
-        /* Set all filename pointers to NULL */
-        memset(bmp_names, 0, sizeof(bmp_names));
-#endif
-
         /* parse the WPS source */
         if (!wps_parse(wps_data, wps_buffer, true)) {
             skin_data_reset(wps_data);
@@ -2116,6 +2166,7 @@
         /* load the bitmaps that were found by the parsing */
         if (!load_skin_bitmaps(wps_data, bmpdir)) {
             skin_data_reset(wps_data);
+            wps_data->wps_loaded = false;
             return false;
         }
 #endif
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index 837e56e..e659f08 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -271,6 +271,9 @@
     struct skin_token_list *images;
     struct skin_token_list *progressbars;
 #endif
+#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+    char *backdrop;
+#endif
 
 #ifdef HAVE_TOUCHSCREEN
     struct skin_token_list *touchregions;
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index d4a4c0e..2631b4c 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -41,8 +41,6 @@
 static struct wps_sync_data sb_skin_sync_data        = { .do_full_update = false };
 
 /* initial setup of wps_data  */
-
-static bool loaded_ok[NB_SCREENS] = { false };
 static int update_delay = DEFAULT_UPDATE_DELAY;
 
 
@@ -68,66 +66,62 @@
         vp->hidden_flags = VP_NEVER_VISIBLE;
     }
 
-    loaded_ok[screen] = success;
+    if (!success && isfile)
+        sb_create_from_settings(screen);
 }
 
-/* temporary viewport structs while the non-skinned bar is in the build */
-static struct viewport inbuilt[NB_SCREENS];
 struct viewport *sb_skin_get_info_vp(enum screen_type screen)
 {
-    int bar_setting = statusbar_position(screen);
-    if (bar_setting == STATUSBAR_CUSTOM)
-        return &find_viewport(VP_INFO_LABEL, sb_skin[screen].data)->vp;
-    else if (bar_setting == STATUSBAR_OFF)
-        return NULL;
-    else
-    {
-        viewport_set_fullscreen(&inbuilt[screen], screen);
-        /* WE need to return the UI area.. NOT the statusbar area! */
-        if (bar_setting == STATUSBAR_TOP)
-            inbuilt[screen].y = STATUSBAR_HEIGHT;
-        inbuilt[screen].height -= STATUSBAR_HEIGHT;
-        return &inbuilt[screen];
-    }
+    return &find_viewport(VP_INFO_LABEL, sb_skin[screen].data)->vp;
 }
 
-inline bool sb_skin_get_state(enum screen_type screen)
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
+char* sb_get_backdrop(enum screen_type screen)
 {
-    /* Temp fix untill the hardcoded bar is removed */
-    int bar_setting = global_settings.statusbar;
-#if NB_SCREENS > 1
-    if (screen == SCREEN_REMOTE)
-        bar_setting = global_settings.remote_statusbar;
-#endif
-    switch (bar_setting)
-    {
-        case STATUSBAR_CUSTOM:
-            return loaded_ok[screen];
-        case STATUSBAR_TOP:
-        case STATUSBAR_BOTTOM:
-           return true;
-        case STATUSBAR_OFF:
-            return false;
-    }
-    return false; /* Should never actually get here */
+    return sb_skin[screen].data->backdrop;
 }
 
+bool sb_set_backdrop(enum screen_type screen, char* filename)
+{
+    if (!filename)
+    {
+        sb_skin[screen].data->backdrop = NULL;
+        return true;
+    }
+    else if (!sb_skin[screen].data->backdrop)
+    {
+        /* need to make room on the buffer */
+        size_t buf_size;
+#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+        if (curr_screen == SCREEN_REMOTE)
+            buf_size = REMOTE_LCD_BACKDROP_BYTES;
+        else
+#endif
+            buf_size = LCD_BACKDROP_BYTES;
+        sb_skin[screen].data->backdrop = skin_buffer_alloc(buf_size);
+        if (!sb_skin[screen].data->backdrop)
+            return false;          
+    }
+  
+    if (!screens[screen].backdrop_load(filename, sb_skin[screen].data->backdrop))
+        sb_skin[screen].data->backdrop = NULL;
+    return sb_skin[screen].data->backdrop != NULL;
+}
+        
+#endif
 void sb_skin_update(enum screen_type screen, bool force)
 {
     static long next_update = 0;
     int i = screen;
     if (TIME_AFTER(current_tick, next_update) || force)
     {
-        if (sb_skin_get_state(i))
-        {
 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
-            /* currently, all remotes are readable without backlight
-             * so still update those */
-            if (lcd_active() || (i != SCREEN_MAIN))
+        /* currently, all remotes are readable without backlight
+         * so still update those */
+        if (lcd_active() || (i != SCREEN_MAIN))
 #endif
-                skin_update(&sb_skin[i], force?
-                        WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC);
-        }
+            skin_update(&sb_skin[i], force?
+                    WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC);
         next_update = current_tick + update_delay; /* don't update too often */
         sb_skin[SCREEN_MAIN].sync_data->do_full_update = false;
     }
@@ -148,6 +142,50 @@
     update_delay = delay;
 }
 
+/* This creates and loads a ".sbs" based on the user settings for:
+ *  - regular statusbar
+ *  - colours
+ *  - ui viewport
+ *  - backdrop
+ */
+void sb_create_from_settings(enum screen_type screen)
+{
+    char buf[128], *ptr, *ptr2;
+    int len, remaining = sizeof(buf);
+    
+    ptr = buf;
+    ptr[0] = '\0';
+    
+    /* %Vi viewport, colours handled by the parser */
+#if NB_SCREENS > 1
+    if (screen == SCREEN_REMOTE)
+        ptr2 = global_settings.remote_ui_vp_config;
+#endif
+    ptr2 = global_settings.ui_vp_config;
+    
+    if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */
+    {
+        len = snprintf(ptr, remaining, "%%Vi|%s\n", ptr2);
+        while ((ptr2 = strchr(ptr, ',')))
+            *ptr2 = '|';
+    }
+    else
+    {
+        int y = 0, height;
+        switch (statusbar_position(screen))
+        {
+            case STATUSBAR_TOP:
+                y = STATUSBAR_HEIGHT;
+            case STATUSBAR_BOTTOM:
+                height = screens[screen].lcdheight - STATUSBAR_HEIGHT;
+                break;
+            default:
+                height = screens[screen].lcdheight;
+        }
+        len = snprintf(ptr, remaining, "%%Vi|0|%d|-|%d|1|-|-|\n", y, height);
+    }
+    sb_skin_data_load(screen, buf, false);
+}
 
 void sb_skin_init(void)
 {
diff --git a/apps/gui/statusbar-skinned.h b/apps/gui/statusbar-skinned.h
index 6016c29..bbd4a65 100644
--- a/apps/gui/statusbar-skinned.h
+++ b/apps/gui/statusbar-skinned.h
@@ -33,20 +33,24 @@
 
 void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile);
 
-/* probably temporary, to shut the classic statusbar up */
-bool sb_skin_get_state(enum screen_type screen);
+void sb_create_from_settings(enum screen_type screen);
 void sb_skin_init(void);
 struct viewport *sb_skin_get_info_vp(enum screen_type screen);
 void sb_skin_update(enum screen_type screen, bool force);
 
 void sb_skin_set_update_delay(int delay);
 
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
+char* sb_get_backdrop(enum screen_type screen);
+bool sb_set_backdrop(enum screen_type screen, char* filename);
+#endif
+
 #else /* CHARCELL */
 #define sb_skin_init()
 #define sb_skin_data_load(a,b,c)
 #define sb_skin_set_update_delay(a)
 #define sb_skin_set_state(a,b)
-#define sb_skin_get_state(a)
+#define sb_create_from_settings(a)
 #endif
 void do_sbs_update_callback(void *param);
 #endif /* __STATUSBAR_SKINNED_H__ */
diff --git a/apps/gui/usb_screen.c b/apps/gui/usb_screen.c
index ac31708..f74747f 100644
--- a/apps/gui/usb_screen.c
+++ b/apps/gui/usb_screen.c
@@ -129,10 +129,10 @@
 };
 
 #ifdef HAVE_LCD_BITMAP
-static bool usb_screen_fix_viewports(struct screen *screen,
+static void usb_screen_fix_viewports(struct screen *screen,
         struct usb_screen_vps_t *usb_screen_vps)
 {
-    bool theme_needs_undo = false;
+    bool disable = true;
     int logo_width, logo_height;
     struct viewport *parent = &usb_screen_vps->parent;
     struct viewport *logo = &usb_screen_vps->logo;
@@ -151,11 +151,8 @@
     }
 
     viewport_set_defaults(parent, screen->screen_type);
-    if (parent->width < logo_width || parent->height < logo_height)
-    {
-        theme_needs_undo = true;
-        viewportmanager_theme_enable(screen->screen_type, false, parent);
-    }
+    disable = (parent->width < logo_width || parent->height < logo_height);
+    viewportmanager_theme_enable(screen->screen_type, !disable, parent);
 
     *logo = *parent;
     logo->x = parent->x + parent->width - logo_width;
@@ -179,18 +176,12 @@
         }
     }
 #endif
-    return theme_needs_undo;
 }
 #endif
 
 static void usb_screens_draw(struct usb_screen_vps_t *usb_screen_vps_ar)
 {
     int i;
-    lcd_clear_display();
-#ifdef HAVE_LCD_REMOTE
-    lcd_remote_clear_display();
-#endif
-
     FOR_NB_SCREENS(i)
     {
         struct screen *screen = &screens[i];
@@ -202,11 +193,8 @@
 #endif
 
         screen->set_viewport(parent);
-#if LCD_DEPTH > 1
-        screen->backdrop_show(BACKDROP_MAIN);
-#endif
-        screen->backlight_on();
         screen->clear_viewport();
+        screen->backlight_on();
 
 #ifdef HAVE_LCD_BITMAP
         screen->set_viewport(logo);
@@ -240,15 +228,14 @@
         status_set_usb(true);
 #endif /* HAVE_LCD_BITMAP */
 
-        screen->update_viewport();
         screen->set_viewport(NULL);
+        screen->update_viewport();
     }
 }
 
 void gui_usb_screen_run(void)
 {
     int i;
-    bool screen_theme_needs_undo[NB_SCREENS];
     struct usb_screen_vps_t usb_screen_vps_ar[NB_SCREENS];
 #if defined HAVE_TOUCHSCREEN
     enum touchscreen_mode old_mode = touchscreen_get_mode();
@@ -273,7 +260,7 @@
 
         screen->set_viewport(NULL);
 #ifdef HAVE_LCD_BITMAP
-        screen_theme_needs_undo[i] = usb_screen_fix_viewports(screen, &usb_screen_vps_ar[i]);
+        usb_screen_fix_viewports(screen, &usb_screen_vps_ar[i]);
 #endif
     }
 
@@ -320,10 +307,7 @@
     FOR_NB_SCREENS(i)
     {
         screens[i].backlight_on();
-        if(screen_theme_needs_undo[i])
-        {
-            viewportmanager_theme_undo(i, false);
-        }
+        viewportmanager_theme_undo(i, false);
     }
 
 }
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c
index fd38b18..78b6379 100644
--- a/apps/gui/viewport.c
+++ b/apps/gui/viewport.c
@@ -109,11 +109,11 @@
 
     if (is_theme_enabled(screen))
     {
-#if LCD_DEPTH > 1 || (defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1)
-        screens[screen].backdrop_show(BACKDROP_MAIN);
-#endif
         /* remove the left overs from the previous screen.
          * could cause a tiny flicker. Redo your screen code if that happens */
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
+        screens[screen].backdrop_show(sb_get_backdrop(screen));
+#endif
         if (!was_enabled[screen] || force)
         {
             struct viewport deadspace, user;
@@ -165,7 +165,7 @@
     else
     {
 #if LCD_DEPTH > 1 || (defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1)
-        screens[screen].backdrop_hide();
+        screens[screen].backdrop_show(NULL);
 #endif
         screens[screen].stop_scroll();
     }
@@ -204,11 +204,6 @@
     int top = theme_stack_top[screen];
     return theme_stack[screen][top].enabled;
 }
-
-static bool custom_vp_loaded_ok[NB_SCREENS];
-static struct viewport custom_vp[NB_SCREENS];
-
-static unsigned viewport_init_ui_vp(void);
 #endif /* HAVE_LCD_BITMAP */
 
 int viewport_get_nb_lines(const struct viewport *vp)
@@ -263,7 +258,6 @@
 #endif
     if (which & THEME_UI_VIEWPORT)
     {
-        viewport_init_ui_vp();
     }
     if (which & THEME_LANGUAGE)
     {   
@@ -281,34 +275,6 @@
     send_event(GUI_EVENT_THEME_CHANGED, NULL);
 }
 
-/*
- * (re)parse the UI vp from the settings
- *  - Returns
- *          0 if no UI vp is used at all
- *          else the bit for the screen (1<<screen) is set
- */
-static unsigned viewport_init_ui_vp(void)
-{
-    int screen;
-    const char *ret = NULL;
-    char *setting;
-    FOR_NB_SCREENS(screen)
-    {
-#ifdef HAVE_REMOTE_LCD
-        if ((screen == SCREEN_REMOTE))
-            setting = global_settings.remote_ui_vp_config;
-        else
-#endif
-            setting = global_settings.ui_vp_config;
-            
-        ret = viewport_parse_viewport(&custom_vp[screen], screen,
-                                     setting, ',');
-
-        custom_vp_loaded_ok[screen] = (ret != NULL);
-    }
-    return true; /* meh fixme */
-}
-
 #ifdef HAVE_TOUCHSCREEN
 /* check if a point (x and y coordinates) are within a viewport */
 bool viewport_point_within_vp(const struct viewport *vp,
@@ -380,59 +346,18 @@
 void viewport_set_defaults(struct viewport *vp,
                             const enum screen_type screen)
 {
-    /* Reposition:
-       1) If the "ui viewport" setting is set, and a sbs is loaded which specifies a %Vi
-            return the intersection of those two viewports
-       2) If only one of the "ui viewport" setting, or sbs %Vi is set
-            return it
-       3) No user viewports set
-            return the full display
-     */
 #if defined(HAVE_LCD_BITMAP) && !defined(__PCTOOL__)
     
-    struct viewport *sbs_area = NULL, *user_setting = NULL;
+    struct viewport *sbs_area = NULL;
     if (!is_theme_enabled(screen))
-   {
+    {
        viewport_set_fullscreen(vp, screen);
        return;
-   }
-    /* get the two viewports */
-    if (custom_vp_loaded_ok[screen])
-        user_setting = &custom_vp[screen];
-    if (sb_skin_get_state(screen))    
-        sbs_area = sb_skin_get_info_vp(screen);
-        
-    /* have both? get their intersection */
-    if (sbs_area && user_setting)
-    {
-        struct viewport *a = sbs_area, *b = user_setting;
-        /* if ui vp and info vp overlap, intersect */
-        if (a->x             < b->x + b->width   &&
-            a->x + a->width  > b->x              &&
-            a->y             < b->y + b->height  &&
-            a->y + a->height > b->y)
-        {
-            /* copy from ui vp first (for other field),fix coordinates after */
-            *vp = *user_setting;
-            set_default_align_flags(vp);
-            vp->x = MAX(a->x, b->x);
-            vp->y = MAX(a->y, b->y);
-            vp->width = MIN(a->x + a->width, b->x + b->width) - vp->x;
-            vp->height = MIN(a->y + a->height, b->y + b->height) - vp->y;
-            return;
-        }
-        /* else (no overlap at all) fall back to info vp from sbs, that
-         * has no redraw problems */
     }
-
-    /* if only one is active use it
-     * or if the above check for overlapping failed, use info vp then, because
-     * that doesn't give redraw problems */
+    sbs_area = sb_skin_get_info_vp(screen);
+    
     if (sbs_area)
         *vp = *sbs_area;
-    else if (user_setting)
-        *vp = *user_setting;
-    /* have neither so its fullscreen which was fixed at the beginning */   
     else  
 #endif /* HAVE_LCD_BITMAP */
         viewport_set_fullscreen(vp, screen);  
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 3c09822..ca74c45 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -99,10 +99,6 @@
 {
     bool loaded_ok;
 
-#if LCD_DEPTH > 1
-    screens[screen].backdrop_unload(BACKDROP_SKIN_WPS);
-#endif
-
 #ifndef __PCTOOL__
     /*
      * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
@@ -129,6 +125,9 @@
     {
         char *skin_buf[NB_SCREENS] = {
 #ifdef HAVE_LCD_BITMAP
+#if LCD_DEPTH > 1
+            "%Xd\n"
+#endif
             "%s%?it<%?in<%in. |>%it|%fn>\n"
             "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
             "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n\n"
@@ -140,6 +139,9 @@
             "%pc%?ps<*|/>%pt\n",
 #endif
 #ifdef HAVE_REMOTE_LCD
+#if LCD_REMOTE_DEPTH > 1
+            "%Xd\n"
+#endif
             "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
             "%s%?it<%?in<%in. |>%it|%fn>\n"
             "%al%pc/%pt%ar[%pp:%pe]\n"
@@ -563,9 +565,6 @@
     FOR_NB_SCREENS(i)
     {
         gui_wps[i].display->stop_scroll();
-#if LCD_DEPTH > 1
-        gui_wps[i].display->backdrop_show(BACKDROP_MAIN);
-#endif
         
 #ifdef HAVE_LCD_BITMAP
         bool draw = false;
@@ -614,7 +613,6 @@
             vp->fg_pattern = display->get_foreground();
             vp->bg_pattern = display->get_background();
         }
-        display->backdrop_show(BACKDROP_SKIN_WPS);
 #endif
         /* make the backdrop actually take effect */
         display->clear_display();
@@ -1298,9 +1296,6 @@
         /* Currently no seperate wps_state needed/possible
            so use the only available ( "global" ) one */
         gui_wps[i].state = &wps_state;
-#if LCD_DEPTH > 1
-        gui_wps[i].display->backdrop_unload(BACKDROP_SKIN_WPS);
-#endif
         /* must point to the same struct for both screens */
         gui_wps[i].sync_data = &wps_sync_data;
     }
diff --git a/apps/menus/theme_menu.c b/apps/menus/theme_menu.c
index accf9e1..7c19335 100644
--- a/apps/menus/theme_menu.c
+++ b/apps/menus/theme_menu.c
@@ -39,6 +39,7 @@
 #include "exported_menus.h"
 #include "appevents.h"
 #include "viewport.h"
+#include "statusbar-skinned.h"
 
 #if LCD_DEPTH > 1
 /**
@@ -47,11 +48,9 @@
 static int clear_main_backdrop(void)
 {
     global_settings.backdrop_file[0]=0;
-    backdrop_unload(BACKDROP_MAIN);
-    backdrop_show(BACKDROP_MAIN);
-    /* force a full redraw so the whole backdrop is cleared */
+    sb_set_backdrop(SCREEN_MAIN, NULL);
     viewportmanager_theme_enable(SCREEN_MAIN, false, NULL);
-    viewportmanager_theme_undo(SCREEN_MAIN, false);
+    viewportmanager_theme_undo(SCREEN_MAIN, true);
     settings_save();
     return 0;
 }
@@ -162,10 +161,7 @@
             old_bar[screen] = statusbar_position(screen);
             break;
         case ACTION_EXIT_MENUITEM:
-            send_event(GUI_EVENT_STATUSBAR_TOGGLE, NULL);
-            /* force a full redraw */
-            viewportmanager_theme_enable(screen, false, NULL);
-            viewportmanager_theme_undo(screen, false);
+            settings_apply_skins();
             break;
     }
     return ACTION_REDRAW;
diff --git a/apps/onplay.c b/apps/onplay.c
index c7b0f7a..8bb71e1 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -61,7 +61,7 @@
 #include "tagtree.h"
 #endif
 #include "cuesheet.h"
-#include "backdrop.h"
+#include "statusbar-skinned.h"
 #include "pitchscreen.h"
 #include "viewport.h"
 
@@ -589,16 +589,16 @@
 static bool set_backdrop(void)
 {
     /* load the image */
-    if(backdrop_load(BACKDROP_MAIN, selected_file)) {
+    if(sb_set_backdrop(SCREEN_MAIN, selected_file)) {
         splash(HZ, str(LANG_BACKDROP_LOADED));
         set_file(selected_file, (char *)global_settings.backdrop_file,
             MAX_FILENAME);
-        backdrop_show(BACKDROP_MAIN);
         return true;
     } else {
         splash(HZ, str(LANG_BACKDROP_FAILED));
         return false;
     }
+    return true;
 }
 #endif
 
diff --git a/apps/screen_access.c b/apps/screen_access.c
index 4744a26..871b1f8 100644
--- a/apps/screen_access.c
+++ b/apps/screen_access.c
@@ -201,9 +201,7 @@
         .backlight_set_timeout=&backlight_set_timeout,
 #if LCD_DEPTH > 1
         .backdrop_load=&backdrop_load,
-        .backdrop_unload=&backdrop_unload,
         .backdrop_show=&backdrop_show,
-        .backdrop_hide=&backdrop_hide,
 #endif
 #ifdef HAVE_BUTTONBAR
         .has_buttonbar=false,
@@ -291,9 +289,7 @@
         
 #if LCD_DEPTH > 1
         .backdrop_load=&remote_backdrop_load,
-        .backdrop_unload=&remote_backdrop_unload,
         .backdrop_show=&remote_backdrop_show,
-        .backdrop_hide=&remote_backdrop_hide,
 #endif
 #ifdef HAVE_BUTTONBAR
         .has_buttonbar=false,
diff --git a/apps/screen_access.h b/apps/screen_access.h
index 31d4b0c..2dc9546 100644
--- a/apps/screen_access.h
+++ b/apps/screen_access.h
@@ -148,10 +148,8 @@
     bool (*is_backlight_on)(bool ignore_always_off);
     void (*backlight_set_timeout)(int index);
 #if LCD_DEPTH > 1
-    bool (*backdrop_load)(enum backdrop_type bdrop, const char* filename);
-    void (*backdrop_unload)(enum backdrop_type bdrop);
-    void (*backdrop_show)(enum backdrop_type bdrop);
-    void (*backdrop_hide)(void);
+    bool (*backdrop_load)(const char *filename, char* backdrop_buffer);
+    void (*backdrop_show)(char* backdrop_buffer);
 #endif
 };
 
diff --git a/apps/settings.c b/apps/settings.c
index 8d1bcf7..1b16e9f 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -63,7 +63,6 @@
 #include "settings_list.h"
 #include "filetypes.h"
 #include "option_select.h"
-#include "backdrop.h"
 #if CONFIG_TUNER
 #include "radio.h"
 #endif
@@ -796,9 +795,6 @@
 #if CONFIG_CODEC == SWCODEC
     int i;
 #endif
-#if LCD_DEPTH > 1
-    int screen;
-#endif
     sound_settings_apply();
 
 #ifdef HAVE_DISK_STORAGE
@@ -907,23 +903,6 @@
             load_kbd(NULL);
 #endif
 
-
-#if LCD_DEPTH > 1
-        if ( global_settings.backdrop_file[0] &&
-            global_settings.backdrop_file[0] != 0xff ) {
-            snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
-                    global_settings.backdrop_file);
-            backdrop_load(BACKDROP_MAIN, buf);
-        } else {
-            backdrop_unload(BACKDROP_MAIN);
-        }
-#endif
-
-#if LCD_DEPTH > 1
-        FOR_NB_SCREENS(screen)
-            screens[screen].backdrop_show(BACKDROP_MAIN);
-#endif
-
         if ( global_settings.lang_file[0]) {
             snprintf(buf, sizeof buf, LANG_DIR "/%s.lng",
                      global_settings.lang_file);