From 9928e3418f67fe6d2f82292ddbddcf56ae20b8f6 Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Tue, 14 Sep 2010 11:56:50 +0000 Subject: Another major skin backend update/hopefully bugfix: Skins are now more self contained in the skin manager which in the future might allow on demand skin loading (i.e smaller skin buffers) Skin backdrops are also managed more intelegently (fixes a bug where you can get a crazy backdrop loaded if a .sbs fails to load) the rockbox_default rescue theme is now called rockbox_failsafe to better express what it actually is. This commit hopefully/maybe fixes the heavily reported data aborts, so please check if you are getting them git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28073 a1c6a512-1295-4272-9138-f99709370657 --- apps/gui/skin_engine/skin_backdrops.c | 164 +++++++++++++++++++++++++--------- apps/gui/skin_engine/skin_display.c | 31 ++++--- apps/gui/skin_engine/skin_engine.h | 24 ++++- apps/gui/skin_engine/skin_parser.c | 42 ++++----- apps/gui/skin_engine/skin_render.c | 3 +- apps/gui/skin_engine/skin_tokens.c | 16 ++-- apps/gui/skin_engine/wps_internals.h | 20 +---- 7 files changed, 187 insertions(+), 113 deletions(-) (limited to 'apps/gui/skin_engine') diff --git a/apps/gui/skin_engine/skin_backdrops.c b/apps/gui/skin_engine/skin_backdrops.c index 9ceee0cd05..f5b72a9652 100644 --- a/apps/gui/skin_engine/skin_backdrops.c +++ b/apps/gui/skin_engine/skin_backdrops.c @@ -30,88 +30,164 @@ #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) +#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS static struct skin_backdrop { char name[MAX_PATH]; char *buffer; enum screen_type screen; -} backdrops[SKINNABLE_SCREENS_COUNT*NB_SCREENS]; +} backdrops[NB_BDROPS]; + +#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS void skin_backdrop_init(void) { int i; - for(i=0;i 1) - if (screen == SCREEN_REMOTE) - buf_size = REMOTE_LCD_BACKDROP_BYTES; - else -#endif - buf_size = LCD_BACKDROP_BYTES; - + int i, free = -1; + if (!backdrop) + return -1; if (backdrop[0] == '-') { + filename[0] = '-'; + filename[1] = '\0'; + filename[2] = '\0'; /* we check this later to see if we actually have an + image to load. != '\0' means display the image */ #if NB_SCREENS > 1 if (screen == SCREEN_REMOTE) { - return NULL; /* remotes don't have a backdrop setting (yet!) */ + filename[0] = '\0'; } - else #endif - { - char settings_bdrop = global_settings.backdrop_file[0]; - if (settings_bdrop == '\0' || settings_bdrop == '-') - { - return NULL; /* backdrop setting not set */ - } - snprintf(filename, sizeof(filename), "%s/%s.bmp", - get_user_file_path(BACKDROP_DIR, 0, dir, sizeof(dir)), - global_settings.backdrop_file); - } } else { const char *bd_dir = get_user_file_path(bmpdir, 0, dir, sizeof(dir)); get_image_filename(backdrop, bd_dir, filename, sizeof(filename)); } - - for(i=0;i= 0) + { + strlcpy(backdrops[free].name, filename, + sizeof (backdrops[free].name)); + backdrops[free].buffer = NULL; + backdrops[free].screen = screen; + return free; + } + return -1; +} + +bool skin_backdrops_preload(void) +{ + bool retval = true; + int i; + char *filename; + for (i=0; i 1) + if (screen == SCREEN_REMOTE) + buf_size = REMOTE_LCD_BACKDROP_BYTES; + else +#endif + buf_size = LCD_BACKDROP_BYTES; + + filename = backdrops[i].name; + if (screen == SCREEN_MAIN && global_settings.backdrop_file[0] && + global_settings.backdrop_file[0] != '-' && filename[0] == '-') + { + char dir[MAX_PATH]; + char* temp = filename+2; /* slightly hacky to get a buffer */ + size_t size = sizeof(backdrops[i].name) - 2; + snprintf(temp, size, "%s/%s.bmp", + get_user_file_path(BACKDROP_DIR, 0, dir, sizeof(dir)), + global_settings.backdrop_file); + filename = temp; + } + if (*filename && *filename != '-') + { + backdrops[i].buffer = (char*)skin_buffer_alloc(buf_size); + loaded = backdrops[i].buffer && + screens[screen].backdrop_load(filename, backdrops[i].buffer); + if (!loaded) + retval = false; + } + if (backdrops[i].name[0] == '-' && loaded) + backdrops[i].name[2] = '.'; } - else if (!bdrop && backdrops[i].buffer == NULL) + } + return retval; +} + +void skin_backdrop_show(int backdrop_id) +{ + if (backdrop_id < 0) + return; + enum screen_type screen = backdrops[backdrop_id].screen; + if (backdrops[backdrop_id].name[0] == '-' && + backdrops[backdrop_id].name[2] == '\0') + return; + if (backdrops[backdrop_id].buffer) + screens[screen].backdrop_show(backdrops[backdrop_id].buffer); +} + +void skin_backdrop_unload(int backdrop_id) +{ + backdrops[backdrop_id].buffer = NULL; +} + +void skin_backdrop_load_setting(void) +{ + int i; + char filename[MAX_PATH], dir[MAX_PATH]; + for(i=0;ibuffer = (char*)skin_buffer_alloc(buf_size); - if (!bdrop->buffer) - return NULL; - loaded = screens[screen].backdrop_load(filename, bdrop->buffer); - bdrop->screen = screen; - strlcpy(bdrop->name, filename, sizeof(bdrop->name)); - - return loaded ? bdrop->buffer : NULL; } + #else void skin_backdrop_init(void) diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c index d76b57976d..f001640cde 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -74,18 +74,21 @@ void skin_render(struct gui_wps *gwps, unsigned refresh_mode); /* update a skinned screen, update_type is WPS_REFRESH_* values. * Usually it should only be WPS_REFRESH_NON_STATIC - * A full update will be done if required (state.do_full_update == true) + * A full update will be done if required (skin_do_full_update() == true) */ -void skin_update(struct gui_wps *gwps, unsigned int update_type) +void skin_update(enum skinnable_screens skin, enum screen_type screen, + unsigned int update_type) { + struct gui_wps *gwps = skin_get_gwps(skin, screen); /* This maybe shouldnt be here, * This is also safe for skined screen which dont use the id3 */ - struct mp3entry *id3 = gwps->state->id3; + struct mp3entry *id3 = skin_get_global_state()->id3; bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false); - gwps->sync_data->do_full_update |= cuesheet_update; + if (cuesheet_update) + skin_request_full_update(skin); - skin_render(gwps, gwps->sync_data->do_full_update ? - SKIN_REFRESH_ALL : update_type); + skin_render(gwps, skin_do_full_update(skin, screen) ? + SKIN_REFRESH_ALL : update_type); } #ifdef HAVE_LCD_BITMAP @@ -126,7 +129,7 @@ void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) { struct screen *display = gwps->display; struct viewport *vp = pb->vp; - struct wps_state *state = gwps->state; + struct wps_state *state = skin_get_global_state(); struct mp3entry *id3 = state->id3; int y = pb->y, height = pb->height; unsigned long length, end; @@ -729,11 +732,10 @@ bool skin_has_sbs(enum screen_type screen, struct wps_data *data) /* do the button loop as often as required for the peak meters to update * with a good refresh rate. - * gwps is really gwps[NB_SCREENS]! don't wrap this if FOR_NB_SCREENS() */ -int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) +int skin_wait_for_action(enum skinnable_screens skin, int context, int timeout) { - (void)gwps; /* silence charcell warning */ + (void)skin; /* silence charcell warning */ int button = ACTION_NONE; #ifdef HAVE_LCD_BITMAP int i; @@ -744,7 +746,7 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) bool pm=false; FOR_NB_SCREENS(i) { - if(gwps[i].data->peak_meter_enabled) + if(skin_get_gwps(skin, i)->data->peak_meter_enabled) pm = true; } @@ -763,8 +765,8 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) if (TIME_AFTER(current_tick, next_refresh)) { FOR_NB_SCREENS(i) { - if(gwps[i].data->peak_meter_enabled) - skin_update(&gwps[i], SKIN_REFRESH_PEAK_METER); + if(skin_get_gwps(skin, i)->data->peak_meter_enabled) + skin_update(skin, i, SKIN_REFRESH_PEAK_METER); next_refresh += HZ / PEAK_METER_FPS; } } @@ -781,3 +783,6 @@ int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout) } return button; } + + + diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h index 6beedd90a2..ef4297d0ce 100644 --- a/apps/gui/skin_engine/skin_engine.h +++ b/apps/gui/skin_engine/skin_engine.h @@ -73,7 +73,8 @@ void skin_disarm_touchregions(struct wps_data *data); #endif /* Do a update_type update of the skinned screen */ -void skin_update(struct gui_wps *gwps, unsigned int update_type); +void skin_update(enum skinnable_screens skin, enum screen_type screen, + unsigned int update_type); /* * setup up the skin-data from a format-buffer (isfile = false) @@ -92,13 +93,28 @@ bool skin_has_sbs(enum screen_type screen, struct wps_data *data); * reuse buffers if the file is already loaded */ char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen); void skin_backdrop_init(void); - +int skin_backdrop_assign(char* backdrop, char *bmpdir, + enum screen_type screen); +bool skin_backdrops_preload(void); +void skin_backdrop_show(int backdrop_id); +void skin_backdrop_load_setting(void); +void skin_backdrop_unload(int backdrop_id); /* do the button loop as often as required for the peak meters to update * with a good refresh rate. * gwps is really gwps[NB_SCREENS]! don't wrap this in FOR_NB_SCREENS() */ -int skin_wait_for_action(struct gui_wps *gwps, int context, int timeout); -#endif +int skin_wait_for_action(enum skinnable_screens skin, int context, int timeout); + +void skin_load(enum skinnable_screens skin, enum screen_type screen, + const char *buf, bool isfile); +struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen); +struct wps_state *skin_get_global_state(void); +void gui_sync_skin_init(void); + + +bool skin_do_full_update(enum skinnable_screens skin, enum screen_type screen); +void skin_request_full_update(enum skinnable_screens skin); +#endif /* !PLUGIN */ #endif diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index a6d4c798dc..2534bf9104 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -447,26 +447,27 @@ static int parse_image_special(struct skin_element *element, { (void)wps_data; /* kill warning */ (void)token; - bool error = false; #if LCD_DEPTH > 1 + char *filename; if (token->type == SKIN_TOKEN_IMAGE_BACKDROP) { - char *filename = element->params[0].data.text; - /* format: %X|filename.bmp| or %Xd */ - if (!strcmp(filename, "d")) + if (isdefault(&element->params[0])) { - wps_data->backdrop = NULL; - return 0; + filename = "-"; } - else if (!error) + else { - wps_data->backdrop = filename; + filename = element->params[0].data.text; + /* format: %X(filename.bmp) or %X(d) */ + if (!strcmp(filename, "d")) + filename = NULL; } + wps_data->backdrop = filename; } #endif - /* Skip the rest of the line */ - return error ? WPS_ERROR_INVALID_PARAM : 0; + + return 0; } #endif @@ -1010,6 +1011,8 @@ static void skin_data_reset(struct wps_data *wps_data) wps_data->progressbars = NULL; #endif #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (wps_data->backdrop_id >= 0) + skin_backdrop_unload(wps_data->backdrop_id); wps_data->backdrop = NULL; #endif #ifdef HAVE_TOUCHSCREEN @@ -1128,23 +1131,7 @@ static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir) } #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - /* Backdrop load scheme: - * 1) %X|filename| - * 2) load the backdrop from settings - */ - if (wps_data->backdrop) - { - if (screens[curr_screen].depth == 1) - { - wps_data->backdrop = NULL; - return retval; - } - bool needed = wps_data->backdrop[0] != '-'; - wps_data->backdrop = skin_backdrop_load(wps_data->backdrop, - bmpdir, curr_screen); - if (!wps_data->backdrop && needed) - retval = false; - } + wps_data->backdrop_id = skin_backdrop_assign(wps_data->backdrop, bmpdir, curr_screen); #endif /* has backdrop support */ return retval; } @@ -1575,6 +1562,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data, } #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 wps_data->backdrop = "-"; + wps_data->backdrop_id = -1; #endif /* parse the skin source */ skin_buffer_save_position(); diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 9f392f144f..4fbd550c72 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c @@ -749,7 +749,8 @@ static void skin_render_playlistviewer(struct playlistviewer* viewer, else #endif { - struct cuesheet *cue = gwps->state->id3 ? gwps->state->id3->cuesheet:NULL; + struct cuesheet *cue = skin_get_global_state()->id3 ? + skin_get_global_state()->id3->cuesheet : NULL; cur_pos = playlist_get_display_index(); max = playlist_amount()+1; if (cue) diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c index 3de6630a51..0e98c2d42f 100644 --- a/apps/gui/skin_engine/skin_tokens.c +++ b/apps/gui/skin_engine/skin_tokens.c @@ -515,18 +515,18 @@ const char *get_radio_token(struct wps_token *token, int preset_offset, } #endif -static struct mp3entry* get_mp3entry_from_offset(struct gui_wps *gwps, - int offset, char **filename) +static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename) { struct mp3entry* pid3 = NULL; - struct cuesheet *cue = gwps->state->id3 ? gwps->state->id3->cuesheet:NULL; + struct wps_state *state = skin_get_global_state(); + struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL; const char *fname = NULL; if (cue && cue->curr_track_idx + offset < cue->track_count) - pid3 = gwps->state->id3; + pid3 = state->id3; else if (offset == 0) - pid3 = gwps->state->id3; + pid3 = state->id3; else if (offset == 1) - pid3 = gwps->state->nid3; + pid3 = state->nid3; else { static char filename_buf[MAX_PATH + 1]; @@ -568,7 +568,7 @@ const char *get_token_value(struct gui_wps *gwps, return NULL; struct wps_data *data = gwps->data; - struct wps_state *state = gwps->state; + struct wps_state *state = skin_get_global_state(); struct mp3entry *id3; /* Think very carefully about using this. maybe get_id3_token() is the better place? */ const char *out_text = NULL; @@ -577,7 +577,7 @@ const char *get_token_value(struct gui_wps *gwps, if (!data || !state) return NULL; - id3 = get_mp3entry_from_offset(gwps, token->next? 1: offset, &filename); + id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename); if (id3) filename = id3->path; diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index 0767f50279..5c3d953fdb 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -266,7 +266,10 @@ struct wps_data struct skin_token_list *progressbars; #endif #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - char *backdrop; + struct { + char *backdrop; + int backdrop_id; + }; #endif #ifdef HAVE_TOUCHSCREEN @@ -305,18 +308,6 @@ struct wps_state bool is_fading; }; -/* Holds data for all screens in a skin. */ -struct wps_sync_data -{ - /* suitable for the viewportmanager, possibly only temporary here - * needs to be same for all screens! can't be split up for screens - * due to what viewportmanager_set_statusbar() accepts - * (FIXME?) */ - int statusbars; - /* indicates whether the skin needs a full update for all screens */ - bool do_full_update; -}; - /* change the ff/rew-status if ff_rew = true then we are in skipping mode else we are in normal mode */ @@ -334,9 +325,6 @@ struct gui_wps { struct screen *display; struct wps_data *data; - struct wps_state *state; - /* must point to the same struct for all screens */ - struct wps_sync_data *sync_data; }; /* gui_wps end */ -- cgit v1.2.3