skinengine: Rework skin loading so skins can be un/loaded individually. This also means that loading a .cfg which doesnt change themes shouldnt have them reloaded

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31037 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jonathan Gordon 2011-11-21 10:02:23 +00:00
parent 814ffffdbe
commit 0ca4b38b1b
7 changed files with 188 additions and 153 deletions

View file

@ -37,6 +37,7 @@ static struct skin_backdrop {
enum screen_type screen;
bool loaded;
int buflib_handle;
int ref_count;
} backdrops[NB_BDROPS];
#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS
@ -63,21 +64,21 @@ static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
static bool first_go = true;
void skin_backdrop_init(void)
{
for (int i=0; i<NB_BDROPS; i++)
if (first_go)
{
if (first_go)
for (int i=0; i<NB_BDROPS; i++)
{
backdrops[i].buflib_handle = -1;
else
skin_backdrop_unload(i);
backdrops[i].name[0] = '\0';
backdrops[i].buffer = NULL;
backdrops[i].loaded = false;
backdrops[i].name[0] = '\0';
backdrops[i].buffer = NULL;
backdrops[i].loaded = false;
backdrops[i].ref_count = 0;
}
FOR_NB_SCREENS(i)
current_lcd_backdrop[i] = -1;
handle_being_loaded = -1;
first_go = false;
}
first_go = false;
FOR_NB_SCREENS(i)
current_lcd_backdrop[i] = -1;
handle_being_loaded = -1;
}
int skin_backdrop_assign(char* backdrop, char *bmpdir,
@ -101,22 +102,26 @@ int skin_backdrop_assign(char* backdrop, char *bmpdir,
for (i=0; i<NB_BDROPS; i++)
{
if (!backdrops[i].name[0] && free < 0)
free = i;
if (!strcmp(backdrops[i].name, filename) && backdrops[i].screen == screen)
{
free = i;
break;
}
else if (!strcmp(backdrops[i].name, filename) && backdrops[i].screen == screen)
{
backdrops[i].ref_count++;
break;
}
}
if (i < NB_BDROPS)
return i;
else if (free >= 0)
if (free >= 0)
{
strlcpy(backdrops[free].name, filename,
sizeof (backdrops[free].name));
strlcpy(backdrops[free].name, filename, MAX_PATH);
backdrops[free].buffer = NULL;
backdrops[free].screen = screen;
backdrops[free].ref_count = 1;
return free;
}
else if (i < NB_BDROPS)
return i;
return -1;
}
@ -188,10 +193,17 @@ void skin_backdrop_show(int backdrop_id)
void skin_backdrop_unload(int backdrop_id)
{
if (backdrops[backdrop_id].buflib_handle > 0)
core_free(backdrops[backdrop_id].buflib_handle);
backdrops[backdrop_id].buffer = NULL;
backdrops[backdrop_id].buflib_handle = -1;
backdrops[backdrop_id].ref_count--;
if (backdrops[backdrop_id].ref_count <= 0)
{
if (backdrops[backdrop_id].buflib_handle > 0)
core_free(backdrops[backdrop_id].buflib_handle);
backdrops[backdrop_id].buffer = NULL;
backdrops[backdrop_id].buflib_handle = -1;
backdrops[backdrop_id].loaded = false;
backdrops[backdrop_id].name[0] = '\0';
backdrops[backdrop_id].ref_count = 0;
}
}
void skin_backdrop_load_setting(void)

View file

@ -38,18 +38,15 @@
#include "skin_buffer.h"
#include "statusbar-skinned.h"
static bool skins_initialising = true;
/* App uses the host malloc to manage the buffer */
void theme_init_buffer(void)
{
skins_initialising = false;
}
#define FAILSAFENAME "rockbox_failsafe"
void skin_data_free_buflib_allocs(struct wps_data *wps_data);
char* wps_default_skin(enum screen_type screen);
char* default_radio_skin(enum screen_type screen);
static char* get_skin_filename(char *buf, size_t buf_size,
enum skinnable_screens skin, enum screen_type screen);
struct wps_state wps_state = { .id3 = NULL };
static struct gui_skin_helper {
int (*preproccess)(enum screen_type screen, struct wps_data *data);
@ -62,17 +59,49 @@ static struct gui_skin_helper {
[FM_SCREEN] = { NULL, NULL, default_radio_skin }
#endif
};
static struct gui_skin {
char filename[MAX_PATH];
struct gui_wps gui_wps;
struct wps_data data;
char *buffer_start;
size_t buffer_usage;
bool failsafe_loaded;
bool needs_full_update;
} skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS];
void gui_skin_reset(struct gui_skin *skin)
{
skin->filename[0] = '\0';
skin->buffer_start = NULL;
skin->failsafe_loaded = false;
skin->needs_full_update = true;
skin->gui_wps.data = &skin->data;
memset(skin->gui_wps.data, 0, sizeof(struct wps_data));
skin->data.wps_loaded = false;
skin->data.buflib_handle = -1;
skin->data.tree = -1;
#ifdef HAVE_TOUCHSCREEN
skin->data.touchregions = -1;
#endif
#ifdef HAVE_SKIN_VARIABLES
skin->data.skinvars = -1;
#endif
#ifdef HAVE_LCD_BITMAP
skin->data.font_ids = -1;
skin->data.images = -1;
#endif
#ifdef HAVE_ALBUMART
skin->data.albumart = -1;
skin->data.playback_aa_slot = -1;
#endif
#ifdef HAVE_BACKDROP_IMAGE
skin->gui_wps.data->backdrop_id = -1;
#endif
}
void gui_sync_skin_init(void)
{
int j;
@ -80,64 +109,60 @@ void gui_sync_skin_init(void)
{
FOR_NB_SCREENS(i)
{
skins[j][i].buffer_start = NULL;
skins[j][i].needs_full_update = true;
skins[j][i].gui_wps.data = &skins[j][i].data;
skin_data_free_buflib_allocs(&skins[j][i].data);
gui_skin_reset(&skins[j][i]);
skins[j][i].gui_wps.display = &screens[i];
memset(skins[j][i].gui_wps.data, 0, sizeof(struct wps_data));
skins[j][i].data.wps_loaded = false;
skins[j][i].data.buflib_handle = -1;
skins[j][i].data.tree = -1;
#ifdef HAVE_TOUCHSCREEN
skins[j][i].data.touchregions = -1;
#endif
#ifdef HAVE_SKIN_VARIABLES
skins[j][i].data.skinvars = -1;
#endif
#ifdef HAVE_LCD_BITMAP
skins[j][i].data.font_ids = -1;
skins[j][i].data.images = -1;
#endif
#ifdef HAVE_ALBUMART
skins[j][i].data.albumart = -1;
skins[j][i].data.playback_aa_slot = -1;
#endif
}
}
}
void skin_unload_all(void)
{
int j;
for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
{
FOR_NB_SCREENS(i)
skin_data_free_buflib_allocs(&skins[j][i].data);
}
#ifdef HAVE_LCD_BITMAP
skin_backdrop_init();
#endif
gui_sync_skin_init();
}
void settings_apply_skins(void)
{
int i;
char filename[MAX_PATH];
static bool first_run = true;
skin_unload_all();
#ifdef HAVE_LCD_BITMAP
skin_backdrop_init();
#endif
/* Make sure each skin is loaded */
for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
{
FOR_NB_SCREENS(j)
skin_get_gwps(i, j);
}
{
bool load = false;
get_skin_filename(filename, MAX_PATH, i,j);
if (filename[0] && (strcmp(filename, skins[i][j].filename) || skins[i][j].failsafe_loaded))
load = true;
else if (first_run || (!filename[0] && !skins[i][j].failsafe_loaded))
load = true;
if (load)
{
if (!first_run)
{
skin_data_free_buflib_allocs(&skins[i][j].data);
#ifdef HAVE_BACKDROP_IMAGE
skin_backdrops_preload(); /* should maybe check the retval here... */
if (skins[i][j].data.backdrop_id >= 0)
skin_backdrop_unload(skins[i][j].data.backdrop_id);
#endif
}
gui_skin_reset(&skins[i][j]);
skins[i][j].gui_wps.display = &screens[j];
skin_get_gwps(i, j);
}
}
}
first_run = false;
viewportmanager_theme_changed(THEME_STATUSBAR);
#ifdef HAVE_BACKDROP_IMAGE
skin_backdrops_preload(); /* should maybe check the retval here... */
FOR_NB_SCREENS(i)
skin_backdrop_show(sb_get_backdrop(i));
#endif
@ -147,104 +172,100 @@ void skin_load(enum skinnable_screens skin, enum screen_type screen,
const char *buf, bool isfile)
{
bool loaded = false;
if (skin_helpers[skin].preproccess)
skin_helpers[skin].preproccess(screen, &skins[skin][screen].data);
if (buf && *buf)
loaded = skin_data_load(screen, &skins[skin][screen].data, buf, isfile);
if (loaded)
strcpy(skins[skin][screen].filename, buf);
if (!loaded && skin_helpers[skin].default_skin)
{
loaded = skin_data_load(screen, &skins[skin][screen].data,
skin_helpers[skin].default_skin(screen), false);
skins[skin][screen].failsafe_loaded = loaded;
}
skins[skin][screen].needs_full_update = true;
if (skin_helpers[skin].postproccess)
skin_helpers[skin].postproccess(screen, &skins[skin][screen].data);
}
static bool loading_a_sbs = false;
static char* get_skin_filename(char *buf, size_t buf_size,
enum skinnable_screens skin, enum screen_type screen)
{
(void)screen;
char *setting = NULL, *ext = NULL;
switch (skin)
{
case CUSTOM_STATUSBAR:
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rsbs_file;
ext = "rsbs";
}
else
#endif
{
setting = global_settings.sbs_file;
ext = "sbs";
}
break;
case WPS:
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rwps_file;
ext = "rwps";
}
else
#endif
{
setting = global_settings.wps_file;
ext = "wps";
}
break;
#if CONFIG_TUNER
case FM_SCREEN:
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rfms_file;
ext = "rfms";
}
else
#endif
{
setting = global_settings.fms_file;
ext = "fms";
}
break;
#endif
default:
return NULL;
}
buf[0] = '\0'; /* force it to reload the default */
if (strcmp(setting, FAILSAFENAME) && strcmp(setting, "-"))
{
snprintf(buf, buf_size, WPS_DIR "/%s.%s", setting, ext);
}
return buf;
}
struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen)
{
if (!loading_a_sbs && skins[skin][screen].data.wps_loaded == false)
if (skins[skin][screen].data.wps_loaded == false)
{
char buf[MAX_PATH*2];
char *setting = NULL, *ext = NULL;
switch (skin)
{
case CUSTOM_STATUSBAR:
#ifdef HAVE_LCD_BITMAP
if (skins_initialising)
{
/* still loading, buffers not initialised yet,
* viewport manager calls into the sbs code, not really
* caring if the sbs has loaded or not, so just return
* the gwps, this is safe. */
return &skins[skin][screen].gui_wps;
}
/* during the sbs load it will call skin_get_gwps() a few times
* which will eventually stkov the viewportmanager, so make
* sure we don't let that happen */
loading_a_sbs = true;
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rsbs_file;
ext = "rsbs";
}
else
#endif
{
setting = global_settings.sbs_file;
ext = "sbs";
}
#else
return &skins[skin][screen].gui_wps;
#endif /* HAVE_LCD_BITMAP */
break;
case WPS:
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rwps_file;
ext = "rwps";
}
else
#endif
{
setting = global_settings.wps_file;
ext = "wps";
}
break;
#if CONFIG_TUNER
case FM_SCREEN:
#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
{
setting = global_settings.rfms_file;
ext = "rfms";
}
else
#endif
{
setting = global_settings.fms_file;
ext = "fms";
}
break;
#endif
default:
return NULL;
}
buf[0] = '\0'; /* force it to reload the default */
if (strcmp(setting, "rockbox_failsafe"))
{
snprintf(buf, sizeof buf, WPS_DIR "/%s.%s", setting, ext);
}
char filename[MAX_PATH];
char *buf = get_skin_filename(filename, MAX_PATH, skin, screen);
cpu_boost(true);
skins[skin][screen].filename[0] = '\0';
skin_load(skin, screen, buf, true);
cpu_boost(false);
loading_a_sbs = false;
}
return &skins[skin][screen].gui_wps;
}

