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

« back to all changes in this revision

Viewing changes to grub-core/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
      grub_print_message_indented (_("Minimum Emacs-like screen editing is \
 
124
supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \
 
125
command-line or ESC to discard edits and return to the GRUB menu."),
 
126
                                   STANDARD_MARGIN, STANDARD_MARGIN, term);
 
127
    }
 
128
  else
 
129
    {
 
130
      const char *msg = _("Use the %C and %C keys to select which "
 
131
                          "entry is highlighted.\n");
 
132
      char *msg_translated;
 
133
 
 
134
      msg_translated = grub_xasprintf (msg, GRUB_UNICODE_UPARROW,
 
135
                                       GRUB_UNICODE_DOWNARROW);
 
136
      if (!msg_translated)
 
137
        return;
 
138
      grub_putcode ('\n', term);
 
139
      grub_print_message_indented (msg_translated, STANDARD_MARGIN,
 
140
                                   STANDARD_MARGIN, term);
 
141
 
 
142
      grub_free (msg_translated);
 
143
 
 
144
      if (nested)
 
145
        {
 
146
          grub_print_message_indented
 
147
            (_("Press enter to boot the selected OS, "
 
148
               "\'e\' to edit the commands before booting "
 
149
               "or \'c\' for a command-line. ESC to return previous menu.\n"),
 
150
             STANDARD_MARGIN, STANDARD_MARGIN, term);
 
151
        }
 
152
      else
 
153
        {
 
154
          grub_print_message_indented
 
155
            (_("Press enter to boot the selected OS, "
 
156
               "\'e\' to edit the commands before booting "
 
157
               "or \'c\' for a command-line.\n"),
 
158
             STANDARD_MARGIN, STANDARD_MARGIN, term);
 
159
        }       
 
160
    }
 
161
}
 
162
 
 
163
static void
 
164
print_entry (int y, int highlight, grub_menu_entry_t entry,
 
165
             struct grub_term_output *term)
 
166
{
 
167
  int x;
 
168
  const char *title;
 
169
  grub_size_t title_len;
 
170
  grub_ssize_t len;
 
171
  grub_uint32_t *unicode_title;
 
172
  grub_ssize_t i;
 
173
  grub_uint8_t old_color_normal, old_color_highlight;
 
174
 
 
175
  title = entry ? entry->title : "";
 
176
  title_len = grub_strlen (title);
 
177
  unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
 
178
  if (! unicode_title)
 
179
    /* XXX How to show this error?  */
 
180
    return;
 
181
 
 
182
  len = grub_utf8_to_ucs4 (unicode_title, title_len,
 
183
                           (grub_uint8_t *) title, -1, 0);
 
184
  if (len < 0)
 
185
    {
 
186
      /* It is an invalid sequence.  */
 
187
      grub_free (unicode_title);
 
188
      return;
 
189
    }
 
190
 
 
191
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
 
192
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
 
193
  grub_term_setcolorstate (term, highlight
 
194
                           ? GRUB_TERM_COLOR_HIGHLIGHT
 
195
                           : GRUB_TERM_COLOR_NORMAL);
 
196
 
 
197
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
 
198
 
 
199
  int last_printed = 0;
 
200
  for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
 
201
       x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
 
202
                  - GRUB_TERM_MARGIN);)
 
203
    {
 
204
      if (i < len
 
205
          && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
 
206
                         - GRUB_TERM_MARGIN - 1))
 
207
        {
 
208
          grub_ssize_t width;
 
209
          struct grub_unicode_glyph glyph;
 
210
 
 
211
          i += grub_unicode_aglomerate_comb (unicode_title + i,
 
212
                                             len - i, &glyph);
 
213
 
 
214
          width = grub_term_getcharwidth (term, &glyph);
 
215
          grub_free (glyph.combining);
 
216
 
 
217
          if (x + width <= (int) (GRUB_TERM_LEFT_BORDER_X 
 
218
                                 + grub_term_border_width (term)
 
219
                                 - GRUB_TERM_MARGIN - 1))
 
220
            last_printed = i;
 
221
          x += width;
 
222
        }
 
223
      else
 
224
        break;
 
225
    }
 
226
 
 
227
  grub_print_ucs4 (unicode_title,
 
228
                   unicode_title + last_printed, 0, 0, term);
 
