All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH] Allow hotkeys to interrupt hidden menu
@ 2013-09-11 13:18 Colin Watson
  2013-09-11 13:31 ` Colin Watson
  2013-09-12  2:44 ` Andrey Borzenkov
  0 siblings, 2 replies; 29+ messages in thread
From: Colin Watson @ 2013-09-11 13:18 UTC (permalink / raw)
  To: grub-devel; +Cc: Franz Hsieh

One of my colleagues, Franz Hsieh (CCed) sent this patch to
https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1178618.  It has a
few minor implementation issues, and I'll follow up with my own review
in a few minutes (it certainly also requires rebasing to apply properly
to trunk), but I wanted to ask what people thought of the design,
particularly since it adds new configuration options.  The basic idea is
to allow a hidden menu (sleep --interruptible) to be interrupted by a
hotkey which is then passed on to the menu code, so that you can use
menuentry --hotkey and still hotkey-select an item from the hidden menu.

I suggested adding an "unput"-type feature to the terminal layer to
support this, but the approach used here of stuffing the hotkey into an
environment variable should work just as well and avoids the need to add
more code to the kernel.

Index: grub2-1.99/grub-core/commands/sleep.c
===================================================================
--- grub2-1.99.orig/grub-core/commands/sleep.c	2013-06-13 10:15:08.574977456 +0800
+++ grub2-1.99/grub-core/commands/sleep.c	2013-06-13 10:15:09.366977489 +0800
@@ -24,6 +24,7 @@
 #include <grub/misc.h>
 #include <grub/extcmd.h>
 #include <grub/i18n.h>
+#include <grub/env.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -31,9 +32,31 @@
   {
     {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0},
     {"interruptible", 'i', 0, N_("Interruptible with ESC."), 0, 0},
+    {"function-key", 'f', 0,
+     N_("Interruptible with function key."), "KEY", ARG_TYPE_STRING},
     {0, 0, 0, 0, 0, 0}
   };
 
+static struct
+{
+  char *name;
+  int key;
+} function_key_aliases[] =
+  {
+    {"f1", GRUB_TERM_KEY_F1},
+    {"f2", GRUB_TERM_KEY_F2},
+    {"f3", GRUB_TERM_KEY_F3},
+    {"f4", GRUB_TERM_KEY_F4},
+    {"f5", GRUB_TERM_KEY_F5},
+    {"f6", GRUB_TERM_KEY_F6},
+    {"f7", GRUB_TERM_KEY_F7},
+    {"f8", GRUB_TERM_KEY_F8},
+    {"f9", GRUB_TERM_KEY_F9},
+    {"f10", GRUB_TERM_KEY_F10},
+    {"f11", GRUB_TERM_KEY_F11},
+    {"f12", GRUB_TERM_KEY_F12},
+  };
+
 static grub_uint16_t *pos;
 
 static void
@@ -46,7 +69,21 @@
 }
 
 static int
-grub_check_keyboard (void)
+grub_parse_function_key(const char* name)
+{
+  unsigned i;
+  if (!name)
+    return 0;
+
+  for (i = 0; i < ARRAY_SIZE (function_key_aliases); i++)
+    if (grub_strcmp (name, function_key_aliases[i].name) == 0)
+      return function_key_aliases[i].key;
+
+  return 0;
+}
+
+static int
+grub_check_keyboard (int fnkey)
 {
   int mods = 0;
   grub_term_input_t term;
@@ -64,22 +101,34 @@
       (mods & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) != 0)
     return 1;
 
-  if (grub_checkkey () >= 0 && grub_getkey () == GRUB_TERM_ESC)
-    return 1;
+  if (grub_checkkey () >= 0)
+    {
+      int key = grub_getkey();
+      if (key == GRUB_TERM_ESC)
+	return 1;
+
+      if (key == fnkey)
+	{
+	  char hotkey[32] = {0};
+	  grub_snprintf(hotkey, 32, "%d", key);
+	  grub_env_set("hotkey", (char*)&hotkey);
+	  return 1;
+	}
+    }
 
   return 0;
 }
 
 /* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
-grub_interruptible_millisleep (grub_uint32_t ms)
+grub_interruptible_millisleep (grub_uint32_t ms, int key)
 {
   grub_uint64_t start;
 
   start = grub_get_time_ms ();
 
   while (grub_get_time_ms () - start < ms)
-    if (grub_check_keyboard ())
+    if (grub_check_keyboard (key))
       return 1;
 
   return 0;
@@ -90,6 +139,7 @@
 {
   struct grub_arg_list *state = ctxt->state;
   int n;
+  int key = 0;
 
   if (argc != 1)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing operand");
@@ -104,14 +154,21 @@
 
   pos = grub_term_save_pos ();
 
+  if (state[2].set)
+    {
+      key = grub_parse_function_key(state[2].arg);
+      if (key == 0)
+	return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid function key");
+    }
+
   for (; n; n--)
     {
       if (state[0].set)
 	do_print (n);
 
-      if (state[1].set)
+      if (state[1].set || state[2].set)
 	{
-	  if (grub_interruptible_millisleep (1000))
+	  if (grub_interruptible_millisleep (1000, key))
 	    return 1;
 	}
       else
Index: grub2-1.99/grub-core/normal/menu.c
===================================================================
--- grub2-1.99.orig/grub-core/normal/menu.c	2013-06-13 10:15:08.618977458 +0800
+++ grub2-1.99/grub-core/normal/menu.c	2013-06-13 10:15:09.370977489 +0800
@@ -103,6 +103,33 @@
   return timeout;
 }
 
+int
+grub_menu_get_hotkey (void)
+{
+  char *val;
+  int hotkey;
+
+  val = grub_env_get ("hotkey");
+  if (! val)
+    return -1;
+
+  grub_error_push();
+
+  hotkey = (int) grub_strtoul (val, 0, 10);
+
+  /* If the value is invalid, unset the variable.  */
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_env_unset ("hotkey");
+      grub_errno = GRUB_ERR_NONE;
+      hotkey = -1;
+    }
+
+  grub_error_pop ();
+
+  return hotkey;
+}
+
 /* Set current timeout in the variable "timeout".  */
 void
 grub_menu_set_timeout (int timeout)
@@ -481,6 +508,21 @@
   return entry;
 }
 
+static int
+get_menuentry_by_hotkey(grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      {
+	menu_fini ();
+	return i;
+      }
+  return 0;
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -495,14 +537,23 @@
   grub_uint64_t saved_time;
   int default_entry, current_entry;
   int timeout;
+  int hotkey = 0;
 
   default_entry = get_entry_number (menu, "default");
+  hotkey = grub_menu_get_hotkey ();
 
   /* If DEFAULT_ENTRY is not within the menu entries, fall back to
      the first entry.  */
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  /* check if hotkey is set */
+  if (hotkey > 0 && (current_entry = get_menuentry_by_hotkey(menu, hotkey)) > 0)
+    {
+      *auto_boot = 1;
+      return current_entry;
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
   if (grub_menu_get_timeout () == 0)
     {
@@ -646,16 +697,12 @@
 
 	    default:
 	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
+		int entry = get_menuentry_by_hotkey(menu, c);
+		if (entry > 0)
+		  {
+		    *auto_boot = 0;
+		    return entry;
+		  }
 	      }
 	      break;
 	    }
Index: grub2-1.99/util/grub-mkconfig.in
===================================================================
--- grub2-1.99.orig/util/grub-mkconfig.in	2013-06-13 10:15:09.322977487 +0800
+++ grub2-1.99/util/grub-mkconfig.in	2013-06-13 10:16:33.954980977 +0800
@@ -251,7 +251,8 @@
   GRUB_INIT_TUNE \
   GRUB_SAVEDEFAULT \
   GRUB_BADRAM \
-  GRUB_RECORDFAIL_TIMEOUT
+  GRUB_RECORDFAIL_TIMEOUT \
+  GRUB_HIDDEN_TIMEOUT_HOTKEY
 
 if test "x${grub_cfg}" != "x"; then
   rm -f ${grub_cfg}.new
Index: grub2-1.99/util/grub.d/30_os-prober.in
===================================================================
--- grub2-1.99.orig/util/grub.d/30_os-prober.in	2013-06-13 10:15:09.010977474 +0800
+++ grub2-1.99/util/grub.d/30_os-prober.in	2013-06-13 10:22:12.534994943 +0800
@@ -34,6 +34,12 @@
 	verbose=" --verbose"
       fi
 
+      if [ "x${GRUB_HIDDEN_TIMEOUT_HOTKEY}" = "x" ] ; then
+        hotkey=
+      else
+        hotkey=" --function-key ${GRUB_HIDDEN_TIMEOUT_HOTKEY}"
+      fi
+
       if [ "x${1}" = "x0" ] ; then
 	cat <<EOF
 if [ "x\${timeout}" != "x-1" ]; then
@@ -44,7 +50,7 @@
       set timeout=0
     fi
   else
-    if sleep$verbose --interruptible 3 ; then
+    if sleep$verbose --interruptible 3$hotkey ; then
       set timeout=0
     fi
   fi
@@ -53,7 +59,7 @@
       else
 	cat << EOF
 if [ "x\${timeout}" != "x-1" ]; then
-  if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT} ; then
+  if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT}$hotkey ; then
     set timeout=0
   fi
 fi

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-11 13:18 [RFC][PATCH] Allow hotkeys to interrupt hidden menu Colin Watson
@ 2013-09-11 13:31 ` Colin Watson
  2013-09-12  2:40   ` Andrey Borzenkov
  2013-09-13  9:18   ` Franz Hsieh
  2013-09-12  2:44 ` Andrey Borzenkov
  1 sibling, 2 replies; 29+ messages in thread
From: Colin Watson @ 2013-09-11 13:31 UTC (permalink / raw)
  To: grub-devel; +Cc: Franz Hsieh

Hi Franz,

Throughout this patch, please take care to adhere to the GRUB coding
style.  This is definitely an improvement over previous versions I've
reviewed, but it still has a number of places where functions are called
or declared with no space before the opening parenthesis.  That is,
"function()" should become "function ()".  I know it's a minor point,
but it makes code much easier to read when it's all in the same style.

On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
wrote:
> +static struct
> +{
> +  char *name;
> +  int key;
> +} function_key_aliases[] =
> +  {
> +    {"f1", GRUB_TERM_KEY_F1},
> +    {"f2", GRUB_TERM_KEY_F2},
> +    {"f3", GRUB_TERM_KEY_F3},
> +    {"f4", GRUB_TERM_KEY_F4},
> +    {"f5", GRUB_TERM_KEY_F5},
> +    {"f6", GRUB_TERM_KEY_F6},
> +    {"f7", GRUB_TERM_KEY_F7},
> +    {"f8", GRUB_TERM_KEY_F8},
> +    {"f9", GRUB_TERM_KEY_F9},
> +    {"f10", GRUB_TERM_KEY_F10},
> +    {"f11", GRUB_TERM_KEY_F11},
> +    {"f12", GRUB_TERM_KEY_F12},
> +  };
> +

This is essentially a copy of hotkey_aliases from
grub-core/commands/menuentry.c, and there's duplicated lookup code as
well.  Can you find any way to share it?  Since we certainly don't want
to put this in the kernel, and neither the sleep module nor the normal
module really ought to depend on the other, I suspect that doing so
would require a new module for shared menu code, which may well be
overkill for this, but it's worth a look.

At the very least it would be a good idea to bring the contents of this
structure into sync with hotkey_aliases and add comments to encourage
developers to keep them that way.

I think we should also call this kind of thing simply "hotkey"
consistently across the code, rather than it sometimes being
"function_key" or "fnkey".

> +      if (key == fnkey)
> +	{
> +	  char hotkey[32] = {0};
> +	  grub_snprintf(hotkey, 32, "%d", key);
> +	  grub_env_set("hotkey", (char*)&hotkey);
> +	  return 1;
> +	}

We've generally tried to get rid of this kind of static allocation.  Use
grub_xasprintf instead:

  if (key == fnkey)
    {
      char *hotkey = grub_xasprintf ("%d", key);
      grub_env_set ("hotkey", hotkey);
      grub_free (hotkey);
      return 1;
    }

> +int
> +grub_menu_get_hotkey (void)

This function is only used in this file, so it should be static.

> Index: grub2-1.99/util/grub-mkconfig.in
> ===================================================================
> --- grub2-1.99.orig/util/grub-mkconfig.in	2013-06-13 10:15:09.322977487 +0800
> +++ grub2-1.99/util/grub-mkconfig.in	2013-06-13 10:16:33.954980977 +0800
> @@ -251,7 +251,8 @@
>    GRUB_INIT_TUNE \
>    GRUB_SAVEDEFAULT \
>    GRUB_BADRAM \
> -  GRUB_RECORDFAIL_TIMEOUT
> +  GRUB_RECORDFAIL_TIMEOUT \
> +  GRUB_HIDDEN_TIMEOUT_HOTKEY
>  
>  if test "x${grub_cfg}" != "x"; then
>    rm -f ${grub_cfg}.new
> Index: grub2-1.99/util/grub.d/30_os-prober.in
> ===================================================================
> --- grub2-1.99.orig/util/grub.d/30_os-prober.in	2013-06-13 10:15:09.010977474 +0800
> +++ grub2-1.99/util/grub.d/30_os-prober.in	2013-06-13 10:22:12.534994943 +0800
> @@ -34,6 +34,12 @@
>  	verbose=" --verbose"
>        fi
>  
> +      if [ "x${GRUB_HIDDEN_TIMEOUT_HOTKEY}" = "x" ] ; then
> +        hotkey=
> +      else
> +        hotkey=" --function-key ${GRUB_HIDDEN_TIMEOUT_HOTKEY}"
> +      fi
> +
>        if [ "x${1}" = "x0" ] ; then
>  	cat <<EOF
>  if [ "x\${timeout}" != "x-1" ]; then
> @@ -44,7 +50,7 @@
>        set timeout=0
>      fi
>    else
> -    if sleep$verbose --interruptible 3 ; then
> +    if sleep$verbose --interruptible 3$hotkey ; then
>        set timeout=0
>      fi
>    fi
> @@ -53,7 +59,7 @@
>        else
>  	cat << EOF
>  if [ "x\${timeout}" != "x-1" ]; then
> -  if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT} ; then
> +  if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT}$hotkey ; then
>      set timeout=0
>    fi
>  fi

Rather than having to configure this explicitly, I have an alternative
suggestion, which ties into my earlier suggestion of making the hotkey
code a bit more shared.  Why not have sleep --interruptible look up the
hotkeys configured in the menu and automatically honour any of those?
That way you wouldn't have to configure hotkeys in two places (grub.cfg
and /etc/default/grub).  Plus, I'm always more comfortable with patches
that don't require adding configuration options.

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-11 13:31 ` Colin Watson
@ 2013-09-12  2:40   ` Andrey Borzenkov
  2013-09-13  9:18   ` Franz Hsieh
  1 sibling, 0 replies; 29+ messages in thread
From: Andrey Borzenkov @ 2013-09-12  2:40 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Franz Hsieh, cjwatson

В Wed, 11 Sep 2013 14:31:29 +0100
Colin Watson <cjwatson@ubuntu.com> пишет:

> 
> Rather than having to configure this explicitly, I have an alternative
> suggestion, which ties into my earlier suggestion of making the hotkey
> code a bit more shared.  Why not have sleep --interruptible look up the
> hotkeys configured in the menu and automatically honour any of those?

+1

> That way you wouldn't have to configure hotkeys in two places (grub.cfg
> and /etc/default/grub).  Plus, I'm always more comfortable with patches
> that don't require adding configuration options.
> 
> Thanks,
> 



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-11 13:18 [RFC][PATCH] Allow hotkeys to interrupt hidden menu Colin Watson
  2013-09-11 13:31 ` Colin Watson
@ 2013-09-12  2:44 ` Andrey Borzenkov
  2013-09-12 13:17   ` Colin Watson
  1 sibling, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-09-12  2:44 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Franz Hsieh, cjwatson

В Wed, 11 Sep 2013 14:18:04 +0100
Colin Watson <cjwatson@ubuntu.com> пишет:

