diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c
index 304ebf1..d0221a8 100644
--- a/apps/gui/skin_engine/skin_render.c
+++ b/apps/gui/skin_engine/skin_render.c
@@ -68,8 +68,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 +375,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 +426,13 @@ 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))
+ if (skin_render_line(child->children[value], info))
needs_update = true;
else
needs_update = needs_update || (last_value != value);
@@ -475,6 +483,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 +497,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 +520,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 +529,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 +576,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 +586,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 +623,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)
@@ -715,14 +719,13 @@ void skin_render(struct gui_wps *gwps, unsigned refresh_mode)
}
#ifdef HAVE_LCD_BITMAP
-static void skin_render_playlistviewer(struct playlistviewer* viewer,
+static __attribute__((noinline)) void skin_render_playlistviewer(struct playlistviewer* viewer,
struct gui_wps *gwps,
struct skin_viewport* skin_viewport,
unsigned long refresh_type)
{
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 +777,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)