1
/* menu_text.c - Basic text menu implementation. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
20
#include <grub/normal.h>
21
#include <grub/term.h>
22
#include <grub/misc.h>
23
#include <grub/loader.h>
25
#include <grub/time.h>
27
#include <grub/menu_viewer.h>
28
#include <grub/i18n.h>
29
#include <grub/charset.h>
31
static grub_uint8_t grub_color_menu_normal;
32
static grub_uint8_t grub_color_menu_highlight;
34
struct menu_viewer_data
38
struct grub_term_output *term;
42
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
43
struct grub_term_output *term)
45
grub_ssize_t width = 0;
47
while (str < last_position)
49
struct grub_unicode_glyph glyph;
50
str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph);
51
width += grub_term_getcharwidth (term, &glyph);
57
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
58
struct grub_term_output *term)
60
grub_uint32_t *unicode_msg;
61
grub_uint32_t *last_position;
65
msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
72
grub_print_ucs4 (unicode_msg, last_position, margin_left, margin_right, term);
74
grub_free (unicode_msg);
79
draw_border (struct grub_term_output *term)
83
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
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);
91
for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
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)
97
GRUB_TERM_TOP_BORDER_Y + i + 1);
98
grub_putcode (GRUB_UNICODE_VLINE, term);
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);
108
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
110
grub_term_gotoxy (term, GRUB_TERM_MARGIN,
111
(GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
112
+ GRUB_TERM_MARGIN + 1));
116
print_message (int nested, int edit, struct grub_term_output *term)
118
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
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);
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);
137
const char *msg = _("Use the %C and %C keys to select which "
138
"entry is highlighted.\n");
139
char *msg_translated;
141
msg_translated = grub_xasprintf (msg, GRUB_UNICODE_UPARROW,
142
GRUB_UNICODE_DOWNARROW);
145
grub_putcode ('\n', term);
146
grub_print_message_indented (msg_translated, STANDARD_MARGIN,
147
STANDARD_MARGIN, term);
149
grub_free (msg_translated);
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);
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);
171
print_entry (int y, int highlight, grub_menu_entry_t entry,
172
struct grub_term_output *term)
176
grub_size_t title_len;
178
grub_uint32_t *unicode_title;
180
grub_uint8_t old_color_normal, old_color_highlight;
182
title = entry ? entry->title : "";
183
title_len = grub_strlen (title);
184
unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
186
/* XXX How to show this error? */
189
len = grub_utf8_to_ucs4 (unicode_title, title_len,
190
(grub_uint8_t *) title, -1, 0);
193
/* It is an invalid sequence. */
194
grub_free (unicode_title);
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);
204
grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
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);)
212
&& x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
213
- GRUB_TERM_MARGIN - 1))
216
struct grub_unicode_glyph glyph;
218
i += grub_unicode_aglomerate_comb (unicode_title + i,
221
width = grub_term_getcharwidth (term, &glyph);
222
grub_free (glyph.combining);
224
if (x + width <= (int) (GRUB_TERM_LEFT_BORDER_X
225
+ grub_term_border_width (term)
226
- GRUB_TERM_MARGIN - 1))
234
grub_print_ucs4 (unicode_title,
235
unicode_title + last_printed, 0, 0, term);
237
if (last_printed != len)
239
grub_putcode (GRUB_UNICODE_RIGHTARROW, term);
240
struct grub_unicode_glyph pseudo_glyph = {
241
.base = GRUB_UNICODE_RIGHTARROW,
248
x += grub_term_getcharwidth (term, &pseudo_glyph);
251
for (; x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
252
- GRUB_TERM_MARGIN); x++)
253
grub_putcode (' ', term);
255
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
256
grub_putcode (' ', term);
258
grub_term_gotoxy (term, grub_term_cursor_x (term), y);
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);
266
print_entries (grub_menu_t menu, int first, int offset,
267
struct grub_term_output *term)
272
grub_term_gotoxy (term,
273
GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
274
GRUB_TERM_FIRST_ENTRY_Y);
277
grub_putcode (GRUB_UNICODE_UPARROW, term);
279
grub_putcode (' ', term);
281
e = grub_menu_get_entry (menu, first);
283
for (i = 0; i < grub_term_num_entries (term); i++)
285
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
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));
295
grub_putcode (GRUB_UNICODE_DOWNARROW, term);
297
grub_putcode (' ', term);
299
grub_term_gotoxy (term, grub_term_cursor_x (term),
300
GRUB_TERM_FIRST_ENTRY_Y + offset);
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. */
307
grub_menu_init_page (int nested, int edit,
308
struct grub_term_output *term)
310
grub_uint8_t old_color_normal, old_color_highlight;
312
grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
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;
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"));
324
grub_normal_init_page (term);
325
grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
327
grub_term_setcolor (term, old_color_normal, old_color_highlight);
328
print_message (nested, edit, term);
332
menu_text_print_timeout (int timeout, void *dataptr)
335
_("The highlighted entry will be executed automatically in %ds.");
336
struct menu_viewer_data *data = dataptr;
337
char *msg_translated;
340
grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
342
msg_translated = grub_xasprintf (msg, timeout);
346
grub_errno = GRUB_ERR_NONE;
350
grub_print_message_indented (msg_translated, 3, 0, data->term);
352
posx = grub_term_getxy (data->term) >> 8;
353
grub_print_spaces (data->term, grub_term_width (data->term) - posx - 1);
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);
362
menu_text_set_chosen_entry (int entry, void *dataptr)
364
struct menu_viewer_data *data = dataptr;
365
int oldoffset = data->offset;
366
int complete_redraw = 0;
368
data->offset = entry - data->first;
369
if (data->offset > grub_term_num_entries (data->term) - 1)
371
data->first = entry - (grub_term_num_entries (data->term) - 1);
372
data->offset = grub_term_num_entries (data->term) - 1;
375
if (data->offset < 0)
382
print_entries (data->menu, data->first, data->offset, data->term);
385
print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
386
grub_menu_get_entry (data->menu, data->first + oldoffset),
388
print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
389
grub_menu_get_entry (data->menu, data->first + data->offset),
392
grub_term_refresh (data->term);
396
menu_text_fini (void *dataptr)
398
struct menu_viewer_data *data = dataptr;
400
grub_term_setcursor (data->term, 1);
401
grub_term_cls (data->term);
406
menu_text_clear_timeout (void *dataptr)
408
struct menu_viewer_data *data = dataptr;
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);
418
grub_menu_try_text (struct grub_term_output *term,
419
int entry, grub_menu_t menu, int nested)
421
struct menu_viewer_data *data;
422
struct grub_menu_viewer *instance;
424
instance = grub_zalloc (sizeof (*instance));
428
data = grub_zalloc (sizeof (*data));
431
grub_free (instance);
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;
444
data->offset = entry;
446
if (data->offset > grub_term_num_entries (data->term) - 1)
448
data->first = data->offset - (grub_term_num_entries (data->term) - 1);
449
data->offset = grub_term_num_entries (data->term) - 1;
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);
458
return GRUB_ERR_NONE;