229
 
 
230
  if (last_printed != len)
 
231
    {
 
232
      grub_putcode (GRUB_UNICODE_RIGHTARROW, term);
 
233
      struct grub_unicode_glyph pseudo_glyph = {
 
234
        .base = GRUB_UNICODE_RIGHTARROW,
 
235
        .variant = 0,
 
236
        .attributes = 0,
 
237
        .ncomb = 0,
 
238
        .combining = 0,
 
239
        .estimated_width = 1
 
240
      };
 
241
      x += grub_term_getcharwidth (term, &pseudo_glyph);
 
242
    }
 
243
 
 
244
  for (; x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
 
245
                    - GRUB_TERM_MARGIN); x++)
 
246
    grub_putcode (' ', term);
 
247
 
 
248
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
 
249
  grub_putcode (' ', term);
 
250
 
 
251
  grub_term_gotoxy (term, grub_term_cursor_x (term), y);
 
252
 
 
253
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
 
254
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
 
255
  grub_free (unicode_title);
 
256
}
 
257
 
 
258
static void
 
259
print_entries (grub_menu_t menu, int first, int offset,
 
260
               struct grub_term_output *term)
 
261
{
 
262
  grub_menu_entry_t e;
 
263
  int i;
 
264
 
 
265
  grub_term_gotoxy (term,
 
266
                    GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
 
267
                    GRUB_TERM_FIRST_ENTRY_Y);
 
268
 
 
269
  if (first)
 
270
    grub_putcode (GRUB_UNICODE_UPARROW, term);
 
271
  else
 
272
    grub_putcode (' ', term);
 
273
 
 
274
  e = grub_menu_get_entry (menu, first);
 
275
 
 
276
  for (i = 0; i < grub_term_num_entries (term); i++)
 
277
    {
 
278
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
 
279
      if (e)
 
280
        e = e->next;
 
281
    }
 
282
 
 
283
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X
 
284
                    + grub_term_border_width (term),
 
285
                    GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term));
 
286
 
 
287
  if (e)
 
288
    grub_putcode (GRUB_UNICODE_DOWNARROW, term);
 
289
  else
 
290
    grub_putcode (' ', term);
 
291
 
 
292
  grub_term_gotoxy (term, grub_term_cursor_x (term),
 
293
                    GRUB_TERM_FIRST_ENTRY_Y + offset);
 
294
}
 
295
 
 
296
/* Initialize the screen.  If NESTED is non-zero, assume that this menu
 
297
   is run from another menu or a command-line. If EDIT is non-zero, show
 
298
   a message for the menu entry editor.  */
 
299
void
 
300
grub_menu_init_page (int nested, int edit,
 
301
                     struct grub_term_output *term)
 
302
{
 
303
  grub_uint8_t old_color_normal, old_color_highlight;
 
304
 
 
305
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
 
306
 
 
307
  /* By default, use the same colors for the menu.  */
 
308
  grub_color_menu_normal = old_color_normal;
 
309
  grub_color_menu_highlight = old_color_highlight;
 
310
 
 
311
  /* Then give user a chance to replace them.  */
 
312
  grub_parse_color_name_pair (&grub_color_menu_normal,
 
313
                              grub_env_get ("menu_color_normal"));
 
314
  grub_parse_color_name_pair (&grub_color_menu_highlight,
 
315
                              grub_env_get ("menu_color_highlight"));
 
316
 
 
317
  grub_normal_init_page (term);
 
318
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
 
319
  draw_border (term);
 
320
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
 
321
  print_message (nested, edit, term);
 
322
}
 
323
 
 
324
static void
 
325
menu_text_print_timeout (int timeout, void *dataptr)
 
