# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: colin@gibibit.com-20080711163832-cutvrahspirds0fw
# target_branch: http://grub.gibibit.com/bzr/trunk-clean
# testament_sha1: 25c6cfc2b182753473e3e2647dd4a223f17a28ec
# timestamp: 2008-07-11 10:10:07 -0700
# source_branch: http://grub.gibibit.com/bzr/trunk-clean
# base_revision_id: colin@gibibit.com-20080711163747-7v43uh66u2lp4mb7
# 
# Begin patch
=== modified file 'commands/videotest.c'
--- commands/videotest.c	2008-07-09 16:14:04 +0000
+++ commands/videotest.c	2008-07-09 16:52:26 +0000
@@ -49,19 +49,6 @@
   int double_buffering;
 };
 
-/* A 2D rectangle type.
- * This could be worth integrating into the video API if it proves useful.*/
-struct grub_video_rect
-{
-  /* These are signed because if there are unsigned it causes Bad Things 
-   * to happen when arithmetic and comparisions involving signed types is 
-   * done.  Important signed types include offsets from absolute locations. */
-  int x;
-  int y;
-  int width;
-  int height;
-};
-typedef struct grub_video_rect grub_video_rect_t;
 
 static void
 basic_video_test (struct videotest_options *vt_opts)

=== modified file 'conf/common.rmk'
--- conf/common.rmk	2008-07-03 14:12:08 +0000
+++ conf/common.rmk	2008-07-07 15:07:13 +0000
@@ -287,6 +287,7 @@
 	cmp.mod cat.mod help.mod font.mod search.mod		\
 	loopback.mod fs_uuid.mod configfile.mod echo.mod	\
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
+	protomenu.mod                                           \
 	read.mod sleep.mod loadenv.mod
 
 # For hello.mod.
@@ -374,6 +375,11 @@
 hexdump_mod_CFLAGS = $(COMMON_CFLAGS)
 hexdump_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For protomenu.mod.
+protomenu_mod_SOURCES = protomenu/protomenu.c protomenu/widget-box.c
+protomenu_mod_CFLAGS = $(COMMON_CFLAGS)
+protomenu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For read.mod.
 read_mod_SOURCES = commands/read.c
 read_mod_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk	2008-07-03 14:27:43 +0000
+++ conf/i386-pc.rmk	2008-07-10 13:55:34 +0000
@@ -46,11 +46,13 @@
 	kern/i386/tsc.c \
 	kern/generic/millisleep.c \
 	kern/env.c \
+	kern/menu_viewer.c \
 	term/i386/pc/console.c \
 	symlist.c
 kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
+	menu_viewer.h \
 	machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \
 	machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h
 kernel_img_CFLAGS = $(COMMON_CFLAGS)

=== added file 'include/grub/menu.h'
--- include/grub/menu.h	1970-01-01 00:00:00 +0000
+++ include/grub/menu.h	2008-07-10 13:55:34 +0000
@@ -0,0 +1,51 @@
+/* menu.h - menu and menu entry model declarations. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MENU_HEADER
+#define GRUB_MENU_HEADER 1
+
+/* The menu entry.  */
+struct grub_menu_entry
+{
+  /* The title name.  */
+  const char *title;
+
+    /* The commands associated with this menu entry.  */
+  struct grub_script *commands;
+
+  /* The sourcecode of the menu entry, used by the editor.  */
+  const char *sourcecode;
+
+  /* The next element.  */
+  struct grub_menu_entry *next;
+};
+typedef struct grub_menu_entry *grub_menu_entry_t;
+
+/* The menu.  */
+struct grub_menu
+{
+  /* The size of a menu.  */
+  int size;
+
+  /* The list of menu entries.  */
+  grub_menu_entry_t entry_list;
+};
+typedef struct grub_menu *grub_menu_t;
+
+#endif /* GRUB_MENU_HEADER */