>  
> +int
> +grub_menu_get_hotkey (void)
> +{
> +  char *val;
> +  int hotkey;
> +
> +  val = grub_env_get ("hotkey");
> +  if (! val)
> +    return -1;
> +
> +  grub_error_push();
> +
> +  hotkey = (int) grub_strtoul (val, 0, 10);
> +
> +  /* If the value is invalid, unset the variable.  */

Why only if invalid? This is one time event which should be reset as
soon as it is consumed.

Actually I'm not sure if user visible environment variable is needed at
all - just make it a global variable in normal.mod. 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-12  2:44 ` Andrey Borzenkov
@ 2013-09-12 13:17   ` Colin Watson
  0 siblings, 0 replies; 29+ messages in thread
From: Colin Watson @ 2013-09-12 13:17 UTC (permalink / raw)
  To: Andrey Borzenkov; +Cc: The development of GNU GRUB, Franz Hsieh

On Thu, Sep 12, 2013 at 06:44:19AM +0400, Andrey Borzenkov wrote:
> В Wed, 11 Sep 2013 14:18:04 +0100
> > +int
> > +grub_menu_get_hotkey (void)
> > +{
> > +  char *val;
> > +  int hotkey;
> > +
> > +  val = grub_env_get ("hotkey");
> > +  if (! val)
> > +    return -1;
> > +
> > +  grub_error_push();
> > +
> > +  hotkey = (int) grub_strtoul (val, 0, 10);
> > +
> > +  /* If the value is invalid, unset the variable.  */
> 
> Why only if invalid? This is one time event which should be reset as
> soon as it is consumed.

Agreed.

> Actually I'm not sure if user visible environment variable is needed at
> all - just make it a global variable in normal.mod. 

This goes back to what I was saying about sleep.mod not being sensibly
able to depend on normal.mod, so in order to do this kind of this we
either need shared code in the kernel (best avoided) or a new module
common to both.

(Or we could do something like exporting grub_dl_resolve_symbol so that
we have dlsym-like functionality.  But this is starting to look rather
baroque just for the sake of avoiding a transient environment variable,
IMO.)

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-11 13:31 ` Colin Watson
  2013-09-12  2:40   ` Andrey Borzenkov
@ 2013-09-13  9:18   ` Franz Hsieh
  2013-09-19  6:28     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-02  8:03     ` Franz Hsieh
  1 sibling, 2 replies; 29+ messages in thread
From: Franz Hsieh @ 2013-09-13  9:18 UTC (permalink / raw)
  To: Colin Watson; +Cc: grub-devel

[-- Attachment #1: Type: text/plain, Size: 3612 bytes --]

On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com> wrote:

> Hi Franz,
>
> Throughout this patch, please take care to adhere to the GRUB coding
> style.  This is definitely an improvement over previous versions I've
> reviewed, but it still has a number of places where functions are called
> or declared with no space before the opening parenthesis.  That is,
> "function()" should become "function ()".  I know it's a minor point,
> but it makes code much easier to read when it's all in the same style.
>
> On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
> wrote:
> > +static struct
> > +{
> > +  char *name;
> > +  int key;
> > +} function_key_aliases[] =
> > +  {
> > +    {"f1", GRUB_TERM_KEY_F1},
> > +    {"f2", GRUB_TERM_KEY_F2},
> > +    {"f3", GRUB_TERM_KEY_F3},
> > +    {"f4", GRUB_TERM_KEY_F4},
> > +    {"f5", GRUB_TERM_KEY_F5},
> > +    {"f6", GRUB_TERM_KEY_F6},
> > +    {"f7", GRUB_TERM_KEY_F7},
> > +    {"f8", GRUB_TERM_KEY_F8},
> > +    {"f9", GRUB_TERM_KEY_F9},
> > +    {"f10", GRUB_TERM_KEY_F10},
> > +    {"f11", GRUB_TERM_KEY_F11},
> > +    {"f12", GRUB_TERM_KEY_F12},
> > +  };
> > +
>
> This is essentially a copy of hotkey_aliases from
> grub-core/commands/menuentry.c, and there's duplicated lookup code as
> well.  Can you find any way to share it?  Since we certainly don't want
> to put this in the kernel, and neither the sleep module nor the normal
> module really ought to depend on the other, I suspect that doing so
> would require a new module for shared menu code, which may well be
> overkill for this, but it's worth a look.
>

I also agree to remove duplicate code, but seems not easy to do it unless
we have a shared module, right? Well it would take me some time to evaluate.

At the very least it would be a good idea to bring the contents of this
> structure into sync with hotkey_aliases and add comments to encourage
> developers to keep them that way.
>
> I think we should also call this kind of thing simply "hotkey"
> consistently across the code, rather than it sometimes being
> "function_key" or "fnkey".
>


>
> > +      if (key == fnkey)
> > +     {
> > +       char hotkey[32] = {0};
> > +       grub_snprintf(hotkey, 32, "%d", key);
> > +       grub_env_set("hotkey", (char*)&hotkey);
> > +       return 1;
> > +     }
>
> We've generally tried to get rid of this kind of static allocation.  Use
> grub_xasprintf instead:
>
>   if (key == fnkey)
>     {
>       char *hotkey = grub_xasprintf ("%d", key);
>       grub_env_set ("hotkey", hotkey);
>       grub_free (hotkey);
>       return 1;
>     }
>
> > +int
> > +grub_menu_get_hotkey (void)
>
> This function is only used in this file, so it should be static.
>

These idea are good and I will do these changes in my patch.

Rather than having to configure this explicitly, I have an alternative
> suggestion, which ties into my earlier suggestion of making the hotkey
> code a bit more shared.  Why not have sleep --interruptible look up the
> hotkeys configured in the menu and automatically honour any of those?
> That way you wouldn't have to configure hotkeys in two places (grub.cfg
> and /etc/default/grub).  Plus, I'm always more comfortable with patches
> that don't require adding configuration options.
>

Agree with Colin's points and I will update the patch.
By the way I would like to combine --function-key and --interruptible. I
think
it is a simple way that sleep.mod always checks ESC for interrupt and
f1~f12 for the
hotkey.

Thanks for your reviews and if there is any good suggestion, please feel
free to tell me.

Regards,
Franz Hsieh

[-- Attachment #2: Type: text/html, Size: 5131 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-13  9:18   ` Franz Hsieh
@ 2013-09-19  6:28     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-02  8:03     ` Franz Hsieh
  1 sibling, 0 replies; 29+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-19  6:28 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 2201 bytes --]

On 13.09.2013 11:18, Franz Hsieh wrote:
> 
> 
> 
> On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com
> <mailto:cjwatson@ubuntu.com>> wrote:
> 
>     Hi Franz,
> 
>     Throughout this patch, please take care to adhere to the GRUB coding
>     style.  This is definitely an improvement over previous versions I've
>     reviewed, but it still has a number of places where functions are called
>     or declared with no space before the opening parenthesis.  That is,
>     "function()" should become "function ()".  I know it's a minor point,
>     but it makes code much easier to read when it's all in the same style.
> 
>     On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
>     wrote:
>     > +static struct
>     > +{
>     > +  char *name;
>     > +  int key;
>     > +} function_key_aliases[] =
>     > +  {
>     > +    {"f1", GRUB_TERM_KEY_F1},
>     > +    {"f2", GRUB_TERM_KEY_F2},
>     > +    {"f3", GRUB_TERM_KEY_F3},
>     > +    {"f4", GRUB_TERM_KEY_F4},
>     > +    {"f5", GRUB_TERM_KEY_F5},
>     > +    {"f6", GRUB_TERM_KEY_F6},
>     > +    {"f7", GRUB_TERM_KEY_F7},
>     > +    {"f8", GRUB_TERM_KEY_F8},
>     > +    {"f9", GRUB_TERM_KEY_F9},
>     > +    {"f10", GRUB_TERM_KEY_F10},
>     > +    {"f11", GRUB_TERM_KEY_F11},
>     > +    {"f12", GRUB_TERM_KEY_F12},
>     > +  };
>     > +
> 
>     This is essentially a copy of hotkey_aliases from
>     grub-core/commands/menuentry.c, and there's duplicated lookup code as
>     well.  Can you find any way to share it?  Since we certainly don't want
>     to put this in the kernel, and neither the sleep module nor the normal
>     module really ought to depend on the other, I suspect that doing so
>     would require a new module for shared menu code, which may well be
>     overkill for this, but it's worth a look.
> 
> 
> I also agree to remove duplicate code, but seems not easy to do it unless
> we have a shared module, right? Well it would take me some time to evaluate.
Why not just allow any key interrupt sleep and if it's not escape using
ungetc-like code (with real ungetc code or global variable of some kind)?


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-09-13  9:18   ` Franz Hsieh
  2013-09-19  6:28     ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-10-02  8:03     ` Franz Hsieh
  2013-10-02  8:50       ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-14  6:02       ` Franz Hsieh
  1 sibling, 2 replies; 29+ messages in thread
From: Franz Hsieh @ 2013-10-02  8:03 UTC (permalink / raw)
  To: grub-devel; +Cc: Colin Watson


[-- Attachment #1.1: Type: text/plain, Size: 4073 bytes --]

Hi, there

  I had merged the patch for enabling hotkey in grub silent mode to
grub-trunk.
  The --function-key now has been removed from sleep.mod, now sleep.mod will
  monitor all function keys, delete, tab and backspace.

Thanks!

Franz Hsieh


On Fri, Sep 13, 2013 at 5:18 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:

>
>
>
> On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com> wrote:
>
>> Hi Franz,
>>
>> Throughout this patch, please take care to adhere to the GRUB coding
>> style.  This is definitely an improvement over previous versions I've
>> reviewed, but it still has a number of places where functions are called
>> or declared with no space before the opening parenthesis.  That is,
>> "function()" should become "function ()".  I know it's a minor point,
>> but it makes code much easier to read when it's all in the same style.
>>
>> On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
>> wrote:
>> > +static struct
>> > +{
>> > +  char *name;
>> > +  int key;
>> > +} function_key_aliases[] =
>> > +  {
>> > +    {"f1", GRUB_TERM_KEY_F1},
>> > +    {"f2", GRUB_TERM_KEY_F2},
>> > +    {"f3", GRUB_TERM_KEY_F3},
>> > +    {"f4", GRUB_TERM_KEY_F4},
>> > +    {"f5", GRUB_TERM_KEY_F5},
>> > +    {"f6", GRUB_TERM_KEY_F6},
>> > +    {"f7", GRUB_TERM_KEY_F7},
>> > +    {"f8", GRUB_TERM_KEY_F8},
>> > +    {"f9", GRUB_TERM_KEY_F9},
>> > +    {"f10", GRUB_TERM_KEY_F10},
>> > +    {"f11", GRUB_TERM_KEY_F11},
>> > +    {"f12", GRUB_TERM_KEY_F12},
>> > +  };
>> > +
>>
>> This is essentially a copy of hotkey_aliases from
>> grub-core/commands/menuentry.c, and there's duplicated lookup code as
>> well.  Can you find any way to share it?  Since we certainly don't want
>> to put this in the kernel, and neither the sleep module nor the normal
>> module really ought to depend on the other, I suspect that doing so
>> would require a new module for shared menu code, which may well be
>> overkill for this, but it's worth a look.
>>
>
> I also agree to remove duplicate code, but seems not easy to do it unless
> we have a shared module, right? Well it would take me some time to
> evaluate.
>
> At the very least it would be a good idea to bring the contents of this
>> structure into sync with hotkey_aliases and add comments to encourage
>> developers to keep them that way.
>>
>> I think we should also call this kind of thing simply "hotkey"
>> consistently across the code, rather than it sometimes being
>> "function_key" or "fnkey".
>>
>
>
>>
>> > +      if (key == fnkey)
>> > +     {
>> > +       char hotkey[32] = {0};
>> > +       grub_snprintf(hotkey, 32, "%d", key);
>> > +       grub_env_set("hotkey", (char*)&hotkey);
>> > +       return 1;
>> > +     }
>>
>> We've generally tried to get rid of this kind of static allocation.  Use
>> grub_xasprintf instead:
>>
>>   if (key == fnkey)
>>     {
>>       char *hotkey = grub_xasprintf ("%d", key);
>>       grub_env_set ("hotkey", hotkey);
>>       grub_free (hotkey);
>>       return 1;
>>     }
>>
>> > +int
>> > +grub_menu_get_hotkey (void)
>>
>> This function is only used in this file, so it should be static.
>>
>
> These idea are good and I will do these changes in my patch.
>
> Rather than having to configure this explicitly, I have an alternative
>> suggestion, which ties into my earlier suggestion of making the hotkey
>> code a bit more shared.  Why not have sleep --interruptible look up the
>> hotkeys configured in the menu and automatically honour any of those?
>> That way you wouldn't have to configure hotkeys in two places (grub.cfg
>> and /etc/default/grub).  Plus, I'm always more comfortable with patches
>> that don't require adding configuration options.
>>
>
> Agree with Colin's points and I will update the patch.
> By the way I would like to combine --function-key and --interruptible. I
> think
> it is a simple way that sleep.mod always checks ESC for interrupt and
> f1~f12 for the
> hotkey.
>
> Thanks for your reviews and if there is any good suggestion, please feel
> free to tell me.
>
> Regards,
> Franz Hsieh
>
>

[-- Attachment #1.2: Type: text/html, Size: 5915 bytes --]

[-- Attachment #2: grub2-enable-hotkey-in-silent-mode.patch --]
[-- Type: application/octet-stream, Size: 4506 bytes --]

=== modified file 'grub-core/commands/sleep.c'
--- a/grub-core/commands/sleep.c	2013-07-11 14:02:22 +0000
+++ b/grub-core/commands/sleep.c	2013-10-01 08:18:24 +0000
@@ -24,6 +24,7 @@
 #include <grub/misc.h>
 #include <grub/extcmd.h>
 #include <grub/i18n.h>
+#include <grub/env.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -46,18 +47,56 @@
   grub_refresh ();
 }
 
+static int
+grub_check_hotkey(int hotkey)
+{
+  switch (hotkey)
+    {
+    case GRUB_TERM_KEY_F1:
+    case GRUB_TERM_KEY_F2:
+    case GRUB_TERM_KEY_F3:
+    case GRUB_TERM_KEY_F4:
+    case GRUB_TERM_KEY_F5:
+    case GRUB_TERM_KEY_F6:
+    case GRUB_TERM_KEY_F7:
+    case GRUB_TERM_KEY_F8:
+    case GRUB_TERM_KEY_F9:
+    case GRUB_TERM_KEY_F10:
+    case GRUB_TERM_KEY_F11:
+    case GRUB_TERM_KEY_F12:
+    case GRUB_TERM_KEY_DC:
+    case GRUB_TERM_BACKSPACE:
+    case GRUB_TERM_TAB:
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
 grub_interruptible_millisleep (grub_uint32_t ms)
 {
   grub_uint64_t start;
+  int key = 0;
 
   start = grub_get_time_ms ();
 
   while (grub_get_time_ms () - start < ms)
-    if (grub_getkey_noblock () == GRUB_TERM_ESC)
-      return 1;
+    {
+      key = grub_getkey_noblock ();
+      if (key == GRUB_TERM_ESC)
+	return 1;
 
+      if (grub_check_hotkey(key))
+	{
+	  char *hotkey = grub_xasprintf ("%d", key);
+	  grub_env_set ("hotkey", hotkey);
+	  grub_free (hotkey);
+	  return 1;
+	}
+    }
+ 
   return 0;
 }
 

=== modified file 'grub-core/normal/menu.c'
--- a/grub-core/normal/menu.c	2013-06-07 16:36:42 +0000
+++ b/grub-core/normal/menu.c	2013-10-01 03:25:16 +0000
@@ -99,6 +99,34 @@
   return timeout;
 }
 
+/* Get hotkey from environment variables */
+int
+grub_menu_get_hotkey (void)
+{
+  const char *val;
+  int hotkey;
+
+  val = grub_env_get ("hotkey");
+  if (! val)
+    return -1;
+
+  grub_error_push();
+
+  hotkey = (int) grub_strtoul (val, 0, 10);
+
+  /* If the value is invalid, return -1.  */
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      hotkey = -1;
+    }
+
+  grub_env_unset ("hotkey");
+  grub_error_pop ();
+
+  return hotkey;
+}
+
 /* Set current timeout in the variable "timeout".  */
 void
 grub_menu_set_timeout (int timeout)
@@ -488,6 +516,21 @@
   return entry;
 }
 
+static int
+get_menuentry_by_hotkey(grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      {
+        menu_fini ();
+	return i;
+      }
+  return 0;
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -502,14 +545,24 @@
   grub_uint64_t saved_time;
   int default_entry, current_entry;
   int timeout;
+  int hotkey = 0;
 
   default_entry = get_entry_number (menu, "default");
+  hotkey = grub_menu_get_hotkey ();
 
   /* If DEFAULT_ENTRY is not within the menu entries, fall back to
      the first entry.  */
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  /* check if hotkey is set */
+  if (hotkey > 0 &&
+      (current_entry = get_menuentry_by_hotkey(menu, hotkey)) > 0)
+    {
+      *auto_boot = 1;
+      return current_entry;
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
   if (grub_menu_get_timeout () == 0)
     {
@@ -652,19 +705,15 @@
 	      goto refresh;
 
 	    default:
-	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
-	      }
-	      break;
+              {
+                int entry = get_menuentry_by_hotkey(menu, c);
+                if (entry > 0)
+                  {
+                    *auto_boot = 0;
+                    return entry;
+                  }
+              }
+ 	      break;
 	    }
 	}
     }

=== modified file 'include/grub/menu.h'
--- a/include/grub/menu.h	2012-03-04 13:55:13 +0000
+++ b/include/grub/menu.h	2013-10-01 03:24:02 +0000
@@ -96,6 +96,7 @@
 
 grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no);
 int grub_menu_get_timeout (void);
+int grub_menu_get_hotkey (void);
 void grub_menu_set_timeout (int timeout);
 void grub_menu_entry_run (grub_menu_entry_t entry);
 int grub_menu_get_default_entry_index (grub_menu_t menu);


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-10-02  8:03     ` Franz Hsieh
@ 2013-10-02  8:50       ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-14  6:02       ` Franz Hsieh
  1 sibling, 0 replies; 29+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-02  8:50 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 522 bytes --]

On 02.10.2013 10:03, Franz Hsieh wrote:
> Hi, there
> 
>   I had merged the patch for enabling hotkey in grub silent mode to
> grub-trunk.
>   The --function-key now has been removed from sleep.mod, now sleep.mod will
>   monitor all function keys, delete, tab and backspace.
> 
Have you missed on-going opposition, discussion and improvement
proposals from me?
I was going to revert the patch but found out that you didn't actually
commit it, please see my comments to make it acceptable and don't push it.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-10-02  8:03     ` Franz Hsieh
  2013-10-02  8:50       ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-10-14  6:02       ` Franz Hsieh
  2013-10-21  6:45         ` Franz Hsieh
  1 sibling, 1 reply; 29+ messages in thread
From: Franz Hsieh @ 2013-10-14  6:02 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 5506 bytes --]

On 02.10.2013 10:50, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>* Hi, there*
>>* *
>>*   I had merged the patch for enabling hotkey in grub silent mode to*
>>* grub-trunk.*
>>*   The --function-key now has been removed from sleep.mod, now sleep.mod will*
>>*   monitor all function keys, delete, tab and backspace.*
>>* *
> Have you missed on-going opposition, discussion and improvement
> proposals from me?
> I was going to revert the patch but found out that you didn't actually
> commit it, please see my comments to make it acceptable and don't push it.

Sorry I did not say it clearly, I downloaded sources from grub-trunk,
add my changes,
and finished the patch file. I haven't committed the patch to trunk yet.

I looked at the codes, there is no ungetkey function to do like
ungetc. So currently
I made it to read all keys but only accept function keys / delete /
backspace and Esc
keys to interrupt the sleep thread.

Only function keys / delete key / backspace key are allowed for hotkey
and will be saved to the hotkey environment variable.



On Wed, Oct 2, 2013 at 4:03 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:

