gfxmenu import

This commit is contained in:
Colin D Bennett 2009-11-20 16:02:58 +01:00 committed by Vladimir 'phcoder' Serbinenko
parent bd86691a07
commit d920a32ab6
25 changed files with 5977 additions and 1 deletions

View file

@ -417,6 +417,28 @@ hello_mod_SOURCES = hello/hello.c
hello_mod_CFLAGS = $(COMMON_CFLAGS)
hello_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For gfxmenu.mod.
pkglib_MODULES += 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 parttool.mod.
parttool_mod_SOURCES = commands/parttool.c
parttool_mod_CFLAGS = $(COMMON_CFLAGS)

View file

@ -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"
}

235
gfxmenu/gfxmenu.c Normal file
View file

@ -0,0 +1,235 @@
/* 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/command.h>
#include <grub/video.h>
#include <grub/gfxterm.h>
#include <grub/bitmap.h>
#include <grub/bitmap_scale.h>
#include <grub/term.h>
#include <grub/env.h>
#include <grub/normal.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", "text");
}
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);
}
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;
}
if (grub_errno != GRUB_ERR_NONE)
*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 text 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 text 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 (grub_command_t cmd UNUSED,
int argc UNUSED, char **args 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
};
static grub_command_t cmd;
GRUB_MOD_INIT (gfxmenu)
{
(void) mod; /* To stop warning. */
grub_menu_viewer_register (&menu_viewer);
cmd = grub_register_command ("gfxmenu", grub_cmd_gfxmenu,
"gfxmenu",
"Show graphical menu interface");
}
GRUB_MOD_FINI (gfxmenu)
{
grub_unregister_command (cmd);
}

372
gfxmenu/gui_box.c Normal file
View file

@ -0,0 +1,372 @@
/* gui_box.c - GUI container that stack components. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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);
if (! self->id)
return grub_errno;
}
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) != GRUB_ERR_NONE)
return grub_errno;
self->preferred_width = w;
self->preferred_height = h;
}
return grub_errno;
}
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);
}

268
gfxmenu/gui_canvas.c Normal file
View file

@ -0,0 +1,268 @@
/* gui_canvas.c - GUI container allowing manually placed components. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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);
if (! self->id)
return grub_errno;
}
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) != GRUB_ERR_NONE)
return grub_errno;
self->preferred_width = w;
self->preferred_height = h;
}
return grub_errno;
}
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;
}

View file

@ -0,0 +1,339 @@
/* gui_circular_process.c - GUI circular progress indicator component. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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) != GRUB_ERR_NONE)
return grub_errno;
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;
}
return grub_errno;
}
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;
}

270
gfxmenu/gui_image.c Normal file
View file

@ -0,0 +1,270 @@
/* gui_image.c - GUI component to display an image. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
rescale_image (grub_gui_image_t self)
{
if (! self->raw_bitmap)
{
if (self->bitmap)
{
grub_video_bitmap_destroy (self->bitmap);
self->bitmap = 0;
}
return grub_errno;
}
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))
{
/* Nothing to do; already the right size. */
return grub_errno;
}
/* 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);
self->bitmap = 0;
/* 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 grub_errno;
}
/* Don't scale to an invalid size. */
if (width == 0 || height == 0)
return grub_errno;
/* Create the scaled bitmap. */
grub_video_bitmap_create_scaled (&self->bitmap,
width,
height,
self->raw_bitmap,
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
if (grub_errno != GRUB_ERR_NONE)
{
grub_error_push ();
grub_error (grub_errno, "failed to scale bitmap for image component");
}
return grub_errno;
}
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 grub_err_t
load_image (grub_gui_image_t self, const char *path)
{
struct grub_video_bitmap *bitmap;
if (grub_video_bitmap_load (&bitmap, path) != GRUB_ERR_NONE)
return grub_errno;
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;
return rescale_image (self);
}
static grub_err_t
image_set_property (void *vself, const char *name, const char *value)
{
grub_gui_image_t self = vself;
if (grub_strcmp (name, "file") == 0)
return 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) != GRUB_ERR_NONE)
return grub_errno;
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;
}
return grub_errno;
}
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;
}

