]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c
5ff3d259f909478cd79a15be03f67918274131a9
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / gfxmenu / theme_loader.c
1 /* theme_loader.c - Theme file loader for gfxmenu. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/types.h>
21 #include <grub/file.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/err.h>
25 #include <grub/dl.h>
26 #include <grub/video.h>
27 #include <grub/gui_string_util.h>
28 #include <grub/bitmap.h>
29 #include <grub/bitmap_scale.h>
30 #include <grub/gfxwidgets.h>
31 #include <grub/gfxmenu_view.h>
32 #include <grub/gui.h>
33 #include <grub/color.h>
34 #include <grub/env.h>
35
36 static grub_err_t
37 parse_proportional_spec (const char *value, signed *abs, grub_fixed_signed_t *prop);
38
39 /* Construct a new box widget using ABSPATTERN to find the pixmap files for
40 it, storing the new box instance at *BOXPTR.
41 PATTERN should be of the form: "(hd0,0)/somewhere/style*.png".
42 The '*' then gets substituted with the various pixmap names that the
43 box uses. */
44 static grub_err_t
45 recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern)
46 {
47 char *prefix;
48 char *suffix;
49 char *star;
50 grub_gfxmenu_box_t box;
51
52 star = grub_strchr (abspattern, '*');
53 if (! star)
54 return grub_error (GRUB_ERR_BAD_ARGUMENT,
55 "missing `*' in box pixmap pattern `%s'", abspattern);
56
57 /* Prefix: Get the part before the '*'. */
58 prefix = grub_malloc (star - abspattern + 1);
59 if (! prefix)
60 return grub_errno;
61
62 grub_memcpy (prefix, abspattern, star - abspattern);
63 prefix[star - abspattern] = '\0';
64
65 /* Suffix: Everything after the '*' is the suffix. */
66 suffix = star + 1;
67
68 box = grub_gfxmenu_create_box (prefix, suffix);
69 grub_free (prefix);
70 if (! box)
71 return grub_errno;
72
73 if (*boxptr)
74 (*boxptr)->destroy (*boxptr);
75 *boxptr = box;
76 return grub_errno;
77 }
78
79
80 /* Construct a new box widget using PATTERN to find the pixmap files for it,
81 storing the new widget at *BOXPTR. PATTERN should be of the form:
82 "somewhere/style*.png". The '*' then gets substituted with the various
83 pixmap names that the widget uses.
84
85 Important! The value of *BOXPTR must be initialized! It must either
86 (1) Be 0 (a NULL pointer), or
87 (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance.
88 In this case, the previous instance is destroyed. */
89 grub_err_t
90 grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
91 const char *pattern, const char *theme_dir)
92 {
93 char *abspattern;
94
95 /* Check arguments. */
96 if (! pattern)
97 {
98 /* If no pixmap pattern is given, then just create an empty box. */
99 if (*boxptr)
100 (*boxptr)->destroy (*boxptr);
101 *boxptr = grub_gfxmenu_create_box (0, 0);
102 return grub_errno;
103 }
104
105 if (! theme_dir)
106 return grub_error (GRUB_ERR_BAD_ARGUMENT,
107 "styled box missing theme directory");
108
109 /* Resolve to an absolute path. */
110 abspattern = grub_resolve_relative_path (theme_dir, pattern);
111 if (! abspattern)
112 return grub_errno;
113
114 /* Create the box. */
115 recreate_box_absolute (boxptr, abspattern);
116 grub_free (abspattern);
117 return grub_errno;
118 }
119
120 static grub_err_t
121 theme_get_unsigned_int_from_proportional (const char *value,
122 unsigned absolute_value,
123 unsigned int *parsed_value)
124 {
125 grub_err_t err;
126 grub_fixed_signed_t frac;
127 signed pixels;
128 err = parse_proportional_spec (value, &pixels, &frac);
129 if (err != GRUB_ERR_NONE)
130 return err;
131 int result = grub_fixed_sfs_multiply (absolute_value, frac) + pixels;
132 if (result < 0)
133 result = 0;
134 *parsed_value = result;
135 return GRUB_ERR_NONE;
136 }
137
138 /* Set the specified property NAME on the view to the given string VALUE.
139 The caller is responsible for the lifetimes of NAME and VALUE. */
140 static grub_err_t
141 theme_set_string (grub_gfxmenu_view_t view,
142 const char *name,
143 const char *value,
144 const char *theme_dir,
145 const char *filename,
146 int line_num,
147 int col_num)
148 {
149 if (! grub_strcmp ("title-font", name))
150 view->title_font = grub_font_get (value);
151 else if (! grub_strcmp ("message-font", name))
152 view->message_font = grub_font_get (value);
153 else if (! grub_strcmp ("terminal-font", name))
154 {
155 grub_free (view->terminal_font_name);
156 view->terminal_font_name = grub_strdup (value);
157 if (! view->terminal_font_name)
158 return grub_errno;
159 }
160 else if (! grub_strcmp ("title-color", name))
161 grub_video_parse_color (value, &view->title_color);
162 else if (! grub_strcmp ("message-color", name))
163 grub_video_parse_color (value, &view->message_color);
164 else if (! grub_strcmp ("message-bg-color", name))
165 grub_video_parse_color (value, &view->message_bg_color);
166 else if (! grub_strcmp("menu-tip-left", name))
167 grub_env_set("VTOY_TIP_LEFT", value);
168 else if (! grub_strcmp("menu-tip-top", name))
169 grub_env_set("VTOY_TIP_TOP", value);
170 else if (! grub_strcmp("menu-tip-color", name))
171 grub_env_set("VTOY_TIP_COLOR", value);
172 else if (! grub_strcmp ("desktop-image", name))
173 {
174 struct grub_video_bitmap *raw_bitmap;
175 char *path;
176 path = grub_resolve_relative_path (theme_dir, value);
177 if (! path)
178 return grub_errno;
179 if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
180 {
181 grub_free (path);
182 return grub_errno;
183 }
184 grub_free(path);
185 grub_video_bitmap_destroy (view->raw_desktop_image);
186 view->raw_desktop_image = raw_bitmap;
187 }
188 else if (! grub_strcmp ("desktop-image-scale-method", name))
189 {
190 if (! value || ! grub_strcmp ("stretch", value))
191 view->desktop_image_scale_method =
192 GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH;
193 else if (! grub_strcmp ("crop", value))
194 view->desktop_image_scale_method =
195 GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP;
196 else if (! grub_strcmp ("padding", value))
197 view->desktop_image_scale_method =
198 GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING;
199 else if (! grub_strcmp ("fitwidth", value))
200 view->desktop_image_scale_method =
201 GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH;
202 else if (! grub_strcmp ("fitheight", value))
203 view->desktop_image_scale_method =
204 GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT;
205 else
206 return grub_error (GRUB_ERR_BAD_ARGUMENT,
207 "Unsupported scale method: %s",
208 value);
209 }
210 else if (! grub_strcmp ("desktop-image-h-align", name))
211 {
212 if (! grub_strcmp ("left", value))
213 view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_LEFT;
214 else if (! grub_strcmp ("center", value))
215 view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER;
216 else if (! grub_strcmp ("right", value))
217 view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT;
218 else
219 return grub_error (GRUB_ERR_BAD_ARGUMENT,
220 "Unsupported horizontal align method: %s",
221 value);
222 }
223 else if (! grub_strcmp ("desktop-image-v-align", name))
224 {
225 if (! grub_strcmp ("top", value))
226 view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_TOP;
227 else if (! grub_strcmp ("center", value))
228 view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER;
229 else if (! grub_strcmp ("bottom", value))
230 view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM;
231 else
232 return grub_error (GRUB_ERR_BAD_ARGUMENT,
233 "Unsupported vertical align method: %s",
234 value);
235 }
236 else if (! grub_strcmp ("desktop-color", name))
237 grub_video_parse_color (value, &view->desktop_color);
238 else if (! grub_strcmp ("terminal-box", name))
239 {
240 grub_err_t err;
241 err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
242 if (err != GRUB_ERR_NONE)
243 return err;
244 }
245 else if (! grub_strcmp ("terminal-border", name))
246 {
247 view->terminal_border = grub_strtoul (value, 0, 10);
248 if (grub_errno)
249 return grub_errno;
250 }
251 else if (! grub_strcmp ("terminal-left", name))
252 {
253 unsigned int tmp;
254 int err = theme_get_unsigned_int_from_proportional (value,
255 view->screen.width,
256 &tmp);
257 if (err != GRUB_ERR_NONE)
258 return err;
259 view->terminal_rect.x = tmp;
260 }
261 else if (! grub_strcmp ("terminal-top", name))
262 {
263 unsigned int tmp;
264 int err = theme_get_unsigned_int_from_proportional (value,
265 view->screen.height,
266 &tmp);
267 if (err != GRUB_ERR_NONE)
268 return err;
269 view->terminal_rect.y = tmp;
270 }
271 else if (! grub_strcmp ("terminal-width", name))
272 {
273 unsigned int tmp;
274 int err = theme_get_unsigned_int_from_proportional (value,
275 view->screen.width,
276 &tmp);
277 if (err != GRUB_ERR_NONE)
278 return err;
279 view->terminal_rect.width = tmp;
280 }
281 else if (! grub_strcmp ("terminal-height", name))
282 {
283 unsigned int tmp;
284 int err = theme_get_unsigned_int_from_proportional (value,
285 view->screen.height,
286 &tmp);
287 if (err != GRUB_ERR_NONE)
288 return err;
289 view->terminal_rect.height = tmp;
290 }
291 else if (! grub_strcmp ("title-text", name))
292 {
293 grub_free (view->title_text);
294 view->title_text = grub_strdup (value);
295 if (! view->title_text)
296 return grub_errno;
297 }
298 else if (! grub_strcmp ("ventoy_left_top_color", name))
299 return grub_errno;
300 else
301 {
302 return grub_error (GRUB_ERR_BAD_ARGUMENT,
303 "%s:%d:%d unknown property `%s'",
304 filename, line_num, col_num, name);
305 }
306 return grub_errno;
307 }
308
309 struct parsebuf
310 {
311 char *buf;
312 int pos;
313 int len;
314 int line_num;
315 int col_num;
316 const char *filename;
317 char *theme_dir;
318 grub_gfxmenu_view_t view;
319 };
320
321 static int
322 has_more (struct parsebuf *p)
323 {
324 return p->pos < p->len;
325 }
326
327 static int
328 read_char (struct parsebuf *p)
329 {
330 if (has_more (p))
331 {
332 char c;
333 c = p->buf[p->pos++];
334 if (c == '\n')
335 {
336 p->line_num++;
337 p->col_num = 1;
338 }
339 else
340 {
341 p->col_num++;
342 }
343 return c;
344 }
345 else
346 return -1;
347 }
348
349 static int
350 peek_char (struct parsebuf *p)
351 {
352 if (has_more (p))
353 return p->buf[p->pos];
354 else
355 return -1;
356 }
357
358 static int
359 is_whitespace (char c)
360 {
361 return (c == ' '
362 || c == '\t'
363 || c == '\r'
364 || c == '\n'
365 || c == '\f');
366 }
367
368 static void
369 skip_whitespace (struct parsebuf *p)
370 {
371 while (has_more (p) && is_whitespace(peek_char (p)))
372 read_char (p);
373 }
374
375 static void
376 advance_to_next_line (struct parsebuf *p)
377 {
378 int c;
379
380 /* Eat characters up to the newline. */
381 do
382 {
383 c = read_char (p);
384 }
385 while (c != -1 && c != '\n');
386 }
387
388 static int
389 is_identifier_char (int c)
390 {
391 return (c != -1
392 && (grub_isalpha(c)
393 || grub_isdigit(c)
394 || c == '_'
395 || c == '-'));
396 }
397
398 static char *
399 read_identifier (struct parsebuf *p)
400 {
401 /* Index of the first character of the identifier in p->buf. */
402 int start;
403 /* Next index after the last character of the identifer in p->buf. */
404 int end;
405
406 skip_whitespace (p);
407
408 /* Capture the start of the identifier. */
409 start = p->pos;
410
411 /* Scan for the end. */
412 while (is_identifier_char (peek_char (p)))
413 read_char (p);
414 end = p->pos;
415
416 if (end - start < 1)
417 return 0;
418
419 return grub_new_substring (p->buf, start, end);
420 }
421
422 static char *
423 read_expression (struct parsebuf *p)
424 {
425 int start;
426 int end;
427
428 skip_whitespace (p);
429 if (peek_char (p) == '"')
430 {
431 /* Read as a quoted string.
432 The quotation marks are not included in the expression value. */
433 /* Skip opening quotation mark. */
434 read_char (p);
435 start = p->pos;
436 while (has_more (p) && peek_char (p) != '"')
437 read_char (p);
438 end = p->pos;
439 /* Skip the terminating quotation mark. */
440 read_char (p);
441 }
442 else if (peek_char (p) == '(')
443 {
444 /* Read as a parenthesized string -- for tuples/coordinates. */
445 /* The parentheses are included in the expression value. */
446 int c;
447
448 start = p->pos;
449 do
450 {
451 c = read_char (p);
452 }
453 while (c != -1 && c != ')');
454 end = p->pos;
455 }
456 else if (has_more (p))
457 {
458 /* Read as a single word -- for numeric values or words without
459 whitespace. */
460 start = p->pos;
461 while (has_more (p) && ! is_whitespace (peek_char (p))
462 && peek_char (p) != '}')
463 read_char (p);
464 end = p->pos;
465 }
466 else
467 {
468 /* The end of the theme file has been reached. */
469 grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file",
470 p->filename, p->line_num, p->col_num);
471 return 0;
472 }
473
474 return grub_new_substring (p->buf, start, end);
475 }
476
477 static grub_err_t
478 parse_proportional_spec (const char *value, signed *abs, grub_fixed_signed_t *prop)
479 {
480 signed num;
481 const char *ptr;
482 int sig = 0;
483 *abs = 0;
484 *prop = 0;
485 ptr = value;
486 while (*ptr)
487 {
488 sig = 0;
489
490 while (*ptr == '-' || *ptr == '+')
491 {
492 if (*ptr == '-')
493 sig = !sig;
494 ptr++;
495 }
496
497 num = grub_strtoul (ptr, (char **) &ptr, 0);
498 if (grub_errno)
499 return grub_errno;
500 if (sig)
501 num = -num;
502 if (*ptr == '%')
503 {
504 *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100);
505 ptr++;
506 }
507 else
508 *abs += num;
509 }
510 return GRUB_ERR_NONE;
511 }
512
513
514 /* Read a GUI object specification from the theme file.
515 Any components created will be added to the GUI container PARENT. */
516 static grub_err_t
517 read_object (struct parsebuf *p, grub_gui_container_t parent)
518 {
519 grub_video_rect_t bounds;
520
521 char *name;
522 name = read_identifier (p);
523 if (! name)
524 goto cleanup;
525
526 grub_gui_component_t component = 0;
527 if (grub_strcmp (name, "label") == 0)
528 {
529 component = grub_gui_label_new ();
530 }
531 else if (grub_strcmp (name, "image") == 0)
532 {
533 component = grub_gui_image_new ();
534 }
535 else if (grub_strcmp (name, "vbox") == 0)
536 {
537 component = (grub_gui_component_t) grub_gui_vbox_new ();
538 }
539 else if (grub_strcmp (name, "hbox") == 0)
540 {
541 component = (grub_gui_component_t) grub_gui_hbox_new ();
542 }
543 else if (grub_strcmp (name, "canvas") == 0)
544 {
545 component = (grub_gui_component_t) grub_gui_canvas_new ();
546 }
547 else if (grub_strcmp (name, "progress_bar") == 0)
548 {
549 component = grub_gui_progress_bar_new ();
550 }
551 else if (grub_strcmp (name, "circular_progress") == 0)
552 {
553 component = grub_gui_circular_progress_new ();
554 }
555 else if (grub_strcmp (name, "boot_menu") == 0)
556 {
557 component = grub_gui_list_new ();
558 }
559 else
560 {
561 /* Unknown type. */
562 grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'",
563 p->filename, p->line_num, p->col_num, name);
564 goto cleanup;
565 }
566
567 if (! component)
568 goto cleanup;
569
570 /* Inform the component about the theme so it can find its resources. */
571 component->ops->set_property (component, "theme_dir", p->theme_dir);
572 component->ops->set_property (component, "theme_path", p->filename);
573
574 /* Add the component as a child of PARENT. */
575 bounds.x = 0;
576 bounds.y = 0;
577 bounds.width = -1;
578 bounds.height = -1;
579 component->ops->set_bounds (component, &bounds);
580 parent->ops->add (parent, component);
581
582 skip_whitespace (p);
583 if (read_char (p) != '{')
584 {
585 grub_error (GRUB_ERR_IO,
586 "%s:%d:%d expected `{' after object type name `%s'",
587 p->filename, p->line_num, p->col_num, name);
588 goto cleanup;
589 }
590
591 while (has_more (p))
592 {
593 skip_whitespace (p);
594
595 /* Check whether the end has been encountered. */
596 if (peek_char (p) == '}')
597 {
598 /* Skip the closing brace. */
599 read_char (p);
600 break;
601 }
602
603 if (peek_char (p) == '#')
604 {
605 /* Skip comments. */
606 advance_to_next_line (p);
607 continue;
608 }
609
610 if (peek_char (p) == '+')
611 {
612 /* Skip the '+'. */
613 read_char (p);
614
615 /* Check whether this component is a container. */
616 if (component->ops->is_instance (component, "container"))
617 {
618 /* Read the sub-object recursively and add it as a child. */
619 if (read_object (p, (grub_gui_container_t) component) != 0)
620 goto cleanup;
621 /* After reading the sub-object, resume parsing, expecting
622 another property assignment or sub-object definition. */
623 continue;
624 }
625 else
626 {
627 grub_error (GRUB_ERR_IO,
628 "%s:%d:%d attempted to add object to non-container",
629 p->filename, p->line_num, p->col_num);
630 goto cleanup;
631 }
632 }
633
634 char *property;
635 property = read_identifier (p);
636 if (! property)
637 {
638 grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file",
639 p->filename, p->line_num, p->col_num);
640 goto cleanup;
641 }
642
643 skip_whitespace (p);
644 if (read_char (p) != '=')
645 {
646 grub_error (GRUB_ERR_IO,
647 "%s:%d:%d expected `=' after property name `%s'",
648 p->filename, p->line_num, p->col_num, property);
649 grub_free (property);
650 goto cleanup;
651 }
652 skip_whitespace (p);
653
654 char *value;
655 value = read_expression (p);
656 if (! value)
657 {
658 grub_free (property);
659 goto cleanup;
660 }
661
662 /* Handle the property value. */
663 if (grub_strcmp (property, "left") == 0)
664 parse_proportional_spec (value, &component->x, &component->xfrac);
665 else if (grub_strcmp (property, "top") == 0)
666 parse_proportional_spec (value, &component->y, &component->yfrac);
667 else if (grub_strcmp (property, "width") == 0)
668 parse_proportional_spec (value, &component->w, &component->wfrac);
669 else if (grub_strcmp (property, "height") == 0)
670 parse_proportional_spec (value, &component->h, &component->hfrac);
671 else
672 /* General property handling. */
673 component->ops->set_property (component, property, value);
674
675 grub_free (value);
676 grub_free (property);
677 if (grub_errno != GRUB_ERR_NONE)
678 goto cleanup;
679 }
680
681 cleanup:
682 grub_free (name);
683 return grub_errno;
684 }
685
686 static grub_err_t
687 read_property (struct parsebuf *p)
688 {
689 char *name;
690
691 /* Read the property name. */
692 name = read_identifier (p);
693 if (! name)
694 {
695 advance_to_next_line (p);
696 return grub_errno;
697 }
698
699 /* Skip whitespace before separator. */
700 skip_whitespace (p);
701
702 /* Read separator. */
703 if (read_char (p) != ':')
704 {
705 grub_error (GRUB_ERR_IO,
706 "%s:%d:%d missing separator after property name `%s'",
707 p->filename, p->line_num, p->col_num, name);
708 goto done;
709 }
710
711 /* Skip whitespace after separator. */
712 skip_whitespace (p);
713
714 /* Get the value based on its type. */
715 if (peek_char (p) == '"')
716 {
717 /* String value (e.g., '"My string"'). */
718 char *value = read_expression (p);
719 if (! value)
720 {
721 grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value",
722 p->filename, p->line_num, p->col_num);
723 goto done;
724 }
725 /* If theme_set_string results in an error, grub_errno will be returned
726 below. */
727 theme_set_string (p->view, name, value, p->theme_dir,
728 p->filename, p->line_num, p->col_num);
729 grub_free (value);
730 }
731 else
732 {
733 grub_error (GRUB_ERR_IO,
734 "%s:%d:%d property value invalid; "
735 "enclose literal values in quotes (\")",
736 p->filename, p->line_num, p->col_num);
737 goto done;
738 }
739
740 done:
741 grub_free (name);
742 return grub_errno;
743 }
744
745 extern int g_menu_update_mode;
746
747 /* Set properties on the view based on settings from the specified
748 theme file. */
749 grub_err_t
750 grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
751 {
752 int flag = 0;
753 grub_file_t file;
754 struct parsebuf p;
755
756 p.view = view;
757 p.theme_dir = grub_get_dirname (theme_path);
758
759 file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME);
760 if (! file)
761 {
762 grub_free (p.theme_dir);
763 return grub_errno;
764 }
765
766 p.len = grub_file_size (file);
767 p.buf = grub_malloc (p.len + 8192);
768 p.pos = 0;
769 p.line_num = 1;
770 p.col_num = 1;
771 p.filename = theme_path;
772 if (! p.buf)
773 {
774 grub_file_close (file);
775 grub_free (p.theme_dir);
776 return grub_errno;
777 }
778 if (grub_file_read (file, p.buf, p.len) != p.len)
779 {
780 grub_free (p.buf);
781 grub_file_close (file);
782 grub_free (p.theme_dir);
783 return grub_errno;
784 }
785
786 {
787 const char *checkret = grub_env_get("VTOY_CHKDEV_RESULT_STRING");
788 if (checkret == NULL || checkret[0] != '0')
789 {
790 p.len += grub_snprintf(p.buf + p.len, 4096, "\n+ hbox{\n left = 1%%\n top = 90%%\n"
791 " + label {text = \"[Unofficial Ventoy]\" color = \"red\" align = \"left\"}\n"
792 "}\n");
793 }
794 }
795
796
797
798 if (view->canvas)
799 view->canvas->component.ops->destroy (view->canvas);
800
801 view->canvas = grub_gui_canvas_new ();
802 if (!view->canvas)
803 goto fail;
804 ((grub_gui_component_t) view->canvas)
805 ->ops->set_bounds ((grub_gui_component_t) view->canvas,
806 &view->screen);
807
808 parse:
809 while (has_more (&p))
810 {
811 /* Skip comments (lines beginning with #). */
812 if (peek_char (&p) == '#')
813 {
814 advance_to_next_line (&p);
815 continue;
816 }
817
818 /* Find the first non-whitespace character. */
819 skip_whitespace (&p);
820
821 /* Handle the content. */
822 if (peek_char (&p) == '+')
823 {
824 /* Skip the '+'. */
825 read_char (&p);
826 read_object (&p, view->canvas);
827 }
828 else
829 {
830 read_property (&p);
831 }
832
833 if (grub_errno != GRUB_ERR_NONE)
834 goto fail;
835 }
836
837
838 if (flag == 0)
839 {
840 const char *tip = grub_env_get("VTOY_MENU_TIP_ENABLE");
841 if (tip && tip[0] == '1')
842 {
843 char tmpmsg[512];
844
845 grub_memset(tmpmsg, 'w', 500);
846 tmpmsg[500] = 0;
847
848 g_menu_update_mode = 1;
849 p.len += grub_snprintf(p.buf + p.len, 4096,
850 "\n+ vbox{\n left = %s\n top = %s\n"
851 "+ label { id=\"VTOY_MENU_TIP_1\" text = \"%s\" color = \"%s\" align = \"%s\"}\n"
852 "+ label { id=\"VTOY_MENU_TIP_2\" text = \"%s\" color = \"%s\" align = \"%s\"}\n"
853 "}\n",
854 grub_env_get("VTOY_TIP_LEFT"),
855 grub_env_get("VTOY_TIP_TOP"),
856 tmpmsg,
857 grub_env_get("VTOY_TIP_COLOR"),
858 grub_env_get("VTOY_TIP_ALIGN"),
859 tmpmsg,
860 grub_env_get("VTOY_TIP_COLOR"),
861 grub_env_get("VTOY_TIP_ALIGN")
862 );
863
864 flag = 1;
865 goto parse;
866 }
867 }
868
869
870
871 /* Set the new theme path. */
872 grub_free (view->theme_path);
873 view->theme_path = grub_strdup (theme_path);
874 goto cleanup;
875
876 fail:
877 if (view->canvas)
878 {
879 view->canvas->component.ops->destroy (view->canvas);
880 view->canvas = 0;
881 }
882
883 cleanup:
884 grub_free (p.buf);
885 grub_file_close (file);
886 grub_free (p.theme_dir);
887 return grub_errno;
888 }