> Hi, there
>
>   I had merged the patch for enabling hotkey in grub silent mode to
> grub-trunk.
>   The --function-key now has been removed from sleep.mod, now sleep.mod
> will
>   monitor all function keys, delete, tab and backspace.
>
> Thanks!
>
> Franz Hsieh
>
>
> On Fri, Sep 13, 2013 at 5:18 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:
>
>>
>>
>>
>> On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com>wrote:
>>
>>> Hi Franz,
>>>
>>> Throughout this patch, please take care to adhere to the GRUB coding
>>> style.  This is definitely an improvement over previous versions I've
>>> reviewed, but it still has a number of places where functions are called
>>> or declared with no space before the opening parenthesis.  That is,
>>> "function()" should become "function ()".  I know it's a minor point,
>>> but it makes code much easier to read when it's all in the same style.
>>>
>>> On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
>>> wrote:
>>> > +static struct
>>> > +{
>>> > +  char *name;
>>> > +  int key;
>>> > +} function_key_aliases[] =
>>> > +  {
>>> > +    {"f1", GRUB_TERM_KEY_F1},
>>> > +    {"f2", GRUB_TERM_KEY_F2},
>>> > +    {"f3", GRUB_TERM_KEY_F3},
>>> > +    {"f4", GRUB_TERM_KEY_F4},
>>> > +    {"f5", GRUB_TERM_KEY_F5},
>>> > +    {"f6", GRUB_TERM_KEY_F6},
>>> > +    {"f7", GRUB_TERM_KEY_F7},
>>> > +    {"f8", GRUB_TERM_KEY_F8},
>>> > +    {"f9", GRUB_TERM_KEY_F9},
>>> > +    {"f10", GRUB_TERM_KEY_F10},
>>> > +    {"f11", GRUB_TERM_KEY_F11},
>>> > +    {"f12", GRUB_TERM_KEY_F12},
>>> > +  };
>>> > +
>>>
>>> This is essentially a copy of hotkey_aliases from
>>> grub-core/commands/menuentry.c, and there's duplicated lookup code as
>>> well.  Can you find any way to share it?  Since we certainly don't want
>>> to put this in the kernel, and neither the sleep module nor the normal
>>> module really ought to depend on the other, I suspect that doing so
>>> would require a new module for shared menu code, which may well be
>>> overkill for this, but it's worth a look.
>>>
>>
>> I also agree to remove duplicate code, but seems not easy to do it unless
>> we have a shared module, right? Well it would take me some time to
>> evaluate.
>>
>> At the very least it would be a good idea to bring the contents of this
>>> structure into sync with hotkey_aliases and add comments to encourage
>>> developers to keep them that way.
>>>
>>> I think we should also call this kind of thing simply "hotkey"
>>> consistently across the code, rather than it sometimes being
>>> "function_key" or "fnkey".
>>>
>>
>>
>>>
>>> > +      if (key == fnkey)
>>> > +     {
>>> > +       char hotkey[32] = {0};
>>> > +       grub_snprintf(hotkey, 32, "%d", key);
>>> > +       grub_env_set("hotkey", (char*)&hotkey);
>>> > +       return 1;
>>> > +     }
>>>
>>> We've generally tried to get rid of this kind of static allocation.  Use
>>> grub_xasprintf instead:
>>>
>>>   if (key == fnkey)
>>>     {
>>>       char *hotkey = grub_xasprintf ("%d", key);
>>>       grub_env_set ("hotkey", hotkey);
>>>       grub_free (hotkey);
>>>       return 1;
>>>     }
>>>
>>> > +int
>>> > +grub_menu_get_hotkey (void)
>>>
>>> This function is only used in this file, so it should be static.
>>>
>>
>> These idea are good and I will do these changes in my patch.
>>
>> Rather than having to configure this explicitly, I have an alternative
>>> suggestion, which ties into my earlier suggestion of making the hotkey
>>> code a bit more shared.  Why not have sleep --interruptible look up the
>>> hotkeys configured in the menu and automatically honour any of those?
>>> That way you wouldn't have to configure hotkeys in two places (grub.cfg
>>> and /etc/default/grub).  Plus, I'm always more comfortable with patches
>>> that don't require adding configuration options.
>>>
>>
>> Agree with Colin's points and I will update the patch.
>> By the way I would like to combine --function-key and --interruptible. I
>> think
>> it is a simple way that sleep.mod always checks ESC for interrupt and
>> f1~f12 for the
>> hotkey.
>>
>> Thanks for your reviews and if there is any good suggestion, please feel
>> free to tell me.
>>
>> Regards,
>> Franz Hsieh
>>
>>
>

[-- Attachment #2: Type: text/html, Size: 8283 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-10-14  6:02       ` Franz Hsieh
@ 2013-10-21  6:45         ` Franz Hsieh
  2013-11-04  3:10           ` Yang Bai
  2013-11-27 23:40           ` Colin Watson
  0 siblings, 2 replies; 29+ messages in thread
From: Franz Hsieh @ 2013-10-21  6:45 UTC (permalink / raw)
  To: grub-devel, phcoder


[-- Attachment #1.1: Type: text/plain, Size: 6223 bytes --]

Hi Vladimir,
  I don't know if l lose any update from you. Would you give me comments
about
  the latest hotkey patch?

  Summary of the patch:
  * allow function keys / delete / backspace to interrupt sleep and set
'hotkey' variable.
  * remove key aliases structure.
  * using grub_xasprintf instead of grub_snprintf
  * unset the 'hotkey' variable quickly when it is unneeded in
grub_menu_get_hotkey

  Many thanks!

Franz Hsieh

On Mon, Oct 14, 2013 at 2:02 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:

> On 02.10.2013 10:50, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>
> >>* Hi, there*
> >>* *
> >>*   I had merged the patch for enabling hotkey in grub silent mode to*
> >>* grub-trunk.*
> >>*   The --function-key now has been removed from sleep.mod, now sleep.mod will*
> >>*   monitor all function keys, delete, tab and backspace.*
> >>* *
>
> > Have you missed on-going opposition, discussion and improvement
> > proposals from me?
> > I was going to revert the patch but found out that you didn't actually
> > commit it, please see my comments to make it acceptable and don't push it.
>
> Sorry I did not say it clearly, I downloaded sources from grub-trunk, add my changes,
> and finished the patch file. I haven't committed the patch to trunk yet.
>
> I looked at the codes, there is no ungetkey function to do like ungetc. So currently
> I made it to read all keys but only accept function keys / delete / backspace and Esc
> keys to interrupt the sleep thread.
>
> Only function keys / delete key / backspace key are allowed for hotkey
>
>
> and will be saved to the hotkey environment variable.
>
>
>
> On Wed, Oct 2, 2013 at 4:03 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:
>
>> Hi, there
>>
>>   I had merged the patch for enabling hotkey in grub silent mode to
>> grub-trunk.
>>   The --function-key now has been removed from sleep.mod, now sleep.mod
>> will
>>   monitor all function keys, delete, tab and backspace.
>>
>> Thanks!
>>
>> Franz Hsieh
>>
>>
>> On Fri, Sep 13, 2013 at 5:18 PM, Franz Hsieh <franz.hsieh@canonical.com>wrote:
>>
>>>
>>>
>>>
>>> On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com>wrote:
>>>
>>>> Hi Franz,
>>>>
>>>> Throughout this patch, please take care to adhere to the GRUB coding
>>>> style.  This is definitely an improvement over previous versions I've
>>>> reviewed, but it still has a number of places where functions are called
>>>> or declared with no space before the opening parenthesis.  That is,
>>>> "function()" should become "function ()".  I know it's a minor point,
>>>> but it makes code much easier to read when it's all in the same style.
>>>>
>>>> On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin Watson)
>>>> wrote:
>>>> > +static struct
>>>> > +{
>>>> > +  char *name;
>>>> > +  int key;
>>>> > +} function_key_aliases[] =
>>>> > +  {
>>>> > +    {"f1", GRUB_TERM_KEY_F1},
>>>> > +    {"f2", GRUB_TERM_KEY_F2},
>>>> > +    {"f3", GRUB_TERM_KEY_F3},
>>>> > +    {"f4", GRUB_TERM_KEY_F4},
>>>> > +    {"f5", GRUB_TERM_KEY_F5},
>>>> > +    {"f6", GRUB_TERM_KEY_F6},
>>>> > +    {"f7", GRUB_TERM_KEY_F7},
>>>> > +    {"f8", GRUB_TERM_KEY_F8},
>>>> > +    {"f9", GRUB_TERM_KEY_F9},
>>>> > +    {"f10", GRUB_TERM_KEY_F10},
>>>> > +    {"f11", GRUB_TERM_KEY_F11},
>>>> > +    {"f12", GRUB_TERM_KEY_F12},
>>>> > +  };
>>>> > +
>>>>
>>>> This is essentially a copy of hotkey_aliases from
>>>> grub-core/commands/menuentry.c, and there's duplicated lookup code as
>>>> well.  Can you find any way to share it?  Since we certainly don't want
>>>> to put this in the kernel, and neither the sleep module nor the normal
>>>> module really ought to depend on the other, I suspect that doing so
>>>> would require a new module for shared menu code, which may well be
>>>> overkill for this, but it's worth a look.
>>>>
>>>
>>> I also agree to remove duplicate code, but seems not easy to do it unless
>>> we have a shared module, right? Well it would take me some time to
>>> evaluate.
>>>
>>> At the very least it would be a good idea to bring the contents of this
>>>> structure into sync with hotkey_aliases and add comments to encourage
>>>> developers to keep them that way.
>>>>
>>>> I think we should also call this kind of thing simply "hotkey"
>>>> consistently across the code, rather than it sometimes being
>>>> "function_key" or "fnkey".
>>>>
>>>
>>>
>>>>
>>>> > +      if (key == fnkey)
>>>> > +     {
>>>> > +       char hotkey[32] = {0};
>>>> > +       grub_snprintf(hotkey, 32, "%d", key);
>>>> > +       grub_env_set("hotkey", (char*)&hotkey);
>>>> > +       return 1;
>>>> > +     }
>>>>
>>>> We've generally tried to get rid of this kind of static allocation.  Use
>>>> grub_xasprintf instead:
>>>>
>>>>   if (key == fnkey)
>>>>     {
>>>>       char *hotkey = grub_xasprintf ("%d", key);
>>>>       grub_env_set ("hotkey", hotkey);
>>>>       grub_free (hotkey);
>>>>       return 1;
>>>>     }
>>>>
>>>> > +int
>>>> > +grub_menu_get_hotkey (void)
>>>>
>>>> This function is only used in this file, so it should be static.
>>>>
>>>
>>> These idea are good and I will do these changes in my patch.
>>>
>>> Rather than having to configure this explicitly, I have an alternative
>>>> suggestion, which ties into my earlier suggestion of making the hotkey
>>>> code a bit more shared.  Why not have sleep --interruptible look up the
>>>> hotkeys configured in the menu and automatically honour any of those?
>>>> That way you wouldn't have to configure hotkeys in two places (grub.cfg
>>>> and /etc/default/grub).  Plus, I'm always more comfortable with patches
>>>> that don't require adding configuration options.
>>>>
>>>
>>> Agree with Colin's points and I will update the patch.
>>> By the way I would like to combine --function-key and --interruptible. I
>>> think
>>> it is a simple way that sleep.mod always checks ESC for interrupt and
>>> f1~f12 for the
>>> hotkey.
>>>
>>> Thanks for your reviews and if there is any good suggestion, please feel
>>> free to tell me.
>>>
>>> Regards,
>>> Franz Hsieh
>>>
>>>
>>
>

[-- Attachment #1.2: Type: text/html, Size: 9335 bytes --]

[-- Attachment #2: grub2-enable-hotkey-in-silent-mode.patch --]
[-- Type: application/octet-stream, Size: 4506 bytes --]

=== modified file 'grub-core/commands/sleep.c'
--- a/grub-core/commands/sleep.c	2013-07-11 14:02:22 +0000
+++ b/grub-core/commands/sleep.c	2013-10-01 08:18:24 +0000
@@ -24,6 +24,7 @@
 #include <grub/misc.h>
 #include <grub/extcmd.h>
 #include <grub/i18n.h>
+#include <grub/env.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -46,18 +47,56 @@
   grub_refresh ();
 }
 
+static int
+grub_check_hotkey(int hotkey)
+{
+  switch (hotkey)
+    {
+    case GRUB_TERM_KEY_F1:
+    case GRUB_TERM_KEY_F2:
+    case GRUB_TERM_KEY_F3:
+    case GRUB_TERM_KEY_F4:
+    case GRUB_TERM_KEY_F5:
+    case GRUB_TERM_KEY_F6:
+    case GRUB_TERM_KEY_F7:
+    case GRUB_TERM_KEY_F8:
+    case GRUB_TERM_KEY_F9:
+    case GRUB_TERM_KEY_F10:
+    case GRUB_TERM_KEY_F11:
+    case GRUB_TERM_KEY_F12:
+    case GRUB_TERM_KEY_DC:
+    case GRUB_TERM_BACKSPACE:
+    case GRUB_TERM_TAB:
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
 grub_interruptible_millisleep (grub_uint32_t ms)
 {
   grub_uint64_t start;
+  int key = 0;
 
   start = grub_get_time_ms ();
 
   while (grub_get_time_ms () - start < ms)
-    if (grub_getkey_noblock () == GRUB_TERM_ESC)
-      return 1;
+    {
+      key = grub_getkey_noblock ();
+      if (key == GRUB_TERM_ESC)
+	return 1;
 
+      if (grub_check_hotkey(key))
+	{
+	  char *hotkey = grub_xasprintf ("%d", key);
+	  grub_env_set ("hotkey", hotkey);
+	  grub_free (hotkey);
+	  return 1;
+	}
+    }
+ 
   return 0;
 }
 

=== modified file 'grub-core/normal/menu.c'
--- a/grub-core/normal/menu.c	2013-06-07 16:36:42 +0000
+++ b/grub-core/normal/menu.c	2013-10-01 03:25:16 +0000
@@ -99,6 +99,34 @@
   return timeout;
 }
 
+/* Get hotkey from environment variables */
+int
+grub_menu_get_hotkey (void)
+{
+  const char *val;
+  int hotkey;
+
+  val = grub_env_get ("hotkey");
+  if (! val)
+    return -1;
+
+  grub_error_push();
+
+  hotkey = (int) grub_strtoul (val, 0, 10);
+
+  /* If the value is invalid, return -1.  */
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      hotkey = -1;
+    }
+
+  grub_env_unset ("hotkey");
+  grub_error_pop ();
+
+  return hotkey;
+}
+
 /* Set current timeout in the variable "timeout".  */
 void
 grub_menu_set_timeout (int timeout)
@@ -488,6 +516,21 @@
   return entry;
 }
 
+static int
+get_menuentry_by_hotkey(grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      {
+        menu_fini ();
+	return i;
+      }
+  return 0;
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -502,14 +545,24 @@
   grub_uint64_t saved_time;
   int default_entry, current_entry;
   int timeout;
+  int hotkey = 0;
 
   default_entry = get_entry_number (menu, "default");
+  hotkey = grub_menu_get_hotkey ();
 
   /* If DEFAULT_ENTRY is not within the menu entries, fall back to
      the first entry.  */
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  /* check if hotkey is set */
+  if (hotkey > 0 &&
+      (current_entry = get_menuentry_by_hotkey(menu, hotkey)) > 0)
+    {
+      *auto_boot = 1;
+      return current_entry;
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
   if (grub_menu_get_timeout () == 0)
     {
@@ -652,19 +705,15 @@
 	      goto refresh;
 
 	    default:
-	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
-	      }
-	      break;
+              {
+                int entry = get_menuentry_by_hotkey(menu, c);
+                if (entry > 0)
+                  {
+                    *auto_boot = 0;
+                    return entry;
+                  }
+              }
+ 	      break;
 	    }
 	}
     }

=== modified file 'include/grub/menu.h'
--- a/include/grub/menu.h	2012-03-04 13:55:13 +0000
+++ b/include/grub/menu.h	2013-10-01 03:24:02 +0000
@@ -96,6 +96,7 @@
 
 grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no);
 int grub_menu_get_timeout (void);
+int grub_menu_get_hotkey (void);
 void grub_menu_set_timeout (int timeout);
 void grub_menu_entry_run (grub_menu_entry_t entry);
 int grub_menu_get_default_entry_index (grub_menu_t menu);


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-10-21  6:45         ` Franz Hsieh
@ 2013-11-04  3:10           ` Yang Bai
  2013-11-27 23:40           ` Colin Watson
  1 sibling, 0 replies; 29+ messages in thread
From: Yang Bai @ 2013-11-04  3:10 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: phcoder

Ping. Any updates?

On Mon, Oct 21, 2013 at 2:45 PM, Franz Hsieh <franz.hsieh@canonical.com> wrote:
> Hi Vladimir,
>   I don't know if l lose any update from you. Would you give me comments
> about
>   the latest hotkey patch?
>
>   Summary of the patch:
>   * allow function keys / delete / backspace to interrupt sleep and set
> 'hotkey' variable.
>   * remove key aliases structure.
>   * using grub_xasprintf instead of grub_snprintf
>   * unset the 'hotkey' variable quickly when it is unneeded in
> grub_menu_get_hotkey
>
>   Many thanks!
>
> Franz Hsieh
>
> On Mon, Oct 14, 2013 at 2:02 PM, Franz Hsieh <franz.hsieh@canonical.com>
> wrote:
>>
>> On 02.10.2013 10:50, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>
>> >> Hi, there
>> >>
>> >>   I had merged the patch for enabling hotkey in grub silent mode to
>> >> grub-trunk.
>> >>   The --function-key now has been removed from sleep.mod, now sleep.mod
>> >> will
>> >>   monitor all function keys, delete, tab and backspace.
>> >>
>> > Have you missed on-going opposition, discussion and improvement
>> > proposals from me?
>> > I was going to revert the patch but found out that you didn't actually
>> > commit it, please see my comments to make it acceptable and don't push
>> > it.
>>
>> Sorry I did not say it clearly, I downloaded sources from grub-trunk, add
>> my changes,
>> and finished the patch file. I haven't committed the patch to trunk yet.
>>
>> I looked at the codes, there is no ungetkey function to do like ungetc. So
>> currently
>> I made it to read all keys but only accept function keys / delete /
>> backspace and Esc
>> keys to interrupt the sleep thread.
>>
>> Only function keys / delete key / backspace key are allowed for hotkey
>>
>>
>>
>> and will be saved to the hotkey environment variable.
>>
>>
>>
>> On Wed, Oct 2, 2013 at 4:03 PM, Franz Hsieh <franz.hsieh@canonical.com>
>> wrote:
>>>
>>> Hi, there
>>>
>>>   I had merged the patch for enabling hotkey in grub silent mode to
>>> grub-trunk.
>>>   The --function-key now has been removed from sleep.mod, now sleep.mod
>>> will
>>>   monitor all function keys, delete, tab and backspace.
>>>
>>> Thanks!
>>>
>>> Franz Hsieh
>>>
>>>
>>> On Fri, Sep 13, 2013 at 5:18 PM, Franz Hsieh <franz.hsieh@canonical.com>
>>> wrote:
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Sep 11, 2013 at 9:31 PM, Colin Watson <cjwatson@ubuntu.com>
>>>> wrote:
>>>>>
>>>>> Hi Franz,
>>>>>
>>>>> Throughout this patch, please take care to adhere to the GRUB coding
>>>>> style.  This is definitely an improvement over previous versions I've
>>>>> reviewed, but it still has a number of places where functions are
>>>>> called
>>>>> or declared with no space before the opening parenthesis.  That is,
>>>>> "function()" should become "function ()".  I know it's a minor point,
>>>>> but it makes code much easier to read when it's all in the same style.
>>>>>
>>>>> On Wed, Sep 11, 2013 at 02:18:04PM +0100, Franz Hsieh (via Colin
>>>>> Watson)
>>>>> wrote:
>>>>> > +static struct
>>>>> > +{
>>>>> > +  char *name;
>>>>> > +  int key;
>>>>> > +} function_key_aliases[] =
>>>>> > +  {
>>>>> > +    {"f1", GRUB_TERM_KEY_F1},
>>>>> > +    {"f2", GRUB_TERM_KEY_F2},
>>>>> > +    {"f3", GRUB_TERM_KEY_F3},
>>>>> > +    {"f4", GRUB_TERM_KEY_F4},
>>>>> > +    {"f5", GRUB_TERM_KEY_F5},
>>>>> > +    {"f6", GRUB_TERM_KEY_F6},
>>>>> > +    {"f7", GRUB_TERM_KEY_F7},
>>>>> > +    {"f8", GRUB_TERM_KEY_F8},
>>>>> > +    {"f9", GRUB_TERM_KEY_F9},
>>>>> > +    {"f10", GRUB_TERM_KEY_F10},
>>>>> > +    {"f11", GRUB_TERM_KEY_F11},
>>>>> > +    {"f12", GRUB_TERM_KEY_F12},
>>>>> > +  };
>>>>> > +
>>>>>
>>>>> This is essentially a copy of hotkey_aliases from
>>>>> grub-core/commands/menuentry.c, and there's duplicated lookup code as
>>>>> well.  Can you find any way to share it?  Since we certainly don't want
>>>>> to put this in the kernel, and neither the sleep module nor the normal
>>>>> module really ought to depend on the other, I suspect that doing so
>>>>> would require a new module for shared menu code, which may well be
>>>>> overkill for this, but it's worth a look.
>>>>
>>>>
>>>> I also agree to remove duplicate code, but seems not easy to do it
>>>> unless
>>>> we have a shared module, right? Well it would take me some time to
>>>> evaluate.
>>>>
>>>>> At the very least it would be a good idea to bring the contents of this
>>>>> structure into sync with hotkey_aliases and add comments to encourage
>>>>> developers to keep them that way.
>>>>>
>>>>> I think we should also call this kind of thing simply "hotkey"
>>>>> consistently across the code, rather than it sometimes being
>>>>> "function_key" or "fnkey".
>>>>
>>>>
>>>>>
>>>>>
>>>>> > +      if (key == fnkey)
>>>>> > +     {
>>>>> > +       char hotkey[32] = {0};
>>>>> > +       grub_snprintf(hotkey, 32, "%d", key);
>>>>> > +       grub_env_set("hotkey", (char*)&hotkey);
>>>>> > +       return 1;
>>>>> > +     }
>>>>>
>>>>> We've generally tried to get rid of this kind of static allocation.
>>>>> Use
>>>>> grub_xasprintf instead:
>>>>>
>>>>>   if (key == fnkey)
>>>>>     {
>>>>>       char *hotkey = grub_xasprintf ("%d", key);
>>>>>       grub_env_set ("hotkey", hotkey);
>>>>>       grub_free (hotkey);
>>>>>       return 1;
>>>>>     }
>>>>>
>>>>> > +int
>>>>> > +grub_menu_get_hotkey (void)
>>>>>
>>>>> This function is only used in this file, so it should be static.
>>>>
>>>>
>>>> These idea are good and I will do these changes in my patch.
>>>>
>>>>> Rather than having to configure this explicitly, I have an alternative
>>>>> suggestion, which ties into my earlier suggestion of making the hotkey
>>>>> code a bit more shared.  Why not have sleep --interruptible look up the
>>>>> hotkeys configured in the menu and automatically honour any of those?
>>>>> That way you wouldn't have to configure hotkeys in two places (grub.cfg
>>>>> and /etc/default/grub).  Plus, I'm always more comfortable with patches
>>>>> that don't require adding configuration options.
>>>>
>>>>
>>>> Agree with Colin's points and I will update the patch.
>>>> By the way I would like to combine --function-key and --interruptible. I
>>>> think
>>>> it is a simple way that sleep.mod always checks ESC for interrupt and
>>>> f1~f12 for the
>>>> hotkey.
>>>>
>>>> Thanks for your reviews and if there is any good suggestion, please feel
>>>> free to tell me.
>>>>
>>>> Regards,
>>>> Franz Hsieh
>>>>
>>>
>>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-10-21  6:45         ` Franz Hsieh
  2013-11-04  3:10           ` Yang Bai