326
{
 
327
  const char *msg =
 
328
    _("The highlighted entry will be executed automatically in %ds.");
 
329
  struct menu_viewer_data *data = dataptr;
 
330
  char *msg_translated;
 
331
  int posx;
 
332
 
 
333
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
 
334
 
 
335
  msg_translated = grub_xasprintf (msg, timeout);
 
336
  if (!msg_translated)
 
337
    {
 
338
      grub_print_error ();
 
339
      grub_errno = GRUB_ERR_NONE;
 
340
      return;
 
341
    }
 
342
 
 
343
  grub_print_message_indented (msg_translated, 3, 0, data->term);
 
344
 
 
345
  posx = grub_term_getxy (data->term) >> 8;
 
346
  grub_print_spaces (data->term, grub_term_width (data->term) - posx - 1);
 
347
 
 
348
  grub_term_gotoxy (data->term,
 
349
                    grub_term_cursor_x (data->term),
 
350
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
 
351
  grub_term_refresh (data->term);
 
352
}
 
353
 
 
354
static void
 
355
menu_text_set_chosen_entry (int entry, void *dataptr)
 
356
{
 
357
  struct menu_viewer_data *data = dataptr;
 
358
  int oldoffset = data->offset;
 
359
  int complete_redraw = 0;
 
360
 
 
361
  data->offset = entry - data->first;
 
362
  if (data->offset > grub_term_num_entries (data->term) - 1)
 
363
    {
 
364
      data->first = entry - (grub_term_num_entries (data->term) - 1);
 
365
      data->offset = grub_term_num_entries (data->term) - 1;
 
366
      complete_redraw = 1;
 
367
    }
 
368
  if (data->offset < 0)
 
369
    {
 
370
      data->offset = 0;
 
371
      data->first = entry;
 
372
      complete_redraw = 1;
 
373
    }
 
374
  if (complete_redraw)
 
375
    print_entries (data->menu, data->first, data->offset, data->term);
 
376
  else
 
377
    {
 
378
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
 
379
                   grub_menu_get_entry (data->menu, data->first + oldoffset),
 
380
                   data->term);
 
381
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
 
382
                   grub_menu_get_entry (data->menu, data->first + data->offset),
 
383
                   data->term);
 
384
    }
 
385
  grub_term_refresh (data->term);
 
386
}
 
387
 
 
388
static void
 
389
menu_text_fini (void *dataptr)
 
390
{
 
391
  struct menu_viewer_data *data = dataptr;
 
392
 
 
393
  grub_term_setcursor (data->term, 1);
 
394
  grub_term_cls (data->term);
 
395
 
 
396
}
 
397
 
 
398
static void
 
399
menu_text_clear_timeout (void *dataptr)
 
400
{
 
401
  struct menu_viewer_data *data = dataptr;
 
402
 
 
403
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
 
404
  grub_print_spaces (data->term, grub_term_width (data->term) - 1);
 
405
  grub_term_gotoxy (data->term, grub_term_cursor_x (data->term),
 
406
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
 
407
  grub_term_refresh (data->term);
 
408
}
 
409
 
 
410
grub_err_t 
 
411
grub_menu_try_text (struct grub_term_output *term, 
 
412
                    int entry, grub_menu_t menu, int nested)
 
413
{
 
414
  struct menu_viewer_data *data;
 
415
  struct grub_menu_viewer *instance;
 
416
 
 
417
  instance = grub_zalloc (sizeof (*instance));
 
418
  if (!instance)
 
419
    return grub_errno;
 
420
 
 
421
  data = grub_zalloc (sizeof (*data));
 
422
  if (!data)
 
423
    {
 
424
      grub_free (instance);
 
425
      return grub_errno;
 
426
    }
 
427
 
 
428
  data->term = term;
 
429
  instance->data = data;
 
430
  instance->set_chosen_entry = menu_text_set_chosen_entry;
 
431
  instance->print_timeout = menu_text_print_timeout;
 
432
  instance->clear_timeout = menu_text_clear_timeout;
 
433
  instance->fini = menu_text_fini;
 
434
 
 
435
  data->menu = menu;
 
436
 
 
437
  data->offset = entry;
 
438
  data->first = 0;
 
439
  if (data->offset > grub_term_num_entries (data->term) - 1)
 
440
    {
 
441
      data->first = data->offset - (grub_term_num_entries (data->term) - 1);
 
442
      data->offset = grub_term_num_entries (data->term) - 1;
 
443
    }
 
444
 
 
445
  grub_term_setcursor (data->term, 0);
 
446
  grub_menu_init_page (nested, 0, data->term);
 
447
  print_entries (menu, data->first, data->offset, data->term);
 
448
  grub_term_refresh (data->term);
 
449
  grub_menu_register_viewer (instance);
 
450
 
 
451
  return GRUB_ERR_NONE;
 
452
}