=== modified file 'conf/common.rmk'
--- conf/common.rmk 2009-01-31 20:26:35 +0000
+++ conf/common.rmk 2009-01-31 20:43:30 +0000
@@ -329,6 +329,7 @@
cmp.mod cat.mod help.mod search.mod \
loopback.mod fs_uuid.mod configfile.mod echo.mod \
terminfo.mod test.mod blocklist.mod hexdump.mod \
+ gfxmenu.mod \
read.mod sleep.mod loadenv.mod crc.mod
# For hello.mod.
@@ -336,6 +337,27 @@
hello_mod_CFLAGS = $(COMMON_CFLAGS)
hello_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For gfxmenu.mod.
+gfxmenu_mod_SOURCES = \
+ gfxmenu/gfxmenu.c \
+ gfxmenu/model.c \
+ gfxmenu/view.c \
+ gfxmenu/icon_manager.c \
+ gfxmenu/theme_loader.c \
+ gfxmenu/widget-box.c \
+ gfxmenu/gui_canvas.c \
+ gfxmenu/gui_circular_progress.c \
+ gfxmenu/gui_box.c \
+ gfxmenu/gui_label.c \
+ gfxmenu/gui_list.c \
+ gfxmenu/gui_image.c \
+ gfxmenu/gui_progress_bar.c \
+ gfxmenu/gui_util.c \
+ gfxmenu/gui_string_util.c \
+ gfxmenu/named_colors.c
+gfxmenu_mod_CFLAGS = $(COMMON_CFLAGS)
+gfxmenu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For boot.mod.
boot_mod_SOURCES = commands/boot.c
boot_mod_CFLAGS = $(COMMON_CFLAGS)
@@ -436,7 +458,7 @@
png.mod font.mod gfxterm.mod
# For video.mod.
-video_mod_SOURCES = video/video.c
+video_mod_SOURCES = video/video.c video/setmode.c
video_mod_CFLAGS = $(COMMON_CFLAGS)
video_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -476,7 +498,7 @@
gfxterm_mod_LDFLAGS = $(COMMON_LDFLAGS)
# Misc.
-pkglib_MODULES += gzio.mod bufio.mod elf.mod
+pkglib_MODULES += gzio.mod bufio.mod elf.mod trig.mod
# For elf.mod.
elf_mod_SOURCES = kern/elf.c
@@ -492,3 +514,8 @@
bufio_mod_SOURCES = io/bufio.c
bufio_mod_CFLAGS = $(COMMON_CFLAGS)
bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For trig.mod.
+trig_mod_SOURCES = lib/trig.c
+trig_mod_CFLAGS = $(COMMON_CFLAGS)
+trig_mod_LDFLAGS = $(COMMON_LDFLAGS)
=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk 2009-01-31 16:50:07 +0000
+++ conf/sparc64-ieee1275.rmk 2009-01-31 20:43:30 +0000
@@ -83,7 +83,7 @@
# Modules.
#_linux.mod linux.mod
pkglib_MODULES = fat.mod ufs.mod ext2.mod minix.mod \
- hfs.mod jfs.mod normal.mod hello.mod font.mod ls.mod \
+ hfs.mod jfs.mod normal.mod hello.mod ls.mod \
boot.mod cmp.mod cat.mod terminal.mod fshelp.mod amiga.mod apple.mod \
pc.mod suspend.mod loopback.mod help.mod reboot.mod halt.mod sun.mod \
configfile.mod search.mod gzio.mod xfs.mod \
@@ -204,11 +204,6 @@
cat_mod_CFLAGS = $(COMMON_CFLAGS)
cat_mod_LDFLAGS = $(COMMON_LDFLAGS)
-# For font.mod.
-font_mod_SOURCES = font/manager.c
-font_mod_CFLAGS = $(COMMON_CFLAGS)
-font_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
# For amiga.mod
amiga_mod_SOURCES = partmap/amiga.c
amiga_mod_CFLAGS = $(COMMON_CFLAGS)
=== added file 'docs/gfxmenu-theme-example.txt'
--- docs/gfxmenu-theme-example.txt 1970-01-01 00:00:00 +0000
+++ docs/gfxmenu-theme-example.txt 2009-01-31 20:43:30 +0000
@@ -0,0 +1,128 @@
+# GRUB gfxmenu theme "winter".
+# Uses background image from:
+# http://www.cyberpunkcafe.com/e107_plugins/autogallery/autogallery.php?show=1.Open%20Source%20Wallpaper
+# "without-leaves.png" was called "Without Leafs in Winter.png"
+
+lua-script: "winter.lua"
+title-text: ""
+title-font: "Helvetica Bold 18"
+status-font: "Helvetica 8"
+terminal-font: "Fixed 9"
+title-color: "40, 40, 40"
+status-color: "#FFF"
+status-bg-color: "0, 166, 183, 128"
+desktop-image: "without-leaves.png"
+desktop-color: "0, 154, 183"
+terminal-box: "terminal_*.png"
+
++ boot_menu {
+ position = (120, 60)
+ preferred_size = (400, -1)
+ item_font = "Helvetica Bold 14"
+ selected_item_font = "Helvetica Bold 14"
+ item_color = "0, 0, 0"
+ selected_item_color = "203, 251, 255"
+ menu_pixmap_style = "menu_*.png"
+ selected_item_pixmap_style = "select_*.png"
+ icon_width = 44
+ icon_height = 44
+ item_height = 32
+ item_padding = 0
+ item_icon_space = 3
+ item_spacing = 11
+}
+
+# You can add text at arbitrary locations on the screen.
+# The specification within the "+label {...}" block is free-form,
+# so you can use as much or as little white space as you like.
+
++ label {
+ position = (170, 50)
+ font = "smoothansi 13"
+ color = "0,0,128"
+ text = "This is the Winter theme ... brought to you by GRUB!"
+}
+
+# Show the text alignment supported by labels.
++ vbox {
+ position = (220, 347)
+ preferred_size = (200, -1) # A preferred size of -1 means automatic.
+ + label { text="Text alignment demo" align="center" font="aqui 11" }
+ + label { text="Left" align="left" font="cure 11" }
+ + label { text="Center" align="center" font="cure 11" }
+ + label { text="Right" align="right" font="cure 11" }
+}
+
++ vbox {
+ position = (580, 10)
+ + label { text="GNU" font="gelly 11" color="0, 0, 0" }
+ + label { text="GRUB" font="aqui 11" color="0, 0, 0" }
+ + label { text="boot loader" font="cure 11" color="0, 0, 0" }
+}
+
++ hbox {
+ position = (80, 10)
+ + label { text="GNU" font="gelly 11" color="0, 0, 0" }
+ + label { text="GRUB" font="aqui 11" color="0, 0, 0" }
+ + label { text="boot loader" font="cure 11" color="0, 0, 0" }
+}
+
+# Demonstration of a compound layout: boxes within boxes.
++ hbox
+{
+ position = (480, 3)
+
+ + vbox
+ {
+ # Note: We can't just use 'size' to set the image's size,
+ # since the vbox will resize the component according to its
+ # preferred size, which for images is the native image size.
+
+ + image { file="/boot/grub/themes/icons/ubuntu.png"
+ preferred_size = (20, 20) }
+ + image { file="/boot/grub/themes/icons/gentoo.png"
+ preferred_size = (20, 20) }
+ }
+
+ + vbox
+ {
+ + label { text="GRand" font="cure 11" color=#99F }
+ + label { text="Unified" font="cure 11" color=#BBF }
+ + label { text="Bootloader" font="cure 11" color=#DDF }
+ }
+}
+
+# By defining a 'progress_bar' type component with an ID of '__timeout__',
+# the progress bar will be used to display the time remaining before an
+# the default entry is automatically booted.
++ progress_bar
+{
+ id = "__timeout__"
+ position = (80, 393)
+ preferred_size = (500, 24)
+ font = "cure 11"
+ text_color = #000
+ fg_color = #CCF
+ bg_color = #66B
+ border_color = #006
+ show_text = false
+}
+
+# Although the progress_bar component is normally used to indicate the
+# time remaining, it's also possible to create other components with an ID
+# of '__timeout__'. All components with and ID of 'timeout_bar' will have
+# the following properties set based on the timeout value:
+# text, value, start, end, visible.
+# In this case, we have set 'show_text=false' on the progress bar, and use
+# the following label's 'text' property to display the message.
++ label
+{
+ id = "__timeout__"
+ position = (80, 420)
+ preferred_size = (500, 24)
+ font = "lime 11"
+ color = #117
+ align = "center"
+}
+
+
=== added file 'gentrigtables.py'
--- gentrigtables.py 1970-01-01 00:00:00 +0000
+++ gentrigtables.py 2009-01-31 20:43:30 +0000
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+# Script to generate trigonometric function tables.
+#
+# GRUB -- GRand Unified Bootloader
+# Copyright (C) 2008 Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB. If not, see .
+
+from math import *
+from sys import stdout
+
+def write(x):
+ stdout.write(x)
+
+def writeTable(arr, name):
+ indent = ' ' * 4
+ write("short ")
+ write(name)
+ write("[] =\n{\n")
+ write(indent)
+ for i in range(len(arr)):
+ if i != 0:
+ write(",")
+ if i % 10 == 0:
+ write("\n")
+ write(indent)
+ write("%d" % arr[i])
+ write("\n};\n")
+
+def main():
+ sintab = []
+ costab = []
+ for i in range(256):
+ # Convert to an angle in 1/256 of a circle.
+ x = i * 2 * pi / 256
+ sintab.append(int(round(sin(x) * 16384)))
+ costab.append(int(round(cos(x) * 16384)))
+
+ write("#define TRIG_ANGLE_MAX 256\n")
+ write("#define TRIG_FRACTION_SCALE 16384\n")
+ writeTable(sintab, "sintab")
+ writeTable(costab, "costab")
+
+if __name__ == "__main__":
+ main()
+
+# vim:ai et sw=4 ts=4
=== added directory 'gfxmenu'
=== added file 'gfxmenu/gfxmenu.c'
--- gfxmenu/gfxmenu.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gfxmenu.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,231 @@
+/* gfxmenu.c - Graphical menu interface controller. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static void switch_to_text_menu (void)
+{
+ grub_env_set ("menuviewer", "terminal");
+}
+
+static void
+process_key_press (int c,
+ grub_gfxmenu_model_t model,
+ grub_gfxmenu_view_t view,
+ int nested,
+ int *should_exit)
+{
+ /* When a key is pressed, stop the timeout. */
+ grub_gfxmenu_model_clear_timeout (model);
+
+ if (c == 'j' || c == GRUB_TERM_DOWN)
+ {
+ int i = grub_gfxmenu_model_get_selected_index (model);
+ int num_items = grub_gfxmenu_model_get_num_entries (model);
+ if (i < num_items - 1)
+ {
+ i++;
+ grub_gfxmenu_model_set_selected_index (model, i);
+ }
+ }
+ else if (c == 'k' || c == GRUB_TERM_UP)
+ {
+ int i = grub_gfxmenu_model_get_selected_index (model);
+ if (i > 0)
+ {
+ i--;
+ grub_gfxmenu_model_set_selected_index (model, i);
+ }
+ }
+ else if (c == '\r' || c == '\n' || c == GRUB_TERM_RIGHT)
+ {
+ int selected = grub_gfxmenu_model_get_selected_index (model);
+ int num_entries = grub_gfxmenu_model_get_num_entries (model);
+ if (selected >= 0 && selected < num_entries)
+ {
+ grub_menu_entry_t entry =
+ grub_gfxmenu_model_get_entry (model, selected);
+ grub_gfxmenu_view_execute_entry (view, entry);
+ }
+ }
+ else if (c == 'c')
+ {
+ grub_gfxmenu_view_run_terminal (view);
+ if (grub_errno != GRUB_ERR_NONE)
+ *should_exit = 1;
+ }
+ else if (c == 't')
+ {
+ /* The write hook for 'menuviewer' will cause
+ * grub_menu_viewer_should_return to return nonzero. */
+ switch_to_text_menu ();
+ *should_exit = 1;
+ }
+ else if (c == '1')
+ {
+ grub_gfxmenu_view_load_theme (view,
+ "/boot/grub/themes/proto/theme.txt");
+ }
+ else if (c == '2')
+ {
+ grub_gfxmenu_view_load_theme (view,
+ "/boot/grub/themes/winter/theme.txt");
+ }
+ else if (c == '3')
+ {
+ grub_gfxmenu_view_load_theme (view,
+ "/boot/grub/themes/ubuntu1/theme.txt");
+ }
+ else if (c == '4')
+ {
+ grub_gfxmenu_view_load_theme (view,
+ "/boot/grub/themes/ubuntu2/theme.txt");
+ }
+ else if (nested && c == GRUB_TERM_ESC)
+ {
+ *should_exit = 1;
+ }
+}
+
+static void
+handle_key_events (grub_gfxmenu_model_t model,
+ grub_gfxmenu_view_t view,
+ int nested,
+ int *should_exit)
+{
+ while (!*should_exit && grub_checkkey () != -1)
+ {
+ int key = grub_getkey ();
+ int c = GRUB_TERM_ASCII_CHAR (key);
+ process_key_press (c, model, view, nested, should_exit);
+ }
+}
+
+static grub_err_t
+show_menu (grub_menu_t menu, int nested)
+{
+ grub_gfxmenu_model_t model;
+
+ model = grub_gfxmenu_model_new (menu);
+ if (! model)
+ {
+ grub_print_error ();
+ grub_printf ("Initializing menu data for graphical menu failed;\n"
+ "falling back to terminal based menu.\n");
+ grub_wait_after_message ();
+ switch_to_text_menu ();
+ return grub_errno;
+ }
+
+ grub_gfxmenu_view_t view;
+
+ /* Create the view. */
+ const char *theme_path = grub_env_get ("theme");
+ if (! theme_path)
+ theme_path = "/boot/grub/themes/proto/theme.txt";
+
+ view = grub_gfxmenu_view_new (theme_path, model);
+ if (! view)
+ {
+ grub_print_error ();
+ grub_printf ("Starting graphical menu failed;\n"
+ "falling back to terminal based menu.\n");
+ grub_wait_after_message ();
+ grub_gfxmenu_model_destroy (model);
+ switch_to_text_menu ();
+ return grub_errno;
+ }
+
+ /* Initially select the default menu entry. */
+ int default_index = grub_menu_get_default_entry_index (menu);
+ grub_gfxmenu_model_set_selected_index (model, default_index);
+
+ /* Start the timer to execute the default entry. */
+ grub_gfxmenu_model_set_timeout (model);
+
+ /* Main event loop. */
+ int exit_requested = 0;
+ while (!exit_requested && !grub_menu_viewer_should_return ())
+ {
+ if (grub_gfxmenu_model_timeout_expired (model))
+ {
+ grub_gfxmenu_model_clear_timeout (model);
+ int i = grub_gfxmenu_model_get_selected_index (model);
+ grub_menu_entry_t e = grub_gfxmenu_model_get_entry (model, i);
+ grub_gfxmenu_view_execute_with_fallback (view, e);
+ continue;
+ }
+
+ grub_gfxmenu_view_draw (view);
+ grub_video_swap_buffers ();
+ handle_key_events (model, view, nested, &exit_requested);
+ }
+
+ grub_gfxmenu_view_destroy (view);
+ grub_gfxmenu_model_destroy (model);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_gfxmenu (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_menu_t menu = grub_env_get_data_slot ("menu");
+ if (!menu)
+ return grub_error (GRUB_ERR_MENU, "No menu context");
+
+ return show_menu (menu, 1);
+}
+
+static struct grub_menu_viewer menu_viewer =
+{
+ .name = "gfxmenu",
+ .show_menu = show_menu
+};
+
+GRUB_MOD_INIT (gfxmenu)
+{
+ (void) mod; /* To stop warning. */
+ grub_menu_viewer_register (&menu_viewer);
+ grub_register_command ("gfxmenu",
+ grub_cmd_gfxmenu, GRUB_COMMAND_FLAG_BOTH,
+ "gfxmenu", "Show graphical menu interface", 0);
+}
+
+GRUB_MOD_FINI (gfxmenu)
+{
+ grub_unregister_command ("gfxmenu");
+}
=== added file 'gfxmenu/gui_box.c'
--- gfxmenu/gui_box.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_box.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,367 @@
+/* gui_box.c - GUI container that stack components. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+struct component_node
+{
+ grub_gui_component_t component;
+ struct component_node *next;
+ struct component_node *prev;
+};
+
+typedef struct grub_gui_box *grub_gui_box_t;
+
+typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout,
+ int *width, int *height);
+
+struct grub_gui_box
+{
+ struct grub_gui_container_ops *container;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+
+ /* Doubly linked list of components with dummy head & tail nodes. */
+ struct component_node chead;
+ struct component_node ctail;
+
+ /* The layout function: differs for vertical and horizontal boxes. */
+ layout_func_t layout_func;
+};
+
+static void
+box_destroy (void *vself)
+{
+ grub_gui_box_t self = vself;
+ struct component_node *cur;
+ struct component_node *next;
+ for (cur = self->chead.next; cur != &self->ctail; cur = next)
+ {
+ /* Copy the 'next' pointer, since we need it for the next iteration,
+ and we're going to free the memory it is stored in. */
+ next = cur->next;
+ /* Destroy the child component. */
+ cur->component->ops->destroy (cur->component);
+ /* Free the linked list node. */
+ grub_free (cur);
+ }
+ grub_free (self);
+}
+
+static const char *
+box_get_id (void *vself)
+{
+ grub_gui_box_t self = vself;
+ return self->id;
+}
+
+static int
+box_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return (grub_strcmp (type, "component") == 0
+ || grub_strcmp (type, "container") == 0);
+}
+
+static void
+layout_horizontally (grub_gui_box_t self, int modify_layout,
+ int *width, int *height)
+{
+ /* Start at the left (chead) and set the x coordinates as we go right. */
+ /* All components have their width set to the box's width. */
+
+ struct component_node *cur;
+ int x = 0;
+ if (height)
+ *height = 0;
+ for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
+ {
+ grub_gui_component_t c = cur->component;
+ grub_video_rect_t r;
+
+ c->ops->get_preferred_size (c, &r.width, &r.height);
+
+ /* Check and possibly update the maximum width, if non-null. */
+ if (height && r.height > *height)
+ *height = r.height;
+
+ /* Set the component's bounds, if the flag is set. */
+ if (modify_layout)
+ {
+ r.x = x;
+ r.y = 0;
+ /* Width comes from the component's preferred size. */
+ r.height = self->bounds.height;
+ c->ops->set_bounds (c, &r);
+ }
+
+ x += r.width;
+ }
+
+ /* Return the sum of the children's preferred widths. */
+ if (width)
+ *width = x;
+}
+
+static void
+layout_vertically (grub_gui_box_t self, int modify_layout,
+ int *width, int *height)
+{
+ /* Start at the top (chead) and set the y coordinates as we go down. */
+ /* All components have their width set to the vbox's width. */
+
+ struct component_node *cur;
+ int y = 0;
+ if (width)
+ *width = 0;
+ for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
+ {
+ grub_gui_component_t c = cur->component;
+ grub_video_rect_t r;
+
+ c->ops->get_preferred_size (c, &r.width, &r.height);
+
+ /* Check and possibly update the maximum width, if non-null. */
+ if (width && r.width > *width)
+ *width = r.width;
+
+ /* Set the component's bounds, if the flag is set. */
+ if (modify_layout)
+ {
+ r.x = 0;
+ r.y = y;
+ r.width = self->bounds.width;
+ /* Height comes from the component's preferred size. */
+ c->ops->set_bounds (c, &r);
+ }
+
+ y += r.height;
+ }
+
+ /* Return the sum of the children's preferred heights. */
+ if (height)
+ *height = y;
+}
+
+static void
+box_paint (void *vself)
+{
+ grub_gui_box_t self = vself;
+ struct component_node *cur;
+ grub_video_rect_t vpsave;
+
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
+ {
+ grub_gui_component_t comp = cur->component;
+ comp->ops->paint (comp);
+ }
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+box_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_box_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+box_get_parent (void *vself)
+{
+ grub_gui_box_t self = vself;
+ return self->parent;
+}
+
+static void
+box_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_box_t self = vself;
+ self->bounds = *bounds;
+ self->layout_func (self, 1, 0, 0); /* Relayout the children. */
+}
+
+static void
+box_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_box_t self = vself;
+ *bounds = self->bounds;
+}
+
+/* The box's preferred size is based on the preferred sizes
+ of its children. */
+static void
+box_get_preferred_size (void *vself, int *width, int *height)
+{
+ grub_gui_box_t self = vself;
+ self->layout_func (self, 0, width, height); /* Just calculate the size. */
+
+ /* Allow preferred dimensions to override the computed dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+box_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_box_t self = vself;
+ if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+}
+
+static void
+box_add (void *vself, grub_gui_component_t comp)
+{
+ grub_gui_box_t self = vself;
+ struct component_node *node;
+ node = grub_malloc (sizeof (*node));
+ if (! node)
+ return; /* Note: probably should handle the error. */
+ node->component = comp;
+ /* Insert the node before the tail. */
+ node->prev = self->ctail.prev;
+ node->prev->next = node;
+ node->next = &self->ctail;
+ node->next->prev = node;
+
+ comp->ops->set_parent (comp, (grub_gui_container_t) self);
+ self->layout_func (self, 1, 0, 0); /* Relayout the children. */
+}
+
+static void
+box_remove (void *vself, grub_gui_component_t comp)
+{
+ grub_gui_box_t self = vself;
+ struct component_node *cur;
+ for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
+ {
+ if (cur->component == comp)
+ {
+ /* Unlink 'cur' from the list. */
+ cur->prev->next = cur->next;
+ cur->next->prev = cur->prev;
+ /* Free the node's memory (but don't destroy the component). */
+ grub_free (cur);
+ /* Must not loop again, since 'cur' would be dereferenced! */
+ return;
+ }
+ }
+}
+
+static void
+box_iterate_children (void *vself,
+ grub_gui_component_callback cb, void *userdata)
+{
+ grub_gui_box_t self = vself;
+ struct component_node *cur;
+ for (cur = self->chead.next; cur != &self->ctail; cur = cur->next)
+ cb (cur->component, userdata);
+}
+
+static struct grub_gui_container_ops box_ops =
+{
+ .component =
+ {
+ .destroy = box_destroy,
+ .get_id = box_get_id,
+ .is_instance = box_is_instance,
+ .paint = box_paint,
+ .set_parent = box_set_parent,
+ .get_parent = box_get_parent,
+ .set_bounds = box_set_bounds,
+ .get_bounds = box_get_bounds,
+ .get_preferred_size = box_get_preferred_size,
+ .set_property = box_set_property
+ },
+ .add = box_add,
+ .remove = box_remove,
+ .iterate_children = box_iterate_children
+};
+
+/* Box constructor. Specify the appropriate layout function to create
+ a horizontal or vertical stacking box. */
+static grub_gui_box_t
+box_new (layout_func_t layout_func)
+{
+ grub_gui_box_t box;
+ box = grub_malloc (sizeof (*box));
+ if (! box)
+ return 0;
+ box->container = &box_ops;
+ box->parent = 0;
+ box->bounds.x = 0;
+ box->bounds.y = 0;
+ box->bounds.width = 0;
+ box->bounds.height = 0;
+ box->id = 0;
+ box->preferred_width = -1;
+ box->preferred_height = -1;
+ box->chead.component = 0;
+ box->chead.prev = 0;
+ box->chead.next = &box->ctail;
+ box->ctail.component = 0;
+ box->ctail.prev = &box->chead;
+ box->ctail.next = 0;
+ box->layout_func = layout_func;
+ return box;
+}
+
+/* Create a new container that stacks its child components horizontally,
+ from left to right. Each child get a width corresponding to its
+ preferred width. The height of each child is set the maximum of the
+ preferred heights of all children. */
+grub_gui_container_t
+grub_gui_hbox_new (void)
+{
+ return (grub_gui_container_t) box_new (layout_horizontally);
+}
+
+/* Create a new container that stacks its child components verticallyj,
+ from top to bottom. Each child get a height corresponding to its
+ preferred height. The width of each child is set the maximum of the
+ preferred widths of all children. */
+grub_gui_container_t
+grub_gui_vbox_new (void)
+{
+ return (grub_gui_container_t) box_new (layout_vertically);
+}
=== added file 'gfxmenu/gui_canvas.c'
--- gfxmenu/gui_canvas.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_canvas.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,264 @@
+/* gui_canvas.c - GUI container allowing manually placed components. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+// TODO Add layering so that components can be properly overlaid.
+
+struct component_node
+{
+ grub_gui_component_t component;
+ struct component_node *next;
+};
+
+struct grub_gui_canvas
+{
+ struct grub_gui_container_ops *container;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ /* Component list (dummy head node). */
+ struct component_node components;
+};
+
+typedef struct grub_gui_canvas *grub_gui_canvas_t;
+
+static void
+canvas_destroy (void *vself)
+{
+ grub_gui_canvas_t self = vself;
+ struct component_node *cur;
+ struct component_node *next;
+ for (cur = self->components.next; cur; cur = next)
+ {
+ /* Copy the 'next' pointer, since we need it for the next iteration,
+ and we're going to free the memory it is stored in. */
+ next = cur->next;
+ /* Destroy the child component. */
+ cur->component->ops->destroy (cur->component);
+ /* Free the linked list node. */
+ grub_free (cur);
+ }
+ grub_free (self);
+}
+
+static const char *
+canvas_get_id (void *vself)
+{
+ grub_gui_canvas_t self = vself;
+ return self->id;
+}
+
+static int
+canvas_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return (grub_strcmp (type, "component") == 0
+ || grub_strcmp (type, "container") == 0);
+}
+
+static void
+canvas_paint (void *vself)
+{
+ grub_gui_canvas_t self = vself;
+ struct component_node *cur;
+ grub_video_rect_t vpsave;
+
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ for (cur = self->components.next; cur; cur = cur->next)
+ {
+ int pw;
+ int ph;
+ grub_video_rect_t r;
+ grub_gui_component_t comp;
+
+ comp = cur->component;
+
+ /* Give the child its preferred size. */
+ comp->ops->get_preferred_size (comp, &pw, &ph);
+ comp->ops->get_bounds (comp, &r);
+ if (r.width != pw || r.height != ph)
+ {
+ r.width = pw;
+ r.height = ph;
+ comp->ops->set_bounds (comp, &r);
+ }
+
+ /* Paint the child. */
+ comp->ops->paint (comp);
+ }
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+canvas_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_canvas_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+canvas_get_parent (void *vself)
+{
+ grub_gui_canvas_t self = vself;
+ return self->parent;
+}
+
+static void
+canvas_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_canvas_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+canvas_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_canvas_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+canvas_get_preferred_size (void *vself, int *width, int *height)
+{
+ grub_gui_canvas_t self = vself;
+ *width = 0;
+ *height = 0;
+
+ /* Allow preferred dimensions to override the empty dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+canvas_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_canvas_t self = vself;
+ if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+}
+
+static void
+canvas_add (void *vself, grub_gui_component_t comp)
+{
+ grub_gui_canvas_t self = vself;
+ struct component_node *node;
+ node = grub_malloc (sizeof (*node));
+ if (! node)
+ return; /* Note: probably should handle the error. */
+ node->component = comp;
+ node->next = self->components.next;
+ self->components.next = node;
+ comp->ops->set_parent (comp, (grub_gui_container_t) self);
+}
+
+static void
+canvas_remove (void *vself, grub_gui_component_t comp)
+{
+ grub_gui_canvas_t self = vself;
+ struct component_node *cur;
+ struct component_node *prev;
+ prev = &self->components;
+ for (cur = self->components.next; cur; prev = cur, cur = cur->next)
+ {
+ if (cur->component == comp)
+ {
+ /* Unlink 'cur' from the list. */
+ prev->next = cur->next;
+ /* Free the node's memory (but don't destroy the component). */
+ grub_free (cur);
+ /* Must not loop again, since 'cur' would be dereferenced! */
+ return;
+ }
+ }
+}
+
+static void
+canvas_iterate_children (void *vself,
+ grub_gui_component_callback cb, void *userdata)
+{
+ grub_gui_canvas_t self = vself;
+ struct component_node *cur;
+ for (cur = self->components.next; cur; cur = cur->next)
+ cb (cur->component, userdata);
+}
+
+static struct grub_gui_container_ops canvas_ops =
+{
+ .component =
+ {
+ .destroy = canvas_destroy,
+ .get_id = canvas_get_id,
+ .is_instance = canvas_is_instance,
+ .paint = canvas_paint,
+ .set_parent = canvas_set_parent,
+ .get_parent = canvas_get_parent,
+ .set_bounds = canvas_set_bounds,
+ .get_bounds = canvas_get_bounds,
+ .get_preferred_size = canvas_get_preferred_size,
+ .set_property = canvas_set_property
+ },
+ .add = canvas_add,
+ .remove = canvas_remove,
+ .iterate_children = canvas_iterate_children
+};
+
+grub_gui_container_t
+grub_gui_canvas_new (void)
+{
+ grub_gui_canvas_t canvas;
+ canvas = grub_malloc (sizeof (*canvas));
+ if (! canvas)
+ return 0;
+ canvas->container = &canvas_ops;
+ canvas->parent = 0;
+ canvas->bounds.x = 0;
+ canvas->bounds.y = 0;
+ canvas->bounds.width = 0;
+ canvas->bounds.height = 0;
+ canvas->id = 0;
+ canvas->preferred_width = -1;
+ canvas->preferred_height = -1;
+ canvas->components.component = 0;
+ canvas->components.next = 0;
+ return (grub_gui_container_t) canvas;
+}
=== added file 'gfxmenu/gui_circular_progress.c'
--- gfxmenu/gui_circular_progress.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_circular_progress.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,339 @@
+/* gui_circular_process.c - GUI circular progress indicator component. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct grub_gui_circular_progress
+{
+ struct grub_gui_component_ops *circprog_ops;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ int visible;
+ int start;
+ int end;
+ int value;
+ int num_ticks;
+ int start_angle;
+ int ticks_disappear;
+ char *theme_dir;
+ int need_to_load_pixmaps;
+ char *center_file;
+ char *tick_file;
+ struct grub_video_bitmap *center_bitmap;
+ struct grub_video_bitmap *tick_bitmap;
+};
+
+typedef struct grub_gui_circular_progress *circular_progress_t;
+
+static void
+circprog_destroy (void *vself)
+{
+ circular_progress_t self = vself;
+ grub_free (self);
+}
+
+static const char *
+circprog_get_id (void *vself)
+{
+ circular_progress_t self = vself;
+ return self->id;
+}
+
+static int
+circprog_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return grub_strcmp (type, "component") == 0;
+}
+
+static struct grub_video_bitmap *
+load_bitmap (const char *dir, const char *file)
+{
+ struct grub_video_bitmap *bitmap;
+ char *abspath;
+
+ /* Check arguments. */
+ if (! dir || ! file)
+ return 0;
+
+ /* Resolve to an absolute path. */
+ abspath = grub_resolve_relative_path (dir, file);
+ if (! abspath)
+ return 0;
+
+ /* Load the image. */
+ grub_errno = GRUB_ERR_NONE;
+ grub_video_bitmap_load (&bitmap, abspath);
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_free (abspath);
+ return bitmap;
+}
+
+static int
+check_pixmaps (circular_progress_t self)
+{
+ if (self->need_to_load_pixmaps)
+ {
+ if (self->center_bitmap)
+ grub_video_bitmap_destroy (self->center_bitmap);
+ self->center_bitmap = load_bitmap (self->theme_dir, self->center_file);
+ self->tick_bitmap = load_bitmap (self->theme_dir, self->tick_file);
+ self->need_to_load_pixmaps = 0;
+ }
+
+ return (self->center_bitmap != 0 && self->tick_bitmap != 0);
+}
+
+static void
+circprog_paint (void *vself)
+{
+ circular_progress_t self = vself;
+
+ if (! self->visible)
+ return;
+ if (! check_pixmaps (self))
+ return;
+
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+
+ int width = self->bounds.width;
+ int height = self->bounds.height;
+ int center_width = grub_video_bitmap_get_width (self->center_bitmap);
+ int center_height = grub_video_bitmap_get_height (self->center_bitmap);
+ int tick_width = grub_video_bitmap_get_width (self->tick_bitmap);
+ int tick_height = grub_video_bitmap_get_height (self->tick_bitmap);
+ grub_video_blit_bitmap (self->center_bitmap, GRUB_VIDEO_BLIT_BLEND,
+ (width - center_width) / 2,
+ (height - center_height) / 2, 0, 0,
+ center_width, center_height);
+
+ int radius = width / 2 - tick_width / 2 - 1;
+ int nticks = (self->num_ticks
+ * (self->value - self->start)
+ / (self->end - self->start));
+ int tick_begin;
+ int tick_end;
+ /* Do ticks appear or disappear as the value approached the end? */
+ if (self->ticks_disappear)
+ {
+ tick_begin = nticks;
+ tick_end = self->num_ticks - 1;
+ }
+ else
+ {
+ tick_begin = 0;
+ tick_end = nticks - 1;
+ }
+
+ int i;
+ for (i = tick_begin; i < tick_end; i++)
+ {
+ int x;
+ int y;
+ int angle;
+
+ /* Calculate the location of the tick. */
+ angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks;
+ x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
+ y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE);
+
+ /* Adjust (x,y) so the tick is centered. */
+ x -= tick_width / 2;
+ y -= tick_height / 2;
+
+ /* Draw the tick. */
+ grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND,
+ x, y, 0, 0, tick_width, tick_height);
+ }
+
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+circprog_set_parent (void *vself, grub_gui_container_t parent)
+{
+ circular_progress_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+circprog_get_parent (void *vself)
+{
+ circular_progress_t self = vself;
+ return self->parent;
+}
+
+static void
+circprog_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ circular_progress_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+circprog_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ circular_progress_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+circprog_get_preferred_size (void *vself, int *width, int *height)
+{
+ circular_progress_t self = vself;
+
+ *width = 0;
+ *height = 0;
+
+ /* Allow preferred dimensions to override the circprog dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+circprog_set_property (void *vself, const char *name, const char *value)
+{
+ circular_progress_t self = vself;
+ if (grub_strcmp (name, "value") == 0)
+ {
+ self->value = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "start") == 0)
+ {
+ self->start = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "end") == 0)
+ {
+ self->end = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "num_ticks") == 0)
+ {
+ self->num_ticks = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "start_angle") == 0)
+ {
+ self->start_angle = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "ticks_disappear") == 0)
+ {
+ self->ticks_disappear = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "center_bitmap") == 0)
+ {
+ self->need_to_load_pixmaps = 1;
+ grub_free (self->center_file);
+ self->center_file = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "tick_bitmap") == 0)
+ {
+ self->need_to_load_pixmaps = 1;
+ grub_free (self->tick_file);
+ self->tick_file = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "theme_dir") == 0)
+ {
+ self->need_to_load_pixmaps = 1;
+ grub_free (self->theme_dir);
+ self->theme_dir = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+ else if (grub_strcmp (name, "visible") == 0)
+ {
+ self->visible = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+}
+
+static struct grub_gui_component_ops circprog_ops =
+{
+ .destroy = circprog_destroy,
+ .get_id = circprog_get_id,
+ .is_instance = circprog_is_instance,
+ .paint = circprog_paint,
+ .set_parent = circprog_set_parent,
+ .get_parent = circprog_get_parent,
+ .set_bounds = circprog_set_bounds,
+ .get_bounds = circprog_get_bounds,
+ .get_preferred_size = circprog_get_preferred_size,
+ .set_property = circprog_set_property
+};
+
+grub_gui_component_t
+grub_gui_circular_progress_new (void)
+{
+ circular_progress_t self;
+ self = grub_malloc (sizeof (*self));
+ if (! self)
+ return 0;
+ self->circprog_ops = &circprog_ops;
+ self->parent = 0;
+ self->bounds.x = 0;
+ self->bounds.y = 0;
+ self->bounds.width = 0;
+ self->bounds.height = 0;
+ self->id = 0;
+ self->preferred_width = -1;
+ self->preferred_height = -1;
+ self->visible = 1;
+ self->start = 0;
+ self->end = 0;
+ self->value = 0;
+ self->num_ticks = 64;
+ self->start_angle = -64;
+ self->ticks_disappear = 0;
+
+ self->theme_dir = 0;
+ self->need_to_load_pixmaps = 0;
+ self->center_file = 0;
+ self->tick_file = 0;
+ self->center_bitmap = 0;
+ self->tick_bitmap = 0;
+
+ return (grub_gui_component_t) self;
+}
=== added file 'gfxmenu/gui_image.c'
--- gfxmenu/gui_image.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_image.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,262 @@
+/* gui_image.c - GUI component to display an image. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct grub_gui_image
+{
+ struct grub_gui_component_ops *image;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ struct grub_video_bitmap *raw_bitmap;
+ struct grub_video_bitmap *bitmap;
+};
+
+typedef struct grub_gui_image *grub_gui_image_t;
+
+static void
+image_destroy (void *vself)
+{
+ grub_gui_image_t self = vself;
+
+ /* Free the scaled bitmap, unless it's a reference to the raw bitmap. */
+ if (self->bitmap && (self->bitmap != self->raw_bitmap))
+ grub_video_bitmap_destroy (self->bitmap);
+ if (self->raw_bitmap)
+ grub_video_bitmap_destroy (self->raw_bitmap);
+
+ grub_free (self);
+}
+
+static const char *
+image_get_id (void *vself)
+{
+ grub_gui_image_t self = vself;
+ return self->id;
+}
+
+static int
+image_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return grub_strcmp (type, "component") == 0;
+}
+
+static void
+image_paint (void *vself)
+{
+ grub_gui_image_t self = vself;
+ if (! self->bitmap)
+ return;
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ grub_video_blit_bitmap (self->bitmap, GRUB_VIDEO_BLIT_BLEND,
+ 0, 0, 0, 0,
+ grub_video_bitmap_get_width (self->bitmap),
+ grub_video_bitmap_get_height (self->bitmap));
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+image_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_image_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+image_get_parent (void *vself)
+{
+ grub_gui_image_t self = vself;
+ return self->parent;
+}
+
+static void
+rescale_image (grub_gui_image_t self)
+{
+ if (! self->raw_bitmap)
+ {
+ if (self->bitmap)
+ {
+ grub_video_bitmap_destroy (self->bitmap);
+ self->bitmap = 0;
+ }
+ return;
+ }
+
+ unsigned width = self->bounds.width;
+ unsigned height = self->bounds.height;
+
+ if (self->bitmap
+ && (grub_video_bitmap_get_width (self->bitmap) == width)
+ && (grub_video_bitmap_get_height (self->bitmap) == height))
+ return; /* Nothing to do; already the right size. */
+
+ /* Free any old scaled bitmap,
+ unless it's a reference to the raw bitmap. */
+ if (self->bitmap && (self->bitmap != self->raw_bitmap))
+ grub_video_bitmap_destroy (self->bitmap);
+
+ /* Create a scaled bitmap, unless the requested size is the same
+ as the raw size -- in that case a reference is made. */
+ if (grub_video_bitmap_get_width (self->raw_bitmap) == width
+ && grub_video_bitmap_get_height (self->raw_bitmap) == height)
+ {
+ self->bitmap = self->raw_bitmap;
+ return;
+ }
+
+ /* Create the scaled bitmap. */
+ grub_video_bitmap_create_scaled (&self->bitmap,
+ width,
+ height,
+ self->raw_bitmap,
+ GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+ grub_errno = GRUB_ERR_NONE; /* Catch any errors. */
+}
+
+static void
+image_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_image_t self = vself;
+ self->bounds = *bounds;
+ rescale_image (self);
+}
+
+static void
+image_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_image_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+image_get_preferred_size (void *vself, int *width, int *height)
+{
+ grub_gui_image_t self = vself;
+
+ if (self->raw_bitmap)
+ {
+ *width = grub_video_bitmap_get_width (self->raw_bitmap);
+ *height = grub_video_bitmap_get_height (self->raw_bitmap);
+ }
+ else
+ {
+ *width = 0;
+ *height = 0;
+ }
+
+ /* Allow preferred dimensions to override the image dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+load_image (grub_gui_image_t self, const char *path)
+{
+ struct grub_video_bitmap *bitmap;
+ grub_errno = GRUB_ERR_NONE;
+ if (grub_video_bitmap_load (&bitmap, path) != GRUB_ERR_NONE)
+ {
+ /* We should log the error somehow. */
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+ if (self->bitmap && (self->bitmap != self->raw_bitmap))
+ grub_video_bitmap_destroy (self->bitmap);
+ if (self->raw_bitmap)
+ grub_video_bitmap_destroy (self->raw_bitmap);
+
+ self->raw_bitmap = bitmap;
+ rescale_image (self);
+}
+
+static void
+image_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_image_t self = vself;
+ if (grub_strcmp (name, "file") == 0)
+ {
+ load_image (self, value);
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+}
+
+static struct grub_gui_component_ops image_ops =
+{
+ .destroy = image_destroy,
+ .get_id = image_get_id,
+ .is_instance = image_is_instance,
+ .paint = image_paint,
+ .set_parent = image_set_parent,
+ .get_parent = image_get_parent,
+ .set_bounds = image_set_bounds,
+ .get_bounds = image_get_bounds,
+ .get_preferred_size = image_get_preferred_size,
+ .set_property = image_set_property
+};
+
+grub_gui_component_t
+grub_gui_image_new (void)
+{
+ grub_gui_image_t image;
+ image = grub_malloc (sizeof (*image));
+ if (! image)
+ return 0;
+ image->image = &image_ops;
+ image->parent = 0;
+ image->bounds.x = 0;
+ image->bounds.y = 0;
+ image->bounds.width = 0;
+ image->bounds.height = 0;
+ image->id = 0;
+ image->preferred_width = -1;
+ image->preferred_height = -1;
+ image->raw_bitmap = 0;
+ image->bitmap = 0;
+ return (grub_gui_component_t) image;
+}
+
=== added file 'gfxmenu/gui_label.c'
--- gfxmenu/gui_label.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_label.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,248 @@
+/* gui_label.c - GUI component to display a line of text. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+static const char *align_options[] =
+{
+ "left",
+ "center",
+ "right",
+ 0
+};
+
+enum align_mode {
+ align_left,
+ align_center,
+ align_right
+};
+
+struct grub_gui_label
+{
+ struct grub_gui_component_ops *label;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ int visible;
+ char *text;
+ grub_font_t font;
+ grub_gui_color_t color;
+ enum align_mode align;
+};
+
+typedef struct grub_gui_label *grub_gui_label_t;
+
+static void
+label_destroy (void *vself)
+{
+ grub_gui_label_t self = vself;
+ grub_free (self->text);
+ grub_free (self);
+}
+
+static const char *
+label_get_id (void *vself)
+{
+ grub_gui_label_t self = vself;
+ return self->id;
+}
+
+static int
+label_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return grub_strcmp (type, "component") == 0;
+}
+
+static void
+label_paint (void *vself)
+{
+ grub_gui_label_t self = vself;
+
+ if (! self->visible)
+ return;
+
+ /* Calculate the starting x coordinate. */
+ int left_x;
+ if (self->align == align_left)
+ left_x = 0;
+ else if (self->align == align_center)
+ left_x = ((self->bounds.width
+ - grub_font_get_string_width (self->font, self->text))
+ ) / 2;
+ else if (self->align == align_right)
+ left_x = (self->bounds.width
+ - grub_font_get_string_width (self->font, self->text));
+ else
+ return; /* Invalid alignment. */
+
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ grub_font_draw_string (self->text,
+ self->font,
+ grub_gui_map_color (self->color),
+ left_x,
+ grub_font_get_ascent (self->font));
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+label_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_label_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+label_get_parent (void *vself)
+{
+ grub_gui_label_t self = vself;
+ return self->parent;
+}
+
+static void
+label_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_label_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+label_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_label_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+label_get_preferred_size (void *vself, int *width, int *height)
+{
+ grub_gui_label_t self = vself;
+ *width = grub_font_get_string_width (self->font, self->text);
+ *height = (grub_font_get_ascent (self->font)
+ + grub_font_get_descent (self->font));
+
+ /* Allow preferred dimensions to override the computed dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+label_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_label_t self = vself;
+ if (grub_strcmp (name, "text") == 0)
+ {
+ grub_free (self->text);
+ if (! value)
+ value = "";
+ self->text = grub_strdup (value);
+ }
+ else if (grub_strcmp (name, "font") == 0)
+ {
+ self->font = grub_font_get (value);
+ }
+ else if (grub_strcmp (name, "color") == 0)
+ {
+ self->color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "align") == 0)
+ {
+ int i;
+ for (i = 0; align_options[i]; i++)
+ {
+ if (grub_strcmp (align_options[i], value) == 0)
+ {
+ self->align = i; /* Set the alignment mode. */
+ break;
+ }
+ }
+ }
+ else if (grub_strcmp (name, "visible") == 0)
+ {
+ self->visible = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+}
+
+static struct grub_gui_component_ops label_ops =
+{
+ .destroy = label_destroy,
+ .get_id = label_get_id,
+ .is_instance = label_is_instance,
+ .paint = label_paint,
+ .set_parent = label_set_parent,
+ .get_parent = label_get_parent,
+ .set_bounds = label_set_bounds,
+ .get_bounds = label_get_bounds,
+ .get_preferred_size = label_get_preferred_size,
+ .set_property = label_set_property
+};
+
+grub_gui_component_t
+grub_gui_label_new (void)
+{
+ grub_gui_label_t label;
+ label = grub_malloc (sizeof (*label));
+ if (! label)
+ return 0;
+ label->label = &label_ops;
+ label->parent = 0;
+ label->bounds.x = 0;
+ label->bounds.y = 0;
+ label->bounds.width = 0;
+ label->bounds.height = 0;
+ label->id = 0;
+ label->preferred_width = -1;
+ label->preferred_height = -1;
+ label->visible = 1;
+ label->text = grub_strdup ("");
+ label->font = grub_font_get ("Helvetica 10");
+ label->color.red = 0;
+ label->color.green = 0;
+ label->color.blue = 0;
+ label->color.alpha = 255;
+ label->align = align_left;
+ return (grub_gui_component_t) label;
+}
=== added file 'gfxmenu/gui_list.c'
--- gfxmenu/gui_list.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_list.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,624 @@
+/* gui_list.c - GUI component to display a selectable list of items. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct grub_gui_list_impl
+{
+ struct grub_gui_list_ops *list_ops;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ int visible;
+
+ int icon_width;
+ int icon_height;
+ int item_height;
+ int item_padding;
+ int item_icon_space;
+ int item_spacing;
+ grub_font_t item_font;
+ grub_font_t selected_item_font;
+ grub_gui_color_t item_color;
+ int selected_item_color_set;
+ grub_gui_color_t selected_item_color;
+
+ int draw_scrollbar;
+ int need_to_recreate_scrollbar;
+ char *scrollbar_frame_pattern;
+ char *scrollbar_thumb_pattern;
+ grub_gfxmenu_box_t scrollbar_frame;
+ grub_gfxmenu_box_t scrollbar_thumb;
+ int scrollbar_width;
+
+ int min_items_shown;
+ int max_items_shown;
+ int first_shown_index;
+
+ int need_to_recreate_boxes;
+ char *theme_dir;
+ char *menu_box_pattern;
+ char *selected_item_box_pattern;
+ grub_gfxmenu_box_t menu_box;
+ grub_gfxmenu_box_t selected_item_box;
+
+ grub_gfxmenu_icon_manager_t icon_manager;
+ grub_gfxmenu_model_t menu;
+};
+
+typedef struct grub_gui_list_impl *list_impl_t;
+
+static void
+list_destroy (void *vself)
+{
+ list_impl_t self = vself;
+
+ grub_free (self->theme_dir);
+ grub_free (self->menu_box_pattern);
+ grub_free (self->selected_item_box_pattern);
+ if (self->menu_box)
+ self->menu_box->destroy (self->menu_box);
+ if (self->selected_item_box)
+ self->selected_item_box->destroy (self->selected_item_box);
+ if (self->icon_manager)
+ grub_gfxmenu_icon_manager_destroy (self->icon_manager);
+
+ grub_free (self);
+}
+
+static int
+get_num_shown_items (list_impl_t self)
+{
+ int n = grub_gfxmenu_model_get_num_entries (self->menu);
+ if (self->min_items_shown != -1 && n < self->min_items_shown)
+ n = self->min_items_shown;
+ if (self->max_items_shown != -1 && n > self->max_items_shown)
+ n = self->max_items_shown;
+ return n;
+}
+
+static int
+check_boxes (list_impl_t self)
+{
+ if (self->need_to_recreate_boxes)
+ {
+ grub_gui_recreate_box (&self->menu_box,
+ self->menu_box_pattern,
+ self->theme_dir);
+
+ grub_gui_recreate_box (&self->selected_item_box,
+ self->selected_item_box_pattern,
+ self->theme_dir);
+
+ self->need_to_recreate_boxes = 0;
+ }
+
+ return (self->menu_box != 0 && self->selected_item_box != 0);
+}
+
+static int
+check_scrollbar (list_impl_t self)
+{
+ if (self->need_to_recreate_scrollbar)
+ {
+ grub_gui_recreate_box (&self->scrollbar_frame,
+ self->scrollbar_frame_pattern,
+ self->theme_dir);
+
+ grub_gui_recreate_box (&self->scrollbar_thumb,
+ self->scrollbar_thumb_pattern,
+ self->theme_dir);
+
+ self->need_to_recreate_scrollbar = 0;
+ }
+
+ return (self->scrollbar_frame != 0 && self->scrollbar_thumb != 0);
+}
+
+static const char *
+list_get_id (void *vself)
+{
+ list_impl_t self = vself;
+ return self->id;
+}
+
+static int
+list_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return (grub_strcmp (type, "component") == 0
+ || grub_strcmp (type, "list") == 0);
+}
+
+static struct grub_video_bitmap *
+get_item_icon (list_impl_t self, int item_index)
+{
+ grub_menu_entry_t entry;
+ entry = grub_gfxmenu_model_get_entry (self->menu, item_index);
+ if (! entry)
+ return 0;
+
+ return grub_gfxmenu_icon_manager_get_icon (self->icon_manager, entry);
+}
+
+static void
+make_selected_item_visible (list_impl_t self)
+{
+ int selected_index = grub_gfxmenu_model_get_selected_index (self->menu);
+ if (selected_index < 0)
+ return; /* No item is selected. */
+ int num_shown_items = get_num_shown_items (self);
+ int last_shown_index = self->first_shown_index + (num_shown_items - 1);
+ if (selected_index < self->first_shown_index)
+ self->first_shown_index = selected_index;
+ else if (selected_index > last_shown_index)
+ self->first_shown_index = selected_index - (num_shown_items - 1);
+}
+
+/* Draw a scrollbar on the menu. */
+static void
+draw_scrollbar (list_impl_t self,
+ int value, int extent, int min, int max,
+ int rightx, int topy, int height)
+{
+ grub_gfxmenu_box_t frame = self->scrollbar_frame;
+ grub_gfxmenu_box_t thumb = self->scrollbar_thumb;
+ int frame_vertical_pad = (frame->get_top_pad (frame)
+ + frame->get_bottom_pad (frame));
+ int frame_horizontal_pad = (frame->get_left_pad (frame)
+ + frame->get_right_pad (frame));
+ int tracktop = topy + frame->get_top_pad (frame);
+ int tracklen = height - frame_vertical_pad;
+ frame->set_content_size (frame, self->scrollbar_width, tracklen);
+ int thumby = tracktop + tracklen * (value - min) / (max - min);
+ int thumbheight = tracklen * extent / (max - min) + 1;
+ thumb->set_content_size (thumb,
+ self->scrollbar_width - frame_horizontal_pad,
+ thumbheight - (thumb->get_top_pad (thumb)
+ + thumb->get_bottom_pad (thumb)));
+ frame->draw (frame,
+ rightx - (self->scrollbar_width + frame_horizontal_pad),
+ topy);
+ thumb->draw (thumb,
+ rightx - (self->scrollbar_width - frame->get_right_pad (frame)),
+ thumby);
+}
+
+/* Draw the list of items. */
+static void
+draw_menu (list_impl_t self)
+{
+ if (! self->menu_box || ! self->selected_item_box)
+ return;
+
+ int boxpad = self->item_padding;
+ int icon_text_space = self->item_icon_space;
+ int item_vspace = self->item_spacing;
+
+ int ascent = grub_font_get_ascent (self->item_font);
+ int descent = grub_font_get_descent (self->item_font);
+ int item_height = self->item_height;
+
+ int total_num_items = grub_gfxmenu_model_get_num_entries (self->menu);
+ int num_shown_items = get_num_shown_items (self);
+ grub_gfxmenu_box_t box = self->menu_box;
+ int width = self->bounds.width;
+ int height = self->bounds.height;
+
+ int box_left_pad = box->get_left_pad (box);
+ int box_top_pad = box->get_top_pad (box);
+ int box_right_pad = box->get_right_pad (box);
+ int box_bottom_pad = box->get_bottom_pad (box);
+
+ box->set_content_size (box,
+ width - box_left_pad - box_right_pad,
+ height - box_top_pad - box_bottom_pad);
+
+ box->draw (box, 0, 0);
+
+ make_selected_item_visible (self);
+
+ int drawing_scrollbar = (self->draw_scrollbar
+ && (num_shown_items < total_num_items)
+ && check_scrollbar (self));
+
+ int scrollbar_h_space = drawing_scrollbar ? self->scrollbar_width : 0;
+
+ int item_top = box_top_pad + boxpad;
+ int item_left = box_left_pad + boxpad;
+ int menu_index;
+ int visible_index;
+
+ for (visible_index = 0, menu_index = self->first_shown_index;
+ visible_index < num_shown_items && menu_index < total_num_items;
+ visible_index++, menu_index++)
+ {
+ int is_selected =
+ (menu_index == grub_gfxmenu_model_get_selected_index (self->menu));
+
+ if (is_selected)
+ {
+ grub_gfxmenu_box_t selbox = self->selected_item_box;
+ int sel_leftpad = selbox->get_left_pad (selbox);
+ int sel_toppad = selbox->get_top_pad (selbox);
+ selbox->set_content_size (selbox,
+ (width - 2 * boxpad
+ - box_left_pad - box_right_pad
+ - scrollbar_h_space),
+ item_height);
+ selbox->draw (selbox,
+ item_left - sel_leftpad,
+ item_top - sel_toppad);
+ }
+
+ struct grub_video_bitmap *icon;
+ if ((icon = get_item_icon (self, menu_index)) != 0)
+ grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
+ item_left,
+ item_top + (item_height - self->icon_height) / 2,
+ 0, 0, self->icon_width, self->icon_height);
+
+ const char *item_title =
+ grub_gfxmenu_model_get_entry_title (self->menu, menu_index);
+ grub_font_t font =
+ (is_selected && self->selected_item_font
+ ? self->selected_item_font
+ : self->item_font);
+ grub_gui_color_t text_color =
+ ((is_selected && self->selected_item_color_set)
+ ? self->selected_item_color
+ : self->item_color);
+ grub_font_draw_string (item_title,
+ font,
+ grub_gui_map_color (text_color),
+ item_left + self->icon_width + icon_text_space,
+ (item_top + (item_height - (ascent + descent))
+ / 2 + ascent));
+
+ item_top += item_height + item_vspace;
+ }
+
+ if (drawing_scrollbar)
+ draw_scrollbar (self,
+ self->first_shown_index, num_shown_items,
+ 0, total_num_items,
+ width - box_right_pad + self->scrollbar_width,
+ box_top_pad + boxpad,
+ height - box_top_pad - box_bottom_pad);
+}
+
+static void
+list_paint (void *vself)
+{
+ list_impl_t self = vself;
+
+ if (! self->visible)
+ return;
+
+ check_boxes (self);
+
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+ draw_menu (self);
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+list_set_parent (void *vself, grub_gui_container_t parent)
+{
+ list_impl_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+list_get_parent (void *vself)
+{
+ list_impl_t self = vself;
+ return self->parent;
+}
+
+static void
+list_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ list_impl_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+list_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ list_impl_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+list_get_preferred_size (void *vself, int *width, int *height)
+{
+ list_impl_t self = vself;
+
+ if (check_boxes (self))
+ {
+ int boxpad = self->item_padding;
+ int item_vspace = self->item_spacing;
+ int item_height = self->item_height;
+ int num_items = get_num_shown_items (self);
+
+ grub_gfxmenu_box_t box = self->menu_box;
+ int box_left_pad = box->get_left_pad (box);
+ int box_top_pad = box->get_top_pad (box);
+ int box_right_pad = box->get_right_pad (box);
+ int box_bottom_pad = box->get_bottom_pad (box);
+
+ *width = 400 + 2 * boxpad + box_left_pad + box_right_pad;
+
+ /* Set the menu box height to fit the items. */
+ *height = (item_height * num_items
+ + item_vspace * (num_items - 1)
+ + 2 * boxpad
+ + box_top_pad + box_bottom_pad);
+ }
+ else
+ {
+ *width = 0;
+ *height = 0;
+ }
+
+ /* Allow preferred dimensions to override the computed dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+list_set_property (void *vself, const char *name, const char *value)
+{
+ list_impl_t self = vself;
+ if (grub_strcmp (name, "item_font") == 0)
+ {
+ self->item_font = grub_font_get (value);
+ }
+ else if (grub_strcmp (name, "selected_item_font") == 0)
+ {
+ if (! value || grub_strcmp (value, "inherit") == 0)
+ self->selected_item_font = 0;
+ else
+ self->selected_item_font = grub_font_get (value);
+ }
+ else if (grub_strcmp (name, "item_color") == 0)
+ {
+ self->item_color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "selected_item_color") == 0)
+ {
+ if (! value || grub_strcmp (value, "inherit") == 0)
+ {
+ self->selected_item_color_set = 0;
+ }
+ else
+ {
+ self->selected_item_color_set = 1;
+ self->selected_item_color = grub_gui_parse_color (value);
+ }
+ }
+ else if (grub_strcmp (name, "icon_width") == 0)
+ {
+ self->icon_width = grub_strtol (value, 0, 10);
+ grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
+ self->icon_width,
+ self->icon_height);
+ }
+ else if (grub_strcmp (name, "icon_height") == 0)
+ {
+ self->icon_height = grub_strtol (value, 0, 10);
+ grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
+ self->icon_width,
+ self->icon_height);
+ }
+ else if (grub_strcmp (name, "item_height") == 0)
+ {
+ self->item_height = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "item_padding") == 0)
+ {
+ self->item_padding = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "item_icon_space") == 0)
+ {
+ self->item_icon_space = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "item_spacing") == 0)
+ {
+ self->item_spacing = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "visible") == 0)
+ {
+ self->visible = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "menu_pixmap_style") == 0)
+ {
+ self->need_to_recreate_boxes = 1;
+ grub_free (self->menu_box_pattern);
+ self->menu_box_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "selected_item_pixmap_style") == 0)
+ {
+ self->need_to_recreate_boxes = 1;
+ grub_free (self->selected_item_box_pattern);
+ self->selected_item_box_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "scrollbar_frame") == 0)
+ {
+ self->need_to_recreate_scrollbar = 1;
+ grub_free (self->scrollbar_frame_pattern);
+ self->scrollbar_frame_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "scrollbar_thumb") == 0)
+ {
+ self->need_to_recreate_scrollbar = 1;
+ grub_free (self->scrollbar_thumb_pattern);
+ self->scrollbar_thumb_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "scrollbar_width") == 0)
+ {
+ self->scrollbar_width = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "scrollbar") == 0)
+ {
+ self->draw_scrollbar = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "min_items_shown") == 0)
+ {
+ self->min_items_shown = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "max_items_shown") == 0)
+ {
+ self->max_items_shown = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "theme_dir") == 0)
+ {
+ self->need_to_recreate_boxes = 1;
+ grub_free (self->theme_dir);
+ self->theme_dir = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+}
+
+/* Set necessary information that the gfxmenu view provides. */
+static void
+list_set_view_info (void *vself,
+ const char *theme_path,
+ grub_gfxmenu_model_t menu)
+{
+ list_impl_t self = vself;
+ grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, theme_path);
+ self->menu = menu;
+}
+
+static struct grub_gui_list_ops list_ops =
+{
+ .component_ops =
+ {
+ .destroy = list_destroy,
+ .get_id = list_get_id,
+ .is_instance = list_is_instance,
+ .paint = list_paint,
+ .set_parent = list_set_parent,
+ .get_parent = list_get_parent,
+ .set_bounds = list_set_bounds,
+ .get_bounds = list_get_bounds,
+ .get_preferred_size = list_get_preferred_size,
+ .set_property = list_set_property
+ },
+ .set_view_info = list_set_view_info
+};
+
+grub_gui_component_t
+grub_gui_list_new (void)
+{
+ list_impl_t self;
+ grub_font_t default_font;
+ grub_gui_color_t default_fg_color;
+ grub_gui_color_t default_bg_color;
+
+ self = grub_malloc (sizeof (*self));
+ if (! self)
+ return 0;
+
+ self->list_ops = &list_ops;
+ self->parent = 0;
+ self->bounds.x = 0;
+ self->bounds.y = 0;
+ self->bounds.width = 0;
+ self->bounds.height = 0;
+ self->id = 0;
+ self->preferred_width = -1;
+ self->preferred_height = -1;
+ self->visible = 1;
+
+ default_font = grub_font_get ("Helvetica 12");
+ default_fg_color = grub_gui_color_rgb (0, 0, 0);
+ default_bg_color = grub_gui_color_rgb (255, 255, 255);
+
+ self->icon_width = 32;
+ self->icon_height = 32;
+ self->item_height = 42;
+ self->item_padding = 14;
+ self->item_icon_space = 4;
+ self->item_spacing = 16;
+ self->item_font = default_font;
+ self->selected_item_font = 0; /* Default to using the item_font. */
+ self->item_color = default_fg_color;
+ self->selected_item_color_set = 0; /* Default to using the item_color. */
+ self->selected_item_color = default_fg_color;
+
+ self->draw_scrollbar = 1;
+ self->need_to_recreate_scrollbar = 1;
+ self->scrollbar_frame = 0;
+ self->scrollbar_thumb = 0;
+ self->scrollbar_frame_pattern = 0;
+ self->scrollbar_thumb_pattern = 0;
+ self->scrollbar_width = 16;
+
+ self->min_items_shown = -1;
+ self->max_items_shown = -1;
+ self->first_shown_index = 0;
+
+ self->need_to_recreate_boxes = 0;
+ self->theme_dir = 0;
+ self->menu_box_pattern = 0;
+ self->selected_item_box_pattern = 0;
+ self->menu_box = grub_gfxmenu_create_box (0, 0);
+ self->selected_item_box = grub_gfxmenu_create_box (0, 0);
+
+ self->icon_manager = grub_gfxmenu_icon_manager_new ();
+ if (! self->icon_manager)
+ {
+ self->list_ops->component_ops.destroy (self);
+ return 0;
+ }
+ grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager,
+ self->icon_width,
+ self->icon_height);
+ return (grub_gui_component_t) self;
+}
=== added file 'gfxmenu/gui_progress_bar.c'
--- gfxmenu/gui_progress_bar.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_progress_bar.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,378 @@
+/* gui_progress_bar.c - GUI progress bar component. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct grub_gui_progress_bar
+{
+ struct grub_gui_component_ops *progress_bar;
+
+ grub_gui_container_t parent;
+ grub_video_rect_t bounds;
+ char *id;
+ int preferred_width;
+ int preferred_height;
+ int visible;
+ int start;
+ int end;
+ int value;
+ int show_text;
+ char *text;
+ grub_font_t font;
+ grub_gui_color_t text_color;
+ grub_gui_color_t border_color;
+ grub_gui_color_t bg_color;
+ grub_gui_color_t fg_color;
+
+ char *theme_dir;
+ int need_to_recreate_pixmaps;
+ char *bar_pattern;
+ char *highlight_pattern;
+ grub_gfxmenu_box_t bar_box;
+ grub_gfxmenu_box_t highlight_box;
+};
+
+typedef struct grub_gui_progress_bar *grub_gui_progress_bar_t;
+
+static void
+progress_bar_destroy (void *vself)
+{
+ grub_gui_progress_bar_t self = vself;
+ grub_free (self);
+}
+
+static const char *
+progress_bar_get_id (void *vself)
+{
+ grub_gui_progress_bar_t self = vself;
+ return self->id;
+}
+
+static int
+progress_bar_is_instance (void *vself __attribute__((unused)), const char *type)
+{
+ return grub_strcmp (type, "component") == 0;
+}
+
+static int
+check_pixmaps (grub_gui_progress_bar_t self)
+{
+ if (self->need_to_recreate_pixmaps)
+ {
+ grub_gui_recreate_box (&self->bar_box,
+ self->bar_pattern,
+ self->theme_dir);
+
+ grub_gui_recreate_box (&self->highlight_box,
+ self->highlight_pattern,
+ self->theme_dir);
+
+ self->need_to_recreate_pixmaps = 0;
+ }
+
+ return (self->bar_box != 0 && self->highlight_box != 0);
+}
+
+static void
+draw_filled_rect_bar (grub_gui_progress_bar_t self)
+{
+ /* Set the progress bar's frame. */
+ grub_video_rect_t f;
+ f.x = 1;
+ f.y = 1;
+ f.width = self->bounds.width - 2;
+ f.height = self->bounds.height - 2;
+
+ /* Border. */
+ grub_video_fill_rect (grub_gui_map_color (self->border_color),
+ f.x - 1, f.y - 1,
+ f.width + 2, f.height + 2);
+
+ /* Bar background. */
+ int barwidth = (f.width
+ * (self->value - self->start)
+ / (self->end - self->start));
+ grub_video_fill_rect (grub_gui_map_color (self->bg_color),
+ f.x + barwidth, f.y,
+ f.width - barwidth, f.height);
+
+ /* Bar foreground. */
+ grub_video_fill_rect (grub_gui_map_color (self->fg_color),
+ f.x, f.y,
+ barwidth, f.height);
+}
+
+static void
+draw_pixmap_bar (grub_gui_progress_bar_t self)
+{
+ grub_gfxmenu_box_t bar = self->bar_box;
+ grub_gfxmenu_box_t hl = self->highlight_box;
+ int w = self->bounds.width;
+ int h = self->bounds.height;
+ int bar_l_pad = bar->get_left_pad (bar);
+ int bar_r_pad = bar->get_right_pad (bar);
+ int bar_t_pad = bar->get_top_pad (bar);
+ int bar_b_pad = bar->get_bottom_pad (bar);
+ int bar_h_pad = bar_l_pad + bar_r_pad;
+ int bar_v_pad = bar_t_pad + bar_b_pad;
+ int tracklen = w - bar_h_pad;
+ int trackheight = h - bar_v_pad;
+ bar->set_content_size (bar, tracklen, trackheight);
+
+ int barwidth = (tracklen
+ * (self->value - self->start)
+ / (self->end - self->start));
+ hl->set_content_size (hl, barwidth, h - bar_v_pad);
+
+ bar->draw (bar, 0, 0);
+ hl->draw (hl, bar_l_pad, bar_t_pad);
+}
+
+static void
+draw_text (grub_gui_progress_bar_t self)
+{
+ const char *text = self->text;
+ if (text && self->show_text)
+ {
+ grub_font_t font = self->font;
+ grub_video_color_t text_color = grub_gui_map_color (self->text_color);
+ int width = self->bounds.width;
+ int height = self->bounds.height;
+
+ /* Center the text. */
+ int text_width = grub_font_get_string_width (font, text);
+ int x = (width - text_width) / 2;
+ int y = ((height - grub_font_get_descent (font)) / 2
+ + grub_font_get_ascent (font) / 2);
+ grub_font_draw_string (text, font, text_color, x, y);
+ }
+}
+
+static void
+progress_bar_paint (void *vself)
+{
+ grub_gui_progress_bar_t self = vself;
+ if (! self->visible)
+ return;
+
+ grub_video_rect_t vpsave;
+ grub_gui_set_viewport (&self->bounds, &vpsave);
+
+ if (check_pixmaps (self))
+ draw_pixmap_bar (self);
+ else
+ draw_filled_rect_bar (self);
+
+ draw_text (self);
+
+ grub_gui_restore_viewport (&vpsave);
+}
+
+static void
+progress_bar_set_parent (void *vself, grub_gui_container_t parent)
+{
+ grub_gui_progress_bar_t self = vself;
+ self->parent = parent;
+}
+
+static grub_gui_container_t
+progress_bar_get_parent (void *vself)
+{
+ grub_gui_progress_bar_t self = vself;
+ return self->parent;
+}
+
+static void
+progress_bar_set_bounds (void *vself, const grub_video_rect_t *bounds)
+{
+ grub_gui_progress_bar_t self = vself;
+ self->bounds = *bounds;
+}
+
+static void
+progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds)
+{
+ grub_gui_progress_bar_t self = vself;
+ *bounds = self->bounds;
+}
+
+static void
+progress_bar_get_preferred_size (void *vself, int *width, int *height)
+{
+ grub_gui_progress_bar_t self = vself;
+
+ *width = 200;
+ *height = 28;
+
+ /* Allow preferred dimensions to override the progress_bar dimensions. */
+ if (self->preferred_width >= 0)
+ *width = self->preferred_width;
+ if (self->preferred_height >= 0)
+ *height = self->preferred_height;
+}
+
+static void
+progress_bar_set_property (void *vself, const char *name, const char *value)
+{
+ grub_gui_progress_bar_t self = vself;
+ if (grub_strcmp (name, "value") == 0)
+ {
+ self->value = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "start") == 0)
+ {
+ self->start = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "end") == 0)
+ {
+ self->end = grub_strtol (value, 0, 10);
+ }
+ else if (grub_strcmp (name, "text") == 0)
+ {
+ grub_free (self->text);
+ if (! value)
+ value = "";
+ self->text = grub_strdup (value);
+ }
+ else if (grub_strcmp (name, "font") == 0)
+ {
+ self->font = grub_font_get (value);
+ }
+ else if (grub_strcmp (name, "text_color") == 0)
+ {
+ self->text_color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "border_color") == 0)
+ {
+ self->border_color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "bg_color") == 0)
+ {
+ self->bg_color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "fg_color") == 0)
+ {
+ self->fg_color = grub_gui_parse_color (value);
+ }
+ else if (grub_strcmp (name, "bar_style") == 0)
+ {
+ self->need_to_recreate_pixmaps = 1;
+ grub_free (self->bar_pattern);
+ self->bar_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "highlight_style") == 0)
+ {
+ self->need_to_recreate_pixmaps = 1;
+ grub_free (self->highlight_pattern);
+ self->highlight_pattern = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "theme_dir") == 0)
+ {
+ self->need_to_recreate_pixmaps = 1;
+ grub_free (self->theme_dir);
+ self->theme_dir = value ? grub_strdup (value) : 0;
+ }
+ else if (grub_strcmp (name, "preferred_size") == 0)
+ {
+ int w;
+ int h;
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ self->preferred_width = w;
+ self->preferred_height = h;
+ }
+ }
+ else if (grub_strcmp (name, "visible") == 0)
+ {
+ self->visible = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "show_text") == 0)
+ {
+ self->show_text = grub_strcmp (value, "false") != 0;
+ }
+ else if (grub_strcmp (name, "id") == 0)
+ {
+ grub_free (self->id);
+ if (value)
+ self->id = grub_strdup (value);
+ else
+ self->id = 0;
+ }
+}
+
+static struct grub_gui_component_ops progress_bar_ops =
+{
+ .destroy = progress_bar_destroy,
+ .get_id = progress_bar_get_id,
+ .is_instance = progress_bar_is_instance,
+ .paint = progress_bar_paint,
+ .set_parent = progress_bar_set_parent,
+ .get_parent = progress_bar_get_parent,
+ .set_bounds = progress_bar_set_bounds,
+ .get_bounds = progress_bar_get_bounds,
+ .get_preferred_size = progress_bar_get_preferred_size,
+ .set_property = progress_bar_set_property
+};
+
+grub_gui_component_t
+grub_gui_progress_bar_new (void)
+{
+ grub_gui_progress_bar_t self;
+ self = grub_malloc (sizeof (*self));
+ if (! self)
+ return 0;
+ self->progress_bar = &progress_bar_ops;
+ self->parent = 0;
+ self->bounds.x = 0;
+ self->bounds.y = 0;
+ self->bounds.width = 0;
+ self->bounds.height = 0;
+ self->id = 0;
+ self->preferred_width = -1;
+ self->preferred_height = -1;
+ self->visible = 1;
+ self->start = 0;
+ self->end = 0;
+ self->value = 0;
+ self->show_text = 1;
+ self->text = grub_strdup ("");
+ self->font = grub_font_get ("Helvetica 10");
+ grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 };
+ grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 };
+ grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 };
+ self->text_color = black;
+ self->border_color = black;
+ self->bg_color = gray;
+ self->fg_color = lightgray;
+
+ self->theme_dir = 0;
+ self->need_to_recreate_pixmaps = 0;
+ self->bar_pattern = 0;
+ self->highlight_pattern = 0;
+ self->bar_box = 0;
+ self->highlight_box = 0;
+
+ return (grub_gui_component_t) self;
+}
=== added file 'gfxmenu/gui_string_util.c'
--- gfxmenu/gui_string_util.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_string_util.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,348 @@
+/* gui_string_util.c - String utilities used by the GUI system. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+/* Create a new NUL-terminated string on the heap as a substring of BUF.
+ The range of buf included is the half-open interval [START,END).
+ The index START is inclusive, END is exclusive. */
+char *
+grub_new_substring (const char *buf,
+ grub_size_t start, grub_size_t end)
+{
+ if (end < start)
+ return 0;
+ grub_size_t len = end - start;
+ char *s = grub_malloc (len + 1);
+ if (! s)
+ return 0;
+ grub_memcpy (s, buf + start, len);
+ s[len] = '\0';
+ return s;
+}
+
+/* Eliminate "." and ".." path elements from PATH. A new heap-allocated
+ string is returned. */
+static char *
+canonicalize_path (const char *path)
+{
+ int i;
+ const char *p;
+ char *newpath = 0;
+
+ /* Count the path components in path. */
+ int components = 1;
+ for (p = path; *p; p++)
+ if (*p == '/')
+ components++;
+
+ char **path_array = grub_malloc (components * sizeof (*path_array));
+ if (! path_array)
+ return 0;
+
+ /* Initialize array elements to NULL pointers; in case once of the
+ allocations fails, the cleanup code can just call grub_free() for all
+ pointers in the array. */
+ for (i = 0; i < components; i++)
+ path_array[i] = 0;
+
+ /* Parse the path into path_array. */
+ p = path;
+ for (i = 0; i < components && p; i++)
+ {
+ /* Find the end of the path element. */
+ const char *end = grub_strchr (p, '/');
+ if (!end)
+ end = p + grub_strlen (p);
+
+ /* Copy the element. */
+ path_array[i] = grub_new_substring (p, 0, end - p);
+ if (!path_array[i])
+ goto cleanup;
+
+ /* Advance p to point to the start of the next element, or NULL. */
+ if (*end)
+ p = end + 1;
+ else
+ p = 0;
+ }
+
+ /* Eliminate '.' and '..' elements from the path array. */
+ int newpath_length = 0;
+ for (i = components - 1; i >= 0; --i)
+ {
+ if (! grub_strcmp (path_array[i], "."))
+ {
+ grub_free (path_array[i]);
+ path_array[i] = 0;
+ }
+ else if (! grub_strcmp (path_array[i], "..")
+ && i > 0)
+ {
+ /* Delete the '..' and the prior path element. */
+ grub_free (path_array[i]);
+ path_array[i] = 0;
+ --i;
+ grub_free (path_array[i]);
+ path_array[i] = 0;
+ }
+ else
+ {
+ newpath_length += grub_strlen (path_array[i]) + 1;
+ }
+ }
+
+ /* Construct a new path string. */
+ newpath = grub_malloc (newpath_length + 1);
+ if (! newpath)
+ goto cleanup;
+
+ newpath[0] = '\0';
+ char *newpath_end = newpath;
+ int first = 1;
+ for (i = 0; i < components; i++)
+ {
+ char *element = path_array[i];
+ if (element)
+ {
+ /* For all components but the first, prefix with a slash. */
+ if (! first)
+ newpath_end = grub_stpcpy (newpath_end, "/");
+ newpath_end = grub_stpcpy (newpath_end, element);
+ first = 0;
+ }
+ }
+
+cleanup:
+ for (i = 0; i < components; i++)
+ grub_free (path_array[i]);
+ grub_free (path_array);
+
+ return newpath;
+}
+
+/* Return a new heap-allocated string representing to absolute path
+ to the file referred to by PATH. If PATH is an absolute path, then
+ the returned path is a copy of PATH. If PATH is a relative path, then
+ BASE is with PATH used to construct the absolute path. */
+char *
+grub_resolve_relative_path (const char *base, const char *path)
+{
+ char *abspath;
+ char *canonpath;
+ char *p;
+
+ /* If PATH is an absolute path, then just use it as is. */
+ if (path[0] == '/' || path[0] == '(')
+ return canonicalize_path (path);
+
+ abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 1);
+ if (!abspath)
+ return 0;
+
+ /* Concatenate BASE and PATH.
+ Note that BASE is expected to have a trailing slash. */
+ p = grub_stpcpy (abspath, base);
+ grub_stpcpy (p, path);
+
+ canonpath = canonicalize_path (abspath);
+ if (!canonpath)
+ return abspath;
+
+ grub_free (abspath);
+ return canonpath;
+}
+
+/* Get the path of the directory where the file at FILE_PATH is located.
+ FILE_PATH should refer to a file, not a directory. The returned path
+ includes a trailing slash.
+ This does not handle GRUB "(hd0,0)" paths properly yet since it only
+ looks at slashes. */
+char *
+grub_get_dirname (const char *file_path)
+{
+ int i;
+ int last_slash;
+
+ last_slash = -1;
+ for (i = grub_strlen (file_path) - 1; i >= 0; --i)
+ {
+ if (file_path[i] == '/')
+ {
+ last_slash = i;
+ break;
+ }
+ }
+ if (last_slash == -1)
+ return grub_strdup ("/");
+
+ return grub_new_substring (file_path, 0, last_slash + 1);
+}
+
+static __inline int
+isxdigit (char c)
+{
+ return ((c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F'));
+}
+
+static int
+parse_hex_color_component (const char *s, unsigned start, unsigned end)
+{
+ unsigned len;
+ char buf[3];
+
+ len = end - start;
+ /* Check the limits so we don't overrun the buffer. */
+ if (len < 1 || len > 2)
+ return 0;
+
+ if (len == 1)
+ {
+ buf[0] = s[start]; /* Get the first and only hex digit. */
+ buf[1] = buf[0]; /* Duplicate the hex digit. */
+ }
+ else if (len == 2)
+ {
+ buf[0] = s[start];
+ buf[1] = s[start + 1];
+ }
+
+ buf[2] = '\0';
+
+ return grub_strtoul (buf, 0, 16);
+}
+
+/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA",
+ "#RRGGBB", or "#RRGGBBAA". */
+grub_gui_color_t
+grub_gui_parse_color (const char *s)
+{
+ grub_gui_color_t c;
+
+ /* Skip whitespace. */
+ while (*s && grub_isspace (*s))
+ s++;
+
+ if (*s == '#')
+ {
+ /* HTML-style. Number if hex digits:
+ [6] #RRGGBB [3] #RGB
+ [8] #RRGGBBAA [4] #RGBA */
+
+ s++; /* Skip the '#'. */
+ /* Count the hexits to determine the format. */
+ int hexits = 0;
+ const char *end = s;
+ while (isxdigit (*end))
+ {
+ end++;
+ hexits++;
+ }
+
+ /* Parse the color components based on the format. */
+ if (hexits == 3 || hexits == 4)
+ {
+ c.red = parse_hex_color_component (s, 0, 1);
+ c.green = parse_hex_color_component (s, 1, 2);
+ c.blue = parse_hex_color_component (s, 2, 3);
+ if (hexits == 4)
+ c.alpha = parse_hex_color_component (s, 3, 4);
+ else
+ c.alpha = 255;
+ }
+ else if (hexits == 6 || hexits == 8)
+ {
+ c.red = parse_hex_color_component (s, 0, 2);
+ c.green = parse_hex_color_component (s, 2, 4);
+ c.blue = parse_hex_color_component (s, 4, 6);
+ if (hexits == 8)
+ c.alpha = parse_hex_color_component (s, 6, 8);
+ else
+ c.alpha = 255;
+ }
+ else
+ goto fail;
+ }
+ else if (grub_isdigit (*s))
+ {
+ /* Comma separated decimal values. */
+ c.red = grub_strtoul (s, 0, 0);
+ if ((s = grub_strchr (s, ',')) == 0)
+ goto fail;
+ s++;
+ c.green = grub_strtoul (s, 0, 0);
+ if ((s = grub_strchr (s, ',')) == 0)
+ goto fail;
+ s++;
+ c.blue = grub_strtoul (s, 0, 0);
+ if ((s = grub_strchr (s, ',')) == 0)
+ c.alpha = 255;
+ else
+ {
+ s++;
+ c.alpha = grub_strtoul (s, 0, 0);
+ }
+ }
+ else
+ {
+ if (! grub_gui_get_named_color (s, &c))
+ goto fail;
+ }
+
+ return c;
+
+fail:
+ c.red = 0;
+ c.green = 0;
+ c.blue = 0;
+ c.alpha = 255;
+ return c;
+}
+
+/* Parse a value in the form "(x, y)", storing the first element (x) into
+ *PX and the second element (y) into *PY.
+ Returns 1 if successful, 0 if failed to parse. */
+int
+grub_gui_parse_2_tuple (const char *s, int *px, int *py)
+{
+ int x;
+ int y;
+
+ while (*s && grub_isspace (*s))
+ s++;
+ if (*s != '(')
+ return 0;
+ s++; /* Skip the opening parentheses. */
+ if (! *s)
+ return 0;
+ x = grub_strtol (s, 0, 10);
+ if ((s = grub_strchr (s, ',')) == 0)
+ return 0;
+ s++; /* Skip the element separator (the comma). */
+ y = grub_strtol (s, 0, 10);
+
+ *px = x;
+ *py = y;
+ return 1;
+}
=== added file 'gfxmenu/gui_util.c'
--- gfxmenu/gui_util.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/gui_util.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,101 @@
+/* gui_util.c - GUI utility functions. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+
+struct find_by_id_state
+{
+ const char *match_id;
+ grub_gui_component_callback match_callback;
+ void *match_userdata;
+};
+
+static void
+find_by_id_recursively (grub_gui_component_t component, void *userdata)
+{
+ struct find_by_id_state *state;
+ const char *id;
+
+ state = (struct find_by_id_state *) userdata;
+ id = component->ops->get_id (component);
+ if (id && grub_strcmp (id, state->match_id) == 0)
+ state->match_callback (component, state->match_userdata);
+
+ if (component->ops->is_instance (component, "container"))
+ {
+ grub_gui_container_t container;
+ container = (grub_gui_container_t) component;
+ container->ops->iterate_children (container,
+ find_by_id_recursively,
+ state);
+ }
+}
+
+void
+grub_gui_find_by_id (grub_gui_component_t root,
+ const char *id,
+ grub_gui_component_callback cb,
+ void *userdata)
+{
+ struct find_by_id_state state;
+ state.match_id = id;
+ state.match_callback = cb;
+ state.match_userdata = userdata;
+ find_by_id_recursively (root, &state);
+}
+
+
+struct iterate_recursively_state
+{
+ grub_gui_component_callback callback;
+ void *userdata;
+};
+
+static
+void iterate_recursively_cb (grub_gui_component_t component, void *userdata)
+{
+ struct iterate_recursively_state *state;
+
+ state = (struct iterate_recursively_state *) userdata;
+ state->callback (component, state->userdata);
+
+ if (component->ops->is_instance (component, "container"))
+ {
+ grub_gui_container_t container;
+ container = (grub_gui_container_t) component;
+ container->ops->iterate_children (container,
+ iterate_recursively_cb,
+ state);
+ }
+}
+
+void
+grub_gui_iterate_recursively (grub_gui_component_t root,
+ grub_gui_component_callback cb,
+ void *userdata)
+{
+ struct iterate_recursively_state state;
+ state.callback = cb;
+ state.userdata = userdata;
+ iterate_recursively_cb (root, &state);
+}
=== added file 'gfxmenu/icon_manager.c'
--- gfxmenu/icon_manager.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/icon_manager.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,254 @@
+/* icon_manager.c - gfxmenu icon manager. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Currently hard coded to '.png' extension. */
+static const char icon_extension[] = ".png";
+
+typedef struct icon_entry
+{
+ char *class_name;
+ struct grub_video_bitmap *bitmap;
+ struct icon_entry *next;
+} *icon_entry_t;
+
+struct grub_gfxmenu_icon_manager
+{
+ char *theme_path;
+ int icon_width;
+ int icon_height;
+
+ /* Icon cache: linked list w/ dummy head node. */
+ struct icon_entry cache;
+};
+
+
+/* Create a new icon manager and return a point to it. */
+grub_gfxmenu_icon_manager_t
+grub_gfxmenu_icon_manager_new (void)
+{
+ grub_gfxmenu_icon_manager_t mgr;
+ mgr = grub_malloc (sizeof (*mgr));
+ if (! mgr)
+ return 0;
+
+ mgr->theme_path = 0;
+ mgr->icon_width = 0;
+ mgr->icon_height = 0;
+
+ /* Initialize the dummy head node. */
+ mgr->cache.class_name = 0;
+ mgr->cache.bitmap = 0;
+ mgr->cache.next = 0;
+
+ return mgr;
+}
+
+/* Destroy the icon manager MGR, freeing all resources used by it.
+
+Note: Any bitmaps returned by grub_gfxmenu_icon_manager_get_icon()
+are destroyed and must not be used by the caller after this function
+is called. */
+void
+grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr)
+{
+ grub_gfxmenu_icon_manager_clear_cache (mgr);
+ grub_free (mgr->theme_path);
+ grub_free (mgr);
+}
+
+/* Clear the icon cache. */
+void
+grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr)
+{
+ icon_entry_t cur;
+ icon_entry_t next;
+ for (cur = mgr->cache.next; cur; cur = next)
+ {
+ next = cur->next;
+ grub_free (cur->class_name);
+ grub_video_bitmap_destroy (cur->bitmap);
+ grub_free (cur);
+ }
+ mgr->cache.next = 0;
+}
+
+/* Set the theme path. If the theme path is changed, the icon cache
+ is cleared. */
+void
+grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr,
+ const char *path)
+{
+ /* Clear the cache if the theme path has changed. */
+ if (((mgr->theme_path == 0) != (path == 0))
+ || (grub_strcmp (mgr->theme_path, path) != 0))
+ grub_gfxmenu_icon_manager_clear_cache (mgr);
+
+ grub_free (mgr->theme_path);
+ mgr->theme_path = path ? grub_strdup (path) : 0;
+}
+
+/* Set the icon size. When icons are requested from the icon manager,
+ they are scaled to this size before being returned. If the size is
+ changed, the icon cache is cleared. */
+void
+grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr,
+ int width, int height)
+{
+ /* If the width or height is changed, we must clear the cache, since the
+ scaled bitmaps are stored in the cache. */
+ if (width != mgr->icon_width || height != mgr->icon_height)
+ grub_gfxmenu_icon_manager_clear_cache (mgr);
+
+ mgr->icon_width = width;
+ mgr->icon_height = height;
+}
+
+/* Try to load an icon for the specified CLASS_NAME in the directory DIR.
+ Returns 0 if the icon could not be loaded, or returns a pointer to a new
+ bitmap if it was successful. */
+static struct grub_video_bitmap *
+try_loading_icon (grub_gfxmenu_icon_manager_t mgr,
+ const char *dir, const char *class_name)
+{
+ char *path = grub_malloc (grub_strlen (dir)
+ + grub_strlen (class_name)
+ + grub_strlen (icon_extension)
+ + 1);
+ if (! path)
+ return 0;
+
+ grub_strcpy (path, dir);
+ grub_strcat (path, class_name);
+ grub_strcat (path, icon_extension);
+
+ struct grub_video_bitmap *raw_bitmap;
+ grub_video_bitmap_load (&raw_bitmap, path);
+ grub_free (path);
+ grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */
+ if (! raw_bitmap)
+ return 0;
+
+ struct grub_video_bitmap *scaled_bitmap;
+ grub_video_bitmap_create_scaled (&scaled_bitmap,
+ mgr->icon_width, mgr->icon_height,
+ raw_bitmap,
+ GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+ grub_video_bitmap_destroy (raw_bitmap);
+ if (! scaled_bitmap)
+ return 0;
+
+ return scaled_bitmap;
+}
+
+/* Get the icon for the specified class CLASS_NAME. If an icon for
+ CLASS_NAME already exists in the cache, then a reference to the cached
+ bitmap is returned. If it is not cached, then it is loaded and cached.
+ If no icon could be could for CLASS_NAME, then 0 is returned. */
+static struct grub_video_bitmap *
+get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name)
+{
+ /* First check the icon cache. */
+ icon_entry_t entry;
+ for (entry = mgr->cache.next; entry; entry = entry->next)
+ {
+ if (grub_strcmp (entry->class_name, class_name) == 0)
+ return entry->bitmap;
+ }
+
+ if (! mgr->theme_path)
+ return 0;
+
+ /* Otherwise, we search for an icon to load. */
+ char *theme_dir = grub_get_dirname (mgr->theme_path);
+ char *icons_dir;
+ struct grub_video_bitmap *icon;
+ icon = 0;
+ /* First try the theme's own icons, from "grub/themes/NAME/icons/" */
+ icons_dir = grub_resolve_relative_path (theme_dir, "icons/");
+ if (icons_dir)
+ {
+ icon = try_loading_icon (mgr, icons_dir, class_name);
+ grub_free (icons_dir);
+ }
+ if (! icon)
+ {
+ /* If the theme doesn't have an appropriate icon, check in
+ "grub/themes/icons". */
+ /* TODO use GRUB prefix "/icons" */
+ icons_dir = grub_resolve_relative_path (theme_dir, "../icons/");
+ if (icons_dir)
+ {
+ icon = try_loading_icon (mgr, icons_dir, class_name);
+ grub_free (icons_dir);
+ }
+ }
+ grub_free (theme_dir);
+
+ /* No icon was found. */
+ /* This should probably be noted in the cache, so that a search is not
+ performed each time an icon for CLASS_NAME is requested. */
+ if (! icon)
+ return 0;
+
+ /* Insert a new cache entry for this icon. */
+ entry = grub_malloc (sizeof (*entry));
+ if (! entry)
+ {
+ grub_video_bitmap_destroy (icon);
+ return 0;
+ }
+ entry->class_name = grub_strdup (class_name);
+ entry->bitmap = icon;
+ entry->next = mgr->cache.next;
+ mgr->cache.next = entry; /* Link it into the cache. */
+ return entry->bitmap;
+}
+
+/* Get the best available icon for ENTRY. Beginning with the first class
+ listed in the menu entry and proceeding forward, an icon for each class
+ is searched for. The first icon found is returned. The returned icon
+ is scaled to the size specified by
+ grub_gfxmenu_icon_manager_set_icon_size().
+
+ Note: Bitmaps returned by this function are destroyed when the
+ icon manager is destroyed.
+ */
+struct grub_video_bitmap *
+grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr,
+ grub_menu_entry_t entry)
+{
+ struct grub_menu_entry_class *c;
+ struct grub_video_bitmap *icon;
+
+ /* Try each class in succession. */
+ icon = 0;
+ for (c = entry->classes->next; c && ! icon; c = c->next)
+ icon = get_icon_by_class (mgr, c->name);
+ return icon;
+}
=== added file 'gfxmenu/model.c'
--- gfxmenu/model.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/model.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,191 @@
+/* model.c - Graphical menu interface MVC model. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Model type definition. */
+struct grub_gfxmenu_model
+{
+ grub_menu_t menu;
+ int num_entries;
+ grub_menu_entry_t *entries;
+ int selected_entry_index;
+ int timeout_set;
+ grub_uint64_t timeout_start;
+ grub_uint64_t timeout_at;
+};
+
+
+grub_gfxmenu_model_t
+grub_gfxmenu_model_new (grub_menu_t menu)
+{
+ grub_gfxmenu_model_t model;
+
+ model = grub_malloc (sizeof (*model));
+ if (! model)
+ return 0;
+
+ model->menu = menu;
+ model->num_entries = menu->size;
+ model->entries = 0;
+ model->selected_entry_index = 0;
+ model->timeout_set = 0;
+ model->timeout_at = 0;
+ if (model->num_entries > 0)
+ {
+ model->entries = grub_malloc (model->num_entries
+ * sizeof (*model->entries));
+ if (! model->entries)
+ goto fail_and_free;
+
+ int i;
+ grub_menu_entry_t cur;
+ for (i = 0, cur = menu->entry_list;
+ i < model->num_entries;
+ i++, cur = cur->next)
+ {
+ model->entries[i] = cur;
+ }
+ }
+
+ return model;
+
+fail_and_free:
+ grub_free (model->entries);
+ grub_free (model);
+ return 0;
+}
+
+void
+grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model)
+{
+ if (! model)
+ return;
+
+ grub_free (model->entries);
+ model->entries = 0;
+
+ grub_free (model);
+}
+
+grub_menu_t
+grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model)
+{
+ return model->menu;
+}
+
+void
+grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model)
+{
+ int timeout_sec = grub_menu_get_timeout ();
+ if (timeout_sec >= 0)
+ {
+ model->timeout_start = grub_get_time_ms ();
+ model->timeout_at = model->timeout_start + timeout_sec * 1000;
+ model->timeout_set = 1;
+ }
+ else
+ {
+ model->timeout_set = 0;
+ }
+}
+
+void
+grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model)
+{
+ model->timeout_set = 0;
+ grub_menu_set_timeout (-1);
+}
+
+int
+grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model)
+{
+ if (!model->timeout_set)
+ return -1;
+
+ return model->timeout_at - model->timeout_start;
+}
+
+int
+grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model)
+{
+ if (!model->timeout_set)
+ return -1;
+
+ return model->timeout_at - grub_get_time_ms ();
+}
+
+int
+grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model)
+{
+ if (model->timeout_set
+ && grub_get_time_ms () >= model->timeout_at)
+ return 1;
+
+ return 0;
+}
+
+int
+grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model)
+{
+ return model->num_entries;
+}
+
+int
+grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model)
+{
+ return model->selected_entry_index;
+}
+
+void
+grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, int index)
+{
+ model->selected_entry_index = index;
+}
+
+const char *
+grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, int index)
+{
+ if (index < 0 || index >= model->num_entries)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index");
+ return 0;
+ }
+
+ return model->entries[index]->title;
+}
+
+grub_menu_entry_t
+grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, int index)
+{
+ if (index < 0 || index >= model->num_entries)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index");
+ return 0;
+ }
+
+ return model->entries[index];
+}
=== added file 'gfxmenu/named_colors.c'
--- gfxmenu/named_colors.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/named_colors.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,209 @@
+/* named_colors.c - Named color values. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+struct named_color
+{
+ const char *name;
+ grub_gui_color_t color;
+};
+
+/*
+ Named color list generated from the list of SVG color keywords from
+ ,
+ processed through the following Perl command:
+ perl -ne 'chomp;split;print "{ \"$_[0]\", RGB_COLOR($_[2]) },\n"'
+ */
+
+#define RGB_COLOR(r,g,b) {.red = r, .green = g, .blue = b, .alpha = 255}
+
+static struct named_color named_colors[] =
+{
+ { "aliceblue", RGB_COLOR(240,248,255) },
+ { "antiquewhite", RGB_COLOR(250,235,215) },
+ { "aqua", RGB_COLOR(0,255,255) },
+ { "aquamarine", RGB_COLOR(127,255,212) },
+ { "azure", RGB_COLOR(240,255,255) },
+ { "beige", RGB_COLOR(245,245,220) },
+ { "bisque", RGB_COLOR(255,228,196) },
+ { "black", RGB_COLOR(0,0,0) },
+ { "blanchedalmond", RGB_COLOR(255,235,205) },
+ { "blue", RGB_COLOR(0,0,255) },
+ { "blueviolet", RGB_COLOR(138,43,226) },
+ { "brown", RGB_COLOR(165,42,42) },
+ { "burlywood", RGB_COLOR(222,184,135) },
+ { "cadetblue", RGB_COLOR(95,158,160) },
+ { "chartreuse", RGB_COLOR(127,255,0) },
+ { "chocolate", RGB_COLOR(210,105,30) },
+ { "coral", RGB_COLOR(255,127,80) },
+ { "cornflowerblue", RGB_COLOR(100,149,237) },
+ { "cornsilk", RGB_COLOR(255,248,220) },
+ { "crimson", RGB_COLOR(220,20,60) },
+ { "cyan", RGB_COLOR(0,255,255) },
+ { "darkblue", RGB_COLOR(0,0,139) },
+ { "darkcyan", RGB_COLOR(0,139,139) },
+ { "darkgoldenrod", RGB_COLOR(184,134,11) },
+ { "darkgray", RGB_COLOR(169,169,169) },
+ { "darkgreen", RGB_COLOR(0,100,0) },
+ { "darkgrey", RGB_COLOR(169,169,169) },
+ { "darkkhaki", RGB_COLOR(189,183,107) },
+ { "darkmagenta", RGB_COLOR(139,0,139) },
+ { "darkolivegreen", RGB_COLOR(85,107,47) },
+ { "darkorange", RGB_COLOR(255,140,0) },
+ { "darkorchid", RGB_COLOR(153,50,204) },
+ { "darkred", RGB_COLOR(139,0,0) },
+ { "darksalmon", RGB_COLOR(233,150,122) },
+ { "darkseagreen", RGB_COLOR(143,188,143) },
+ { "darkslateblue", RGB_COLOR(72,61,139) },
+ { "darkslategray", RGB_COLOR(47,79,79) },
+ { "darkslategrey", RGB_COLOR(47,79,79) },
+ { "darkturquoise", RGB_COLOR(0,206,209) },
+ { "darkviolet", RGB_COLOR(148,0,211) },
+ { "deeppink", RGB_COLOR(255,20,147) },
+ { "deepskyblue", RGB_COLOR(0,191,255) },
+ { "dimgray", RGB_COLOR(105,105,105) },
+ { "dimgrey", RGB_COLOR(105,105,105) },
+ { "dodgerblue", RGB_COLOR(30,144,255) },
+ { "firebrick", RGB_COLOR(178,34,34) },
+ { "floralwhite", RGB_COLOR(255,250,240) },
+ { "forestgreen", RGB_COLOR(34,139,34) },
+ { "fuchsia", RGB_COLOR(255,0,255) },
+ { "gainsboro", RGB_COLOR(220,220,220) },
+ { "ghostwhite", RGB_COLOR(248,248,255) },
+ { "gold", RGB_COLOR(255,215,0) },
+ { "goldenrod", RGB_COLOR(218,165,32) },
+ { "gray", RGB_COLOR(128,128,128) },
+ { "green", RGB_COLOR(0,128,0) },
+ { "greenyellow", RGB_COLOR(173,255,47) },
+ { "grey", RGB_COLOR(128,128,128) },
+ { "honeydew", RGB_COLOR(240,255,240) },
+ { "hotpink", RGB_COLOR(255,105,180) },
+ { "indianred", RGB_COLOR(205,92,92) },
+ { "indigo", RGB_COLOR(75,0,130) },
+ { "ivory", RGB_COLOR(255,255,240) },
+ { "khaki", RGB_COLOR(240,230,140) },
+ { "lavender", RGB_COLOR(230,230,250) },
+ { "lavenderblush", RGB_COLOR(255,240,245) },
+ { "lawngreen", RGB_COLOR(124,252,0) },
+ { "lemonchiffon", RGB_COLOR(255,250,205) },
+ { "lightblue", RGB_COLOR(173,216,230) },
+ { "lightcoral", RGB_COLOR(240,128,128) },
+ { "lightcyan", RGB_COLOR(224,255,255) },
+ { "lightgoldenrodyellow", RGB_COLOR(250,250,210) },
+ { "lightgray", RGB_COLOR(211,211,211) },
+ { "lightgreen", RGB_COLOR(144,238,144) },
+ { "lightgrey", RGB_COLOR(211,211,211) },
+ { "lightpink", RGB_COLOR(255,182,193) },
+ { "lightsalmon", RGB_COLOR(255,160,122) },
+ { "lightseagreen", RGB_COLOR(32,178,170) },
+ { "lightskyblue", RGB_COLOR(135,206,250) },
+ { "lightslategray", RGB_COLOR(119,136,153) },
+ { "lightslategrey", RGB_COLOR(119,136,153) },
+ { "lightsteelblue", RGB_COLOR(176,196,222) },
+ { "lightyellow", RGB_COLOR(255,255,224) },
+ { "lime", RGB_COLOR(0,255,0) },
+ { "limegreen", RGB_COLOR(50,205,50) },
+ { "linen", RGB_COLOR(250,240,230) },
+ { "magenta", RGB_COLOR(255,0,255) },
+ { "maroon", RGB_COLOR(128,0,0) },
+ { "mediumaquamarine", RGB_COLOR(102,205,170) },
+ { "mediumblue", RGB_COLOR(0,0,205) },
+ { "mediumorchid", RGB_COLOR(186,85,211) },
+ { "mediumpurple", RGB_COLOR(147,112,219) },
+ { "mediumseagreen", RGB_COLOR(60,179,113) },
+ { "mediumslateblue", RGB_COLOR(123,104,238) },
+ { "mediumspringgreen", RGB_COLOR(0,250,154) },
+ { "mediumturquoise", RGB_COLOR(72,209,204) },
+ { "mediumvioletred", RGB_COLOR(199,21,133) },
+ { "midnightblue", RGB_COLOR(25,25,112) },
+ { "mintcream", RGB_COLOR(245,255,250) },
+ { "mistyrose", RGB_COLOR(255,228,225) },
+ { "moccasin", RGB_COLOR(255,228,181) },
+ { "navajowhite", RGB_COLOR(255,222,173) },
+ { "navy", RGB_COLOR(0,0,128) },
+ { "oldlace", RGB_COLOR(253,245,230) },
+ { "olive", RGB_COLOR(128,128,0) },
+ { "olivedrab", RGB_COLOR(107,142,35) },
+ { "orange", RGB_COLOR(255,165,0) },
+ { "orangered", RGB_COLOR(255,69,0) },
+ { "orchid", RGB_COLOR(218,112,214) },
+ { "palegoldenrod", RGB_COLOR(238,232,170) },
+ { "palegreen", RGB_COLOR(152,251,152) },
+ { "paleturquoise", RGB_COLOR(175,238,238) },
+ { "palevioletred", RGB_COLOR(219,112,147) },
+ { "papayawhip", RGB_COLOR(255,239,213) },
+ { "peachpuff", RGB_COLOR(255,218,185) },
+ { "peru", RGB_COLOR(205,133,63) },
+ { "pink", RGB_COLOR(255,192,203) },
+ { "plum", RGB_COLOR(221,160,221) },
+ { "powderblue", RGB_COLOR(176,224,230) },
+ { "purple", RGB_COLOR(128,0,128) },
+ { "red", RGB_COLOR(255,0,0) },
+ { "rosybrown", RGB_COLOR(188,143,143) },
+ { "royalblue", RGB_COLOR(65,105,225) },
+ { "saddlebrown", RGB_COLOR(139,69,19) },
+ { "salmon", RGB_COLOR(250,128,114) },
+ { "sandybrown", RGB_COLOR(244,164,96) },
+ { "seagreen", RGB_COLOR(46,139,87) },
+ { "seashell", RGB_COLOR(255,245,238) },
+ { "sienna", RGB_COLOR(160,82,45) },
+ { "silver", RGB_COLOR(192,192,192) },
+ { "skyblue", RGB_COLOR(135,206,235) },
+ { "slateblue", RGB_COLOR(106,90,205) },
+ { "slategray", RGB_COLOR(112,128,144) },
+ { "slategrey", RGB_COLOR(112,128,144) },
+ { "snow", RGB_COLOR(255,250,250) },
+ { "springgreen", RGB_COLOR(0,255,127) },
+ { "steelblue", RGB_COLOR(70,130,180) },
+ { "tan", RGB_COLOR(210,180,140) },
+ { "teal", RGB_COLOR(0,128,128) },
+ { "thistle", RGB_COLOR(216,191,216) },
+ { "tomato", RGB_COLOR(255,99,71) },
+ { "turquoise", RGB_COLOR(64,224,208) },
+ { "violet", RGB_COLOR(238,130,238) },
+ { "wheat", RGB_COLOR(245,222,179) },
+ { "white", RGB_COLOR(255,255,255) },
+ { "whitesmoke", RGB_COLOR(245,245,245) },
+ { "yellow", RGB_COLOR(255,255,0) },
+ { "yellowgreen", RGB_COLOR(154,205,50) },
+ { 0, { 0, 0, 0, 0 } } /* Terminator. */
+};
+
+/* Get the color named NAME. If the color was found, returns 1 and
+ stores the color into *COLOR. If the color was not found, returns 0 and
+ does not modify *COLOR. */
+int
+grub_gui_get_named_color (const char *name,
+ grub_gui_color_t *color)
+{
+ int i;
+ for (i = 0; named_colors[i].name; i++)
+ {
+ if (grub_strcmp (named_colors[i].name, name) == 0)
+ {
+ *color = named_colors[i].color;
+ return 1;
+ }
+ }
+ return 0;
+}
=== added file 'gfxmenu/theme_loader.c'
--- gfxmenu/theme_loader.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/theme_loader.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,609 @@
+/* theme_loader.c - Theme file loader for gfxmenu. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Construct a new box widget using ABSPATTERN to find the pixmap files for
+ it, storing the new box instance at *BOXPTR.
+ PATTERN should be of the form: "(hd0,0)/somewhere/style*.png".
+ The '*' then gets substituted with the various pixmap names that the
+ box uses.
+
+ Returns zero on failure, nonzero on success.
+ */
+static int
+recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern)
+{
+ char *prefix;
+ char *suffix;
+ char *star;
+ grub_gfxmenu_box_t box;
+
+ star = grub_strchr (abspattern, '*');
+ if (! star)
+ return 0;
+
+ /* Prefix: Get the part before the '*'. */
+ prefix = grub_malloc (star - abspattern + 1);
+ if (! prefix)
+ return 0;
+
+ grub_memcpy (prefix, abspattern, star - abspattern);
+ prefix[star - abspattern] = '\0';
+
+ /* Suffix: Everything after the '*' is the suffix. */
+ suffix = star + 1;
+
+ box = grub_gfxmenu_create_box (prefix, suffix);
+ grub_free (prefix);
+ if (! box)
+ return 0;
+
+ if (*boxptr)
+ (*boxptr)->destroy (*boxptr);
+ *boxptr = box;
+ return 1;
+}
+
+
+/* Construct a new box widget using PATTERN to find the pixmap files for it,
+ storing the new widget at *BOXPTR. PATTERN should be of the form:
+ "somewhere/style*.png". The '*' then gets substituted with the various
+ pixmap names that the widget uses.
+
+ Important! The value of *BOXPTR must be initialized! It must either
+ (1) Be 0 (a NULL pointer), or
+ (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance.
+ In this case, the previous instance is destroyed.
+
+ Returns zero on failure, nonzero on success.
+ */
+int
+grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
+ const char *pattern, const char *theme_dir)
+{
+ char *abspattern;
+ int success;
+
+ /* Check arguments. */
+ if (! pattern || ! theme_dir)
+ return 0;
+
+ /* Resolve to an absolute path. */
+ abspattern = grub_resolve_relative_path (theme_dir, pattern);
+ if (! abspattern)
+ return 0;
+
+ /* Create the box. */
+ success = recreate_box_absolute (boxptr, abspattern);
+ grub_free (abspattern);
+ return success;
+}
+
+/* Set the specified property NAME on the view to the given string VALUE.
+ This function takes ownership of both NAME and VALUE, so the caller
+ should pass pointers to new heap-allocated strings. */
+static void
+theme_set_string (grub_gfxmenu_view_t view,
+ const char *name,
+ const char *value,
+ const char *theme_dir)
+{
+ if (! grub_strcmp ("title-font", name))
+ view->title_font = grub_font_get (value);
+ else if (! grub_strcmp ("message-font", name))
+ view->message_font = grub_font_get (value);
+ else if (! grub_strcmp ("terminal-font", name))
+ {
+ grub_free (view->terminal_font_name);
+ view->terminal_font_name = grub_strdup (value);
+ }
+ else if (! grub_strcmp ("title-color", name))
+ view->title_color = grub_gui_parse_color (value);
+ else if (! grub_strcmp ("message-color", name))
+ view->message_color = grub_gui_parse_color (value);
+ else if (! grub_strcmp ("message-bg-color", name))
+ view->message_bg_color = grub_gui_parse_color (value);
+ else if (! grub_strcmp ("desktop-image", name))
+ {
+ struct grub_video_bitmap *raw_bitmap;
+ struct grub_video_bitmap *scaled_bitmap;
+ char *path;
+ path = grub_resolve_relative_path (theme_dir, value);
+ if (! path)
+ return;
+ grub_errno = GRUB_ERR_NONE;
+ if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_free (path);
+ return;
+ }
+ grub_free(path);
+ grub_video_bitmap_create_scaled (&scaled_bitmap,
+ view->screen.width,
+ view->screen.height,
+ raw_bitmap,
+ GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+ grub_video_bitmap_destroy (raw_bitmap);
+ if (!scaled_bitmap)
+ return;
+
+ grub_video_bitmap_destroy (view->desktop_image);
+ view->desktop_image = scaled_bitmap;
+ }
+ else if (! grub_strcmp ("desktop-color", name))
+ view->desktop_color = grub_gui_parse_color (value);
+ else if (! grub_strcmp ("terminal-box", name))
+ grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
+ else if (! grub_strcmp ("title-text", name))
+ {
+ grub_free (view->title_text);
+ view->title_text = grub_strdup (value);
+ }
+}
+
+struct parsebuf
+{
+ char *buf;
+ int pos;
+ int len;
+ char *theme_dir;
+ grub_gfxmenu_view_t view;
+};
+
+static void
+advance_to_next_line (struct parsebuf *p)
+{
+ /* Eat characters up to the newline. */
+ while (p->pos < p->len && p->buf[p->pos] != '\n')
+ p->pos++;
+ p->pos++; /* Eat the newline. */
+}
+
+static void
+skip_whitespace (struct parsebuf *p)
+{
+ while (p->pos < p->len
+ && (p->buf[p->pos] == ' '
+ || p->buf[p->pos] == '\t'
+ || p->buf[p->pos] == '\r'
+ || p->buf[p->pos] == '\n'
+ || p->buf[p->pos] == '\f'))
+ p->pos++;
+}
+
+static int
+read_char (struct parsebuf *p)
+{
+ if (p->pos < p->len)
+ return p->buf[p->pos++];
+ else
+ return -1;
+}
+
+static char *
+read_identifier (struct parsebuf *p)
+{
+ int start;
+ int end;
+
+ skip_whitespace (p);
+ start = p->pos;
+ while (p->pos < p->len
+ && (grub_isalpha(p->buf[p->pos])
+ || grub_isdigit(p->buf[p->pos])
+ || p->buf[p->pos] == '_'
+ || p->buf[p->pos] == '-'))
+ p->pos++;
+ end = p->pos;
+ if (end - start < 1)
+ return 0;
+
+ return grub_new_substring (p->buf, start, end);
+}
+
+static char *
+read_expression (struct parsebuf *p)
+{
+ int start;
+ int end;
+
+ skip_whitespace (p);
+ if (p->pos < p->len && p->buf[p->pos] == '"')
+ {
+ /* Read as a quoted string. */
+ /* The quotation marks are not included in the expression value. */
+ p->pos++;
+ start = p->pos;
+ while (p->pos < p->len
+ && p->buf[p->pos] != '"')
+ p->pos++;
+ end = p->pos;
+ if (p->pos < p->len)
+ p->pos++; /* Skip the terminating quotation mark. */
+ }
+ else if (p->pos < p->len && p->buf[p->pos] == '(')
+ {
+ /* Read as a parenthesized string -- for tuples/coordinates. */
+ /* The parentheses are included in the expression value. */
+ start = p->pos;
+ while (p->pos < p->len)
+ {
+ char c = p->buf[p->pos];
+ p->pos++;
+ if (c == ')')
+ break;
+ }
+ end = p->pos;
+ }
+ else if (p->pos < p->len)
+ {
+ /* Read as a single word -- for numeric values. */
+ start = p->pos;
+ while (p->pos < p->len
+ && ! grub_isspace (p->buf[p->pos]))
+ p->pos++;
+ end = p->pos;
+ }
+ else
+ return 0;
+
+ return grub_new_substring (p->buf, start, end);
+}
+
+/* Read a GUI object specification from the theme file.
+ Any components created will be added to the GUI container PARENT.
+ Returns 0 on success, nonzero on failure. */
+static int
+read_object (struct parsebuf *p, grub_gui_container_t parent)
+{
+ char *name;
+ name = read_identifier (p);
+ if (! name)
+ goto fail;
+
+ grub_gui_component_t component = 0;
+ if (grub_strcmp (name, "label") == 0)
+ {
+ component = grub_gui_label_new ();
+ }
+ else if (grub_strcmp (name, "image") == 0)
+ {
+ component = grub_gui_image_new ();
+ }
+ else if (grub_strcmp (name, "vbox") == 0)
+ {
+ component = (grub_gui_component_t) grub_gui_vbox_new ();
+ }
+ else if (grub_strcmp (name, "hbox") == 0)
+ {
+ component = (grub_gui_component_t) grub_gui_hbox_new ();
+ }
+ else if (grub_strcmp (name, "canvas") == 0)
+ {
+ component = (grub_gui_component_t) grub_gui_canvas_new ();
+ }
+ else if (grub_strcmp (name, "progress_bar") == 0)
+ {
+ component = grub_gui_progress_bar_new ();
+ }
+ else if (grub_strcmp (name, "circular_progress") == 0)
+ {
+ component = grub_gui_circular_progress_new ();
+ }
+ else if (grub_strcmp (name, "boot_menu") == 0)
+ {
+ component = grub_gui_list_new ();
+ }
+ else
+ {
+ /* Unknown type; ignore. */
+ goto fail; /* We should actually parse the structure. */
+ }
+
+ if (component)
+ {
+ grub_video_rect_t r = { .x=0, .y=0, .width=-1, .height=-1 };
+ component->ops->set_bounds (component, &r);
+ parent->ops->add (parent, component);
+ }
+
+ skip_whitespace (p);
+ if (read_char (p) != '{')
+ goto fail;
+
+ while (p->pos < p->len)
+ {
+ skip_whitespace (p);
+
+ /* Check whether the end has been encountered. */
+ if (p->pos < p->len
+ && p->buf[p->pos] == '}')
+ {
+ p->pos++; /* Skip the closing brace. */
+ break;
+ }
+
+ if (p->pos < p->len
+ && p->buf[p->pos] == '#')
+ {
+ /* Skip comments. */
+ advance_to_next_line (p);
+ continue;
+ }
+
+ if (p->pos < p->len
+ && p->buf[p->pos] == '+')
+ {
+ p->pos++; /* Skip the '+'. */
+ /* Check whether this component is a container. */
+ if (component->ops->is_instance (component, "container"))
+ {
+ /* Read the sub-object recursively and add it as a child. */
+ if (read_object (p, (grub_gui_container_t) component) != 0)
+ goto fail;
+ /* After reading the sub-object, resume parsing, expecting
+ another property assignment or sub-object definition. */
+ continue;
+ }
+ else
+ {
+ /* error ("Attempted to add object to non-container.") */
+ goto fail;
+ }
+ }
+
+ char *property;
+ property = read_identifier (p);
+ if (! property)
+ goto fail;
+
+ skip_whitespace (p);
+ if (read_char (p) != '=')
+ {
+ grub_free (property);
+ goto fail;
+ }
+ skip_whitespace (p);
+
+ char *value;
+ value = read_expression (p);
+ if (! value)
+ {
+ grub_free (property);
+ goto fail;
+ }
+
+ /* Handle the property value. */
+ if (grub_strcmp (property, "position") == 0)
+ {
+ /* Special case for position value. */
+ int x;
+ int y;
+
+ if (grub_gui_parse_2_tuple (value, &x, &y))
+ {
+ grub_video_rect_t r;
+ component->ops->get_bounds (component, &r);
+ r.x = x;
+ r.y = y;
+ component->ops->set_bounds (component, &r);
+ }
+ }
+ else if (grub_strcmp (property, "size") == 0)
+ {
+ /* Special case for size value. */
+ int w;
+ int h;
+
+ if (grub_gui_parse_2_tuple (value, &w, &h))
+ {
+ grub_video_rect_t r;
+ component->ops->get_bounds (component, &r);
+ r.width = w;
+ r.height = h;
+ component->ops->set_bounds (component, &r);
+ }
+ }
+ else
+ {
+ /* General property handling. */
+ component->ops->set_property (component, property, value);
+ }
+
+ grub_free (value);
+ grub_free (property);
+ }
+
+ /* Set the object's size to its preferred size unless the user has
+ explicitly specified the size. */
+ grub_video_rect_t r;
+ component->ops->get_bounds (component, &r);
+ if (r.width == -1 || r.height == -1)
+ {
+ component->ops->get_preferred_size (component, &r.width, &r.height);
+ component->ops->set_bounds (component, &r);
+ }
+
+ return 0;
+
+fail:
+ grub_free (name);
+
+ /* Once the opening brace has been found, we always jump past the closing
+ brace if an error is encountered. */
+ while (p->pos < p->len
+ && p->buf[p->pos] != '}')
+ p->pos++;
+ return 1;
+}
+
+static void
+read_property (struct parsebuf *p)
+{
+ char *name;
+
+ name = read_identifier (p); /* Read the property name. */
+ if (! name)
+ goto next_line;
+
+ skip_whitespace (p); /* Skip whitespace before separator. */
+
+ if (read_char (p) != ':') /* Read separator. */
+ goto next_line;
+
+ skip_whitespace (p); /* Skip whitespace after separator. */
+
+ /* Get the value based on its type. */
+ if (p->pos < p->len && p->buf[p->pos] == '"')
+ {
+ /* String value. (e.g., '"My string"') */
+ char *value = read_expression (p);
+ if (! value)
+ goto next_line;
+ theme_set_string (p->view, name, value, p->theme_dir);
+ grub_free (value);
+ }
+
+next_line:
+ grub_free (name);
+ advance_to_next_line (p);
+}
+
+struct theme_info
+{
+ const char *theme_dir;
+ const char *theme_path;
+};
+
+static void
+update_theme_info_visit (grub_gui_component_t component, void *userdata)
+{
+ struct theme_info *info;
+ info = userdata;
+ component->ops->set_property (component, "theme_dir", info->theme_dir);
+ component->ops->set_property (component, "theme_path", info->theme_path);
+}
+
+/* Update any boot menu components with the current menu model and
+ theme path. */
+static void
+update_component_tree_theme_info (grub_gui_component_t root,
+ const char *theme_dir,
+ const char *theme_path)
+{
+ struct theme_info info;
+ info.theme_dir = theme_dir;
+ info.theme_path = theme_path;
+ grub_gui_iterate_recursively (root, update_theme_info_visit, &info);
+}
+
+/* Set properties on the view based on settings from the specified
+ theme file. Returns nonzero on success, zero on failure. */
+int
+grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
+{
+ grub_file_t file;
+ struct parsebuf p;
+
+ p.view = view;
+ p.theme_dir = grub_get_dirname (theme_path);
+
+ file = grub_file_open (theme_path);
+ if (!file)
+ {
+ grub_free (p.theme_dir);
+ return 0;
+ }
+
+ p.len = grub_file_size (file);
+ p.buf = grub_malloc (p.len);
+ if (! p.buf)
+ {
+ grub_file_close (file);
+ grub_free (p.theme_dir);
+ return 0;
+ }
+ if (grub_file_read (file, p.buf, p.len) != p.len)
+ {
+ grub_free (p.buf);
+ grub_file_close (file);
+ grub_free (p.theme_dir);
+ return 0;
+ }
+
+ if (view->canvas)
+ view->canvas->ops->component.destroy (view->canvas);
+
+ view->canvas = grub_gui_canvas_new ();
+ ((grub_gui_component_t) view->canvas)
+ ->ops->set_bounds ((grub_gui_component_t) view->canvas,
+ &view->screen);
+
+ p.pos = 0;
+ while (p.pos < p.len)
+ {
+ /* Skip comments (lines beginning with #). */
+ if (p.pos < p.len && p.buf[p.pos] == '#')
+ {
+ advance_to_next_line (&p);
+ continue;
+ }
+
+ /* Get name. */
+ /* Find the first non-whitespace character. */
+ skip_whitespace (&p);
+
+ /* Handle the content. */
+ if (p.buf[p.pos] == '+')
+ {
+ p.pos++; /* Skip the '+'. */
+ read_object (&p, view->canvas);
+ }
+ else
+ {
+ read_property (&p);
+ }
+ }
+
+ /* Set the new theme path. */
+ grub_free (view->theme_path);
+ view->theme_path = grub_strdup (theme_path);
+ update_component_tree_theme_info ((grub_gui_component_t) view->canvas,
+ p.theme_dir,
+ theme_path);
+
+ grub_free (p.buf);
+ grub_file_close (file);
+ grub_free (p.theme_dir);
+ return 1;
+}
=== added file 'gfxmenu/view.c'
--- gfxmenu/view.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/view.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,505 @@
+/* view.c - Graphical menu interface MVC view. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* The component ID identifying GUI components to be updated as the timeout
+ status changes. */
+#define TIMEOUT_COMPONENT_ID "__timeout__"
+
+static void init_terminal (grub_gfxmenu_view_t view);
+static void destroy_terminal (void);
+static grub_err_t set_graphics_mode (void);
+static grub_err_t set_text_mode (void);
+
+/* Create a new view object, loading the theme specified by THEME_PATH and
+ associating MODEL with the view. */
+grub_gfxmenu_view_t
+grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model)
+{
+ grub_gfxmenu_view_t view;
+
+ view = grub_malloc (sizeof (*view));
+ if (! view)
+ return 0;
+
+ set_graphics_mode ();
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+ grub_video_get_viewport ((unsigned *) &view->screen.x,
+ (unsigned *) &view->screen.y,
+ (unsigned *) &view->screen.width,
+ (unsigned *) &view->screen.height);
+
+ /* Clear the screen; there may be garbage left over in video memory, and
+ loading the menu style (particularly the background) can take a while. */
+ grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
+ view->screen.x, view->screen.y,
+ view->screen.width, view->screen.height);
+ grub_video_swap_buffers ();
+
+ grub_font_t default_font;
+ grub_gui_color_t default_fg_color;
+ grub_gui_color_t default_bg_color;
+
+ default_font = grub_font_get ("Helvetica 12");
+ default_fg_color = grub_gui_color_rgb (0, 0, 0);
+ default_bg_color = grub_gui_color_rgb (255, 255, 255);
+
+ view->model = model;
+ view->canvas = 0;
+
+ view->title_font = default_font;
+ view->message_font = default_font;
+ view->terminal_font_name = grub_strdup ("Fixed 10");
+ view->title_color = default_fg_color;
+ view->message_color = default_bg_color;
+ view->message_bg_color = default_fg_color;
+ view->desktop_image = 0;
+ view->desktop_color = default_bg_color;
+ view->terminal_box = grub_gfxmenu_create_box (0, 0);
+ view->title_text = grub_strdup ("GRUB Boot Menu");
+ view->progress_message_text = 0;
+ view->theme_path = 0;
+
+ if (! grub_gfxmenu_view_load_theme (view, theme_path))
+ {
+ grub_gfxmenu_view_destroy (view);
+ return 0;
+ }
+
+ init_terminal (view);
+
+ return view;
+}
+
+/* Destroy the view object. All used memory is freed. */
+void
+grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
+{
+ grub_video_bitmap_destroy (view->desktop_image);
+ if (view->terminal_box)
+ view->terminal_box->destroy (view->terminal_box);
+ grub_free (view->terminal_font_name);
+ grub_free (view->title_text);
+ grub_free (view->progress_message_text);
+ grub_free (view->theme_path);
+ if (view->canvas)
+ view->canvas->ops->component.destroy (view->canvas);
+ grub_free (view);
+
+ set_text_mode ();
+ destroy_terminal ();
+}
+
+/* Sets MESSAGE as the progress message for the view.
+ MESSAGE can be 0, in which case no message is displayed. */
+static void
+set_progress_message (grub_gfxmenu_view_t view, const char *message)
+{
+ grub_free (view->progress_message_text);
+ if (message)
+ view->progress_message_text = grub_strdup (message);
+ else
+ view->progress_message_text = 0;
+}
+
+static void
+draw_background (grub_gfxmenu_view_t view)
+{
+ if (view->desktop_image)
+ {
+ struct grub_video_bitmap *img = view->desktop_image;
+ grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
+ view->screen.x, view->screen.y, 0, 0,
+ grub_video_bitmap_get_width (img),
+ grub_video_bitmap_get_height (img));
+ }
+ else
+ {
+ grub_video_fill_rect (grub_gui_map_color (view->desktop_color),
+ view->screen.x, view->screen.y,
+ view->screen.width, view->screen.height);
+ }
+}
+
+static void
+draw_title (grub_gfxmenu_view_t view)
+{
+ if (! view->title_text)
+ return;
+
+ /* Center the title. */
+ int title_width = grub_font_get_string_width (view->title_font,
+ view->title_text);
+ int x = (view->screen.width - title_width) / 2;
+ int y = 40 + grub_font_get_ascent (view->title_font);
+ grub_font_draw_string (view->title_text,
+ view->title_font,
+ grub_gui_map_color (view->title_color),
+ x, y);
+}
+
+struct progress_value_data
+{
+ const char *visible;
+ const char *start;
+ const char *end;
+ const char *value;
+ const char *text;
+};
+
+static void
+update_timeout_visit (grub_gui_component_t component,
+ void *userdata)
+{
+ struct progress_value_data *pv;
+ pv = (struct progress_value_data *) userdata;
+ component->ops->set_property (component, "visible", pv->visible);
+ component->ops->set_property (component, "start", pv->start);
+ component->ops->set_property (component, "end", pv->end);
+ component->ops->set_property (component, "value", pv->value);
+ component->ops->set_property (component, "text", pv->text);
+}
+
+static void
+update_timeout (grub_gfxmenu_view_t view)
+{
+ char startbuf[20];
+ char valuebuf[20];
+ char msgbuf[120];
+
+ int timeout = grub_gfxmenu_model_get_timeout_ms (view->model);
+ int remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model);
+ struct progress_value_data pv;
+
+ pv.visible = timeout > 0 ? "true" : "false";
+ grub_sprintf (startbuf, "%d", -timeout);
+ pv.start = startbuf;
+ pv.end = "0";
+ grub_sprintf (valuebuf, "%d", remaining > 0 ? -remaining : 0);
+ pv.value = valuebuf;
+
+ int seconds_remaining_rounded_up = (remaining + 999) / 1000;
+ grub_sprintf (msgbuf,
+ "The highlighted entry will be booted automatically in %d s.",
+ seconds_remaining_rounded_up);
+ pv.text = msgbuf;
+
+ grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
+ TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv);
+}
+
+static void
+update_menu_visit (grub_gui_component_t component,
+ void *userdata)
+{
+ grub_gfxmenu_view_t view;
+ view = userdata;
+ if (component->ops->is_instance (component, "list"))
+ {
+ grub_gui_list_t list = (grub_gui_list_t) component;
+ list->ops->set_view_info (list, view->theme_path, view->model);
+ }
+}
+
+/* Update any boot menu components with the current menu model and
+ theme path. */
+static void
+update_menu_components (grub_gfxmenu_view_t view)
+{
+ grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
+ update_menu_visit, view);
+}
+
+static void
+draw_message (grub_gfxmenu_view_t view)
+{
+ char *text = view->progress_message_text;
+ if (! text)
+ return;
+
+ grub_font_t font = view->message_font;
+ grub_video_color_t color = grub_gui_map_color (view->message_color);
+
+ /* Set the timeout bar's frame. */
+ grub_video_rect_t f;
+ f.width = view->screen.width * 4 / 5;
+ f.height = 50;
+ f.x = view->screen.x + (view->screen.width - f.width) / 2;
+ f.y = view->screen.y + view->screen.height - 90 - 20 - f.height;
+
+ /* Border. */
+ grub_video_fill_rect (color,
+ f.x-1, f.y-1, f.width+2, f.height+2);
+ /* Fill. */
+ grub_video_fill_rect (grub_gui_map_color (view->message_bg_color),
+ f.x, f.y, f.width, f.height);
+
+ /* Center the text. */
+ int text_width = grub_font_get_string_width (font, text);
+ int x = f.x + (f.width - text_width) / 2;
+ int y = (f.y + (f.height - grub_font_get_descent (font)) / 2
+ + grub_font_get_ascent (font) / 2);
+ grub_font_draw_string (text, font, color, x, y);
+}
+
+
+void
+grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
+{
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+ update_timeout (view);
+ update_menu_components (view);
+
+ draw_background (view);
+ if (view->canvas)
+ view->canvas->ops->component.paint (view->canvas);
+ draw_title (view);
+ draw_message (view);
+}
+
+static grub_err_t
+set_graphics_mode (void)
+{
+ const char *doublebuf_str = grub_env_get ("doublebuffering");
+ int doublebuf_flags =
+ (doublebuf_str && doublebuf_str[0] == 'n')
+ ? 0
+ : GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+
+ const char *modestr = grub_env_get ("gfxmode");
+ if (grub_video_setup_preferred_mode (modestr, doublebuf_flags, 640, 480)
+ != GRUB_ERR_NONE)
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+set_text_mode (void)
+{
+ return grub_video_restore ();
+}
+
+static int term_target_width;
+static int term_target_height;
+static struct grub_video_render_target *term_target;
+static int term_initialized;
+static grub_term_output_t term_original;
+static grub_gfxmenu_view_t term_view;
+
+static void
+repaint_terminal (int x __attribute ((unused)),
+ int y __attribute ((unused)),
+ int width __attribute ((unused)),
+ int height __attribute ((unused)))
+{
+ if (! term_view)
+ return;
+
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+ grub_gfxmenu_view_draw (term_view);
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+ int termx = term_view->screen.x
+ + term_view->screen.width * (10 - 7) / 10 / 2;
+ int termy = term_view->screen.y
+ + term_view->screen.height * (10 - 7) / 10 / 2;
+
+ grub_gfxmenu_box_t term_box = term_view->terminal_box;
+ if (term_box)
+ {
+ term_box->set_content_size (term_box,
+ term_target_width, term_target_height);
+
+ term_box->draw (term_box,
+ termx - term_box->get_left_pad (term_box),
+ termy - term_box->get_top_pad (term_box));
+ }
+
+ grub_video_blit_render_target (term_target, GRUB_VIDEO_BLIT_REPLACE,
+ termx, termy,
+ 0, 0, term_target_width, term_target_height);
+ grub_video_swap_buffers ();
+}
+
+static void
+init_terminal (grub_gfxmenu_view_t view)
+{
+ term_original = grub_term_get_current_output ();
+
+ term_target_width = view->screen.width * 7 / 10;
+ term_target_height = view->screen.height * 7 / 10;
+
+ grub_video_create_render_target (&term_target,
+ term_target_width,
+ term_target_height,
+ GRUB_VIDEO_MODE_TYPE_RGB
+ | GRUB_VIDEO_MODE_TYPE_ALPHA);
+ if (grub_errno != GRUB_ERR_NONE)
+ return;
+
+ /* Note: currently there is no API for changing the gfxterm font
+ on the fly, so whatever font the initially loaded theme specifies
+ will be permanent. */
+ grub_gfxterm_init_window (term_target, 0, 0,
+ term_target_width, term_target_height,
+ view->terminal_font_name, 3);
+ if (grub_errno != GRUB_ERR_NONE)
+ return;
+ term_initialized = 1;
+
+ /* XXX: store static pointer to the 'view' object so the repaint callback can access it. */
+ term_view = view;
+ grub_gfxterm_set_repaint_callback (repaint_terminal);
+ grub_term_set_current_output (grub_gfxterm_get_term ());
+}
+
+static void destroy_terminal (void)
+{
+ term_view = 0;
+ if (term_initialized)
+ grub_gfxterm_destroy_window ();
+ grub_gfxterm_set_repaint_callback (0);
+ if (term_target)
+ grub_video_delete_render_target (term_target);
+ if (term_original)
+ grub_term_set_current_output (term_original);
+}
+
+
+static void
+notify_booting (void *userdata, grub_menu_entry_t entry)
+{
+ grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
+
+ char *s = grub_malloc (100 + grub_strlen (entry->title));
+ if (!s)
+ return;
+
+ grub_sprintf (s, "Booting '%s'", entry->title);
+ set_progress_message (view, s);
+ grub_free (s);
+ grub_gfxmenu_view_draw (view);
+ grub_video_swap_buffers ();
+}
+
+static void
+notify_fallback (void *userdata, grub_menu_entry_t entry)
+{
+ grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
+
+ char *s = grub_malloc (100 + grub_strlen (entry->title));
+ if (!s)
+ return;
+
+ grub_sprintf (s, "Falling back to '%s'", entry->title);
+ set_progress_message (view, s);
+ grub_free (s);
+ grub_gfxmenu_view_draw (view);
+ grub_video_swap_buffers ();
+}
+
+static void
+notify_execution_failure (void *userdata __attribute__ ((unused)))
+{
+}
+
+
+static struct grub_menu_execute_callback execute_callback =
+{
+ .notify_booting = notify_booting,
+ .notify_fallback = notify_fallback,
+ .notify_failure = notify_execution_failure
+};
+
+int
+grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view,
+ grub_menu_entry_t entry)
+{
+ grub_menu_execute_with_fallback (grub_gfxmenu_model_get_menu (view->model),
+ entry, &execute_callback, (void *) view);
+
+ if (set_graphics_mode () != GRUB_ERR_NONE)
+ return 0; /* Failure. */
+
+ /* If we returned, there was a failure. */
+ set_progress_message (view,
+ "Unable to automatically boot. "
+ "Press SPACE to continue.");
+ grub_gfxmenu_view_draw (view);
+ grub_video_swap_buffers ();
+ while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ')
+ {
+ /* Wait for SPACE to be pressed. */
+ }
+
+ set_progress_message (view, 0); /* Clear the message. */
+
+ return 1; /* Ok. */
+}
+
+int
+grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view,
+ grub_menu_entry_t entry)
+{
+ /* Currently we switch back to text mode by restoring
+ the original terminal before executing the menu entry.
+ It is hard to make it work when executing a menu entry
+ that switches video modes -- it using gfxterm in a
+ window, the repaint callback seems to crash GRUB. */
+ /* TODO: Determine if this works when 'gfxterm' was set as
+ the current terminal before invoking the gfxmenu. */
+ destroy_terminal ();
+
+ grub_menu_execute_entry (entry);
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_wait_after_message ();
+
+ if (set_graphics_mode () != GRUB_ERR_NONE)
+ return 0; /* Failure. */
+
+ init_terminal (view);
+ return 1; /* Ok. */
+}
+
+void
+grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view __attribute__((unused)))
+{
+ grub_cmdline_run (1);
+}
=== added file 'gfxmenu/widget-box.c'
--- gfxmenu/widget-box.c 1970-01-01 00:00:00 +0000
+++ gfxmenu/widget-box.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,271 @@
+/* widget_box.c - Pixmap-stylized box widget. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum box_pixmaps
+{
+ BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW,
+ BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W,
+ BOX_PIXMAP_CENTER
+};
+
+static const char *box_pixmap_names[] = {
+ /* Corners: */
+ "nw", "ne", "se", "sw",
+ /* Sides: */
+ "n", "e", "s", "w",
+ /* Center: */
+ "c"
+};
+
+#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names))
+
+static int
+get_height (struct grub_video_bitmap *bitmap)
+{
+ if (bitmap)
+ return grub_video_bitmap_get_height (bitmap);
+ else
+ return 0;
+}
+
+static int
+get_width (struct grub_video_bitmap *bitmap)
+{
+ if (bitmap)
+ return grub_video_bitmap_get_width (bitmap);
+ else
+ return 0;
+}
+
+static void
+blit (grub_gfxmenu_box_t self, int pixmap_index, int x, int y)
+{
+ struct grub_video_bitmap *bitmap;
+ bitmap = self->scaled_pixmaps[pixmap_index];
+ if (! bitmap)
+ return;
+ grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND,
+ x, y, 0, 0,
+ grub_video_bitmap_get_width (bitmap),
+ grub_video_bitmap_get_height (bitmap));
+}
+
+static void
+draw (grub_gfxmenu_box_t self, int x, int y)
+{
+ int height_n;
+ int height_s;
+ int height_e;
+ int height_w;
+ int width_n;
+ int width_s;
+ int width_e;
+ int width_w;
+
+ height_n = get_height (self->scaled_pixmaps[BOX_PIXMAP_N]);
+ height_s = get_height (self->scaled_pixmaps[BOX_PIXMAP_S]);
+ height_e = get_height (self->scaled_pixmaps[BOX_PIXMAP_E]);
+ height_w = get_height (self->scaled_pixmaps[BOX_PIXMAP_W]);
+ width_n = get_width (self->scaled_pixmaps[BOX_PIXMAP_N]);
+ width_s = get_width (self->scaled_pixmaps[BOX_PIXMAP_S]);
+ width_e = get_width (self->scaled_pixmaps[BOX_PIXMAP_E]);
+ width_w = get_width (self->scaled_pixmaps[BOX_PIXMAP_W]);
+
+ /* Draw sides. */
+ blit (self, BOX_PIXMAP_N, x + width_w, y);
+ blit (self, BOX_PIXMAP_S, x + width_w, y + height_n + self->content_height);
+ blit (self, BOX_PIXMAP_E, x + width_w + self->content_width, y + height_n);
+ blit (self, BOX_PIXMAP_W, x, y + height_n);
+
+ /* Draw corners. */
+ blit (self, BOX_PIXMAP_NW, x, y);
+ blit (self, BOX_PIXMAP_NE, x + width_w + self->content_width, y);
+ blit (self, BOX_PIXMAP_SE,
+ x + width_w + self->content_width,
+ y + height_n + self->content_height);
+ blit (self, BOX_PIXMAP_SW, x, y + height_n + self->content_height);
+
+ /* Draw center. */
+ blit (self, BOX_PIXMAP_CENTER, x + width_w, y + height_n);
+}
+
+static void
+scale_pixmap (grub_gfxmenu_box_t self, int i, int w, int h)
+{
+ struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i];
+ struct grub_video_bitmap *raw = self->raw_pixmaps[i];
+
+ if (raw == 0)
+ return;
+
+ if (w == -1)
+ w = grub_video_bitmap_get_width (raw);
+ if (h == -1)
+ h = grub_video_bitmap_get_height (raw);
+
+ if (*scaled == 0
+ || ((int) grub_video_bitmap_get_width (*scaled) != w)
+ || ((int) grub_video_bitmap_get_height (*scaled) != h))
+ {
+ if (*scaled)
+ {
+ grub_video_bitmap_destroy (*scaled);
+ *scaled = 0;
+ }
+ grub_video_bitmap_create_scaled (scaled, w, h, raw,
+ GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+ }
+}
+
+static void
+set_content_size (grub_gfxmenu_box_t self,
+ int width, int height)
+{
+ self->content_width = width;
+ self->content_height = height;
+ /* Resize sides to match the width and height. */
+ /* It is assumed that the corners width/height match the adjacent sides. */
+
+ /* Resize N and S sides to match width. */
+ scale_pixmap(self, BOX_PIXMAP_N, width, -1);
+ scale_pixmap(self, BOX_PIXMAP_S, width, -1);
+
+ /* Resize E and W sides to match height. */
+ scale_pixmap(self, BOX_PIXMAP_E, -1, height);
+ scale_pixmap(self, BOX_PIXMAP_W, -1, height);
+
+ /* Don't scale the corners--they are assumed to match the sides. */
+ scale_pixmap(self, BOX_PIXMAP_NW, -1, -1);
+ scale_pixmap(self, BOX_PIXMAP_SW, -1, -1);
+ scale_pixmap(self, BOX_PIXMAP_NE, -1, -1);
+ scale_pixmap(self, BOX_PIXMAP_SE, -1, -1);
+
+ /* Scale the center area. */
+ scale_pixmap(self, BOX_PIXMAP_CENTER, width, height);
+}
+
+static int
+get_left_pad (grub_gfxmenu_box_t self)
+{
+ return get_width (self->raw_pixmaps[BOX_PIXMAP_W]);
+}
+
+static int
+get_top_pad (grub_gfxmenu_box_t self)
+{
+ return get_height (self->raw_pixmaps[BOX_PIXMAP_N]);
+}
+
+static int
+get_right_pad (grub_gfxmenu_box_t self)
+{
+ return get_width (self->raw_pixmaps[BOX_PIXMAP_E]);
+}
+
+static int
+get_bottom_pad (grub_gfxmenu_box_t self)
+{
+ return get_height (self->raw_pixmaps[BOX_PIXMAP_S]);
+}
+
+static void
+destroy (grub_gfxmenu_box_t self)
+{
+ unsigned i;
+ for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+ {
+ if (self->raw_pixmaps[i])
+ grub_video_bitmap_destroy(self->raw_pixmaps[i]);
+ self->raw_pixmaps[i] = 0;
+
+ if (self->scaled_pixmaps[i])
+ grub_video_bitmap_destroy(self->scaled_pixmaps[i]);
+ self->scaled_pixmaps[i] = 0;
+ }
+ grub_free (self->raw_pixmaps);
+ self->raw_pixmaps = 0;
+ grub_free (self->scaled_pixmaps);
+ self->scaled_pixmaps = 0;
+
+ grub_free (self); /* Free self: must be the last step! */
+}
+
+
+/* Create a new box. If PIXMAPS_PREFIX and PIXMAPS_SUFFIX are both non-null,
+ then an attempt is made to load the north, south, east, west, northwest,
+ northeast, southeast, southwest, and center pixmaps.
+ If either PIXMAPS_PREFIX or PIXMAPS_SUFFIX is 0, then no pixmaps are
+ loaded, and the box has zero-width borders and is drawn transparent. */
+grub_gfxmenu_box_t
+grub_gfxmenu_create_box (const char *pixmaps_prefix,
+ const char *pixmaps_suffix)
+{
+ char path[200];
+ unsigned i;
+ grub_gfxmenu_box_t box;
+
+ box = (grub_gfxmenu_box_t) grub_malloc (sizeof (*box));
+ if (!box)
+ return 0;
+ box->content_width = 0;
+ box->content_height = 0;
+ box->raw_pixmaps =
+ (struct grub_video_bitmap **)
+ grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
+ box->scaled_pixmaps =
+ (struct grub_video_bitmap **)
+ grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
+
+ for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+ {
+ if (pixmaps_prefix && pixmaps_suffix)
+ {
+ /* TODO XXX dynamically allocate PATH, ensure it's large enough */
+ grub_sprintf (path, "%s%s%s",
+ pixmaps_prefix, box_pixmap_names[i], pixmaps_suffix);
+ grub_errno = GRUB_ERR_NONE;
+ grub_video_bitmap_load (&box->raw_pixmaps[i], path);
+ grub_errno = GRUB_ERR_NONE; /* Clear any potential error. */
+ }
+ else
+ {
+ box->raw_pixmaps[i] = 0;
+ }
+ box->scaled_pixmaps[i] = 0;
+ }
+
+ box->draw = draw;
+ box->set_content_size = set_content_size;
+ box->get_left_pad = get_left_pad;
+ box->get_top_pad = get_top_pad;
+ box->get_right_pad = get_right_pad;
+ box->get_bottom_pad = get_bottom_pad;
+ box->destroy = destroy;
+
+ return box;
+}
=== added file 'include/grub/gfxmenu_model.h'
--- include/grub/gfxmenu_model.h 1970-01-01 00:00:00 +0000
+++ include/grub/gfxmenu_model.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,59 @@
+/* gfxmenu_model.h - gfxmenu model interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_GFXMENU_MODEL_HEADER
+#define GRUB_GFXMENU_MODEL_HEADER 1
+
+#include
+
+struct grub_gfxmenu_model; /* Forward declaration of opaque type. */
+typedef struct grub_gfxmenu_model *grub_gfxmenu_model_t;
+
+
+grub_gfxmenu_model_t grub_gfxmenu_model_new (grub_menu_t menu);
+
+void grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model);
+
+grub_menu_t grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model,
+ int index);
+
+const char *grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model,
+ int index);
+
+grub_menu_entry_t grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model,
+ int index);
+
+#endif /* GRUB_GFXMENU_MODEL_HEADER */
+
=== added file 'include/grub/gfxmenu_view.h'
--- include/grub/gfxmenu_view.h 1970-01-01 00:00:00 +0000
+++ include/grub/gfxmenu_view.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,92 @@
+/* gfxmenu_view.h - gfxmenu view interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_GFXMENU_VIEW_HEADER
+#define GRUB_GFXMENU_VIEW_HEADER 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct grub_gfxmenu_view; /* Forward declaration of opaque type. */
+typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t;
+
+
+grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path,
+ grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view);
+
+/* Set properties on the view based on settings from the specified
+ theme file. */
+int grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view,
+ const char *theme_path);
+
+int
+grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
+ const char *pattern, const char *theme_dir);
+
+void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view);
+
+int grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view,
+ grub_menu_entry_t entry);
+
+int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view,
+ grub_menu_entry_t entry);
+
+void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view);
+
+
+
+/* Implementation details -- this should not be used outside of the
+ view itself. */
+
+#include
+#include
+#include
+#include
+#include
+
+/* Definition of the private representation of the view. */
+struct grub_gfxmenu_view
+{
+ grub_video_rect_t screen;
+
+ grub_font_t title_font;
+ grub_font_t message_font;
+ char *terminal_font_name;
+ grub_gui_color_t title_color;
+ grub_gui_color_t message_color;
+ grub_gui_color_t message_bg_color;
+ struct grub_video_bitmap *desktop_image;
+ grub_gui_color_t desktop_color;
+ grub_gfxmenu_box_t terminal_box;
+ char *title_text;
+ char *progress_message_text;
+ char *theme_path;
+
+ grub_gui_container_t canvas;
+
+ grub_gfxmenu_model_t model;
+};
+
+#endif /* ! GRUB_GFXMENU_VIEW_HEADER */
=== added file 'include/grub/gfxterm.h'
--- include/grub/gfxterm.h 1970-01-01 00:00:00 +0000
+++ include/grub/gfxterm.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,41 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_GFXTERM_HEADER
+#define GRUB_GFXTERM_HEADER 1
+
+#include
+#include
+#include
+#include
+
+grub_err_t
+grub_gfxterm_init_window (struct grub_video_render_target *target,
+ int x, int y, int width, int height,
+ const char *font_name, int border_width);
+
+void grub_gfxterm_destroy_window (void);
+
+grub_term_output_t grub_gfxterm_get_term (void);
+
+typedef void (*grub_gfxterm_repaint_callback_t)(int x, int y,
+ int width, int height);
+
+void grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func);
+
+#endif /* ! GRUB_GFXTERM_HEADER */
=== added file 'include/grub/gfxwidgets.h'
--- include/grub/gfxwidgets.h 1970-01-01 00:00:00 +0000
+++ include/grub/gfxwidgets.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,49 @@
+/* gfxwidgets.h - Widgets for the graphical menu (gfxmenu). */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_GFXWIDGETS_HEADER
+#define GRUB_GFXWIDGETS_HEADER 1
+
+#include
+
+typedef struct grub_gfxmenu_box *grub_gfxmenu_box_t;
+
+struct grub_gfxmenu_box
+{
+ /* The size of the content. */
+ int content_width;
+ int content_height;
+
+ struct grub_video_bitmap **raw_pixmaps;
+ struct grub_video_bitmap **scaled_pixmaps;
+
+ void (*draw) (grub_gfxmenu_box_t self, int x, int y);
+ void (*set_content_size) (grub_gfxmenu_box_t self,
+ int width, int height);
+ int (*get_left_pad) (grub_gfxmenu_box_t self);
+ int (*get_top_pad) (grub_gfxmenu_box_t self);
+ int (*get_right_pad) (grub_gfxmenu_box_t self);
+ int (*get_bottom_pad) (grub_gfxmenu_box_t self);
+ void (*destroy) (grub_gfxmenu_box_t self);
+};
+
+grub_gfxmenu_box_t grub_gfxmenu_create_box (const char *pixmaps_prefix,
+ const char *pixmaps_suffix);
+
+#endif /* ! GRUB_GFXWIDGETS_HEADER */
=== added file 'include/grub/gui.h'
--- include/grub/gui.h 1970-01-01 00:00:00 +0000
+++ include/grub/gui.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,165 @@
+/* gui.h - GUI components header file. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifndef GRUB_GUI_H
+#define GRUB_GUI_H 1
+
+/* A representation of a color. Unlike grub_video_color_t, this
+ representation is independent of any video mode specifics. */
+typedef struct grub_gui_color
+{
+ grub_uint8_t red;
+ grub_uint8_t green;
+ grub_uint8_t blue;
+ grub_uint8_t alpha;
+} grub_gui_color_t;
+
+typedef struct grub_gui_component *grub_gui_component_t;
+typedef struct grub_gui_container *grub_gui_container_t;
+typedef struct grub_gui_list *grub_gui_list_t;
+
+typedef void (*grub_gui_component_callback) (grub_gui_component_t component,
+ void *userdata);
+
+/* Component interface. */
+
+struct grub_gui_component_ops
+{
+ void (*destroy) (void *self);
+ const char * (*get_id) (void *self);
+ int (*is_instance) (void *self, const char *type);
+ void (*paint) (void *self);
+ void (*set_parent) (void *self, grub_gui_container_t parent);
+ grub_gui_container_t (*get_parent) (void *self);
+ void (*set_bounds) (void *self, const grub_video_rect_t *bounds);
+ void (*get_bounds) (void *self, grub_video_rect_t *bounds);
+ void (*get_preferred_size) (void *self, int *width, int *height);
+ void (*set_property) (void *self, const char *name, const char *value);
+};
+
+struct grub_gui_container_ops
+{
+ struct grub_gui_component_ops component;
+ void (*add) (void *self, grub_gui_component_t comp);
+ void (*remove) (void *self, grub_gui_component_t comp);
+ void (*iterate_children) (void *self,
+ grub_gui_component_callback cb, void *userdata);
+};
+
+struct grub_gui_list_ops
+{
+ struct grub_gui_component_ops component_ops;
+ void (*set_view_info) (void *self,
+ const char *theme_path,
+ grub_gfxmenu_model_t menu);
+};
+
+struct grub_gui_component
+{
+ struct grub_gui_component_ops *ops;
+};
+
+struct grub_gui_container
+{
+ struct grub_gui_container_ops *ops;
+};
+
+struct grub_gui_list
+{
+ struct grub_gui_list_ops *ops;
+};
+
+
+/* Interfaces to concrete component classes. */
+
+grub_gui_container_t grub_gui_canvas_new (void);
+grub_gui_container_t grub_gui_vbox_new (void);
+grub_gui_container_t grub_gui_hbox_new (void);
+grub_gui_component_t grub_gui_label_new (void);
+grub_gui_component_t grub_gui_image_new (void);
+grub_gui_component_t grub_gui_progress_bar_new (void);
+grub_gui_component_t grub_gui_list_new (void);
+grub_gui_component_t grub_gui_circular_progress_new (void);
+
+/* Manipulation functions. */
+
+/* Visit all components with the specified ID. */
+void grub_gui_find_by_id (grub_gui_component_t root,
+ const char *id,
+ grub_gui_component_callback cb,
+ void *userdata);
+
+/* Visit all components. */
+void grub_gui_iterate_recursively (grub_gui_component_t root,
+ grub_gui_component_callback cb,
+ void *userdata);
+
+/* Helper functions. */
+
+static __inline void
+grub_gui_save_viewport (grub_video_rect_t *r)
+{
+ grub_video_get_viewport ((unsigned *) &r->x,
+ (unsigned *) &r->y,
+ (unsigned *) &r->width,
+ (unsigned *) &r->height);
+}
+
+static __inline void
+grub_gui_restore_viewport (const grub_video_rect_t *r)
+{
+ grub_video_set_viewport (r->x, r->y, r->width, r->height);
+}
+
+/* Set a new viewport relative the the current one, saving the current
+ viewport in OLD so it can be later restored. */
+static __inline void
+grub_gui_set_viewport (const grub_video_rect_t *r, grub_video_rect_t *old)
+{
+ grub_gui_save_viewport (old);
+ grub_video_set_viewport (old->x + r->x,
+ old->y + r->y,
+ r->width,
+ r->height);
+}
+
+static __inline grub_gui_color_t
+grub_gui_color_rgb (int r, int g, int b)
+{
+ grub_gui_color_t c;
+ c.red = r;
+ c.green = g;
+ c.blue = b;
+ c.alpha = 255;
+ return c;
+}
+
+static __inline grub_video_color_t
+grub_gui_map_color (grub_gui_color_t c)
+{
+ return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha);
+}
+
+#endif /* ! GRUB_GUI_H */
=== added file 'include/grub/gui_string_util.h'
--- include/grub/gui_string_util.h 1970-01-01 00:00:00 +0000
+++ include/grub/gui_string_util.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,39 @@
+/* gui_string_util.h - String utilities for the graphical menu interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_GUI_STRING_UTIL_HEADER
+#define GRUB_GUI_STRING_UTIL_HEADER 1
+
+#include
+#include
+
+char *grub_new_substring (const char *buf,
+ grub_size_t start, grub_size_t end);
+
+char *grub_resolve_relative_path (const char *base, const char *path);
+
+char *grub_get_dirname (const char *file_path);
+
+int grub_gui_get_named_color (const char *name, grub_gui_color_t *color);
+
+grub_gui_color_t grub_gui_parse_color (const char *s);
+
+int grub_gui_parse_2_tuple (const char *s, int *px, int *py);
+
+#endif /* GRUB_GUI_STRING_UTIL_HEADER */
=== added file 'include/grub/icon_manager.h'
--- include/grub/icon_manager.h 1970-01-01 00:00:00 +0000
+++ include/grub/icon_manager.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,41 @@
+/* icon_manager.h - gfxmenu icon manager. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_ICON_MANAGER_HEADER
+#define GRUB_ICON_MANAGER_HEADER 1
+
+#include
+#include
+
+/* Forward declaration of opaque structure handle type. */
+typedef struct grub_gfxmenu_icon_manager *grub_gfxmenu_icon_manager_t;
+
+grub_gfxmenu_icon_manager_t grub_gfxmenu_icon_manager_new (void);
+void grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr);
+void grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr);
+void grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr,
+ const char *path);
+void grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr,
+ int width, int height);
+struct grub_video_bitmap *
+grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr,
+ grub_menu_entry_t entry);
+
+#endif /* GRUB_ICON_MANAGER_HEADER */
+
=== modified file 'include/grub/menu_viewer.h'
--- include/grub/menu_viewer.h 2009-01-31 09:15:43 +0000
+++ include/grub/menu_viewer.h 2009-01-31 20:43:30 +0000
@@ -36,8 +36,13 @@
};
typedef struct grub_menu_viewer *grub_menu_viewer_t;
+void grub_menu_viewer_init (void);
+
void grub_menu_viewer_register (grub_menu_viewer_t viewer);
grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested);
+/* Return nonzero iff the menu viewer should clean up and return ASAP. */
+int grub_menu_viewer_should_return (void);
+
#endif /* GRUB_MENU_VIEWER_HEADER */
=== modified file 'include/grub/misc.h'
--- include/grub/misc.h 2009-01-31 16:50:07 +0000
+++ include/grub/misc.h 2009-01-31 20:43:30 +0000
@@ -1,7 +1,7 @@
/* misc.h - prototypes for misc functions */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2008 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,11 +53,14 @@
char *EXPORT_FUNC(grub_strstr) (const char *haystack, const char *needle);
int EXPORT_FUNC(grub_iswordseparator) (int c);
int EXPORT_FUNC(grub_isspace) (int c);
+int EXPORT_FUNC(grub_iscntrl) (int c);
int EXPORT_FUNC(grub_isprint) (int c);
int EXPORT_FUNC(grub_isalpha) (int c);
+int EXPORT_FUNC(grub_isalnum) (int c);
int EXPORT_FUNC(grub_isgraph) (int c);
int EXPORT_FUNC(grub_isdigit) (int c);
int EXPORT_FUNC(grub_tolower) (int c);
+long EXPORT_FUNC(grub_strtol) (const char *str, char **end, int base);
unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base);
unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base);
char *EXPORT_FUNC(grub_strdup) (const char *s);
=== modified file 'include/grub/normal.h'
--- include/grub/normal.h 2009-01-31 16:48:22 +0000
+++ include/grub/normal.h 2009-01-31 20:43:30 +0000
@@ -114,6 +114,7 @@
void *callback_data);
void grub_menu_entry_run (grub_menu_entry_t entry);
void grub_menu_execute_entry(grub_menu_entry_t entry);
+int grub_menu_get_default_entry_index (grub_menu_t menu);
int grub_menu_get_timeout (void);
void grub_menu_set_timeout (int timeout);
void grub_cmdline_run (int nested);
=== added file 'include/grub/trig.h'
--- include/grub/trig.h 1970-01-01 00:00:00 +0000
+++ include/grub/trig.h 2009-01-31 20:43:30 +0000
@@ -0,0 +1,44 @@
+/* trig.h - Trigonometric function support. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#ifndef GRUB_TRIG_HEADER
+#define GRUB_TRIG_HEADER 1
+
+#define GRUB_TRIG_ANGLE_MAX 256
+#define GRUB_TRIG_ANGLE_MASK 255
+#define GRUB_TRIG_FRACTION_SCALE 16384
+
+extern short grub_trig_sintab[];
+extern short grub_trig_costab[];
+
+static __inline int
+grub_sin (int x)
+{
+ x &= GRUB_TRIG_ANGLE_MASK;
+ return grub_trig_sintab[x];
+}
+
+static __inline int
+grub_cos (int x)
+{
+ x &= GRUB_TRIG_ANGLE_MASK;
+ return grub_trig_costab[x];
+}
+
+#endif /* ! GRUB_TRIG_HEADER */
=== modified file 'include/grub/types.h'
--- include/grub/types.h 2009-01-10 13:07:44 +0000
+++ include/grub/types.h 2009-01-31 20:43:30 +0000
@@ -94,10 +94,12 @@
#if GRUB_CPU_SIZEOF_VOID_P == 8
# define ULONG_MAX 18446744073709551615UL
-# define LONG_MAX 9223372036854775807UL
+# define LONG_MIN (-9223372036854775808UL) /* -2**63 */
+# define LONG_MAX 9223372036854775807L /* 2**63 + 1 */
#else
# define ULONG_MAX 4294967295UL
-# define LONG_MAX 2147483647UL
+# define LONG_MIN (-2147483648L) /* -2**31 */
+# define LONG_MAX 2147483647L /* 2**31 + 1 */
#endif
/* The type for representing a file offset. */
=== modified file 'include/grub/video.h'
--- include/grub/video.h 2009-01-05 17:38:14 +0000
+++ include/grub/video.h 2009-01-31 20:43:30 +0000
@@ -73,7 +73,7 @@
/* When needed, decode color or just use value as is. */
GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR,
-
+
/* Two color bitmap; bits packed: rows are not padded to byte boundary. */
GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
};
@@ -309,4 +309,11 @@
grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target);
+
+/* Defined in video/setmode.c */
+grub_err_t
+grub_video_setup_preferred_mode (const char *mode_list, int mode_flags,
+ int default_width, int default_height);
+
+
#endif /* ! GRUB_VIDEO_HEADER */
=== modified file 'kern/misc.c'
--- kern/misc.c 2009-01-31 16:50:07 +0000
+++ kern/misc.c 2009-01-31 20:43:30 +0000
@@ -378,6 +378,12 @@
}
int
+grub_iscntrl (int c)
+{
+ return (c >= 0x00 && c <= 0x1F) || c == 0x7F;
+}
+
+int
grub_isprint (int c)
{
return (c >= ' ' && c <= '~');
@@ -390,6 +396,12 @@
}
int
+grub_isalnum (int c)
+{
+ return grub_isalpha (c) || grub_isdigit (c);
+}
+
+int
grub_isdigit (int c)
{
return (c >= '0' && c <= '9');
@@ -410,6 +422,41 @@
return c;
}
+long
+grub_strtol (const char *str, char **end, int base)
+{
+ int negative = 0;
+
+ while (*str && grub_isspace (*str))
+ str++;
+
+ if (*str == '-')
+ {
+ negative = 1;
+ str++;
+ }
+
+ unsigned long long magnitude;
+ magnitude = grub_strtoull (str, end, base);
+ if (negative)
+ {
+ if (magnitude > -((long long) LONG_MIN))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "negative overflow");
+ return LONG_MIN;
+ }
+ return -((long long) magnitude);
+ }
+ else
+ {
+ if (magnitude > LONG_MAX)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "positive overflow");
+ return LONG_MAX;
+ }
+ return (long) magnitude;
+ }
+}
unsigned long
grub_strtoul (const char *str, char **end, int base)
=== added file 'lib/trig.c'
--- lib/trig.c 1970-01-01 00:00:00 +0000
+++ lib/trig.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,83 @@
+/* trig.c - Trigonometric table definitions. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+
+/* These tables were generated with `gentrigtables.py'. */
+
+short grub_trig_sintab[] =
+{
+ 0,402,804,1205,1606,2006,2404,2801,3196,3590,
+ 3981,4370,4756,5139,5520,5897,6270,6639,7005,7366,
+ 7723,8076,8423,8765,9102,9434,9760,10080,10394,10702,
+ 11003,11297,11585,11866,12140,12406,12665,12916,13160,13395,
+ 13623,13842,14053,14256,14449,14635,14811,14978,15137,15286,
+ 15426,15557,15679,15791,15893,15986,16069,16143,16207,16261,
+ 16305,16340,16364,16379,16384,16379,16364,16340,16305,16261,
+ 16207,16143,16069,15986,15893,15791,15679,15557,15426,15286,
+ 15137,14978,14811,14635,14449,14256,14053,13842,13623,13395,
+ 13160,12916,12665,12406,12140,11866,11585,11297,11003,10702,
+ 10394,10080,9760,9434,9102,8765,8423,8076,7723,7366,
+ 7005,6639,6270,5897,5520,5139,4756,4370,3981,3590,
+ 3196,2801,2404,2006,1606,1205,804,402,0,-402,
+ -804,-1205,-1606,-2006,-2404,-2801,-3196,-3590,-3981,-4370,
+ -4756,-5139,-5520,-5897,-6270,-6639,-7005,-7366,-7723,-8076,
+ -8423,-8765,-9102,-9434,-9760,-10080,-10394,-10702,-11003,-11297,
+ -11585,-11866,-12140,-12406,-12665,-12916,-13160,-13395,-13623,-13842,
+ -14053,-14256,-14449,-14635,-14811,-14978,-15137,-15286,-15426,-15557,
+ -15679,-15791,-15893,-15986,-16069,-16143,-16207,-16261,-16305,-16340,
+ -16364,-16379,-16384,-16379,-16364,-16340,-16305,-16261,-16207,-16143,
+ -16069,-15986,-15893,-15791,-15679,-15557,-15426,-15286,-15137,-14978,
+ -14811,-14635,-14449,-14256,-14053,-13842,-13623,-13395,-13160,-12916,
+ -12665,-12406,-12140,-11866,-11585,-11297,-11003,-10702,-10394,-10080,
+ -9760,-9434,-9102,-8765,-8423,-8076,-7723,-7366,-7005,-6639,
+ -6270,-5897,-5520,-5139,-4756,-4370,-3981,-3590,-3196,-2801,
+ -2404,-2006,-1606,-1205,-804,-402
+};
+
+short grub_trig_costab[] =
+{
+ 16384,16379,16364,16340,16305,16261,16207,16143,16069,15986,
+ 15893,15791,15679,15557,15426,15286,15137,14978,14811,14635,
+ 14449,14256,14053,13842,13623,13395,13160,12916,12665,12406,
+ 12140,11866,11585,11297,11003,10702,10394,10080,9760,9434,
+ 9102,8765,8423,8076,7723,7366,7005,6639,6270,5897,
+ 5520,5139,4756,4370,3981,3590,3196,2801,2404,2006,
+ 1606,1205,804,402,0,-402,-804,-1205,-1606,-2006,
+ -2404,-2801,-3196,-3590,-3981,-4370,-4756,-5139,-5520,-5897,
+ -6270,-6639,-7005,-7366,-7723,-8076,-8423,-8765,-9102,-9434,
+ -9760,-10080,-10394,-10702,-11003,-11297,-11585,-11866,-12140,-12406,
+ -12665,-12916,-13160,-13395,-13623,-13842,-14053,-14256,-14449,-14635,
+ -14811,-14978,-15137,-15286,-15426,-15557,-15679,-15791,-15893,-15986,
+ -16069,-16143,-16207,-16261,-16305,-16340,-16364,-16379,-16384,-16379,
+ -16364,-16340,-16305,-16261,-16207,-16143,-16069,-15986,-15893,-15791,
+ -15679,-15557,-15426,-15286,-15137,-14978,-14811,-14635,-14449,-14256,
+ -14053,-13842,-13623,-13395,-13160,-12916,-12665,-12406,-12140,-11866,
+ -11585,-11297,-11003,-10702,-10394,-10080,-9760,-9434,-9102,-8765,
+ -8423,-8076,-7723,-7366,-7005,-6639,-6270,-5897,-5520,-5139,
+ -4756,-4370,-3981,-3590,-3196,-2801,-2404,-2006,-1606,-1205,
+ -804,-402,0,402,804,1205,1606,2006,2404,2801,
+ 3196,3590,3981,4370,4756,5139,5520,5897,6270,6639,
+ 7005,7366,7723,8076,8423,8765,9102,9434,9760,10080,
+ 10394,10702,11003,11297,11585,11866,12140,12406,12665,12916,
+ 13160,13395,13623,13842,14053,14256,14449,14635,14811,14978,
+ 15137,15286,15426,15557,15679,15791,15893,15986,16069,16143,
+ 16207,16261,16305,16340,16364,16379
+};
+
=== modified file 'normal/main.c'
--- normal/main.c 2009-01-31 16:48:22 +0000
+++ normal/main.c 2009-01-31 20:43:30 +0000
@@ -638,6 +638,8 @@
/* This registers some built-in commands. */
grub_command_init ();
+
+ grub_menu_viewer_init ();
}
GRUB_MOD_FINI(normal)
=== modified file 'normal/menu.c'
--- normal/menu.c 2009-01-31 17:29:26 +0000
+++ normal/menu.c 2009-01-31 20:43:30 +0000
@@ -311,6 +311,20 @@
return entry;
}
+/* Get the default menu entry index. */
+int
+grub_menu_get_default_entry_index (grub_menu_t menu)
+{
+ int i = get_entry_number ("default");
+
+ /* If DEFAULT_ENTRY is not within the menu entries, fall back to
+ the first entry. */
+ if (i < 0 || i >= menu->size)
+ i = 0;
+
+ return i;
+}
+
/* Get the first entry number from the variable NAME, which is a
space-separated list of nonnegative integers. The entry number which
is returned is stripped from the value of NAME. If no entry number can
@@ -373,12 +387,7 @@
first = 0;
- default_entry = get_entry_number ("default");
-
- /* If DEFAULT_ENTRY is not within the menu entries, fall back to
- the first entry. */
- if (default_entry < 0 || default_entry >= menu->size)
- default_entry = 0;
+ default_entry = grub_menu_get_default_entry_index (menu);
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
@@ -405,7 +414,7 @@
if (timeout > 0)
print_timeout (timeout, offset, 0);
- while (1)
+ while (!grub_menu_viewer_should_return ())
{
int c;
timeout = grub_menu_get_timeout ();
@@ -576,6 +585,10 @@
}
goto refresh;
+ case 't':
+ grub_env_set ("menuviewer", "gfxmenu");
+ goto refresh;
+
default:
break;
}
@@ -584,7 +597,8 @@
}
}
- /* Never reach here. */
+ /* Exit menu without activating an item. This occurs if the user presses
+ * 't', switching to the graphical menu viewer. */
return -1;
}
=== modified file 'normal/menu_viewer.c'
--- normal/menu_viewer.c 2009-01-31 09:15:43 +0000
+++ normal/menu_viewer.c 2009-01-31 20:43:30 +0000
@@ -25,6 +25,9 @@
/* The list of menu viewers. */
static grub_menu_viewer_t menu_viewer_list;
+static int should_return;
+static int menu_viewer_changed;
+
void
grub_menu_viewer_register (grub_menu_viewer_t viewer)
{
@@ -36,7 +39,7 @@
{
const char *selected_name = grub_env_get ("menuviewer");
- /* If none selected, pick the last registered one. */
+ /* If none selected, pick the last registered one. */
if (selected_name == 0)
return menu_viewer_list;
@@ -54,10 +57,43 @@
grub_err_t
grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
{
- grub_menu_viewer_t cur = get_current_menu_viewer ();
- if (!cur)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
-
- return cur->show_menu (menu, nested);
+ grub_err_t err;
+ int repeat = 0;
+ do
+ {
+ repeat = 0;
+ menu_viewer_changed = 0;
+ grub_menu_viewer_t cur = get_current_menu_viewer ();
+ if (!cur)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
+
+ should_return = 0;
+ err = cur->show_menu (menu, nested);
+ if (menu_viewer_changed)
+ repeat = 1;
+ }
+ while (repeat);
+ return err;
+}
+
+int
+grub_menu_viewer_should_return (void)
+{
+ return should_return;
+}
+
+static char *
+menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ menu_viewer_changed = 1;
+ should_return = 1;
+ return grub_strdup (val);
+}
+
+void
+grub_menu_viewer_init (void)
+{
+ grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook);
}
=== modified file 'term/gfxterm.c'
--- term/gfxterm.c 2009-01-19 17:48:34 +0000
+++ term/gfxterm.c 2009-01-31 20:43:30 +0000
@@ -26,12 +26,12 @@
#include
#include
#include
+#include
#include
#include
#define DEFAULT_VIDEO_WIDTH 640
#define DEFAULT_VIDEO_HEIGHT 480
-#define DEFAULT_VIDEO_FLAGS 0
#define DEFAULT_BORDER_WIDTH 10
@@ -106,10 +106,20 @@
struct grub_colored_char *text_buffer;
};
+static int refcount;
+static struct grub_video_render_target *render_target;
+static grub_video_rect_t window;
static struct grub_virtual_screen virtual_screen;
+static grub_gfxterm_repaint_callback_t repaint_callback;
+
+static grub_err_t init_window (struct grub_video_render_target *target,
+ int x, int y, int width, int height,
+ const char *font_name, int border_width);
+
+static void destroy_window (void);
+
static grub_dl_t my_mod;
-static struct grub_video_mode_info mode_info;
static struct grub_video_render_target *text_layer;
@@ -235,15 +245,61 @@
}
static grub_err_t
+init_window (struct grub_video_render_target *target,
+ int x, int y, int width, int height,
+ const char *font_name, int border_width)
+{
+ /* Clean up any prior instance. */
+ destroy_window ();
+
+ /* Create virtual screen. */
+ if (grub_virtual_screen_setup (border_width, border_width,
+ width - 2 * border_width,
+ height - 2 * border_width,
+ font_name)
+ != GRUB_ERR_NONE)
+ {
+ return grub_errno;
+ }
+
+ /* Set the render target. */
+ render_target = target;
+
+ /* Set window bounds. */
+ window.x = x;
+ window.y = y;
+ window.width = width;
+ window.height = height;
+
+ /* Mark whole window as dirty. */
+ dirty_region_reset ();
+ dirty_region_add (0, 0, width, height);
+
+ return (grub_errno = GRUB_ERR_NONE);
+}
+
+grub_err_t
+grub_gfxterm_init_window (struct grub_video_render_target *target,
+ int x, int y, int width, int height,
+ const char *font_name, int border_width)
+{
+ grub_errno = GRUB_ERR_NONE;
+ if (refcount++ == 0)
+ init_window (target, x, y, width, height, font_name, border_width);
+ return grub_errno;
+}
+
+static grub_err_t
grub_gfxterm_init (void)
{
- char *font_name;
- char *modevar;
- int width = DEFAULT_VIDEO_WIDTH;
- int height = DEFAULT_VIDEO_HEIGHT;
- int depth = -1;
- int flags = DEFAULT_VIDEO_FLAGS;
- grub_video_color_t color;
+ const char *font_name;
+ const char *modevar;
+ struct grub_video_mode_info mode_info;
+
+ /* If gfxterm has already been initialized by calling the init_window
+ function, then leave it alone when it is set as the current terminal. */
+ if (refcount++ != 0)
+ return GRUB_ERR_NONE;
/* Select the font to use. */
font_name = grub_env_get ("gfxterm_font");
@@ -252,270 +308,74 @@
/* Parse gfxmode environment variable if set. */
modevar = grub_env_get ("gfxmode");
- if (modevar)
- {
- char *tmp;
- char *next_mode;
- char *current_mode;
- char *param;
- char *value;
- int mode_found = 0;
-
- /* Take copy of env.var. as we don't want to modify that. */
- tmp = grub_strdup (modevar);
- modevar = tmp;
-
- if (grub_errno != GRUB_ERR_NONE)
- return grub_errno;
-
- /* Initialize next mode. */
- next_mode = modevar;
-
- /* Loop until all modes has been tested out. */
- while (next_mode != NULL)
- {
- /* Use last next_mode as current mode. */
- tmp = next_mode;
-
- /* Reset video mode settings. */
- width = DEFAULT_VIDEO_WIDTH;
- height = DEFAULT_VIDEO_HEIGHT;
- depth = -1;
- flags = DEFAULT_VIDEO_FLAGS;
-
- /* Save position of next mode and separate modes. */
- next_mode = grub_strchr(next_mode, ';');
- if (next_mode)
- {
- *next_mode = 0;
- next_mode++;
- }
-
- /* Skip whitespace. */
- while (grub_isspace (*tmp))
- tmp++;
-
- /* Initialize token holders. */
- current_mode = tmp;
- param = tmp;
- value = NULL;
-
- /* Parse x[x]*/
-
- /* Find width value. */
- value = param;
- param = grub_strchr(param, 'x');
- if (param == NULL)
- {
- grub_err_t rc;
-
- /* First setup error message. */
- rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
- "Invalid mode: %s\n",
- current_mode);
-
- /* Free memory before returning. */
- grub_free (modevar);
-
- return rc;
- }
-
- *param = 0;
- param++;
-
- width = grub_strtoul (value, 0, 0);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_err_t rc;
-
- /* First setup error message. */
- rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
- "Invalid mode: %s\n",
- current_mode);
-
- /* Free memory before returning. */
- grub_free (modevar);
-
- return rc;
- }
-
- /* Find height value. */
- value = param;
- param = grub_strchr(param, 'x');
- if (param == NULL)
- {
- height = grub_strtoul (value, 0, 0);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_err_t rc;
-
- /* First setup error message. */
- rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
- "Invalid mode: %s\n",
- current_mode);
-
- /* Free memory before returning. */
- grub_free (modevar);
-
- return rc;
- }
- }
- else
- {
- /* We have optional color depth value. */
- *param = 0;
- param++;
-
- height = grub_strtoul (value, 0, 0);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_err_t rc;
-
- /* First setup error message. */
- rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
- "Invalid mode: %s\n",
- current_mode);
-
- /* Free memory before returning. */
- grub_free (modevar);
-
- return rc;
- }
-
- /* Convert color depth value. */
- value = param;
- depth = grub_strtoul (value, 0, 0);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_err_t rc;
-
- /* First setup error message. */
- rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
- "Invalid mode: %s\n",
- current_mode);
-
- /* Free memory before returning. */
- grub_free (modevar);
-
- return rc;
- }
- }
-
- /* Try out video mode. */
-
- /* If we have 8 or less bits, then assume that it is indexed color mode. */
- if ((depth <= 8) && (depth != -1))
- flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
-
- /* We have more than 8 bits, then assume that it is RGB color mode. */
- if (depth > 8)
- flags |= GRUB_VIDEO_MODE_TYPE_RGB;
-
- /* If user requested specific depth, forward that information to driver. */
- if (depth != -1)
- flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
- & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
-
- /* Try to initialize requested mode. Ignore any errors. */
- grub_error_push ();
- if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
- {
- grub_error_pop ();
- continue;
- }
-
- /* Figure out what mode we ended up. */
- if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
- {
- /* Couldn't get video mode info, restore old mode and continue to next one. */
- grub_error_pop ();
-
- grub_video_restore ();
- continue;
- }
-
- /* Restore state of error stack. */
- grub_error_pop ();
-
- /* Mode found! Exit loop. */
- mode_found = 1;
- break;
- }
-
- /* Free memory. */
- grub_free (modevar);
-
- if (!mode_found)
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- "No suitable mode found.");
- }
- else
- {
- /* No gfxmode variable set, use defaults. */
-
- /* If we have 8 or less bits, then assume that it is indexed color mode. */
- if ((depth <= 8) && (depth != -1))
- flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
-
- /* We have more than 8 bits, then assume that it is RGB color mode. */
- if (depth > 8)
- flags |= GRUB_VIDEO_MODE_TYPE_RGB;
-
- /* If user requested specific depth, forward that information to driver. */
- if (depth != -1)
- flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
- & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
-
- /* Initialize user requested mode. */
- if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
- return grub_errno;
-
- /* Figure out what mode we ended up. */
- if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
- {
- grub_video_restore ();
- return grub_errno;
- }
+ if (grub_video_setup_preferred_mode (modevar, 0,
+ DEFAULT_VIDEO_WIDTH,
+ DEFAULT_VIDEO_HEIGHT)
+ != GRUB_ERR_NONE)
+ return grub_errno;
+
+ /* Figure out what mode we ended up. */
+ if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+ {
+ grub_video_restore ();
+ return grub_errno;
}
/* Make sure screen is black. */
- color = grub_video_map_rgb (0, 0, 0);
- grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
+ grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
+ 0, 0, mode_info.width, mode_info.height);
bitmap = 0;
+ /* Select the font to use. */
+ font_name = grub_env_get ("gfxterm_font");
+ if (!font_name)
+ font_name = ""; /* Allow fallback to any font. */
+
/* Leave borders for virtual screen. */
- width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
- height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
-
- /* Create virtual screen. */
- if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
- width, height, font_name) != GRUB_ERR_NONE)
+ if (init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY,
+ 0, 0, mode_info.width, mode_info.height,
+ font_name,
+ DEFAULT_BORDER_WIDTH) != GRUB_ERR_NONE)
{
grub_video_restore ();
return grub_errno;
}
- /* Mark whole screen as dirty. */
- dirty_region_reset ();
- dirty_region_add (0, 0, mode_info.width, mode_info.height);
-
return (grub_errno = GRUB_ERR_NONE);
}
+static void
+destroy_window (void)
+{
+ if (bitmap)
+ {
+ grub_video_bitmap_destroy (bitmap);
+ bitmap = 0;
+ }
+
+ repaint_callback = 0;
+ grub_virtual_screen_free ();
+}
+
+void
+grub_gfxterm_destroy_window (void)
+{
+ if (--refcount == 0)
+ destroy_window ();
+}
+
static grub_err_t
grub_gfxterm_fini (void)
{
- if (bitmap)
+ /* Don't destroy an explicitly initialized terminal instance when it is
+ unset as the current terminal. */
+ if (--refcount == 0)
{
- grub_video_bitmap_destroy (bitmap);
- bitmap = 0;
+ destroy_window ();
+ grub_video_restore ();
}
- grub_virtual_screen_free ();
-
- grub_video_restore ();
-
- return GRUB_ERR_NONE;
+ return (grub_errno = GRUB_ERR_NONE);
}
static void
@@ -523,9 +383,15 @@
unsigned int width, unsigned int height)
{
grub_video_color_t color;
-
- grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
-
+ grub_video_rect_t saved_view;
+
+ grub_video_set_active_render_target (render_target);
+ /* Save viewport and set it to our window. */
+ grub_video_get_viewport ((unsigned *) &saved_view.x,
+ (unsigned *) &saved_view.y,
+ (unsigned *) &saved_view.width,
+ (unsigned *) &saved_view.height);
+ grub_video_set_viewport (window.x, window.y, window.width, window.height);
if (bitmap)
{
@@ -592,6 +458,14 @@
y - virtual_screen.offset_y,
width, height);
}
+
+ /* Restore saved viewport. */
+ grub_video_set_viewport (saved_view.x, saved_view.y,
+ saved_view.width, saved_view.height);
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+ if (repaint_callback)
+ repaint_callback (x, y, width, height);
}
static void
@@ -800,7 +674,16 @@
dirty_region_add_virtualscreen ();
}
else
- {
+ {
+ grub_video_rect_t saved_view;
+ grub_video_set_active_render_target (render_target);
+ /* Save viewport and set it to our window. */
+ grub_video_get_viewport ((unsigned *) &saved_view.x,
+ (unsigned *) &saved_view.y,
+ (unsigned *) &saved_view.width,
+ (unsigned *) &saved_view.height);
+ grub_video_set_viewport (window.x, window.y, window.width, window.height);
+
/* Clear new border area. */
grub_video_fill_rect (color,
virtual_screen.offset_x, virtual_screen.offset_y,
@@ -809,10 +692,18 @@
/* Scroll physical screen. */
grub_video_scroll (color, 0, -virtual_screen.normal_char_height);
+ /* Restore saved viewport. */
+ grub_video_set_viewport (saved_view.x, saved_view.y,
+ saved_view.width, saved_view.height);
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
/* Draw cursor if visible. */
if (virtual_screen.cursor_state)
draw_cursor (1);
}
+
+ if (repaint_callback)
+ repaint_callback (window.x, window.y, window.width, window.height);
}
static void
@@ -952,7 +843,7 @@
}
static grub_ssize_t
-grub_gfxterm_getcharwidth (grub_uint32_t c)
+grub_gfxterm_getcharwidth (grub_uint32_t c __attribute__((unused)))
{
struct grub_font_glyph *glyph;
unsigned char char_width;
@@ -1027,7 +918,8 @@
/* Clear text layer. */
grub_video_set_active_render_target (text_layer);
color = virtual_screen.bg_color;
- grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
+ grub_video_fill_rect (color, 0, 0,
+ virtual_screen.width, virtual_screen.height);
grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
/* Mark virtual screen to be redrawn. */
@@ -1096,6 +988,11 @@
dirty_region_redraw ();
}
+void
+grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func)
+{
+ repaint_callback = func;
+}
/* Option array indices. */
#define BACKGROUND_CMD_ARGINDEX_MODE 0
@@ -1123,7 +1020,7 @@
/* Mark whole screen as dirty. */
dirty_region_reset ();
- dirty_region_add (0, 0, mode_info.width, mode_info.height);
+ dirty_region_add (0, 0, window.width, window.height);
}
/* If filename was provided, try to load that. */
@@ -1139,15 +1036,15 @@
|| grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg,
"stretch") == 0)
{
- if (mode_info.width != grub_video_bitmap_get_width (bitmap)
- || mode_info.height != grub_video_bitmap_get_height (bitmap))
+ if (window.width != (int) grub_video_bitmap_get_width (bitmap)
+ || window.height != (int) grub_video_bitmap_get_height (bitmap))
{
struct grub_video_bitmap *scaled_bitmap;
grub_video_bitmap_create_scaled (&scaled_bitmap,
- mode_info.width,
- mode_info.height,
- bitmap,
- GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+ window.width,
+ window.height,
+ bitmap,
+ GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
if (grub_errno == GRUB_ERR_NONE)
{
/* Replace the original bitmap with the scaled one. */
@@ -1167,7 +1064,7 @@
/* Mark whole screen as dirty. */
dirty_region_reset ();
- dirty_region_add (0, 0, mode_info.width, mode_info.height);
+ dirty_region_add (0, 0, window.width, window.height);
}
}
@@ -1196,9 +1093,16 @@
.next = 0
};
+grub_term_output_t
+grub_gfxterm_get_term (void)
+{
+ return &grub_video_term;
+}
+
GRUB_MOD_INIT(term_gfxterm)
{
my_mod = mod;
+ refcount = 0;
grub_term_register_output (&grub_video_term);
grub_register_command ("background_image",
=== added file 'video/setmode.c'
--- video/setmode.c 1970-01-01 00:00:00 +0000
+++ video/setmode.c 2009-01-31 20:43:30 +0000
@@ -0,0 +1,249 @@
+/* video/setmode.c - Smart video mode selection based on preferences. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+/* Set the video mode based on the preferred modes specified in MODE_LIST in
+ the form: x[x][;...]
+
+ For example: 640x480;800x600x8;400x300x32
+
+ If MODE_LIST is null, or no modes in it are usable, then DEFAULT_WIDTH and
+ DEFAULT_HEIGHT are used to set the mode. The MODE_FLAGS argument determines
+ the video mode flags such as double buffering that are used. */
+
+grub_err_t
+grub_video_setup_preferred_mode (const char *mode_list, int mode_flags,
+ int default_width, int default_height)
+{
+ int mode_found = 0;
+
+ if (mode_list != NULL)
+ {
+ /* Take copy of mode_list as we don't want tat. */
+ char *const modes_copy = grub_strdup (mode_list);
+ if (modes_copy == NULL)
+ return grub_errno;
+
+ /* Initialize next mode. */
+ char *next_mode = modes_copy;
+
+ /* Loop until all modes has been tested out. */
+ while ((next_mode != NULL) && !mode_found)
+ {
+ /* Use last next_mode as current mode. */
+ char *tmp = next_mode;
+
+ int width = -1;
+ int height = -1;
+ int depth = -1;
+
+ /* Save position of next mode and separate modes. */
+ next_mode = grub_strchr(next_mode, ';');
+ if (next_mode)
+ {
+ *next_mode = 0;
+ next_mode++;
+ }
+
+ /* Skip whitespace. */
+ while (grub_isspace (*tmp))
+ tmp++;
+
+ /* Initialize token holders. */
+ char *current_mode = tmp;
+ char *param = tmp;
+ char *value = NULL;
+
+ /* Parse x[x]*/
+
+ /* Find width value. */
+ value = param;
+ param = grub_strchr(param, 'x');
+ if (param == NULL)
+ {
+ grub_err_t rc;
+
+ /* First setup error message. */
+ rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "Invalid mode: %s\n",
+ current_mode);
+
+ /* Free memory before returning. */
+ grub_free (modes_copy);
+
+ return rc;
+ }
+
+ *param = 0;
+ param++;
+
+ width = grub_strtoul (value, 0, 0);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_err_t rc;
+
+ /* First setup error message. */
+ rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "Invalid mode: %s\n",
+ current_mode);
+
+ /* Free memory before returning. */
+ grub_free (modes_copy);
+
+ return rc;
+ }
+
+ /* Find height value. */
+ value = param;
+ param = grub_strchr(param, 'x');
+ if (param == NULL)
+ {
+ height = grub_strtoul (value, 0, 0);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_err_t rc;
+
+ /* First setup error message. */
+ rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "Invalid mode: %s\n",
+ current_mode);
+
+ /* Free memory before returning. */
+ grub_free (modes_copy);
+
+ return rc;
+ }
+ }
+ else
+ {
+ /* We have optional color depth value. */
+ *param = 0;
+ param++;
+
+ height = grub_strtoul (value, 0, 0);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_err_t rc;
+
+ /* First setup error message. */
+ rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "Invalid mode: %s\n",
+ current_mode);
+
+ /* Free memory before returning. */
+ grub_free (modes_copy);
+
+ return rc;
+ }
+
+ /* Convert color depth value. */
+ value = param;
+ depth = grub_strtoul (value, 0, 0);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_err_t rc;
+
+ /* First setup error message. */
+ rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "Invalid mode: %s\n",
+ current_mode);
+
+ /* Free memory before returning. */
+ grub_free (modes_copy);
+
+ return rc;
+ }
+ }
+
+ /* Try out video mode. */
+
+ int flags = mode_flags;
+ /* If we have <= 8 bits, assume it is an indexed color mode. */
+ if ((depth <= 8) && (depth != -1))
+ flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
+
+ /* We have > 8 bits; assume that it is RGB color mode. */
+ if (depth > 8)
+ flags |= GRUB_VIDEO_MODE_TYPE_RGB;
+
+ /* If user requested specific depth, pass the request to driver. */
+ if (depth != -1)
+ flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
+ & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
+
+ /* Try to initialize requested mode. Ignore any errors. */
+ grub_error_push ();
+ if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
+ {
+ grub_error_pop ();
+ continue;
+ }
+
+ /* Figure out what mode we ended up. */
+ struct grub_video_mode_info mode_info;
+ if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+ {
+ /* Couldn't get video mode info, restore old mode
+ and continue to next one. */
+ grub_error_pop ();
+
+ grub_video_restore ();
+ continue;
+ }
+
+ /* Restore state of error stack. */
+ grub_error_pop ();
+
+ /* Mode found! Exit loop. */
+ mode_found = 1;
+ }
+
+ /* Free memory. */
+ grub_free (modes_copy);
+ }
+
+ if (!mode_found)
+ {
+ /* No gfxmode variable set, or no listed mode was supported.
+ Use the caller-specified defaults. */
+ int flags = mode_flags | GRUB_VIDEO_MODE_TYPE_RGB;
+
+ /* Initialize user requested mode. */
+ if (grub_video_setup (default_width, default_height, flags)
+ != GRUB_ERR_NONE)
+ return grub_errno;
+
+ /* Figure out what mode we ended up. */
+ struct grub_video_mode_info mode_info;
+ if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+ grub_video_restore ();
+ else
+ mode_found = 1;
+ }
+
+ if (!mode_found)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "No suitable mode found.");
+
+ return (grub_errno = GRUB_ERR_NONE);
+}