@ 2013-11-27 23:40           ` Colin Watson
  2013-11-28  2:30             ` Colin Watson
  1 sibling, 1 reply; 29+ messages in thread
From: Colin Watson @ 2013-11-27 23:40 UTC (permalink / raw)
  To: grub-devel

On Mon, Oct 21, 2013 at 02:45:04PM +0800, Franz Hsieh wrote:
>   I don't know if l lose any update from you. Would you give me comments
> about the latest hotkey patch?

Vladimir and I talked about this on IRC today.  We share a dislike for
the hardcoded hotkey names.  Between us, we came up with a better plan:

 * The simplest way to work out what hotkeys to honour is to introspect
   the menu structure itself.  However, this can only be done after all
   the top-level commands in grub.cfg have been executed, so it can't be
   done in the "sleep" command.
 * There's nothing particular that says that we have to implement the
   hidden timeout in a "sleep" command, although we have to take some
   care to ensure configuration file compatibility with older modules.
   Since the main timeout is implemented in normal.mod, it makes some
   sense for the hidden timeout to go there too, where we can get at the
   menu structure.
 * The simplest way to arrange for configuration file compatibility is
   to add a new "hiddentimeout" command that sets a "hidden_timeout"
   environment variable; we could also set the environment variable
   directly, but having a command allows us to detect the absence of
   that command and infer that we need to fall back to the old
   mechanism.

Here's a candidate patch.  This does duplicate "sleep" a little bit, but
it has the great advantages of not duplicating the list of valid hotkeys
and of only honouring hotkeys that are associated with menu entries.

 Add a new "hiddentimeout" command.  If this is used, then the
 menu will use a hidden timeout much as was previously done with "sleep
 --interruptible", except that pressing any hotkeys associated with menu
 entries will boot the corresponding menu entry immediately.

---
 ChangeLog                          |   7 ++
 docs/grub.texi                     |  39 ++++++--
 grub-core/Makefile.core.def        |   5 ++
 grub-core/commands/hiddentimeout.c |  68 ++++++++++++++
 grub-core/normal/menu.c            | 177 ++++++++++++++++++++++++++++++++-----
 util/grub.d/00_header.in           |   6 +-
 6 files changed, 271 insertions(+), 31 deletions(-)
 create mode 100644 grub-core/commands/hiddentimeout.c

diff --git a/ChangeLog b/ChangeLog
index d24f533..cfca08a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-27  Colin Watson  <cjwatson@ubuntu.com>
+
+	Add a new "hiddentimeout" command.  If this is used, then the menu
+	will use a hidden timeout much as was previously done with "sleep
+	--interruptible", except that pressing any hotkeys associated with
+	menu entries will boot the corresponding menu entry immediately.
+
 2013-11-27  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	Eliminate variable length arrays in grub_vsnprintf_real.
diff --git a/docs/grub.texi b/docs/grub.texi
index 6aee292..3b92105 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -1299,13 +1299,19 @@ immediately without displaying the menu, or to @samp{-1} to wait
 indefinitely.
 
 @item GRUB_HIDDEN_TIMEOUT
-Wait this many seconds for @key{ESC} to be pressed before displaying the menu.
-If no @key{ESC} is pressed during that time, display the menu for the number of
-seconds specified in GRUB_TIMEOUT before booting the default entry. We expect
-that most people who use GRUB_HIDDEN_TIMEOUT will want to have GRUB_TIMEOUT set 
-to @samp{0} so that the menu is not displayed at all unless @key{ESC} is
-pressed.
-Unset by default.
+Wait this many seconds for @key{ESC} or a hotkey associated with a menu
+entry to be pressed before displaying the menu.  If @key{ESC} is pressed,
+display the menu and wait for input according to @samp{GRUB_TIMEOUT}.  If a
+hotkey is pressed, boot the associated menu entry immediately.  If the
+timeout expires before either of these happens, display the menu for the
+number of seconds specified in @samp{GRUB_TIMEOUT} before booting the
+default entry.
+
+We expect that most people who use @samp{GRUB_HIDDEN_TIMEOUT} will want to
+have @samp{GRUB_TIMEOUT} set to @samp{0} so that the menu is not displayed
+at all unless @key{ESC} is pressed.
+
+This option is unset by default.
 
 @item GRUB_HIDDEN_TIMEOUT_QUIET
 In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
@@ -3736,6 +3742,7 @@ you forget a command, you can run the command @command{help}
 * halt::                        Shut down your computer
 * hashsum::                     Compute or check hash checksum
 * help::                        Show help messages
+* hiddentimeout::               Configure the hidden menu timeout
 * initrd::                      Load a Linux initrd
 * initrd16::                    Load a Linux initrd (16-bit mode)
 * insmod::                      Insert a module
@@ -4243,6 +4250,24 @@ about each of the commands whose names begin with those @var{patterns}.
 @end deffn
 
 
+@node hiddentimeout
+@subsection hiddentimeout
+
+@deffn Command hiddentimeout [@option{--visible-timeout} timeout] timeout
+Configure the @samp{normal} module (@pxref{normal}) to wait @var{timeout}
+seconds for @key{ESC} or a hotkey associated with a menu entry to be pressed
+before displaying the menu.  If @key{ESC} is pressed, display the menu and
+wait for input according to the value of the @samp{timeout} variable
+(@pxref{timeout}).  If a hotkey is pressed, boot the associated menu entry
+immediately.  If the timeout expires before either of these happens, display
+the menu for the number of seconds specified in the @samp{timeout} variable
+before booting the default entry.
+
+If the @option{--visible-timeout} option is given, then configure the
+@samp{normal} module to set the @samp{timeout} variable to its value if the
+timeout expires without any of the recognised keys being pressed.
+@end deffn
+
 @node initrd
 @subsection initrd
 
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 5cd84b1..41114a8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2247,3 +2247,8 @@ module = {
   name = progress;
   common = lib/progress.c;
 };
+
+module = {
+  name = hiddentimeout;
+  common = commands/hiddentimeout.c;
+};
diff --git a/grub-core/commands/hiddentimeout.c b/grub-core/commands/hiddentimeout.c
new file mode 100644
index 0000000..99fdaff
--- /dev/null
+++ b/grub-core/commands/hiddentimeout.c
@@ -0,0 +1,68 @@
+/* hiddentimeout.c - command to configure the hidden menu timeout  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+  {
+    {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0},
+    {"visible-timeout", 0, 0,
+     N_("Timeout for the visible menu after the hidden timeout expires."),
+     0, ARG_TYPE_INT},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+static grub_err_t
+grub_cmd_hiddentimeout (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+  struct grub_arg_list *state = ctxt->state;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+  grub_env_set ("hidden_timeout", args[0]);
+  grub_env_set ("hidden_timeout_verbose", state[0].set ? "1" : "0");
+
+  if (state[1].set)
+    grub_env_set ("visible_timeout", state[1].arg);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+\f
+GRUB_MOD_INIT(hiddentimeout)
+{
+  cmd = grub_register_extcmd ("hiddentimeout", grub_cmd_hiddentimeout, 0,
+			      N_("NUMBER_OF_SECONDS"),
+			      N_("Show hidden menu for a specified number of "
+				 "seconds."),
+			      options);
+}
+
+GRUB_MOD_FINI(hiddentimeout)
+{
+  grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 9b88290..cea8d47 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -70,6 +70,21 @@ grub_menu_get_entry (grub_menu_t menu, int no)
   return e;
 }
 
+/* Get the index of a menu entry associated with a given hotkey, or -1.  */
+static int
+get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      return i;
+
+  return -1;
+}
+
 /* Return the current timeout. If the variable "timeout" is not set or
    invalid, return -1.  */
 int
@@ -113,6 +128,46 @@ grub_menu_set_timeout (int timeout)
     }
 }
 