248
gfxmenu/gui_label.c Normal file
View file

@ -0,0 +1,248 @@
/* gui_label.c - GUI component to display a line of text. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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)
{
grub_gui_parse_color (value, &self->color);
}
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) == GRUB_ERR_NONE)
{
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;
}

625
gfxmenu/gui_list.c Normal file
View file

@ -0,0 +1,625 @@
/* gui_list.c - GUI component to display a selectable list of items. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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)
{
grub_gui_parse_color (value, &self->item_color);
}
else if (grub_strcmp (name, "selected_item_color") == 0)
{
if (! value || grub_strcmp (value, "inherit") == 0)
{
self->selected_item_color_set = 0;
}
else
{
if (grub_gui_parse_color (value, &self->selected_item_color)
== GRUB_ERR_NONE)
self->selected_item_color_set = 1;
}
}
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) != GRUB_ERR_NONE)
return grub_errno;
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;
}
return grub_errno;
}
/* 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;
}

378
gfxmenu/gui_progress_bar.c Normal file
View file

@ -0,0 +1,378 @@
/* gui_progress_bar.c - GUI progress bar component. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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)
{
grub_gui_parse_color (value, &self->text_color);
}
else if (grub_strcmp (name, "border_color") == 0)
{
grub_gui_parse_color (value, &self->border_color);
}
else if (grub_strcmp (name, "bg_color") == 0)
{
grub_gui_parse_color (value, &self->bg_color);
}
else if (grub_strcmp (name, "fg_color") == 0)
{
grub_gui_parse_color (value, &self->fg_color);
}
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) != GRUB_ERR_NONE)
return grub_errno;
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;
}
return grub_errno;
}
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;
}

358
gfxmenu/gui_string_util.c Normal file
View file

@ -0,0 +1,358 @@
/* gui_string_util.c - String utilities used by the GUI system. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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_err_t
grub_gui_parse_color (const char *s, grub_gui_color_t *color)
{
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
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"invalid HTML-type color string `%s'", s);
}
else if (grub_isdigit (*s))
{
/* Comma separated decimal values. */
c.red = grub_strtoul (s, 0, 0);
if ((s = grub_strchr (s, ',')) == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"missing 1st comma separator in color `%s'", s);
s++;
c.green = grub_strtoul (s, 0, 0);
if ((s = grub_strchr (s, ',')) == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"missing 2nd comma separator in color `%s'", s);
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))
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"invalid named color `%s'", s);
}
if (grub_errno == GRUB_ERR_NONE)
*color = c;
return grub_errno;
}
/* Parse a value in the form "(x, y)", storing the first element (x) into
*PX and the second element (y) into *PY.
Returns GRUB_ERR_NONE if successfully parsed. */
grub_err_t
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 grub_error (GRUB_ERR_BAD_ARGUMENT,
"missing `(' in 2-tuple `%s'", s);
/* Skip the opening parentheses. */
s++;
if (*s == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"unexpected end of 2-tuple after `(' in `%s'", s);
/* Parse the first element. */
x = grub_strtol (s, 0, 10);
if ((s = grub_strchr (s, ',')) == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"missing comma in 2-tuple `%s'", s);
/* Skip the element separator (the comma). */
s++;
/* Parse the second element. */
y = grub_strtol (s, 0, 10);
*px = x;
*py = y;
return grub_errno;
}

101
gfxmenu/gui_util.c Normal file
View file

@ -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);
}

258
gfxmenu/icon_manager.c Normal file
View file

