diff src/keyboard.c @ 3972:e49ff3115e7d

(read_char): After Fgarbage_collect, call redisplay. (read_key_sequence): When inserting `menu-bar' prefix, modify the position field to prevent doing so twice. Do all these forms of event expansion after replayed events also. Set last_real_key_start before each key. Use last_real_key_start in criterion for being the first event. (syms_of_keyboard): Doc fix. (Vhelp_char): Renamed from help_char. (Vprefix_help_command): New Lisp variable. (read_key_sequence): Use that, for help char after prefix key. (kbd_buffer_get_event): Clear f before calling mouse_position_hook.
author Richard M. Stallman <rms@gnu.org>
date Sun, 04 Jul 1993 02:21:02 +0000
parents d620db2bc420
children 992a1abeb6cd
line wrap: on
line diff
--- a/src/keyboard.c	Sun Jul 04 02:20:59 1993 +0000
+++ b/src/keyboard.c	Sun Jul 04 02:21:02 1993 +0000
@@ -122,11 +122,14 @@
 int immediate_quit;
 
 /* Character to recognize as the help char.  */
-Lisp_Object help_char;
+Lisp_Object Vhelp_char;
 
 /* Form to execute when help char is typed.  */
 Lisp_Object Vhelp_form;
 
+/* Command to run when the help character follows a prefix key.  */
+Lisp_Object Vprefix_help_command;
+
 /* Character that causes a quit.  Normally C-g.
 
    If we are running on an ordinary terminal, this must be an ordinary
@@ -505,7 +508,7 @@
 	  ptr += name->size;
 	}
 
-      if (echoptr == echobuf && EQ (c, help_char))
+      if (echoptr == echobuf && EQ (c, Vhelp_char))
 	{
 	  strcpy (ptr, " (Type ? for further options)");
 	  ptr += strlen (ptr);
@@ -1480,7 +1483,10 @@
 		 consing going on to make it worthwhile.  */
 	      if (!detect_input_pending ()
 		  && consing_since_gc > gc_cons_threshold / 2)
-		Fgarbage_collect ();
+		{
+		  Fgarbage_collect ();
+		  redisplay ();
+		}
 	    }
 	}
     }
@@ -1587,7 +1593,7 @@
   num_input_chars++;
 
   /* Process the help character specially if enabled */
-  if (EQ (c, help_char) && !NILP (Vhelp_form))
+  if (EQ (c, Vhelp_char) && !NILP (Vhelp_form))
     {
       Lisp_Object tem0;
       count = specpdl_ptr - specpdl;
@@ -1914,7 +1920,7 @@
     }
   else if (do_mouse_tracking && mouse_moved)
     {
-      FRAME_PTR f;
+      FRAME_PTR f = 0;
       Lisp_Object bar_window;
       enum scroll_bar_part part;
       Lisp_Object x, y;
@@ -3802,6 +3808,9 @@
       this_command_key_count = keys_local_start;
       first_binding = local_first_binding;
 
+      /* By default, assume each event is "real".  */
+      last_real_key_start = t;
+
       /* Does mock_input indicate that we are re-reading a key sequence?  */
       if (t < mock_input)
 	{
@@ -3815,8 +3824,6 @@
 	{
 	  struct buffer *buf = current_buffer;
 
-	  last_real_key_start = t;
-
 	  key = read_char (!prompt, nmaps, submaps, last_nonmenu_event,
 			   &used_mouse_menu);
 
@@ -3830,125 +3837,131 @@
 	    }
 	  
 	  Vquit_flag = Qnil;
-
-	  /* Clicks in non-text areas get prefixed by the symbol 
-	     in their CHAR-ADDRESS field.  For example, a click on
-	     the mode line is prefixed by the symbol `mode-line'.
-
-	     Furthermore, key sequences beginning with mouse clicks
-	     are read using the keymaps of the buffer clicked on, not
-	     the current buffer.  So we may have to switch the buffer
-	     here.
-
-	     If the event was obtained from the unread_command_events
-	     queue, then don't expand it; we did that the first time
-	     we read it.  */
-	  if (EVENT_HAS_PARAMETERS (key))
+	}
+
+      /* Clicks in non-text areas get prefixed by the symbol 
+	 in their CHAR-ADDRESS field.  For example, a click on
+	 the mode line is prefixed by the symbol `mode-line'.
+
+	 Furthermore, key sequences beginning with mouse clicks
+	 are read using the keymaps of the buffer clicked on, not
+	 the current buffer.  So we may have to switch the buffer
+	 here.
+
+	 When we turn one event into two events, we must make sure
+	 that neither of the two looks like the original--so that,
+	 if we replay the events, they won't be expanded again.
+	 If not for this, such reexpansion could happen either here
+	 or when user programs play with this-command-keys.  */
+      if (EVENT_HAS_PARAMETERS (key))
+	{
+	  Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+
+	  if (EQ (kind, Qmouse_click))
 	    {
-	      Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
-
-	      if (EQ (kind, Qmouse_click))
+	      Lisp_Object window = POSN_WINDOW      (EVENT_START (key));
+	      Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
+
+	      if (XTYPE (posn) == Lisp_Cons)
 		{
-		  Lisp_Object window = POSN_WINDOW      (EVENT_START (key));
-		  Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
-
-		  /* Key sequences beginning with mouse clicks are
-		     read using the keymaps in the buffer clicked on,
-		     not the current buffer.  If we're at the
-		     beginning of a key sequence, switch buffers.  */
-		  if (t == 0
-		      && XTYPE (window) == Lisp_Window
-		      && XTYPE (XWINDOW (window)->buffer) == Lisp_Buffer
-		      && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
-		    {
-		      keybuf[t] = key;
-		      mock_input = t + 1;
-
-		      /* Arrange to go back to the original buffer once we're
-			 done reading the key sequence.  Note that we can't
-			 use save_excursion_{save,restore} here, because they
-			 save point as well as the current buffer; we don't
-			 want to save point, because redisplay may change it,
-			 to accommodate a Fset_window_start or something.  We
-			 don't want to do this at the top of the function,
-			 because we may get input from a subprocess which
-			 wants to change the selected window and stuff (say,
-			 emacsclient).  */
-		      record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
-			 
-		      set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
-		      goto replay_sequence;
-		    }
-		  else if (XTYPE (posn) == Lisp_Symbol)
-		    {
-		      if (t + 1 >= bufsize)
-			error ("key sequence too long");
-		      keybuf[t] = posn;
-		      keybuf[t+1] = key;
-		      mock_input = t + 2;
-
-		      /* Zap the position in key, so we know that we've
-			 expanded it, and don't try to do so again.  */
-		      POSN_BUFFER_POSN (EVENT_START (key))
-			= Fcons (posn, Qnil);
-
-		      /* If we switched buffers while reading the first event,
-			 replay in case we switched keymaps too.  */
-		      if (buf != current_buffer && t == 0)
-			goto replay_sequence;
-		      goto replay_key;
-		    }
-		  else if (XTYPE (posn) == Lisp_Cons)
-		    {
-		      /* We're looking at the second event of a
-			 sequence which we expanded before.  Set
-			 last_real_key_start appropriately.  */
-		      if (last_real_key_start == t && t > 0)
-			last_real_key_start = t - 1;
-		    }
+		  /* We're looking at the second event of a
+		     sequence which we expanded before.  Set
+		     last_real_key_start appropriately.  */
+		  if (t > 0)
+		    last_real_key_start = t - 1;
 		}
-	      else if (EQ (kind, Qswitch_frame))
-		{
-		  /* If we're at the beginning of a key sequence, go
-		     ahead and return this event.  If we're in the
-		     midst of a key sequence, delay it until the end. */
-		  if (t > 0)
-		    {
-		      delayed_switch_frame = key;
-		      goto replay_key;
-		    }
-		}
-	      else
+
+	      /* Key sequences beginning with mouse clicks are
+		 read using the keymaps in the buffer clicked on,
+		 not the current buffer.  If we're at the
+		 beginning of a key sequence, switch buffers.  */
+	      if (last_real_key_start == 0
+		  && XTYPE (window) == Lisp_Window
+		  && XTYPE (XWINDOW (window)->buffer) == Lisp_Buffer
+		  && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
 		{
-		  Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
-
-		  /* Handle menu-bar events:
-		     insert the dummy prefix char `menu-bar'.  */
-		  if (EQ (posn, Qmenu_bar))
-		    {
-		      if (t + 1 >= bufsize)
-			error ("key sequence too long");
-		      /* Run the Lucid hook.  */
-		      call1 (Vrun_hooks, Qactivate_menubar_hook);
-		      /* If it has changed current-menubar from previous value,
-			 really recompute the menubar from the value.  */
-		      if (! NILP (Vlucid_menu_bar_dirty_flag))
-			call0 (Qrecompute_lucid_menubar);
-		      keybuf[t] = posn;
-		      keybuf[t+1] = key;
-		      mock_input = t + 2;
-		      goto replay_sequence;
-		    }
+		  keybuf[t] = key;
+		  mock_input = t + 1;
+
+		  /* Arrange to go back to the original buffer once we're
+		     done reading the key sequence.  Note that we can't
+		     use save_excursion_{save,restore} here, because they
+		     save point as well as the current buffer; we don't
+		     want to save point, because redisplay may change it,
+		     to accommodate a Fset_window_start or something.  We
+		     don't want to do this at the top of the function,
+		     because we may get input from a subprocess which
+		     wants to change the selected window and stuff (say,
+		     emacsclient).  */
+		  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
+		  set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
+		  goto replay_sequence;
+		}
+	      else if (XTYPE (posn) == Lisp_Symbol)
+		{
+		  /* Expand mode-line and scroll-bar events into two events:
+		     use posn as a fake prefix key.  */
+
+		  if (t + 1 >= bufsize)
+		    error ("key sequence too long");
+		  keybuf[t] = posn;
+		  keybuf[t+1] = key;
+		  mock_input = t + 2;
+
+		  /* Zap the position in key, so we know that we've
+		     expanded it, and don't try to do so again.  */
+		  POSN_BUFFER_POSN (EVENT_START (key))
+		    = Fcons (posn, Qnil);
+		  goto replay_key;
 		}
 	    }
-
-	  /* If we switched buffers while reading the first event,
-	     replay in case we switched keymaps too.  */
-	  if (buf != current_buffer && t == 0)
+	  else if (EQ (kind, Qswitch_frame))
+	    {
+	      /* If we're at the beginning of a key sequence, go
+		 ahead and return this event.  If we're in the
+		 midst of a key sequence, delay it until the end. */
+	      if (t > 0)
+		{
+		  delayed_switch_frame = key;
+		  goto replay_key;
+		}
+	    }
+	  else
 	    {
-	      keybuf[t++] = key;
-	      mock_input = t;
-	      goto replay_sequence;
+	      Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
+
+	      /* Handle menu-bar events:
+		 insert the dummy prefix event `menu-bar'.  */
+	      if (EQ (posn, Qmenu_bar))
+		{
+		  if (t + 1 >= bufsize)
+		    error ("key sequence too long");
+		  /* Run the Lucid hook.  */
+		  call1 (Vrun_hooks, Qactivate_menubar_hook);
+		  /* If it has changed current-menubar from previous value,
+		     really recompute the menubar from the value.  */
+		  if (! NILP (Vlucid_menu_bar_dirty_flag))
+		    call0 (Qrecompute_lucid_menubar);
+		  keybuf[t] = posn;
+		  keybuf[t+1] = key;
+
+		  /* Zap the position in key, so we know that we've
+		     expanded it, and don't try to do so again.  */
+		  POSN_BUFFER_POSN (EVENT_START (key))
+		    = Fcons (posn, Qnil);
+
+		  mock_input = t + 2;
+		  goto replay_sequence;
+		}
+	      else if (XTYPE (posn) == Lisp_Cons)
+		{
+		  /* We're looking at the second event of a
+		     sequence which we expanded before.  Set
+		     last_real_key_start appropriately.  */
+		  if (last_real_key_start == t && t > 0)
+		    last_real_key_start = t - 1;
+		}
 	    }
 	}
 
@@ -3966,6 +3979,14 @@
 	{
 	  Lisp_Object head = EVENT_HEAD (key);
 
+	  if (EQ (head, Vhelp_char))
+	    {
+	      read_key_sequence_cmd = Vprefix_help_command;
+	      keybuf[t++] = key;
+	      last_nonmenu_event = key;
+	      goto done;
+	    }
+
 	  if (XTYPE (head) == Lisp_Symbol)
 	    {
 	      Lisp_Object breakdown = parse_modifiers (head);
@@ -5081,18 +5102,24 @@
   Vlast_event_frame = Qnil;
 #endif
 
-  DEFVAR_LISP ("help-char", &help_char,
+  DEFVAR_LISP ("help-char", &Vhelp_char,
     "Character to recognize as meaning Help.\n\
 When it is read, do `(eval help-form)', and display result if it's a string.\n\
 If the value of `help-form' is nil, this char can be read normally.");
-  XSET (help_char, Lisp_Int, Ctl ('H'));
+  XSET (Vhelp_char, Lisp_Int, Ctl ('H'));
 
   DEFVAR_LISP ("help-form", &Vhelp_form,
-    "Form to execute when character help-char is read.\n\
+    "Form to execute when character `help-char' is read.\n\
 If the form returns a string, that string is displayed.\n\
 If `help-form' is nil, the help char is not recognized.");
   Vhelp_form = Qnil;
 
+  DEFVAR_LISP ("prefix-help-command", &Vprefix_help_command,
+    "Command to run when `help-char' character follows a prefix key.\n\
+This command is used only when there is no actual binding\n\
+for that character after that prefix key.");
+  Vprefix_help_command = Qnil;
+
   DEFVAR_LISP ("top-level", &Vtop_level,
     "Form to evaluate when Emacs starts up.\n\
 Useful to set before you dump a modified Emacs.");
@@ -5144,7 +5171,7 @@
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
-    "Normal hook run before each command is executed.");
+    "Normal hook run after each command is executed.");
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,