+/* Return the current hidden timeout.  If the variable "hidden_timeout" is
+   not set or invalid, return -1.  */
+static int
+get_hidden_timeout (void)
+{
+  const char *val;
+  int hidden_timeout;
+
+  val = grub_env_get ("hidden_timeout");
+  if (! val)
+    return -1;
+
+  grub_error_push ();
+
+  hidden_timeout = (int) grub_strtoul (val, 0, 0);
+
+  /* If the value is invalid, unset the variable.  */
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_env_unset ("hidden_timeout");
+      grub_errno = GRUB_ERR_NONE;
+      hidden_timeout = -1;
+    }
+
+  grub_error_pop ();
+
+  return hidden_timeout;
+}
+
+/* Return 1 if the hidden timeout should show a verbose countdown, otherwise
+   0.  */
+static int
+get_hidden_timeout_verbose (void)
+{
+  const char *val;
+
+  val = grub_env_get ("hidden_timeout_verbose");
+  return val && grub_strtoul (val, 0, 0) != 0;
+}
+
 /* Get the first entry number from the value of the environment variable NAME,
    which is a space-separated list of non-negative integers.  The entry number
    which is returned is stripped from the value of NAME.  If no entry number
@@ -488,6 +543,33 @@ get_entry_number (grub_menu_t menu, const char *name)
   return entry;
 }
 
+/* Check whether a second has elapsed since the last tick.  If so, adjust
+   the timer and return 1; otherwise, return 0.  */
+static int
+has_second_elapsed (grub_uint64_t *saved_time)
+{
+  grub_uint64_t current_time;
+
+  current_time = grub_get_time_ms ();
+  if (current_time - *saved_time >= 1000)
+    {
+      *saved_time = current_time;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static void
+print_countdown (struct grub_term_coordinate *pos, int n)
+{
+  grub_term_restore_pos (pos);
+  /* NOTE: Do not remove the trailing space characters.
+     They are required to clear the line.  */
+  grub_printf ("%d    ", n);
+  grub_refresh ();
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -501,7 +583,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
 {
   grub_uint64_t saved_time;
   int default_entry, current_entry;
-  int timeout;
+  int hidden_timeout, timeout;
 
   default_entry = get_entry_number (menu, "default");
 
@@ -510,6 +592,65 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  hidden_timeout = get_hidden_timeout ();
+  if (hidden_timeout != -1)
+    {
+      int verbose = get_hidden_timeout_verbose ();
+      static struct grub_term_coordinate *pos;
+      int entry = -1;
+
+      if (verbose && hidden_timeout)
+	{
+	  pos = grub_term_save_pos ();
+	  print_countdown (pos, hidden_timeout);
+	}
+
+      /* Enter interruptible sleep until Escape or a menu hotkey is pressed,
+         or the timeout expires.  */
+      saved_time = grub_get_time_ms ();
+      while (1)
+	{
+	  int key;
+
+	  key = grub_getkey_noblock ();
+	  if (key != GRUB_TERM_NO_KEY)
+	    {
+	      entry = get_entry_index_by_hotkey (menu, key);
+	      if (entry >= 0)
+		break;
+	    }
+	  if (key == GRUB_TERM_ESC)
+	    break;
+
+	  if (hidden_timeout > 0 && has_second_elapsed (&saved_time))
+	    {
+	      hidden_timeout--;
+	      if (verbose)
+		print_countdown (pos, hidden_timeout);
+	    }
+
+	  if (hidden_timeout == 0)
+	    {
+	      const char *visible_timeout;
+
+	      visible_timeout = grub_env_get ("visible_timeout");
+	      if (visible_timeout)
+		grub_env_set ("timeout", visible_timeout);
+	      break;
+	    }
+	}
+
+      /* Don't do this again.  */
+      grub_env_unset ("hidden_timeout");
+      grub_env_unset ("visible_timeout");
+
+      if (entry >= 0)
+	{
+	  *auto_boot = 1;
+	  return entry;
+	}
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
   if (grub_menu_get_timeout () == 0)
     {
@@ -540,18 +681,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
       if (grub_normal_exit_level)
 	return -1;
 
-      if (timeout > 0)
+      if (timeout > 0 && has_second_elapsed (&saved_time))
 	{
-	  grub_uint64_t current_time;
-
-	  current_time = grub_get_time_ms ();
-	  if (current_time - saved_time >= 1000)
-	    {
-	      timeout--;
-	      grub_menu_set_timeout (timeout);
-	      saved_time = current_time;
-	      menu_print_timeout (timeout);
-	    }
+	  timeout--;
+	  grub_menu_set_timeout (timeout);
+	  menu_print_timeout (timeout);
 	}
 
       if (timeout == 0)
@@ -653,16 +787,15 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
 
 	    default:
 	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
+		int entry;
+
+		entry = get_entry_index_by_hotkey (menu, c);
+		if (entry >= 0)
+		  {
+		    menu_fini ();
+		    *auto_boot = 0;
+		    return entry;
+		  }
 	      }
 	      break;
 	    }
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index 9838720..6d2f074 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -289,8 +289,10 @@ make_timeout ()
 	    verbose=" --verbose"
 	fi
 	cat << EOF
-if sleep$verbose --interruptible ${1} ; then
-  set timeout=${2}
+if ! hiddentimeout$verbose --visible-timeout=${2} ${1} ; then
+  if sleep$verbose --interruptible ${1} ; then
+    set timeout=${2}
+  fi
 fi
 EOF
     else
-- 
1.8.4.4

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-27 23:40           ` Colin Watson
@ 2013-11-28  2:30             ` Colin Watson
  2013-11-28  6:19               ` Vladimir 'phcoder' Serbinenko
  2013-11-28 17:22               ` Andrey Borzenkov
  0 siblings, 2 replies; 29+ messages in thread
From: Colin Watson @ 2013-11-28  2:30 UTC (permalink / raw)
  To: grub-devel

Following discussion with Vladimir on IRC, here's another attempt.  The
preferred user-facing configuration mechanism is now simpler, although
some unfortunate compatibility code is required to make all this work.

Revamp hidden timeout handling

Add a new timeout_style environment variable and a corresponding
GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig.  This
controls hidden-timeout handling more simply than the previous
arrangements, and pressing any hotkeys associated with menu entries
during the hidden timeout will now boot the corresponding menu entry
immediately.

GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now
generates a warning, and if it shows the menu it will do so as if
the second timeout were not present.  Other combinations are
translated into reasonable equivalents.
---
 ChangeLog                |  14 ++++
 docs/grub.texi           |  57 ++++++++++++---
 grub-core/normal/main.c  |   2 +-
 grub-core/normal/menu.c  | 175 +++++++++++++++++++++++++++++++++++++++++------
 util/grub-mkconfig.in    |   1 +
 util/grub.d/00_header.in |  35 +++++++++-
 6 files changed, 251 insertions(+), 33 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d24f533..4cc4562 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-11-28  Colin Watson  <cjwatson@ubuntu.com>
+
+	Add a new timeout_style environment variable and a corresponding
+	GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig.  This
+	controls hidden-timeout handling more simply than the previous
+	arrangements, and pressing any hotkeys associated with menu entries
+	during the hidden timeout will now boot the corresponding menu entry
+	immediately.
+
+	GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now
+	generates a warning, and if it shows the menu it will do so as if
+	the second timeout were not present.  Other combinations are
+	translated into reasonable equivalents.
+
 2013-11-27  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	Eliminate variable length arrays in grub_vsnprintf_real.
diff --git a/docs/grub.texi b/docs/grub.texi
index 6aee292..f494a3d 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -1298,19 +1298,46 @@ a key is pressed.  The default is @samp{5}.  Set to @samp{0} to boot
 immediately without displaying the menu, or to @samp{-1} to wait
 indefinitely.
 
+If @samp{GRUB_TIMEOUT_STYLE} is set to @samp{countdown} or @samp{hidden},
+the timeout is instead counted before the menu is displayed.
+
+@item GRUB_TIMEOUT_STYLE
+If this option is unset or set to @samp{menu}, then GRUB will display the
+menu and then wait for the timeout set by @samp{GRUB_TIMEOUT} to expire
+before booting the default entry.  Pressing a key interrupts the timeout.
+
+If this option is set to @samp{countdown} or @samp{hidden}, then, before
+displaying the menu, GRUB will wait for the timeout set by
+@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that time, it
+will display the menu and wait for input according to @samp{GRUB_TIMEOUT}.
+If a hotkey associated with a menu entry is pressed, it will boot the
+associated menu entry immediately.  If the timeout expires before either of
+these happens, it will display the menu.  In the @samp{countdown} case, it
+will show a one-line indication of the remaining time.
+
 @item GRUB_HIDDEN_TIMEOUT
-Wait this many seconds for @key{ESC} to be pressed before displaying the menu.
-If no @key{ESC} is pressed during that time, display the menu for the number of
-seconds specified in GRUB_TIMEOUT before booting the default entry. We expect
-that most people who use GRUB_HIDDEN_TIMEOUT will want to have GRUB_TIMEOUT set 
-to @samp{0} so that the menu is not displayed at all unless @key{ESC} is
-pressed.
-Unset by default.
+Wait this many seconds before displaying the menu.  If @key{ESC} is pressed
+during that time, display the menu and wait for input according to
+@samp{GRUB_TIMEOUT}.  If a hotkey associated with a menu entry is pressed,
+boot the associated menu entry immediately.  If the timeout expires before
+either of these happens, display the menu for the number of seconds
+specified in @samp{GRUB_TIMEOUT} before booting the default entry.
+
+If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set
+@samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless
+@key{ESC} is pressed.
+
+This option is unset by default, and is deprecated in favour of the less
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
+@samp{GRUB_TIMEOUT_STYLE=hidden}.
 
 @item GRUB_HIDDEN_TIMEOUT_QUIET
 In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
 suppress the verbose countdown while waiting for a key to be pressed before
-displaying the menu.  Unset by default.
+displaying the menu.
+
+This option is unset by default, and is deprecated in favour of the less
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown}.
 
 @item GRUB_DEFAULT_BUTTON
 @itemx GRUB_TIMEOUT_BUTTON
@@ -3030,6 +3057,7 @@ These variables have special meaning to GRUB.
 * superusers::
 * theme::
 * timeout::
+* timeout_style::
 @end menu
 
 
@@ -3462,10 +3490,23 @@ keyboard input before booting the default menu entry.  A timeout of @samp{0}
 means to boot the default entry immediately without displaying the menu; a
 timeout of @samp{-1} (or unset) means to wait indefinitely.
 
+If @samp{timeout_style} (@pxref{timeout_style}) is set to @samp{countdown}
+or @samp{hidden}, the timeout is instead counted before the menu is
+displayed.
+
 This variable is often set by @samp{GRUB_TIMEOUT} or
 @samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}).
 
 
+@node timeout_style
+@subsection timeout_style
+
+This variable may be set to @samp{menu}, @samp{countdown}, or @samp{hidden}
+to control the way in which the timeout (@pxref{timeout}) interacts with
+displaying the menu.  See the documentation of @samp{GRUB_TIMEOUT_STYLE}
+(@pxref{Simple configuration}) for details.
+
+
 @node Environment block
 @section The GRUB environment block
 
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index ad36273..778de61 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -523,7 +523,7 @@ static const char *features[] = {
   "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
   "feature_default_font_path", "feature_all_video_module",
   "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
-  "feature_nativedisk_cmd"
+  "feature_nativedisk_cmd", "feature_timeout_style"
 };
 
 GRUB_MOD_INIT(normal)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 9b88290..fa85c35 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -40,6 +40,22 @@
 grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
 				     int nested) = NULL;
 
+enum timeout_style {
+  TIMEOUT_STYLE_MENU,
+  TIMEOUT_STYLE_COUNTDOWN,
+  TIMEOUT_STYLE_HIDDEN
+};
+
+struct timeout_style_name {
+  const char *name;
+  enum timeout_style style;
+} timeout_style_names[] = {
+  {"menu", TIMEOUT_STYLE_MENU},
+  {"countdown", TIMEOUT_STYLE_COUNTDOWN},
+  {"hidden", TIMEOUT_STYLE_HIDDEN},
+  {NULL, 0}
+};
+
 /* Wait until the user pushes any key so that the user
    can see what happened.  */
 void
@@ -70,6 +86,38 @@ grub_menu_get_entry (grub_menu_t menu, int no)
   return e;
 }
 
+/* Get the index of a menu entry associated with a given hotkey, or -1.  */
+static int
+get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      return i;
+
+  return -1;
+}
+
+/* Return the timeout style.  If the variable "timeout_style" is not set or
+   invalid, default to TIMEOUT_STYLE_MENU.  */
+static enum timeout_style
+get_timeout_style (void)
+{
+  const char *val;
+  struct timeout_style_name *style_name;
+
+  val = grub_env_get ("timeout_style");
+  if (val)
+    for (style_name = timeout_style_names; style_name->name; style_name++)
+      if (grub_strcmp (style_name->name, val) == 0)
+	return style_name->style;
+
+  return TIMEOUT_STYLE_MENU;
+}
+
 /* Return the current timeout. If the variable "timeout" is not set or
    invalid, return -1.  */
 int
@@ -488,6 +536,33 @@ get_entry_number (grub_menu_t menu, const char *name)
   return entry;
 }
 
+/* Check whether a second has elapsed since the last tick.  If so, adjust
+   the timer and return 1; otherwise, return 0.  */
+static int
+has_second_elapsed (grub_uint64_t *saved_time)
+{
+  grub_uint64_t current_time;
+
+  current_time = grub_get_time_ms ();
+  if (current_time - *saved_time >= 1000)
+    {
+      *saved_time = current_time;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static void
+print_countdown (struct grub_term_coordinate *pos, int n)
+{
+  grub_term_restore_pos (pos);
+  /* NOTE: Do not remove the trailing space characters.
+     They are required to clear the line.  */
+  grub_printf ("%d    ", n);
+  grub_refresh ();
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -502,6 +577,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
   grub_uint64_t saved_time;
   int default_entry, current_entry;
   int timeout;
+  enum timeout_style timeout_style;
 
   default_entry = get_entry_number (menu, "default");
 
@@ -510,8 +586,71 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  timeout = grub_menu_get_timeout ();
+  if (timeout < 0)
+    /* If there is no timeout, the "countdown" and "hidden" styles result in
+       the system doing nothing and providing no or very little indication
+       why.  Technically this is what the user asked for, but it's not very
+       useful and likely to be a source of confusion, so we disallow this.  */
+    grub_env_unset ("timeout_style");
+
+  timeout_style = get_timeout_style ();
+
+  if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
+      || timeout_style == TIMEOUT_STYLE_HIDDEN)
+    {
+      static struct grub_term_coordinate *pos;
+      int entry = -1;
+
+      if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
+	{
+	  pos = grub_term_save_pos ();
+	  print_countdown (pos, timeout);
+	}
+
+      /* Enter interruptible sleep until Escape or a menu hotkey is pressed,
+         or the timeout expires.  */
+      saved_time = grub_get_time_ms ();
+      while (1)
+	{
+	  int key;
+
+	  key = grub_getkey_noblock ();
+	  if (key != GRUB_TERM_NO_KEY)
+	    {
+	      entry = get_entry_index_by_hotkey (menu, key);
+	      if (entry >= 0)
+		break;
+	    }
+	  if (key == GRUB_TERM_ESC)
+	    {
+	      timeout = -1;
+	      break;
+	    }
+
+	  if (timeout > 0 && has_second_elapsed (&saved_time))
+	    {
+	      timeout--;
+	      if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
+		print_countdown (pos, timeout);
+	    }
+
+	  if (timeout == 0)
+	    /* We will fall through to auto-booting the default entry.  */
+	    break;
+	}
+
+      grub_env_unset ("timeout");
+      grub_env_unset ("timeout_style");
+      if (entry >= 0)
+	{
+	  *auto_boot = 0;
+	  return entry;
+	}
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
-  if (grub_menu_get_timeout () == 0)
+  if (timeout == 0)
     {
       *auto_boot = 1;
       return default_entry;
@@ -540,18 +679,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
       if (grub_normal_exit_level)
 	return -1;
 
-      if (timeout > 0)
+      if (timeout > 0 && has_second_elapsed (&saved_time))
 	{
-	  grub_uint64_t current_time;
-
-	  current_time = grub_get_time_ms ();
-	  if (current_time - saved_time >= 1000)
-	    {
-	      timeout--;
-	      grub_menu_set_timeout (timeout);
-	      saved_time = current_time;
-	      menu_print_timeout (timeout);
-	    }
+	  timeout--;
+	  grub_menu_set_timeout (timeout);
+	  menu_print_timeout (timeout);
 	}
 
       if (timeout == 0)
@@ -653,16 +785,15 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
 
 	    default:
 	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
+		int entry;
+
+		entry = get_entry_index_by_hotkey (menu, c);
+		if (entry >= 0)
+		  {
+		    menu_fini ();
+		    *auto_boot = 0;
+		    return entry;
+		  }
 	      }
 	      break;
 	    }
diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
index ba1d4ef..50f73aa 100644
--- a/util/grub-mkconfig.in
+++ b/util/grub-mkconfig.in
@@ -186,6 +186,7 @@ export GRUB_DEFAULT \
   GRUB_HIDDEN_TIMEOUT \
   GRUB_HIDDEN_TIMEOUT_QUIET \
   GRUB_TIMEOUT \
+  GRUB_TIMEOUT_STYLE \
   GRUB_DEFAULT_BUTTON \
   GRUB_HIDDEN_TIMEOUT_BUTTON \
   GRUB_TIMEOUT_BUTTON \
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index 9838720..d5cf342 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -282,14 +282,45 @@ fi
 
 make_timeout ()
 {
-    if [ "x${1}" != "x" ] ; then
+    if [ "x${GRUB_TIMEOUT_STYLE}" != "x" ] ; then
+	cat << EOF
+if [ x\$feature_timeout_style = xy ] ; then
+  set timeout_style=${GRUB_TIMEOUT_STYLE}
+  set timeout=${2}
+EOF
+	if [ "x${GRUB_TIMEOUT_STYLE}" != "xmenu" ] ; then
+	    # Fallback hidden-timeout code in case the timeout_style feature
+	    # is unavailable.  Note that we now ignore GRUB_HIDDEN_TIMEOUT
+	    # and take the hidden-timeout from GRUB_TIMEOUT instead.
+	    if [ "x${GRUB_TIMEOUT_STYLE}" = "xhidden" ] ; then
+		verbose=
+	    else
+		verbose=" --verbose"
+	    fi
+	    cat << EOF
+elif sleep$verbose --interruptible ${2} ; then
+  set timeout=0
+EOF
+	fi
+	cat << EOF
+fi
+EOF
+    elif [ "x${1}" != "x" ] ; then
+	if [ "x${2}" != "x0" ] ; then
+	    grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")"
+	fi
 	if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
 	    verbose=
+	    style="hidden"
 	else
 	    verbose=" --verbose"
+	    style="countdown"
 	fi
 	cat << EOF
-if sleep$verbose --interruptible ${1} ; then
+if [ x\$feature_timeout_style = xy ] ; then
+  set timeout_style=$style
+  set timeout=${1}
+elif sleep$verbose --interruptible ${1} ; then
   set timeout=${2}
 fi
 EOF
-- 
1.8.4.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28  2:30             ` Colin Watson
@ 2013-11-28  6:19               ` Vladimir 'phcoder' Serbinenko
  2013-11-28 11:04                 ` Colin Watson
  2013-11-28 17:22               ` Andrey Borzenkov
  1 sibling, 1 reply; 29+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2013-11-28  6:19 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 17059 bytes --]

On Nov 28, 2013 3:31 AM, "Colin Watson" <cjwatson@ubuntu.com> wrote:
>
> Following discussion with Vladimir on IRC, here's another attempt.  The
> preferred user-facing configuration mechanism is now simpler, although
> some unfortunate compatibility code is required to make all this work.
>
> Revamp hidden timeout handling
>
> Add a new timeout_style environment variable and a corresponding
> GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig.  This
> controls hidden-timeout handling more simply than the previous
> arrangements, and pressing any hotkeys associated with menu entries
> during the hidden timeout will now boot the corresponding menu entry
> immediately.
>
> GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now
> generates a warning, and if it shows the menu it will do so as if
> the second timeout were not present.  Other combinations are
> translated into reasonable equivalents.
> ---
>  ChangeLog                |  14 ++++
>  docs/grub.texi           |  57 ++++++++++++---
>  grub-core/normal/main.c  |   2 +-
>  grub-core/normal/menu.c  | 175
+++++++++++++++++++++++++++++++++++++++++------
>  util/grub-mkconfig.in    |   1 +
>  util/grub.d/00_header.in |  35 +++++++++-
>  6 files changed, 251 insertions(+), 33 deletions(-)
>
> diff --git a/ChangeLog b/ChangeLog
> index d24f533..4cc4562 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,17 @@
> +2013-11-28  Colin Watson  <cjwatson@ubuntu.com>
> +
> +       Add a new timeout_style environment variable and a corresponding
> +       GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig.  This
> +       controls hidden-timeout handling more simply than the previous
> +       arrangements, and pressing any hotkeys associated with menu
entries
> +       during the hidden timeout will now boot the corresponding menu
entry
> +       immediately.
> +
> +       GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now
> +       generates a warning, and if it shows the menu it will do so as if
> +       the second timeout were not present.  Other combinations are
> +       translated into reasonable equivalents.
> +
>  2013-11-27  Vladimir Serbinenko  <phcoder@gmail.com>
>
>         Eliminate variable length arrays in grub_vsnprintf_real.
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 6aee292..f494a3d 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -1298,19 +1298,46 @@ a key is pressed.  The default is @samp{5}.  Set
to @samp{0} to boot
>  immediately without displaying the menu, or to @samp{-1} to wait
>  indefinitely.
>
> +If @samp{GRUB_TIMEOUT_STYLE} is set to @samp{countdown} or @samp{hidden},
> +the timeout is instead counted before the menu is displayed.
> +
> +@item GRUB_TIMEOUT_STYLE
> +If this option is unset or set to @samp{menu}, then GRUB will display the
> +menu and then wait for the timeout set by @samp{GRUB_TIMEOUT} to expire
> +before booting the default entry.  Pressing a key interrupts the timeout.
> +
> +If this option is set to @samp{countdown} or @samp{hidden}, then, before
> +displaying the menu, GRUB will wait for the timeout set by
> +@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that
time, it
> +will display the menu and wait for input according to
@samp{GRUB_TIMEOUT}.
> +If a hotkey associated with a menu entry is pressed, it will boot the
> +associated menu entry immediately.  If the timeout expires before either
of
> +these happens, it will display the menu.
What you describe here doesn‘t serm what code is doing. Copypaste error?
> In the @samp{countdown} case, it
> +will show a one-line indication of the remaining time.
> +
>  @item GRUB_HIDDEN_TIMEOUT
> -Wait this many seconds for @key{ESC} to be pressed before displaying the
menu.
> -If no @key{ESC} is pressed during that time, display the menu for the
number of
> -seconds specified in GRUB_TIMEOUT before booting the default entry. We
expect
> -that most people who use GRUB_HIDDEN_TIMEOUT will want to have
GRUB_TIMEOUT set
> -to @samp{0} so that the menu is not displayed at all unless @key{ESC} is
> -pressed.
> -Unset by default.
> +Wait this many seconds before displaying the menu.  If @key{ESC} is
pressed
> +during that time, display the menu and wait for input according to
> +@samp{GRUB_TIMEOUT}.  If a hotkey associated with a menu entry is
pressed,
> +boot the associated menu entry immediately.  If the timeout expires
before
> +either of these happens, display the menu for the number of seconds
> +specified in @samp{GRUB_TIMEOUT} before booting the default entry.
> +
> +If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set
> +@samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless
> +@key{ESC} is pressed.
> +
> +This option is unset by default, and is deprecated in favour of the less
> +confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
> +@samp{GRUB_TIMEOUT_STYLE=hidden}.
>
>  @item GRUB_HIDDEN_TIMEOUT_QUIET
>  In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true}
to
>  suppress the verbose countdown while waiting for a key to be pressed
before
> -displaying the menu.  Unset by default.
> +displaying the menu.
> +
> +This option is unset by default, and is deprecated in favour of the less
> +confusing @samp{GRUB_TIMEOUT_STYLE=countdown}.
>
>  @item GRUB_DEFAULT_BUTTON
>  @itemx GRUB_TIMEOUT_BUTTON
> @@ -3030,6 +3057,7 @@ These variables have special meaning to GRUB.
>  * superusers::
>  * theme::
>  * timeout::
> +* timeout_style::
>  @end menu
>
>
> @@ -3462,10 +3490,23 @@ keyboard input before booting the default menu
entry.  A timeout of @samp{0}
>  means to boot the default entry immediately without displaying the menu;
a
>  timeout of @samp{-1} (or unset) means to wait indefinitely.
>
> +If @samp{timeout_style} (@pxref{timeout_style}) is set to
@samp{countdown}
> +or @samp{hidden}, the timeout is instead counted before the menu is
> +displayed.
> +
>  This variable is often set by @samp{GRUB_TIMEOUT} or
>  @samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}).
>
>
> +@node timeout_style
> +@subsection timeout_style
> +
> +This variable may be set to @samp{menu}, @samp{countdown}, or
@samp{hidden}
> +to control the way in which the timeout (@pxref{timeout}) interacts with
> +displaying the menu.  See the documentation of @samp{GRUB_TIMEOUT_STYLE}
> +(@pxref{Simple configuration}) for details.
> +
> +
>  @node Environment block
>  @section The GRUB environment block
>
> diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
> index ad36273..778de61 100644
> --- a/grub-core/normal/main.c
> +++ b/grub-core/normal/main.c
> @@ -523,7 +523,7 @@ static const char *features[] = {
>    "feature_chainloader_bpb", "feature_ntldr",
"feature_platform_search_hint",
>    "feature_default_font_path", "feature_all_video_module",
>    "feature_menuentry_id", "feature_menuentry_options",
"feature_200_final",
> -  "feature_nativedisk_cmd"
> +  "feature_nativedisk_cmd", "feature_timeout_style"
>  };
>
>  GRUB_MOD_INIT(normal)
> diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
> index 9b88290..fa85c35 100644
> --- a/grub-core/normal/menu.c
> +++ b/grub-core/normal/menu.c
> @@ -40,6 +40,22 @@
>  grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
>                                      int nested) = NULL;
>
> +enum timeout_style {
> +  TIMEOUT_STYLE_MENU,
> +  TIMEOUT_STYLE_COUNTDOWN,
> +  TIMEOUT_STYLE_HIDDEN
> +};
> +
> +struct timeout_style_name {
> +  const char *name;
> +  enum timeout_style style;
> +} timeout_style_names[] = {
> +  {"menu", TIMEOUT_STYLE_MENU},
> +  {"countdown", TIMEOUT_STYLE_COUNTDOWN},
> +  {"hidden", TIMEOUT_STYLE_HIDDEN},
> +  {NULL, 0}
> +};
> +
>  /* Wait until the user pushes any key so that the user
>     can see what happened.  */
>  void
> @@ -70,6 +86,38 @@ grub_menu_get_entry (grub_menu_t menu, int no)
>    return e;
>  }
>
> +/* Get the index of a menu entry associated with a given hotkey, or -1.
 */
