~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, 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
 
static void
42
 
print_spaces (int number_spaces, struct grub_term_output *term)
43
 
{
44
 
  int i;
45
 
  for (i = 0; i < number_spaces; i++)
46
 
    grub_putcode (' ', term);
47
 
}
48
 
 
49
 
void
50
 
grub_print_ucs4 (const grub_uint32_t * str,
51
 
                 const grub_uint32_t * last_position,
52
 
                 struct grub_term_output *term)
53
 
{
54
 
  while (str < last_position)
55
 
    {
56
 
      grub_putcode (*str, term);
57
 
      str++;
58
 
    }
59
 
}
60
 
 
61
 
grub_ssize_t
62
 
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
63
 
                     struct grub_term_output *term)
64
 
{
65
 
  grub_ssize_t width = 0;
66
 
 
67
 
  while (str < last_position)
68
 
    {
69
 
      width += grub_term_getcharwidth (term, *str);
70
 
      str++;
71
 
    }
72
 
  return width;
73
 
}
74
 
 
75
 
void
76
 
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
77
 
                             struct grub_term_output *term)
78
 
{
79
 
  int line_len;
80
 
 
81
 
  grub_uint32_t *unicode_msg;
82
 
  grub_uint32_t *last_position;
83
 
 
84
 
  int msg_len;
85
 
 
86
 
  line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') *
87
 
    (margin_left + margin_right);
88
 
 
89
 
  msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
90
 
 
91
 
  if (msg_len < 0)
92
 
    {
93
 
      return;
94
 
    }
95
 
 
96
 
  grub_uint32_t *current_position = unicode_msg;
97
 
 
98
 
  grub_uint32_t *next_new_line = unicode_msg;
99
 
 
100
 
  int first_loop = 1;
101
 
 
102
 
  while (current_position < last_position)
103
 
    {
104
 
      if (! first_loop)
105
 
        grub_putcode ('\n', term);
106
 
     
107
 
      next_new_line = (grub_uint32_t *) last_position;
108
 
 
109
 
      while (grub_getstringwidth (current_position, next_new_line,term) 
110
 
             > line_len
111
 
             || (next_new_line != last_position && *next_new_line != ' '
112
 
                 && next_new_line > current_position))
113
 
       {
114
 
         next_new_line--;
115
 
       }
116
 
 
117
 
      if (next_new_line == current_position)
118
 
       {
119
 
         next_new_line = (next_new_line + line_len > last_position) ?
120
 
           (grub_uint32_t *) last_position : next_new_line + line_len;
121
 
       }
122
 
 
123
 
      print_spaces (margin_left, term);
124
 
      grub_print_ucs4 (current_position, next_new_line, term);
125
 
 
126
 
      next_new_line++;
127
 
      current_position = next_new_line;
128
 
      first_loop = 0;
129
 
    }
130
 
  grub_free (unicode_msg);
131
 
}
132
 
 
133
 
 
134
 
static void
135
 
draw_border (struct grub_term_output *term)
136
 
{
137
 
  unsigned i;
138
 
 
139
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
140
 
 
141
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
142
 
  grub_putcode (GRUB_TERM_DISP_UL, term);
143
 
  for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
144
 
    grub_putcode (GRUB_TERM_DISP_HLINE, term);
145
 
  grub_putcode (GRUB_TERM_DISP_UR, term);
146
 
 
147
 
  for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
148
 
    {
149
 
      grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
150
 
      grub_putcode (GRUB_TERM_DISP_VLINE, term);
151
 
      grub_term_gotoxy (term, GRUB_TERM_MARGIN + grub_term_border_width (term)
152
 
                        - 1,
153
 
                        GRUB_TERM_TOP_BORDER_Y + i + 1);
154
 
      grub_putcode (GRUB_TERM_DISP_VLINE, term);
155
 
    }
156
 
 
157
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN,
158
 
                    GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1);
159
 
  grub_putcode (GRUB_TERM_DISP_LL, term);
160
 
  for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
161
 
    grub_putcode (GRUB_TERM_DISP_HLINE, term);
162
 
  grub_putcode (GRUB_TERM_DISP_LR, term);
