(hopefully) Fix FS#12639 and other skin related buflib corruption issues.
[maemo-rb.git] / apps / gui / skin_engine / skin_parser.c
blobe364cf1c76f535cc63e411bf06ada0b052ab8a60
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
11 * 2010 Jonathan Gordon
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 ****************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "config.h"
27 #ifndef __PCTOOL__
28 #include "core_alloc.h"
29 #endif
30 #include "file.h"
31 #include "misc.h"
32 #include "plugin.h"
33 #include "viewport.h"
35 #include "skin_buffer.h"
36 #include "skin_debug.h"
37 #include "skin_parser.h"
38 #include "tag_table.h"
40 #ifdef __PCTOOL__
41 #ifdef WPSEDITOR
42 #include "proxy.h"
43 #include "sysfont.h"
44 #else
45 #include "action.h"
46 #include "checkwps.h"
47 #include "audio.h"
48 #define lang_is_rtl() (false)
49 #define DEBUGF printf
50 #endif /*WPSEDITOR*/
51 #else
52 #include "debug.h"
53 #include "language.h"
54 #endif /*__PCTOOL__*/
56 #include <ctype.h>
57 #include <stdbool.h>
58 #include "font.h"
60 #include "wps_internals.h"
61 #include "skin_engine.h"
62 #include "settings.h"
63 #include "settings_list.h"
64 #if CONFIG_TUNER
65 #include "radio.h"
66 #include "tuner.h"
67 #endif
69 #ifdef HAVE_LCD_BITMAP
70 #include "bmp.h"
71 #endif
73 #ifdef HAVE_ALBUMART
74 #include "playback.h"
75 #endif
77 #include "backdrop.h"
78 #include "statusbar-skinned.h"
80 #define WPS_ERROR_INVALID_PARAM -1
82 static char* skin_buffer = NULL;
83 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
84 static char *backdrop_filename;
85 #endif
87 static bool isdefault(struct skin_tag_parameter *param)
89 return param->type == DEFAULT;
92 static inline char*
93 get_param_text(struct skin_element *element, int param_number)
95 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
96 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.text);
99 static inline struct skin_element*
100 get_param_code(struct skin_element *element, int param_number)
102 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
103 return SKINOFFSETTOPTR(skin_buffer, params[param_number].data.code);
106 static inline struct skin_tag_parameter*
107 get_param(struct skin_element *element, int param_number)
109 struct skin_tag_parameter* params = SKINOFFSETTOPTR(skin_buffer, element->params);
110 return &params[param_number];
113 /* which screen are we parsing for? */
114 static enum screen_type curr_screen;
116 /* the current viewport */
117 static struct skin_element *curr_viewport_element;
118 static struct skin_viewport *curr_vp;
119 static struct skin_element *first_viewport;
121 static struct line *curr_line;
123 static int follow_lang_direction = 0;
125 typedef int (*parse_function)(struct skin_element *element,
126 struct wps_token *token,
127 struct wps_data *wps_data);
129 #ifdef HAVE_LCD_BITMAP
130 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
131 * chains require the order to be kept.
133 static void add_to_ll_chain(OFFSETTYPE(struct skin_token_list *) *listoffset,
134 struct skin_token_list *item)
136 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, *listoffset);
137 if (list == NULL)
139 *listoffset = PTRTOSKINOFFSET(skin_buffer, item);
141 else
143 while (SKINOFFSETTOPTR(skin_buffer, list->next))
144 list = SKINOFFSETTOPTR(skin_buffer, list->next);
145 list->next = PTRTOSKINOFFSET(skin_buffer, item);
149 #endif
152 void *skin_find_item(const char *label, enum skin_find_what what,
153 struct wps_data *data)
155 const char *itemlabel = NULL;
156 char *databuf = get_skin_buffer(data);
157 union {
158 struct skin_token_list *linkedlist;
159 struct skin_element *vplist;
160 } list = {NULL};
161 bool isvplist = false;
162 void *ret = NULL;
163 if (!databuf)
164 databuf = skin_buffer;
165 switch (what)
167 case SKIN_FIND_UIVP:
168 case SKIN_FIND_VP:
169 list.vplist = SKINOFFSETTOPTR(databuf, data->tree);
170 isvplist = true;
171 break;
172 #ifdef HAVE_LCD_BITMAP
173 case SKIN_FIND_IMAGE:
174 list.linkedlist = SKINOFFSETTOPTR(databuf, data->images);
175 break;
176 #endif
177 #ifdef HAVE_TOUCHSCREEN
178 case SKIN_FIND_TOUCHREGION:
179 list.linkedlist = SKINOFFSETTOPTR(databuf, data->touchregions);
180 break;
181 #endif
182 #ifdef HAVE_SKIN_VARIABLES
183 case SKIN_VARIABLE:
184 list.linkedlist = SKINOFFSETTOPTR(databuf, data->skinvars);
185 break;
186 #endif
189 while (list.linkedlist)
191 bool skip = false;
192 #ifdef HAVE_LCD_BITMAP
193 struct wps_token *token = NULL;
194 if (!isvplist)
195 token = SKINOFFSETTOPTR(databuf, list.linkedlist->token);
196 #endif
197 switch (what)
199 case SKIN_FIND_UIVP:
200 case SKIN_FIND_VP:
201 ret = SKINOFFSETTOPTR(databuf, list.vplist->data);
202 if (((struct skin_viewport *)ret)->label == VP_DEFAULT_LABEL)
203 itemlabel = VP_DEFAULT_LABEL_STRING;
204 else
205 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_viewport *)ret)->label);
206 skip = !(((struct skin_viewport *)ret)->is_infovp ==
207 (what==SKIN_FIND_UIVP));
208 break;
209 #ifdef HAVE_LCD_BITMAP
210 case SKIN_FIND_IMAGE:
211 ret = SKINOFFSETTOPTR(databuf, token->value.data);
212 itemlabel = SKINOFFSETTOPTR(databuf, ((struct gui_img *)ret)->label);
213 break;
214 #endif
215 #ifdef HAVE_TOUCHSCREEN
216 case SKIN_FIND_TOUCHREGION:
217 ret = SKINOFFSETTOPTR(databuf, token->value.data);
218 itemlabel = SKINOFFSETTOPTR(databuf, ((struct touchregion *)ret)->label);
219 break;
220 #endif
221 #ifdef HAVE_SKIN_VARIABLES
222 case SKIN_VARIABLE:
223 ret = SKINOFFSETTOPTR(databuf, token->value.data);
224 itemlabel = SKINOFFSETTOPTR(databuf, ((struct skin_var *)ret)->label);
225 break;
226 #endif
229 if (!skip && itemlabel && !strcmp(itemlabel, label))
231 return ret;
234 if (isvplist)
235 list.vplist = SKINOFFSETTOPTR(databuf, list.vplist->next);
236 else
237 list.linkedlist = SKINOFFSETTOPTR(databuf, list.linkedlist->next);
239 return NULL;
242 #ifdef HAVE_LCD_BITMAP
244 /* create and init a new wpsll item.
245 * passing NULL to token will alloc a new one.
246 * You should only pass NULL for the token when the token type (table above)
247 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
249 static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
250 void* token_data)
252 struct skin_token_list *llitem = skin_buffer_alloc(sizeof(*llitem));
253 if (!token)
254 token = skin_buffer_alloc(sizeof(*token));
255 if (!llitem || !token)
256 return NULL;
257 llitem->next = PTRTOSKINOFFSET(skin_buffer, NULL);
258 llitem->token = PTRTOSKINOFFSET(skin_buffer, token);
259 if (token_data)
260 token->value.data = PTRTOSKINOFFSET(skin_buffer, token_data);
261 return llitem;
264 static int parse_statusbar_tags(struct skin_element* element,
265 struct wps_token *token,
266 struct wps_data *wps_data)
268 (void)element;
269 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
271 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)&curr_vp->vp);
273 else
275 struct skin_viewport *default_vp = SKINOFFSETTOPTR(skin_buffer, first_viewport->data);
276 if (first_viewport->params_count == 0)
278 wps_data->wps_sb_tag = true;
279 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
281 if (wps_data->show_sb_on_wps)
283 viewport_set_defaults(&default_vp->vp, curr_screen);
285 else
287 viewport_set_fullscreen(&default_vp->vp, curr_screen);
289 #ifdef HAVE_REMOTE_LCD
290 /* This parser requires viewports which will use the settings font to
291 * have font == 1, but the above viewport_set() calls set font to
292 * the current real font id. So force 1 here it will be set correctly
293 * at the end
295 default_vp->vp.font = 1;
296 #endif
298 return 0;
301 static int get_image_id(int c)
303 if(c >= 'a' && c <= 'z')
304 return c - 'a';
305 else if(c >= 'A' && c <= 'Z')
306 return c - 'A' + 26;
307 else
308 return -1;
311 void get_image_filename(const char *start, const char* bmpdir,
312 char *buf, int buf_size)
314 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
317 static int parse_image_display(struct skin_element *element,
318 struct wps_token *token,
319 struct wps_data *wps_data)
321 char *label = get_param_text(element, 0);
322 char sublabel = '\0';
323 int subimage;
324 struct gui_img *img;
325 struct image_display *id = skin_buffer_alloc(sizeof(*id));
327 if (element->params_count == 1 && strlen(label) <= 2)
329 /* backwards compatability. Allow %xd(Aa) to still work */
330 sublabel = label[1];
331 label[1] = '\0';
333 /* sanity check */
334 img = skin_find_item(label, SKIN_FIND_IMAGE, wps_data);
335 if (!img || !id)
337 return WPS_ERROR_INVALID_PARAM;
339 id->label = img->label;
340 id->offset = 0;
341 id->token = PTRTOSKINOFFSET(skin_buffer, NULL);
342 if (img->using_preloaded_icons)
344 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
347 if (element->params_count > 1)
349 if (get_param(element, 1)->type == CODE)
350 id->token = get_param_code(element, 1)->data;
351 /* specify a number. 1 being the first subimage (i.e top) NOT 0 */
352 else if (get_param(element, 1)->type == INTEGER)
353 id->subimage = get_param(element, 1)->data.number - 1;
354 if (element->params_count > 2)
355 id->offset = get_param(element, 2)->data.number;
357 else
359 if ((subimage = get_image_id(sublabel)) != -1)
361 if (subimage >= img->num_subimages)
362 return WPS_ERROR_INVALID_PARAM;
363 id->subimage = subimage;
364 } else {
365 id->subimage = 0;
368 token->value.data = PTRTOSKINOFFSET(skin_buffer, id);
369 return 0;
372 static int parse_image_load(struct skin_element *element,
373 struct wps_token *token,
374 struct wps_data *wps_data)
376 const char* filename;
377 const char* id;
378 int x = 0,y = 0, subimages = 1;
379 struct gui_img *img;
381 /* format: %x(n,filename.bmp[,x,y])
382 or %xl(n,filename.bmp[,x,y])
383 or %xl(n,filename.bmp[,x,y,num_subimages])
386 id = get_param_text(element, 0);
387 filename = get_param_text(element, 1);
388 /* x,y,num_subimages handling:
389 * If all 3 are left out use sane defaults.
390 * If there are 2 params it must be x,y
391 * if there is only 1 param it must be the num_subimages
393 if (element->params_count == 3)
394 subimages = get_param(element, 2)->data.number;
395 else if (element->params_count > 3)
397 x = get_param(element, 2)->data.number;
398 y = get_param(element, 3)->data.number;
399 if (element->params_count == 5)
400 subimages = get_param(element, 4)->data.number;
402 /* check the image number and load state */
403 if(skin_find_item(id, SKIN_FIND_IMAGE, wps_data))
405 /* Invalid image ID */
406 return WPS_ERROR_INVALID_PARAM;
408 img = skin_buffer_alloc(sizeof(*img));
409 if (!img)
410 return WPS_ERROR_INVALID_PARAM;
411 /* save a pointer to the filename */
412 img->bm.data = (char*)filename;
413 img->label = PTRTOSKINOFFSET(skin_buffer, (void*)id);
414 img->x = x;
415 img->y = y;
416 img->num_subimages = subimages;
417 img->display = -1;
418 img->using_preloaded_icons = false;
419 img->buflib_handle = -1;
421 /* save current viewport */
422 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
424 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
425 token->value.data = PTRTOSKINOFFSET(skin_buffer, img);
427 if (!strcmp(img->bm.data, "__list_icons__"))
429 img->num_subimages = Icon_Last_Themeable;
430 img->using_preloaded_icons = true;
433 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
434 if (!item)
435 return WPS_ERROR_INVALID_PARAM;
436 add_to_ll_chain(&wps_data->images, item);
438 return 0;
440 struct skin_font {
441 int id; /* the id from font_load */
442 char *name; /* filename without path and extension */
443 int glyphs; /* how many glyphs to reserve room for */
445 static struct skin_font skinfonts[MAXUSERFONTS];
446 static int parse_font_load(struct skin_element *element,
447 struct wps_token *token,
448 struct wps_data *wps_data)
450 (void)wps_data; (void)token;
451 int id = get_param(element, 0)->data.number;
452 char *filename = get_param_text(element, 1);
453 int glyphs;
454 char *ptr;
456 if(element->params_count > 2)
457 glyphs = get_param(element, 2)->data.number;
458 else
459 glyphs = global_settings.glyphs_to_cache;
460 if (id < 2)
462 DEBUGF("font id must be >= 2 (%d)\n", id);
463 return 1;
465 #if defined(DEBUG) || defined(SIMULATOR)
466 if (skinfonts[id-2].name != NULL)
468 DEBUGF("font id %d already being used\n", id);
470 #endif
471 /* make sure the filename contains .fnt,
472 * we dont actually use it, but require it anyway */
473 ptr = strchr(filename, '.');
474 if (!ptr || strncmp(ptr, ".fnt", 4))
475 return WPS_ERROR_INVALID_PARAM;
476 skinfonts[id-2].id = -1;
477 skinfonts[id-2].name = filename;
478 skinfonts[id-2].glyphs = glyphs;
480 return 0;
484 #ifdef HAVE_LCD_BITMAP
486 static int parse_playlistview(struct skin_element *element,
487 struct wps_token *token,
488 struct wps_data *wps_data)
490 (void)wps_data;
491 struct playlistviewer *viewer = skin_buffer_alloc(sizeof(*viewer));
492 if (!viewer)
493 return WPS_ERROR_INVALID_PARAM;
494 viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
495 viewer->show_icons = true;
496 viewer->start_offset = get_param(element, 0)->data.number;
497 viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
499 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)viewer);
501 return 0;
503 #endif
504 #ifdef HAVE_LCD_COLOR
505 static int parse_viewport_gradient_setup(struct skin_element *element,
506 struct wps_token *token,
507 struct wps_data *wps_data)
509 (void)wps_data;
510 struct gradient_config *cfg;
511 if (element->params_count < 2) /* only start and end are required */
512 return 1;
513 cfg = skin_buffer_alloc(sizeof(*cfg));
514 if (!cfg)
515 return 1;
516 if (!parse_color(curr_screen, get_param_text(element, 0), &cfg->start) ||
517 !parse_color(curr_screen, get_param_text(element, 1), &cfg->end))
518 return 1;
519 if (element->params_count > 2)
521 if (!parse_color(curr_screen, get_param_text(element, 2), &cfg->text))
522 return 1;
524 else
526 cfg->text = curr_vp->vp.fg_pattern;
529 token->value.data = PTRTOSKINOFFSET(skin_buffer, cfg);
530 return 0;
532 #endif
534 static int parse_listitem(struct skin_element *element,
535 struct wps_token *token,
536 struct wps_data *wps_data)
538 (void)wps_data;
539 struct listitem *li = skin_buffer_alloc(sizeof(*li));
540 if (!li)
541 return 1;
542 token->value.data = PTRTOSKINOFFSET(skin_buffer, li);
543 if (element->params_count == 0)
544 li->offset = 0;
545 else
547 li->offset = get_param(element, 0)->data.number;
548 if (element->params_count > 1)
549 li->wrap = strcasecmp(get_param_text(element, 1), "nowrap") != 0;
550 else
551 li->wrap = true;
553 return 0;
556 static int parse_listitemviewport(struct skin_element *element,
557 struct wps_token *token,
558 struct wps_data *wps_data)
560 #ifndef __PCTOOL__
561 struct listitem_viewport_cfg *cfg = skin_buffer_alloc(sizeof(*cfg));
562 if (!cfg)
563 return -1;
564 cfg->data = wps_data;
565 cfg->tile = false;
566 cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
567 cfg->width = -1;
568 cfg->height = -1;
569 if (!isdefault(get_param(element, 1)))
570 cfg->width = get_param(element, 1)->data.number;
571 if (!isdefault(get_param(element, 2)))
572 cfg->height = get_param(element, 2)->data.number;
573 if (element->params_count > 3 &&
574 !strcmp(get_param_text(element, 3), "tile"))
575 cfg->tile = true;
576 token->value.data = PTRTOSKINOFFSET(skin_buffer, (void*)cfg);
577 #endif
578 return 0;
581 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
582 static int parse_viewporttextstyle(struct skin_element *element,
583 struct wps_token *token,
584 struct wps_data *wps_data)
586 (void)wps_data;
587 int style;
588 char *mode = get_param_text(element, 0);
589 unsigned colour;
591 if (!strcmp(mode, "invert"))
593 style = STYLE_INVERT;
595 else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
597 if (element->params_count < 2 ||
598 !parse_color(curr_screen, get_param_text(element, 1), &colour))
599 return 1;
600 style = STYLE_COLORED|(STYLE_COLOR_MASK&colour);
602 #ifdef HAVE_LCD_COLOR
603 else if (!strcmp(mode, "gradient"))
605 int num_lines;
606 if (element->params_count < 2)
607 num_lines = 1;
608 else /* atoi() instead of using a number in the parser is because [si]
609 * will select the number for something which looks like a colour
610 * making the "colour" case (above) harder to parse */
611 num_lines = atoi(get_param_text(element, 1));
612 style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0);
614 #endif
615 else if (!strcmp(mode, "clear"))
617 style = STYLE_DEFAULT;
619 else
620 return 1;
621 token->value.l = style;
622 return 0;
625 static int parse_drawrectangle( struct skin_element *element,
626 struct wps_token *token,
627 struct wps_data *wps_data)
629 (void)wps_data;
630 struct draw_rectangle *rect = skin_buffer_alloc(sizeof(*rect));
632 if (!rect)
633 return -1;
635 rect->x = get_param(element, 0)->data.number;
636 rect->y = get_param(element, 1)->data.number;
638 if (isdefault(get_param(element, 2)))
639 rect->width = curr_vp->vp.width - rect->x;
640 else
641 rect->width = get_param(element, 2)->data.number;
643 if (isdefault(get_param(element, 3)))
644 rect->height = curr_vp->vp.height - rect->y;
645 else
646 rect->height = get_param(element, 3)->data.number;
648 rect->start_colour = curr_vp->vp.fg_pattern;
649 rect->end_colour = curr_vp->vp.fg_pattern;
651 if (element->params_count > 4)
653 if (!parse_color(curr_screen, get_param_text(element, 4),
654 &rect->start_colour))
655 return -1;
656 rect->end_colour = rect->start_colour;
658 if (element->params_count > 5)
660 if (!parse_color(curr_screen, get_param_text(element, 5),
661 &rect->end_colour))
662 return -1;
664 token->value.data = PTRTOSKINOFFSET(skin_buffer, rect);
666 return 0;
669 static int parse_viewportcolour(struct skin_element *element,
670 struct wps_token *token,
671 struct wps_data *wps_data)
673 (void)wps_data;
674 struct skin_tag_parameter *param = get_param(element, 0);
675 struct viewport_colour *colour = skin_buffer_alloc(sizeof(*colour));
676 if (!colour)
677 return -1;
678 if (isdefault(param))
680 colour->colour = get_viewport_default_colour(curr_screen,
681 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
683 else
685 if (!parse_color(curr_screen, SKINOFFSETTOPTR(skin_buffer, param->data.text),
686 &colour->colour))
687 return -1;
689 colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
690 token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
691 if (element->line == curr_viewport_element->line)
693 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
695 curr_vp->start_fgcolour = colour->colour;
696 curr_vp->vp.fg_pattern = colour->colour;
698 else
700 curr_vp->start_bgcolour = colour->colour;
701 curr_vp->vp.bg_pattern = colour->colour;
704 return 0;
707 static int parse_image_special(struct skin_element *element,
708 struct wps_token *token,
709 struct wps_data *wps_data)
711 (void)wps_data; /* kill warning */
712 (void)token;
714 #if LCD_DEPTH > 1
715 char *filename;
716 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
718 if (isdefault(get_param(element, 0)))
720 filename = "-";
722 else
724 filename = get_param_text(element, 0);
725 /* format: %X(filename.bmp) or %X(d) */
726 if (!strcmp(filename, "d"))
727 filename = NULL;
729 backdrop_filename = filename;
731 #endif
733 return 0;
735 #endif
737 #endif /* HAVE_LCD_BITMAP */
739 static int parse_setting_and_lang(struct skin_element *element,
740 struct wps_token *token,
741 struct wps_data *wps_data)
743 /* NOTE: both the string validations that happen in here will
744 * automatically PASS on checkwps because its too hard to get
745 * settings_list.c and english.lang built for it.
746 * If that ever changes remove the #ifndef __PCTOOL__'s here
748 (void)wps_data;
749 char *temp = get_param_text(element, 0);
750 int i;
752 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
754 #ifndef __PCTOOL__
755 i = lang_english_to_id(temp);
756 if (i < 0)
757 return WPS_ERROR_INVALID_PARAM;
758 #endif
760 else
762 #ifndef __PCTOOL__
763 if (find_setting_by_cfgname(temp, &i) == NULL)
764 return WPS_ERROR_INVALID_PARAM;
765 #endif
767 /* Store the setting number */
768 token->value.i = i;
769 return 0;
772 static int parse_logical_andor(struct skin_element *element,
773 struct wps_token *token,
774 struct wps_data *wps_data)
776 (void)wps_data;
777 token->value.data = PTRTOSKINOFFSET(skin_buffer, element);
778 return 0;
781 static int parse_logical_if(struct skin_element *element,
782 struct wps_token *token,
783 struct wps_data *wps_data)
785 (void)wps_data;
786 char *op = get_param_text(element, 1);
787 struct logical_if *lif = skin_buffer_alloc(sizeof(*lif));
788 if (!lif)
789 return -1;
790 token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
791 lif->token = get_param_code(element, 0)->data;
793 if (!strncmp(op, "=", 1))
794 lif->op = IF_EQUALS;
795 else if (!strncmp(op, "!=", 2))
796 lif->op = IF_NOTEQUALS;
797 else if (!strncmp(op, ">=", 2))
798 lif->op = IF_GREATERTHAN_EQ;
799 else if (!strncmp(op, "<=", 2))
800 lif->op = IF_LESSTHAN_EQ;
801 else if (!strncmp(op, ">", 2))
802 lif->op = IF_GREATERTHAN;
803 else if (!strncmp(op, "<", 1))
804 lif->op = IF_LESSTHAN;
806 memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
807 if (element->params_count > 3)
808 lif->num_options = get_param(element, 3)->data.number;
809 else
810 lif->num_options = TOKEN_VALUE_ONLY;
811 return 0;
815 static int parse_timeout_tag(struct skin_element *element,
816 struct wps_token *token,
817 struct wps_data *wps_data)
819 (void)wps_data;
820 int val = 0;
821 if (element->params_count == 0)
823 switch (token->type)
825 case SKIN_TOKEN_SUBLINE_TIMEOUT:
826 return -1;
827 case SKIN_TOKEN_BUTTON_VOLUME:
828 case SKIN_TOKEN_TRACK_STARTING:
829 case SKIN_TOKEN_TRACK_ENDING:
830 val = 10;
831 break;
832 default:
833 break;
836 else
837 val = get_param(element, 0)->data.number;
838 token->value.i = val * TIMEOUT_UNIT;
839 return 0;
842 static int parse_substring_tag(struct skin_element* element,
843 struct wps_token *token,
844 struct wps_data *wps_data)
846 (void)wps_data;
847 struct substring *ss = skin_buffer_alloc(sizeof(*ss));
848 if (!ss)
849 return 1;
850 ss->start = get_param(element, 0)->data.number;
851 if (get_param(element, 1)->type == DEFAULT)
852 ss->length = -1;
853 else
854 ss->length = get_param(element, 1)->data.number;
855 ss->token = get_param_code(element, 2)->data;
856 if (element->params_count > 3)
857 ss->expect_number = !strcmp(get_param_text(element, 3), "number");
858 else
859 ss->expect_number = false;
860 token->value.data = PTRTOSKINOFFSET(skin_buffer, ss);
861 return 0;
864 static int parse_progressbar_tag(struct skin_element* element,
865 struct wps_token *token,
866 struct wps_data *wps_data)
868 #ifdef HAVE_LCD_BITMAP
869 struct progressbar *pb;
870 struct viewport *vp = &curr_vp->vp;
871 struct skin_tag_parameter *param = get_param(element, 0);
872 int curr_param = 0;
873 char *image_filename = NULL;
875 if (element->params_count == 0 &&
876 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
877 return 0; /* nothing to do */
878 pb = skin_buffer_alloc(sizeof(*pb));
880 token->value.data = PTRTOSKINOFFSET(skin_buffer, pb);
882 if (!pb)
883 return WPS_ERROR_INVALID_PARAM;
884 pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
885 pb->follow_lang_direction = follow_lang_direction > 0;
886 pb->nofill = false;
887 pb->nobar = false;
888 pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
889 pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
890 pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
891 pb->invert_fill_direction = false;
892 pb->horizontal = true;
894 if (element->params_count == 0)
896 pb->x = 0;
897 pb->width = vp->width;
898 pb->height = SYSFONT_HEIGHT-2;
899 pb->y = -1; /* Will be computed during the rendering */
900 pb->type = element->tag->type;
901 return 0;
904 /* (x, y, width, height, ...) */
905 if (!isdefault(param))
906 pb->x = param->data.number;
907 else
908 pb->x = 0;
909 param++;
911 if (!isdefault(param))
912 pb->y = param->data.number;
913 else
914 pb->y = -1; /* computed at rendering */
915 param++;
917 if (!isdefault(param))
918 pb->width = param->data.number;
919 else
920 pb->width = vp->width - pb->x;
921 param++;
923 if (!isdefault(param))
925 /* A zero height makes no sense - reject it */
926 if (param->data.number == 0)
927 return WPS_ERROR_INVALID_PARAM;
929 pb->height = param->data.number;
931 else
933 if (vp->font > FONT_UI)
934 pb->height = -1; /* calculate at display time */
935 else
937 #ifndef __PCTOOL__
938 pb->height = font_get(vp->font)->height;
939 #else
940 pb->height = 8;
941 #endif
944 /* optional params, first is the image filename if it isnt recognised as a keyword */
946 curr_param = 4;
947 if (isdefault(get_param(element, curr_param)))
949 param++;
950 curr_param++;
953 pb->horizontal = pb->width > pb->height;
954 while (curr_param < element->params_count)
956 char* text;
957 param++;
958 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
959 if (!strcmp(text, "invert"))
960 pb->invert_fill_direction = true;
961 else if (!strcmp(text, "nofill"))
962 pb->nofill = true;
963 else if (!strcmp(text, "nobar"))
964 pb->nobar = true;
965 else if (!strcmp(text, "slider"))
967 if (curr_param+1 < element->params_count)
969 curr_param++;
970 param++;
971 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
972 pb->slider = PTRTOSKINOFFSET(skin_buffer,
973 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
975 else /* option needs the next param */
976 return -1;
978 else if (!strcmp(text, "image"))
980 if (curr_param+1 < element->params_count)
982 curr_param++;
983 param++;
984 image_filename = SKINOFFSETTOPTR(skin_buffer, param->data.text);
986 else /* option needs the next param */
987 return -1;
989 else if (!strcmp(text, "backdrop"))
991 if (curr_param+1 < element->params_count)
993 curr_param++;
994 param++;
995 text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
996 pb->backdrop = PTRTOSKINOFFSET(skin_buffer,
997 skin_find_item(text, SKIN_FIND_IMAGE, wps_data));
1000 else /* option needs the next param */
1001 return -1;
1003 else if (!strcmp(text, "vertical"))
1005 pb->horizontal = false;
1006 if (isdefault(get_param(element, 3)))
1007 pb->height = vp->height - pb->y;
1009 else if (!strcmp(text, "horizontal"))
1010 pb->horizontal = true;
1011 else if (curr_param == 4)
1012 image_filename = text;
1014 curr_param++;
1017 if (image_filename)
1019 pb->image = PTRTOSKINOFFSET(skin_buffer,
1020 skin_find_item(image_filename, SKIN_FIND_IMAGE, wps_data));
1021 if (!SKINOFFSETTOPTR(skin_buffer, pb->image)) /* load later */
1023 struct gui_img *img = skin_buffer_alloc(sizeof(*img));
1024 if (!img)
1025 return WPS_ERROR_INVALID_PARAM;
1026 /* save a pointer to the filename */
1027 img->bm.data = (char*)image_filename;
1028 img->label = PTRTOSKINOFFSET(skin_buffer, image_filename);
1029 img->x = 0;
1030 img->y = 0;
1031 img->num_subimages = 1;
1032 img->display = -1;
1033 img->using_preloaded_icons = false;
1034 img->buflib_handle = -1;
1035 img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1036 struct skin_token_list *item = new_skin_token_list_item(NULL, img);
1037 if (!item)
1038 return WPS_ERROR_INVALID_PARAM;
1039 add_to_ll_chain(&wps_data->images, item);
1040 pb->image = PTRTOSKINOFFSET(skin_buffer, img);
1044 if (token->type == SKIN_TOKEN_VOLUME)
1045 token->type = SKIN_TOKEN_VOLUMEBAR;
1046 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1047 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1048 else if (token->type == SKIN_TOKEN_TUNER_RSSI)
1049 token->type = SKIN_TOKEN_TUNER_RSSI_BAR;
1050 else if (token->type == SKIN_TOKEN_PEAKMETER_LEFT)
1051 token->type = SKIN_TOKEN_PEAKMETER_LEFTBAR;
1052 else if (token->type == SKIN_TOKEN_PEAKMETER_RIGHT)
1053 token->type = SKIN_TOKEN_PEAKMETER_RIGHTBAR;
1054 else if (token->type == SKIN_TOKEN_LIST_NEEDS_SCROLLBAR)
1055 token->type = SKIN_TOKEN_LIST_SCROLLBAR;
1056 pb->type = token->type;
1058 return 0;
1060 #else
1061 (void)element;
1062 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1063 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1065 wps_data->full_line_progressbar =
1066 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1068 return 0;
1070 #endif
1073 #ifdef HAVE_ALBUMART
1074 static int parse_albumart_load(struct skin_element* element,
1075 struct wps_token *token,
1076 struct wps_data *wps_data)
1078 struct dim dimensions;
1079 int albumart_slot;
1080 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1081 struct skin_albumart *aa = skin_buffer_alloc(sizeof(*aa));
1082 (void)token; /* silence warning */
1083 if (!aa)
1084 return -1;
1086 /* reset albumart info in wps */
1087 aa->width = -1;
1088 aa->height = -1;
1089 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1090 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1092 aa->x = get_param(element, 0)->data.number;
1093 aa->y = get_param(element, 1)->data.number;
1094 aa->width = get_param(element, 2)->data.number;
1095 aa->height = get_param(element, 3)->data.number;
1097 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
1098 aa->draw_handle = -1;
1100 /* if we got here, we parsed everything ok .. ! */
1101 if (aa->width < 0)
1102 aa->width = 0;
1103 else if (aa->width > LCD_WIDTH)
1104 aa->width = LCD_WIDTH;
1106 if (aa->height < 0)
1107 aa->height = 0;
1108 else if (aa->height > LCD_HEIGHT)
1109 aa->height = LCD_HEIGHT;
1111 if (swap_for_rtl)
1112 aa->x = LCD_WIDTH - (aa->x + aa->width);
1114 aa->state = WPS_ALBUMART_LOAD;
1115 wps_data->albumart = PTRTOSKINOFFSET(skin_buffer, aa);
1117 dimensions.width = aa->width;
1118 dimensions.height = aa->height;
1120 albumart_slot = playback_claim_aa_slot(&dimensions);
1122 if (0 <= albumart_slot)
1123 wps_data->playback_aa_slot = albumart_slot;
1125 if (element->params_count > 4 && !isdefault(get_param(element, 4)))
1127 switch (*get_param_text(element, 4))
1129 case 'l':
1130 case 'L':
1131 if (swap_for_rtl)
1132 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1133 else
1134 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1135 break;
1136 case 'c':
1137 case 'C':
1138 aa->xalign = WPS_ALBUMART_ALIGN_CENTER;
1139 break;
1140 case 'r':
1141 case 'R':
1142 if (swap_for_rtl)
1143 aa->xalign = WPS_ALBUMART_ALIGN_LEFT;
1144 else
1145 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1146 break;
1149 if (element->params_count > 5 && !isdefault(get_param(element, 5)))
1151 switch (*get_param_text(element, 5))
1153 case 't':
1154 case 'T':
1155 aa->yalign = WPS_ALBUMART_ALIGN_TOP;
1156 break;
1157 case 'c':
1158 case 'C':
1159 aa->yalign = WPS_ALBUMART_ALIGN_CENTER;
1160 break;
1161 case 'b':
1162 case 'B':
1163 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1164 break;
1167 return 0;
1170 #endif /* HAVE_ALBUMART */
1171 #ifdef HAVE_SKIN_VARIABLES
1172 static struct skin_var* find_or_add_var(const char* label,
1173 struct wps_data *data)
1175 struct skin_var* ret = skin_find_item(label, SKIN_VARIABLE, data);
1176 if (ret)
1177 return ret;
1179 ret = skin_buffer_alloc(sizeof(*ret));
1180 if (!ret)
1181 return ret;
1182 ret->label = PTRTOSKINOFFSET(skin_buffer, label);
1183 ret->value = 1;
1184 ret->last_changed = 0xffff;
1185 struct skin_token_list *item = new_skin_token_list_item(NULL, ret);
1186 if (!item)
1187 return NULL;
1188 add_to_ll_chain(&data->skinvars, item);
1189 return ret;
1191 static int parse_skinvar( struct skin_element *element,
1192 struct wps_token *token,
1193 struct wps_data *wps_data)
1195 const char* label = get_param_text(element, 0);
1196 struct skin_var* var = find_or_add_var(label, wps_data);
1197 if (!var)
1198 return WPS_ERROR_INVALID_PARAM;
1199 switch (token->type)
1201 case SKIN_TOKEN_VAR_GETVAL:
1202 token->value.data = PTRTOSKINOFFSET(skin_buffer, var);
1203 return 0;
1204 case SKIN_TOKEN_VAR_SET:
1206 struct skin_var_changer *data = skin_buffer_alloc(sizeof(*data));
1207 if (!data)
1208 return WPS_ERROR_INVALID_PARAM;
1209 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1210 if (!isdefault(get_param(element, 2)))
1211 data->newval = get_param(element, 2)->data.number;
1212 else if (strcmp(get_param_text(element, 1), "touch"))
1213 return WPS_ERROR_INVALID_PARAM;
1214 data->max = 0;
1215 if (!strcmp(get_param_text(element, 1), "set"))
1216 data->direct = true;
1217 else if (!strcmp(get_param_text(element, 1), "inc"))
1219 data->direct = false;
1221 else if (!strcmp(get_param_text(element, 1), "dec"))
1223 data->direct = false;
1224 data->newval *= -1;
1226 else if (!strcmp(get_param_text(element, 1), "touch"))
1228 data->direct = false;
1229 data->newval = 0;
1231 if (element->params_count > 3)
1232 data->max = get_param(element, 3)->data.number;
1233 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1235 return 0;
1236 case SKIN_TOKEN_VAR_TIMEOUT:
1238 struct skin_var_lastchange *data = skin_buffer_alloc(sizeof(*data));
1239 if (!data)
1240 return WPS_ERROR_INVALID_PARAM;
1241 data->var = PTRTOSKINOFFSET(skin_buffer, var);
1242 data->timeout = 10;
1243 if (element->params_count > 1)
1244 data->timeout = get_param(element, 1)->data.number;
1245 data->timeout *= TIMEOUT_UNIT;
1246 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1248 default:
1249 return 0;
1252 #endif /* HAVE_SKIN_VARIABLES */
1253 #ifdef HAVE_TOUCHSCREEN
1254 static int parse_lasttouch(struct skin_element *element,
1255 struct wps_token *token,
1256 struct wps_data *wps_data)
1258 struct touchregion_lastpress *data = skin_buffer_alloc(sizeof(*data));
1259 int i;
1260 struct touchregion *region = NULL;
1261 if (!data)
1262 return WPS_ERROR_INVALID_PARAM;
1264 data->timeout = 10;
1266 for (i=0; i<element->params_count; i++)
1268 if (get_param(element, i)->type == STRING)
1269 region = skin_find_item(get_param_text(element, i),
1270 SKIN_FIND_TOUCHREGION, wps_data);
1271 else if (get_param(element, i)->type == INTEGER ||
1272 get_param(element, i)->type == DECIMAL)
1273 data->timeout = get_param(element, i)->data.number;
1276 data->region = PTRTOSKINOFFSET(skin_buffer, region);
1277 data->timeout *= TIMEOUT_UNIT;
1278 token->value.data = PTRTOSKINOFFSET(skin_buffer, data);
1279 return 0;
1282 struct touchaction {const char* s; int action;};
1283 static const struct touchaction touchactions[] = {
1284 /* generic actions, convert to screen actions on use */
1285 {"none", ACTION_TOUCHSCREEN_IGNORE},{"lock", ACTION_TOUCH_SOFTLOCK },
1286 {"prev", ACTION_STD_PREV }, {"next", ACTION_STD_NEXT },
1287 {"hotkey", ACTION_STD_HOTKEY}, {"select", ACTION_STD_OK },
1288 {"menu", ACTION_STD_MENU }, {"cancel", ACTION_STD_CANCEL },
1289 {"contextmenu", ACTION_STD_CONTEXT},{"quickscreen", ACTION_STD_QUICKSCREEN },
1291 /* list/tree actions */
1292 { "resumeplayback", ACTION_TREE_WPS}, /* returns to previous music, WPS/FM */
1293 /* not really WPS specific, but no equivilant ACTION_STD_* */
1294 {"voldown", ACTION_WPS_VOLDOWN}, {"volup", ACTION_WPS_VOLUP},
1295 {"mute", ACTION_TOUCH_MUTE },
1297 /* generic settings changers */
1298 {"setting_inc", ACTION_SETTINGS_INC}, {"setting_dec", ACTION_SETTINGS_DEC},
1299 {"setting_set", ACTION_SETTINGS_SET},
1301 /* WPS specific actions */
1302 {"rwd", ACTION_WPS_SEEKBACK }, {"ffwd", ACTION_WPS_SEEKFWD },
1303 {"wps_prev", ACTION_WPS_SKIPPREV }, {"wps_next", ACTION_WPS_SKIPNEXT },
1304 {"browse", ACTION_WPS_BROWSE },
1305 {"play", ACTION_WPS_PLAY }, {"stop", ACTION_WPS_STOP },
1306 {"shuffle", ACTION_TOUCH_SHUFFLE }, {"repmode", ACTION_TOUCH_REPMODE },
1307 {"pitch", ACTION_WPS_PITCHSCREEN}, {"trackinfo", ACTION_WPS_ID3SCREEN },
1308 {"playlist", ACTION_WPS_VIEW_PLAYLIST },
1309 {"listbookmarks", ACTION_WPS_LIST_BOOKMARKS },
1310 {"createbookmark", ACTION_WPS_CREATE_BOOKMARK },
1312 #if CONFIG_TUNER
1313 /* FM screen actions */
1314 /* Also allow browse, play, stop from WPS codes */
1315 {"mode", ACTION_FM_MODE }, {"record", ACTION_FM_RECORD },
1316 {"presets", ACTION_FM_PRESET},
1317 #endif
1320 static int touchregion_setup_setting(struct skin_element *element, int param_no,
1321 struct touchregion *region)
1323 #ifndef __PCTOOL__
1324 int p = param_no;
1325 char *name = get_param_text(element, p++);
1326 int j;
1328 region->setting_data.setting = find_setting_by_cfgname(name, &j);
1329 if (region->setting_data.setting == NULL)
1330 return WPS_ERROR_INVALID_PARAM;
1332 if (region->action == ACTION_SETTINGS_SET)
1334 char* text;
1335 int temp;
1336 struct touchsetting *setting =
1337 &region->setting_data;
1338 if (element->params_count < p+1)
1339 return -1;
1341 text = get_param_text(element, p++);
1342 switch (settings[j].flags&F_T_MASK)
1344 case F_T_CUSTOM:
1345 setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
1346 break;
1347 case F_T_INT:
1348 case F_T_UINT:
1349 if (settings[j].cfg_vals == NULL)
1351 setting->value.number = atoi(text);
1353 else if (cfg_string_to_int(j, &temp, text))
1355 if (settings[j].flags&F_TABLE_SETTING)
1356 setting->value.number =
1357 settings[j].table_setting->values[temp];
1358 else
1359 setting->value.number = temp;
1361 else
1362 return -1;
1363 break;
1364 case F_T_BOOL:
1365 if (cfg_string_to_int(j, &temp, text))
1367 setting->value.number = temp;
1369 else
1370 return -1;
1371 break;
1372 default:
1373 return -1;
1376 return p-param_no;
1377 #endif /* __PCTOOL__ */
1378 return 0;
1381 static int parse_touchregion(struct skin_element *element,
1382 struct wps_token *token,
1383 struct wps_data *wps_data)
1385 (void)token;
1386 unsigned i, imax;
1387 int p;
1388 struct touchregion *region = NULL;
1389 const char *action;
1390 const char pb_string[] = "progressbar";
1391 const char vol_string[] = "volume";
1393 /* format: %T([label,], x,y,width,height,action[, ...])
1394 * if action starts with & the area must be held to happen
1398 region = skin_buffer_alloc(sizeof(*region));
1399 if (!region)
1400 return WPS_ERROR_INVALID_PARAM;
1402 /* should probably do some bounds checking here with the viewport... but later */
1403 region->action = ACTION_NONE;
1405 if (get_param(element, 0)->type == STRING)
1407 region->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
1408 p = 1;
1409 /* "[SI]III[SI]|SS" is the param list. There MUST be 4 numbers
1410 * followed by at least one string. Verify that here */
1411 if (element->params_count < 6 ||
1412 get_param(element, 4)->type != INTEGER)
1413 return WPS_ERROR_INVALID_PARAM;
1415 else
1417 region->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1418 p = 0;
1421 region->x = get_param(element, p++)->data.number;
1422 region->y = get_param(element, p++)->data.number;
1423 region->width = get_param(element, p++)->data.number;
1424 region->height = get_param(element, p++)->data.number;
1425 region->wvp = PTRTOSKINOFFSET(skin_buffer, curr_vp);
1426 region->armed = false;
1427 region->reverse_bar = false;
1428 region->value = 0;
1429 region->last_press = 0xffff;
1430 region->press_length = PRESS;
1431 region->allow_while_locked = false;
1432 action = get_param_text(element, p++);
1434 /* figure out the action */
1435 if(!strcmp(pb_string, action))
1436 region->action = ACTION_TOUCH_SCROLLBAR;
1437 else if(!strcmp(vol_string, action))
1438 region->action = ACTION_TOUCH_VOLUME;
1439 else
1441 imax = ARRAYLEN(touchactions);
1442 for (i = 0; i < imax; i++)
1444 /* try to match with one of our touchregion screens */
1445 if (!strcmp(touchactions[i].s, action))
1447 region->action = touchactions[i].action;
1448 if (region->action == ACTION_SETTINGS_INC ||
1449 region->action == ACTION_SETTINGS_DEC ||
1450 region->action == ACTION_SETTINGS_SET)
1452 int val;
1453 if (element->params_count < p+1)
1454 return WPS_ERROR_INVALID_PARAM;
1455 val = touchregion_setup_setting(element, p, region);
1456 if (val < 0)
1457 return WPS_ERROR_INVALID_PARAM;
1458 p += val;
1460 break;
1463 if (region->action == ACTION_NONE)
1464 return WPS_ERROR_INVALID_PARAM;
1466 while (p < element->params_count)
1468 char* param = get_param_text(element, p++);
1469 if (!strcmp(param, "allow_while_locked"))
1470 region->allow_while_locked = true;
1471 else if (!strcmp(param, "reverse_bar"))
1472 region->reverse_bar = true;
1473 else if (!strcmp(param, "repeat_press"))
1474 region->press_length = REPEAT;
1475 else if (!strcmp(param, "long_press"))
1476 region->press_length = LONG_PRESS;
1478 struct skin_token_list *item = new_skin_token_list_item(NULL, region);
1479 if (!item)
1480 return WPS_ERROR_INVALID_PARAM;
1481 add_to_ll_chain(&wps_data->touchregions, item);
1483 if (region->action == ACTION_TOUCH_MUTE)
1485 region->value = global_settings.volume;
1489 return 0;
1491 #endif
1493 static bool check_feature_tag(const int type)
1495 switch (type)
1497 case SKIN_TOKEN_RTC_PRESENT:
1498 #if CONFIG_RTC
1499 return true;
1500 #else
1501 return false;
1502 #endif
1503 case SKIN_TOKEN_HAVE_RECORDING:
1504 #ifdef HAVE_RECORDING
1505 return true;
1506 #else
1507 return false;
1508 #endif
1509 case SKIN_TOKEN_HAVE_TUNER:
1510 #if CONFIG_TUNER
1511 if (radio_hardware_present())
1512 return true;
1513 #endif
1514 return false;
1515 case SKIN_TOKEN_HAVE_TOUCH:
1516 #ifdef HAVE_TOUCHSCREEN
1517 return true;
1518 #else
1519 return false;
1520 #endif
1522 #if CONFIG_TUNER
1523 case SKIN_TOKEN_HAVE_RDS:
1524 #ifdef HAVE_RDS_CAP
1525 return true;
1526 #else
1527 return false;
1528 #endif /* HAVE_RDS_CAP */
1529 #endif /* CONFIG_TUNER */
1530 default: /* not a tag we care about, just don't skip */
1531 return true;
1535 /* This is used to free any buflib allocations before the rest of
1536 * wps_data is reset.
1537 * The call to this in settings_apply_skins() is the last chance to do
1538 * any core_free()'s before wps_data is trashed and those handles lost
1540 void skin_data_free_buflib_allocs(struct wps_data *wps_data)
1542 if (wps_data->wps_loaded)
1543 skin_buffer = get_skin_buffer(wps_data);
1544 #ifdef HAVE_LCD_BITMAP
1545 #ifndef __PCTOOL__
1546 struct skin_token_list *list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1547 int *font_ids = SKINOFFSETTOPTR(skin_buffer, wps_data->font_ids);
1548 while (list)
1550 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1551 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1552 if (img->buflib_handle > 0)
1553 core_free(img->buflib_handle);
1554 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1556 wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
1557 if (font_ids != NULL)
1559 while (wps_data->font_count > 0)
1560 font_unload(font_ids[--wps_data->font_count]);
1562 wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1563 if (wps_data->buflib_handle > 0)
1564 core_free(wps_data->buflib_handle);
1565 wps_data->buflib_handle = -1;
1566 #endif
1567 #endif
1571 * initial setup of wps_data; does reset everything
1572 * except fields which need to survive, i.e.
1573 * Also called if the load fails
1575 static void skin_data_reset(struct wps_data *wps_data)
1577 skin_data_free_buflib_allocs(wps_data);
1578 #ifdef HAVE_LCD_BITMAP
1579 wps_data->images = INVALID_OFFSET;
1580 #endif
1581 wps_data->tree = INVALID_OFFSET;
1582 #ifdef HAVE_BACKDROP_IMAGE
1583 if (wps_data->backdrop_id >= 0)
1584 skin_backdrop_unload(wps_data->backdrop_id);
1585 backdrop_filename = NULL;
1586 #endif
1587 #ifdef HAVE_TOUCHSCREEN
1588 wps_data->touchregions = INVALID_OFFSET;
1589 #endif
1590 #ifdef HAVE_SKIN_VARIABLES
1591 wps_data->skinvars = INVALID_OFFSET;
1592 #endif
1593 #ifdef HAVE_ALBUMART
1594 wps_data->albumart = INVALID_OFFSET;
1595 if (wps_data->playback_aa_slot >= 0)
1597 playback_release_aa_slot(wps_data->playback_aa_slot);
1598 wps_data->playback_aa_slot = -1;
1600 #endif
1602 #ifdef HAVE_LCD_BITMAP
1603 wps_data->peak_meter_enabled = false;
1604 wps_data->wps_sb_tag = false;
1605 wps_data->show_sb_on_wps = false;
1606 #else /* HAVE_LCD_CHARCELLS */
1607 /* progress bars */
1608 int i;
1609 for (i = 0; i < 8; i++)
1611 wps_data->wps_progress_pat[i] = 0;
1613 wps_data->full_line_progressbar = false;
1614 #endif
1615 wps_data->wps_loaded = false;
1618 #ifdef HAVE_LCD_BITMAP
1619 #ifndef __PCTOOL__
1620 static int currently_loading_handle = -1;
1621 static int buflib_move_callback(int handle, void* current, void* new)
1623 (void)current;
1624 (void)new;
1625 if (handle == currently_loading_handle)
1626 return BUFLIB_CB_CANNOT_MOVE;
1627 return BUFLIB_CB_OK;
1629 static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
1630 static void lock_handle(int handle)
1632 currently_loading_handle = handle;
1634 static void unlock_handle(void)
1636 currently_loading_handle = -1;
1638 #endif
1640 static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
1642 (void)wps_data; /* only needed for remote targets */
1643 char img_path[MAX_PATH];
1644 int fd;
1645 int handle;
1646 get_image_filename(bitmap->data, bmpdir,
1647 img_path, sizeof(img_path));
1649 /* load the image */
1650 int format;
1651 #ifdef HAVE_REMOTE_LCD
1652 if (curr_screen == SCREEN_REMOTE)
1653 format = FORMAT_ANY|FORMAT_REMOTE;
1654 else
1655 #endif
1656 format = FORMAT_ANY|FORMAT_TRANSPARENT;
1658 fd = open(img_path, O_RDONLY);
1659 if (fd < 0)
1661 DEBUGF("Couldn't open %s\n", img_path);
1662 return fd;
1664 #ifndef __PCTOOL__
1665 size_t buf_size = read_bmp_fd(fd, bitmap, 0,
1666 format|FORMAT_RETURN_SIZE, NULL);
1667 handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
1668 if (handle < 0)
1670 DEBUGF("Not enough skin buffer: need %zd more.\n",
1671 buf_size - skin_buffer_freespace());
1672 close(fd);
1673 return handle;
1675 lseek(fd, 0, SEEK_SET);
1676 lock_handle(handle);
1677 bitmap->data = core_get_data(handle);
1678 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
1679 bitmap->data = NULL; /* do this to force a crash later if the
1680 caller doesnt call core_get_data() */
1681 unlock_handle();
1682 close(fd);
1683 if (ret > 0)
1685 /* free unused alpha channel, if any */
1686 core_shrink(handle, core_get_data(handle), ret);
1687 return handle;
1689 else
1691 /* Abort if we can't load an image */
1692 DEBUGF("Couldn't load '%s'\n", img_path);
1693 core_free(handle);
1694 return -1;
1696 #else /* !__PCTOOL__ */
1697 close(fd);
1698 return 1;
1699 #endif
1702 static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
1704 struct skin_token_list *list;
1705 bool retval = true; /* return false if a single image failed to load */
1707 /* regular images */
1708 list = SKINOFFSETTOPTR(skin_buffer, wps_data->images);
1709 while (list)
1711 struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, list->token);
1712 struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
1713 if (img->bm.data)
1715 if (img->using_preloaded_icons)
1717 img->loaded = true;
1718 token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON;
1720 else
1722 img->buflib_handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
1723 img->loaded = img->buflib_handle >= 0;
1724 if (img->loaded)
1725 img->subimage_height = img->bm.height / img->num_subimages;
1726 else
1727 retval = false;
1730 list = SKINOFFSETTOPTR(skin_buffer, list->next);
1733 #ifdef HAVE_BACKDROP_IMAGE
1734 wps_data->backdrop_id = skin_backdrop_assign(backdrop_filename, bmpdir, curr_screen);
1735 #endif /* has backdrop support */
1736 return retval;
1739 static bool skin_load_fonts(struct wps_data *data)
1741 /* don't spit out after the first failue to aid debugging */
1742 int id_array[MAXUSERFONTS];
1743 int font_count = 0;
1744 bool success = true;
1745 struct skin_element *vp_list;
1746 int font_id;
1747 /* walk though each viewport and assign its font */
1748 for(vp_list = SKINOFFSETTOPTR(skin_buffer, data->tree);
1749 vp_list; vp_list = SKINOFFSETTOPTR(skin_buffer, vp_list->next))
1751 /* first, find the viewports that have a non-sys/ui-font font */
1752 struct skin_viewport *skin_vp =
1753 SKINOFFSETTOPTR(skin_buffer, vp_list->data);
1754 struct viewport *vp = &skin_vp->vp;
1756 font_id = skin_vp->parsed_fontid;
1757 if (font_id == 1)
1758 { /* the usual case -> built-in fonts */
1759 vp->font = screens[curr_screen].getuifont();
1760 continue;
1762 else if (font_id <= 0)
1764 vp->font = FONT_SYSFIXED;
1765 continue;
1768 /* now find the corresponding skin_font */
1769 struct skin_font *font = &skinfonts[font_id-2];
1770 if (!font->name)
1772 if (success)
1774 DEBUGF("font %d not specified\n", font_id);
1776 success = false;
1777 continue;
1780 /* load the font - will handle loading the same font again if
1781 * multiple viewports use the same */
1782 if (font->id < 0)
1784 char path[MAX_PATH];
1785 snprintf(path, sizeof path, FONT_DIR "/%s", font->name);
1786 #ifndef __PCTOOL__
1787 font->id = font_load_ex(path, 0, skinfonts[font_id-2].glyphs);
1789 #else
1790 font->id = font_load(path);
1791 #endif
1792 //printf("[%d] %s -> %d\n",font_id, font->name, font->id);
1793 id_array[font_count++] = font->id;
1796 if (font->id < 0)
1798 DEBUGF("Unable to load font %d: '%s.fnt'\n",
1799 font_id, font->name);
1800 font->name = NULL; /* to stop trying to load it again if we fail */
1801 success = false;
1802 continue;
1805 /* finally, assign the font_id to the viewport */
1806 vp->font = font->id;
1808 if (font_count)
1810 int *font_ids = skin_buffer_alloc(font_count * sizeof(int));
1811 if (!success || font_ids == NULL)
1813 while (font_count > 0)
1815 if(id_array[--font_count] != -1)
1816 font_unload(id_array[font_count]);
1818 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1819 return false;
1821 memcpy(font_ids, id_array, sizeof(int)*font_count);
1822 data->font_count = font_count;
1823 data->font_ids = PTRTOSKINOFFSET(skin_buffer, font_ids);
1825 else
1827 data->font_count = 0;
1828 data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL);
1830 return success;
1833 #endif /* HAVE_LCD_BITMAP */
1834 static int convert_viewport(struct wps_data *data, struct skin_element* element)
1836 struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(*skin_vp));
1837 struct screen *display = &screens[curr_screen];
1839 if (!skin_vp)
1840 return CALLBACK_ERROR;
1842 skin_vp->hidden_flags = 0;
1843 skin_vp->label = PTRTOSKINOFFSET(skin_buffer, NULL);
1844 skin_vp->is_infovp = false;
1845 skin_vp->parsed_fontid = 1;
1846 element->data = PTRTOSKINOFFSET(skin_buffer, skin_vp);
1847 curr_vp = skin_vp;
1848 curr_viewport_element = element;
1849 if (!first_viewport)
1850 first_viewport = element;
1852 viewport_set_defaults(&skin_vp->vp, curr_screen);
1854 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1855 skin_vp->output_to_backdrop_buffer = false;
1856 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1857 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1858 #endif
1859 #ifdef HAVE_LCD_COLOR
1860 skin_vp->start_gradient.start = skin_vp->vp.lss_pattern;
1861 skin_vp->start_gradient.end = skin_vp->vp.lse_pattern;
1862 skin_vp->start_gradient.text = skin_vp->vp.lst_pattern;
1863 #endif
1866 struct skin_tag_parameter *param = get_param(element, 0);
1867 if (element->params_count == 0) /* default viewport */
1869 if (data->tree < 0) /* first viewport in the skin */
1870 data->tree = PTRTOSKINOFFSET(skin_buffer, element);
1871 skin_vp->label = VP_DEFAULT_LABEL;
1872 return CALLBACK_OK;
1875 if (element->params_count == 6)
1877 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1879 skin_vp->is_infovp = true;
1880 if (isdefault(param))
1882 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1883 skin_vp->label = VP_DEFAULT_LABEL;
1885 else
1887 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1888 skin_vp->label = param->data.text;
1891 else
1893 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1894 skin_vp->label = param->data.text;
1896 param++;
1898 /* x */
1899 if (!isdefault(param))
1901 skin_vp->vp.x = param->data.number;
1902 if (param->data.number < 0)
1903 skin_vp->vp.x += display->lcdwidth;
1905 param++;
1906 /* y */
1907 if (!isdefault(param))
1909 skin_vp->vp.y = param->data.number;
1910 if (param->data.number < 0)
1911 skin_vp->vp.y += display->lcdheight;
1913 param++;
1914 /* width */
1915 if (!isdefault(param))
1917 skin_vp->vp.width = param->data.number;
1918 if (param->data.number < 0)
1919 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1921 else
1923 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1925 param++;
1926 /* height */
1927 if (!isdefault(param))
1929 skin_vp->vp.height = param->data.number;
1930 if (param->data.number < 0)
1931 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1933 else
1935 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1937 param++;
1938 #ifdef HAVE_LCD_BITMAP
1939 /* font */
1940 if (!isdefault(param))
1941 skin_vp->parsed_fontid = param->data.number;
1942 #endif
1943 if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth ||
1944 skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth ||
1945 (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight ||
1946 skin_vp->vp.height + skin_vp->vp.y > display->lcdheight)
1947 return CALLBACK_ERROR;
1949 return CALLBACK_OK;
1952 static int skin_element_callback(struct skin_element* element, void* data)
1954 struct wps_data *wps_data = (struct wps_data *)data;
1955 struct wps_token *token;
1956 parse_function function = NULL;
1958 switch (element->type)
1960 /* IMPORTANT: element params are shared, so copy them if needed
1961 * or use then NOW, dont presume they have a long lifespan
1963 case TAG:
1965 token = skin_buffer_alloc(sizeof(*token));
1966 memset(token, 0, sizeof(*token));
1967 token->type = element->tag->type;
1968 token->value.data = INVALID_OFFSET;
1970 if (element->tag->flags&SKIN_RTC_REFRESH)
1972 #if CONFIG_RTC
1973 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
1974 #else
1975 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1976 #endif
1978 else
1979 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
1981 element->data = PTRTOSKINOFFSET(skin_buffer, token);
1983 /* Some tags need special handling for the tag, so add them here */
1984 switch (token->type)
1986 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
1987 follow_lang_direction = 2;
1988 break;
1989 case SKIN_TOKEN_LOGICAL_IF:
1990 function = parse_logical_if;
1991 break;
1992 case SKIN_TOKEN_LOGICAL_AND:
1993 case SKIN_TOKEN_LOGICAL_OR:
1994 function = parse_logical_andor;
1995 break;
1996 case SKIN_TOKEN_SUBSTRING:
1997 function = parse_substring_tag;
1998 break;
1999 case SKIN_TOKEN_PROGRESSBAR:
2000 case SKIN_TOKEN_VOLUME:
2001 case SKIN_TOKEN_BATTERY_PERCENT:
2002 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
2003 case SKIN_TOKEN_PEAKMETER_LEFT:
2004 case SKIN_TOKEN_PEAKMETER_RIGHT:
2005 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
2006 #ifdef HAVE_RADIO_RSSI
2007 case SKIN_TOKEN_TUNER_RSSI:
2008 #endif
2009 function = parse_progressbar_tag;
2010 break;
2011 case SKIN_TOKEN_SUBLINE_TIMEOUT:
2012 case SKIN_TOKEN_BUTTON_VOLUME:
2013 case SKIN_TOKEN_TRACK_STARTING:
2014 case SKIN_TOKEN_TRACK_ENDING:
2015 function = parse_timeout_tag;
2016 break;
2017 #ifdef HAVE_LCD_BITMAP
2018 case SKIN_TOKEN_LIST_ITEM_TEXT:
2019 case SKIN_TOKEN_LIST_ITEM_ICON:
2020 function = parse_listitem;
2021 break;
2022 case SKIN_TOKEN_DISABLE_THEME:
2023 case SKIN_TOKEN_ENABLE_THEME:
2024 case SKIN_TOKEN_DRAW_INBUILTBAR:
2025 function = parse_statusbar_tags;
2026 break;
2027 case SKIN_TOKEN_LIST_TITLE_TEXT:
2028 #ifndef __PCTOOL__
2029 sb_skin_has_title(curr_screen);
2030 #endif
2031 break;
2032 #endif
2033 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2034 case SKIN_TOKEN_DRAWRECTANGLE:
2035 function = parse_drawrectangle;
2036 break;
2037 #endif
2038 case SKIN_TOKEN_FILE_DIRECTORY:
2039 token->value.i = get_param(element, 0)->data.number;
2040 break;
2041 #ifdef HAVE_BACKDROP_IMAGE
2042 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
2043 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
2044 function = parse_viewportcolour;
2045 break;
2046 case SKIN_TOKEN_IMAGE_BACKDROP:
2047 function = parse_image_special;
2048 break;
2049 case SKIN_TOKEN_VIEWPORT_TEXTSTYLE:
2050 function = parse_viewporttextstyle;
2051 break;
2052 case SKIN_TOKEN_VIEWPORT_DRAWONBG:
2053 curr_vp->output_to_backdrop_buffer = true;
2054 backdrop_filename = BACKDROP_BUFFERNAME;
2055 wps_data->use_extra_framebuffer = true;
2056 break;
2057 #endif
2058 #ifdef HAVE_LCD_COLOR
2059 case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP:
2060 function = parse_viewport_gradient_setup;
2061 break;
2062 #endif
2063 case SKIN_TOKEN_TRANSLATEDSTRING:
2064 case SKIN_TOKEN_SETTING:
2065 function = parse_setting_and_lang;
2066 break;
2067 #ifdef HAVE_LCD_BITMAP
2068 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
2069 function = parse_playlistview;
2070 break;
2071 case SKIN_TOKEN_LOAD_FONT:
2072 function = parse_font_load;
2073 break;
2074 case SKIN_TOKEN_VIEWPORT_ENABLE:
2075 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
2076 token->value.data = get_param(element, 0)->data.text;
2077 break;
2078 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
2079 function = parse_image_display;
2080 break;
2081 case SKIN_TOKEN_IMAGE_PRELOAD:
2082 case SKIN_TOKEN_IMAGE_DISPLAY:
2083 function = parse_image_load;
2084 break;
2085 case SKIN_TOKEN_LIST_ITEM_CFG:
2086 function = parse_listitemviewport;
2087 break;
2088 #endif
2089 #ifdef HAVE_TOUCHSCREEN
2090 case SKIN_TOKEN_TOUCHREGION:
2091 function = parse_touchregion;
2092 break;
2093 case SKIN_TOKEN_LASTTOUCH:
2094 function = parse_lasttouch;
2095 break;
2096 #endif
2097 #ifdef HAVE_ALBUMART
2098 case SKIN_TOKEN_ALBUMART_DISPLAY:
2099 if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
2101 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2102 aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
2104 break;
2105 case SKIN_TOKEN_ALBUMART_LOAD:
2106 function = parse_albumart_load;
2107 break;
2108 #endif
2109 #ifdef HAVE_SKIN_VARIABLES
2110 case SKIN_TOKEN_VAR_SET:
2111 case SKIN_TOKEN_VAR_GETVAL:
2112 case SKIN_TOKEN_VAR_TIMEOUT:
2113 function = parse_skinvar;
2114 break;
2115 #endif
2116 default:
2117 break;
2119 if (function)
2121 if (function(element, token, wps_data) < 0)
2122 return CALLBACK_ERROR;
2124 /* tags that start with 'F', 'I' or 'D' are for the next file */
2125 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
2126 *(element->tag->name) == 'D')
2127 token->next = true;
2128 if (follow_lang_direction > 0 )
2129 follow_lang_direction--;
2130 break;
2132 case VIEWPORT:
2133 return convert_viewport(wps_data, element);
2134 case LINE:
2136 curr_line = skin_buffer_alloc(sizeof(*curr_line));
2137 curr_line->update_mode = SKIN_REFRESH_STATIC;
2138 element->data = PTRTOSKINOFFSET(skin_buffer, curr_line);
2140 break;
2141 case LINE_ALTERNATOR:
2143 struct line_alternator *alternator = skin_buffer_alloc(sizeof(*alternator));
2144 alternator->current_line = 0;
2145 #ifndef __PCTOOL__
2146 alternator->next_change_tick = current_tick;
2147 #endif
2148 element->data = PTRTOSKINOFFSET(skin_buffer, alternator);
2150 break;
2151 case CONDITIONAL:
2153 struct conditional *conditional = skin_buffer_alloc(sizeof(*conditional));
2154 conditional->last_value = -1;
2155 conditional->token = element->data;
2156 element->data = PTRTOSKINOFFSET(skin_buffer, conditional);
2157 if (!check_feature_tag(element->tag->type))
2159 return FEATURE_NOT_AVAILABLE;
2161 return CALLBACK_OK;
2163 case TEXT:
2164 curr_line->update_mode |= SKIN_REFRESH_STATIC;
2165 break;
2166 default:
2167 break;
2169 return CALLBACK_OK;
2172 /* to setup up the wps-data from a format-buffer (isfile = false)
2173 from a (wps-)file (isfile = true)*/
2174 bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2175 const char *buf, bool isfile)
2177 char *wps_buffer = NULL;
2178 if (!wps_data || !buf)
2179 return false;
2180 #ifdef HAVE_ALBUMART
2181 int status;
2182 struct mp3entry *curtrack;
2183 long offset;
2184 struct skin_albumart old_aa = {.state = WPS_ALBUMART_NONE};
2185 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2186 if (aa)
2188 old_aa.state = aa->state;
2189 old_aa.height = aa->height;
2190 old_aa.width = aa->width;
2192 #endif
2193 #ifdef HAVE_LCD_BITMAP
2194 int i;
2195 for (i=0;i<MAXUSERFONTS;i++)
2197 skinfonts[i].id = -1;
2198 skinfonts[i].name = NULL;
2200 #endif
2201 #ifdef DEBUG_SKIN_ENGINE
2202 if (isfile && debug_wps)
2204 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf);
2206 #endif
2209 /* get buffer space from the plugin buffer */
2210 size_t buffersize = 0;
2211 wps_buffer = (char *)plugin_get_buffer(&buffersize);
2213 if (!wps_buffer)
2214 return false;
2216 skin_data_reset(wps_data);
2217 wps_data->wps_loaded = false;
2218 curr_screen = screen;
2219 curr_line = NULL;
2220 curr_vp = NULL;
2221 curr_viewport_element = NULL;
2222 first_viewport = NULL;
2224 if (isfile)
2226 int fd = open_utf8(buf, O_RDONLY);
2228 if (fd < 0)
2229 return false;
2230 /* copy the file's content to the buffer for parsing,
2231 ensuring that every line ends with a newline char. */
2232 unsigned int start = 0;
2233 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
2235 start += strlen(wps_buffer + start);
2236 if (start < buffersize - 1)
2238 wps_buffer[start++] = '\n';
2239 wps_buffer[start] = 0;
2242 close(fd);
2243 if (start <= 0)
2244 return false;
2245 start++;
2246 skin_buffer = &wps_buffer[start];
2247 buffersize -= start;
2249 else
2251 skin_buffer = wps_buffer;
2252 wps_buffer = (char*)buf;
2254 skin_buffer = (void *)(((unsigned long)skin_buffer + 3) & ~3);
2255 buffersize -= 3;
2256 #ifdef HAVE_BACKDROP_IMAGE
2257 backdrop_filename = "-";
2258 wps_data->backdrop_id = -1;
2259 #endif
2260 /* parse the skin source */
2261 skin_buffer_init(skin_buffer, buffersize);
2262 struct skin_element *tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
2263 wps_data->tree = PTRTOSKINOFFSET(skin_buffer, tree);
2264 if (!SKINOFFSETTOPTR(skin_buffer, wps_data->tree)) {
2265 #ifdef DEBUG_SKIN_ENGINE
2266 if (isfile && debug_wps)
2267 skin_error_format_message();
2268 #endif
2269 skin_data_reset(wps_data);
2270 return false;
2273 #ifdef HAVE_LCD_BITMAP
2274 char bmpdir[MAX_PATH];
2275 if (isfile)
2277 /* get the bitmap dir */
2278 char *dot = strrchr(buf, '.');
2279 strlcpy(bmpdir, buf, dot - buf + 1);
2281 else
2283 snprintf(bmpdir, MAX_PATH, "%s", BACKDROP_DIR);
2285 /* load the bitmaps that were found by the parsing */
2286 if (!load_skin_bitmaps(wps_data, bmpdir) ||
2287 !skin_load_fonts(wps_data))
2289 skin_data_reset(wps_data);
2290 return false;
2292 #endif
2293 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2294 status = audio_status();
2295 if (status & AUDIO_STATUS_PLAY)
2297 struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
2298 if (aa && ((aa->state && !old_aa.state) ||
2299 (aa->state &&
2300 (((old_aa.height != aa->height) ||
2301 (old_aa.width != aa->width))))))
2303 curtrack = audio_current_track();
2304 offset = curtrack->offset;
2305 audio_stop();
2306 if (!(status & AUDIO_STATUS_PAUSE))
2307 audio_play(offset);
2310 #endif
2311 #ifndef __PCTOOL__
2312 wps_data->buflib_handle = core_alloc(isfile ? buf : "failsafe skin",
2313 skin_buffer_usage());
2314 if (wps_data->buflib_handle >= 0)
2316 wps_data->wps_loaded = true;
2317 memcpy(core_get_data(wps_data->buflib_handle), skin_buffer,
2318 skin_buffer_usage());
2320 #else
2321 wps_data->wps_loaded = wps_data->tree >= 0;
2322 #endif
2323 skin_buffer = NULL;
2324 return true;