]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Initial effort for gfxmenu on multiterm branch
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 26 Dec 2009 00:49:57 +0000 (01:49 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 26 Dec 2009 00:49:57 +0000 (01:49 +0100)
21 files changed:
1  2 
Makefile.in
conf/any-emu.rmk
conf/common.rmk
genmk.rb
gfxmenu/gfxmenu.c
gfxmenu/gui_circular_progress.c
gfxmenu/gui_list.c
gfxmenu/gui_progress_bar.c
gfxmenu/model.c
gfxmenu/view.c
include/grub/gfxmenu_model.h
include/grub/gfxmenu_view.h
include/grub/gui.h
include/grub/menu.h
include/grub/misc.h
kern/misc.c
kern/term.c
loader/i386/linux.c
normal/cmdline.c
normal/menu.c
normal/menu_viewer.c

diff --cc Makefile.in
Simple merge
Simple merge
diff --cc conf/common.rmk
Simple merge
diff --cc genmk.rb
index b3dbe867811d36347d7567039ebb84d496284d8c,43eaef150155729d627502a7e6dff4143dc9c7c1..6cb7b5a89576348716fead399525997e67a312f0
+++ b/genmk.rb
@@@ -240,6 -242,11 +242,11 @@@ VIDEOFILES += #{video
          $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
          | sh $(srcdir)/genhandlerlist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
  
 -#{terminal}: #{src} $(#{src}_DEPENDENCIES) genterminlist.sh
++#{terminal}: #{src} $(#{src}_DEPENDENCIES) genterminallist.sh
+       set -e; \
+         $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
+         | sh $(srcdir)/genterminallist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
  #{video}: #{src} $(#{src}_DEPENDENCIES) genvideolist.sh
        set -e; \
          $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
index 62ee34234499639b712f87c4889da42a35dc6766,0000000000000000000000000000000000000000..0d807914b3dd1e4301a4b03ec2423994d83570e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,235 -1,0 +1,94 @@@
- static void switch_to_text_menu (void)
 +/* 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>
 +#include <grub/time.h>
 +
-   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);
-   switch (c)
-     {
-     case 'j':
-     case 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);
-           grub_gfxmenu_redraw_menu (view);
-         }
-       }
-     break;
-     case 'k':
-     case GRUB_TERM_UP:
-       {
-       int i = grub_gfxmenu_model_get_selected_index (model);
-       if (i > 0)
-         {
-           i--;
-           grub_gfxmenu_model_set_selected_index (model, i);
-           grub_gfxmenu_redraw_menu (view);
-         }
-       }
-     break;
-     case '\r':
-     case '\n':
-     case 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);
-         }
-       }
-     break;
-     case 'c':
-       grub_gfxmenu_view_run_terminal (view);
-       break;
-     case 't':
-       /* The write hook for 'menuviewer' will cause
-        * grub_menu_viewer_should_return to return nonzero. */
-       switch_to_text_menu ();
-       *should_exit = 1;
-       break;
++void 
++grub_gfxmenu_viewer_fini (void *data)
 +{
-     case GRUB_TERM_ESC:
-       if (nested)
-       *should_exit = 1;
-       break;
-     }
-   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);
-     }
++  grub_gfxmenu_view_t view = data;
 +
- static grub_err_t
- show_menu (grub_menu_t menu, int nested)
++  grub_gfxmenu_view_destroy (view);
 +}
 +