> +static int
> +get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
> +{
> +  grub_menu_entry_t entry;
> +  int i;
> +
> +  for (i = 0, entry = menu->entry_list; i < menu->size;
> +       i++, entry = entry->next)
> +    if (entry->hotkey == hotkey)
> +      return i;
> +
> +  return -1;
> +}
> +
> +/* Return the timeout style.  If the variable "timeout_style" is not set
or
> +   invalid, default to TIMEOUT_STYLE_MENU.  */
> +static enum timeout_style
> +get_timeout_style (void)
> +{
> +  const char *val;
> +  struct timeout_style_name *style_name;
> +
> +  val = grub_env_get ("timeout_style");
> +  if (val)
> +    for (style_name = timeout_style_names; style_name->name;
style_name++)
> +      if (grub_strcmp (style_name->name, val) == 0)
> +       return style_name->style;
> +
> +  return TIMEOUT_STYLE_MENU;
> +}
> +
>  /* Return the current timeout. If the variable "timeout" is not set or
>     invalid, return -1.  */
>  int
> @@ -488,6 +536,33 @@ get_entry_number (grub_menu_t menu, const char *name)
>    return entry;
>  }
>
> +/* Check whether a second has elapsed since the last tick.  If so, adjust
> +   the timer and return 1; otherwise, return 0.  */
> +static int
> +has_second_elapsed (grub_uint64_t *saved_time)
> +{
> +  grub_uint64_t current_time;
> +
> +  current_time = grub_get_time_ms ();
> +  if (current_time - *saved_time >= 1000)
> +    {
> +      *saved_time = current_time;
> +      return 1;
> +    }
> +  else
> +    return 0;
> +}
> +
> +static void
> +print_countdown (struct grub_term_coordinate *pos, int n)
> +{
> +  grub_term_restore_pos (pos);
> +  /* NOTE: Do not remove the trailing space characters.
> +     They are required to clear the line.  */
> +  grub_printf ("%d    ", n);
> +  grub_refresh ();
> +}
> +
>  #define GRUB_MENU_PAGE_SIZE 10
>
>  /* Show the menu and handle menu entry selection.  Returns the menu entry
> @@ -502,6 +577,7 @@ run_menu (grub_menu_t menu, int nested, int
*auto_boot)
>    grub_uint64_t saved_time;
>    int default_entry, current_entry;
>    int timeout;
> +  enum timeout_style timeout_style;
>
>    default_entry = get_entry_number (menu, "default");
>
> @@ -510,8 +586,71 @@ run_menu (grub_menu_t menu, int nested, int
*auto_boot)
>    if (default_entry < 0 || default_entry >= menu->size)
>      default_entry = 0;
>
> +  timeout = grub_menu_get_timeout ();
> +  if (timeout < 0)
> +    /* If there is no timeout, the "countdown" and "hidden" styles
result in
> +       the system doing nothing and providing no or very little
indication
> +       why.  Technically this is what the user asked for, but it's not
very
> +       useful and likely to be a source of confusion, so we disallow
this.  */
> +    grub_env_unset ("timeout_style");
> +
> +  timeout_style = get_timeout_style ();
> +
> +  if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
> +      || timeout_style == TIMEOUT_STYLE_HIDDEN)
> +    {
> +      static struct grub_term_coordinate *pos;
> +      int entry = -1;
> +
> +      if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
> +       {
> +         pos = grub_term_save_pos ();
> +         print_countdown (pos, timeout);
> +       }
> +
> +      /* Enter interruptible sleep until Escape or a menu hotkey is
pressed,
> +         or the timeout expires.  */
> +      saved_time = grub_get_time_ms ();
> +      while (1)
> +       {
> +         int key;
> +
> +         key = grub_getkey_noblock ();
> +         if (key != GRUB_TERM_NO_KEY)
> +           {
> +             entry = get_entry_index_by_hotkey (menu, key);
> +             if (entry >= 0)
> +               break;
> +           }
> +         if (key == GRUB_TERM_ESC)
> +           {
> +             timeout = -1;
> +             break;
> +           }
> +
> +         if (timeout > 0 && has_second_elapsed (&saved_time))
> +           {
> +             timeout--;
> +             if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
> +               print_countdown (pos, timeout);
> +           }
> +
> +         if (timeout == 0)
> +           /* We will fall through to auto-booting the default entry.  */
> +           break;
> +       }
> +
> +      grub_env_unset ("timeout");
> +      grub_env_unset ("timeout_style");
> +      if (entry >= 0)
> +       {
> +         *auto_boot = 0;
> +         return entry;
> +       }
> +    }
> +
>    /* If timeout is 0, drawing is pointless (and ugly).  */
> -  if (grub_menu_get_timeout () == 0)
> +  if (timeout == 0)
>      {
>        *auto_boot = 1;
>        return default_entry;
> @@ -540,18 +679,11 @@ run_menu (grub_menu_t menu, int nested, int
*auto_boot)
>        if (grub_normal_exit_level)
>         return -1;
>
> -      if (timeout > 0)
> +      if (timeout > 0 && has_second_elapsed (&saved_time))
>         {
> -         grub_uint64_t current_time;
> -
> -         current_time = grub_get_time_ms ();
> -         if (current_time - saved_time >= 1000)
> -           {
> -             timeout--;
> -             grub_menu_set_timeout (timeout);
> -             saved_time = current_time;
> -             menu_print_timeout (timeout);
> -           }
> +         timeout--;
> +         grub_menu_set_timeout (timeout);
> +         menu_print_timeout (timeout);
>         }
>
>        if (timeout == 0)
> @@ -653,16 +785,15 @@ run_menu (grub_menu_t menu, int nested, int
*auto_boot)
>
>             default:
>               {
> -               grub_menu_entry_t entry;
> -               int i;
> -               for (i = 0, entry = menu->entry_list; i < menu->size;
> -                    i++, entry = entry->next)
> -                 if (entry->hotkey == c)
> -                   {
> -                     menu_fini ();
> -                     *auto_boot = 0;
> -                     return i;
> -                   }
> +               int entry;
> +
> +               entry = get_entry_index_by_hotkey (menu, c);
> +               if (entry >= 0)
> +                 {
> +                   menu_fini ();
> +                   *auto_boot = 0;
> +                   return entry;
> +                 }
>               }
>               break;
>             }
> diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
> index ba1d4ef..50f73aa 100644
> --- a/util/grub-mkconfig.in
> +++ b/util/grub-mkconfig.in
> @@ -186,6 +186,7 @@ export GRUB_DEFAULT \
>    GRUB_HIDDEN_TIMEOUT \
>    GRUB_HIDDEN_TIMEOUT_QUIET \
>    GRUB_TIMEOUT \
> +  GRUB_TIMEOUT_STYLE \
you need button variant as well
>    GRUB_DEFAULT_BUTTON \
>    GRUB_HIDDEN_TIMEOUT_BUTTON \
>    GRUB_TIMEOUT_BUTTON \
> diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
> index 9838720..d5cf342 100644
> --- a/util/grub.d/00_header.in
> +++ b/util/grub.d/00_header.in
> @@ -282,14 +282,45 @@ fi
>
>  make_timeout ()
>  {
> -    if [ "x${1}" != "x" ] ; then
> +    if [ "x${GRUB_TIMEOUT_STYLE}" != "x" ] ; then
> +       cat << EOF
> +if [ x\$feature_timeout_style = xy ] ; then
> +  set timeout_style=${GRUB_TIMEOUT_STYLE}
> +  set timeout=${2}
> +EOF
> +       if [ "x${GRUB_TIMEOUT_STYLE}" != "xmenu" ] ; then
> +           # Fallback hidden-timeout code in case the timeout_style
feature
> +           # is unavailable.  Note that we now ignore GRUB_HIDDEN_TIMEOUT
> +           # and take the hidden-timeout from GRUB_TIMEOUT instead.
> +           if [ "x${GRUB_TIMEOUT_STYLE}" = "xhidden" ] ; then
> +               verbose=
> +           else
> +               verbose=" --verbose"
> +           fi
> +           cat << EOF
> +elif sleep$verbose --interruptible ${2} ; then
> +  set timeout=0
> +EOF
> +       fi
> +       cat << EOF
> +fi
> +EOF
> +    elif [ "x${1}" != "x" ] ; then
> +       if [ "x${2}" != "x0" ] ; then
> +           grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero
value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")"
> +       fi
>         if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
>             verbose=
> +           style="hidden"
>         else
>             verbose=" --verbose"
> +           style="countdown"
>         fi
>         cat << EOF
> -if sleep$verbose --interruptible ${1} ; then
> +if [ x\$feature_timeout_style = xy ] ; then
> +  set timeout_style=$style
> +  set timeout=${1}
> +elif sleep$verbose --interruptible ${1} ; then
>    set timeout=${2}
Is behaviour mismatch between both versions intentional?
I see 2 ways of handling double timeout: either not supporting at all
anymore or generate old code for it. This one seems to be mix of both
>  fi
>  EOF
> --
> 1.8.4.4
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel

[-- Attachment #2: Type: text/html, Size: 21459 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28  6:19               ` Vladimir 'phcoder' Serbinenko
@ 2013-11-28 11:04                 ` Colin Watson
  2013-11-28 14:08                   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-11-28 17:20                   ` [RFC][PATCH] Allow hotkeys to interrupt hidden menu Andrey Borzenkov
  0 siblings, 2 replies; 29+ messages in thread
From: Colin Watson @ 2013-11-28 11:04 UTC (permalink / raw)
  To: grub-devel

On Thu, Nov 28, 2013 at 07:19:46AM +0100, Vladimir 'phcoder' Serbinenko wrote:
> On Nov 28, 2013 3:31 AM, "Colin Watson" <cjwatson@ubuntu.com> wrote:
> > +If this option is set to @samp{countdown} or @samp{hidden}, then, before
> > +displaying the menu, GRUB will wait for the timeout set by
> > +@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that
> > time, it
> > +will display the menu and wait for input according to
> > @samp{GRUB_TIMEOUT}.
> > +If a hotkey associated with a menu entry is pressed, it will boot the
> > +associated menu entry immediately.  If the timeout expires before either
> > of
> > +these happens, it will display the menu.
> 
> What you describe here doesn‘t serm what code is doing. Copypaste error?

I must be missing something.  What part of this doesn't agree with the
code?

... oh, right, if the timeout expires then it will boot the default
entry.  I'll fix that, thanks.

> > diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
> > index ba1d4ef..50f73aa 100644
> > --- a/util/grub-mkconfig.in
> > +++ b/util/grub-mkconfig.in
> > @@ -186,6 +186,7 @@ export GRUB_DEFAULT \
> >    GRUB_HIDDEN_TIMEOUT \
> >    GRUB_HIDDEN_TIMEOUT_QUIET \
> >    GRUB_TIMEOUT \
> > +  GRUB_TIMEOUT_STYLE \
> 
> you need button variant as well

Can you suggest a use case for that?  I can understand why you might
want different timeouts in the button case, just about, but not why
you'd want an entirely different style of menu.

> > +       fi
> >         if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
> >             verbose=
> > +           style="hidden"
> >         else
> >             verbose=" --verbose"
> > +           style="countdown"
> >         fi
> >         cat << EOF
> > -if sleep$verbose --interruptible ${1} ; then
> > +if [ x\$feature_timeout_style = xy ] ; then
> > +  set timeout_style=$style
> > +  set timeout=${1}
> > +elif sleep$verbose --interruptible ${1} ; then
> >    set timeout=${2}
> 
> Is behaviour mismatch between both versions intentional?
> I see 2 ways of handling double timeout: either not supporting at all
> anymore or generate old code for it. This one seems to be mix of both

The code is somewhat inevitably confusing, I'll agree, but I don't see
the mismatch.  Could you please give me an example?

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 11:04                 ` Colin Watson
@ 2013-11-28 14:08                   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-11-29 16:18                     ` Colin Watson
  2013-11-28 17:20                   ` [RFC][PATCH] Allow hotkeys to interrupt hidden menu Andrey Borzenkov
  1 sibling, 1 reply; 29+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-11-28 14:08 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 2764 bytes --]

On 28.11.2013 12:04, Colin Watson wrote:
> On Thu, Nov 28, 2013 at 07:19:46AM +0100, Vladimir 'phcoder' Serbinenko wrote:
>> On Nov 28, 2013 3:31 AM, "Colin Watson" <cjwatson@ubuntu.com> wrote:
>>> +If this option is set to @samp{countdown} or @samp{hidden}, then, before
>>> +displaying the menu, GRUB will wait for the timeout set by
>>> +@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that
>>> time, it
>>> +will display the menu and wait for input according to
>>> @samp{GRUB_TIMEOUT}.
>>> +If a hotkey associated with a menu entry is pressed, it will boot the
>>> +associated menu entry immediately.  If the timeout expires before either
>>> of
>>> +these happens, it will display the menu.
>>
>> What you describe here doesn‘t serm what code is doing. Copypaste error?
> 
> I must be missing something.  What part of this doesn't agree with the
> code?
> 
> ... oh, right, if the timeout expires then it will boot the default
> entry.  I'll fix that, thanks.
> 
>>> diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
>>> index ba1d4ef..50f73aa 100644
>>> --- a/util/grub-mkconfig.in
>>> +++ b/util/grub-mkconfig.in
>>> @@ -186,6 +186,7 @@ export GRUB_DEFAULT \
>>>    GRUB_HIDDEN_TIMEOUT \
>>>    GRUB_HIDDEN_TIMEOUT_QUIET \
>>>    GRUB_TIMEOUT \
>>> +  GRUB_TIMEOUT_STYLE \
>>
>> you need button variant as well
> 
> Can you suggest a use case for that?  I can understand why you might
> want different timeouts in the button case, just about, but not why
> you'd want an entirely different style of menu.
> 
Normal button: normal start, hidden menu
Second button: diagnostic, show menu
>>> +       fi
>>>         if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
>>>             verbose=
>>> +           style="hidden"
>>>         else
>>>             verbose=" --verbose"
>>> +           style="countdown"
>>>         fi
>>>         cat << EOF
>>> -if sleep$verbose --interruptible ${1} ; then
>>> +if [ x\$feature_timeout_style = xy ] ; then
>>> +  set timeout_style=$style
>>> +  set timeout=${1}
>>> +elif sleep$verbose --interruptible ${1} ; then
>>>    set timeout=${2}
>>
>> Is behaviour mismatch between both versions intentional?
>> I see 2 ways of handling double timeout: either not supporting at all
>> anymore or generate old code for it. This one seems to be mix of both
> 
> The code is somewhat inevitably confusing, I'll agree, but I don't see
> the mismatch.  Could you please give me an example?
>
if both GRUB_HIDDEN_TIMEOUT and GRUB_TIMEOUT are set the part for old
GRUB will replicate old behaviour while part for new GRUB would make
only one timeout. To make them align it would need set timeout=-1 at
last line.

> Thanks,
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 11:04                 ` Colin Watson
  2013-11-28 14:08                   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-11-28 17:20                   ` Andrey Borzenkov
  2013-11-28 18:05                     ` Colin Watson
  1 sibling, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-28 17:20 UTC (permalink / raw)
  To: grub-devel

В Thu, 28 Nov 2013 11:04:28 +0000
Colin Watson <cjwatson@ubuntu.com> пишет:

> On Thu, Nov 28, 2013 at 07:19:46AM +0100, Vladimir 'phcoder' Serbinenko wrote:
> > On Nov 28, 2013 3:31 AM, "Colin Watson" <cjwatson@ubuntu.com> wrote:
> > > +If this option is set to @samp{countdown} or @samp{hidden}, then, before
> > > +displaying the menu, GRUB will wait for the timeout set by
> > > +@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that
> > > time, it
> > > +will display the menu and wait for input according to
> > > @samp{GRUB_TIMEOUT}.
> > > +If a hotkey associated with a menu entry is pressed, it will boot the
> > > +associated menu entry immediately.  If the timeout expires before either
> > > of
> > > +these happens, it will display the menu.
> > 
> > What you describe here doesn‘t serm what code is doing. Copypaste error?
> 
> I must be missing something.  What part of this doesn't agree with the
> code?
> 
> ... oh, right, if the timeout expires then it will boot the default
> entry.  I'll fix that, thanks.
> 

Not only. If you hit ESC it will not "wait for input according to
GRUB_TIMEOUT" - it will stop displaying menu.

I'm not sure whether exposing menu but continuing count down is useful.
We could let any other key (or specific key - SPACE?) do it.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28  2:30             ` Colin Watson
  2013-11-28  6:19               ` Vladimir 'phcoder' Serbinenko
@ 2013-11-28 17:22               ` Andrey Borzenkov
  2013-11-28 18:06                 ` Colin Watson
  1 sibling, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-28 17:22 UTC (permalink / raw)
  To: grub-devel

В Thu, 28 Nov 2013 02:30:56 +0000
Colin Watson <cjwatson@ubuntu.com> пишет:

>  @item GRUB_HIDDEN_TIMEOUT
>  @item GRUB_HIDDEN_TIMEOUT_QUIET

I suggest removing them from user visible documentation and leaving
only as compatibility options in grub-mkconfig. No reason do endorse
their usage ("deprecated" is usually was nobody pays attention to).


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 17:20                   ` [RFC][PATCH] Allow hotkeys to interrupt hidden menu Andrey Borzenkov
@ 2013-11-28 18:05                     ` Colin Watson
  2013-11-29  6:17                       ` Andrey Borzenkov
  0 siblings, 1 reply; 29+ messages in thread
From: Colin Watson @ 2013-11-28 18:05 UTC (permalink / raw)
  To: grub-devel

On Thu, Nov 28, 2013 at 09:20:17PM +0400, Andrey Borzenkov wrote:
> Not only. If you hit ESC it will not "wait for input according to
> GRUB_TIMEOUT" - it will stop displaying menu.

No, that's not true in my tests.  If you hit Escape while a hidden
timeout is active and GRUB_TIMEOUT is non-zero, it'll display the menu.

If you can make this happen, please post a detailed test case.

> I'm not sure whether exposing menu but continuing count down is useful.
> We could let any other key (or specific key - SPACE?) do it.

I don't think it's very useful, which is why it isn't available in the
new GRUB_TIMEOUT + GRUB_TIMEOUT_STYLE interface; but it was exposed in
the old GRUB_HIDDEN_TIMEOUT + GRUB_TIMEOUT interface so I don't want to
break it entirely.

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 17:22               ` Andrey Borzenkov
@ 2013-11-28 18:06                 ` Colin Watson
  2013-11-29  6:21                   ` Andrey Borzenkov
  0 siblings, 1 reply; 29+ messages in thread
From: Colin Watson @ 2013-11-28 18:06 UTC (permalink / raw)
  To: grub-devel

On Thu, Nov 28, 2013 at 09:22:49PM +0400, Andrey Borzenkov wrote:
> В Thu, 28 Nov 2013 02:30:56 +0000
> Colin Watson <cjwatson@ubuntu.com> пишет:
> >  @item GRUB_HIDDEN_TIMEOUT
> >  @item GRUB_HIDDEN_TIMEOUT_QUIET
> 
> I suggest removing them from user visible documentation and leaving
> only as compatibility options in grub-mkconfig. No reason do endorse
> their usage ("deprecated" is usually was nobody pays attention to).

My concern is that they will probably hang around in people's
configurations for some time and I would like the documentation to tell
users what these mysterious things mean.

As a compromise, perhaps we could move them to a separate page?

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 18:05                     ` Colin Watson
@ 2013-11-29  6:17                       ` Andrey Borzenkov
  2013-11-29 15:26                         ` Colin Watson
  0 siblings, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-29  6:17 UTC (permalink / raw)
  To: grub-devel

В Thu, 28 Nov 2013 18:05:37 +0000
Colin Watson <cjwatson@ubuntu.com> пишет:

> On Thu, Nov 28, 2013 at 09:20:17PM +0400, Andrey Borzenkov wrote:
> > Not only. If you hit ESC it will not "wait for input according to
> > GRUB_TIMEOUT" - it will stop displaying menu.
> 
> No, that's not true in my tests.  If you hit Escape while a hidden
> timeout is active and GRUB_TIMEOUT is non-zero, it'll display the menu.
> 

Oh, sorry for my English, I see where confusion is. I meant "it will
display menu and stay there indefinitely". But documentation says "it
will display the menu and wait for input according to `GRUB_TIMEOUT'"
which is wrong because timeout is already canceled at this point.

> If you can make this happen, please post a detailed test case.
> 
> > I'm not sure whether exposing menu but continuing count down is useful.
> > We could let any other key (or specific key - SPACE?) do it.
> 
> I don't think it's very useful, which is why it isn't available in the
> new GRUB_TIMEOUT + GRUB_TIMEOUT_STYLE interface; but it was exposed in
> the old GRUB_HIDDEN_TIMEOUT + GRUB_TIMEOUT interface so I don't want to
> break it entirely.
> 

Anyway it is trivial to add if anyone complaints.

Thank you!


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 18:06                 ` Colin Watson
@ 2013-11-29  6:21                   ` Andrey Borzenkov
  0 siblings, 0 replies; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-29  6:21 UTC (permalink / raw)
  To: grub-devel

В Thu, 28 Nov 2013 18:06:44 +0000
Colin Watson <cjwatson@ubuntu.com> пишет:

> On Thu, Nov 28, 2013 at 09:22:49PM +0400, Andrey Borzenkov wrote:
> > В Thu, 28 Nov 2013 02:30:56 +0000
> > Colin Watson <cjwatson@ubuntu.com> пишет:
> > >  @item GRUB_HIDDEN_TIMEOUT
> > >  @item GRUB_HIDDEN_TIMEOUT_QUIET
> > 
> > I suggest removing them from user visible documentation and leaving
> > only as compatibility options in grub-mkconfig. No reason do endorse
> > their usage ("deprecated" is usually was nobody pays attention to).
> 
> My concern is that they will probably hang around in people's
> configurations for some time and I would like the documentation to tell
> users what these mysterious things mean.
> 
> As a compromise, perhaps we could move them to a separate page?
> 

May be collect all deprecated options at the end of list with heading
like "The following options are still accepted for compatibility with
existing configurations but should not be used in new setup anymore" or
similar.

And BTW, we probably need to start collecting NEWS topics - this is
excellent candidate for inclusion :)


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-29  6:17                       ` Andrey Borzenkov
@ 2013-11-29 15:26                         ` Colin Watson
  0 siblings, 0 replies; 29+ messages in thread
From: Colin Watson @ 2013-11-29 15:26 UTC (permalink / raw)
  To: grub-devel

On Fri, Nov 29, 2013 at 10:17:26AM +0400, Andrey Borzenkov wrote:
> В Thu, 28 Nov 2013 18:05:37 +0000
> Colin Watson <cjwatson@ubuntu.com> пишет:
> > On Thu, Nov 28, 2013 at 09:20:17PM +0400, Andrey Borzenkov wrote:
> > > Not only. If you hit ESC it will not "wait for input according to
> > > GRUB_TIMEOUT" - it will stop displaying menu.
> > 
> > No, that's not true in my tests.  If you hit Escape while a hidden
> > timeout is active and GRUB_TIMEOUT is non-zero, it'll display the menu.
> 
> Oh, sorry for my English, I see where confusion is. I meant "it will
> display menu and stay there indefinitely". But documentation says "it
> will display the menu and wait for input according to `GRUB_TIMEOUT'"
> which is wrong because timeout is already canceled at this point.

Ah, I see what you mean, sorry, and thanks.  I've fixed that for the
next version of this patch.

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-28 14:08                   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-11-29 16:18                     ` Colin Watson
  2013-11-29 16:56                       ` Andrey Borzenkov
  2013-11-29 17:29                       ` [PATCH] document sleep command exit codes Andrey Borzenkov
  0 siblings, 2 replies; 29+ messages in thread
From: Colin Watson @ 2013-11-29 16:18 UTC (permalink / raw)
  To: grub-devel

On Thu, Nov 28, 2013 at 03:08:53PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> On 28.11.2013 12:04, Colin Watson wrote:
> > On Thu, Nov 28, 2013 at 07:19:46AM +0100, Vladimir 'phcoder' Serbinenko wrote:
> >> On Nov 28, 2013 3:31 AM, "Colin Watson" <cjwatson@ubuntu.com> wrote:
> >>> +  GRUB_TIMEOUT_STYLE \
> >>
> >> you need button variant as well
> > 
> > Can you suggest a use case for that?  I can understand why you might
> > want different timeouts in the button case, just about, but not why
> > you'd want an entirely different style of menu.
> 
> Normal button: normal start, hidden menu
> Second button: diagnostic, show menu

Oh, I'd clearly totally misunderstood how the vendor power-on button
stuff works.  Thanks for the cluebat.  I've added
GRUB_TIMEOUT_STYLE_BUTTON now.

> >>> -if sleep$verbose --interruptible ${1} ; then
> >>> +if [ x\$feature_timeout_style = xy ] ; then
> >>> +  set timeout_style=$style
> >>> +  set timeout=${1}
> >>> +elif sleep$verbose --interruptible ${1} ; then
> >>>    set timeout=${2}
> >>
> >> Is behaviour mismatch between both versions intentional?
> >> I see 2 ways of handling double timeout: either not supporting at all
> >> anymore or generate old code for it. This one seems to be mix of both
> > 
> > The code is somewhat inevitably confusing, I'll agree, but I don't see
> > the mismatch.  Could you please give me an example?
> 
> if both GRUB_HIDDEN_TIMEOUT and GRUB_TIMEOUT are set the part for old
> GRUB will replicate old behaviour while part for new GRUB would make
> only one timeout. To make them align it would need set timeout=-1 at
> last line.

Ah, you're right that I was apparently trying to preserve the old
behaviour in one of the branches.  However, I think you've read this
backwards in one place.  "sleep --interruptible" returns true (i.e. 0)
if and only if the timeout expires *without* being interrupted, in which
case we want timeout=0, not timeout=-1.  If the timeout is interrupted,
then it should be fine to just fall through, on the grounds that timeout
will previously have been unset.

In any case, I've fixed the inconsistency now, and taken the opportunity
to remove duplication from the code.

What do you think of this version?  I think this takes into account all
the comments to date.

diff --git a/ChangeLog b/ChangeLog
index d24f533..4cc4562 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2013-11-28  Colin Watson  <cjwatson@ubuntu.com>
+
+	Add a new timeout_style environment variable and a corresponding
+	GRUB_TIMEOUT_STYLE configuration key for grub-mkconfig.  This
+	controls hidden-timeout handling more simply than the previous
+	arrangements, and pressing any hotkeys associated with menu entries
+	during the hidden timeout will now boot the corresponding menu entry
+	immediately.
+
+	GRUB_HIDDEN_TIMEOUT=<non-empty> + GRUB_TIMEOUT=<non-zero> now
+	generates a warning, and if it shows the menu it will do so as if
+	the second timeout were not present.  Other combinations are
+	translated into reasonable equivalents.
+
 2013-11-27  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	Eliminate variable length arrays in grub_vsnprintf_real.
diff --git a/docs/grub.texi b/docs/grub.texi
index 6aee292..1caee83 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -1298,23 +1298,26 @@ a key is pressed.  The default is @samp{5}.  Set to @samp{0} to boot
 immediately without displaying the menu, or to @samp{-1} to wait
 indefinitely.
 
-@item GRUB_HIDDEN_TIMEOUT
-Wait this many seconds for @key{ESC} to be pressed before displaying the menu.
-If no @key{ESC} is pressed during that time, display the menu for the number of
-seconds specified in GRUB_TIMEOUT before booting the default entry. We expect
-that most people who use GRUB_HIDDEN_TIMEOUT will want to have GRUB_TIMEOUT set 
-to @samp{0} so that the menu is not displayed at all unless @key{ESC} is
-pressed.
-Unset by default.
-
-@item GRUB_HIDDEN_TIMEOUT_QUIET
-In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
-suppress the verbose countdown while waiting for a key to be pressed before
-displaying the menu.  Unset by default.
+If @samp{GRUB_TIMEOUT_STYLE} is set to @samp{countdown} or @samp{hidden},
+the timeout is instead counted before the menu is displayed.
+
+@item GRUB_TIMEOUT_STYLE
+If this option is unset or set to @samp{menu}, then GRUB will display the
+menu and then wait for the timeout set by @samp{GRUB_TIMEOUT} to expire
+before booting the default entry.  Pressing a key interrupts the timeout.
+
+If this option is set to @samp{countdown} or @samp{hidden}, then, before
+displaying the menu, GRUB will wait for the timeout set by
+@samp{GRUB_TIMEOUT} to expire.  If @key{ESC} is pressed during that time, it
+will display the menu and wait for input.  If a hotkey associated with a
+menu entry is pressed, it will boot the associated menu entry immediately.
+If the timeout expires before either of these happens, it will boot the
+default entry.  In the @samp{countdown} case, it will show a one-line
+indication of the remaining time.
 
 @item GRUB_DEFAULT_BUTTON
 @itemx GRUB_TIMEOUT_BUTTON
-@itemx GRUB_HIDDEN_TIMEOUT_BUTTON
+@itemx GRUB_TIMEOUT_STYLE_BUTTON
 @itemx GRUB_BUTTON_CMOS_ADDRESS
 Variants of the corresponding variables without the @samp{_BUTTON} suffix,
 used to support vendor-specific power buttons.  @xref{Vendor power-on keys}.
@@ -1489,6 +1492,44 @@ Each module will be loaded as early as possible, at the start of
 
 @end table
 
+The following options are still accepted for compatibility with existing
+configurations, but have better replacements:
+
+@table @samp
+@item GRUB_HIDDEN_TIMEOUT
+Wait this many seconds before displaying the menu.  If @key{ESC} is pressed
+during that time, display the menu and wait for input according to
+@samp{GRUB_TIMEOUT}.  If a hotkey associated with a menu entry is pressed,
+boot the associated menu entry immediately.  If the timeout expires before
+either of these happens, display the menu for the number of seconds
+specified in @samp{GRUB_TIMEOUT} before booting the default entry.
+
+If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set
+@samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless
+@key{ESC} is pressed.
+
+This option is unset by default, and is deprecated in favour of the less
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
+@samp{GRUB_TIMEOUT_STYLE=hidden}.
+
+@item GRUB_HIDDEN_TIMEOUT_QUIET
+In conjunction with @samp{GRUB_HIDDEN_TIMEOUT}, set this to @samp{true} to
+suppress the verbose countdown while waiting for a key to be pressed before
+displaying the menu.
+
+This option is unset by default, and is deprecated in favour of the less
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown}.
+
+@item GRUB_HIDDEN_TIMEOUT_BUTTON
+Variant of @samp{GRUB_HIDDEN_TIMEOUT}, used to support vendor-specific power
+buttons.  @xref{Vendor power-on keys}.
+
+This option is unset by default, and is deprecated in favour of the less
+confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
+@samp{GRUB_TIMEOUT_STYLE=hidden}.
+
+@end table
+
 For more detailed customisation of @command{grub-mkconfig}'s output, you may
 edit the scripts in @file{/etc/grub.d} directly.
 @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom
