changeset 5230:8c30e49ddc04

(message): Use message2, not message1. (display_string): Fix truncation-criterion after main loop for termination due to LENGTH. (echo_area_glyphs_length): New variable. (message1): Set it. (message2): New function. (display_string): New arg LENGTH. (echo_area_display): Pass new arg to display_string. (redisplay_window): Likewise. (display_text_line): Likewise. (display_menu_bar): Likewise. (display_mode_element): Likewise. (update_menu_bar, update_menu_bars): New functions. (prepare_menu_bars): New function. (redisplay_window): Don't update menu bar here. (display_menu_bar): Assume item list already updated. (redisplay_window): Don't alter lpoint when w is selected window in a non-selected frame.
author Richard M. Stallman <rms@gnu.org>
date Thu, 23 Dec 1993 01:04:26 +0000
parents 110539a25499
children 6646271e8d32
files src/xdisp.c
diffstat 1 files changed, 257 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/src/xdisp.c	Thu Dec 23 01:00:49 1993 +0000
+++ b/src/xdisp.c	Thu Dec 23 01:04:26 1993 +0000
@@ -124,6 +124,8 @@
 void mark_window_display_accurate ();
 static void redisplay_windows ();
 static void redisplay_window ();
+static void update_menu_bars ();
+static void update_menu_bar ();
 static void try_window ();
 static int try_window_id ();
 static struct position *display_text_line ();
@@ -147,6 +149,9 @@
    It overrides the minibuf_prompt as well as the buffer.  */
 char *echo_area_glyphs;
 
+/* This is the length of the message in echo_area_glyphs.  */
+int echo_area_glyphs_length;
+
 /* true iff we should redraw the mode lines on the next redisplay */
 int update_mode_lines;
 
@@ -182,6 +187,7 @@
 
 /* Specify m, a string, as a message in the minibuf.  If m is 0, clear out
    any existing message, and let the minibuffer text show through.  */
+
 void
 message1 (m)
      char *m;
@@ -214,7 +220,59 @@
 #endif
 
       if (m)
-	echo_area_glyphs = m;
+	{
+	  echo_area_glyphs = m;
+	  echo_area_glyphs_length = strlen (m);
+	}
+      else
+	echo_area_glyphs = previous_echo_glyphs = 0;
+
+      do_pending_window_change ();
+      echo_area_display ();
+      update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
+      do_pending_window_change ();
+    }
+}
+
+/* Display an echo area message M with a specified length of LEN chars.
+   This way, null characters can be included.  */
+
+void
+message2 (m, len)
+     char *m;
+     int len;
+{
+  if (noninteractive)
+    {
+      if (noninteractive_need_newline)
+	putc ('\n', stderr);
+      noninteractive_need_newline = 0;
+      fwrite (m, len, 1, stderr);
+      if (cursor_in_echo_area == 0)
+	fprintf (stderr, "\n");
+      fflush (stderr);
+    }
+  /* A null message buffer means that the frame hasn't really been
+     initialized yet.  Error messages get reported properly by
+     cmd_error, so this must be just an informative message; toss it.  */
+  else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
+    {
+#ifdef MULTI_FRAME
+      Lisp_Object minibuf_frame;
+
+      choose_minibuf_frame ();
+      minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
+      FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
+      if (FRAME_VISIBLE_P (selected_frame)
+	  && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
+	Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
+#endif
+
+      if (m)
+	{
+	  echo_area_glyphs = m;
+	  echo_area_glyphs_length = len;
+	}
       else
 	echo_area_glyphs = previous_echo_glyphs = 0;
 
@@ -269,22 +327,21 @@
 	{
 	  if (m)
 	    {
-	      {
+	      int len;
 #ifdef NO_ARG_ARRAY
-		int a[3];
-		a[0] = a1;
-		a[1] = a2;
-		a[2] = a3;
-
-		doprnt (FRAME_MESSAGE_BUF (echo_frame),
-			FRAME_WIDTH (echo_frame), m, 0, 3, a);
+	      int a[3];
+	      a[0] = a1;
+	      a[1] = a2;
+	      a[2] = a3;
+
+	      len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+			    FRAME_WIDTH (echo_frame), m, 0, 3, a);
 #else
-		doprnt (FRAME_MESSAGE_BUF (echo_frame),
-			FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
+	      len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+			    FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
-	      }
-
-	      message1 (FRAME_MESSAGE_BUF (echo_frame));
+
+	      message2 (FRAME_MESSAGE_BUF (echo_frame), len);
 	    }
 	  else
 	    message1 (0);
@@ -323,6 +380,7 @@
       get_display_line (f, vpos, 0);
       display_string (XWINDOW (minibuf_window), vpos,
 		      echo_area_glyphs ? echo_area_glyphs : "",
+		      echo_area_glyphs ? echo_area_glyphs_length : -1,
 		      0, 0, 0, FRAME_WIDTH (f));
 
       /* If desired cursor location is on this line, put it at end of text */
@@ -338,7 +396,7 @@
 	  {
 	    get_display_line (f, i, 0);
 	    display_string (XWINDOW (minibuf_window), vpos,
-			    "", 0, 0, 0, FRAME_WIDTH (f));
+			    "", 0, 0, 0, 0, FRAME_WIDTH (f));
 	  }
       }
     }
@@ -351,6 +409,77 @@
   previous_echo_glyphs = echo_area_glyphs;
 }
 