-   grub_gfxmenu_model_t model;
++/* FIXME: 't' and 'c'.  */
++grub_err_t
++grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
 +{
-     {
-       switch_to_text_menu ();
-       return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified");
-     }
 +  grub_gfxmenu_view_t view;
 +  const char *theme_path;
++  struct grub_menu_viewer *instance;
 +
 +  theme_path = grub_env_get ("theme");
 +  if (! theme_path)
-   model = grub_gfxmenu_model_new (menu);
-   if (! model)
-     {
-       switch_to_text_menu ();
-       return grub_errno;
-     }
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified");
 +
-   view = grub_gfxmenu_view_new (theme_path, model);
++  instance = grub_zalloc (sizeof (*instance));
++  if (!instance)
++    return grub_errno;
 +
 +  /* Create the view.  */
-       grub_print_error ();
-       grub_gfxmenu_model_destroy (model);
-       switch_to_text_menu ();
++  view = grub_gfxmenu_view_new (theme_path, menu, entry, nested);
 +
 +  if (! view)
 +    {
-   /* 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;
++      grub_free (instance);
 +      return grub_errno;
 +    }
 +
-   grub_video_swap_buffers ();
-   if (view->double_repaint)
-     grub_gfxmenu_view_draw (view);
-   while ((! exit_requested) && (! grub_menu_viewer_should_return ()))
-     {
-       grub_gfxmenu_redraw_timeout (view);
-       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);
-       handle_key_events (model, view, nested, &exit_requested);
-       grub_cpu_idle ();
-     }
 +
-   grub_gfxmenu_view_destroy (view);
-   grub_gfxmenu_model_destroy (model);
++  instance->data = view;
++  instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry;
++  instance->fini = grub_gfxmenu_viewer_fini;
++  instance->print_timeout = grub_gfxmenu_print_timeout;
++  instance->clear_timeout = grub_gfxmenu_clear_timeout;
 +
-   return grub_errno;
++  grub_menu_register_viewer (instance);
 +
- static grub_err_t
- grub_cmd_gfxmenu (grub_command_t cmd __attribute__ ((unused)),
-                   int argc __attribute__ ((unused)),
-                 char **args __attribute__ ((unused)))
- {
-   grub_menu_t menu = grub_env_get_data_slot ("menu");
-   if (! menu)
-     return grub_error (GRUB_ERR_MENU, "no menu context");
-   return show_menu (menu, 1);
- }
- static struct grub_menu_viewer menu_viewer =
- {
-   .name = "gfxmenu",
-   .show_menu = show_menu
- };
- static grub_command_t cmd;
++  return GRUB_ERR_NONE;
 +}
 +
-   (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_INIT (gfxmenu)
 +{
-   grub_unregister_command (cmd);
++  grub_gfxmenu_try_hook = grub_gfxmenu_try;
 +}
 +
 +GRUB_MOD_FINI (gfxmenu)
 +{
++  grub_gfxmenu_try_hook = NULL;
 +}
index f3c8bc3af67ae2c6e86eef9befec0c6c01cd0679,0000000000000000000000000000000000000000..98d818558fd08ca88be80f16082d156d838c57c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,343 -1,0 +1,347 @@@
-   int nticks = (self->num_ticks
-                 * (self->value - self->start)
-                 / (self->end - self->start));
 +/* 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, const grub_video_rect_t *region)
 +{
 +  circular_progress_t self = vself;
 +
 +  if (! self->visible)
 +    return;
 +
 +  if (!grub_video_have_common_points (region, &self->bounds))
 +    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;
 +  int tick_begin;
 +  int tick_end;
++  if (self->end == self->start)
++    nticks = 0;
++  else
++    nticks = (self->num_ticks
++            * (self->value - self->start)
++            / (self->end - self->start));
 +  /* 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;
 +}
index bf6d94657bef0f805ab27d9f9d2bba8489dc4faa,0000000000000000000000000000000000000000..68f19a3a64c63df2a96f873bbd02fe78b20371b2
mode 100644,000000..100644
--- /dev/null
@@@ -1,627 -1,0 +1,627 @@@
-   grub_gfxmenu_model_t menu;
 +/* 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;
-   int n = grub_gfxmenu_model_get_num_entries (self->menu);
++
++  grub_gfxmenu_view_t view;
 +};
 +
 +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)
 +{
-   entry = grub_gfxmenu_model_get_entry (self->menu, item_index);
++  int n = self->view->menu->size;
 +  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;
-   int selected_index = grub_gfxmenu_model_get_selected_index (self->menu);
++  entry = grub_menu_get_entry (self->view->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 total_num_items = grub_gfxmenu_model_get_num_entries (self->menu);
++  int selected_index = self->view->selected;
 +  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 is_selected =
-         (menu_index == grub_gfxmenu_model_get_selected_index (self->menu));
++  int total_num_items = self->view->menu->size;
 +  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++)
 +    {
-         grub_gfxmenu_model_get_entry_title (self->menu, menu_index);
++      int is_selected = (menu_index == self->view->selected);
 +
 +      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 =
-                     const char *theme_path,
-                     grub_gfxmenu_model_t menu)
++        grub_menu_get_entry (self->view->menu, menu_index)->title;
 +      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, const grub_video_rect_t *region)
 +{
 +  list_impl_t self = vself;
 +  grub_video_rect_t vpsave;
 +
 +  if (! self->visible)
 +    return;
 +  if (!grub_video_have_common_points (region, &self->bounds))
 +    return;
 +
 +  check_boxes (self);
 +
 +  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,
-   grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, theme_path);
-   self->menu = menu;
++                    grub_gfxmenu_view_t view)
 +{
 +  list_impl_t self = vself;
++  grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager,
++                                          view->theme_path);
++  self->view = view;
 +}
 +
 +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;
 +}
index 49871116990b9ea1fc4ba71ad9c7544813affd05,0000000000000000000000000000000000000000..c71997812a9b39803dc79414270e6fd6135e2dd3
mode 100644,000000..100644
--- /dev/null
@@@ -1,380 -1,0 +1,386 @@@
-   int barwidth = (tracklen
-                   * (self->value - self->start)
-                   / (self->end - self->start));
 +/* 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;
++  int barwidth;
++
++  if (self->end == self->start)
++    return;
++
 +  bar->set_content_size (bar, tracklen, trackheight);
 +
-   grub_video_rect_t vpsave;
++  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, const grub_video_rect_t *region)
 +{
 +  grub_gui_progress_bar_t self = vself;
++  grub_video_rect_t vpsave;
++
 +  if (! self->visible)
 +    return;
 +  if (!grub_video_have_common_points (region, &self->bounds))
 +    return;
 +
 +  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;
 +}
diff --cc gfxmenu/model.c
index 26490ea1fc8819788f2fa672f59bb73dd4991946,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
mode 100644,000000..100644
--- /dev/null
diff --cc gfxmenu/view.c
index 7d9bb1cd074886cef6d74b8c4394e582d53d835b,0000000000000000000000000000000000000000..882469447db51be55513c554e2590fb80298fe86
mode 100644,000000..100644
--- /dev/null
@@@ -1,595 -1,0 +1,565 @@@
- #include <grub/gui_string_util.h>
 +/* 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.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>
- static void init_terminal (grub_gfxmenu_view_t view);
- static void destroy_terminal (void);
++#include <grub/gui_string_util.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__"
 +
++#if 0
 +static grub_gfxmenu_view_t term_view;
++#endif
 +
- grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model)
 +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
-   view->model = model;
++grub_gfxmenu_view_new (const char *theme_path, grub_menu_t menu, int entry,
++                     int nested)
 +{
 +  grub_gfxmenu_view_t view;
 +  grub_err_t err;
 +  struct grub_video_mode_info mode_info;
 +
 +  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);
 +
 +  err = grub_video_get_info (&mode_info);
 +  if (err)
 +    {
 +      grub_free (view);
 +      return 0;
 +    }
 +  else
 +    view->double_repaint = (mode_info.mode_type
 +                          & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
 +      && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
 +
 +
 +  /* 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->last_seconds_remaining = -2;
 +  view->canvas = 0;
++  view->selected = entry;
++  view->menu = menu;
++  view->nested = nested;
++  view->first_timeout = -1;
 +
 +  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;
- static inline void
- update_timeout (grub_gfxmenu_view_t view, int is_init)
 +
 +  /* Set the timeout bar's frame.  */
 +  view->progress_message_frame.width = view->screen.width * 4 / 5;
 +  view->progress_message_frame.height = 50;
 +  view->progress_message_frame.x = view->screen.x
 +    + (view->screen.width - view->progress_message_frame.width) / 2;
 +  view->progress_message_frame.y = view->screen.y
 +    + view->screen.height - 90 - 20 - view->progress_message_frame.height;
 +
 +  if (grub_gfxmenu_view_load_theme (view, theme_path) != 0)
 +    {
 +      grub_gfxmenu_view_destroy (view);
 +      return 0;
 +    }
 +
++#if 0
 +  init_terminal (view);
++#endif
 +
 +  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 ();
++#if 0
 +  destroy_terminal ();
++#endif
 +}
 +
++#if 0
 +/* 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;
 +}
++#endif
 +
 +static void
 +redraw_background (grub_gfxmenu_view_t view,
 +                 const grub_video_rect_t *bounds)
 +{
 +  if (view->desktop_image)
 +    {
 +      struct grub_video_bitmap *img = view->desktop_image;
 +      grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
 +                              bounds->x, bounds->y,
 +                            bounds->x - view->screen.x,
 +                            bounds->y - view->screen.y,
 +                            bounds->width, bounds->height);
 +    }
 +  else
 +    {
 +      grub_video_fill_rect (grub_gui_map_color (view->desktop_color),
 +                            bounds->x, bounds->y,
 +                            bounds->width, bounds->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);
 +}
 +
-   char startbuf[20];
-   char valuebuf[20];
++void 
++grub_gfxmenu_print_timeout (int timeout, void *data)
 +{
-   int timeout;
-   int remaining;
++  char valuebuf[sizeof ("-XXXXXXXXXXX")];
++  char startbuf[sizeof ("-XXXXXXXXXXX")];
 +  char msgbuf[120];
++  struct grub_gfxmenu_view *view = data;
 +
-   int seconds_remaining_rounded_up;
 +  struct progress_value_data pv;
-   timeout = grub_gfxmenu_model_get_timeout_ms (view->model);
-   if (timeout > 0)
-     {
-       remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model);
-       seconds_remaining_rounded_up = (remaining + 999) / 1000;
-     }
-   else
-     {
-       seconds_remaining_rounded_up = -1;
-       remaining = -1;
-     }
 +
 +  auto void redraw_timeout_visit (grub_gui_component_t component,
 +                                void *userdata __attribute__ ((unused)));
 +
 +  auto void redraw_timeout_visit (grub_gui_component_t component,
 +                                void *userdata __attribute__ ((unused)))
 +  {
 +    grub_video_rect_t bounds;
 +    component->ops->get_bounds (component, &bounds);
 +    grub_gfxmenu_view_redraw (view, &bounds);
 +  }
 +
-   if (view->last_seconds_remaining == seconds_remaining_rounded_up && !is_init)
-     return;
-   view->last_seconds_remaining = seconds_remaining_rounded_up;
-   pv.visible = timeout > 0 ? "true" : "false";
-   grub_sprintf (startbuf, "%d", -timeout);
++  if (view->first_timeout == -1)
++    view->first_timeout = timeout;
 +
-   grub_sprintf (valuebuf, "%d", remaining > 0 ? -remaining : 0);
++  pv.visible = "true";
++  grub_sprintf (startbuf, "%d", -(view->first_timeout + 1));
 +  pv.start = startbuf;
 +  pv.end = "0";
-                 seconds_remaining_rounded_up);
++  grub_sprintf (valuebuf, "%d", -timeout);
 +  pv.value = valuebuf;
 +
 +  grub_sprintf (msgbuf,
 +                "The highlighted entry will be booted automatically in %d s.",
-   if (!is_init)
-     {
-       grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
-                          TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
-       grub_video_swap_buffers ();
-       if (view->double_repaint)
-       grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
-                            TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
-     }
++              timeout);
 +  pv.text = msgbuf;
 +
 +  grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
 +                       TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv);
- void
- grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view)
++  grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
++                     TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
++  grub_video_swap_buffers ();
++  if (view->double_repaint)
++    grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
++                       TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
 +}
 +
-   update_timeout (view, 0);
++void 
++grub_gfxmenu_clear_timeout (void *data)
 +{
-       list->ops->set_view_info (list, view->theme_path, view->model);
++  struct progress_value_data pv;
++  struct grub_gfxmenu_view *view = data;
++
++  auto void redraw_timeout_visit (grub_gui_component_t component,
++                                void *userdata __attribute__ ((unused)));
++
++  auto void redraw_timeout_visit (grub_gui_component_t component,
++                                void *userdata __attribute__ ((unused)))
++  {
++    grub_video_rect_t bounds;
++    component->ops->get_bounds (component, &bounds);
++    grub_gfxmenu_view_redraw (view, &bounds);
++  }
++
++  pv.visible = "false";
++  pv.start = "1";
++  pv.end = "0";
++  pv.value = "0";
++  pv.text = "";
++
++  grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
++                       TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv);
++  grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
++                     TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv);
++  grub_video_swap_buffers ();
++  if (view->double_repaint)
++    grub_gui_find_by_id ((grub_gui_component_t) view->canvas,
++                       TIMEOUT_COMPONENT_ID, redraw_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;
-   update_timeout (view, 1);
++      list->ops->set_view_info (list, view);
 +    }
 +}
 +
 +/* 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;
 +  grub_video_rect_t f = view->progress_message_frame;
 +  if (! text)
 +    return;
 +
 +  grub_font_t font = view->message_font;
 +  grub_video_color_t color = grub_gui_map_color (view->message_color);
 +
 +  /* 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_redraw (grub_gfxmenu_view_t view,
 +                        const grub_video_rect_t *region)
 +{
 +  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
 +
 +  redraw_background (view, region);
 +  if (view->canvas)
 +    view->canvas->ops->component.paint (view->canvas, region);
 +  draw_title (view);
 +  if (grub_video_have_common_points (&view->progress_message_frame, region))
 +    draw_message (view);
 +}
 +
 +void
 +grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
 +{
 +  update_menu_components (view);
 +
 +  grub_gfxmenu_view_redraw (view, &view->screen);
 +  grub_video_swap_buffers ();
 +  if (view->double_repaint)
 +    grub_gfxmenu_view_redraw (view, &view->screen);
 +}
 +
 +static void
 +redraw_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_video_rect_t bounds;
 +
 +      list = (grub_gui_list_t) component;
 +      component->ops->get_bounds (component, &bounds);
 +      grub_gfxmenu_view_redraw (view, &bounds);
 +    }
 +}
 +
 +void
 +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view)
 +{
 +  update_menu_components (view);
 +
 +  grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
 +                                redraw_menu_visit, view);
 +  grub_video_swap_buffers ();
 +  if (view->double_repaint)
 +    {
 +      grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
 +                                  redraw_menu_visit, view);
 +    }
 +}
 +
++void 
++grub_gfxmenu_set_chosen_entry (int entry, void *data)
++{
++  grub_gfxmenu_view_t view = data;
++
++  view->selected = entry;
++  grub_gfxmenu_redraw_menu (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 ();
 +}
 +
++/* FIXME */
++#if 0
 +static int term_target_width;
 +static int term_target_height;
 +static int term_initialized;
 +static grub_term_output_t term_original;
 +
 +static void
 +draw_terminal_box (grub_gfxmenu_view_t view)
 +{
 +  grub_gfxmenu_box_t term_box;
 +  int termx;
 +  int termy;
 +
 +  term_box = term_view->terminal_box;
 +  if (!term_box)
 +    return;
 +
 +  termx = term_view->screen.x + term_view->screen.width * (10 - 7) / 10 / 2;
 +  termy = term_view->screen.y + term_view->screen.height * (10 - 7) / 10 / 2;
 +  
 +  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_swap_buffers ();
 +  if (view->double_repaint)
 +    term_box->draw (term_box,
 +                  termx - term_box->get_left_pad (term_box),
 +                  termy - term_box->get_top_pad (term_box));
 +}
 +
 +static void
 +init_terminal (grub_gfxmenu_view_t view)
 +{
 +  int termx;
 +  int termy;
 +
 +  term_original = grub_term_get_current_output ();
 +
 +  term_target_width = view->screen.width * 7 / 10;
 +  term_target_height = view->screen.height * 7 / 10;
 +
 +  termx = view->screen.x + view->screen.width * (10 - 7) / 10 / 2;
 +  termy = view->screen.y + view->screen.height * (10 - 7) / 10 / 2;
 +
 +  /* 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 (GRUB_VIDEO_RENDER_TARGET_DISPLAY, termx, termy,
 +                            term_target_width, term_target_height,
 +                          view->double_repaint, view->terminal_font_name, 3);
 +  if (grub_errno != GRUB_ERR_NONE)
 +    return;
 +  term_initialized = 1;
 +
 +  term_view = view;
 +
 +  grub_term_set_current_output (grub_gfxterm_get_term ());
 +  grub_refresh ();
 +}
 +
 +static void destroy_terminal (void)
 +{
 +  if (term_initialized)
 +    grub_gfxterm_destroy_window ();
 +  if (term_original)
 +    grub_term_set_current_output (term_original);
 +}
 +
- int
- grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view,
-                                          grub_menu_entry_t entry)
- {
-   draw_terminal_box (view);
-   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);
-   while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ')
-     {
-       /* Wait for SPACE to be pressed.  */
-     }
-   set_progress_message (view, 0);   /* Clear the message.  */
-   grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
-   grub_video_swap_buffers ();
-   if (view->double_repaint)
-     grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
-   return 1;   /* Ok.  */
- }
- int
- grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view,
-                                  grub_menu_entry_t entry)
- {
-   draw_terminal_box (view);
-   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.  */
-   grub_gfxmenu_view_draw (view);
-   return 1;   /* Ok.  */
- }
- void
- grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view)
- {
-   draw_terminal_box (view);
-   grub_cmdline_run (1);
-   grub_gfxmenu_view_draw (view);
- }
 +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_redraw (view, &view->progress_message_frame);
 +  grub_video_swap_buffers ();
 +  if (view->double_repaint)
 +    grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 +}
 +
 +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_redraw (view, &view->progress_message_frame);
 +  grub_video_swap_buffers ();
 +  if (view->double_repaint)
 +    grub_gfxmenu_view_redraw (view, &view->progress_message_frame);
 +}
 +
 +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
 +};
 +