=== added file 'include/grub/menu_viewer.h'
--- include/grub/menu_viewer.h	1970-01-01 00:00:00 +0000
+++ include/grub/menu_viewer.h	2008-07-11 14:56:59 +0000
@@ -0,0 +1,48 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MENU_VIEWER_HEADER
+#define GRUB_MENU_VIEWER_HEADER 1
+
+#include <grub/err.h>
+#include <grub/symbol.h>
+#include <grub/types.h>
+#include <grub/menu.h>
+
+struct grub_menu_viewer
+{
+  /* The menu viewer name.  */
+  const char *name;
+
+  grub_err_t (*show_menu) (grub_menu_t menu, int nested);
+
+  struct grub_menu_viewer *next;
+};
+typedef struct grub_menu_viewer *grub_menu_viewer_t;
+
+void EXPORT_FUNC(grub_menu_viewer_init) (void);
+
+void EXPORT_FUNC(grub_menu_viewer_register) (grub_menu_viewer_t viewer);
+
+grub_err_t EXPORT_FUNC(grub_menu_viewer_show_menu) (grub_menu_t menu, int nested);
+
+/* Return nonzero iff the menu viewer should clean up and return ASAP. */
+int EXPORT_FUNC(grub_menu_viewer_should_return) (void);
+
+#endif /* GRUB_MENU_VIEWER_HEADER */
+

=== modified file 'include/grub/normal.h'
--- include/grub/normal.h	2008-03-26 12:01:02 +0000
+++ include/grub/normal.h	2008-07-11 16:03:24 +0000
@@ -25,6 +25,7 @@
 #include <grub/err.h>
 #include <grub/arg.h>
 #include <grub/env.h>
+#include <grub/menu.h>
 
 /* The maximum size of a command-line.  */
 #define GRUB_MAX_CMDLINE	1600
@@ -84,34 +85,6 @@
 };
 typedef struct grub_command *grub_command_t;
 
-/* The menu entry.  */
-struct grub_menu_entry
-{
-  /* The title name.  */
-  const char *title;
-
-    /* The commands associated with this menu entry.  */
-  struct grub_script *commands;
-
-  /* The sourcecode of the menu entry, used by the editor.  */
-  const char *sourcecode;
-
-  /* The next element.  */
-  struct grub_menu_entry *next;
-};
-typedef struct grub_menu_entry *grub_menu_entry_t;
-
-/* The menu.  */
-struct grub_menu
-{
-  /* The size of a menu.  */
-  int size;
-
-  /* The list of menu entries.  */
-  grub_menu_entry_t entry_list;
-};
-typedef struct grub_menu *grub_menu_t;
-
 /* This is used to store the names of filesystem modules for auto-loading.  */
 struct grub_fs_module_list
 {
@@ -123,10 +96,12 @@
 /* To exit from the normal mode.  */
 extern grub_jmp_buf grub_exit_env;
 
+extern struct grub_menu_viewer grub_normal_terminal_menu_viewer;
+
 void grub_enter_normal_mode (const char *config);
 void grub_normal_execute (const char *config, int nested);
-void grub_menu_run (grub_menu_t menu, int nested);
 void grub_menu_entry_run (grub_menu_entry_t entry);
+void grub_menu_execute_entry(grub_menu_entry_t entry);
 void grub_cmdline_run (int nested);
 int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
 		      int echo_char, int readline);

=== added file 'include/grub/proto_widgets.h'
--- include/grub/proto_widgets.h	1970-01-01 00:00:00 +0000
+++ include/grub/proto_widgets.h	2008-07-08 13:59:48 +0000
@@ -0,0 +1,48 @@
+/* proto_widgets.h - Widgets for the graphical menu prototype.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_PROTO_WIDGETS_HEADER
+#define GRUB_PROTO_WIDGETS_HEADER 1
+
+#include <grub/video.h>
+
+typedef struct grub_protomenu_widgets_box
+{
+  /* The size of the content.  */
+  int width;
+  int height;
+
+  struct grub_video_bitmap **raw_pixmaps;
+  struct grub_video_bitmap **scaled_pixmaps;
+
+  void (*draw) (struct grub_protomenu_widgets_box *self, int x, int y);
+  void (*set_content_size) (struct grub_protomenu_widgets_box *self,
+                            int width, int height);
+  int (*get_left_pad) (struct grub_protomenu_widgets_box *self);
+  int (*get_top_pad) (struct grub_protomenu_widgets_box *self);
+  void (*destroy) (struct grub_protomenu_widgets_box *self);
+}
+*grub_protomenu_widgets_box_t;
+
+grub_protomenu_widgets_box_t
+grub_protomenu_widgets_create_box (const char *pixmaps_prefix,
+                                   const char *pixmaps_suffix);
+
+#endif /* ! GRUB_PROTO_WIDGETS_HEADER */
+

