fix FS#12295
[maemo-rb.git] / apps / gui / skin_engine / skin_engine.c
blob89230cbcb344f47846ff651b10a431c7d9df3001
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 "misc.h"
31 #include "crc32.h"
32 #include "settings.h"
33 #include "wps.h"
34 #include "file.h"
35 #include "buffer.h"
36 #if CONFIG_TUNER
37 #include "radio.h"
38 #endif
39 #include "skin_engine.h"
40 #include "skin_buffer.h"
41 #include "statusbar-skinned.h"
43 static bool skins_initialising = true;
45 /* App uses the host malloc to manage the buffer */
46 #ifdef APPLICATION
47 #define skin_buffer NULL
48 #define skin_buffer_size 0
49 void theme_init_buffer(void)
51 skins_initialising = false;
53 #else
54 static size_t skin_buffer_size;
55 static char *skin_buffer = NULL;
56 static int buflib_move_callback(int handle, void* current, void* new)
58 (void)handle;
59 (void)current;
60 (void)new;
61 return BUFLIB_CB_CANNOT_MOVE;
63 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL};
65 void theme_init_buffer(void)
67 int fd;
68 size_t size = SKIN_BUFFER_SIZE;
69 fd = open_utf8(ROCKBOX_DIR "/skin_buffer_size.txt", O_RDONLY);
70 if (fd >= 0)
72 char buf[32];
73 read(fd, buf, sizeof(buf));
74 if (buf[0] >= '0' && buf[0] <= '9')
75 size = atoi(buf)*1024;
76 close(fd);
78 skin_buffer = core_get_data(core_alloc_ex("skin buffer", size, &buflib_ops));
79 skin_buffer_size = size;
80 skins_initialising = false;
82 #endif
84 void skin_data_free_buflib_allocs(struct wps_data *wps_data);
85 char* wps_default_skin(enum screen_type screen);
86 char* default_radio_skin(enum screen_type screen);
88 struct wps_state wps_state = { .id3 = NULL };
89 static struct gui_skin_helper {
90 int (*preproccess)(enum screen_type screen, struct wps_data *data);
91 int (*postproccess)(enum screen_type screen, struct wps_data *data);
92 char* (*default_skin)(enum screen_type screen);
93 } skin_helpers[SKINNABLE_SCREENS_COUNT] = {
94 [CUSTOM_STATUSBAR] = { sb_preproccess, sb_postproccess, sb_create_from_settings },
95 [WPS] = { NULL, NULL, wps_default_skin },
96 #if CONFIG_TUNER
97 [FM_SCREEN] = { NULL, NULL, default_radio_skin }
98 #endif
101 static struct gui_skin {
102 struct gui_wps gui_wps;
103 struct wps_data data;
104 char *buffer_start;
105 size_t buffer_usage;
107 bool needs_full_update;
108 } skins[SKINNABLE_SCREENS_COUNT][NB_SCREENS];
111 void gui_sync_skin_init(void)
113 int i, j;
114 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
116 FOR_NB_SCREENS(i)
118 skins[j][i].buffer_start = NULL;
119 skins[j][i].needs_full_update = true;
120 skins[j][i].gui_wps.data = &skins[j][i].data;
121 skins[j][i].gui_wps.display = &screens[i];
122 memset(skins[j][i].gui_wps.data, 0, sizeof(struct wps_data));
123 skins[j][i].data.wps_loaded = false;
124 #ifdef HAVE_ALBUMART
125 skins[j][i].data.albumart = NULL;
126 skins[j][i].data.playback_aa_slot = -1;
127 #endif
132 void skin_unload_all(void)
134 int i, j;
136 for(j=0; j<SKINNABLE_SCREENS_COUNT; j++)
138 FOR_NB_SCREENS(i)
139 skin_data_free_buflib_allocs(&skins[j][i].data);
142 skin_buffer_init(skin_buffer, skin_buffer_size);
143 #ifdef HAVE_LCD_BITMAP
144 skin_backdrop_init();
145 #endif
146 gui_sync_skin_init();
149 void settings_apply_skins(void)
151 int i, j;
153 skin_unload_all();
154 /* Make sure each skin is loaded */
155 for (i=0; i<SKINNABLE_SCREENS_COUNT; i++)
157 FOR_NB_SCREENS(j)
158 skin_get_gwps(i, j);
160 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
161 skin_backdrops_preload(); /* should maybe check the retval here... */
162 #endif
163 viewportmanager_theme_changed(THEME_STATUSBAR);
164 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
165 FOR_NB_SCREENS(i)
166 skin_backdrop_show(sb_get_backdrop(i));
167 #endif
170 void skin_load(enum skinnable_screens skin, enum screen_type screen,
171 const char *buf, bool isfile)
173 bool loaded = false;
175 if (skin_helpers[skin].preproccess)
176 skin_helpers[skin].preproccess(screen, &skins[skin][screen].data);
178 if (buf && *buf)
179 loaded = skin_data_load(screen, &skins[skin][screen].data, buf, isfile);
181 if (!loaded && skin_helpers[skin].default_skin)
182 loaded = skin_data_load(screen, &skins[skin][screen].data,
183 skin_helpers[skin].default_skin(screen), false);
185 skins[skin][screen].needs_full_update = true;
186 if (skin_helpers[skin].postproccess)
187 skin_helpers[skin].postproccess(screen, &skins[skin][screen].data);
190 static bool loading_a_sbs = false;
191 struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen)
193 if (!loading_a_sbs && skins[skin][screen].data.wps_loaded == false)
195 char buf[MAX_PATH*2];
196 char *setting = NULL, *ext = NULL;
197 switch (skin)
199 case CUSTOM_STATUSBAR:
200 #ifdef HAVE_LCD_BITMAP
201 if (skins_initialising)
203 /* still loading, buffers not initialised yet,
204 * viewport manager calls into the sbs code, not really
205 * caring if the sbs has loaded or not, so just return
206 * the gwps, this is safe. */
207 return &skins[skin][screen].gui_wps;
209 /* during the sbs load it will call skin_get_gwps() a few times
210 * which will eventually stkov the viewportmanager, so make
211 * sure we don't let that happen */
212 loading_a_sbs = true;
213 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
214 if (screen == SCREEN_REMOTE)
216 setting = global_settings.rsbs_file;
217 ext = "rsbs";
219 else
220 #endif
222 setting = global_settings.sbs_file;
223 ext = "sbs";
225 #else
226 return &skins[skin][screen].gui_wps;
227 #endif /* HAVE_LCD_BITMAP */
228 break;
229 case WPS:
230 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
231 if (screen == SCREEN_REMOTE)
233 setting = global_settings.rwps_file;
234 ext = "rwps";
236 else
237 #endif
239 setting = global_settings.wps_file;
240 ext = "wps";
242 break;
243 #if CONFIG_TUNER
244 case FM_SCREEN:
245 #if defined(HAVE_REMOTE_LCD) && NB_SCREENS > 1
246 if (screen == SCREEN_REMOTE)
248 setting = global_settings.rfms_file;
249 ext = "rfms";
251 else
252 #endif
254 setting = global_settings.fms_file;
255 ext = "fms";
257 break;
258 #endif
259 default:
260 return NULL;
263 buf[0] = '\0'; /* force it to reload the default */
264 if (strcmp(setting, "rockbox_failsafe"))
266 snprintf(buf, sizeof buf, WPS_DIR "/%s.%s", setting, ext);
268 cpu_boost(true);
269 skin_load(skin, screen, buf, true);
270 cpu_boost(false);
271 loading_a_sbs = false;
274 return &skins[skin][screen].gui_wps;
277 struct wps_state *skin_get_global_state(void)
279 return &wps_state;
282 /* This is called to find out if we the screen needs a full update.
283 * if true you MUST do a full update as the next call will return false */
284 bool skin_do_full_update(enum skinnable_screens skin,
285 enum screen_type screen)
287 bool ret = skins[skin][screen].needs_full_update;
288 skins[skin][screen].needs_full_update = false;
289 return ret;
292 /* tell a skin to do a full update next time */
293 void skin_request_full_update(enum skinnable_screens skin)
295 int i;
296 FOR_NB_SCREENS(i)
297 skins[skin][i].needs_full_update = true;