++#endif
index e5c7da3ace6d217a71dbb4080b354ad6aebe5e4f,0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
mode 100644,000000..100644
--- /dev/null
@@@ -1,59 -1,0 +1,1 @@@
- /* 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 */
 +
index c8633440091ef244573333b10f186eac6d6b347d,0000000000000000000000000000000000000000..92cedc6a7be8958195884ebcb94e99768304f694
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,116 @@@
- #include <grub/gfxmenu_model.h>
 +/* 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>
-                                            grub_gfxmenu_model_t model);
 +#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;
-   int last_seconds_remaining;
++                                           grub_menu_t menu, int entry,
++                                         int nested);
 +
 +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);
 +
 +void
 +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view);
 +
 +void
 +grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view);
 +
 +void
 +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view,
 +                        const grub_video_rect_t *region);
 +
++void 
++grub_gfxmenu_clear_timeout (void *data);
++void 
++grub_gfxmenu_print_timeout (int timeout, void *data);
++void
++grub_gfxmenu_set_chosen_entry (int entry, void *data);
++
 +/* 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;
 +
 +  int double_repaint;
 +
++  int selected;
++
 +  grub_video_rect_t progress_message_frame;
++
++  grub_menu_t menu;
++
++  int nested;
++
++  int first_timeout;
 +};
 +
 +#endif /* ! GRUB_GFXMENU_VIEW_HEADER */