163
 
 
164
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
165
 
 
166
 
  grub_term_gotoxy (term, GRUB_TERM_MARGIN,
167
 
                    (GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
168
 
                     + GRUB_TERM_MARGIN + 1));
169
 
}
170
 
 
171
 
static void
172
 
print_message (int nested, int edit, struct grub_term_output *term)
173
 
{
174
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
175
 
 
176
 
  if (edit)
177
 
    {
178
 
      grub_putcode ('\n', term);
179
 
      grub_print_message_indented (_("Minimum Emacs-like screen editing is \
180
 
supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \
181
 
command-line or ESC to return menu."), STANDARD_MARGIN, STANDARD_MARGIN,
182
 
                                   term);
183
 
    }
184
 
  else
185
 
    {
186
 
      const char *msg = _("Use the %C and %C keys to select which "
187
 
                          "entry is highlighted.\n");
188
 
      char *msg_translated;
189
 
 
190
 
      msg_translated = grub_xasprintf (msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
191
 
                                     (grub_uint32_t) GRUB_TERM_DISP_DOWN);
192
 
      if (!msg_translated)
193
 
        return;
194
 
      grub_putchar ('\n');
195
 
      grub_print_message_indented (msg_translated, STANDARD_MARGIN,
196
 
                                   STANDARD_MARGIN, term);
197
 
 
198
 
      grub_free (msg_translated);
199
 
 
200
 
      if (nested)
201
 
        {
202
 
          grub_print_message_indented
203
 
            (_("Press enter to boot the selected OS, "
204
 
               "\'e\' to edit the commands before booting "
205
 
               "or \'c\' for a command-line. ESC to return previous menu.\n"),
206
 
             STANDARD_MARGIN, STANDARD_MARGIN, term);
207
 
        }
208
 
      else
209
 
        {
210
 
          grub_print_message_indented
211
 
            (_("Press enter to boot the selected OS, "
212
 
               "\'e\' to edit the commands before booting "
213
 
               "or \'c\' for a command-line.\n"),
214
 
             STANDARD_MARGIN, STANDARD_MARGIN, term);
215
 
        }       
216
 
    }
217
 
}
218
 
 
219
 
static void
220
 
print_entry (int y, int highlight, grub_menu_entry_t entry,
221
 
             struct grub_term_output *term)
222
 
{
223
 
  int x;
224
 
  const char *title;
225
 
  grub_size_t title_len;
226
 
  grub_ssize_t len;
227
 
  grub_uint32_t *unicode_title;
228
 
  grub_ssize_t i;
229
 
  grub_uint8_t old_color_normal, old_color_highlight;
230
 
 
231
 
  title = entry ? entry->title : "";
232
 
  title_len = grub_strlen (title);
233
 
  unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
234
 
  if (! unicode_title)
235
 
    /* XXX How to show this error?  */
236
 
    return;
237
 
 
238
 
  len = grub_utf8_to_ucs4 (unicode_title, title_len,
239
 
                           (grub_uint8_t *) title, -1, 0);
240
 
  if (len < 0)
241
 
    {
242
 
      /* It is an invalid sequence.  */
243
 
      grub_free (unicode_title);
244
 
      return;
245
 
    }
246
 
 
247
 
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
248
 
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
249
 
  grub_term_setcolorstate (term, highlight
250
 
                           ? GRUB_TERM_COLOR_HIGHLIGHT
251
 
                           : GRUB_TERM_COLOR_NORMAL);
252
 
 
253
 
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
254
 
 
255
 
  for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
256
 
       x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
257
 
                  - GRUB_TERM_MARGIN);
258
 
       i++)
259
 
    {
260
 
      if (i < len
261
 
          && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
262
 
                         - GRUB_TERM_MARGIN - 1))
263
 
        {
264
 
          grub_ssize_t width;
265
 
 
266
 
          width = grub_term_getcharwidth (term, unicode_title[i]);
267
 
 
268
 
          if (x + width > (int) (GRUB_TERM_LEFT_BORDER_X 
269
 
                                 + grub_term_border_width (term)
270
 
                                 - GRUB_TERM_MARGIN - 1))
271
 
            grub_putcode (GRUB_TERM_DISP_RIGHT, term);
272
 
          else
273
 
            grub_putcode (unicode_title[i], term);
274
 
 
275
 
          x += width;
276
 
        }
