1
Description: Revamp hidden timeout handling
2
Add a new timeout_style environment variable and a corresponding
3
GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig. This controls
4
hidden-timeout handling more simply than the previous arrangements, and
5
pressing any hotkeys associated with menu entries during the hidden timeout
6
will now boot the corresponding menu entry immediately.
8
GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now generates a
9
warning, and if it shows the menu it will do so as if the second timeout
10
were not present. Other combinations are translated into reasonable
12
Author: Colin Watson <cjwatson@ubuntu.com>
13
Origin: backport, http://git.savannah.gnu.org/gitweb/?p=grub.git;a=commitdiff;h=44d488477902f0786d6bce44b74713f1713a34a9;hp=9e4e6ddfbfaad73e0c0f542c818c247135961c48
14
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1178618
15
Forwarded: https://lists.gnu.org/archive/html/grub-devel/2013-11/msg00388.html
16
Applied-Upstream: http://git.savannah.gnu.org/gitweb/?p=grub.git;a=commitdiff;h=44d488477902f0786d6bce44b74713f1713a34a9;hp=9e4e6ddfbfaad73e0c0f542c818c247135961c48
17
Last-Update: 2013-12-03
19
Index: b/docs/grub.texi
20
===================================================================
23
@@ -1134,22 +1134,26 @@
24
immediately without displaying the menu, or to @samp{-1} to wait
27
-@item GRUB_HIDDEN_TIMEOUT
28
-Wait this many seconds for a key to be pressed before displaying the menu.
29
-If no key is pressed during that time, display the menu for the number of
30
-seconds specified in GRUB_TIMEOUT before booting the default entry. We expect
31
-that most people who use GRUB_HIDDEN_TIMEOUT will want to have GRUB_TIMEOUT set
32
-to @samp{0} so that the menu is not displayed at all unless a key is pressed.
34
+If @samp{GRUB_TIMEOUT_STYLE} is set to @samp{countdown} or @samp{hidden},
35
+the timeout is instead counted before the menu is displayed.
37
-@item GRUB_HIDDEN_TIMEOUT_QUIET
38
-In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
39
-suppress the verbose countdown while waiting for a key to be pressed before
40
-displaying the menu. Unset by default.
41
+@item GRUB_TIMEOUT_STYLE
42
+If this option is unset or set to @samp{menu}, then GRUB will display the
43
+menu and then wait for the timeout set by @samp{GRUB_TIMEOUT} to expire
44
+before booting the default entry. Pressing a key interrupts the timeout.
46
+If this option is set to @samp{countdown} or @samp{hidden}, then, before
47
+displaying the menu, GRUB will wait for the timeout set by
48
+@samp{GRUB_TIMEOUT} to expire. If @key{ESC} is pressed during that time, it
49
+will display the menu and wait for input. If a hotkey associated with a
50
+menu entry is pressed, it will boot the associated menu entry immediately.
51
+If the timeout expires before either of these happens, it will boot the
52
+default entry. In the @samp{countdown} case, it will show a one-line
53
+indication of the remaining time.
55
@item GRUB_DEFAULT_BUTTON
56
@itemx GRUB_TIMEOUT_BUTTON
57
-@itemx GRUB_HIDDEN_TIMEOUT_BUTTON
58
+@itemx GRUB_TIMEOUT_STYLE_BUTTON
59
@itemx GRUB_BUTTON_CMOS_ADDRESS
60
Variants of the corresponding variables without the @samp{_BUTTON} suffix,
61
used to support vendor-specific power buttons. @xref{Vendor power-on keys}.
62
@@ -1291,6 +1295,44 @@
66
+The following options are still accepted for compatibility with existing
67
+configurations, but have better replacements:
70
+@item GRUB_HIDDEN_TIMEOUT
71
+Wait this many seconds before displaying the menu. If @key{ESC} is pressed
72
+during that time, display the menu and wait for input according to
73
+@samp{GRUB_TIMEOUT}. If a hotkey associated with a menu entry is pressed,
74
+boot the associated menu entry immediately. If the timeout expires before
75
+either of these happens, display the menu for the number of seconds
76
+specified in @samp{GRUB_TIMEOUT} before booting the default entry.
78
+If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set
79
+@samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless
80
+@key{ESC} is pressed.
82
+This option is unset by default, and is deprecated in favour of the less
83
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
84
+@samp{GRUB_TIMEOUT_STYLE=hidden}.
86
+@item GRUB_HIDDEN_TIMEOUT_QUIET
87
+In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
88
+suppress the verbose countdown while waiting for a key to be pressed before
91
+This option is unset by default, and is deprecated in favour of the less
92
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown}.
94
+@item GRUB_HIDDEN_TIMEOUT_BUTTON
95
+Variant of @samp{GRUB_HIDDEN_TIMEOUT}, used to support vendor-specific power
96
+buttons. @xref{Vendor power-on keys}.
98
+This option is unset by default, and is deprecated in favour of the less
99
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
100
+@samp{GRUB_TIMEOUT_STYLE=hidden}.
104
For more detailed customisation of @command{grub-mkconfig}'s output, you may
105
edit the scripts in @file{/etc/grub.d} directly.
106
@file{/etc/grub.d/40_custom} is particularly useful for adding entire custom
107
@@ -2137,15 +2179,16 @@
108
@node Vendor power-on keys
109
@chapter Using GRUB with vendor power-on keys
111
-Some laptop vendors provide an additional power-on button which boots another
112
-OS. GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
113
-@samp{GRUB_DEFAULT_BUTTON}, @samp{GRUB_HIDDEN_TIMEOUT_BUTTON} and
114
+Some laptop vendors provide an additional power-on button which boots
115
+another OS. GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
116
+@samp{GRUB_TIMEOUT_STYLE_BUTTON}, @samp{GRUB_DEFAULT_BUTTON}, and
117
@samp{GRUB_BUTTON_CMOS_ADDRESS} variables in default/grub (@pxref{Simple
118
-configuration}). @samp{GRUB_TIMEOUT_BUTTON}, @samp{GRUB_DEFAULT_BUTTON} and
119
-@samp{GRUB_HIDDEN_TIMEOUT_BUTTON} are used instead of the corresponding
120
-variables without the @samp{_BUTTON} suffix when powered on using the special
121
-button. @samp{GRUB_BUTTON_CMOS_ADDRESS} is vendor-specific and partially
122
-model-specific. Values known to the GRUB team are:
123
+configuration}). @samp{GRUB_TIMEOUT_BUTTON},
124
+@samp{GRUB_TIMEOUT_STYLE_BUTTON}, and @samp{GRUB_DEFAULT_BUTTON} are used
125
+instead of the corresponding variables without the @samp{_BUTTON} suffix
126
+when powered on using the special button. @samp{GRUB_BUTTON_CMOS_ADDRESS}
127
+is vendor-specific and partially model-specific. Values known to the GRUB
132
@@ -2629,6 +2672,7 @@
140
@@ -2966,8 +3010,21 @@
141
means to boot the default entry immediately without displaying the menu; a
142
timeout of @samp{-1} (or unset) means to wait indefinitely.
144
-This variable is often set by @samp{GRUB_TIMEOUT} or
145
-@samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}).
146
+If @samp{timeout_style} (@pxref{timeout_style}) is set to @samp{countdown}
147
+or @samp{hidden}, the timeout is instead counted before the menu is
150
+This variable is often set by @samp{GRUB_TIMEOUT} (@pxref{Simple
155
+@subsection timeout_style
157
+This variable may be set to @samp{menu}, @samp{countdown}, or @samp{hidden}
158
+to control the way in which the timeout (@pxref{timeout}) interacts with
159
+displaying the menu. See the documentation of @samp{GRUB_TIMEOUT_STYLE}
160
+(@pxref{Simple configuration}) for details.
163
@node Environment block
164
Index: b/grub-core/normal/main.c
165
===================================================================
166
--- a/grub-core/normal/main.c
167
+++ b/grub-core/normal/main.c
169
static const char *features[] = {
170
"feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
171
"feature_default_font_path", "feature_all_video_module",
172
- "feature_menuentry_id", "feature_menuentry_options", "feature_200_final"
173
+ "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
174
+ "feature_timeout_style"
177
GRUB_MOD_INIT(normal)
178
Index: b/grub-core/normal/menu.c
179
===================================================================
180
--- a/grub-core/normal/menu.c
181
+++ b/grub-core/normal/menu.c
183
grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
186
+enum timeout_style {
187
+ TIMEOUT_STYLE_MENU,
188
+ TIMEOUT_STYLE_COUNTDOWN,
189
+ TIMEOUT_STYLE_HIDDEN
192
+struct timeout_style_name {
194
+ enum timeout_style style;
195
+} timeout_style_names[] = {
196
+ {"menu", TIMEOUT_STYLE_MENU},
197
+ {"countdown", TIMEOUT_STYLE_COUNTDOWN},
198
+ {"hidden", TIMEOUT_STYLE_HIDDEN},
202
/* Wait until the user pushes any key so that the user
203
can see what happened. */
209
+/* Get the index of a menu entry associated with a given hotkey, or -1. */
211
+get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
213
+ grub_menu_entry_t entry;
216
+ for (i = 0, entry = menu->entry_list; i < menu->size;
217
+ i++, entry = entry->next)
218
+ if (entry->hotkey == hotkey)
224
+/* Return the timeout style. If the variable "timeout_style" is not set or
225
+ invalid, default to TIMEOUT_STYLE_MENU. */
226
+static enum timeout_style
227
+get_timeout_style (void)
230
+ struct timeout_style_name *style_name;
232
+ val = grub_env_get ("timeout_style");
234
+ return TIMEOUT_STYLE_MENU;
236
+ for (style_name = timeout_style_names; style_name->name; style_name++)
237
+ if (grub_strcmp (style_name->name, val) == 0)
238
+ return style_name->style;
240
+ return TIMEOUT_STYLE_MENU;
243
/* Return the current timeout. If the variable "timeout" is not set or
244
invalid, return -1. */
250
+/* Check whether a second has elapsed since the last tick. If so, adjust
251
+ the timer and return 1; otherwise, return 0. */
253
+has_second_elapsed (grub_uint64_t *saved_time)
255
+ grub_uint64_t current_time;
257
+ current_time = grub_get_time_ms ();
258
+ if (current_time - *saved_time >= 1000)
260
+ *saved_time = current_time;
268
+print_countdown (grub_uint16_t *pos, int n)
270
+ grub_term_restore_pos (pos);
271
+ /* NOTE: Do not remove the trailing space characters.
272
+ They are required to clear the line. */
273
+ grub_printf ("%d ", n);
277
#define GRUB_MENU_PAGE_SIZE 10
279
/* Show the menu and handle menu entry selection. Returns the menu entry
281
grub_uint64_t saved_time;
282
int default_entry, current_entry;
284
+ enum timeout_style timeout_style;
286
default_entry = get_entry_number (menu, "default");
289
if (default_entry < 0 || default_entry >= menu->size)
292
+ timeout = grub_menu_get_timeout ();
294
+ /* If there is no timeout, the "countdown" and "hidden" styles result in
295
+ the system doing nothing and providing no or very little indication
296
+ why. Technically this is what the user asked for, but it's not very
297
+ useful and likely to be a source of confusion, so we disallow this. */
298
+ grub_env_unset ("timeout_style");
300
+ timeout_style = get_timeout_style ();
302
+ if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
303
+ || timeout_style == TIMEOUT_STYLE_HIDDEN)
305
+ static grub_uint16_t *pos;
308
+ if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
310
+ pos = grub_term_save_pos ();
311
+ print_countdown (pos, timeout);
314
+ /* Enter interruptible sleep until Escape or a menu hotkey is pressed,
315
+ or the timeout expires. */
316
+ saved_time = grub_get_time_ms ();
321
+ key = grub_getkey_noblock ();
322
+ if (key != GRUB_TERM_NO_KEY)
324
+ entry = get_entry_index_by_hotkey (menu, key);
328
+ if (key == GRUB_TERM_ESC)
334
+ if (timeout > 0 && has_second_elapsed (&saved_time))
337
+ if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
338
+ print_countdown (pos, timeout);
342
+ /* We will fall through to auto-booting the default entry. */
346
+ grub_env_unset ("timeout");
347
+ grub_env_unset ("timeout_style");
355
/* If timeout is 0, drawing is pointless (and ugly). */
356
- if (grub_menu_get_timeout () == 0)
360
return default_entry;
361
@@ -535,18 +676,11 @@
362
if (grub_normal_exit_level)
366
+ if (timeout > 0 && has_second_elapsed (&saved_time))
368
- grub_uint64_t current_time;
370
- current_time = grub_get_time_ms ();
371
- if (current_time - saved_time >= 1000)
374
- grub_menu_set_timeout (timeout);
375
- saved_time = current_time;
376
- menu_print_timeout (timeout);
379
+ grub_menu_set_timeout (timeout);
380
+ menu_print_timeout (timeout);
384
@@ -648,16 +782,15 @@
388
- grub_menu_entry_t entry;
390
- for (i = 0, entry = menu->entry_list; i < menu->size;
391
- i++, entry = entry->next)
392
- if (entry->hotkey == c)
400
+ entry = get_entry_index_by_hotkey (menu, c);
410
Index: b/util/grub-mkconfig.in
411
===================================================================
412
--- a/util/grub-mkconfig.in
413
+++ b/util/grub-mkconfig.in
415
GRUB_HIDDEN_TIMEOUT \
416
GRUB_HIDDEN_TIMEOUT_QUIET \
418
+ GRUB_TIMEOUT_STYLE \
419
GRUB_DEFAULT_BUTTON \
420
GRUB_HIDDEN_TIMEOUT_BUTTON \
421
GRUB_TIMEOUT_BUTTON \
422
+ GRUB_TIMEOUT_STYLE_BUTTON \
423
GRUB_BUTTON_CMOS_ADDRESS \
424
GRUB_BUTTON_CMOS_CLEAN \
426
Index: b/util/grub.d/00_header.in
427
===================================================================
428
--- a/util/grub.d/00_header.in
429
+++ b/util/grub.d/00_header.in
430
@@ -272,15 +272,41 @@
434
- if [ "x${1}" != "x" ] ; then
435
- if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
437
+ if [ "x${1}${3}" != "x" ] ; then
438
+ if [ "x${3}" != "x" ] ; then
442
+ # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
444
+ if [ "x${2}" != "x0" ] ; then
445
+ grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")"
447
+ if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
453
+ if [ "x${style}" = "xcountdown" ] ; then
459
+if [ x\$feature_timeout_style = xy ] ; then
460
+ set timeout_style=${style}
461
+ set timeout=${timeout}
463
+ if [ "x${style}" != "xmenu" ] ; then
465
+# Fallback hidden-timeout code in case the timeout_style feature is
467
+elif sleep${verbose} --interruptible ${timeout} ; then
472
-if sleep$verbose --interruptible ${1} ; then
477
@@ -294,12 +320,12 @@
479
if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
481
-make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}"
482
+make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_STYLE_BUTTON}"
484
-make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
485
+make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
488
-make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
489
+make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
492
if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ] && [ "x$GRUB_BUTTON_CMOS_CLEAN" = "xyes" ]; then