index 385c0962be10fe319ae1b32682392b41fc6943b2,0000000000000000000000000000000000000000..605242da6df8d1d187ee74d929fd96f7ef85c26b
mode 100644,000000..100644
--- /dev/null
@@@ -1,179 -1,0 +1,178 @@@
- #include <grub/gfxmenu_model.h>
 +/* 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>
-                          const char *theme_path,
-                          grub_gfxmenu_model_t menu);
++#include <grub/gfxmenu_view.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, const grub_video_rect_t *bounds);
 +  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);
 +  void (*repaint) (void *self, int second_pass);
 +};
 +
 +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,
++                         grub_gfxmenu_view_t view);
 +};
 +
 +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);
 +}
 +
 +static inline int
 +grub_video_have_common_points (const grub_video_rect_t *a,
 +                             const grub_video_rect_t *b)
 +{
 +  if (!((a->x <= b->x && b->x <= a->x + a->width)
 +      || (b->x <= a->x && a->x <= b->x + b->width)))
 +    return 0;
 +  if (!((a->y <= b->y && b->y <= a->y + a->height)
 +      || (b->y <= a->y && a->y <= b->y + b->height)))
 +    return 0;
 +  return 1;
 +}
 +
 +#endif /* ! GRUB_GUI_H */
index cfe7e7cec2da06649a9ea9cbe3081e279d3c19cd,c7114a93b210ef04d452fc6a621a94b419ebe1c6..20a1fc47f03f01a9d4f2c16e48472d68fdfbae10
@@@ -83,6 -83,6 +83,9 @@@ typedef struct grub_menu_execute_callba
  }
  *grub_menu_execute_callback_t;
  
++extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
++                                          int nested);
++
  
  grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no);
  int grub_menu_get_timeout (void);
Simple merge
diff --cc kern/misc.c
Simple merge
diff --cc kern/term.c
index 8c4e1e33950a7f22713fc05963c8ab3777f57173,b76771d86e3741f00cac6ceaabdc4fdc72c02e4f..b973f0b6394bb8c3f3c275be7b1fde1399a94872
@@@ -131,8 -77,19 +77,21 @@@ grub_putchar (int c
  int
  grub_getkey (void)
  {
-   return (grub_cur_term_input->getkey) ();
+   grub_term_input_t term;
 +  grub_refresh ();
++
+   while (1)
+     {
+       FOR_ACTIVE_TERM_INPUTS(term)
+       {
+       int key = term->checkkey ();
+       if (key != -1)
+         return term->getkey ();
+       }
+       grub_cpu_idle ();
+     }
  }
  
  int
Simple merge
index a4cb6681fc25a4c598515beec153d115420f3990,3521c3cbd6eea51e74a9fce2afeac12fe30ac575..a3c7a28ec48baffba022981d38acd292f42f2fc0
@@@ -266,166 -352,217 +352,219 @@@ grub_cmdline_get (const char *prompt
    lpos = llen = 0;
    buf[0] = '\0';
  
-   if ((grub_getxy () >> 8) != 0)
-     grub_putchar ('\n');
+   {
+     grub_term_output_t term;
  
+     FOR_ACTIVE_TERM_OUTPUTS(term)
+       if ((grub_term_getxy (term) >> 8) != 0)
+       grub_putcode ('\n', term);
+   }
    grub_printf ("%s", prompt_translated);
  
-   xpos = plen;
-   ystart = ypos = (grub_getxy () & 0xFF);
-   cl_insert (cmdline);
+   {
+     struct cmdline_term *cl_term_cur;
+     struct grub_term_output *cur;
+     nterms = 0;
+     FOR_ACTIVE_TERM_OUTPUTS(cur)
+       nterms++;
+     cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms);
+     if (!cl_terms)
+       return 0;
+     cl_term_cur = cl_terms;
+     FOR_ACTIVE_TERM_OUTPUTS(cur)
+     {
+       cl_term_cur->term = cur;
+       init_clterm (cl_term_cur);
+       cl_term_cur++;
+     }
+   }
  
-   if (history && hist_used == 0)
-     grub_history_add (buf);
+   if (hist_used == 0)
+     grub_history_add (buf, llen);
  
 +  grub_refresh ();
 +
    while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r')
      {
-       if (readline)
+       switch (key)
        {
-         switch (key)
+       case 1: /* Ctrl-a */
+         lpos = 0;
+         cl_set_pos_all ();
+         break;
+       case 2: /* Ctrl-b */
+         if (lpos > 0)
            {
-           case 1:     /* Ctrl-a */
-             lpos = 0;
-             cl_set_pos ();
-             break;
+             lpos--;
+             cl_set_pos_all ();
+           }
+         break;
  
-           case 2:     /* Ctrl-b */
-             if (lpos > 0)
-               {
-                 lpos--;
-                 cl_set_pos ();
-               }
-             break;
+       case 5: /* Ctrl-e */
+         lpos = llen;
+         cl_set_pos_all ();
+         break;
+       case 6: /* Ctrl-f */
+         if (lpos < llen)
+           {
+             lpos++;
+             cl_set_pos_all ();
+           }
+         break;
  
-           case 5:     /* Ctrl-e */
-             lpos = llen;
-             cl_set_pos ();
-             break;
+       case 9: /* Ctrl-i or TAB */
+         {
+           int restore;
+           char *insertu8;
+           char *bufu8;
  
-           case 6:     /* Ctrl-f */
-             if (lpos < llen)
-               {
-                 lpos++;
-                 cl_set_pos ();
-               }
-             break;
+           buf[lpos] = '\0';
  
-           case 9:     /* Ctrl-i or TAB */
+           bufu8 = grub_ucs4_to_utf8_alloc (buf, lpos);
+           if (!bufu8)
              {
-               char *insert;
-               int restore;
+               grub_print_error ();
+               grub_errno = GRUB_ERR_NONE;
+               break;
+             }
  
-               /* Backup the next character and make it 0 so it will
-                  be easy to use string functions.  */
-               char backup = buf[lpos];
-               buf[lpos] = '\0';
+           insertu8 = grub_normal_do_completion (bufu8, &restore,
+                                                 print_completion);
+           grub_free (bufu8);
  
+           if (restore)
+             {
+               /* Restore the prompt.  */
+               grub_printf ("\n%s", prompt_translated);
+               init_clterm_all ();
+               cl_print_all (0, 0);
+             }
  
-               insert = grub_normal_do_completion (buf, &restore,
-                                                   print_completion);
-               /* Restore the original string.  */
-               buf[lpos] = backup;
+           if (insertu8)
+             {
+               grub_size_t insertlen;
+               grub_ssize_t t;
+               grub_uint32_t *insert;
  
-               if (restore)
+               insertlen = grub_strlen (insertu8);
+               insert = grub_malloc ((insertlen + 1) * sizeof (grub_uint32_t));
+               if (!insert)
                  {
-                   /* Restore the prompt.  */
-                   grub_printf ("\n%s %s", prompt_translated, buf);
-                   xpos = plen;
-                   ystart = ypos = (grub_getxy () & 0xFF);
+                   grub_free (insertu8);
+                   grub_print_error ();
+                   grub_errno = GRUB_ERR_NONE;
+                   break;
                  }
-               if (insert)
+               t = grub_utf8_to_ucs4 (insert, insertlen,
+                                      (grub_uint8_t *) insertu8,
+                                      insertlen, 0);
+               if (t > 0)
                  {
+                   insert[t] = 0;
                    cl_insert (insert);
-                   grub_free (insert);
                  }
+               grub_free (insertu8);
+               grub_free (insert);
              }
-             break;
+         }
+         break;
  
-           case 11:    /* Ctrl-k */
-             if (lpos < llen)
-               {
-                 if (kill_buf)
-                   grub_free (kill_buf);
+       case 11:        /* Ctrl-k */
+         if (lpos < llen)
+           {
+             if (kill_buf)
+               grub_free (kill_buf);
  
-                 kill_buf = grub_strdup (buf + lpos);
+             kill_buf = grub_malloc ((llen - lpos + 1)
+                                     * sizeof (grub_uint32_t));
+             if (grub_errno)
+               {
+                 grub_print_error ();
                  grub_errno = GRUB_ERR_NONE;
-                 cl_delete (llen - lpos);
                }
-             break;
-           case 14:    /* Ctrl-n */
-             {
-               char *hist;
+             else
+               {
+                 grub_memcpy (kill_buf, buf + lpos,
+                              (llen - lpos + 1) * sizeof (grub_uint32_t));
+                 kill_buf[llen - lpos] = 0;
+               }
  
-               lpos = 0;
+             cl_delete (llen - lpos);
+           }
+         break;
  
-               if (histpos > 0)
-                 {
-                   grub_history_replace (histpos, buf);
-                   histpos--;
-                 }
+       case 14:        /* Ctrl-n */
+         {
+           grub_uint32_t *hist;
  
-               cl_delete (llen);
-               hist = grub_history_get (histpos);
-               cl_insert (hist);
+           lpos = 0;
  
-               break;
-             }
-           case 16:    /* Ctrl-p */
+           if (histpos > 0)
              {
-               char *hist;
+               grub_history_replace (histpos, buf, llen);
+               histpos--;
+             }
  
-               lpos = 0;
+           cl_delete (llen);
+           hist = grub_history_get (histpos);
+           cl_insert (hist);
  
-               if (histpos < hist_used - 1)
-                 {
-                   grub_history_replace (histpos, buf);
-                   histpos++;
-                 }
+           break;
+         }
+       case 16:        /* Ctrl-p */
+         {
+           grub_uint32_t *hist;
  
-               cl_delete (llen);
-               hist = grub_history_get (histpos);
+           lpos = 0;
  
-               cl_insert (hist);
+           if (histpos < hist_used - 1)
+             {
+               grub_history_replace (histpos, buf, llen);
+               histpos++;
              }
-             break;
  
-           case 21:    /* Ctrl-u */
-             if (lpos > 0)
-               {
-                 grub_size_t n = lpos;
+           cl_delete (llen);
+           hist = grub_history_get (histpos);
  
-                 if (kill_buf)
-                   grub_free (kill_buf);
+           cl_insert (hist);
+         }
+         break;
  
-                 kill_buf = grub_malloc (n + 1);
+       case 21:        /* Ctrl-u */
+         if (lpos > 0)
+           {
+             grub_size_t n = lpos;
+             if (kill_buf)
+               grub_free (kill_buf);
+             kill_buf = grub_malloc (n + 1);
+             if (grub_errno)
+               {
+                 grub_print_error ();
                  grub_errno = GRUB_ERR_NONE;
-                 if (kill_buf)
-                   {
-                     grub_memcpy (kill_buf, buf, n);
-                     kill_buf[n] = '\0';
-                   }
-                 lpos = 0;
-                 cl_set_pos ();
-                 cl_delete (n);
                }
-             break;
-           case 25:    /* Ctrl-y */
              if (kill_buf)
-               cl_insert (kill_buf);
-             break;
+               {
+                 grub_memcpy (kill_buf, buf, n);
+                 kill_buf[n] = '\0';
+               }
+             lpos = 0;
+             cl_set_pos_all ();
+             cl_delete (n);
            }
-       }
+         break;
+       case 25:        /* Ctrl-y */
+         if (kill_buf)
+           cl_insert (kill_buf);
+         break;
  
-       switch (key)
-       {
        case '\e':
          return 0;
  
diff --cc normal/menu.c
index 282dddae5f9a1d133bd2f03a6d6c382716a32d61,62f33b61bc026c5ae9939d9367b578373222b17e..d671cc9fd20dbd54e292a6449e7e0bded4a16905
@@@ -181,9 -203,77 +205,89 @@@ grub_menu_execute_with_fallback (grub_m
    callback->notify_failure (callback_data);
  }
  
+ static struct grub_menu_viewer *viewers;
+ static void
+ menu_set_chosen_entry (int entry)
+ {
+   struct grub_menu_viewer *cur;
+   for (cur = viewers; cur; cur = cur->next)
+     cur->set_chosen_entry (entry, cur->data);
+ }
+ static void
+ menu_print_timeout (int timeout)
+ {
+   struct grub_menu_viewer *cur;
+   for (cur = viewers; cur; cur = cur->next)
+     cur->print_timeout (timeout, cur->data);
+ }
+ static void
+ menu_fini (void)
+ {
+   struct grub_menu_viewer *cur, *next;
+   for (cur = viewers; cur; cur = next)
+     {
+       next = cur->next;
+       cur->fini (cur->data);
+       grub_free (cur);
+     }
+   viewers = NULL;
+ }
++/* FIXME: allow text menu in parallel with gfxmenu.  */
++grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
++                                   int nested) = NULL;
+ static void
+ menu_init (int entry, grub_menu_t menu, int nested)
+ {
+   struct menu_run_callback *cb;
++
++  if (grub_gfxmenu_try_hook)
++    {
++      if(!grub_gfxmenu_try_hook (entry, menu, nested))
++      return;
++      grub_print_error ();
++      grub_errno = GRUB_ERR_NONE;
++    }
++
+   for (cb = callbacks; cb; cb = cb->next)
+     cb->hook (entry, menu, nested);
+ }
+ static void
+ clear_timeout (void)
+ {
+   struct grub_menu_viewer *cur;
+   for (cur = viewers; cur; cur = cur->next)
+     cur->clear_timeout (cur->data);
+ }
+ void
+ grub_menu_register_viewer (struct grub_menu_viewer *viewer)
+ {
+   viewer->next = viewers;
+   viewers = viewer;
+ }
+ grub_err_t
+ grub_menu_register_viewer_init (void (*callback) (int entry, grub_menu_t menu,
+                                                 int nested))
+ {
+   struct menu_run_callback *cb;
+   cb = grub_malloc (sizeof (*cb));
+   if (!cb)
+     return grub_errno;
+   cb->hook = callback;
+   cb->next = callbacks;
+   callbacks = cb;
+   return GRUB_ERR_NONE;
+ }
  /* Get the entry number from the variable NAME.  */
  static int
 -get_entry_number (const char *name)
 +get_entry_number (grub_menu_t menu, const char *name)
  {
    char *val;
    int entry;
    return entry;
  }
  
- int
- grub_menu_get_default_entry_index (grub_menu_t menu)
+ #define GRUB_MENU_PAGE_SIZE 10
+ /* Show the menu and handle menu entry selection.  Returns the menu entry
+    index that should be executed or -1 if no entry should be executed (e.g.,
+    Esc pressed to exit a sub-menu or switching menu viewers).
+    If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
+    entry to be executed is a result of an automatic default selection because
+    of the timeout.  */
+ static int
+ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+ {
+   grub_uint64_t saved_time;
+   int default_entry, current_entry;
+   int timeout;
 -  default_entry = get_entry_number ("default");
++  default_entry = get_entry_number (menu, "default");
+   /* If DEFAULT_ENTRY is not within the menu entries, fall back to
+      the first entry.  */
+   if (default_entry < 0 || default_entry >= menu->size)
+     default_entry = 0;
+   /* If timeout is 0, drawing is pointless (and ugly).  */
+   if (grub_menu_get_timeout () == 0)
+     {
+       *auto_boot = 1;
+       return default_entry;
+     }
+   current_entry = default_entry;
+   /* Initialize the time.  */
+   saved_time = grub_get_time_ms ();
+  refresh:
+   menu_init (current_entry, menu, nested);
+   timeout = grub_menu_get_timeout ();
+   if (timeout > 0)
+     menu_print_timeout (timeout);
+   while (1)
+     {
+       int c;
+       timeout = grub_menu_get_timeout ();
+       if (grub_normal_exit_level)
+       return -1;
+       if (timeout > 0)
+       {
+         grub_uint64_t current_time;
+         current_time = grub_get_time_ms ();
+         if (current_time - saved_time >= 1000)
+           {
+             timeout--;
+             grub_menu_set_timeout (timeout);
+             saved_time = current_time;
+             menu_print_timeout (timeout);
+           }
+       }
+       if (timeout == 0)
+       {
+         grub_env_unset ("timeout");
+           *auto_boot = 1;
+         menu_fini ();
+         return default_entry;
+       }
+       if (grub_checkkey () >= 0 || timeout < 0)
+       {
+         c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
+         if (timeout >= 0)
+           {
+             grub_env_unset ("timeout");
+             grub_env_unset ("fallback");
+             clear_timeout ();
+           }
+         switch (c)
+           {
+           case GRUB_TERM_HOME:
+             current_entry = 0;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case GRUB_TERM_END:
+             current_entry = menu->size - 1;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case GRUB_TERM_UP:
+           case '^':
+             if (current_entry > 0)
+               current_entry--;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case GRUB_TERM_DOWN:
+           case 'v':
+             if (current_entry < menu->size - 1)
+               current_entry++;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case GRUB_TERM_PPAGE:
+             if (current_entry < GRUB_MENU_PAGE_SIZE)
+               current_entry = 0;
+             else
+               current_entry -= GRUB_MENU_PAGE_SIZE;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case GRUB_TERM_NPAGE:
+             if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
+               current_entry += GRUB_MENU_PAGE_SIZE;
+             else
+               current_entry = menu->size - 1;
+             menu_set_chosen_entry (current_entry);
+             break;
+           case '\n':
+           case '\r':
+           case 6:
+             menu_fini ();
+               *auto_boot = 0;
+             return current_entry;
+           case '\e':
+             if (nested)
+               {
+                 menu_fini ();
+                 return -1;
+               }
+             break;
+           case 'c':
+             menu_fini ();
+             grub_cmdline_run (1);
+             goto refresh;
+           case 'e':
+             menu_fini ();
+               {
+                 grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
+                 if (e)
+                   grub_menu_entry_run (e);
+               }
+             goto refresh;
+           default:
+             break;
+           }
+       }
+     }
+   /* Never reach here.  */
+   return -1;
+ }
+ /* Callback invoked immediately before a menu entry is executed.  */
+ static void
+ notify_booting (grub_menu_entry_t entry,
+               void *userdata __attribute__((unused)))
+ {
+   grub_printf ("  ");
+   grub_printf_ (N_("Booting \'%s\'"), entry->title);
+   grub_printf ("\n\n");
+ }
+ /* Callback invoked when a default menu entry executed because of a timeout
+    has failed and an attempt will be made to execute the next fallback
+    entry, ENTRY.  */
+ static void
+ notify_fallback (grub_menu_entry_t entry,
+                void *userdata __attribute__((unused)))
  {
-   return get_entry_number (menu, "default");
+   grub_printf ("\n   ");
+   grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
+   grub_printf ("\n\n");
+   grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
+ }
+ /* Callback invoked when a menu entry has failed and there is no remaining
+    fallback entry to attempt.  */
+ static void
+ notify_execution_failure (void *userdata __attribute__((unused)))
+ {
+   if (grub_errno != GRUB_ERR_NONE)
+     {
+       grub_print_error ();
+       grub_errno = GRUB_ERR_NONE;
+     }
+   grub_printf ("\n  ");
+   grub_printf_ (N_("Failed to boot default entries.\n"));
+   grub_wait_after_message ();
+ }
+ /* Callbacks used by the text menu to provide user feedback when menu entries
+    are executed.  */
+ static struct grub_menu_execute_callback execution_callback =
+ {
+   .notify_booting = notify_booting,
+   .notify_fallback = notify_fallback,
+   .notify_failure = notify_execution_failure
+ };
+ static grub_err_t
+ show_menu (grub_menu_t menu, int nested)
+ {
+   while (1)
+     {
+       int boot_entry;
+       grub_menu_entry_t e;
+       int auto_boot;
+       boot_entry = run_menu (menu, nested, &auto_boot);
+       if (boot_entry < 0)
+       break;
+       e = grub_menu_get_entry (menu, boot_entry);
+       if (! e)
+       continue; /* Menu is empty.  */
+       grub_cls ();
+       if (auto_boot)
+         {
+           grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
+         }
+       else
+         {
+           grub_errno = GRUB_ERR_NONE;
+           grub_menu_execute_entry (e);
+           if (grub_errno != GRUB_ERR_NONE)
+             {
+               grub_print_error ();
+               grub_errno = GRUB_ERR_NONE;
+               grub_wait_after_message ();
+             }
+         }
+     }
+   return GRUB_ERR_NONE;
+ }
+ grub_err_t
+ grub_show_menu (grub_menu_t menu, int nested)
+ {
+   grub_err_t err1, err2;
+   while (1)
+     {
+       err1 = show_menu (menu, nested);
+       grub_print_error ();
+       if (grub_normal_exit_level)
+       break;
+       err2 = grub_auth_check_authentication (NULL);
+       if (err2)
+       {
+         grub_print_error ();
+         grub_errno = GRUB_ERR_NONE;
+         continue;
+       }
+       break;
+     }
+   return err1;
  }
index 7a547a764b8fd7a95f9dea9837277e35b381577e,b600e75007a919f8b756d419e7b157460dfcb4b6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
@@@ -1,112 -1,26 +1,0 @@@
--/*
-- *  GRUB  --  GRand Unified Bootloader
-- *  Copyright (C) 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/env.h>
--#include <grub/menu_viewer.h>
--#include <grub/menu.h>
--#include <grub/auth.h>
- /* The list of menu viewers.  */
- static grub_menu_viewer_t menu_viewer_list;
- static int should_return;
- static int menu_viewer_changed;
- void
- grub_menu_viewer_register (grub_menu_viewer_t viewer)
- {
-   viewer->next = menu_viewer_list;
-   menu_viewer_list = viewer;
- }
- static grub_menu_viewer_t get_current_menu_viewer (void)
- {
-   const char *selected_name = grub_env_get ("menuviewer");
-   /* If none selected, pick the last registered one. */
-   if (selected_name == 0)
-     return menu_viewer_list;
-   grub_menu_viewer_t cur;
-   for (cur = menu_viewer_list; cur; cur = cur->next)
-     {
-       if (grub_strcmp (cur->name, selected_name) == 0)
-         return cur;
-     }
-   /* Fall back to the first entry (or null).  */
-   return menu_viewer_list;
- }
- grub_err_t
- grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
- {
-   grub_err_t err1, err2;
-   while (1)
-     {
-       grub_menu_viewer_t cur = get_current_menu_viewer ();
-       if (!cur)
-       return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
-       menu_viewer_changed = 0;
-       should_return = 0;
-       err1 = cur->show_menu (menu, nested);
-       grub_print_error ();
-       if (menu_viewer_changed)
-       continue;
-       err2 = grub_auth_check_authentication (NULL);
-       if (err2)
-       {
-         grub_print_error ();
-         grub_errno = GRUB_ERR_NONE;
-         continue;
-       }
-       break;
-     }
-   return err1;
- }
- int
- grub_menu_viewer_should_return (void)
- {
-   return should_return;
- }
- static char *
- menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)),
-                        const char *val)
- {
-   menu_viewer_changed = 1;
-   should_return = 1;
-   return grub_strdup (val);
- }
--
- void
- grub_menu_viewer_init (void)
- {
-   grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook);
- }
--