277
 
      else
278
 
        {
279
 
          grub_putcode (' ', term);
280
 
          x++;
281
 
        }
282
 
    }
283
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
284
 
  grub_putcode (' ', term);
285
 
 
286
 
  grub_term_gotoxy (term, grub_term_cursor_x (term), y);
287
 
 
288
 
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
289
 
  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
290
 
  grub_free (unicode_title);
291
 
}
292
 
 
293
 
static void
294
 
print_entries (grub_menu_t menu, int first, int offset,
295
 
               struct grub_term_output *term)
296
 
{
297
 
  grub_menu_entry_t e;
298
 
  int i;
299
 
 
300
 
  grub_term_gotoxy (term,
301
 
                    GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
302
 
                    GRUB_TERM_FIRST_ENTRY_Y);
303
 
 
304
 
  if (first)
305
 
    grub_putcode (GRUB_TERM_DISP_UP, term);
306
 
  else
307
 
    grub_putcode (' ', term);
308
 
 
309
 
  e = grub_menu_get_entry (menu, first);
310
 
 
311
 
  for (i = 0; i < grub_term_num_entries (term); i++)
312
 
    {
313
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
314
 
      if (e)
315
 
        e = e->next;
316
 
    }
317
 
 
318
 
  grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X
319
 
                    + grub_term_border_width (term),
320
 
                    GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term));
321
 
 
322
 
  if (e)
323
 
    grub_putcode (GRUB_TERM_DISP_DOWN, term);
324
 
  else
325
 
    grub_putcode (' ', term);
326
 
 
327
 
  grub_term_gotoxy (term, grub_term_cursor_x (term),
328
 
                    GRUB_TERM_FIRST_ENTRY_Y + offset);
329
 
}
330
 
 
331
 
/* Initialize the screen.  If NESTED is non-zero, assume that this menu
332
 
   is run from another menu or a command-line. If EDIT is non-zero, show
333
 
   a message for the menu entry editor.  */
334
 
void
335
 
grub_menu_init_page (int nested, int edit,
336
 
                     struct grub_term_output *term)
337
 
{
338
 
  grub_uint8_t old_color_normal, old_color_highlight;
339
 
 
340
 
  grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
341
 
 
342
 
  /* By default, use the same colors for the menu.  */
343
 
  grub_color_menu_normal = old_color_normal;
344
 
  grub_color_menu_highlight = old_color_highlight;
345
 
 
346
 
  /* Then give user a chance to replace them.  */
347
 
  grub_parse_color_name_pair (&grub_color_menu_normal,
348
 
                              grub_env_get ("menu_color_normal"));
349
 
  grub_parse_color_name_pair (&grub_color_menu_highlight,
350
 
                              grub_env_get ("menu_color_highlight"));
351
 
 
352
 
  grub_normal_init_page (term);
353
 
  grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
354
 
  draw_border (term);
355
 
  grub_term_setcolor (term, old_color_normal, old_color_highlight);
356
 
  print_message (nested, edit, term);
357
 
}
358
 
 
359
 
static void
360
 
menu_text_print_timeout (int timeout, void *dataptr)
361
 