@ -0,0 +1,258 @@
/* icon_manager.c - gfxmenu icon manager. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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)
{
grub_error_push ();
grub_error (grub_errno, "failed to scale icon");
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;
}

191
gfxmenu/model.c Normal file
View file

@ -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];
}

209
gfxmenu/named_colors.c Normal file
View file

@ -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;
}

720
gfxmenu/theme_loader.c Normal file
View file

@ -0,0 +1,720 @@
/* 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. */
static grub_err_t
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 grub_error (GRUB_ERR_BAD_ARGUMENT,
"missing `*' in box pixmap pattern `%s'", abspattern);
/* Prefix: Get the part before the '*'. */
prefix = grub_malloc (star - abspattern + 1);
if (! prefix)
return grub_errno;
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 grub_errno;
if (*boxptr)
(*boxptr)->destroy (*boxptr);
*boxptr = box;
return grub_errno;
}
/* 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. */
grub_err_t
grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr,
const char *pattern, const char *theme_dir)
{
char *abspattern;
/* Check arguments. */
if (! pattern)
{
/* If no pixmap pattern is given, then just create an empty box. */
if (*boxptr)
(*boxptr)->destroy (*boxptr);
*boxptr = grub_gfxmenu_create_box (0, 0);
return grub_errno;
}
if (! theme_dir)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"styled box missing theme directory");
/* Resolve to an absolute path. */
abspattern = grub_resolve_relative_path (theme_dir, pattern);
if (! abspattern)
return grub_errno;
/* Create the box. */
recreate_box_absolute (boxptr, abspattern);
grub_free (abspattern);
return grub_errno;
}
/* Set the specified property NAME on the view to the given string VALUE.
The caller is responsible for the lifetimes of NAME and VALUE. */
static grub_err_t
theme_set_string (grub_gfxmenu_view_t view,
const char *name,
const char *value,
const char *theme_dir,
const char *filename,
int line_num,
int col_num)
{
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);
if (! view->terminal_font_name)
return grub_errno;
}
else if (! grub_strcmp ("title-color", name))
grub_gui_parse_color (value, &view->title_color);
else if (! grub_strcmp ("message-color", name))
grub_gui_parse_color (value, &view->message_color);
else if (! grub_strcmp ("message-bg-color", name))
grub_gui_parse_color (value, &view->message_bg_color);
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;
if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
{
grub_free (path);
return grub_errno;
}
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)
{
grub_error_push ();
return grub_error (grub_errno, "error scaling desktop image");
}
grub_video_bitmap_destroy (view->desktop_image);
view->desktop_image = scaled_bitmap;
}
else if (! grub_strcmp ("desktop-color", name))
grub_gui_parse_color (value, &view->desktop_color);
else if (! grub_strcmp ("terminal-box", name))
{
grub_err_t err;
err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
if (err != GRUB_ERR_NONE)
return err;
}
else if (! grub_strcmp ("title-text", name))
{
grub_free (view->title_text);
view->title_text = grub_strdup (value);
if (! view->title_text)
return grub_errno;
}
else
{
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"%s:%d:%d unknown property `%s'",
filename, line_num, col_num, name);
}
return grub_errno;
}
struct parsebuf
{
char *buf;
int pos;
int len;
int line_num;
int col_num;
const char *filename;
char *theme_dir;
grub_gfxmenu_view_t view;
};
static int
has_more (struct parsebuf *p)
{
return p->pos < p->len;
}
static int
read_char (struct parsebuf *p)
{
if (has_more (p))
{
char c;
c = p->buf[p->pos++];
if (c == '\n')
{
p->line_num++;
p->col_num = 1;
}
else
{
p->col_num++;
}
return c;
}
else
return -1;
}
static int
peek_char (struct parsebuf *p)
{
if (has_more (p))
return p->buf[p->pos];
else
return -1;
}
static int
is_whitespace (char c)
{
return (c == ' '
|| c == '\t'
|| c == '\r'
|| c == '\n'
|| c == '\f');
}
static void
skip_whitespace (struct parsebuf *p)
{
while (has_more (p) && is_whitespace(peek_char (p)))
read_char (p);
}
static void
advance_to_next_line (struct parsebuf *p)
{
int c;
/* Eat characters up to the newline. */
do
{
c = read_char (p);
}
while (c != -1 && c != '\n');
}
static int
is_identifier_char (int c)
{
return (c != -1
&& (grub_isalpha(c)
|| grub_isdigit(c)
|| c == '_'
|| c == '-'));
}
static char *
read_identifier (struct parsebuf *p)
{
/* Index of the first character of the identifier in p->buf. */
int start;
/* Next index after the last character of the identifer in p->buf. */
int end;
skip_whitespace (p);
/* Capture the start of the identifier. */
start = p->pos;
/* Scan for the end. */
while (is_identifier_char (peek_char (p)))
read_char (p);
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 (peek_char (p) == '"')
{
/* Read as a quoted string.
The quotation marks are not included in the expression value. */
/* Skip opening quotation mark. */
read_char (p);
start = p->pos;
while (has_more (p) && peek_char (p) != '"')
read_char (p);
end = p->pos;
/* Skip the terminating quotation mark. */
read_char (p);
}
else if (peek_char (p) == '(')
{
/* Read as a parenthesized string -- for tuples/coordinates. */
/* The parentheses are included in the expression value. */
int c;
start = p->pos;
do
{
c = read_char (p);
}
while (c != -1 && c != ')');
end = p->pos;
}
else if (has_more (p))
{
/* Read as a single word -- for numeric values or words without
whitespace. */
start = p->pos;
while (has_more (p) && ! is_whitespace (peek_char (p)))
read_char (p);
end = p->pos;
}
else
{
/* The end of the theme file has been reached. */
grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file",
p->filename, p->line_num, p->col_num);
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. */
static grub_err_t
read_object (struct parsebuf *p, grub_gui_container_t parent)
{
grub_video_rect_t bounds;
char *name;
name = read_identifier (p);
if (! name)
goto cleanup;
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. */
grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'",
p->filename, p->line_num, p->col_num, name);
goto cleanup;
}
if (! component)
goto cleanup;
/* Inform the component about the theme so it can find its resources. */
component->ops->set_property (component, "theme_dir", p->theme_dir);
component->ops->set_property (component, "theme_path", p->filename);
/* Add the component as a child of PARENT. */
bounds.x = 0;
bounds.y = 0;
bounds.width = -1;
bounds.height = -1;
component->ops->set_bounds (component, &bounds);
parent->ops->add (parent, component);
skip_whitespace (p);
if (read_char (p) != '{')
{
grub_error (GRUB_ERR_IO,
"%s:%d:%d expected `{' after object type name `%s'",
p->filename, p->line_num, p->col_num, name);
goto cleanup;
}
while (has_more (p))
{
skip_whitespace (p);
/* Check whether the end has been encountered. */
if (peek_char (p) == '}')
{
/* Skip the closing brace. */
read_char (p);
break;
}
if (peek_char (p) == '#')
{
/* Skip comments. */
advance_to_next_line (p);
continue;
}
if (peek_char (p) == '+')
{
/* Skip the '+'. */
read_char (p);
/* 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 cleanup;
/* After reading the sub-object, resume parsing, expecting
another property assignment or sub-object definition. */
continue;
}
else
{
grub_error (GRUB_ERR_IO,
"%s:%d:%d attempted to add object to non-container",
p->filename, p->line_num, p->col_num);
goto cleanup;
}
}
char *property;
property = read_identifier (p);
if (! property)
{
grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file",
p->filename, p->line_num, p->col_num);
goto cleanup;
}
skip_whitespace (p);
if (read_char (p) != '=')
{
grub_error (GRUB_ERR_IO,
"%s:%d:%d expected `=' after property name `%s'",
p->filename, p->line_num, p->col_num, property);
grub_free (property);
goto cleanup;
}
skip_whitespace (p);
char *value;
value = read_expression (p);
if (! value)
{
grub_free (property);
goto cleanup;
}
/* 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_ERR_NONE)
{
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_ERR_NONE)
{
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);
if (grub_errno != GRUB_ERR_NONE)
goto cleanup;
}
/* Set the object's size to its preferred size unless the user has
explicitly specified the size. */
component->ops->get_bounds (component, &bounds);
if (bounds.width == -1 || bounds.height == -1)
{
component->ops->get_preferred_size (component,
&bounds.width, &bounds.height);
component->ops->set_bounds (component, &bounds);
}
cleanup:
grub_free (name);
return grub_errno;
}
static grub_err_t
read_property (struct parsebuf *p)
{
char *name;
/* Read the property name. */
name = read_identifier (p);
if (! name)
{
advance_to_next_line (p);
return grub_errno;
}
/* Skip whitespace before separator. */
skip_whitespace (p);
/* Read separator. */
if (read_char (p) != ':')
{
grub_error (GRUB_ERR_IO,
"%s:%d:%d missing separator after property name `%s'",
p->filename, p->line_num, p->col_num, name);
goto done;
}
/* Skip whitespace after separator. */
skip_whitespace (p);
/* Get the value based on its type. */
if (peek_char (p) == '"')
{
/* String value (e.g., '"My string"'). */
char *value = read_expression (p);
if (! value)
{
grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value",
p->filename, p->line_num, p->col_num);
goto done;
}
/* If theme_set_string results in an error, grub_errno will be returned
below. */
theme_set_string (p->view, name, value, p->theme_dir,
p->filename, p->line_num, p->col_num);
grub_free (value);
}
else
{
grub_error (GRUB_ERR_IO,
"%s:%d:%d property value invalid; "
"enclose literal values in quotes (\")",
p->filename, p->line_num, p->col_num);
goto done;
}
done:
grub_free (name);
return grub_errno;
}
/* Set properties on the view based on settings from the specified
theme file. */
grub_err_t
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 grub_errno;
}
p.len = grub_file_size (file);
p.buf = grub_malloc (p.len);
p.pos = 0;
p.line_num = 1;
p.col_num = 1;
p.filename = theme_path;
if (! p.buf)
{
grub_file_close (file);
grub_free (p.theme_dir);
return grub_errno;
}
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 grub_errno;
}
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);
while (has_more (&p))
{
/* Skip comments (lines beginning with #). */
if (peek_char (&p) == '#')
{
advance_to_next_line (&p);
continue;
}
/* Find the first non-whitespace character. */
skip_whitespace (&p);
/* Handle the content. */
if (peek_char (&p) == '+')
{
/* Skip the '+'. */
read_char (&p);
read_object (&p, view->canvas);
}
else
{
read_property (&p);
}
if (grub_errno != GRUB_ERR_NONE)
goto fail;
}
/* Set the new theme path. */
grub_free (view->theme_path);
view->theme_path = grub_strdup (theme_path);
goto cleanup;
fail:
if (view->canvas)
{
view->canvas->ops->component.destroy (view->canvas);
view->canvas = 0;
}
cleanup:
grub_free (p.buf);
grub_file_close (file);
grub_free (p.theme_dir);
return grub_errno;
}

