$(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 $< \
--- /dev/null
- 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;
+}
--- /dev/null
- 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;
+}
--- /dev/null
- 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;
+}
--- /dev/null
- 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;
+}
--- /dev/null
- #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
--- /dev/null
- /* 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 */
+
--- /dev/null
- #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 */
--- /dev/null
- #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 */
}
*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);
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
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;
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;
}
--/*
-- * 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);
- }
--