~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, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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
}