Check for the magic file "/.rockbox/skin_buffer_size.txt" on bootup which can have...
[maemo-rb.git] / apps / gui / skin_engine / skin_engine.c
blob0d86cc289fed03af333d5630e803b83d978623d6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Stuart Martin
11 * RTC config saving code (C) 2002 by hessu@hes.iki.fi
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdio.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <limits.h>
26 #include "inttypes.h"
27 #include "config.h"
28 #include "core_alloc.h"
29 #include "action.h"
30 #include "crc32.h"
31 #include "settings.h"
32 #include "wps.h"
33 #include "file.h"
34 #include "buffer.h"
35 #if CONFIG_TUNER
36 #include "radio.h"
37 #endif
38 #include "skin_engine.h"
39 #include "skin_buffer.h"
40 #include "statusbar-skinned.h"
42 static bool skins_initialising = true;
44 /* App uses the host malloc to manage the buffer */
45 #ifdef APPLICATION
46 #define skin_buffer NULL
47 void theme_init_buffer(void)
49 skins_initialising = false;
51 #else
52 static size_t skin_buffer_size;
53 static char *skin_buffer = NULL;
54 static int buflib_move_callback(int handle, void* current, void* new)
56 (void)current;
57 (void)new;
58 return BUFLIB_CB_CANNOT_MOVE;
60 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
62 void theme_init_buffer(void)
64 int fd;
65 size_t size = SKIN_BUFFER_SIZE;
66 fd = open_utf8(ROCKBOX_DIR "/skin_buffer_size.txt", O_RDONLY);
67 if (fd >= 0)
69 char buf[32];
70 read(fd, buf, sizeof(buf));
71 if (buf[0] >= '0' && buf[0] <= '9')
72 size = atoi(buf)*1024;
73 close(fd);
75 skin_buffer = core_get_data(core_alloc_ex("skin buffer", size, &buflib_ops));
76 skin_buffer_size = size;
77 skins_initialising = false;
79 #endif
81 void skin_data_free_buflib_allocs(struct wps_data *wps_data);
82 char* wps_default_skin(enum screen_type screen);
83 char* default_radio_skin(enum screen_type screen);
85 struct wps_state wps_state = { .id3 = NULL };
86 static struct gui_skin_helper {
87 int (*preproccess)(enum screen_type screen, struct wps_data *data);
88 int (*postproccess)(enum screen_type screen, struct wps_data *data);
89 char* (*default_skin)(enum screen_type screen);
90 } skin_helpers[SKINNABLE_SCREENS_COUNT] = {
91 [CUSTOM_STATUSBAR] = { sb_preproccess, sb_postproccess, sb_create_from_settings },
92 [WPS] = { NULL, NULL, wps_default_skin },
93 #if CONFIG_TUNER
94 [FM_SCREEN] = { NULL, NULL, default_radio_skin }
95 #endif
98 static struct gui_skin {
99 struct gui_wps gui_wps;
100 struct wps_data data;
101 char *buffer_start;
102 size_t buffer_usage;
104 bool needs_full_update;
105 } skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS];
108 void gui_sync_skin_init(void)
110 int i, j;
111 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
113 FOR_NB_SCREENS(i)
115 skins[j][i].buffer_start = NULL;
116 skins[j][i].needs_full_update = true;
117 skins[j][i].gui_wps.data = &skins[j][i].data;
118 skins[j][i].gui_wps.display = &screens[i];
119 memset(skins[j][i].gui_wps.data, 0, sizeof(struct wps_data));
120 skins[j][i].data.wps_loaded = false;
121 #ifdef HAVE_ALBUMART
122 skins[j][i].data.albumart = NULL;
123 skins[j][i].data.playback_aa_slot = -1;
124 #endif
129 void settings_apply_skins(void)
131 int i, j;
133 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
135 FOR_NB_SCREENS(i)
136 skin_data_free_buflib_allocs(&skins[j][i].data);
139 skin_buffer_init(skin_buffer, skin_buffer_size);
141 #ifdef HAVE_LCD_BITMAP
142 skin_backdrop_init();
143 #endif
144 gui_sync_skin_init();
146 /* Make sure each skin is loaded */
147 for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
149 FOR_NB_SCREENS(j)
150 skin_get_gwps(i, j);
152 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
153 skin_backdrops_preload(); /* should maybe check the retval here... */
154 #endif
155 viewportmanager_theme_changed(THEME_STATUSBAR);
156 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
157 FOR_NB_SCREENS(i)
158 skin_backdrop_show(sb_get_backdrop(i));
159 #endif
162 void skin_load(enum skinnable_screens skin, enum screen_type screen,
163 const char *buf, bool isfile)
165 bool loaded = false;
167 if (skin_helpers[skin].preproccess)
168 skin_helpers[skin].preproccess(screen, &skins[skin][screen].data);
170 if (buf && *buf)
171 loaded = skin_data_load(screen, &skins[skin][screen].data, buf, isfile);
173 if (!loaded && skin_helpers[skin].default_skin)
174 loaded = skin_data_load(screen, &skins[skin][screen].data,
175 skin_helpers[skin].default_skin(screen), false);
177 skins[skin][screen].needs_full_update = true;
178 if (skin_helpers[skin].postproccess)
179 skin_helpers[skin].postproccess(screen, &skins[skin][screen].data);
182 static bool loading_a_sbs = false;
183 struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen)
185 if (!loading_a_sbs && skins[skin][screen].data.wps_loaded == false)
187 char buf[MAX_PATH*2];
188 char *setting = NULL, *ext = NULL;
189 switch (skin)
191 case CUSTOM_STATUSBAR:
192 #ifdef HAVE_LCD_BITMAP
193 if (skins_initialising)
195 /* still loading, buffers not initialised yet,
196 * viewport manager calls into the sbs code, not really
197 * caring if the sbs has loaded or not, so just return
198 * the gwps, this is safe. */
199 return &skins[skin][screen].gui_wps;
201 /* during the sbs load it will call skin_get_gwps() a few times
202 * which will eventually stkov the viewportmanager, so make
203 * sure we don't let that happen */
204 loading_a_sbs = true;
205 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
206 if (screen == SCREEN_REMOTE)
208 setting = global_settings.rsbs_file;
209 ext = "rsbs";
211 else
212 #endif
214 setting = global_settings.sbs_file;
215 ext = "sbs";
217 #else
218 return &skins[skin][screen].gui_wps;
219 #endif /* HAVE_LCD_BITMAP */
220 break;
221 case WPS:
222 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
223 if (screen == SCREEN_REMOTE)
225 setting = global_settings.rwps_file;
226 ext = "rwps";
228 else
229 #endif
231 setting = global_settings.wps_file;
232 ext = "wps";
234 break;
235 #if CONFIG_TUNER
236 case FM_SCREEN:
237 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
238 if (screen == SCREEN_REMOTE)
240 setting = global_settings.rfms_file;
241 ext = "rfms";
243 else
244 #endif
246 setting = global_settings.fms_file;
247 ext = "fms";
249 break;
250 #endif
251 default:
252 return NULL;
255 buf[0] = '\0'; /* force it to reload the default */
256 if (strcmp(setting, "rockbox_failsafe"))
258 snprintf(buf, sizeof buf, WPS_DIR "/%s.%s", setting, ext);
260 cpu_boost(true);
261 skin_load(skin, screen, buf, true);
262 cpu_boost(false);
263 loading_a_sbs = false;
266 return &skins[skin][screen].gui_wps;
269 struct wps_state *skin_get_global_state(void)
271 return &wps_state;
274 /* This is called to find out if we the screen needs a full update.
275 * if true you MUST do a full update as the next call will return false */
276 bool skin_do_full_update(enum skinnable_screens skin,
277 enum screen_type screen)
279 bool ret = skins[skin][screen].needs_full_update;
280 skins[skin][screen].needs_full_update = false;
281 return ret;
284 /* tell a skin to do a full update next time */
285 void skin_request_full_update(enum skinnable_screens skin)
287 int i;
288 FOR_NB_SCREENS(i)
289 skins[skin][i].needs_full_update = true;