* [PATCH] Split #4: text menu separation
@ 2009-04-11 17:39 Bean
2009-04-17 11:28 ` phcoder
0 siblings, 1 reply; 3+ messages in thread
From: Bean @ 2009-04-11 17:39 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 113 bytes --]
Hi,
This patch moves menu_text.c to menu/text/, and it changes
grub_menu_viewer structure as handler.
--
Bean
[-- Attachment #2: s4.diff --]
[-- Type: text/x-patch, Size: 37331 bytes --]
diff --git a/conf/common.rmk b/conf/common.rmk
index 00aff3d..fac3c1a 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -342,7 +342,7 @@ pkglib_MODULES += minicmd.mod extcmd.mod hello.mod handler.mod \
loopback.mod fs_uuid.mod configfile.mod echo.mod \
terminfo.mod test.mod blocklist.mod hexdump.mod \
read.mod sleep.mod loadenv.mod crc.mod parttool.mod \
- pcpart.mod memrw.mod normal.mod sh.mod
+ pcpart.mod memrw.mod normal.mod sh.mod textmenu.mod
# For minicmd.mod.
minicmd_mod_SOURCES = commands/minicmd.c
@@ -466,10 +466,9 @@ memrw_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For normal.mod.
normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \
- normal/autofs.c normal/handler.c \
- normal/color.c normal/completion.c normal/datetime.c normal/menu.c \
- normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \
- normal/misc.c
+ normal/autofs.c normal/handler.c normal/completion.c \
+ normal/datetime.c normal/misc.c normal/menu_viewer.c \
+ normal/color.c normal/menu.c normal/menu_entry.c
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -479,6 +478,11 @@ sh_mod_SOURCES = script/sh/main.c script/sh/script.c script/sh/execute.c \
sh_mod_CFLAGS = $(COMMON_CFLAGS)
sh_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For textmenu.mod.
+textmenu_mod_SOURCES = menu/text/menu_text.c
+textmenu_mod_CFLAGS = $(COMMON_CFLAGS)
+textmenu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# Common Video Subsystem specific modules.
pkglib_MODULES += video.mod videotest.mod bitmap.mod tga.mod jpeg.mod \
png.mod font.mod gfxterm.mod
diff --git a/include/grub/menu_viewer.h b/include/grub/menu_viewer.h
index 725c975..bd6b937 100644
--- a/include/grub/menu_viewer.h
+++ b/include/grub/menu_viewer.h
@@ -24,19 +24,43 @@
#include <grub/symbol.h>
#include <grub/types.h>
#include <grub/menu.h>
+#include <grub/handler.h>
struct grub_menu_viewer
{
+ struct grub_menu_viewer *next;
+
/* The menu viewer name. */
const char *name;
- grub_err_t (*show_menu) (grub_menu_t menu, int nested);
+ grub_err_t (*init) (void);
- struct grub_menu_viewer *next;
+ grub_err_t (*fini) (void);
+
+ grub_err_t (*show_menu) (grub_menu_t menu, int nested);
};
typedef struct grub_menu_viewer *grub_menu_viewer_t;
-void grub_menu_viewer_register (grub_menu_viewer_t viewer);
+extern struct grub_handler_class grub_menu_viewer_class;
+
+static inline void
+grub_menu_viewer_register (const char *name __attribute__ ((unused)),
+ grub_menu_viewer_t viewer)
+{
+ grub_handler_register (&grub_menu_viewer_class, GRUB_AS_HANDLER (viewer));
+}
+
+static inline void
+grub_menu_viewer_unregister (grub_menu_viewer_t viewer)
+{
+ grub_handler_unregister (&grub_menu_viewer_class, GRUB_AS_HANDLER (viewer));
+}
+
+static inline grub_menu_viewer_t
+grub_menu_viewer_get_current (void)
+{
+ return (grub_menu_viewer_t) grub_menu_viewer_class.cur_handler;
+}
grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested);
diff --git a/include/grub/normal.h b/include/grub/normal.h
index 948289a..cf61f07 100644
--- a/include/grub/normal.h
+++ b/include/grub/normal.h
@@ -41,8 +41,6 @@ enum grub_completion_type
};
typedef enum grub_completion_type grub_completion_type_t;
-extern struct grub_menu_viewer grub_normal_text_menu_viewer;
-
/* Callback structure menu viewers can use to provide user feedback when
default entries are executed, possibly including fallback entries. */
typedef struct grub_menu_execute_callback
diff --git a/menu/text/menu_text.c b/menu/text/menu_text.c
new file mode 100644
index 0000000..35ff623
--- /dev/null
+++ b/menu/text/menu_text.c
@@ -0,0 +1,614 @@
+/* main.c - Basic text menu implementation. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * 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/dl.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/mm.h>
+#include <grub/time.h>
+#include <grub/env.h>
+#include <grub/menu_viewer.h>
+#include <grub/menu.h>
+#include <grub/normal.h>
+
+/* Time to delay after displaying an error message about a default/fallback
+ entry failing to boot. */
+#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
+
+static grub_uint8_t grub_color_menu_normal;
+static grub_uint8_t grub_color_menu_highlight;
+
+/* Wait until the user pushes any key so that the user
+ can see what happened. */
+void
+grub_wait_after_message (void)
+{
+ grub_printf ("\nPress any key to continue...");
+ (void) grub_getkey ();
+}
+
+static void
+draw_border (void)
+{
+ unsigned i;
+
+ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
+
+ grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
+ grub_putcode (GRUB_TERM_DISP_UL);
+ for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
+ grub_putcode (GRUB_TERM_DISP_HLINE);
+ grub_putcode (GRUB_TERM_DISP_UR);
+
+ for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++)
+ {
+ grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
+ grub_putcode (GRUB_TERM_DISP_VLINE);
+ grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1,
+ GRUB_TERM_TOP_BORDER_Y + i + 1);
+ grub_putcode (GRUB_TERM_DISP_VLINE);
+ }
+
+ grub_gotoxy (GRUB_TERM_MARGIN,
+ GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1);
+ grub_putcode (GRUB_TERM_DISP_LL);
+ for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
+ grub_putcode (GRUB_TERM_DISP_HLINE);
+ grub_putcode (GRUB_TERM_DISP_LR);
+
+ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
+
+ grub_gotoxy (GRUB_TERM_MARGIN,
+ (GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES
+ + GRUB_TERM_MARGIN + 1));
+}
+
+static void
+print_message (int nested, int edit)
+{
+ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
+
+ if (edit)
+ {
+ grub_printf ("\n\
+ Minimum Emacs-like screen editing is supported. TAB lists\n\
+ completions. Press Ctrl-x to boot, Ctrl-c for a command-line\n\
+ or ESC to return menu.");
+ }
+ else
+ {
+ grub_printf ("\n\
+ Use the %C and %C keys to select which entry is highlighted.\n",
+ (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) GRUB_TERM_DISP_DOWN);
+ grub_printf ("\
+ Press enter to boot the selected OS, \'e\' to edit the\n\
+ commands before booting or \'c\' for a command-line.");
+ if (nested)
+ grub_printf ("\n\
+ ESC to return previous menu.");
+ }
+}
+
+static void
+print_entry (int y, int highlight, grub_menu_entry_t entry)
+{
+ int x;
+ const char *title;
+ grub_size_t title_len;
+ grub_ssize_t len;
+ grub_uint32_t *unicode_title;
+ grub_ssize_t i;
+ grub_uint8_t old_color_normal, old_color_highlight;
+
+ title = entry ? entry->title : "";
+ title_len = grub_strlen (title);
+ unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
+ if (! unicode_title)
+ /* XXX How to show this error? */
+ return;
+
+ len = grub_utf8_to_ucs4 (unicode_title, title_len,
+ (grub_uint8_t *) title, -1, 0);
+ if (len < 0)
+ {
+ /* It is an invalid sequence. */
+ grub_free (unicode_title);
+ return;
+ }
+
+ grub_getcolor (&old_color_normal, &old_color_highlight);
+ grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
+ grub_setcolorstate (highlight
+ ? GRUB_TERM_COLOR_HIGHLIGHT
+ : GRUB_TERM_COLOR_NORMAL);
+
+ grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
+
+ for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
+ x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN;
+ i++)
+ {
+ if (i < len
+ && x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
+ - GRUB_TERM_MARGIN - 1))
+ {
+ grub_ssize_t width;
+
+ width = grub_getcharwidth (unicode_title[i]);
+
+ if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
+ - GRUB_TERM_MARGIN - 1))
+ grub_putcode (GRUB_TERM_DISP_RIGHT);
+ else
+ grub_putcode (unicode_title[i]);
+
+ x += width;
+ }
+ else
+ {
+ grub_putchar (' ');
+ x++;
+ }
+ }
+ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
+ grub_putchar (' ');
+
+ grub_gotoxy (GRUB_TERM_CURSOR_X, y);
+
+ grub_setcolor (old_color_normal, old_color_highlight);
+ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
+ grub_free (unicode_title);
+}
+
+static void
+print_entries (grub_menu_t menu, int first, int offset)
+{
+ grub_menu_entry_t e;
+ int i;
+
+ grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
+ GRUB_TERM_FIRST_ENTRY_Y);
+
+ if (first)
+ grub_putcode (GRUB_TERM_DISP_UP);
+ else
+ grub_putchar (' ');
+
+ e = grub_menu_get_entry (menu, first);
+
+ for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++)
+ {
+ print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e);
+ if (e)
+ e = e->next;
+ }
+
+ grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
+ GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES);
+
+ if (e)
+ grub_putcode (GRUB_TERM_DISP_DOWN);
+ else
+ grub_putchar (' ');
+
+ grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
+}
+
+/* Initialize the screen. If NESTED is non-zero, assume that this menu
+ is run from another menu or a command-line. If EDIT is non-zero, show
+ a message for the menu entry editor. */
+void
+grub_menu_init_page (int nested, int edit)
+{
+ grub_uint8_t old_color_normal, old_color_highlight;
+
+ grub_getcolor (&old_color_normal, &old_color_highlight);
+
+ /* By default, use the same colors for the menu. */
+ grub_color_menu_normal = old_color_normal;
+ grub_color_menu_highlight = old_color_highlight;
+
+ /* Then give user a chance to replace them. */
+ grub_parse_color_name_pair (&grub_color_menu_normal, grub_env_get ("menu_color_normal"));
+ grub_parse_color_name_pair (&grub_color_menu_highlight, grub_env_get ("menu_color_highlight"));
+
+ grub_normal_init_page ();
+
+ grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
+ draw_border ();
+ grub_setcolor (old_color_normal, old_color_highlight);
+ print_message (nested, edit);
+}
+
+/* Get the entry number from the variable NAME. */
+static int
+get_entry_number (const char *name)
+{
+ char *val;
+ int entry;
+
+ val = grub_env_get (name);
+ if (! val)
+ return -1;
+
+ grub_error_push ();
+
+ entry = (int) grub_strtoul (val, 0, 0);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ entry = -1;
+ }
+
+ grub_error_pop ();
+
+ return entry;
+}
+
+static void
+print_timeout (int timeout, int offset, int second_stage)
+{
+ /* NOTE: Do not remove the trailing space characters.
+ They are required to clear the line. */
+ char *msg = " The highlighted entry will be booted automatically in %ds. ";
+ char *msg_end = grub_strchr (msg, '%');
+
+ grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3);
+ grub_printf (second_stage ? msg_end : msg, timeout);
+ grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
+ grub_refresh ();
+};
+
+/* 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)
+{
+ int first, offset;
+ grub_uint64_t saved_time;
+ int default_entry;
+ int timeout;
+
+ first = 0;
+
+ default_entry = get_entry_number ("default");
+
+ /* If DEFAULT_ENTRY is not within the menu entries, fall back to
+ the first entry. */
+ if (default_entry < 0 || default_entry >= menu->size)
+ default_entry = 0;
+
+ /* If timeout is 0, drawing is pointless (and ugly). */
+ if (grub_menu_get_timeout () == 0)
+ {
+ *auto_boot = 1;
+ return default_entry;
+ }
+
+ offset = default_entry;
+ if (offset > GRUB_TERM_NUM_ENTRIES - 1)
+ {
+ first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
+ offset = GRUB_TERM_NUM_ENTRIES - 1;
+ }
+
+ /* Initialize the time. */
+ saved_time = grub_get_time_ms ();
+
+ refresh:
+ grub_setcursor (0);
+ grub_menu_init_page (nested, 0);
+ print_entries (menu, first, offset);
+ grub_refresh ();
+
+ timeout = grub_menu_get_timeout ();
+
+ if (timeout > 0)
+ print_timeout (timeout, offset, 0);
+
+ while (1)
+ {
+ int c;
+ timeout = grub_menu_get_timeout ();
+
+ 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;
+ print_timeout (timeout, offset, 1);
+ }
+ }
+
+ if (timeout == 0)
+ {
+ grub_env_unset ("timeout");
+ *auto_boot = 1;
+ return default_entry;
+ }
+
+ if (grub_checkkey () >= 0 || timeout < 0)
+ {
+ c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
+
+ if (timeout >= 0)
+ {
+ grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
+ grub_printf ("\
+ ");
+ grub_env_unset ("timeout");
+ grub_env_unset ("fallback");
+ grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
+ }
+
+ switch (c)
+ {
+ case GRUB_TERM_HOME:
+ first = 0;
+ offset = 0;
+ print_entries (menu, first, offset);
+ break;
+
+ case GRUB_TERM_END:
+ offset = menu->size - 1;
+ if (offset > GRUB_TERM_NUM_ENTRIES - 1)
+ {
+ first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
+ offset = GRUB_TERM_NUM_ENTRIES - 1;
+ }
+ print_entries (menu, first, offset);
+ break;
+
+ case GRUB_TERM_UP:
+ case '^':
+ if (offset > 0)
+ {
+ print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
+ grub_menu_get_entry (menu, first + offset));
+ offset--;
+ print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
+ grub_menu_get_entry (menu, first + offset));
+ }
+ else if (first > 0)
+ {
+ first--;
+ print_entries (menu, first, offset);
+ }
+ break;
+
+ case GRUB_TERM_DOWN:
+ case 'v':
+ if (menu->size > first + offset + 1)
+ {
+ if (offset < GRUB_TERM_NUM_ENTRIES - 1)
+ {
+ print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
+ grub_menu_get_entry (menu, first + offset));
+ offset++;
+ print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
+ grub_menu_get_entry (menu, first + offset));
+ }
+ else
+ {
+ first++;
+ print_entries (menu, first, offset);
+ }
+ }
+ break;
+
+ case GRUB_TERM_PPAGE:
+ if (first == 0)
+ {
+ offset = 0;
+ }
+ else
+ {
+ first -= GRUB_TERM_NUM_ENTRIES;
+
+ if (first < 0)
+ {
+ offset += first;
+ first = 0;
+ }
+ }
+ print_entries (menu, first, offset);
+ break;
+
+ case GRUB_TERM_NPAGE:
+ if (offset == 0)
+ {
+ offset += GRUB_TERM_NUM_ENTRIES - 1;
+ if (first + offset >= menu->size)
+ {
+ offset = menu->size - first - 1;
+ }
+ }
+ else
+ {
+ first += GRUB_TERM_NUM_ENTRIES;
+
+ if (first + offset >= menu->size)
+ {
+ first -= GRUB_TERM_NUM_ENTRIES;
+ offset += GRUB_TERM_NUM_ENTRIES;
+
+ if (offset > menu->size - 1 ||
+ offset > GRUB_TERM_NUM_ENTRIES - 1)
+ {
+ offset = menu->size - first - 1;
+ }
+ if (offset > GRUB_TERM_NUM_ENTRIES)
+ {
+ first += offset - GRUB_TERM_NUM_ENTRIES + 1;
+ offset = GRUB_TERM_NUM_ENTRIES - 1;
+ }
+ }
+ }
+ print_entries (menu, first, offset);
+ break;
+
+ case '\n':
+ case '\r':
+ case 6:
+ grub_setcursor (1);
+ *auto_boot = 0;
+ return first + offset;
+
+ case '\e':
+ if (nested)
+ {
+ grub_setcursor (1);
+ return -1;
+ }
+ break;
+
+ case 'c':
+ grub_cmdline_run (nested);
+ goto refresh;
+
+ case 'e':
+ {
+ grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset);
+ if (e)
+ grub_menu_entry_run (e);
+ }
+ goto refresh;
+
+ default:
+ break;
+ }
+
+ grub_refresh ();
+ }
+ }
+
+ /* 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 (" Booting \'%s\'\n\n", entry->title);
+}
+
+/* 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)))
+{
+ grub_printf ("\n Falling back to \'%s\'\n\n", entry->title);
+ 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 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_text_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 ();
+ grub_setcursor (1);
+
+ 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;
+}
+
+struct grub_menu_viewer grub_text_menu_viewer =
+{
+ .name = "text",
+ .show_menu = show_text_menu
+};
+
+GRUB_MOD_INIT(textmenu)
+{
+ (void) mod;
+
+ grub_menu_viewer_register ("text", &grub_text_menu_viewer);
+}
+
+GRUB_MOD_FINI(textmenu)
+{
+ grub_menu_viewer_unregister (&grub_text_menu_viewer);
+}
diff --git a/normal/main.c b/normal/main.c
index 2df53be..b9b6f2c 100644
--- a/normal/main.c
+++ b/normal/main.c
@@ -537,8 +537,6 @@ GRUB_MOD_INIT(normal)
if (mod)
grub_dl_ref (mod);
- grub_menu_viewer_register (&grub_normal_text_menu_viewer);
-
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
grub_reader_register ("normal", &grub_normal_reader);
diff --git a/normal/menu_text.c b/normal/menu_text.c
deleted file mode 100644
index 0c4461f..0000000
--- a/normal/menu_text.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/* menu_text.c - Basic text menu implementation. */
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * 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/normal.h>
-#include <grub/term.h>
-#include <grub/misc.h>
-#include <grub/loader.h>
-#include <grub/mm.h>
-#include <grub/time.h>
-#include <grub/env.h>
-#include <grub/menu_viewer.h>
-
-/* Time to delay after displaying an error message about a default/fallback
- entry failing to boot. */
-#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
-
-static grub_uint8_t grub_color_menu_normal;
-static grub_uint8_t grub_color_menu_highlight;
-
-/* Wait until the user pushes any key so that the user
- can see what happened. */
-void
-grub_wait_after_message (void)
-{
- grub_printf ("\nPress any key to continue...");
- (void) grub_getkey ();
-}
-
-static void
-draw_border (void)
-{
- unsigned i;
-
- grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
-
- grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
- grub_putcode (GRUB_TERM_DISP_UL);
- for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
- grub_putcode (GRUB_TERM_DISP_HLINE);
- grub_putcode (GRUB_TERM_DISP_UR);
-
- for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++)
- {
- grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
- grub_putcode (GRUB_TERM_DISP_VLINE);
- grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1,
- GRUB_TERM_TOP_BORDER_Y + i + 1);
- grub_putcode (GRUB_TERM_DISP_VLINE);
- }
-
- grub_gotoxy (GRUB_TERM_MARGIN,
- GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1);
- grub_putcode (GRUB_TERM_DISP_LL);
- for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
- grub_putcode (GRUB_TERM_DISP_HLINE);
- grub_putcode (GRUB_TERM_DISP_LR);
-
- grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
-
- grub_gotoxy (GRUB_TERM_MARGIN,
- (GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES
- + GRUB_TERM_MARGIN + 1));
-}
-
-static void
-print_message (int nested, int edit)
-{
- grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
-
- if (edit)
- {
- grub_printf ("\n\
- Minimum Emacs-like screen editing is supported. TAB lists\n\
- completions. Press Ctrl-x to boot, Ctrl-c for a command-line\n\
- or ESC to return menu.");
- }
- else
- {
- grub_printf ("\n\
- Use the %C and %C keys to select which entry is highlighted.\n",
- (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) GRUB_TERM_DISP_DOWN);
- grub_printf ("\
- Press enter to boot the selected OS, \'e\' to edit the\n\
- commands before booting or \'c\' for a command-line.");
- if (nested)
- grub_printf ("\n\
- ESC to return previous menu.");
- }
-}
-
-static void
-print_entry (int y, int highlight, grub_menu_entry_t entry)
-{
- int x;
- const char *title;
- grub_size_t title_len;
- grub_ssize_t len;
- grub_uint32_t *unicode_title;
- grub_ssize_t i;
- grub_uint8_t old_color_normal, old_color_highlight;
-
- title = entry ? entry->title : "";
- title_len = grub_strlen (title);
- unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
- if (! unicode_title)
- /* XXX How to show this error? */
- return;
-
- len = grub_utf8_to_ucs4 (unicode_title, title_len,
- (grub_uint8_t *) title, -1, 0);
- if (len < 0)
- {
- /* It is an invalid sequence. */
- grub_free (unicode_title);
- return;
- }
-
- grub_getcolor (&old_color_normal, &old_color_highlight);
- grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
- grub_setcolorstate (highlight
- ? GRUB_TERM_COLOR_HIGHLIGHT
- : GRUB_TERM_COLOR_NORMAL);
-
- grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
-
- for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
- x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN;
- i++)
- {
- if (i < len
- && x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
- - GRUB_TERM_MARGIN - 1))
- {
- grub_ssize_t width;
-
- width = grub_getcharwidth (unicode_title[i]);
-
- if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
- - GRUB_TERM_MARGIN - 1))
- grub_putcode (GRUB_TERM_DISP_RIGHT);
- else
- grub_putcode (unicode_title[i]);
-
- x += width;
- }
- else
- {
- grub_putchar (' ');
- x++;
- }
- }
- grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
- grub_putchar (' ');
-
- grub_gotoxy (GRUB_TERM_CURSOR_X, y);
-
- grub_setcolor (old_color_normal, old_color_highlight);
- grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
- grub_free (unicode_title);
-}
-
-static void
-print_entries (grub_menu_t menu, int first, int offset)
-{
- grub_menu_entry_t e;
- int i;
-
- grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
- GRUB_TERM_FIRST_ENTRY_Y);
-
- if (first)
- grub_putcode (GRUB_TERM_DISP_UP);
- else
- grub_putchar (' ');
-
- e = grub_menu_get_entry (menu, first);
-
- for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++)
- {
- print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e);
- if (e)
- e = e->next;
- }
-
- grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
- GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES);
-
- if (e)
- grub_putcode (GRUB_TERM_DISP_DOWN);
- else
- grub_putchar (' ');
-
- grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
-}
-
-/* Initialize the screen. If NESTED is non-zero, assume that this menu
- is run from another menu or a command-line. If EDIT is non-zero, show
- a message for the menu entry editor. */
-void
-grub_menu_init_page (int nested, int edit)
-{
- grub_uint8_t old_color_normal, old_color_highlight;
-
- grub_getcolor (&old_color_normal, &old_color_highlight);
-
- /* By default, use the same colors for the menu. */
- grub_color_menu_normal = old_color_normal;
- grub_color_menu_highlight = old_color_highlight;
-
- /* Then give user a chance to replace them. */
- grub_parse_color_name_pair (&grub_color_menu_normal, grub_env_get ("menu_color_normal"));
- grub_parse_color_name_pair (&grub_color_menu_highlight, grub_env_get ("menu_color_highlight"));
-
- grub_normal_init_page ();
- grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
- draw_border ();
- grub_setcolor (old_color_normal, old_color_highlight);
- print_message (nested, edit);
-}
-
-/* Get the entry number from the variable NAME. */
-static int
-get_entry_number (const char *name)
-{
- char *val;
- int entry;
-
- val = grub_env_get (name);
- if (! val)
- return -1;
-
- grub_error_push ();
-
- entry = (int) grub_strtoul (val, 0, 0);
-
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_errno = GRUB_ERR_NONE;
- entry = -1;
- }
-
- grub_error_pop ();
-
- return entry;
-}
-
-static void
-print_timeout (int timeout, int offset, int second_stage)
-{
- /* NOTE: Do not remove the trailing space characters.
- They are required to clear the line. */
- char *msg = " The highlighted entry will be booted automatically in %ds. ";
- char *msg_end = grub_strchr (msg, '%');
-
- grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3);
- grub_printf (second_stage ? msg_end : msg, timeout);
- grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
- grub_refresh ();
-};
-
-/* 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)
-{
- int first, offset;
- grub_uint64_t saved_time;
- int default_entry;
- int timeout;
-
- first = 0;
-
- default_entry = get_entry_number ("default");
-
- /* If DEFAULT_ENTRY is not within the menu entries, fall back to
- the first entry. */
- if (default_entry < 0 || default_entry >= menu->size)
- default_entry = 0;
-
- /* If timeout is 0, drawing is pointless (and ugly). */
- if (grub_menu_get_timeout () == 0)
- {
- *auto_boot = 1;
- return default_entry;
- }
-
- offset = default_entry;
- if (offset > GRUB_TERM_NUM_ENTRIES - 1)
- {
- first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
- offset = GRUB_TERM_NUM_ENTRIES - 1;
- }
-
- /* Initialize the time. */
- saved_time = grub_get_time_ms ();
-
- refresh:
- grub_setcursor (0);
- grub_menu_init_page (nested, 0);
- print_entries (menu, first, offset);
- grub_refresh ();
-
- timeout = grub_menu_get_timeout ();
-
- if (timeout > 0)
- print_timeout (timeout, offset, 0);
-
- while (1)
- {
- int c;
- timeout = grub_menu_get_timeout ();
-
- 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;
- print_timeout (timeout, offset, 1);
- }
- }
-
- if (timeout == 0)
- {
- grub_env_unset ("timeout");
- *auto_boot = 1;
- return default_entry;
- }
-
- if (grub_checkkey () >= 0 || timeout < 0)
- {
- c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
-
- if (timeout >= 0)
- {
- grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
- grub_printf ("\
- ");
- grub_env_unset ("timeout");
- grub_env_unset ("fallback");
- grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
- }
-
- switch (c)
- {
- case GRUB_TERM_HOME:
- first = 0;
- offset = 0;
- print_entries (menu, first, offset);
- break;
-
- case GRUB_TERM_END:
- offset = menu->size - 1;
- if (offset > GRUB_TERM_NUM_ENTRIES - 1)
- {
- first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
- offset = GRUB_TERM_NUM_ENTRIES - 1;
- }
- print_entries (menu, first, offset);
- break;
-
- case GRUB_TERM_UP:
- case '^':
- if (offset > 0)
- {
- print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
- grub_menu_get_entry (menu, first + offset));
- offset--;
- print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
- grub_menu_get_entry (menu, first + offset));
- }
- else if (first > 0)
- {
- first--;
- print_entries (menu, first, offset);
- }
- break;
-
- case GRUB_TERM_DOWN:
- case 'v':
- if (menu->size > first + offset + 1)
- {
- if (offset < GRUB_TERM_NUM_ENTRIES - 1)
- {
- print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
- grub_menu_get_entry (menu, first + offset));
- offset++;
- print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
- grub_menu_get_entry (menu, first + offset));
- }
- else
- {
- first++;
- print_entries (menu, first, offset);
- }
- }
- break;
-
- case GRUB_TERM_PPAGE:
- if (first == 0)
- {
- offset = 0;
- }
- else
- {
- first -= GRUB_TERM_NUM_ENTRIES;
-
- if (first < 0)
- {
- offset += first;
- first = 0;
- }
- }
- print_entries (menu, first, offset);
- break;
-
- case GRUB_TERM_NPAGE:
- if (offset == 0)
- {
- offset += GRUB_TERM_NUM_ENTRIES - 1;
- if (first + offset >= menu->size)
- {
- offset = menu->size - first - 1;
- }
- }
- else
- {
- first += GRUB_TERM_NUM_ENTRIES;
-
- if (first + offset >= menu->size)
- {
- first -= GRUB_TERM_NUM_ENTRIES;
- offset += GRUB_TERM_NUM_ENTRIES;
-
- if (offset > menu->size - 1 ||
- offset > GRUB_TERM_NUM_ENTRIES - 1)
- {
- offset = menu->size - first - 1;
- }
- if (offset > GRUB_TERM_NUM_ENTRIES)
- {
- first += offset - GRUB_TERM_NUM_ENTRIES + 1;
- offset = GRUB_TERM_NUM_ENTRIES - 1;
- }
- }
- }
- print_entries (menu, first, offset);
- break;
-
- case '\n':
- case '\r':
- case 6:
- grub_setcursor (1);
- *auto_boot = 0;
- return first + offset;
-
- case '\e':
- if (nested)
- {
- grub_setcursor (1);
- return -1;
- }
- break;
-
- case 'c':
- grub_cmdline_run (1);
- goto refresh;
-
- case 'e':
- {
- grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset);
- if (e)
- grub_menu_entry_run (e);
- }
- goto refresh;
-
- default:
- break;
- }
-
- grub_refresh ();
- }
- }
-
- /* 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 (" Booting \'%s\'\n\n", entry->title);
-}
-
-/* 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)))
-{
- grub_printf ("\n Falling back to \'%s\'\n\n", entry->title);
- 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 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_text_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 ();
- grub_setcursor (1);
-
- 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;
-}
-
-struct grub_menu_viewer grub_normal_text_menu_viewer =
-{
- .name = "text",
- .show_menu = show_text_menu
-};
diff --git a/normal/menu_viewer.c b/normal/menu_viewer.c
index f7047c7..9d0d414 100644
--- a/normal/menu_viewer.c
+++ b/normal/menu_viewer.c
@@ -16,48 +16,24 @@
* 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/err.h>
#include <grub/menu_viewer.h>
-#include <grub/menu.h>
-/* The list of menu viewers. */
-static grub_menu_viewer_t menu_viewer_list;
-
-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;
-}
+struct grub_handler_class grub_menu_viewer_class =
+ {
+ .name = "menu_viewer"
+ };
grub_err_t
grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
{
- grub_menu_viewer_t cur = get_current_menu_viewer ();
+ grub_menu_viewer_t cur = grub_menu_viewer_get_current ();
if (!cur)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
- return cur->show_menu (menu, nested);
-}
+ grub_err_t err;
+
+ err = cur->show_menu (menu, nested);
+ return err;
+}
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] Split #4: text menu separation
2009-04-11 17:39 [PATCH] Split #4: text menu separation Bean
@ 2009-04-17 11:28 ` phcoder
2009-04-17 13:39 ` Bean
0 siblings, 1 reply; 3+ messages in thread
From: phcoder @ 2009-04-17 11:28 UTC (permalink / raw)
To: The development of GRUB 2
Hello. Couldn't this be done by transforming menu viewer to a command?
What are pros and contras of both approaches?
Bean wrote:
> Hi,
>
> This patch moves menu_text.c to menu/text/, and it changes
> grub_menu_viewer structure as handler.
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Regards
Vladimir 'phcoder' Serbinenko
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Split #4: text menu separation
2009-04-17 11:28 ` phcoder
@ 2009-04-17 13:39 ` Bean
0 siblings, 0 replies; 3+ messages in thread
From: Bean @ 2009-04-17 13:39 UTC (permalink / raw)
To: The development of GRUB 2
Hi,
With the handler.lst patch, commands to switch between different
handler are registered automatically. For example, you can start the
text menu with this command:
menu_viewer.text
On Fri, Apr 17, 2009 at 7:28 PM, phcoder <phcoder@gmail.com> wrote:
> Hello. Couldn't this be done by transforming menu viewer to a command? What
> are pros and contras of both approaches?
> Bean wrote:
>>
>> Hi,
>>
>> This patch moves menu_text.c to menu/text/, and it changes
>> grub_menu_viewer structure as handler.
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>
> --
>
> Regards
> Vladimir 'phcoder' Serbinenko
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
--
Bean
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-04-17 13:39 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-11 17:39 [PATCH] Split #4: text menu separation Bean
2009-04-17 11:28 ` phcoder
2009-04-17 13:39 ` Bean
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.