=== modified file 'include/grub/video.h'
--- include/grub/video.h	2008-07-03 14:12:08 +0000
+++ include/grub/video.h	2008-07-07 15:07:13 +0000
@@ -151,6 +151,16 @@
   grub_uint8_t a; /* Reserved bits value (0-255).  */
 };
 
+/* A 2D rectangle type.  */
+struct grub_video_rect
+{
+  int x;
+  int y;
+  int width;
+  int height;
+};
+typedef struct grub_video_rect grub_video_rect_t;
+
 struct grub_video_adapter
 {
   /* The video adapter name.  */

=== added file 'kern/menu_viewer.c'
--- kern/menu_viewer.c	1970-01-01 00:00:00 +0000
+++ kern/menu_viewer.c	2008-07-11 14:56:59 +0000
@@ -0,0 +1,99 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007  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>
+
+/* 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 err;
+  int repeat = 0;
+  do
+    {
+      repeat = 0;
+      menu_viewer_changed = 0;
+      grub_menu_viewer_t cur = get_current_menu_viewer ();
+      if (!cur) 
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
+
+      should_return = 0;
+      err = cur->show_menu (menu, nested);
+      if (menu_viewer_changed)
+        repeat = 1;
+    }
+  while (repeat);
+  return err;
+}
+
+int
+grub_menu_viewer_should_return (void)
+{
+  return should_return;
+}
+
+static char *
+menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)),
+                       const char *val)
+{
+  menu_viewer_changed = 1;
+  should_return = 1;
+  return grub_strdup (val);
+}
+
+void
+grub_menu_viewer_init (void)
+{
+  grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook);
+}
+

=== modified file 'normal/main.c'
--- normal/main.c	2008-02-02 16:48:52 +0000
+++ normal/main.c	2008-07-11 14:56:59 +0000
@@ -28,6 +28,7 @@
 #include <grub/env.h>
 #include <grub/parser.h>
 #include <grub/script.h>
+#include <grub/menu_viewer.h>
 
 grub_jmp_buf grub_exit_env;
 
@@ -476,7 +477,7 @@
 
   if (menu && menu->size)
     {
-      grub_menu_run (menu, nested);
+      grub_menu_viewer_show_menu (menu, nested);
       if (nested)
 	free_menu (menu);
     }
@@ -519,6 +520,8 @@
   if (mod)
     grub_dl_ref (mod);
 
+  grub_menu_viewer_register (&grub_normal_terminal_menu_viewer);
+
   grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
 
   /* Register a command "normal" for the rescue mode.  */
@@ -535,6 +538,8 @@
 
   /* This registers some built-in commands.  */
   grub_command_init ();
+
+  grub_menu_viewer_init ();
 }
 
 GRUB_MOD_FINI(normal)

=== modified file 'normal/menu.c'
--- normal/menu.c	2008-02-09 11:00:19 +0000
+++ normal/menu.c	2008-07-11 16:03:24 +0000
@@ -24,6 +24,7 @@
 #include <grub/machine/time.h>
 #include <grub/env.h>
 #include <grub/script.h>
+#include <grub/menu_viewer.h>
 
 static grub_uint8_t grub_color_menu_normal;
 static grub_uint8_t grub_color_menu_highlight;
@@ -364,7 +365,7 @@
   if (timeout > 0)
     print_timeout (timeout, offset, 0);
 
-  while (1)
+  while (!grub_menu_viewer_should_return ())
     {
       int c;
       timeout = get_timeout ();
@@ -468,6 +469,10 @@
 		}
 	      goto refresh;
 	      
+	    case 't':
+	      grub_env_set ("menuviewer", "protomenu");
+	      goto refresh;
+
 	    default:
 	      break;
 	    }
@@ -476,13 +481,14 @@
 	}
     }
 
-  /* Never reach here.  */
+  /* Exit menu without activating an item.  This occurs if the user presses
+   * 't', switching to the graphical menu viewer.  */
   return -1;
 }
 
 /* Run a menu entry.  */
