* [PATCH] 5/5 Graphical menu (gfxmenu)
@ 2009-01-31 20:59 Colin D Bennett
2009-01-31 21:39 ` Vesa Jääskeläinen
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Colin D Bennett @ 2009-01-31 20:59 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1.1: Type: text/plain, Size: 1414 bytes --]
This long-awaited patch adds graphical menu support to GRUB 2. It is
largely the result of my work during the Google Summer of Code 2008.
The graphical menu system supports image-based themes, of which I have
created several sample themes[1].
There are still a few important things that need to be done on gfxmenu
before it is completely ready for end-users (off the top of my head):
- Need a good way to switch themes at runtime. I want to add a popup
menu that lists the available themes and lets the user choose one.
(Currently the keys 1, 2, 3, and 4 are hardcoded to switch between my
sample themes...)
- gfxmenu interacts badly with gfxterm. Running commands from the
terminal withing gfxmenu that switch the video mode
('videotest basic', for instance) cause a crash when the command
returns. I think this has something to do with the interaction of
video mode-switching and the GRUB output terminal.
The default theme is set in grub.cfg like so:
set theme="/boot/grub/themes/proto/theme.txt"
Also, pressing 't' currently switches between graphical and text mode
menus, but by adding the following menu entries, it can be done from
the menu:
menuentry "Switch to text menu" {
set menuviewer="terminal"
}
menuentry "Switch to graphical menu" {
set menuviewer="gfxmenu"
}
Regards,
Colin
[1] <http://grub.gibibit.com/Themes>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 05_gfxmenu.patch --]
[-- Type: text/x-patch, Size: 229841 bytes --]
=== 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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/gfxterm.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/term.h>
+#include <grub/gfxwidgets.h>
+#include <grub/menu.h>
+#include <grub/menu_viewer.h>
+#include <grub/gfxmenu_model.h>
+#include <grub/gfxmenu_view.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+
+// 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/font.h>
+#include <grub/gui_string_util.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/gfxwidgets.h>
+#include <grub/trig.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/font.h>
+#include <grub/gui_string_util.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/gfxwidgets.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/font.h>
+#include <grub/gui_string_util.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/gfxwidgets.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/gui_string_util.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/gui_string_util.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/menu.h>
+#include <grub/icon_manager.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/menu.h>
+#include <grub/time.h>
+#include <grub/gfxmenu_model.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/gui.h>
+#include <grub/gui_string_util.h>
+#include <grub/misc.h>
+
+struct named_color
+{
+ const char *name;
+ grub_gui_color_t color;
+};
+
+/*
+ Named color list generated from the list of SVG color keywords from
+ <http://www.w3.org/TR/css3-color/#svg-color>,
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/video.h>
+#include <grub/gui_string_util.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/gfxwidgets.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/gui.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/gui_string_util.h>
+#include <grub/gfxterm.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/term.h>
+#include <grub/gfxwidgets.h>
+#include <grub/time.h>
+#include <grub/menu.h>
+#include <grub/menu_viewer.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/gui.h>
+#include <grub/icon_manager.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/gfxwidgets.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXMENU_MODEL_HEADER
+#define GRUB_GFXMENU_MODEL_HEADER 1
+
+#include <grub/menu.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXMENU_VIEW_HEADER
+#define GRUB_GFXMENU_VIEW_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/menu.h>
+#include <grub/font.h>
+#include <grub/gfxmenu_model.h>
+#include <grub/gfxwidgets.h>
+
+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 <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/gui.h>
+#include <grub/gfxwidgets.h>
+#include <grub/icon_manager.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXTERM_HEADER
+#define GRUB_GFXTERM_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/term.h>
+#include <grub/video.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXWIDGETS_HEADER
+#define GRUB_GFXWIDGETS_HEADER 1
+
+#include <grub/video.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/gfxmenu_model.h>
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GUI_STRING_UTIL_HEADER
+#define GRUB_GUI_STRING_UTIL_HEADER 1
+
+#include <grub/types.h>
+#include <grub/gui.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_ICON_MANAGER_HEADER
+#define GRUB_ICON_MANAGER_HEADER 1
+
+#include <grub/menu.h>
+#include <grub/bitmap.h>
+
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/trig.h>
+
+/* 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 <grub/mm.h>
#include <grub/env.h>
#include <grub/video.h>
+#include <grub/gfxterm.h>
#include <grub/bitmap.h>
#include <grub/bitmap_scale.h>
#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 <width>x<height>[x<depth>]*/
-
- /* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/video.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+/* Set the video mode based on the preferred modes specified in MODE_LIST in
+ the form: <width>x<height>[x<depth>][;...]
+
+ 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 <width>x<height>[x<depth>]*/
+
+ /* 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);
+}
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] 5/5 Graphical menu (gfxmenu)
2009-01-31 20:59 [PATCH] 5/5 Graphical menu (gfxmenu) Colin D Bennett
@ 2009-01-31 21:39 ` Vesa Jääskeläinen
2009-02-08 0:54 ` Robert Millan
2009-03-21 20:13 ` Vesa Jääskeläinen
2 siblings, 0 replies; 4+ messages in thread
From: Vesa Jääskeläinen @ 2009-01-31 21:39 UTC (permalink / raw)
To: The development of GRUB 2
Hi,
As this patch is quite large and I am going go to sleep soon so I only
comment your message on this run...
Colin D Bennett wrote:
> This long-awaited patch adds graphical menu support to GRUB 2. It is
> largely the result of my work during the Google Summer of Code 2008.
And thanks for it!
> There are still a few important things that need to be done on gfxmenu
> before it is completely ready for end-users (off the top of my head):
>
> - Need a good way to switch themes at runtime. I want to add a popup
> menu that lists the available themes and lets the user choose one.
> (Currently the keys 1, 2, 3, and 4 are hardcoded to switch between my
> sample themes...)
I think switching would need to validate new theme before taking it to
into use. When it is ok then it is safe to switch...
> - gfxmenu interacts badly with gfxterm. Running commands from the
> terminal withing gfxmenu that switch the video mode
> ('videotest basic', for instance) cause a crash when the command
> returns. I think this has something to do with the interaction of
> video mode-switching and the GRUB output terminal.
I have thought about this for some years... but still haven't
implemented it.
Basically it should work something like this:
state = grub_video_save_state()
change mode or what ever.
grub_video_restore_state(state);
State would have two parts. One is generic part that tells what video
driver to load and then second part is driver specific so it can restore
old video mode perhaps with same palette if in indexed color mode... but
contents of display does not need to saved. If there is no need to
perform any change on restore (eg. state matches) then no action is taken.
This should work also with text mode, so that at start before changing
video mode grub_video_save_state() would be called which records text
mdoe. And if graphical mode fails, then it would call restore with this
state. Now if there was graphical mode before this it would restore to
old working graphical mode.
> The default theme is set in grub.cfg like so:
>
> set theme="/boot/grub/themes/proto/theme.txt"
I think it would be wise to pick some other theme extension that .txt.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] 5/5 Graphical menu (gfxmenu)
2009-01-31 20:59 [PATCH] 5/5 Graphical menu (gfxmenu) Colin D Bennett
2009-01-31 21:39 ` Vesa Jääskeläinen
@ 2009-02-08 0:54 ` Robert Millan
2009-03-21 20:13 ` Vesa Jääskeläinen
2 siblings, 0 replies; 4+ messages in thread
From: Robert Millan @ 2009-02-08 0:54 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jan 31, 2009 at 12:59:39PM -0800, Colin D Bennett wrote:
> This long-awaited patch adds graphical menu support to GRUB 2. It is
> largely the result of my work during the Google Summer of Code 2008.
:-)
> +# For gfxmenu.mod.
> +gfxmenu_mod_SOURCES = \
I think there's some patch/mod/hack for GRUB Legacy that is called like that.
Perhaps it'd be a good idea to use another name to avoid confusion.
--
Robert Millan
The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
how) you may access your data; but nobody's threatening your freedom: we
still allow you to remove your data and not access it at all."
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] 5/5 Graphical menu (gfxmenu)
2009-01-31 20:59 [PATCH] 5/5 Graphical menu (gfxmenu) Colin D Bennett
2009-01-31 21:39 ` Vesa Jääskeläinen
2009-02-08 0:54 ` Robert Millan
@ 2009-03-21 20:13 ` Vesa Jääskeläinen
2 siblings, 0 replies; 4+ messages in thread
From: Vesa Jääskeläinen @ 2009-03-21 20:13 UTC (permalink / raw)
To: The development of GRUB 2
Colin D Bennett wrote:
> This long-awaited patch adds graphical menu support to GRUB 2. It is
> largely the result of my work during the Google Summer of Code 2008.
>
> The graphical menu system supports image-based themes, of which I have
> created several sample themes[1].
>
> There are still a few important things that need to be done on gfxmenu
> before it is completely ready for end-users (off the top of my head):
>
> - Need a good way to switch themes at runtime. I want to add a popup
> menu that lists the available themes and lets the user choose one.
> (Currently the keys 1, 2, 3, and 4 are hardcoded to switch between my
> sample themes...)
Switching themes on runtime is not a priority. It is a nice to have
feature thou... but we can wait a bit with that.
> - gfxmenu interacts badly with gfxterm. Running commands from the
> terminal withing gfxmenu that switch the video mode
> ('videotest basic', for instance) cause a crash when the command
> returns. I think this has something to do with the interaction of
> video mode-switching and the GRUB output terminal.
I think we can live with some oddities so I would propose that we get
some version in. In fact it will make fixing bugs a bit more robust as
others can also contribute...
So whats the status of your actions. I think some of the patches were
already approved with some minor changes...
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-03-21 20:13 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-31 20:59 [PATCH] 5/5 Graphical menu (gfxmenu) Colin D Bennett
2009-01-31 21:39 ` Vesa Jääskeläinen
2009-02-08 0:54 ` Robert Millan
2009-03-21 20:13 ` Vesa Jääskeläinen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.