@@ -2477,15 +2518,17 @@ menu requires several fancy features of your terminal.
 @node Vendor power-on keys
 @chapter Using GRUB with vendor power-on keys
 
-Some laptop vendors provide an additional power-on button which boots another
-OS.  GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
-@samp{GRUB_DEFAULT_BUTTON}, @samp{GRUB_HIDDEN_TIMEOUT_BUTTON} and
-@samp{GRUB_BUTTON_CMOS_ADDRESS} variables in default/grub (@pxref{Simple
-configuration}).  @samp{GRUB_TIMEOUT_BUTTON}, @samp{GRUB_DEFAULT_BUTTON} and
-@samp{GRUB_HIDDEN_TIMEOUT_BUTTON} are used instead of the corresponding
-variables without the @samp{_BUTTON} suffix when powered on using the special
-button.  @samp{GRUB_BUTTON_CMOS_ADDRESS} is vendor-specific and partially
-model-specific.  Values known to the GRUB team are:
+Some laptop vendors provide an additional power-on button which boots
+another OS.  GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
+@samp{GRUB_TIMEOUT_STYLE_BUTTON}, @samp{GRUB_DEFAULT_BUTTON},
+@samp{GRUB_HIDDEN_TIMEOUT_BUTTON} and @samp{GRUB_BUTTON_CMOS_ADDRESS}
+variables in default/grub (@pxref{Simple configuration}).
+@samp{GRUB_TIMEOUT_BUTTON}, @samp{GRUB_TIMEOUT_STYLE_BUTTON},
+@samp{GRUB_DEFAULT_BUTTON}, and @samp{GRUB_HIDDEN_TIMEOUT_BUTTON} are used
+instead of the corresponding variables without the @samp{_BUTTON} suffix
+when powered on using the special button.  @samp{GRUB_BUTTON_CMOS_ADDRESS}
+is vendor-specific and partially model-specific.  Values known to the GRUB
+team are:
 
 @table @key
 @item Dell XPS M1330M
