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
print_spaces (int number_spaces, struct grub_term_output *term)
45
for (i = 0; i < number_spaces; i++)
46
grub_putcode (' ', term);
50
grub_print_ucs4 (const grub_uint32_t * str,
51
const grub_uint32_t * last_position,
52
struct grub_term_output *term)
54
while (str < last_position)
56
grub_putcode (*str, term);
62
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
63
struct grub_term_output *term)
65
grub_ssize_t width = 0;
67
while (str < last_position)
69
width += grub_term_getcharwidth (term, *str);
76
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
77
struct grub_term_output *term)
81
grub_uint32_t *unicode_msg;
82
grub_uint32_t *last_position;
86
line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') *
87
(margin_left + margin_right);
89
msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
96
grub_uint32_t *current_position = unicode_msg;
98
grub_uint32_t *next_new_line = unicode_msg;
102
while (current_position < last_position)
105
grub_putcode ('\n', term);
107
next_new_line = (grub_uint32_t *) last_position;
109
while (grub_getstringwidth (current_position, next_new_line,term)
111
|| (next_new_line != last_position && *next_new_line != ' '
112
&& next_new_line > current_position))
117
if (next_new_line == current_position)
119
next_new_line = (next_new_line + line_len > last_position) ?
120
(grub_uint32_t *) last_position : next_new_line + line_len;
123
print_spaces (margin_left, term);
124
grub_print_ucs4 (current_position, next_new_line, term);
127
current_position = next_new_line;
130
grub_free (unicode_msg);
135
draw_border (struct grub_term_output *term)
139
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
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);
147
for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
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)
153
GRUB_TERM_TOP_BORDER_Y + i + 1);
154
grub_putcode (GRUB_TERM_DISP_VLINE, term);
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);
164
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
166
grub_term_gotoxy (term, GRUB_TERM_MARGIN,
167
(GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
168
+ GRUB_TERM_MARGIN + 1));
172
print_message (int nested, int edit, struct grub_term_output *term)
174
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
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,
186
const char *msg = _("Use the %C and %C keys to select which "
187
"entry is highlighted.\n");
188
char *msg_translated;
190
msg_translated = grub_xasprintf (msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
191
(grub_uint32_t) GRUB_TERM_DISP_DOWN);
195
grub_print_message_indented (msg_translated, STANDARD_MARGIN,
196
STANDARD_MARGIN, term);
198
grub_free (msg_translated);
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);
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);
220
print_entry (int y, int highlight, grub_menu_entry_t entry,
221
struct grub_term_output *term)
225
grub_size_t title_len;
227
grub_uint32_t *unicode_title;
229
grub_uint8_t old_color_normal, old_color_highlight;
231
title = entry ? entry->title : "";
232
title_len = grub_strlen (title);
233
unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
235
/* XXX How to show this error? */
238
len = grub_utf8_to_ucs4 (unicode_title, title_len,
239
(grub_uint8_t *) title, -1, 0);
242
/* It is an invalid sequence. */
243
grub_free (unicode_title);
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);
253
grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
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)
261
&& x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
262
- GRUB_TERM_MARGIN - 1))
266
width = grub_term_getcharwidth (term, unicode_title[i]);
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);
273
grub_putcode (unicode_title[i], term);
279
grub_putcode (' ', term);
283
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
284
grub_putcode (' ', term);
286
grub_term_gotoxy (term, grub_term_cursor_x (term), y);
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);
294
print_entries (grub_menu_t menu, int first, int offset,
295
struct grub_term_output *term)
300
grub_term_gotoxy (term,
301
GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
302
GRUB_TERM_FIRST_ENTRY_Y);
305
grub_putcode (GRUB_TERM_DISP_UP, term);
307
grub_putcode (' ', term);
309
e = grub_menu_get_entry (menu, first);
311
for (i = 0; i < grub_term_num_entries (term); i++)
313
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
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));
323
grub_putcode (GRUB_TERM_DISP_DOWN, term);
325
grub_putcode (' ', term);
327
grub_term_gotoxy (term, grub_term_cursor_x (term),
328
GRUB_TERM_FIRST_ENTRY_Y + offset);
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. */
335
grub_menu_init_page (int nested, int edit,
336
struct grub_term_output *term)
338
grub_uint8_t old_color_normal, old_color_highlight;
340
grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
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;
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"));
352
grub_normal_init_page (term);
353
grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
355
grub_term_setcolor (term, old_color_normal, old_color_highlight);
356
print_message (nested, edit, term);
360
menu_text_print_timeout (int timeout, void *dataptr)
363
_("The highlighted entry will be executed automatically in %ds.");
364
struct menu_viewer_data *data = dataptr;
365
char *msg_translated;
368
grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
370
msg_translated = grub_xasprintf (msg, timeout);
374
grub_errno = GRUB_ERR_NONE;
378
grub_print_message_indented (msg_translated, 3, 0, data->term);
380
posx = grub_term_getxy (data->term) >> 8;
381
print_spaces (grub_term_width (data->term) - posx - 1, data->term);
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);
390
menu_text_set_chosen_entry (int entry, void *dataptr)
392
struct menu_viewer_data *data = dataptr;
393
int oldoffset = data->offset;
394
int complete_redraw = 0;
396
data->offset = entry - data->first;
397
if (data->offset > grub_term_num_entries (data->term) - 1)
399
data->first = entry - (grub_term_num_entries (data->term) - 1);
400
data->offset = grub_term_num_entries (data->term) - 1;
403
if (data->offset < 0)
410
print_entries (data->menu, data->first, data->offset, data->term);
413
print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
414
grub_menu_get_entry (data->menu, data->first + oldoffset),
416
print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
417
grub_menu_get_entry (data->menu, data->first + data->offset),
420
grub_term_refresh (data->term);
424
menu_text_fini (void *dataptr)
426
struct menu_viewer_data *data = dataptr;
428
grub_term_setcursor (data->term, 1);
429
grub_term_cls (data->term);
434
menu_text_clear_timeout (void *dataptr)
436
struct menu_viewer_data *data = dataptr;
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);
446
grub_menu_try_text (struct grub_term_output *term,
447
int entry, grub_menu_t menu, int nested)
449
struct menu_viewer_data *data;
450
struct grub_menu_viewer *instance;
452
instance = grub_zalloc (sizeof (*instance));
456
data = grub_zalloc (sizeof (*data));
459
grub_free (instance);
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;
472
data->offset = entry;
474
if (data->offset > grub_term_num_entries (data->term) - 1)
476
data->first = data->offset - (grub_term_num_entries (data->term) - 1);
477
data->offset = grub_term_num_entries (data->term) - 1;
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);
486
return GRUB_ERR_NONE;