~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to normal/menu_text.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* menu_text.c - Basic text menu implementation.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2003,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
5
 
 *
6
 
 *  GRUB is free software: you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation, either version 3 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  GRUB is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include <grub/normal.h>
21
 
#include <grub/term.h>
22
 
#include <grub/misc.h>
23
 
#include <grub/loader.h>
24
 
#include <grub/mm.h>
25
 
#include <grub/time.h>
26
 
#include <grub/env.h>
27
 
#include <grub/menu_viewer.h>
28
 
#include <grub/i18n.h>
29
 
#include <grub/charset.h>
30
 
 
31
 
static grub_uint8_t grub_color_menu_normal;
32
 
static grub_uint8_t grub_color_menu_highlight;
33
 
 
34
 
struct menu_viewer_data
35
 
{
36
 
  int first, offset;
37
 
  grub_menu_t menu;
38
 
  struct grub_term_output *term;
39
 
};
40
 
 
41
 
grub_ssize_t
42
 
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
43
 
                     struct grub_term_output *term)
44
 
{
45
 
  grub_ssize_t width = 0;
46
 
 
47
 
  while (str < last_position)
48
 
    {
49
 
      struct grub_unicode_glyph glyph;
50
 
      str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph);
51
 
      width += grub_term_getcharwidth (term, &glyph);
52
 
    }
53
 
  return width;
54
 
}
55
 
 
56
 
void
57
 
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
58
 
                             struct grub_term_output *term)
59
 
{
60
 
  grub_uint32_t *unicode_msg;
61
 
  grub_uint32_t *last_position;
62
 
 
63
 
  int msg_len;
64
 
 
65
 
  msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
66
 
 
67
 
  if (msg_len < 0)
68
 
    {
69
 
      return;
70
 
    }
71
 
 
72
 
  grub_print_ucs4 (unicode_msg, last_position, margin_left, margin_right, term);
73
 
 
74
 
  grub_free (unicode_msg);
75
 
}
76
 
 
77
 
 
78
 
static void
79
 
draw_border (struct grub_term_output *term)
80
 
{
81
 
  unsigned i;
82
 
 
83
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
84
 
 
85
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
86
 
  grub_putcode (GRUB_UNICODE_CORNER_UL, term);
87
 
  for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
88
 
    grub_putcode (GRUB_UNICODE_HLINE, term);
89
 
  grub_putcode (GRUB_UNICODE_CORNER_UR, term);
90
 
 
91
 
  for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
92
 
    {
93
 
      grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
94
 
      grub_putcode (GRUB_UNICODE_VLINE, term);
95
 
      grub_term_gotoxy (term, GRUB_TERM_MARGIN + grub_term_border_width (term)
96
 
                        - 1,
97
 
                        GRUB_TERM_TOP_BORDER_Y + i + 1);
98
 
      grub_putcode (GRUB_UNICODE_VLINE, term);
99
 
    }
100
 
 
101
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN,
102
 
                    GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1);
103
 
  grub_putcode (GRUB_UNICODE_CORNER_LL, term);
104
 
  for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
105
 
    grub_putcode (GRUB_UNICODE_HLINE, term);
106
 
  grub_putcode (GRUB_UNICODE_CORNER_LR, term);
107
 
 
108
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
109
 
 
110
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN,
111
 
                    (GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
112
 
                     + GRUB_TERM_MARGIN + 1));
113
 
}
114
 
 
115
 
static void
116
 
print_message (int nested, int edit, struct grub_term_output *term)
117
 