497
gfxmenu/view.c Normal file
View file

@ -0,0 +1,497 @@
/* 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) != 0)
{
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 *modestr = grub_env_get ("gfxmode");
if (!modestr || !modestr[0])
modestr = "auto";
return grub_video_set_mode (modestr, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
}
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, 0,
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 (grub_menu_entry_t entry, void *userdata)
{
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 (grub_menu_entry_t entry, void *userdata)
{
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);
}

313
gfxmenu/widget-box.c Normal file
View file

@ -0,0 +1,313 @@
/* widget_box.c - Pixmap-stylized box widget. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 grub_err_t
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 grub_errno;
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;
}
/* Don't try to create a bitmap with a zero dimension. */
if (w != 0 && h != 0)
grub_video_bitmap_create_scaled (scaled, w, h, raw,
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
if (grub_errno != GRUB_ERR_NONE)
{
grub_error_push ();
grub_error (grub_errno,
"failed to scale bitmap for styled box pixmap #%d", i);
}
}
return grub_errno;
}
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. */
if (scale_pixmap(self, BOX_PIXMAP_N, width, -1) != GRUB_ERR_NONE)
return;
if (scale_pixmap(self, BOX_PIXMAP_S, width, -1) != GRUB_ERR_NONE)
return;
/* Resize E and W sides to match height. */
if (scale_pixmap(self, BOX_PIXMAP_E, -1, height) != GRUB_ERR_NONE)
return;
if (scale_pixmap(self, BOX_PIXMAP_W, -1, height) != GRUB_ERR_NONE)
return;
/* Don't scale the corners--they are assumed to match the sides. */
if (scale_pixmap(self, BOX_PIXMAP_NW, -1, -1) != GRUB_ERR_NONE)
return;
if (scale_pixmap(self, BOX_PIXMAP_SW, -1, -1) != GRUB_ERR_NONE)
return;
if (scale_pixmap(self, BOX_PIXMAP_NE, -1, -1) != GRUB_ERR_NONE)
return;
if (scale_pixmap(self, BOX_PIXMAP_SE, -1, -1) != GRUB_ERR_NONE)
return;
/* Scale the center area. */
if (scale_pixmap(self, BOX_PIXMAP_CENTER, width, height) != GRUB_ERR_NONE)
return;
}
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;
/* Free self: must be the last step! */
grub_free (self);
}
/* 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)
{
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 *));
/* Initialize all pixmap pointers to NULL so that proper destruction can
be performed if an error is encountered partway through construction. */
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
box->raw_pixmaps[i] = 0;
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
box->scaled_pixmaps[i] = 0;
/* Load the pixmaps. */
for (i = 0; i < BOX_NUM_PIXMAPS; i++)
{
if (pixmaps_prefix && pixmaps_suffix)
{
char *path;
char *path_end;
path = grub_malloc (grub_strlen (pixmaps_prefix)
+ grub_strlen (box_pixmap_names[i])
+ grub_strlen (pixmaps_suffix)
+ 1);
if (! path)
goto fail_and_destroy;
/* Construct the specific path for this pixmap. */
path_end = grub_stpcpy (path, pixmaps_prefix);
path_end = grub_stpcpy (path_end, box_pixmap_names[i]);
path_end = grub_stpcpy (path_end, pixmaps_suffix);
grub_video_bitmap_load (&box->raw_pixmaps[i], path);
grub_free (path);
/* Ignore missing pixmaps. */
grub_errno = GRUB_ERR_NONE;
}
}
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;
fail_and_destroy:
destroy (box);
return 0;
}

View file

@ -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 */

View file

@ -0,0 +1,91 @@
/* gfxmenu_view.h - gfxmenu view interface. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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. */
grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view,
const char *theme_path);
grub_err_t 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 */

49
include/grub/gfxwidgets.h Normal file
View file

@ -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 */

165
include/grub/gui.h Normal file
View file

@ -0,0 +1,165 @@
/* gui.h - GUI components header file. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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);
grub_err_t (*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 */

View file

@ -0,0 +1,39 @@
/* gui_string_util.h - String utilities for the graphical menu interface. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color);
grub_err_t grub_gui_parse_2_tuple (const char *s, int *px, int *py);
#endif /* GRUB_GUI_STRING_UTIL_HEADER */

View file

@ -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 */

View file

@ -261,7 +261,7 @@ grub_term_set_current_input (grub_term_input_t term)
}
static inline grub_err_t
grub_term_set_current_output (grub_term_output_t term)
grub_term_set_current_output (const struct grub_term_output *term)
{
return grub_handler_set_current (&grub_term_output_class,
GRUB_AS_HANDLER (term));