summaryrefslogtreecommitdiff
path: root/apps/gui/skin_engine
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2011-11-21 10:02:23 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2011-11-21 10:02:23 +0000
commit0ca4b38b1b04e6b7d6f5ad1f3654f8f361d8933f (patch)
treec17fc93ca3814537e12521c4bebfb560739c8ea9 /apps/gui/skin_engine
parent814ffffdbe5a5ea420ddc6475512a75cba7a8583 (diff)
downloadrockbox-0ca4b38b1b04e6b7d6f5ad1f3654f8f361d8933f.tar.gz
rockbox-0ca4b38b1b04e6b7d6f5ad1f3654f8f361d8933f.zip
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
Diffstat (limited to 'apps/gui/skin_engine')
-rw-r--r--apps/gui/skin_engine/skin_backdrops.c56
-rw-r--r--apps/gui/skin_engine/skin_engine.c245
-rw-r--r--apps/gui/skin_engine/skin_parser.c4
3 files changed, 169 insertions, 136 deletions
diff --git a/apps/gui/skin_engine/skin_backdrops.c b/apps/gui/skin_engine/skin_backdrops.c
index 0b67125bbf..0433d0258d 100644
--- a/apps/gui/skin_engine/skin_backdrops.c
+++ b/apps/gui/skin_engine/skin_backdrops.c
@@ -37,6 +37,7 @@ static struct skin_backdrop {
37 enum screen_type screen; 37 enum screen_type screen;
38 bool loaded; 38 bool loaded;
39 int buflib_handle; 39 int buflib_handle;
40 int ref_count;
40} backdrops[NB_BDROPS]; 41} backdrops[NB_BDROPS];
41 42
42#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS 43#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS
@@ -63,21 +64,21 @@ static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
63static bool first_go = true; 64static bool first_go = true;
64void skin_backdrop_init(void) 65void skin_backdrop_init(void)
65{ 66{
66 for (int i=0; i<NB_BDROPS; i++) 67 if (first_go)
67 { 68 {
68 if (first_go) 69 for (int i=0; i<NB_BDROPS; i++)
70 {
69 backdrops[i].buflib_handle = -1; 71 backdrops[i].buflib_handle = -1;
70 else 72 backdrops[i].name[0] = '\0';
71 skin_backdrop_unload(i); 73 backdrops[i].buffer = NULL;
72 backdrops[i].name[0] = '\0'; 74 backdrops[i].loaded = false;
73 backdrops[i].buffer = NULL; 75 backdrops[i].ref_count = 0;
74 backdrops[i].loaded = false; 76 }
75 77 FOR_NB_SCREENS(i)
78 current_lcd_backdrop[i] = -1;
79 handle_being_loaded = -1;
80 first_go = false;
76 } 81 }
77 first_go = false;
78 FOR_NB_SCREENS(i)
79 current_lcd_backdrop[i] = -1;
80 handle_being_loaded = -1;
81} 82}
82 83
83int skin_backdrop_assign(char* backdrop, char *bmpdir, 84int skin_backdrop_assign(char* backdrop, char *bmpdir,
@@ -101,22 +102,26 @@ int skin_backdrop_assign(char* backdrop, char *bmpdir,
101 for (i=0; i<NB_BDROPS; i++) 102 for (i=0; i<NB_BDROPS; i++)
102 { 103 {
103 if (!backdrops[i].name[0] && free < 0) 104 if (!backdrops[i].name[0] && free < 0)
105 {
104 free = i; 106 free = i;
105 if (!strcmp(backdrops[i].name, filename) && backdrops[i].screen == screen) 107 break;
108 }
109 else if (!strcmp(backdrops[i].name, filename) && backdrops[i].screen == screen)
106 { 110 {
111 backdrops[i].ref_count++;
107 break; 112 break;
108 } 113 }
109 } 114 }
110 if (i < NB_BDROPS) 115 if (free >= 0)
111 return i;
112 else if (free >= 0)
113 { 116 {
114 strlcpy(backdrops[free].name, filename, 117 strlcpy(backdrops[free].name, filename, MAX_PATH);
115 sizeof (backdrops[free].name));
116 backdrops[free].buffer = NULL; 118 backdrops[free].buffer = NULL;
117 backdrops[free].screen = screen; 119 backdrops[free].screen = screen;
120 backdrops[free].ref_count = 1;
118 return free; 121 return free;
119 } 122 }
123 else if (i < NB_BDROPS)
124 return i;
120 return -1; 125 return -1;
121} 126}
122 127
@@ -188,10 +193,17 @@ void skin_backdrop_show(int backdrop_id)
188 193
189void skin_backdrop_unload(int backdrop_id) 194void skin_backdrop_unload(int backdrop_id)
190{ 195{
191 if (backdrops[backdrop_id].buflib_handle > 0) 196 backdrops[backdrop_id].ref_count--;
192 core_free(backdrops[backdrop_id].buflib_handle); 197 if (backdrops[backdrop_id].ref_count <= 0)
193 backdrops[backdrop_id].buffer = NULL; 198 {
194 backdrops[backdrop_id].buflib_handle = -1; 199 if (backdrops[backdrop_id].buflib_handle > 0)
200 core_free(backdrops[backdrop_id].buflib_handle);
201 backdrops[backdrop_id].buffer = NULL;
202 backdrops[backdrop_id].buflib_handle = -1;
203 backdrops[backdrop_id].loaded = false;
204 backdrops[backdrop_id].name[0] = '\0';
205 backdrops[backdrop_id].ref_count = 0;
206 }
195} 207}
196 208
197void skin_backdrop_load_setting(void) 209void skin_backdrop_load_setting(void)
diff --git a/apps/gui/skin_engine/skin_engine.c b/apps/gui/skin_engine/skin_engine.c
index c6791cac09..ce6c985e16 100644
--- a/apps/gui/skin_engine/skin_engine.c
+++ b/apps/gui/skin_engine/skin_engine.c
@@ -38,18 +38,15 @@
38#include "skin_buffer.h" 38#include "skin_buffer.h"
39#include "statusbar-skinned.h" 39#include "statusbar-skinned.h"
40 40
41static bool skins_initialising = true; 41#define FAILSAFENAME "rockbox_failsafe"
42
43/* App uses the host malloc to manage the buffer */
44void theme_init_buffer(void)
45{
46 skins_initialising = false;
47}
48 42
49void skin_data_free_buflib_allocs(struct wps_data *wps_data); 43void skin_data_free_buflib_allocs(struct wps_data *wps_data);
50char* wps_default_skin(enum screen_type screen); 44char* wps_default_skin(enum screen_type screen);
51char* default_radio_skin(enum screen_type screen); 45char* default_radio_skin(enum screen_type screen);
52 46
47static char* get_skin_filename(char *buf, size_t buf_size,
48 enum skinnable_screens skin, enum screen_type screen);
49
53struct wps_state wps_state = { .id3 = NULL }; 50struct wps_state wps_state = { .id3 = NULL };
54static struct gui_skin_helper { 51static struct gui_skin_helper {
55 int (*preproccess)(enum screen_type screen, struct wps_data *data); 52 int (*preproccess)(enum screen_type screen, struct wps_data *data);
@@ -62,82 +59,110 @@ static struct gui_skin_helper {
62 [FM_SCREEN] = { NULL, NULL, default_radio_skin } 59 [FM_SCREEN] = { NULL, NULL, default_radio_skin }
63#endif 60#endif
64}; 61};
65 62
66static struct gui_skin { 63static struct gui_skin {
64 char filename[MAX_PATH];
67 struct gui_wps gui_wps; 65 struct gui_wps gui_wps;
68 struct wps_data data; 66 struct wps_data data;
69 char *buffer_start; 67 char *buffer_start;
70 size_t buffer_usage; 68 size_t buffer_usage;
71 69 bool failsafe_loaded;
70
72 bool needs_full_update; 71 bool needs_full_update;
73} skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS]; 72} skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS];
74 73
75 74
76void gui_sync_skin_init(void) 75void gui_skin_reset(struct gui_skin *skin)
77{ 76{
78 int j; 77 skin->filename[0] = '\0';
79 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++) 78 skin->buffer_start = NULL;
80 { 79 skin->failsafe_loaded = false;
81 FOR_NB_SCREENS(i) 80 skin->needs_full_update = true;
82 { 81 skin->gui_wps.data = &skin->data;
83 skins[j][i].buffer_start = NULL; 82 memset(skin->gui_wps.data, 0, sizeof(struct wps_data));
84 skins[j][i].needs_full_update = true; 83 skin->data.wps_loaded = false;
85 skins[j][i].gui_wps.data = &skins[j][i].data; 84 skin->data.buflib_handle = -1;
86 skins[j][i].gui_wps.display = &screens[i]; 85 skin->data.tree = -1;
87 memset(skins[j][i].gui_wps.data, 0, sizeof(struct wps_data));
88 skins[j][i].data.wps_loaded = false;
89 skins[j][i].data.buflib_handle = -1;
90 skins[j][i].data.tree = -1;
91#ifdef HAVE_TOUCHSCREEN 86#ifdef HAVE_TOUCHSCREEN
92 skins[j][i].data.touchregions = -1; 87 skin->data.touchregions = -1;
93#endif 88#endif
94#ifdef HAVE_SKIN_VARIABLES 89#ifdef HAVE_SKIN_VARIABLES
95 skins[j][i].data.skinvars = -1; 90 skin->data.skinvars = -1;
96#endif 91#endif
97#ifdef HAVE_LCD_BITMAP 92#ifdef HAVE_LCD_BITMAP
98 skins[j][i].data.font_ids = -1; 93 skin->data.font_ids = -1;
99 skins[j][i].data.images = -1; 94 skin->data.images = -1;
100#endif 95#endif
101#ifdef HAVE_ALBUMART 96#ifdef HAVE_ALBUMART
102 skins[j][i].data.albumart = -1; 97 skin->data.albumart = -1;
103 skins[j][i].data.playback_aa_slot = -1; 98 skin->data.playback_aa_slot = -1;
99#endif
100#ifdef HAVE_BACKDROP_IMAGE
101 skin->gui_wps.data->backdrop_id = -1;
104#endif 102#endif
105 }
106 }
107} 103}
108 104
109void skin_unload_all(void) 105void gui_sync_skin_init(void)
110{ 106{
111 int j; 107 int j;
112
113 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++) 108 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
114 { 109 {
115 FOR_NB_SCREENS(i) 110 FOR_NB_SCREENS(i)
111 {
116 skin_data_free_buflib_allocs(&skins[j][i].data); 112 skin_data_free_buflib_allocs(&skins[j][i].data);
113 gui_skin_reset(&skins[j][i]);
114 skins[j][i].gui_wps.display = &screens[i];
115 }
117 } 116 }
117}
118 118
119#ifdef HAVE_LCD_BITMAP 119void skin_unload_all(void)
120 skin_backdrop_init(); 120{
121#endif
122 gui_sync_skin_init(); 121 gui_sync_skin_init();
123} 122}
124 123
125void settings_apply_skins(void) 124void settings_apply_skins(void)
126{ 125{
127 int i; 126 int i;
127 char filename[MAX_PATH];
128 static bool first_run = true;
128 129
129 skin_unload_all(); 130#ifdef HAVE_LCD_BITMAP
131 skin_backdrop_init();
132#endif
130 /* Make sure each skin is loaded */ 133 /* Make sure each skin is loaded */
131 for (i=0; i<SKINNABLE_SCREENS_COUNT; i++) 134 for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
132 { 135 {
133 FOR_NB_SCREENS(j) 136 FOR_NB_SCREENS(j)
134 skin_get_gwps(i, j); 137 {
135 } 138 bool load = false;
139 get_skin_filename(filename, MAX_PATH, i,j);
140
141 if (filename[0] && (strcmp(filename, skins[i][j].filename) || skins[i][j].failsafe_loaded))
142 load = true;
143 else if (first_run || (!filename[0] && !skins[i][j].failsafe_loaded))
144 load = true;
145
146 if (load)
147 {
148 if (!first_run)
149 {
150 skin_data_free_buflib_allocs(&skins[i][j].data);
136#ifdef HAVE_BACKDROP_IMAGE 151#ifdef HAVE_BACKDROP_IMAGE
137 skin_backdrops_preload(); /* should maybe check the retval here... */ 152 if (skins[i][j].data.backdrop_id >= 0)
153 skin_backdrop_unload(skins[i][j].data.backdrop_id);
138#endif 154#endif
155 }
156 gui_skin_reset(&skins[i][j]);
157 skins[i][j].gui_wps.display = &screens[j];
158 skin_get_gwps(i, j);
159 }
160 }
161 }
162 first_run = false;
139 viewportmanager_theme_changed(THEME_STATUSBAR); 163 viewportmanager_theme_changed(THEME_STATUSBAR);
140#ifdef HAVE_BACKDROP_IMAGE 164#ifdef HAVE_BACKDROP_IMAGE
165 skin_backdrops_preload(); /* should maybe check the retval here... */
141 FOR_NB_SCREENS(i) 166 FOR_NB_SCREENS(i)
142 skin_backdrop_show(sb_get_backdrop(i)); 167 skin_backdrop_show(sb_get_backdrop(i));
143#endif 168#endif
@@ -147,104 +172,100 @@ void skin_load(enum skinnable_screens skin, enum screen_type screen,
147 const char *buf, bool isfile) 172 const char *buf, bool isfile)
148{ 173{
149 bool loaded = false; 174 bool loaded = false;
150 175
151 if (skin_helpers[skin].preproccess) 176 if (skin_helpers[skin].preproccess)
152 skin_helpers[skin].preproccess(screen, &skins[skin][screen].data); 177 skin_helpers[skin].preproccess(screen, &skins[skin][screen].data);
153 178
154 if (buf && *buf) 179 if (buf && *buf)
155 loaded = skin_data_load(screen, &skins[skin][screen].data, buf, isfile); 180 loaded = skin_data_load(screen, &skins[skin][screen].data, buf, isfile);
181 if (loaded)
182 strcpy(skins[skin][screen].filename, buf);
156 183
157 if (!loaded && skin_helpers[skin].default_skin) 184 if (!loaded && skin_helpers[skin].default_skin)
185 {
158 loaded = skin_data_load(screen, &skins[skin][screen].data, 186 loaded = skin_data_load(screen, &skins[skin][screen].data,
159 skin_helpers[skin].default_skin(screen), false); 187 skin_helpers[skin].default_skin(screen), false);
160 188 skins[skin][screen].failsafe_loaded = loaded;
189 }
190
161 skins[skin][screen].needs_full_update = true; 191 skins[skin][screen].needs_full_update = true;
162 if (skin_helpers[skin].postproccess) 192 if (skin_helpers[skin].postproccess)
163 skin_helpers[skin].postproccess(screen, &skins[skin][screen].data); 193 skin_helpers[skin].postproccess(screen, &skins[skin][screen].data);
164} 194}
165 195
166static bool loading_a_sbs = false; 196static char* get_skin_filename(char *buf, size_t buf_size,
167struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen) 197 enum skinnable_screens skin, enum screen_type screen)
168{ 198{
169 if (!loading_a_sbs && skins[skin][screen].data.wps_loaded == false) 199 (void)screen;
200 char *setting = NULL, *ext = NULL;
201 switch (skin)
170 { 202 {
171 char buf[MAX_PATH*2]; 203 case CUSTOM_STATUSBAR:
172 char *setting = NULL, *ext = NULL;
173 switch (skin)
174 {
175 case CUSTOM_STATUSBAR:
176#ifdef HAVE_LCD_BITMAP
177 if (skins_initialising)
178 {
179 /* still loading, buffers not initialised yet,
180 * viewport manager calls into the sbs code, not really
181 * caring if the sbs has loaded or not, so just return
182 * the gwps, this is safe. */
183 return &skins[skin][screen].gui_wps;
184 }
185 /* during the sbs load it will call skin_get_gwps() a few times
186 * which will eventually stkov the viewportmanager, so make
187 * sure we don't let that happen */
188 loading_a_sbs = true;
189#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1 204#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
190 if (screen == SCREEN_REMOTE) 205 if (screen == SCREEN_REMOTE)
191 { 206 {
192 setting = global_settings.rsbs_file; 207 setting = global_settings.rsbs_file;
193 ext = "rsbs"; 208 ext = "rsbs";
194 } 209 }
195 else 210 else
196#endif 211#endif
197 { 212 {
198 setting = global_settings.sbs_file; 213 setting = global_settings.sbs_file;
199 ext = "sbs"; 214 ext = "sbs";
200 } 215 }
201#else 216 break;
202 return &skins[skin][screen].gui_wps; 217 case WPS:
203#endif /* HAVE_LCD_BITMAP */
204 break;
205 case WPS:
206#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1 218#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
207 if (screen == SCREEN_REMOTE) 219 if (screen == SCREEN_REMOTE)
208 { 220 {
209 setting = global_settings.rwps_file; 221 setting = global_settings.rwps_file;
210 ext = "rwps"; 222 ext = "rwps";
211 } 223 }
212 else 224 else
213#endif 225#endif
214 { 226 {
215 setting = global_settings.wps_file; 227 setting = global_settings.wps_file;
216 ext = "wps"; 228 ext = "wps";
217 } 229 }
218 break; 230 break;
219#if CONFIG_TUNER 231#if CONFIG_TUNER
220 case FM_SCREEN: 232 case FM_SCREEN:
221#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1 233#if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
222 if (screen == SCREEN_REMOTE) 234 if (screen == SCREEN_REMOTE)
223 { 235 {
224 setting = global_settings.rfms_file; 236 setting = global_settings.rfms_file;
225 ext = "rfms"; 237 ext = "rfms";
226 } 238 }
227 else 239 else
228#endif 240#endif
229 { 241 {
230 setting = global_settings.fms_file; 242 setting = global_settings.fms_file;
231 ext = "fms"; 243 ext = "fms";
232 } 244 }
233 break; 245 break;
234#endif 246#endif
235 default: 247 default:
236 return NULL; 248 return NULL;
237 } 249 }
238 250
239 buf[0] = '\0'; /* force it to reload the default */ 251 buf[0] = '\0'; /* force it to reload the default */
240 if (strcmp(setting, "rockbox_failsafe")) 252 if (strcmp(setting, FAILSAFENAME) && strcmp(setting, "-"))
241 { 253 {
242 snprintf(buf, sizeof buf, WPS_DIR "/%s.%s", setting, ext); 254 snprintf(buf, buf_size, WPS_DIR "/%s.%s", setting, ext);
243 } 255 }
256 return buf;
257}
258
259struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen)
260{
261 if (skins[skin][screen].data.wps_loaded == false)
262 {
263 char filename[MAX_PATH];
264 char *buf = get_skin_filename(filename, MAX_PATH, skin, screen);
244 cpu_boost(true); 265 cpu_boost(true);
266 skins[skin][screen].filename[0] = '\0';
245 skin_load(skin, screen, buf, true); 267 skin_load(skin, screen, buf, true);
246 cpu_boost(false); 268 cpu_boost(false);
247 loading_a_sbs = false;
248 } 269 }
249 return &skins[skin][screen].gui_wps; 270 return &skins[skin][screen].gui_wps;
250} 271}
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index ef365720b4..0118977be5 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -1687,7 +1687,7 @@ static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1687 list = SKINOFFSETTOPTR(skin_buffer, list->next); 1687 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1688 } 1688 }
1689 1689
1690#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 1690#ifdef HAVE_BACKDROP_IMAGE
1691 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen); 1691 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1692#endif /* has backdrop support */ 1692#endif /* has backdrop support */
1693 return retval; 1693 return retval;
@@ -1986,7 +1986,7 @@ static int skin_element_callback(struct skin_element* element, void* data)
1986 case SKIN_TOKEN_FILE_DIRECTORY: 1986 case SKIN_TOKEN_FILE_DIRECTORY:
1987 token->value.i = get_param(element, 0)->data.number; 1987 token->value.i = get_param(element, 0)->data.number;
1988 break; 1988 break;
1989#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 1989#ifdef HAVE_BACKDROP_IMAGE
1990 case SKIN_TOKEN_VIEWPORT_FGCOLOUR: 1990 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
1991 case SKIN_TOKEN_VIEWPORT_BGCOLOUR: 1991 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
1992 function = parse_viewportcolour; 1992 function = parse_viewportcolour;