{
118
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
119
 
 
120
 
  if (edit)
121
 
    {
122
 
      grub_putcode ('\n', term);
123
 
#ifdef GRUB_MACHINE_EFI
124
 
      grub_print_message_indented (_("Minimum Emacs-like screen editing is \
125
 
supported. TAB lists completions. Press F1 to boot, F2=Ctrl-a, F3=Ctrl-e, \
126
 
F4 for a command-line or ESC to discard edits and return to the GRUB menu."),
127
 
                                   STANDARD_MARGIN, STANDARD_MARGIN, term);
128
 
#else
129
 
      grub_print_message_indented (_("Minimum Emacs-like screen editing is \
130
 
supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \
131
 
command-line or ESC to discard edits and return to the GRUB menu."),
132
 
                                   STANDARD_MARGIN, STANDARD_MARGIN, term);
133
 
#endif
134
 
    }
135
 
  else
136
 
    {
137
 
      const char *msg = _("Use the %C and %C keys to select which "
138
 
                          "entry is highlighted.\n");
139
 
      char *msg_translated;
140
 
 
141
 
      msg_translated = grub_xasprintf (msg, GRUB_UNICODE_UPARROW,
142
 
                                       GRUB_UNICODE_DOWNARROW);
143
 
      if (!msg_translated)
144
 
        return;
145
 
      grub_putcode ('\n', term);
146
 
      grub_print_message_indented (msg_translated, STANDARD_MARGIN,
147
 
                                   STANDARD_MARGIN, term);
148
 
 
149
 
      grub_free (msg_translated);
150
 
 
151
 
      if (nested)
152
 
        {
153
 
          grub_print_message_indented
154
 
            (_("Press enter to boot the selected OS, "
155
 
               "\'e\' to edit the commands before booting "
156
 
               "or \'c\' for a command-line. ESC to return previous menu.\n"),
157
 
             STANDARD_MARGIN, STANDARD_MARGIN, term);
158
 
        }
159
 
      else
160
 
        {
161
 
          grub_print_message_indented
162
 
            (_("Press enter to boot the selected OS, "
163
 
               "\'e\' to edit the commands before booting "
164
 
               "or \'c\' for a command-line.\n"),
165
 
             STANDARD_MARGIN, STANDARD_MARGIN, term);
166
 
        }       
167
 
    }
168
 
}
169
 
 
170
 
static void
171
 
print_entry (int y, int highlight, grub_menu_entry_t entry,
172
 
             struct grub_term_output *term)
173
 
{
174
 
  int x;
175
 
  const char *title;
176
 
  grub_size_t title_len;
177
 
  grub_ssize_t len;
178
 
  grub_uint32_t *unicode_title;
179
 
  grub_ssize_t i;
180
 
  grub_uint8_t old_color_normal, old_color_highlight;
181
 
 
182
 
  title = entry ? entry->title : "";
183
 
  title_len = grub_strlen (title);
184
 
  unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
185
 
  if (! unicode_title)
186
 
    /* XXX How to show this error?  */
187
 
    return;
188
 
 
189
 
  len = grub_utf8_to_ucs4 (unicode_title, title_len,
190
 
                           (grub_uint8_t *) title, -1, 0);
191
 
  if (len < 0)
192
 
    {
193
 
      /* It is an invalid sequence.  */
194
 
      grub_free (unicode_title);
195
 
      return;
196
 
    }
197
 
 
198
 
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
199
 
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
200
 
  grub_term_setcolorstate (term, highlight
201
 
                           ? GRUB_TERM_COLOR_HIGHLIGHT
202
 
                           : GRUB_TERM_COLOR_NORMAL);
203
 
 
204
 
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
205
 
 
206
 
  int last_printed = 0;
207
 
  for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
208
 
       x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
209
 
                  - GRUB_TERM_MARGIN);)
210
 
    {
211
 
      if (i < len
212
 
          && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
213
 
                         - GRUB_TERM_MARGIN - 1))
214
 
        {
215
 
          grub_ssize_t width;
216
 
          struct grub_unicode_glyph glyph;
217
 
 
218
 
          i += grub_unicode_aglomerate_comb (unicode_title + i,
219
 
                                             len - i, &glyph);
220
 
 
221
 
          width = grub_term_getcharwidth (term, &glyph);
222
 
          grub_free (glyph.combining);
223
 
 
224
 
          if (x + width <= (int) (GRUB_TERM_LEFT_BORDER_X 
225
 
                                 + grub_term_border_width (term)
226
 
                                 - GRUB_TERM_MARGIN - 1))
227
 
            last_printed = i;
228
 
          x += width;
229
 
        }
230
 
      else
231
 
        break;
232
 
    }
233
 
 
234
 
  grub_print_ucs4 (unicode_title,
235
 
                   unicode_title + last_printed, 0, 0, term);
236
 
 
237
 
  if (last_printed != len)