-static void
-run_menu_entry (grub_menu_entry_t entry)
+void
+grub_menu_execute_entry(grub_menu_entry_t entry)
 {
   grub_script_execute (entry->commands);
   
@@ -491,8 +497,8 @@
     grub_command_execute ("boot", 0);
 }
 
-void
-grub_menu_run (grub_menu_t menu, int nested)
+static grub_err_t
+show_menu (grub_menu_t menu, int nested)
 {
   while (1)
     {
@@ -513,7 +519,7 @@
 
       grub_printf ("  Booting \'%s\'\n\n", e->title);
   
-      run_menu_entry (e);
+      grub_menu_execute_entry (e);
 
       /* Deal with a fallback entry.  */
       /* FIXME: Multiple fallback entries like GRUB Legacy.  */
@@ -526,7 +532,7 @@
 	  e = get_entry (menu, fallback_entry);
 	  grub_env_unset ("fallback");
 	  grub_printf ("\n  Falling back to \'%s\'\n\n", e->title);
-	  run_menu_entry (e);
+	  grub_menu_execute_entry (e);
 	}
 
       if (grub_errno != GRUB_ERR_NONE)
@@ -537,4 +543,14 @@
 	  grub_wait_after_message ();
 	}
     }
+
+  return GRUB_ERR_NONE;
 }
+
+struct grub_menu_viewer grub_normal_terminal_menu_viewer =
+{
+  .name = "terminal",
+  .show_menu = show_menu
+};
+
+

