2010-09-14 11:59:52 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 by Stuart Martin
|
|
|
|
* RTC config saving code (C) 2002 by hessu@hes.iki.fi
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include "inttypes.h"
|
|
|
|
#include "config.h"
|
2011-09-25 12:55:40 +00:00
|
|
|
#include "core_alloc.h"
|
2010-09-14 11:59:52 +00:00
|
|
|
#include "action.h"
|
|
|
|
#include "crc32.h"
|
|
|
|
#include "settings.h"
|
|
|
|
#include "wps.h"
|
|
|
|
#include "file.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
#if CONFIG_TUNER
|
|
|
|
#include "radio.h"
|
|
|
|
#endif
|
|
|
|
#include "skin_engine.h"
|
|
|
|
#include "skin_buffer.h"
|
|
|
|
#include "statusbar-skinned.h"
|
|
|
|
|
2010-11-04 10:15:33 +00:00
|
|
|
static bool skins_initialising = true;
|
|
|
|
|
2010-11-05 19:12:23 +00:00
|
|
|
/* App uses the host malloc to manage the buffer */
|
|
|
|
#ifdef APPLICATION
|
|
|
|
#define skin_buffer NULL
|
2010-09-14 11:59:52 +00:00
|
|
|
void theme_init_buffer(void)
|
|
|
|
{
|
2010-11-04 10:15:33 +00:00
|
|
|
skins_initialising = false;
|
2010-09-14 11:59:52 +00:00
|
|
|
}
|
2010-11-05 19:12:23 +00:00
|
|
|
#else
|
2011-09-25 12:55:40 +00:00
|
|
|
static size_t skin_buffer_size;
|
|
|
|
static char *skin_buffer = NULL;
|
|
|
|
static int buflib_move_callback(int handle, void* current, void* new)
|
|
|
|
{
|
|
|
|
(void)current;
|
|
|
|
(void)new;
|
|
|
|
return BUFLIB_CB_CANNOT_MOVE;
|
|
|
|
}
|
|
|
|
static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
|
|
|
|
|
2010-11-04 10:15:33 +00:00
|
|
|
void theme_init_buffer(void)
|
|
|
|
{
|
2011-09-25 12:55:40 +00:00
|
|
|
int fd;
|
|
|
|
size_t size = SKIN_BUFFER_SIZE;
|
|
|
|
fd = open_utf8(ROCKBOX_DIR "/skin_buffer_size.txt", O_RDONLY);
|
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
read(fd, buf, sizeof(buf));
|
|
|
|
if (buf[0] >= '0' && buf[0] <= '9')
|
|
|
|
size = atoi(buf)*1024;
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
skin_buffer = core_get_data(core_alloc_ex("skin buffer", size, &buflib_ops));
|
|
|
|
skin_buffer_size = size;
|
2010-11-04 10:15:33 +00:00
|
|
|
skins_initialising = false;
|
|
|
|
}
|
|
|
|
#endif
|
2010-09-14 11:59:52 +00:00
|
|
|
|
2011-09-15 13:48:17 +00:00
|
|
|
void skin_data_free_buflib_allocs(struct wps_data *wps_data);
|
2010-09-14 11:59:52 +00:00
|
|
|
char* wps_default_skin(enum screen_type screen);
|
|
|
|
char* default_radio_skin(enum screen_type screen);
|
2010-09-14 12:21:56 +00:00
|
|
|
|
2010-09-14 11:59:52 +00:00
|
|
|
struct wps_state wps_state = { .id3 = NULL };
|
|
|
|
static struct gui_skin_helper {
|
|
|
|
int (*preproccess)(enum screen_type screen, struct wps_data *data);
|
|
|
|
int (*postproccess)(enum screen_type screen, struct wps_data *data);
|
|
|
|
char* (*default_skin)(enum screen_type screen);
|
|
|
|
} skin_helpers[SKINNABLE_SCREENS_COUNT] = {
|
|
|
|
[CUSTOM_STATUSBAR] = { sb_preproccess, sb_postproccess, sb_create_from_settings },
|
|
|
|
[WPS] = { NULL, NULL, wps_default_skin },
|
|
|
|
#if CONFIG_TUNER
|
|
|
|
[FM_SCREEN] = { NULL, NULL, default_radio_skin }
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2010-10-16 15:23:41 +00:00
|
|
|
static struct gui_skin {
|
2010-09-14 11:59:52 +00:00
|
|
|
struct gui_wps gui_wps;
|
|
|
|
struct wps_data data;
|
|
|
|
char *buffer_start;
|
|
|
|
size_t buffer_usage;
|
|
|
|
|
|
|
|
bool needs_full_update;
|
|
|
|
} skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS];
|
|
|
|
|
|
|
|
|
|
|
|
void gui_sync_skin_init(void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
|
|
|
|
{
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
{
|
|
|
|
skins[j][i].buffer_start = NULL;
|
|
|
|
skins[j][i].needs_full_update = true;
|
2011-09-11 09:07:20 +00:00
|
|
|
skins[j][i].gui_wps.data = &skins[j][i].data;
|
|
|
|
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;
|
2010-09-14 11:59:52 +00:00
|
|
|
#ifdef HAVE_ALBUMART
|
|
|
|
skins[j][i].data.albumart = NULL;
|
|
|
|
skins[j][i].data.playback_aa_slot = -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-15 13:48:17 +00:00
|
|
|
void settings_apply_skins(void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2011-09-24 13:19:34 +00:00
|
|
|
for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
|
2011-09-15 13:48:17 +00:00
|
|
|
{
|
2011-09-24 13:19:34 +00:00
|
|
|
FOR_NB_SCREENS(i)
|
2011-09-15 13:48:17 +00:00
|
|
|
skin_data_free_buflib_allocs(&skins[j][i].data);
|
|
|
|
}
|
|
|
|
|
2011-09-25 12:55:40 +00:00
|
|
|
skin_buffer_init(skin_buffer, skin_buffer_size);
|
2011-09-15 13:48:17 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_LCD_BITMAP
|
|
|
|
skin_backdrop_init();
|
|
|
|
#endif
|
|
|
|
gui_sync_skin_init();
|
|
|
|
|
|
|
|
/* Make sure each skin is loaded */
|
|
|
|
for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
|
|
|
|
{
|
|
|
|
FOR_NB_SCREENS(j)
|
|
|
|
skin_get_gwps(i, j);
|
|
|
|
}
|
|
|
|
#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
|
|
|
|
skin_backdrops_preload(); /* should maybe check the retval here... */
|
|
|
|
#endif
|
|
|
|
viewportmanager_theme_changed(THEME_STATUSBAR);
|
|
|
|
#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
skin_backdrop_show(sb_get_backdrop(i));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-14 11:59:52 +00:00
|
|
|
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 && skin_helpers[skin].default_skin)
|
|
|
|
loaded = skin_data_load(screen, &skins[skin][screen].data,
|
|
|
|
skin_helpers[skin].default_skin(screen), false);
|
|
|
|
|
|
|
|
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;
|
|
|
|
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)
|
|
|
|
{
|
2010-12-06 22:26:31 +00:00
|
|
|
char buf[MAX_PATH*2];
|
2010-09-14 12:21:56 +00:00
|
|
|
char *setting = NULL, *ext = NULL;
|
2010-09-14 11:59:52 +00:00
|
|
|
switch (skin)
|
|
|
|
{
|
|
|
|
case CUSTOM_STATUSBAR:
|
2010-09-14 12:21:56 +00:00
|
|
|
#ifdef HAVE_LCD_BITMAP
|
2010-11-04 10:15:33 +00:00
|
|
|
if (skins_initialising)
|
2010-09-14 11:59:52 +00:00
|
|
|
{
|
|
|
|
/* 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";
|
|
|
|
}
|
2010-09-14 12:21:56 +00:00
|
|
|
#else
|
|
|
|
return &skins[skin][screen].gui_wps;
|
|
|
|
#endif /* HAVE_LCD_BITMAP */
|
2010-09-14 11:59:52 +00:00
|
|
|
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"))
|
|
|
|
{
|
2010-12-06 22:26:31 +00:00
|
|
|
snprintf(buf, sizeof buf, WPS_DIR "/%s.%s", setting, ext);
|
2010-09-14 11:59:52 +00:00
|
|
|
}
|
|
|
|
cpu_boost(true);
|
|
|
|
skin_load(skin, screen, buf, true);
|
|
|
|
cpu_boost(false);
|
|
|
|
loading_a_sbs = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &skins[skin][screen].gui_wps;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wps_state *skin_get_global_state(void)
|
|
|
|
{
|
|
|
|
return &wps_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is called to find out if we the screen needs a full update.
|
|
|
|
* if true you MUST do a full update as the next call will return false */
|
|
|
|
bool skin_do_full_update(enum skinnable_screens skin,
|
|
|
|
enum screen_type screen)
|
|
|
|
{
|
|
|
|
bool ret = skins[skin][screen].needs_full_update;
|
|
|
|
skins[skin][screen].needs_full_update = false;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tell a skin to do a full update next time */
|
|
|
|
void skin_request_full_update(enum skinnable_screens skin)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
FOR_NB_SCREENS(i)
|
|
|
|
skins[skin][i].needs_full_update = true;
|
|
|
|
}
|