+/* Prepare for redisplay by updating menu-bar item lists when appropriate.
+   This can't be done in `redisplay' itself because it can call eval.  */
+
+void
+prepare_menu_bars ()
+{
+  register struct window *w = XWINDOW (selected_window);
+  int all_windows;
+
+  if (noninteractive)
+    return;
+
+  /* Set the visible flags for all frames.
+     Do this before checking for resized or garbaged frames; they want
+     to know if their frames are visible.
+     See the comment in frame.h for FRAME_SAMPLE_VISIBILITY.  */
+  {
+    Lisp_Object tail, frame;
+
+    FOR_EACH_FRAME (tail, frame)
+      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+  }
+
+  /* Notice any pending interrupt request to change frame size.  */
+  do_pending_window_change ();
+
+  if (frame_garbaged)
+    {
+      redraw_garbaged_frames ();
+      frame_garbaged = 0;
+    }
+
+  if (clip_changed || windows_or_buffers_changed)
+    update_mode_lines++;
+
+  /* Detect case that we need to write a star in the mode line.  */
+  if (XFASTINT (w->last_modified) < MODIFF
+      && XFASTINT (w->last_modified) <= current_buffer->save_modified)
+    {
+      w->update_mode_line = Qt;
+      if (buffer_shared > 1)
+	update_mode_lines++;
+    }
+
+  all_windows = update_mode_lines || buffer_shared > 1;
+
+  /* If specs for an arrow have changed, do thorough redisplay
+     to ensure we remove any arrow that should no longer exist.  */
+  if (! EQ (Voverlay_arrow_position, last_arrow_position)
+      || ! EQ (Voverlay_arrow_string, last_arrow_string))
+    all_windows = 1, clip_changed = 1;
+
+  /* Update the menu bar item lists, if appropriate.
+     This has to be done before any actual redisplay
+     or generation of display lines.  */
+  if (all_windows)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+	{
+	  FRAME_PTR f = XFRAME (frame);
+
+	  if (FRAME_VISIBLE_P (f))
+	    update_menu_bars (FRAME_ROOT_WINDOW (f));
+	}
+    }
+  else if (FRAME_VISIBLE_P (selected_frame))
+    update_menu_bar (selected_window);
+}
+
 /* Do a frame update, taking possible shortcuts into account.
    This is the main external entry point for redisplay.
 
@@ -358,11 +487,14 @@
    message is no longer requested, we clear the echo area
    or bring back the minibuffer if that is in use.
 
-   Everyone would like to have a hook here to call eval,
-   but that cannot be done safely without a lot of changes elsewhere.
-   This can be called from signal handlers; with alarms set up;
+   Do not call eval from within this function.
+   Calls to eval after the call to echo_area_display would confuse
+   the display_line mechanism and would cause a crash.
+   Calls to eval before that point will work most of the time,
+   but can still lose, because  this function
+   can be called from signal handlers; with alarms set up;
    or with synchronous processes running.
-   See the function `echo' in keyboard.c.
+
    See Fcall_process; if you called it from here, it could be
    entered recursively.  */
 
@@ -400,16 +532,6 @@
       frame_garbaged = 0;
     }
 
-  /* Normally the message* functions will have already displayed and
-     updated the echo area, but the frame may have been trashed, or
-     the update may have been preempted, so display the echo area
-     again here.  */
-  if (echo_area_glyphs || previous_echo_glyphs)
-    {
-      echo_area_display ();
-      must_finish = 1;
-    }
-
   if (clip_changed || windows_or_buffers_changed)
     update_mode_lines++;
 
@@ -432,6 +554,16 @@
       || ! EQ (Voverlay_arrow_string, last_arrow_string))
     all_windows = 1, clip_changed = 1;
 