@@ -3030,6 +3073,7 @@ These variables have special meaning to GRUB.
 * superusers::
 * theme::
 * timeout::
+* timeout_style::
 @end menu
 
 
@@ -3462,10 +3506,23 @@ keyboard input before booting the default menu entry.  A timeout of @samp{0}
 means to boot the default entry immediately without displaying the menu; a
 timeout of @samp{-1} (or unset) means to wait indefinitely.
 
+If @samp{timeout_style} (@pxref{timeout_style}) is set to @samp{countdown}
+or @samp{hidden}, the timeout is instead counted before the menu is
+displayed.
+
 This variable is often set by @samp{GRUB_TIMEOUT} or
 @samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}).
 
 
+@node timeout_style
+@subsection timeout_style
+
+This variable may be set to @samp{menu}, @samp{countdown}, or @samp{hidden}
+to control the way in which the timeout (@pxref{timeout}) interacts with
+displaying the menu.  See the documentation of @samp{GRUB_TIMEOUT_STYLE}
+(@pxref{Simple configuration}) for details.
+
+
 @node Environment block
 @section The GRUB environment block
 
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index ad36273..778de61 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -523,7 +523,7 @@ static const char *features[] = {
   "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
   "feature_default_font_path", "feature_all_video_module",
   "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
-  "feature_nativedisk_cmd"
+  "feature_nativedisk_cmd", "feature_timeout_style"
 };
 
 GRUB_MOD_INIT(normal)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 9b88290..fa85c35 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -40,6 +40,22 @@
 grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
 				     int nested) = NULL;
 
+enum timeout_style {
+  TIMEOUT_STYLE_MENU,
+  TIMEOUT_STYLE_COUNTDOWN,
+  TIMEOUT_STYLE_HIDDEN
+};
+
+struct timeout_style_name {
+  const char *name;
+  enum timeout_style style;
+} timeout_style_names[] = {
+  {"menu", TIMEOUT_STYLE_MENU},
+  {"countdown", TIMEOUT_STYLE_COUNTDOWN},
+  {"hidden", TIMEOUT_STYLE_HIDDEN},
+  {NULL, 0}
+};
+
 /* Wait until the user pushes any key so that the user
    can see what happened.  */
 void
@@ -70,6 +86,38 @@ grub_menu_get_entry (grub_menu_t menu, int no)
   return e;
 }
 
+/* Get the index of a menu entry associated with a given hotkey, or -1.  */
+static int
+get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
+{
+  grub_menu_entry_t entry;
+  int i;
+
+  for (i = 0, entry = menu->entry_list; i < menu->size;
+       i++, entry = entry->next)
+    if (entry->hotkey == hotkey)
+      return i;
+
+  return -1;
+}
+
+/* Return the timeout style.  If the variable "timeout_style" is not set or
+   invalid, default to TIMEOUT_STYLE_MENU.  */
+static enum timeout_style
+get_timeout_style (void)
+{
+  const char *val;
+  struct timeout_style_name *style_name;
+
+  val = grub_env_get ("timeout_style");
+  if (val)
+    for (style_name = timeout_style_names; style_name->name; style_name++)
+      if (grub_strcmp (style_name->name, val) == 0)
+	return style_name->style;
+
+  return TIMEOUT_STYLE_MENU;
+}
+
 /* Return the current timeout. If the variable "timeout" is not set or
    invalid, return -1.  */
 int
@@ -488,6 +536,33 @@ get_entry_number (grub_menu_t menu, const char *name)
   return entry;
 }
 
+/* Check whether a second has elapsed since the last tick.  If so, adjust
+   the timer and return 1; otherwise, return 0.  */
+static int
+has_second_elapsed (grub_uint64_t *saved_time)
+{
+  grub_uint64_t current_time;
+
+  current_time = grub_get_time_ms ();
+  if (current_time - *saved_time >= 1000)
+    {
+      *saved_time = current_time;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static void
+print_countdown (struct grub_term_coordinate *pos, int n)
+{
+  grub_term_restore_pos (pos);
+  /* NOTE: Do not remove the trailing space characters.
+     They are required to clear the line.  */
+  grub_printf ("%d    ", n);
+  grub_refresh ();
+}
+
 #define GRUB_MENU_PAGE_SIZE 10
 
 /* Show the menu and handle menu entry selection.  Returns the menu entry
@@ -502,6 +577,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
   grub_uint64_t saved_time;
   int default_entry, current_entry;
   int timeout;
+  enum timeout_style timeout_style;
 
   default_entry = get_entry_number (menu, "default");
 
@@ -510,8 +586,71 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
   if (default_entry < 0 || default_entry >= menu->size)
     default_entry = 0;
 
+  timeout = grub_menu_get_timeout ();
+  if (timeout < 0)
+    /* If there is no timeout, the "countdown" and "hidden" styles result in
+       the system doing nothing and providing no or very little indication
+       why.  Technically this is what the user asked for, but it's not very
+       useful and likely to be a source of confusion, so we disallow this.  */
+    grub_env_unset ("timeout_style");
+
+  timeout_style = get_timeout_style ();
+
+  if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
+      || timeout_style == TIMEOUT_STYLE_HIDDEN)
+    {
+      static struct grub_term_coordinate *pos;
+      int entry = -1;
+
+      if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
+	{
+	  pos = grub_term_save_pos ();
+	  print_countdown (pos, timeout);
+	}
+
+      /* Enter interruptible sleep until Escape or a menu hotkey is pressed,
+         or the timeout expires.  */
+      saved_time = grub_get_time_ms ();
+      while (1)
+	{
+	  int key;
+
+	  key = grub_getkey_noblock ();
+	  if (key != GRUB_TERM_NO_KEY)
+	    {
+	      entry = get_entry_index_by_hotkey (menu, key);
+	      if (entry >= 0)
+		break;
+	    }
+	  if (key == GRUB_TERM_ESC)
+	    {
+	      timeout = -1;
+	      break;
+	    }
+
+	  if (timeout > 0 && has_second_elapsed (&saved_time))
+	    {
+	      timeout--;
+	      if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
+		print_countdown (pos, timeout);
+	    }
+
+	  if (timeout == 0)
+	    /* We will fall through to auto-booting the default entry.  */
+	    break;
+	}
+
+      grub_env_unset ("timeout");
+      grub_env_unset ("timeout_style");
+      if (entry >= 0)
+	{
+	  *auto_boot = 0;
+	  return entry;
+	}
+    }
+
   /* If timeout is 0, drawing is pointless (and ugly).  */
-  if (grub_menu_get_timeout () == 0)
+  if (timeout == 0)
     {
       *auto_boot = 1;
       return default_entry;
@@ -540,18 +679,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
       if (grub_normal_exit_level)
 	return -1;
 
-      if (timeout > 0)
+      if (timeout > 0 && has_second_elapsed (&saved_time))
 	{
-	  grub_uint64_t current_time;
-
-	  current_time = grub_get_time_ms ();
-	  if (current_time - saved_time >= 1000)
-	    {
-	      timeout--;
-	      grub_menu_set_timeout (timeout);
-	      saved_time = current_time;
-	      menu_print_timeout (timeout);
-	    }
+	  timeout--;
+	  grub_menu_set_timeout (timeout);
+	  menu_print_timeout (timeout);
 	}
 
       if (timeout == 0)
@@ -653,16 +785,15 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
 
 	    default:
 	      {
-		grub_menu_entry_t entry;
-		int i;
-		for (i = 0, entry = menu->entry_list; i < menu->size;
-		     i++, entry = entry->next)
-		  if (entry->hotkey == c)
-		    {
-		      menu_fini ();
-		      *auto_boot = 0;
-		      return i;
-		    }
+		int entry;
+
+		entry = get_entry_index_by_hotkey (menu, c);
+		if (entry >= 0)
+		  {
+		    menu_fini ();
+		    *auto_boot = 0;
+		    return entry;
+		  }
 	      }
 	      break;
 	    }
diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
index ba1d4ef..016ee82 100644
--- a/util/grub-mkconfig.in
+++ b/util/grub-mkconfig.in
@@ -186,9 +186,11 @@ export GRUB_DEFAULT \
   GRUB_HIDDEN_TIMEOUT \
   GRUB_HIDDEN_TIMEOUT_QUIET \
   GRUB_TIMEOUT \
+  GRUB_TIMEOUT_STYLE \
   GRUB_DEFAULT_BUTTON \
   GRUB_HIDDEN_TIMEOUT_BUTTON \
   GRUB_TIMEOUT_BUTTON \
+  GRUB_TIMEOUT_STYLE_BUTTON \
   GRUB_BUTTON_CMOS_ADDRESS \
   GRUB_BUTTON_CMOS_CLEAN \
   GRUB_DISTRIBUTOR \
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index 9838720..d2e7252 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -282,15 +282,41 @@ fi
 
 make_timeout ()
 {
-    if [ "x${1}" != "x" ] ; then
-	if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
-	    verbose=
+    if [ "x${1}${3}" != "x" ] ; then
+	if [ "x${3}" != "x" ] ; then
+	    timeout="${2}"
+	    style="${3}"
 	else
+	    # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
+	    timeout="${1}"
+	    if [ "x${2}" != "x0" ] ; then
+		grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")"
+	    fi
+	    if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
+		style="hidden"
+	    else
+		style="countdown"
+	    fi
+	fi
+	if [ "x${style}" = "xcountdown" ] ; then
 	    verbose=" --verbose"
+	else
+	    verbose=
+	fi
+	cat << EOF
+if [ x\$feature_timeout_style = xy ] ; then
+  set timeout_style=${style}
+  set timeout=${timeout}
+EOF
+	if [ "x${style}" != "xmenu" ] ; then
+	    cat << EOF
+# Fallback hidden-timeout code in case the timeout_style feature is
+# unavailable.
+elif sleep${verbose} --interruptible ${timeout} ; then
+  set timeout=0
+EOF
 	fi
 	cat << EOF
-if sleep$verbose --interruptible ${1} ; then
-  set timeout=${2}
 fi
 EOF
     else
@@ -304,12 +330,12 @@ if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
     cat <<EOF
 if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
 EOF
-make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}"
+make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_STYLE_BUTTON}"
 echo else
-make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
+make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
 echo fi
 else
-make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
+make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}"
 fi
 
 if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ] && [ "x$GRUB_BUTTON_CMOS_CLEAN" = "xyes" ]; then

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-29 16:18                     ` Colin Watson
@ 2013-11-29 16:56                       ` Andrey Borzenkov
  2013-11-29 17:20                         ` Colin Watson
  2013-11-29 17:29                       ` [PATCH] document sleep command exit codes Andrey Borzenkov
  1 sibling, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-29 16:56 UTC (permalink / raw)
  To: grub-devel

В Fri, 29 Nov 2013 16:18:45 +0000
Colin Watson <cjwatson@ubuntu.com> пишет:

>  This variable is often set by @samp{GRUB_TIMEOUT} or
>  @samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}).

> +Some laptop vendors provide an additional power-on button which boots
> +another OS.  GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
> +@samp{GRUB_TIMEOUT_STYLE_BUTTON}, @samp{GRUB_DEFAULT_BUTTON},
> +@samp{GRUB_HIDDEN_TIMEOUT_BUTTON} and @samp{GRUB_BUTTON_CMOS_ADDRESS}
> +variables in default/grub (@pxref{Simple configuration}).
> +@samp{GRUB_TIMEOUT_BUTTON}, @samp{GRUB_TIMEOUT_STYLE_BUTTON},
> +@samp{GRUB_DEFAULT_BUTTON}, and @samp{GRUB_HIDDEN_TIMEOUT_BUTTON} are used

Please do not mention (resp. remove) deprecated options here. This falls
under "endorse usage" :)


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [RFC][PATCH] Allow hotkeys to interrupt hidden menu
  2013-11-29 16:56                       ` Andrey Borzenkov
@ 2013-11-29 17:20                         ` Colin Watson
  0 siblings, 0 replies; 29+ messages in thread
From: Colin Watson @ 2013-11-29 17:20 UTC (permalink / raw)
  To: The development of GNU GRUB

On Fri, Nov 29, 2013 at 08:56:03PM +0400, Andrey Borzenkov wrote:
> В Fri, 29 Nov 2013 16:18:45 +0000
> Colin Watson <cjwatson@ubuntu.com> пишет:
> > +Some laptop vendors provide an additional power-on button which boots
> > +another OS.  GRUB supports such buttons with the @samp{GRUB_TIMEOUT_BUTTON},
> > +@samp{GRUB_TIMEOUT_STYLE_BUTTON}, @samp{GRUB_DEFAULT_BUTTON},
> > +@samp{GRUB_HIDDEN_TIMEOUT_BUTTON} and @samp{GRUB_BUTTON_CMOS_ADDRESS}
> > +variables in default/grub (@pxref{Simple configuration}).
> > +@samp{GRUB_TIMEOUT_BUTTON}, @samp{GRUB_TIMEOUT_STYLE_BUTTON},
> > +@samp{GRUB_DEFAULT_BUTTON}, and @samp{GRUB_HIDDEN_TIMEOUT_BUTTON} are used
> 
> Please do not mention (resp. remove) deprecated options here. This falls
> under "endorse usage" :)

Fixed, thanks.

  http://git.savannah.gnu.org/gitweb/?p=grub.git;a=commitdiff;h=f70ab525f941fc24cd721720751e2f0ff283b17c
  
-- 
Colin Watson                                       [cjwatson@ubuntu.com]


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH] document sleep command exit codes
  2013-11-29 16:18                     ` Colin Watson
  2013-11-29 16:56                       ` Andrey Borzenkov
@ 2013-11-29 17:29                       ` Andrey Borzenkov
  2013-11-30 10:39                         ` Vladimir 'φ-coder/phcoder' Serbinenko
  1 sibling, 1 reply; 29+ messages in thread
From: Andrey Borzenkov @ 2013-11-29 17:29 UTC (permalink / raw)
  To: grub-devel

>                          "sleep --interruptible" returns true (i.e. 0)
> if and only if the timeout expires *without* being interrupted, 

This should not require digging in sources ...

---
 docs/grub.texi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 529e328..ceea7eb 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4883,7 +4883,8 @@ Alias for @code{hashsum --hash sha512 arg @dots{}}. See command @command{hashsum
 @deffn Command sleep [@option{--verbose}] [@option{--interruptible}] count
 Sleep for @var{count} seconds. If option @option{--interruptible} is given,
 allow @key{ESC} to interrupt sleep. With @option{--verbose} show countdown
-of remaining seconds.
+of remaining seconds. Exit code is set to 0 if timeout expired and to 1
+if timeout was interrupted by @key{ESC}.
 @end deffn
 
 
-- 
tg: (8ddf84b..) u/sleep-exit-code (depends on: master)


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH] document sleep command exit codes
  2013-11-29 17:29                       ` [PATCH] document sleep command exit codes Andrey Borzenkov
@ 2013-11-30 10:39                         ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 0 replies; 29+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-11-30 10:39 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 1000 bytes --]

On 29.11.2013 18:29, Andrey Borzenkov wrote:
>>                          "sleep --interruptible" returns true (i.e. 0)
>> if and only if the timeout expires *without* being interrupted, 
> 
> This should not require digging in sources ...
> 
Go ahead
> ---
>  docs/grub.texi | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 529e328..ceea7eb 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -4883,7 +4883,8 @@ Alias for @code{hashsum --hash sha512 arg @dots{}}. See command @command{hashsum
>  @deffn Command sleep [@option{--verbose}] [@option{--interruptible}] count
>  Sleep for @var{count} seconds. If option @option{--interruptible} is given,
>  allow @key{ESC} to interrupt sleep. With @option{--verbose} show countdown
> -of remaining seconds.
> +of remaining seconds. Exit code is set to 0 if timeout expired and to 1
> +if timeout was interrupted by @key{ESC}.
>  @end deffn
>  
>  
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2013-11-30 10:40 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-11 13:18 [RFC][PATCH] Allow hotkeys to interrupt hidden menu Colin Watson
2013-09-11 13:31 ` Colin Watson
2013-09-12  2:40   ` Andrey Borzenkov
2013-09-13  9:18   ` Franz Hsieh
2013-09-19  6:28     ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-02  8:03     ` Franz Hsieh
2013-10-02  8:50       ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-14  6:02       ` Franz Hsieh
2013-10-21  6:45         ` Franz Hsieh
2013-11-04  3:10           ` Yang Bai
2013-11-27 23:40           ` Colin Watson
2013-11-28  2:30             ` Colin Watson
2013-11-28  6:19               ` Vladimir 'phcoder' Serbinenko
2013-11-28 11:04                 ` Colin Watson
2013-11-28 14:08                   ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-11-29 16:18                     ` Colin Watson
2013-11-29 16:56                       ` Andrey Borzenkov
2013-11-29 17:20                         ` Colin Watson
2013-11-29 17:29                       ` [PATCH] document sleep command exit codes Andrey Borzenkov
2013-11-30 10:39                         ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-11-28 17:20                   ` [RFC][PATCH] Allow hotkeys to interrupt hidden menu Andrey Borzenkov
2013-11-28 18:05                     ` Colin Watson
2013-11-29  6:17                       ` Andrey Borzenkov
2013-11-29 15:26                         ` Colin Watson
2013-11-28 17:22               ` Andrey Borzenkov
2013-11-28 18:06                 ` Colin Watson
2013-11-29  6:21                   ` Andrey Borzenkov
2013-09-12  2:44 ` Andrey Borzenkov
2013-09-12 13:17   ` Colin Watson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.