238
 
    {
239
 
      grub_putcode (GRUB_UNICODE_RIGHTARROW, term);
240
 
      struct grub_unicode_glyph pseudo_glyph = {
241
 
        .base = GRUB_UNICODE_RIGHTARROW,
242
 
        .variant = 0,
243
 
        .attributes = 0,
244
 
        .ncomb = 0,
245
 
        .combining = 0,
246
 
        .estimated_width = 1
247
 
      };
248
 
      x += grub_term_getcharwidth (term, &pseudo_glyph);
249
 
    }
250
 
 
251
 
  for (; x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
252
 
                    - GRUB_TERM_MARGIN); x++)
253
 
    grub_putcode (' ', term);
254
 
 
255
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
256
 
  grub_putcode (' ', term);
257
 
 
258
 
  grub_term_gotoxy (term, grub_term_cursor_x (term), y);
259
 
 
260
 
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
261
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
262
 
  grub_free (unicode_title);
263
 
}
264
 
 
265
 
static void
266
 
print_entries (grub_menu_t menu, int first, int offset,
267
 
               struct grub_term_output *term)
268
 
{
269
 
  grub_menu_entry_t e;
270
 
  int i;
271
 
 
272
 
  grub_term_gotoxy (term,
273
 
                    GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
274
 
                    GRUB_TERM_FIRST_ENTRY_Y);
275
 
 
276
 
  if (first)
277
 
    grub_putcode (GRUB_UNICODE_UPARROW, term);
278
 
  else
279
 
    grub_putcode (' ', term);
280
 
 
281
 
  e = grub_menu_get_entry (menu, first);
282
 
 
283
 
  for (i = 0; i < grub_term_num_entries (term); i++)
284
 
    {
285
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
286
 
      if (e)
287
 
        e = e->next;
288
 
    }
289
 
 
290
 
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X
291
 
                    + grub_term_border_width (term),
292
 
                    GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term));
293
 
 
294
 
  if (e)
295
 
    grub_putcode (GRUB_UNICODE_DOWNARROW, term);
296
 
  else
297
 
    grub_putcode (' ', term);
298
 
 
299
 
  grub_term_gotoxy (term, grub_term_cursor_x (term),
300
 
                    GRUB_TERM_FIRST_ENTRY_Y + offset);
301
 
}
302
 
 
303
 
/* Initialize the screen.  If NESTED is non-zero, assume that this menu
304
 
   is run from another menu or a command-line. If EDIT is non-zero, show
305
 
   a message for the menu entry editor.  */
306
 
void
307
 
grub_menu_init_page (int nested, int edit,
308
 
                     struct grub_term_output *term)
309
 
{
310
 
  grub_uint8_t old_color_normal, old_color_highlight;
311
 
 
312
 
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
313
 
 
314
 
  /* By default, use the same colors for the menu.  */
315
 
  grub_color_menu_normal = old_color_normal;
316
 
  grub_color_menu_highlight = old_color_highlight;
317
 
 
318
 
  /* Then give user a chance to replace them.  */
319
 
  grub_parse_color_name_pair (&grub_color_menu_normal,
320
 
                              grub_env_get ("menu_color_normal"));
321
 
  grub_parse_color_name_pair (&grub_color_menu_highlight,
322
 
                              grub_env_get ("menu_color_highlight"));
323
 
 
324
 
  grub_normal_init_page (term);
325
 
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
326
 
  draw_border (term);
327
 
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
328
 
  print_message (nested, edit, term);
329
 
}
330
 
 
331
 
static void
332
 
menu_text_print_timeout (int timeout, void *dataptr)
333
 