+  /* Normally the message* functions will have already displayed and
+     updated the echo area, but the frame may have been trashed, or
+     the update may have been preempted, so display the echo area
+     again here.  */
+  if (echo_area_glyphs || previous_echo_glyphs)
+    {
+      echo_area_display ();
+      must_finish = 1;
+    }
+
   /* If showing region, and mark has changed, must redisplay whole window.  */
   if (((!NILP (Vtransient_mark_mode)
 	&& !NILP (XBUFFER (w->buffer)->mark_active))
@@ -752,8 +884,78 @@
     }
 }
 
+/* Update the menu bar item lists for WINDOW
+   and its subwindows and siblings.
+   This has to be done before we start to fill in any display lines,
+   because it can call eval.  */
+
+static void
+update_menu_bars (window)
+     Lisp_Object window;
+{
+  for (; !NILP (window); window = XWINDOW (window)->next)
+    update_menu_bar (window, 0);
+}
+
+/* Update the menu bar item list for window WINDOW and its subwindows.  */
+
+static void
+update_menu_bar (window, just_this_one)
+     Lisp_Object window;
+     int just_this_one;
+{
+  register struct window *w = XWINDOW (window);
+  struct buffer *old = current_buffer;
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+
+  /* If this is a combination window, do its children; that's all.  */
+
+  if (!NILP (w->vchild))
+    {
+      update_menu_bars (w->vchild);
+      return;
+    }
+  if (!NILP (w->hchild))
+    {
+      update_menu_bars (w->hchild);
+      return;
+    }
+  if (NILP (w->buffer))
+    abort ();
+  
+  if (update_mode_lines)
+    w->update_mode_line = Qt;
+
+  /* When we reach a frame's selected window, redo the frame's menu bar.  */
+  if (!NILP (w->update_mode_line)
+      && FRAME_MENU_BAR_LINES (f) > 0
+      && EQ (FRAME_SELECTED_WINDOW (f), window))
+    {
+      /* If the user has switched buffers or windows, we need to
+	 recompute to reflect the new bindings.  But we'll
+	 recompute when update_mode_lines is set too; that means
+	 that people can use force-mode-line-update to request
+	 that the menu bar be recomputed.  The adverse effect on
+	 the rest of the redisplay algorithm is about the same as
+	 windows_or_buffers_changed anyway.  */
+      if (windows_or_buffers_changed
+	  || update_mode_lines
+	  || (XFASTINT (w->last_modified) < MODIFF
+	      && (XFASTINT (w->last_modified)
+		  <= XBUFFER (w->buffer)->save_modified)))
+	{
+	  struct buffer *prev = current_buffer;
+	  current_buffer = XBUFFER (w->buffer);
+	  FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
+	  current_buffer = prev;
+	}
+    }
+}
+
 int do_id = 1;
 
+/* Redisplay WINDOW and its subwindows and siblings.  */
+
 static void
 redisplay_windows (window)
      Lisp_Object window;
@@ -762,6 +964,8 @@
     redisplay_window (window, 0);
 }
 
+/* Redisplay window WINDOW and its subwindows.  */
+
 static void
 redisplay_window (window, just_this_one)
      Lisp_Object window;
@@ -817,7 +1021,7 @@
 	  for (i = 0; i < height; i++)
 	    {
 	      get_display_line (f, vpos + i, 0);
-	      display_string (w, vpos + i, "", 0, 0, 0, width);
+	      display_string (w, vpos + i, "", 0, 0, 0, 0, width);
 	    }
 	  
 	  goto finish_scroll_bars;
@@ -887,7 +1091,7 @@
 				- (1 << (SHORTBITS - 1)),
 				width, hscroll, pos_tab_offset (w, startp));
 	  SET_PT (pos.bufpos);