{
362
 
  const char *msg =
363
 
    _("The highlighted entry will be executed automatically in %ds.");
364
 
  struct menu_viewer_data *data = dataptr;
365
 
  char *msg_translated;
366
 
  int posx;
367
 
 
368
 
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
369
 
 
370
 
  msg_translated = grub_xasprintf (msg, timeout);
371
 
  if (!msg_translated)
372
 
    {
373
 
      grub_print_error ();
374
 
      grub_errno = GRUB_ERR_NONE;
375
 
      return;
376
 
    }
377
 
 
378
 
  grub_print_message_indented (msg_translated, 3, 0, data->term);
379
 
 
380
 
  posx = grub_term_getxy (data->term) >> 8;
381
 
  print_spaces (grub_term_width (data->term) - posx - 1, data->term);
382
 
 
383
 
  grub_term_gotoxy (data->term,
384
 
                    grub_term_cursor_x (data->term),
385
 
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
386
 
  grub_term_refresh (data->term);
387
 
}
388
 
 
389
 
static void
390
 
menu_text_set_chosen_entry (int entry, void *dataptr)
391
 
{
392
 
  struct menu_viewer_data *data = dataptr;
393
 
  int oldoffset = data->offset;
394
 
  int complete_redraw = 0;
395
 
 
396
 
  data->offset = entry - data->first;
397
 
  if (data->offset > grub_term_num_entries (data->term) - 1)
398
 
    {
399
 
      data->first = entry - (grub_term_num_entries (data->term) - 1);
400
 
      data->offset = grub_term_num_entries (data->term) - 1;
401
 
      complete_redraw = 1;
402
 
    }
403
 
  if (data->offset < 0)
404
 
    {
405
 
      data->offset = 0;
406
 
      data->first = entry;
407
 
      complete_redraw = 1;
408
 
    }
409
 
  if (complete_redraw)
410
 
    print_entries (data->menu, data->first, data->offset, data->term);
411
 
  else
412
 
    {
413
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
414
 
                   grub_menu_get_entry (data->menu, data->first + oldoffset),
415
 
                   data->term);
416
 
      print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
417
 
                   grub_menu_get_entry (data->menu, data->first + data->offset),
418
 
                   data->term);
419
 
    }
420
 
  grub_term_refresh (data->term);
421
 
}
422
 
 
423
 
static void
424
 
menu_text_fini (void *dataptr)
425
 
{
426
 
  struct menu_viewer_data *data = dataptr;
427
 
 
428
 
  grub_term_setcursor (data->term, 1);
429
 
  grub_term_cls (data->term);
430
 
 
431
 
}
432
 
 
433
 
static void
434
 
menu_text_clear_timeout (void *dataptr)
435
 
{
436
 
  struct menu_viewer_data *data = dataptr;
437
 
 
438
 
  grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
439
 
  print_spaces (grub_term_width (data->term) - 1, data->term);
440
 
  grub_term_gotoxy (data->term, grub_term_cursor_x (data->term),
441
 
                    GRUB_TERM_FIRST_ENTRY_Y + data->offset);
442
 
  grub_term_refresh (data->term);
443
 
}
444
 
 
445
 
grub_err_t 
446
 
grub_menu_try_text (struct grub_term_output *term, 
447
 
                    int entry, grub_menu_t menu, int nested)
448
 
{
449
 
  struct menu_viewer_data *data;
450
 
  struct grub_menu_viewer *instance;
451
 
 
452
 
  instance = grub_zalloc (sizeof (*instance));
453
 
  if (!instance)
454
 
    return grub_errno;
455
 
 
456
 
  data = grub_zalloc (sizeof (*data));
457
 
  if (!data)
458
 
    {
459
 
      grub_free (instance);
460
 
      return grub_errno;
461
 
    }
462
 
 
463
 
  data->term = term;
464
 
  instance->data = data;
465
 
  instance->set_chosen_entry = menu_text_set_chosen_entry;
466
 
  instance->print_timeout = menu_text_print_timeout;
467
 
  instance->clear_timeout = menu_text_clear_timeout;
468
 
  instance->fini = menu_text_fini;
469
 
 
470
 
  data->menu = menu;
471
 
 
472
 
  data->offset = entry;
473
 
  data->first = 0;
474
 
  if (data->offset > grub_term_num_entries (data->term) - 1)
475
 
    {
476
 
      data->first = data->offset - (grub_term_num_entries (data->term) - 1);
477
 
      data->offset = grub_term_num_entries (data->term) - 1;
478
 
    }
479
 
 
480
 
  grub_term_setcursor (data->term, 0);
481
 
  grub_menu_init_page (nested, 0, data->term);
482
 
  print_entries (menu, data->first, data->offset, data->term);
483
 
  grub_term_refresh (data->term);
484
 
  grub_menu_register_viewer (instance);
485
 
 
486
 
  return GRUB_ERR_NONE;
487
 
}