diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c
index 304ebf1..0b843a5 100644
--- a/apps/gui/skin_engine/skin_render.c
+++ b/apps/gui/skin_engine/skin_render.c
@@ -27,6 +27,10 @@
#include "strlcat.h"
#include "config.h"
+
+#include "thread.h"
+extern struct thread_entry threads[MAXTHREADS];
+
#include "kernel.h"
#ifdef HAVE_ALBUMART
#include "albumart.h"
@@ -68,8 +72,8 @@ struct skin_draw_info {
int offset; /* used by the playlist viewer */
};
-typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info);
-bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info);
+static int alternator_change_line(struct skin_element* alternator,
+ struct skin_draw_info *info, bool* line_changed);
#ifdef HAVE_LCD_BITMAP
static void skin_render_playlistviewer(struct playlistviewer* viewer,
@@ -375,14 +379,29 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
{
bool needs_update = false;
int last_value, value;
+ bool in_changed_alternator = false;
+ struct skin_element *child;
+ struct conditional *conditional;
+ int old_refresh_mode = info->refresh_type;
+
+ if (line->type == LINE_ALTERNATOR)
+ {
+ line = line->children[alternator_change_line(line, info,
+ &in_changed_alternator)];
+ if (line->children_count == 0)
+ return in_changed_alternator;
+ if (in_changed_alternator)
+ {
+ info->refresh_type = SKIN_REFRESH_ALL;
+ info->force_redraw = true;
+ }
+
+ }
if (line->children_count == 0)
return false; /* empty line, do nothing */
+ child = line->children[0];
- struct skin_element *child = line->children[0];
- struct conditional *conditional;
- skin_render_func func = skin_render_line;
- int old_refresh_mode = info->refresh_type;
while (child)
{
switch (child->type)
@@ -411,20 +430,15 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
if (last_value >= 0 && value != last_value && last_value < child->children_count)
do_tags_in_hidden_conditional(child->children[last_value], info);
}
- if (child->children[value]->type == LINE_ALTERNATOR)
- {
- func = skin_render_alternator;
- }
- else if (child->children[value]->type == LINE)
- func = skin_render_line;
-
if (value != last_value)
{
info->refresh_type = SKIN_REFRESH_ALL;
info->force_redraw = true;
}
-
- if (func(child->children[value], info))
+ struct thread_entry *t = &threads[thread_get_current()];
+ if (thread_stack_usage(t) > 90)
+ panicf("skin engine: rendering stack overflow");
+ if (skin_render_line(child->children[value], info))
needs_update = true;
else
needs_update = needs_update || (last_value != value);
@@ -475,6 +489,12 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
child = child->next;
}
+ if (in_changed_alternator)
+ {
+ info->refresh_type = old_refresh_mode;
+ info->force_redraw = false;
+ needs_update = true;
+ }
return needs_update;
}
@@ -483,6 +503,8 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line)
struct skin_element *element=line;
struct wps_token *token;
int retval = DEFAULT_SUBLINE_TIME_MULTIPLIER*TIMEOUT_UNIT;
+restart: /* we are really using tail recursion so do it with a messy goto
+ to prevent stack overusage */
if (element->type == LINE)
{
if (element->children_count == 0)
@@ -504,9 +526,8 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line)
element->children_count);
if (val >= 0)
{
- retval = get_subline_timeout(gwps, element->children[val]);
- if (retval >= 0)
- return retval;
+ element = element->children[val];
+ goto restart;
}
}
element = element->next;
@@ -514,11 +535,11 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line)
return retval;
}
-bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info)
+static int alternator_change_line(struct skin_element* element,
+ struct skin_draw_info *info, bool* line_changed)
{
bool changed_lines = false;
struct line_alternator *alternator = (struct line_alternator*)element->data;
- unsigned old_refresh = info->refresh_type;
if (info->refresh_type == SKIN_REFRESH_ALL)
{
alternator->current_line = element->children_count-1;
@@ -561,13 +582,9 @@ bool skin_render_alternator(struct skin_element* element, struct skin_draw_info
alternator->current_line = try_line;
alternator->next_change_tick = current_tick + rettimeout;
}
-
- info->refresh_type = SKIN_REFRESH_ALL;
- info->force_redraw = true;
}
- bool ret = skin_render_line(element->children[alternator->current_line], info);
- info->refresh_type = old_refresh;
- return changed_lines || ret;
+ *line_changed = changed_lines;
+ return alternator->current_line;
}
static void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps,
@@ -575,7 +592,6 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps *
{
struct screen *display = gwps->display;
char linebuf[MAX_LINE];
- skin_render_func func = skin_render_line;
struct skin_element* line = viewport;
struct skin_draw_info info = {
.gwps = gwps,
@@ -613,14 +629,8 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps *
align->left = info.buf;
align->center = NULL;
align->right = NULL;
-
-
- if (line->type == LINE_ALTERNATOR)
- func = skin_render_alternator;
- else if (line->type == LINE)
- func = skin_render_line;
-
- needs_update = func(line, &info);
+
+ needs_update = skin_render_line(line, &info);
/* only update if the line needs to be, and there is something to write */
if (refresh_type && needs_update)
@@ -722,7 +732,6 @@ static void skin_render_playlistviewer(struct playlistviewer* viewer,
{
struct screen *display = gwps->display;
char linebuf[MAX_LINE];
- skin_render_func func = skin_render_line;
struct skin_element* line;
struct skin_draw_info info = {
.gwps = gwps,
@@ -774,13 +783,7 @@ static void skin_render_playlistviewer(struct playlistviewer* viewer,
align->center = NULL;
align->right = NULL;
-
- if (line->type == LINE_ALTERNATOR)
- func = skin_render_alternator;
- else if (line->type == LINE)
- func = skin_render_line;
-
- needs_update = func(line, &info);
+ needs_update = skin_render_line(line, &info);
/* only update if the line needs to be, and there is something to write */
if (refresh_type && needs_update)