View file

@ -1687,7 +1687,7 @@ static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
list = SKINOFFSETTOPTR(skin_buffer, list->next);
}
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
#ifdef HAVE_BACKDROP_IMAGE
wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
#endif /* has backdrop support */
return retval;
@ -1986,7 +1986,7 @@ static int skin_element_callback(struct skin_element* element, void* data)
case SKIN_TOKEN_FILE_DIRECTORY:
token->value.i = get_param(element, 0)->data.number;
break;
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
#ifdef HAVE_BACKDROP_IMAGE
case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
function = parse_viewportcolour;

View file

@ -50,6 +50,7 @@ static int update_delay = DEFAULT_UPDATE_DELAY;
static bool sbs_has_title[NB_SCREENS];
static char* sbs_title[NB_SCREENS];
static enum themable_icons sbs_icon[NB_SCREENS];
static bool sbs_loaded[NB_SCREENS] = { false };
bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen)
{
@ -76,6 +77,7 @@ enum themable_icons sb_get_icon(enum screen_type screen)
int sb_preproccess(enum screen_type screen, struct wps_data *data)
{
(void)data;
sbs_loaded[screen] = false;
sbs_has_title[screen] = false;
viewportmanager_theme_enable(screen, false, NULL);
return 1;
@ -101,6 +103,7 @@ int sb_postproccess(enum screen_type screen, struct wps_data *data)
vp->hidden_flags = VP_NEVER_VISIBLE;
}
sb_set_info_vp(screen, VP_DEFAULT_LABEL);
sbs_loaded[screen] = true;
}
viewportmanager_theme_undo(screen, false);
return 1;
@ -115,6 +118,8 @@ void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label)
struct viewport *sb_skin_get_info_vp(enum screen_type screen)
{
if (sbs_loaded[screen] == false)
return NULL;
struct wps_data *data = skin_get_gwps(CUSTOM_STATUSBAR, screen)->data;
struct skin_viewport *vp = NULL;
char *label;

View file

@ -393,7 +393,6 @@ static void init(void)
tree_mem_init();
filetype_init();
playlist_init();
theme_init_buffer();
shortcuts_init();
#if CONFIG_CODEC != SWCODEC
@ -678,7 +677,6 @@ static void init(void)
tree_mem_init();
filetype_init();
scrobbler_init();
theme_init_buffer();
shortcuts_init();
#if CONFIG_CODEC != SWCODEC

View file

@ -222,7 +222,6 @@ void sound_settings_apply(void);
* skin buffer is reset properly
*/
void settings_apply_skins(void);
void theme_init_buffer(void);
void settings_apply(bool read_disk);
void settings_apply_pm_range(void);

View file

@ -203,7 +203,7 @@ static const char graphic_numeric[] = "graphic,numeric";
/* Default theme settings */
#define DEFAULT_WPSNAME "cabbiev2"
#define DEFAULT_SBSNAME "-"
#define DEFAULT_FMS_NAME DEFAULT_WPSNAME
#define DEFAULT_FMS_NAME "-"
#ifdef HAVE_LCD_BITMAP