{
334
 
  const char *msg =
335
 
    _("The highlighted entry will be executed automatically in %ds.");
336
 
  struct menu_viewer_data *data = dataptr;
337
 
  char *msg_translated;
338
 
  int posx;
339
 
 
340
 
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
341
 
 
342
 
  msg_translated = grub_xasprintf (msg, timeout);
343
 
  if (!msg_translated)
344
 
    {
345
 
      grub_print_error ();
346
 
      grub_errno = GRUB_ERR_NONE;
347
 
      return;
348
 
    }
349
 
 
350
 
  grub_print_message_indented (msg_translated, 3, 0, data->term);
351
 
 
352
 
  posx = grub_term_getxy (data->term) >> 8;
353
 
  grub_print_spaces (data->term, grub_term_width (data->term) - posx - 1);
354
 
 
355
 
  grub_term_gotoxy (data->term,
356
 
                    grub_term_cursor_x (data->term),
357
 
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
358
 
  grub_term_refresh (data->term);
359
 
}
360
 
 
361
 
static void
362
 
menu_text_set_chosen_entry (int entry, void *dataptr)
363
 
{
364
 
  struct menu_viewer_data *data = dataptr;
365
 
  int oldoffset = data->offset;
366
 
  int complete_redraw = 0;
367
 
 
368
 
  data->offset = entry - data->first;
369
 
  if (data->offset > grub_term_num_entries (data->term) - 1)
370
 
    {
371
 
      data->first = entry - (grub_term_num_entries (data->term) - 1);
372
 
      data->offset = grub_term_num_entries (data->term) - 1;
373
 
      complete_redraw = 1;
374
 
    }
375
 
  if (data->offset < 0)
376
 
    {
377
 
      data->offset = 0;
378
 
      data->first = entry;
379
 
      complete_redraw = 1;
380
 
    }
381
 
  if (complete_redraw)
382
 
    print_entries (data->menu, data->first, data->offset, data->term);
383
 
  else
384
 
    {
385
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
386
 
                   grub_menu_get_entry (data->menu, data->first + oldoffset),
387
 
                   data->term);
388
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
389
 
                   grub_menu_get_entry (data->menu, data->first + data->offset),
390
 
                   data->term);
391
 
    }
392
 
  grub_term_refresh (data->term);
393
 
}
394
 
 
395
 
static void
396
 
menu_text_fini (void *dataptr)
397
 
{
398
 
  struct menu_viewer_data *data = dataptr;
399
 
 
400
 
  grub_term_setcursor (data->term, 1);
401
 
  grub_term_cls (data->term);
402
 
 
403
 
}
404
 
 
405
 
static void
406
 
menu_text_clear_timeout (void *dataptr)
407
 
{
408
 
  struct menu_viewer_data *data = dataptr;
409
 
 
410
 
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
411
 
  grub_print_spaces (data->term, grub_term_width (data->term) - 1);
412
 
  grub_term_gotoxy (data->term, grub_term_cursor_x (data->term),
413
 
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
414
 
  grub_term_refresh (data->term);
415
 
}
416
 
 
417
 
grub_err_t 
418
 
grub_menu_try_text (struct grub_term_output *term, 
419
 
                    int entry, grub_menu_t menu, int nested)
420
 
{
421
 
  struct menu_viewer_data *data;
422
 
  struct grub_menu_viewer *instance;
423
 
 
424
 
  instance = grub_zalloc (sizeof (*instance));
425
 
  if (!instance)
426
 
    return grub_errno;
427
 
 
428
 
  data = grub_zalloc (sizeof (*data));
429
 
  if (!data)
430
 
    {
431
 
      grub_free (instance);
432
 
      return grub_errno;
433
 
    }
434
 
 
435
 
  data->term = term;
436
 
  instance->data = data;
437
 
  instance->set_chosen_entry = menu_text_set_chosen_entry;
438
 
  instance->print_timeout = menu_text_print_timeout;
439
 
  instance->clear_timeout = menu_text_clear_timeout;
440
 
  instance->fini = menu_text_fini;
441
 
 
442
 
  data->menu = menu;
443
 
 
444
 
  data->offset = entry;
445
 
  data->first = 0;
446
 
  if (data->offset > grub_term_num_entries (data->term) - 1)
447
 
    {
448
 
      data->first = data->offset - (grub_term_num_entries (data->term) - 1);
449
 
      data->offset = grub_term_num_entries (data->term) - 1;
450
 
    }
451
 
 
452
 
  grub_term_setcursor (data->term, 0);
453
 
  grub_menu_init_page (nested, 0, data->term);
454
 
  print_entries (menu, data->first, data->offset, data->term);
455
 
  grub_term_refresh (data->term);
456
 
  grub_menu_register_viewer (instance);
457
 
 
458
 
  return GRUB_ERR_NONE;
459
 
}