=== added directory 'protomenu'
=== added file 'protomenu/protomenu.c'
--- protomenu/protomenu.c	1970-01-01 00:00:00 +0000
+++ protomenu/protomenu.c	2008-07-11 16:03:24 +0000
@@ -0,0 +1,417 @@
+/* protomenu.c - Prototype graphical menu: command implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/term.h>
+#include <grub/proto_widgets.h>
+#include <grub/menu.h>
+#include <grub/menu_viewer.h>
+
+typedef struct menu_item
+{
+  const char *name;
+  struct grub_video_bitmap *icon;
+  grub_menu_entry_t entry;
+}
+menu_item_t;
+
+static const int icon_width = 48;
+static const int icon_height = 48;
+static grub_video_rect_t screen;
+static grub_font_t title_font;
+static grub_font_t item_font;
+static grub_font_t status_font;
+static grub_video_color_t title_color;
+static grub_video_color_t item_color;
+static grub_video_color_t status_color;
+static grub_video_color_t status_bg_color;
+static struct grub_video_bitmap *background_image;
+static const char title_text[] = "GRUB 2 Boot Menu";
+static int num_items;
+static menu_item_t *items;
+static int selected_item_index;
+static grub_protomenu_widgets_box_t menu_box;
+static grub_protomenu_widgets_box_t selected_item_box;
+
+static grub_err_t
+menu_init (grub_menu_t menu)
+{
+  num_items = menu->size;
+  if (num_items < 1)
+    return grub_error (GRUB_ERR_MENU, "Empty menu");
+
+  items = grub_malloc (num_items * sizeof (*items));
+  if (!items)
+    return grub_errno;
+
+  int i;
+  grub_menu_entry_t cur;
+  for (i = 0, cur = menu->entry_list; i < num_items; i++, cur = cur->next)
+    {
+        items[i].name = cur->title;
+        items[i].icon = 0;  /* TODO match w/ patterns to choose an icon */
+        items[i].entry = cur;
+    }
+
+  /*
+  items[0].name = "Ubuntu 8.10";
+  grub_video_bitmap_load (&img, "/boot/images/icon-ubuntu.tga");
+  if (grub_errno == GRUB_ERR_NONE)
+    {
+      grub_video_bitmap_create_scaled (&items[0].icon, icon_width,
+                                       icon_height, img,
+                                       GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+      if (grub_errno != GRUB_ERR_NONE)
+        return;
+      grub_video_bitmap_destroy (img);
+    }
+  */
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+menu_destroy (void)
+{
+  if (items)
+    {
+      int i;
+      for (i = 0; i < num_items; i++)
+        {
+          if (items[i].icon)
+            {
+              grub_video_bitmap_destroy (items[i].icon);
+              items[i].icon = 0;
+            }
+        }
+      grub_free (items);
+      items = 0;
+    }
+}
+
+static grub_err_t
+style_init (void)
+{
+  if (!(title_font = grub_font_get ("Helvetica Bold 24"))
+      || !(item_font = grub_font_get ("Helvetica Bold 14"))
+      || !(status_font = grub_font_get ("Helvetica 10")))
+    return grub_errno;
+
+  title_color = grub_video_map_rgb (0, 0, 0);
+  item_color = grub_video_map_rgb (0, 0, 0);
+  status_color = grub_video_map_rgb (255, 255, 255);
+  status_bg_color = grub_video_map_rgba (0, 0, 0, 112);
+
+  struct grub_video_bitmap *img;
+  grub_video_bitmap_load (&img, "/boot/images/bg-protomenu1.tga");
+  if (grub_errno != GRUB_ERR_NONE)
+    return grub_errno;
+
+  grub_video_bitmap_create_scaled (&background_image, screen.width,
+                                   screen.height, img,
+                                   GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+  if (grub_errno != GRUB_ERR_NONE)
+    return grub_errno;
+  grub_video_bitmap_destroy (img);
+
+  menu_box = grub_protomenu_widgets_create_box ("/boot/images/menubox_", ".tga");
+  if (menu_box == 0)
+      return grub_error (GRUB_ERR_MENU, "Unable to create menu box");
+
+  selected_item_box = grub_protomenu_widgets_create_box ("/boot/images/select_blue_", ".tga");
+  if (selected_item_box == 0)
+      return grub_error (GRUB_ERR_MENU, "Unable to create selection box");
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+style_destroy (void)
+{
+  if (menu_box) 
+    {
+      menu_box->destroy(menu_box);
+      menu_box = 0;
+    }
+  if (selected_item_box) 
+    {
+      selected_item_box->destroy(selected_item_box);
+      selected_item_box = 0;
+    }
+}
+
+static void
+draw_background (void)
+{
+  grub_video_blit_bitmap (background_image, GRUB_VIDEO_BLIT_REPLACE,
+                          0, 0, 0, 0,
+                          grub_video_bitmap_get_width (background_image),
+                          grub_video_bitmap_get_height (background_image));
+}
+
+static void
+draw_menu (void)
+{
+  int boxpad = 14;
+  int icon_text_space = 4;
+  int item_vspace = 16;
+
+  int ascent = grub_font_get_ascent (item_font);
+  int descent = grub_font_get_descent (item_font);
+  int item_height = 52;
+
+  grub_video_rect_t r;
+  r.width = screen.width * 2 / 3;
+  /* Set the menu box height to fit the items.  */
+  r.height = (item_height * num_items 
+              + item_vspace * (num_items - 1) 
+              + 2 * boxpad);
+  r.x = (screen.width - r.width) / 2;
+  r.y = (screen.height - r.height) / 2;
+  menu_box->set_content_size (menu_box, r.width, r.height);
+
+  int menu_box_left_pad = menu_box->get_left_pad (menu_box);
+  int menu_box_top_pad = menu_box->get_top_pad (menu_box);
+  menu_box->draw (menu_box, r.x - menu_box_left_pad, r.y - menu_box_top_pad);
+
+  int item_top = r.y + boxpad;
+  int item_left = r.x + boxpad;
+  int i;
+
+  for (i = 0; i < num_items; i++)
+    {
+      if (i == selected_item_index)
+        {
+          selected_item_box->set_content_size (selected_item_box,
+                                               r.width - 2 * boxpad,
+                                               item_height);
+          int leftpad = selected_item_box->get_left_pad (selected_item_box);
+          int toppad = selected_item_box->get_top_pad (selected_item_box);
+          selected_item_box->draw (selected_item_box, 
+                                   item_left - leftpad, 
+                                   item_top - toppad);
+        }
+
+      if (items[i].icon)
+        grub_video_blit_bitmap (items[i].icon, GRUB_VIDEO_BLIT_BLEND,
+                                item_left,
+                                item_top + (item_height - icon_height) / 2,
+                                0, 0, icon_width, icon_height);
+
+      grub_video_draw_string (items[i].name, item_font, item_color,
+                              item_left + icon_width + icon_text_space,
+                              (item_top + (item_height - (ascent + descent)) 
+                               / 2 + ascent));
+
+      item_top += item_height + item_vspace;
+    }
+}
+
+static void
+draw_title (void)
+{
+  /* Center the title. */
+  int title_width = grub_font_get_string_width (title_font, title_text);
+  int x = (screen.width - title_width) / 2;
+  int y = 40 + grub_font_get_ascent (title_font);
+  grub_video_draw_string (title_text, title_font, title_color, x, y);
+}
+
+static void
+draw_status (void)
+{
+  int descent = grub_font_get_descent (status_font);
+  int ascent = grub_font_get_ascent (status_font);
+  int vpad = 5;
+  int textheight = descent + ascent + 1;
+  int h = 2 * vpad + 2 * textheight;
+
+  grub_video_fill_rect (status_bg_color, 0, screen.height - h,
+                        screen.width, screen.height - 1);
+
+  int texty = screen.height - h + vpad + ascent;
+  grub_video_draw_string ("Select an item with the arrow keys and "
+                          "press Enter to boot.",
+                          status_font, status_color, 30, texty);
+  texty += textheight;
+  grub_video_draw_string ("Press:  'c' for command line; 't' to switch to "
+                          "non-graphical menu.",
+                          status_font, status_color, 30, texty);
+
+}
+
+static grub_err_t
+set_graphics_mode (void)
+{
+  const char *nodoublebuf_str = grub_env_get ("protomenu_nodoublebuf");
+  int doublebuf_flags =
+    (nodoublebuf_str && nodoublebuf_str[0] == 'y')
+    ? 0
+    : GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+
+  if (grub_video_setup (1024, 768, GRUB_VIDEO_MODE_TYPE_RGB | doublebuf_flags) 
+      != GRUB_ERR_NONE)
+    return grub_errno;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+set_text_mode (void)
+{
+  return grub_video_restore ();
+}
+
+/* TODO set the 'terminal' type to console for now, here.
+   (until gfxterm use is integrated). */
+static grub_err_t
+show_menu (grub_menu_t menu, int nested __attribute__ ((unused)))
+{
+  set_graphics_mode ();
+
+  grub_error_push ();
+  grub_video_get_viewport ((unsigned *) &screen.x,
+                           (unsigned *) &screen.y,
+                           (unsigned *) &screen.width,
+                           (unsigned *) &screen.height);
+
+  /* Clear the screen; there may be garbage left over in video memory, and
+     loading the menu style (particularly the background) can take a while. */
+  grub_video_fill_rect (grub_video_map_rgb (100, 100, 100),
+                        screen.x, screen.y, screen.width, screen.height);
+  grub_video_swap_buffers ();
+
+  if (menu_init (menu) != GRUB_ERR_NONE)
+    goto menufail;
+
+  if (style_init () != GRUB_ERR_NONE)
+    goto stylefail;
+
+  selected_item_index = 0;
+  int done = 0;
+  while (!done && !grub_menu_viewer_should_return ())
+    {
+      draw_background ();
+      draw_menu ();
+      draw_title ();
+      draw_status ();
+      grub_video_swap_buffers ();
+
+      int c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
+      if (c == 'j' || c == 14)
+        {
+          selected_item_index++;
+          if (selected_item_index >= num_items)
+            selected_item_index = 0;
+        }
+      else if (c == 'k' || c == 16)
+        {
+          selected_item_index--;
+          if (selected_item_index < 0)
+            selected_item_index = num_items - 1;
+        }
+      else if (c == '\r' || c == '\n' || c == 6)
+        {
+          if (selected_item_index >=0 && selected_item_index < num_items)
+            {
+              menu_item_t *item = &items[selected_item_index];
+              if (item->entry != 0)
+                {
+                  set_text_mode ();
+                  grub_menu_execute_entry (item->entry);
+                  if (grub_errno != GRUB_ERR_NONE)
+                    grub_wait_after_message ();
+                  if (set_graphics_mode () != GRUB_ERR_NONE)
+                    done = 1;
+                }
+            }
+        }
+      else if (c == 'c')
+        {
+          set_text_mode ();
+          grub_cmdline_run (1);
+          if (grub_errno != GRUB_ERR_NONE)
+            grub_wait_after_message ();
+          if (set_graphics_mode () != GRUB_ERR_NONE)
+            done = 1;
+        }
+      else if (c == 't')
+        {
+          /* The write hook for 'menuviewer' will cause 
+           * grub_menu_viewer_should_return to return nonzero. */
+          grub_env_set ("menuviewer", "terminal");
+        }
+      else if (nested && c == GRUB_TERM_ESC)
+        {
+          done = 1;
+        }
+    }
+
+  style_destroy ();
+stylefail:
+  menu_destroy ();
+menufail:
+  set_text_mode ();
+
+  grub_print_error ();
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_protomenu (struct grub_arg_list *state __attribute__ ((unused)),
+                    int argc __attribute__ ((unused)),
+                    char **args __attribute__ ((unused)))
+{
+  grub_menu_t menu = grub_env_get_data_slot ("menu");
+  if (!menu)
+    return grub_error (GRUB_ERR_MENU, "No menu context");
+
+  show_menu (menu, 1);
+
+  return 0;
+}
+
+static struct grub_menu_viewer menu_viewer =
+{
+  .name = "protomenu",
+  .show_menu = show_menu
+};
+
+GRUB_MOD_INIT (protomenu)
+{
+  (void) mod;                   /* To stop warning. */
+  grub_register_command ("protomenu",
+                         grub_cmd_protomenu, GRUB_COMMAND_FLAG_BOTH,
+                         "protomenu", "Show graphical menu prototype", 0);
+  grub_menu_viewer_register (&menu_viewer);
+}
+
+GRUB_MOD_FINI (protomenu)
+{
+  grub_unregister_command ("protomenu");
+}

=== added file 'protomenu/widget-box.c'
--- protomenu/widget-box.c	1970-01-01 00:00:00 +0000
+++ protomenu/widget-box.c	2008-07-08 13:59:48 +0000
@@ -0,0 +1,245 @@
+/* widget_box.c - Pixmap-stylized box widget. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/proto_widgets.h>
+
+enum box_pixmaps
+{
+  BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW,
+  BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W,
+  BOX_PIXMAP_CENTER
+};
+
+static const char *box_pixmap_names[] = {
+  /* Corners: */
+  "nw", "ne", "se", "sw",
+  /* Sides: */
+  "n", "e", "s", "w",
+  /* Center: */
+  "c"
+};
+
+#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names))
+
+static void
+draw (struct grub_protomenu_widgets_box *self, int x, int y)
+{
+  int height_n;
+  int height_s;
+  int height_e;
+  int height_w;
+  int width_n;
+  int width_s;
+  int width_e;
+  int width_w;
+  unsigned i;
+
+  /* Don't try to draw if any pixmaps are null, except the center. */
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      if (i != BOX_PIXMAP_CENTER && self->scaled_pixmaps[i] == 0)
+        return;
+    }
+
+  height_n = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_N]);
+  height_s = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_S]);
+  height_e = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_E]);
+  height_w = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_W]);
+  width_n = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_N]);
+  width_s = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_S]);
+  width_e = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_E]);
+  width_w = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_W]);
+
+  /* Draw sides.  */
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_N], 
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w, y, 0, 0, width_n, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_S],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w, y + height_n + height_w,
+                          0, 0, width_s, height_s);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_E],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y + height_n,
+                          0, 0, width_e, height_e);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_W],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y + height_n, 0, 0, width_w, height_w);
+
+  /* Draw corners.  */
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_NW],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y, 0, 0, width_w, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_NE],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y, 
+                          0, 0, width_e, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_SE],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y + height_n + height_e, 
+                          0, 0, width_e, height_s);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_SW],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y + height_n + height_w, 
+                          0, 0, width_w, height_s);
+
+  /* Draw center.  */
+  if (self->scaled_pixmaps[BOX_PIXMAP_CENTER])
+    grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_CENTER],
+                            GRUB_VIDEO_BLIT_BLEND,
+                            x + width_w, y + height_n,
+                            0, 0, self->width, self->height);
+}
+
+static void
+scale_pixmap (grub_protomenu_widgets_box_t self, int i, int w, int h)
+{
+  struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i];
+  struct grub_video_bitmap *raw = self->raw_pixmaps[i];
+
+  if (raw == 0)
+    return;
+
+  if (w == -1)
+    w = grub_video_bitmap_get_width (raw);
+  if (h == -1)
+    h = grub_video_bitmap_get_height (raw);
+
+  if (*scaled == 0 
+      || ((int) grub_video_bitmap_get_width (*scaled) != w)
+      || ((int) grub_video_bitmap_get_height (*scaled) != h))
+    {
+      if (*scaled)
+        {
+          grub_video_bitmap_destroy (*scaled);
+          *scaled = 0;
+        }
+      grub_video_bitmap_create_scaled (scaled, w, h, raw, 
+                                       GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+    }
+}
+
+static void
+set_content_size (grub_protomenu_widgets_box_t self,
+                  int width, int height)
+{
+  self->width = width;
+  self->height = height;
+  /* Resize sides to match the width and height.  */
+  /* It is assumed that the corners width/height match the adjacent sides.  */
+
+  /* Resize N and S sides to match width.  */
+  scale_pixmap(self, BOX_PIXMAP_N, width, -1);
+  scale_pixmap(self, BOX_PIXMAP_S, width, -1);
+
+  /* Resize E and W sides to match height.  */
+  scale_pixmap(self, BOX_PIXMAP_E, -1, height);
+  scale_pixmap(self, BOX_PIXMAP_W, -1, height);
+
+  /* Don't scale the corners--they are assumed to match the sides. */
+  scale_pixmap(self, BOX_PIXMAP_NW, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_SW, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_NE, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_SE, -1, -1);
+
+  /* Scale the center area. */
+  scale_pixmap(self, BOX_PIXMAP_CENTER, width, height);
+}
+
+static int
+get_left_pad (struct grub_protomenu_widgets_box *self)
+{
+  return grub_video_bitmap_get_width (self->raw_pixmaps[BOX_PIXMAP_W]);
+}
+
+static int
+get_top_pad (struct grub_protomenu_widgets_box *self)
+{
+  return grub_video_bitmap_get_height (self->raw_pixmaps[BOX_PIXMAP_N]);
+}
+
+static void
+destroy (struct grub_protomenu_widgets_box *self)
+{
+  unsigned i;
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      if (self->raw_pixmaps[i])
+        grub_video_bitmap_destroy(self->raw_pixmaps[i]);
+      self->raw_pixmaps[i] = 0;
+
+      if (self->scaled_pixmaps[i])
+        grub_video_bitmap_destroy(self->scaled_pixmaps[i]);
+      self->scaled_pixmaps[i] = 0;
+    }
+  grub_free (self->raw_pixmaps);
+  self->raw_pixmaps = 0;
+  grub_free (self->scaled_pixmaps);
+  self->scaled_pixmaps = 0;
+
+  grub_free (self);             /* Free self:  must be the last step! */
+}
+
+
+grub_protomenu_widgets_box_t
+grub_protomenu_widgets_create_box (const char *pixmaps_prefix,
+                                   const char *pixmaps_suffix)
+{
+  char path[200];
+  unsigned i;
+  grub_protomenu_widgets_box_t box;
+
+  box = (grub_protomenu_widgets_box_t) grub_malloc (sizeof (*box));
+  if (!box)
+    return 0;
+  box->width = 0;
+  box->height = 0;
+  box->raw_pixmaps =
+    (struct grub_video_bitmap **) grub_malloc (BOX_NUM_PIXMAPS *
+                                               sizeof (struct grub_video_bitmap
+                                                       *));
+  box->scaled_pixmaps =
+    (struct grub_video_bitmap **) grub_malloc (BOX_NUM_PIXMAPS *
+                                               sizeof (struct grub_video_bitmap
+                                                       *));
+
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      /* TODO dynamically allocate PATH, making sure it's large enough */
+      grub_sprintf (path, "%s%s%s",
+                    pixmaps_prefix, box_pixmap_names[i], pixmaps_suffix);
+      grub_video_bitmap_load (&box->raw_pixmaps[i], path);
+      box->scaled_pixmaps[i] = 0;
+    }
+
+  box->draw = draw;
+  box->set_content_size = set_content_size;
+  box->get_left_pad = get_left_pad;
+  box->get_top_pad = get_top_pad;
+  box->destroy = destroy;
+
+  return box;
+}

# Begin bundle
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
RUP/4u5IpwoSCKoPHUA=
