GRUB 2 Graphical Menu Software Design

Author: Colin D. Bennett <colin@gibibit.com>
Date: 17 August 2008

Introduction

The gfxmenu module provides a graphical menu interface for GRUB 2. It functions as an alternative to the menu interface provided by the normal module, which uses the grub terminal interface to display a menu on a character-oriented terminal.

The graphical menu uses the GRUB video API, which is currently for the VESA BIOS extensions (VBE) 2.0+. This is supported on the i386-pc platform. However, the graphical menu itself does not depend on using VBE, so if another GRUB video driver were implemented, the gfxmenu graphical menu would work on the new video driver as well.

Startup Sequence

grub_enter_normal_mode [normal/main.c]
grub_normal_execute [normal/main.c]
read_config_file [normal/main.c]
(When gfxmenu.mod is loaded with insmod, it will
call grub_menu_viewer_register() to register itself.)
GRUB_MOD_INIT (gfxmenu) [gfxmenu/gfxmenu.c]
grub_menu_viewer_register [kern/menu_viewer.c]
grub_menu_viewer_show_menu [kern/menu_viewer.c]
get_current_menu_viewer() [kern/menu_viewer.c]
show_menu() [gfxmenu/gfxmenu.c]
grub_gfxmenu_model_new [gfxmenu/model.c]
grub_gfxmenu_view_new [gfxmenu/view.c]
set_graphics_mode [gfxmenu/view.c]
grub_gfxmenu_view_load_theme [gfxmenu/theme_loader.c]

GUI Components

The graphical menu implements a GUI component system that supports a container-based layout system. Components can be added to containers, and containers (which are a type of component) can then be added to other containers, to form a tree of components. Currently, the root component of this tree is a canvas component, which allows manual layout of its child components.

Components (non-container):

  • label
  • image
  • progress_bar
  • circular_progress
  • list (currently hard coded to be a boot menu list)

Containers:

  • canvas
  • hbox
  • vbox

The GUI component instances are created by the theme loader in gfxmenu/theme_loader.c when a theme is loaded. Theme files specify statements such as +vbox{ +label{ text="Hello" } +label{ text="World" } } to add components to the component tree root. By nesting the component creation statements in the theme file, the instantiated components are nested the same way.

When a component is added to a container, that new child is considered owned by the container. Great care should be taken if the caller retains a reference to the child component, since it will be destroyed if its parent container is destroyed. A better choice instead of storing a pointer to the child component is to use the component ID to find the desired component. Component IDs do not have to be unique (it is often useful to have multiple components with an ID of "__timeout__", for instance).

In order to access and use components in the component tree, there are two functions (defined in gfxmenu/gui_util.c) that are particularly useful:

  • grub_gui_find_by_id (root, id, callback, userdata):

    This function ecursively traverses the component tree rooted at root, and for every component that has an ID equal to id, calls the function pointed to by callback with the matching component and the void pointer userdata as arguments. The callback function can do whatever is desired to use the component passed in.

  • grub_gui_iterate_recursively (root, callback, userdata):

    This function calls the function pointed to by callback for every component that is a descendant of root in the component tree. When the callback function is called, the component and the void pointer userdata as arguments. The callback function can do whatever is desired to use the component passed in.

Command Line Window

The terminal window used to provide command line access within the graphical menu is managed by gfxmenu/view.c. The gfxterm terminal is used, and it has been modified to allow rendering to an offscreen render target to allow it to be composed into the double buffering system that the graphical menu view uses. This is bad for performance, however, so it would probably be a good idea to make it possible to temporarily disable double buffering as long as the terminal window is visible. There are still unresolved problems that occur when commands are executed from the terminal window that change the graphics mode. It's possible that making grub_video_restore() return to the graphics mode that was in use before grub_video_setup() was called might fix some of the problems.