-	  if (w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
+	  if (w != XWINDOW (selected_window))
 	    Fset_marker (w->pointm, make_number (point), Qnil);
 	  else
 	    {
@@ -1765,7 +1969,7 @@
       && vpos == XFASTINT (w->top))
     {
       if (minibuf_prompt)
-	hpos = display_string (w, vpos, minibuf_prompt, hpos,
+	hpos = display_string (w, vpos, minibuf_prompt, -1, hpos,
 			       (!truncate ? continuer : truncator),
 			       -1, -1);
       minibuf_prompt_width = hpos;
@@ -2149,25 +2353,6 @@
 
   get_display_line (f, vpos, 0);
 
-  /* If the user has switched buffers or windows, we need to
-     recompute to reflect the new bindings.  But we'll
-     recompute when update_mode_lines is set too; that means
-     that people can use force-mode-line-update to request
-     that the menu bar be recomputed.  The adverse effect on
-     the rest of the redisplay algorithm is about the same as
-     windows_or_buffers_changed anyway.  */
-  if (windows_or_buffers_changed
-      || update_mode_lines
-      || (XFASTINT (w->last_modified) < MODIFF
-	  && (XFASTINT (w->last_modified)
-	      <= XBUFFER (w->buffer)->save_modified)))
-    {
-      struct buffer *prev = current_buffer;
-      current_buffer = XBUFFER (w->buffer);
-      FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
-      current_buffer = prev;
-    }
-
   for (tail = FRAME_MENU_BAR_ITEMS (f); CONSP (tail); tail = XCONS (tail)->cdr)
     {
       Lisp_Object string;
@@ -2180,12 +2365,13 @@
       if (hpos < maxendcol)
 	hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
 			       XSTRING (string)->data,
+			       XSTRING (string)->size,
 			       hpos, 0, hpos, maxendcol);
       /* Put a gap of 3 spaces between items.  */
       if (hpos < maxendcol)
 	{
 	  int hpos1 = hpos + 3;
-	  hpos = display_string (w, vpos, "", hpos, 0,
+	  hpos = display_string (w, vpos, "", 0, hpos, 0,
 				 min (hpos1, maxendcol), maxendcol);
 	}
     }
@@ -2195,7 +2381,7 @@
 
   /* Fill out the line with spaces.  */
   if (maxendcol > hpos)
-    hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1);
+    hpos = display_string (w, vpos, "", 0, hpos, 0, maxendcol, -1);
 
   /* Clear the rest of the lines allocated to the menu bar.  */
   vpos++;
@@ -2311,7 +2497,7 @@
 	    if (this - 1 != last)
 	      {
 		register int lim = --this - last + hpos;
-		hpos = display_string (w, vpos, last, hpos, 0, hpos,
+		hpos = display_string (w, vpos, last, -1, hpos, 0, hpos,
 				       min (lim, maxendcol));
 	      }
 	    else /* c == '%' */
@@ -2340,6 +2526,7 @@
 		  hpos = display_string (w, vpos,
 					 decode_mode_spec (w, c,
 							   maxendcol - hpos),
+					 -1,
 					 hpos, 0, spec_width, maxendcol);
 	      }
 	  }
@@ -2361,6 +2548,7 @@
 	       don't check for % within it.  */
 	    if (XTYPE (tem) == Lisp_String)
 	      hpos = display_string (w, vpos, XSTRING (tem)->data,
+				     XSTRING (tem)->size,
 				     hpos, 0, minendcol, maxendcol);
 	    /* Give up right away for nil or t.  */
 	    else if (!EQ (tem, elt))
@@ -2450,13 +2638,13 @@
 
     default:
     invalid:
-      return (display_string (w, vpos, "*invalid*", hpos, 0,
+      return (display_string (w, vpos, "*invalid*", -1, hpos, 0,
 			      minendcol, maxendcol));
     }
 
  end:
   if (minendcol > hpos)
-    hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
+    hpos = display_string (w, vpos, "", 0, hpos, 0, minendcol, -1);
   return hpos;
 }
 
@@ -2733,6 +2921,7 @@
 /* Display STRING on one line of window W, starting at HPOS.
    Display at position VPOS.  Caller should have done get_display_line.
    If VPOS == -1, display it as the current frame's title.
+   LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
 
   TRUNCATE is GLYPH to display at end if truncated.  Zero for none.
 
@@ -2746,9 +2935,10 @@
   Returns ending hpos */
 
 static int
-display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
+display_string (w, vpos, string, length, hpos, truncate, mincol, maxcol)
      struct window *w;
      unsigned char *string;
+     int length;
      int vpos, hpos;
      GLYPH truncate;
      int mincol, maxcol;
@@ -2798,8 +2988,16 @@
 
   while (p1 < end)
     {
+      if (length == 0)
+	break;
       c = *string++;
-      if (!c) break;
+      /* Specified length.  */
+      if (length >= 0)
+	length--;
+      /* Unspecified length (null-terminated string).  */
+      else if (c == 0)
+	break;
+
       if (c >= 040 && c < 0177
 	  && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
 	{
@@ -2847,7 +3045,7 @@
 	}
     }
 
-  if (c)
+  if (c && length > 0)
     {
       p1 = end;
       if (truncate) *p1++ = truncate;