]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(prepare_menu_bars): Clear size-change flag before running
[gnu-emacs] / src / xdisp.c
index 7b464dfa74eb8cc43ddc0120d19f83cc140e5384..3e25cdd35db1bae32de16ed6a5605c450084f0f7 100644 (file)
@@ -1,5 +1,5 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -44,10 +44,14 @@ extern int command_loop_level;
 
 extern Lisp_Object Qface;
 
-/* Nonzero means print newline before next minibuffer message.  */
+/* Nonzero means print newline to stdout before next minibuffer message.  */
 
 int noninteractive_need_newline;
 
+/* Nonzero means print newline to message log before next message.  */
+
+static int message_log_need_newline;
+
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #define max(a, b) ((a) > (b) ? (a) : (b))
 
@@ -103,6 +107,11 @@ Lisp_Object Vframe_title_format;
 /* Like mode-line-format, but for the titlebar on an iconified frame.  */
 Lisp_Object Vicon_title_format;
 
+/* List of functions to call when a window's size changes.  These
+   functions get one arg, a frame on which one or more windows' sizes
+   have changed.  */
+static Lisp_Object Vwindow_size_change_functions;
+
 /* Values of those variables at last redisplay.  */
 static Lisp_Object last_arrow_position, last_arrow_string;
 
@@ -116,13 +125,14 @@ static int highlight_nonselected_windows;
 
 /* If cursor motion alone moves point off frame,
    Try scrolling this many lines up or down if that will bring it back.  */
-int scroll_step;
+static int scroll_step;
 
 /* Nonzero if try_window_id has made blank lines at window bottom
  since the last redisplay that paused */
 static int blank_end_of_window;
 
-/* Number of windows showing the buffer of the selected window.
+/* Number of windows showing the buffer of the selected window
+   (or another buffer with the same base buffer).
    keyboard.c refers to this.  */
 int buffer_shared;
 
@@ -133,11 +143,12 @@ int buffer_shared;
 static int cursor_vpos;
 static int cursor_hpos;
 
-int debug_end_pos;
+static int debug_end_pos;
 
 /* Nonzero means display mode line highlighted */
 int mode_line_inverse_video;
 
+static int message_log_check_duplicate ();
 static void echo_area_display ();
 void mark_window_display_accurate ();
 static void redisplay_windows ();
@@ -201,8 +212,144 @@ int windows_or_buffers_changed;
 int line_number_displayed;
 
 /* Maximum buffer size for which to display line numbers.  */
-int line_number_display_limit;
+static int line_number_display_limit;
+
+/* Number of lines to keep in the message log buffer.
+   t means infinite.  nil means don't log at all.  */
+Lisp_Object Vmessage_log_max;
 \f
+void
+message_log_maybe_newline ()
+{
+  if (message_log_need_newline)
+    message_dolog ("", 0, 1);
+}
+
+
+/* Add a string to the message log, optionally terminated with a newline.
+   This function calls low-level routines in order to bypass text property
+   hooks, etc. which might not be safe to run.  */
+
+void
+message_dolog (m, len, nlflag)
+     char *m;
+     int len, nlflag;
+{
+  if (!NILP (Vmessage_log_max))
+    {
+      struct buffer *oldbuf;
+      int oldpoint, oldbegv, oldzv;
+
+      oldbuf = current_buffer;
+      Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
+      current_buffer->undo_list = Qt;
+      oldpoint = PT;
+      oldbegv = BEGV;
+      oldzv = ZV;
+      BEGV = BEG;
+      ZV = Z;
+      if (oldpoint == Z)
+       oldpoint += len + nlflag;
+      if (oldzv == Z)
+       oldzv += len + nlflag;
+      TEMP_SET_PT (Z);
+      if (len)
+       insert_1 (m, len, 1, 0);
+      if (nlflag)
+       {
+         int this_bol, prev_bol, dup;
+         insert_1 ("\n", 1, 1, 0);
+
+         this_bol = scan_buffer ('\n', Z, 0, -2, 0, 0);
+         if (this_bol > BEG)
+           {
+             prev_bol = scan_buffer ('\n', this_bol, 0, -2, 0, 0);
+             dup = message_log_check_duplicate (prev_bol, this_bol);
+             if (dup)
+               {
+                 if (oldpoint > prev_bol)
+                   oldpoint -= min (this_bol, oldpoint) - prev_bol;
+                 if (oldbegv > prev_bol)
+                   oldbegv -= min (this_bol, oldbegv) - prev_bol;
+                 if (oldzv > prev_bol)
+                   oldzv -= min (this_bol, oldzv) - prev_bol;
+                 del_range_1 (prev_bol, this_bol, 0);
+                 if (dup > 1)
+                   {
+                     char dupstr[40];
+                     int duplen;
+
+                     /* If you change this format, don't forget to also
+                        change message_log_check_duplicate.  */
+                     sprintf (dupstr, " [%d times]", dup);
+                     duplen = strlen (dupstr);
+                     TEMP_SET_PT (Z-1);
+                     if (oldpoint == Z)
+                       oldpoint += duplen;
+                     if (oldzv == Z)
+                       oldzv += duplen;
+                     insert_1 (dupstr, duplen, 1, 0);
+                   }
+               }
+           }
+
+         if (NATNUMP (Vmessage_log_max))
+           {
+             int pos = scan_buffer ('\n', Z, 0,
+                                    -XFASTINT (Vmessage_log_max) - 1, 0, 0);
+             oldpoint -= min (pos, oldpoint) - BEG;
+             oldbegv -= min (pos, oldbegv) - BEG;
+             oldzv -= min (pos, oldzv) - BEG;
+             del_range_1 (BEG, pos, 0);
+           }
+       }
+      BEGV = oldbegv;
+      ZV = oldzv;
+      TEMP_SET_PT (oldpoint);
+      set_buffer_internal (oldbuf);
+      message_log_need_newline = !nlflag;
+    }
+}
+
+
+/* We are at the end of the buffer after just having inserted a newline.
+   (Note: We depend on the fact we won't be crossing the gap.)
+   Check to see if the most recent message looks a lot like the previous one.
+   Return 0 if different, 1 if the new one should just replace it, or a
+   value N > 1 if we should also append " [N times]".  */
+
+static int
+message_log_check_duplicate (prev_bol, this_bol)
+     int prev_bol, this_bol;
+{
+  int i;
+  int len = Z - 1 - this_bol;
+  int seen_dots = 0;
+  unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
+  unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
+
+  for (i = 0; i < len; i++)
+    {
+      if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.'
+         && p1[i] != '\n')
+       seen_dots = 1;
+      if (p1[i] != p2[i])
+       return seen_dots;
+    }
+  p1 += len;
+  if (*p1 == '\n')
+    return 2;
+  if (*p1++ == ' ' && *p1++ == '[')
+    {
+      int n = 0;
+      while (*p1 >= '0' && *p1 <= '9')
+       n = n * 10 + *p1++ - '0';
+      if (strncmp (p1, " times]\n", 8) == 0)
+       return n+1;
+    }
+  return 0;
+}
+
 /* Display an echo area message M with a specified length of LEN chars.
    The string may include null characters.  If m is 0, clear out any
    existing message, and let the minibuffer text show through.
@@ -212,6 +359,21 @@ void
 message2 (m, len)
      char *m;
      int len;
+{
+  /* First flush out any partial line written with print.  */
+  message_log_maybe_newline ();
+  if (m)
+    message_dolog (m, len, 1);
+  message2_nolog (m, len);
+}
+
+
+/* The non-logging part of that function.  */
+
+void
+message2_nolog (m, len)
+     char *m;
+     int len;
 {
   if (noninteractive)
     {
@@ -263,6 +425,13 @@ message1 (m)
   message2 (m, (m ? strlen (m) : 0));
 }
 
+void
+message1_nolog (m)
+     char *m;
+{
+  message2_nolog (m, (m ? strlen (m) : 0));
+}
+
 /* Truncate what will be displayed in the echo area
    the next time we display it--but don't redisplay it now.  */
 
@@ -348,6 +517,19 @@ message (m, a1, a2, a3)
     }
 }
 
+/* The non-logging version of that function.  */
+void
+message_nolog (m, a1, a2, a3)
+     char *m;
+     EMACS_INT a1, a2, a3;
+{
+  Lisp_Object old_log_max;
+  old_log_max = Vmessage_log_max;
+  Vmessage_log_max = Qnil;
+  message (m, a1, a2, a3);
+  Vmessage_log_max = old_log_max;
+}
+
 void
 update_echo_area ()
 {
@@ -385,6 +567,8 @@ echo_area_display ()
                      0, 0, 0, 0, FRAME_WIDTH (f));
 
       /* If desired cursor location is on this line, put it at end of text */
+      if (cursor_in_echo_area)
+       FRAME_CURSOR_Y (f) = vpos;
       if (FRAME_CURSOR_Y (f) == vpos)
        FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
 
@@ -465,40 +649,55 @@ x_consider_frame_title (frame)
 #endif
 \f
 /* Prepare for redisplay by updating menu-bar item lists when appropriate.
-   This can't be done in `redisplay' itself because it can call eval.  */
+   This can call eval.  */
 
 void
 prepare_menu_bars ()
 {
   register struct window *w = XWINDOW (selected_window);
   int all_windows;
+  struct gcpro gcpro1, gcpro2;
 
-  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 ();
+  all_windows = (update_mode_lines || buffer_shared > 1
+                || clip_changed || windows_or_buffers_changed);
 
-  if (frame_garbaged)
+  /* 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)
     {
-      redraw_garbaged_frames ();
-      frame_garbaged = 0;
-    }
+      Lisp_Object tail, frame;
 
-  all_windows = (update_mode_lines || buffer_shared > 1
-                || clip_changed || windows_or_buffers_changed);
+      FOR_EACH_FRAME (tail, frame)
+       {
+         /* If a window on this frame changed size,
+            report that to the user and clear the size-change flag.  */
+         if (FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)))
+           {
+             Lisp_Object functions;
+             /* Clear flag first in case we get error below.  */
+             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
+             functions = Vwindow_size_change_functions;
+             GCPRO2 (tail, functions);
+             while (CONSP (functions))
+               {
+                 call1 (XCONS (functions)->car, frame);
+                 functions = XCONS (functions)->cdr;
+               }
+             UNGCPRO;
+           }
+         GCPRO1 (tail);
+         update_menu_bar (XFRAME (frame));
+         UNGCPRO;
+       }
+    }
+  else
+    update_menu_bar (selected_frame);
 
+  /* Update all frame titles based on their buffer names, etc.
+     We do this after the menu bars so that the frame will first
+     create its menu bar using the name `emacs' if no other name
+     has yet been specified.  */
 #ifdef HAVE_X_WINDOWS
   if (windows_or_buffers_changed)
     {
@@ -510,19 +709,6 @@ prepare_menu_bars ()
          x_consider_frame_title (frame);
     }
 #endif
-
-  /* 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)
-       update_menu_bar (XFRAME (frame));
-    }
-  else
-    update_menu_bar (selected_frame);
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -545,6 +731,10 @@ prepare_menu_bars ()
 
 static int do_verify_charstarts;
 
+/* Counter is used to clear the face cache
+   no more than once ever 1000 redisplays.  */
+static int clear_face_cache_count;
+
 void
 redisplay ()
 {
@@ -554,7 +744,6 @@ redisplay ()
   int all_windows;
   register int tlbufpos, tlendpos;
   struct position pos;
-  extern int input_pending;
 
   if (noninteractive)
     return;
@@ -567,7 +756,13 @@ redisplay ()
     Lisp_Object tail, frame;
 
     FOR_EACH_FRAME (tail, frame)
-      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+      {
+       FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+
+       /* Clear out all the display lines in which we will generate the
+          glyphs to display.  */
+       init_desired_glyphs (XFRAME (frame));
+      }
   }
 
   /* Notice any pending interrupt request to change frame size.  */
@@ -579,12 +774,16 @@ redisplay ()
       frame_garbaged = 0;
     }
 
-  if (clip_changed || windows_or_buffers_changed)
+  prepare_menu_bars ();
+
+  if (clip_changed || windows_or_buffers_changed
+      || (!NILP (w->column_number_displayed)
+         && XFASTINT (w->column_number_displayed) != current_column ()))
     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)
+      && XFASTINT (w->last_modified) <= SAVE_MODIFF)
     {
       w->update_mode_line = Qt;
       if (buffer_shared > 1)
@@ -671,7 +870,6 @@ redisplay ()
                  int left = XFASTINT (w->left);
                  int *charstart_next_line
                    = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
-                 int i;
                  int adjust;
 
                  if (Z - tlendpos == ZV)
@@ -703,10 +901,12 @@ redisplay ()
            }
          goto update;
        }
-      /* If highlighting the region, we can't just move the cursor.  */
+      /* If highlighting the region, or if the cursor is in the echo area,
+        then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && NILP (w->region_showing))
+              && NILP (w->region_showing)
+              && !cursor_in_echo_area)
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
@@ -732,14 +932,20 @@ redisplay ()
   this_line_bufpos = 0;
   all_windows |= buffer_shared > 1;
 
+  clear_face_cache_count++;
+
   if (all_windows)
     {
       Lisp_Object tail, frame;
 
-#ifdef HAVE_X_WINDOWS
-      /* Since we're doing a thorough redisplay, we might as well
-        recompute all our display faces.  */
-      clear_face_vector ();
+#ifdef HAVE_FACES
+      /* Clear the face cache, only when we do a full redisplay
+        and not too often either.  */
+      if (clear_face_cache_count > 1000)
+       {
+         clear_face_cache ();
+         clear_face_cache_count = 0;
+       }
 #endif
 
       /* Recompute # windows showing selected buffer.
@@ -749,19 +955,22 @@ redisplay ()
       FOR_EACH_FRAME (tail, frame)
        {
          FRAME_PTR f = XFRAME (frame);
+         if (! FRAME_TERMCAP_P (f) || f == selected_frame)
+           {
 
-         /* Mark all the scroll bars to be removed; we'll redeem the ones
-            we want when we redisplay their windows.  */
-         if (condemn_scroll_bars_hook)
-           (*condemn_scroll_bars_hook) (f);
+             /* Mark all the scroll bars to be removed; we'll redeem the ones
+                we want when we redisplay their windows.  */
+             if (condemn_scroll_bars_hook)
+               (*condemn_scroll_bars_hook) (f);
 
-         if (FRAME_VISIBLE_P (f))
-           redisplay_windows (FRAME_ROOT_WINDOW (f));
+             if (FRAME_VISIBLE_P (f))
+               redisplay_windows (FRAME_ROOT_WINDOW (f));
 
-         /* Any scroll bars which redisplay_windows should have nuked
-            should now go away.  */
-         if (judge_scroll_bars_hook)
-           (*judge_scroll_bars_hook) (f);
+             /* Any scroll bars which redisplay_windows should have nuked
+                should now go away.  */
+             if (judge_scroll_bars_hook)
+               (*judge_scroll_bars_hook) (f);
+           }
        }
     }
   else if (FRAME_VISIBLE_P (selected_frame))
@@ -794,7 +1003,9 @@ update:
            continue;
 
          f = XFRAME (XCONS (tail)->car);
-         if (FRAME_VISIBLE_P (f))
+
+         if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
+             && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
              if (!pause)
@@ -811,6 +1022,8 @@ update:
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
+      else
+       pause = 0;
 
       /* We may have called echo_area_display at the top of this
         function.  If the echo area is on another frame, that may
@@ -1002,7 +1215,7 @@ update_menu_bar (f)
          || !NILP (w->update_mode_line)
          || (XFASTINT (w->last_modified) < MODIFF
              && (XFASTINT (w->last_modified)
-                 <= XBUFFER (w->buffer)->save_modified)))
+                 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer)))))
        {
          struct buffer *prev = current_buffer;
          call1 (Vrun_hooks, Qmenu_bar_update_hook);
@@ -1046,7 +1259,7 @@ redisplay_window (window, just_this_one)
   struct position pos;
   int opoint = PT;
   int tem;
-  int window_needs_modeline;
+  int update_mode_line;
 
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
@@ -1066,6 +1279,7 @@ redisplay_window (window, just_this_one)
     abort ();
   
   height = window_internal_height (w);
+  update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
 
   if (MINI_WINDOW_P (w))
     {
@@ -1092,19 +1306,30 @@ redisplay_window (window, just_this_one)
        }
     }
 
-  if (update_mode_lines)
-    w->update_mode_line = Qt;
-
   /* Otherwise set up data on this window; select its buffer and point value */
 
-  current_buffer = XBUFFER (w->buffer);
+  if (update_mode_line)
+    set_buffer_internal (XBUFFER (w->buffer));
+  else
+    set_buffer_temp (XBUFFER (w->buffer));
+
   opoint = PT;
 
-  /* Count number of windows showing the selected buffer.  */
+  /* Count number of windows showing the selected buffer.
+     An indirect buffer counts as its base buffer.  */
 
-  if (!just_this_one
-      && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
-    buffer_shared++;
+  if (!just_this_one)
+    {
+      struct buffer *current_base, *window_base;
+      current_base = current_buffer;
+      window_base = XBUFFER (XWINDOW (selected_window)->buffer);
+      if (current_base->base_buffer)
+       current_base = current_base->base_buffer;
+      if (window_base->base_buffer)
+       window_base = window_base->base_buffer;
+      if (current_base == window_base)
+       buffer_shared++;
+    }
 
   /* POINT refers normally to the selected window.
      For any other window, set up appropriate value.  */
@@ -1157,7 +1382,14 @@ redisplay_window (window, just_this_one)
     {
       /* Forget any recorded base line for line number display.  */
       w->base_line_number = Qnil;
-      w->update_mode_line = Qt;
+      /* Redisplay the mode line.  Select the buffer properly for that.  */
+      if (!update_mode_line)
+       {
+         set_buffer_temp (old);
+         set_buffer_internal (XBUFFER (w->buffer));
+         update_mode_line = 1;
+         w->update_mode_line = Qt;
+       }
       w->force_start = Qnil;
       XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
@@ -1186,10 +1418,12 @@ redisplay_window (window, just_this_one)
            }
          /* If we are highlighting the region,
             then we just changed the region, so redisplay to show it.  */
-         cancel_my_columns (XWINDOW (window));
          if (!NILP (Vtransient_mark_mode)
              && !NILP (current_buffer->mark_active))
-           try_window (window, startp);
+           {
+             cancel_my_columns (XWINDOW (window));
+             try_window (window, startp);
+           }
        }
       goto done;
     }
@@ -1207,6 +1441,10 @@ redisplay_window (window, just_this_one)
   if (XFASTINT (w->last_modified) >= MODIFF
       && PT >= startp && !clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      /* If force-mode-line-update was called, really redisplay;
+        that's how redisplay is forced after e.g. changing
+        buffer-invisibility-spec.  */
+      && NILP (w->update_mode_line)
       /* Can't use this case if highlighting a region.  */
       && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
       && NILP (w->region_showing)
@@ -1216,7 +1454,7 @@ redisplay_window (window, just_this_one)
       && !EQ (window, minibuf_window))
     {
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
-                           PT, height + 1, 10000, width, hscroll,
+                           PT, height0, width, hscroll,
                            pos_tab_offset (w, startp), w);
 
       if (pos.vpos < height)
@@ -1293,7 +1531,14 @@ redisplay_window (window, just_this_one)
     }
 
   XSETFASTINT (w->last_modified, 0);
-  w->update_mode_line = Qt;
+  /* Redisplay the mode line.  Select the buffer properly for that.  */
+  if (!update_mode_line)
+    {
+      set_buffer_temp (old);
+      set_buffer_internal (XBUFFER (w->buffer));
+      update_mode_line = 1;
+      w->update_mode_line = Qt;
+    }
 
   /* Try to scroll by specified few lines */
 
@@ -1307,7 +1552,8 @@ redisplay_window (window, just_this_one)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
+      pos = *vmotion (startp,
+                     (PT < startp ? - scroll_step : scroll_step),
                      width, hscroll, window);
 
       if (PT >= pos.bufpos)
@@ -1340,11 +1586,13 @@ recenter:
     = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
-  if ((!NILP (w->update_mode_line)
+  if ((update_mode_line
        /* If window not full width, must redo its mode line
          if the window to its side is being redone */
        || (!just_this_one && width < FRAME_WIDTH (f) - 1)
-       || INTEGERP (w->base_line_pos))
+       || INTEGERP (w->base_line_pos)
+       || (!NILP (w->column_number_displayed)
+          && XFASTINT (w->column_number_displayed) != current_column ()))
       && height != XFASTINT (w->height))
     display_mode_line (w);
   if (! line_number_displayed
@@ -1355,7 +1603,7 @@ done:
     }
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
-  if (!NILP (w->update_mode_line)
+  if (update_mode_line
 #ifdef USE_X_TOOLKIT
       && FRAME_EXTERNAL_MENU_BAR (f) 
 #else
@@ -1380,7 +1628,7 @@ done:
          || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
        {
          whole = ZV - BEGV;
-         start = startp - BEGV;
+         start = marker_position (w->start) - BEGV;
          /* I don't think this is guaranteed to be right.  For the
             moment, we'll pretend it is.  */
          end = (Z - XINT (w->window_end_pos)) - BEGV;
@@ -1400,7 +1648,10 @@ done:
     }
 
   BUF_PT (current_buffer) = opoint;
-  current_buffer = old;
+  if (update_mode_line)
+    set_buffer_internal (old);
+  else
+    set_buffer_temp (old);
   BUF_PT (current_buffer) = lpoint;
 }
 \f
@@ -1429,18 +1680,30 @@ try_window (window, pos)
     {
       val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
       tab_offset += width;
+      /* For the first line displayed, display_text_line
+        subtracts the prompt width from the tab offset.
+        But it does not affect the value of our variable tab_offset.
+        So we do the subtraction again,
+        for the sake of continuation lines of that first line.  */
+      if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
+       tab_offset -= minibuf_prompt_width;
+
       if (val.vpos) tab_offset = 0;
       vpos++;
       if (pos != val.bufpos)
-       last_text_vpos
-         /* Next line, unless prev line ended in end of buffer with no cr */
-         = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n'
+       {
+         int invis = 0;
 #ifdef USE_TEXT_PROPERTIES
-                                || ! NILP (Fget_char_property (val.bufpos-1,
-                                                               Qinvisible,
-                                                               window))
+         Lisp_Object invis_prop;
+         invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
+         invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
 #endif
-                                ));
+
+         last_text_vpos
+           /* Next line, unless prev line ended in end of buffer with no cr */
+           = vpos - (val.vpos
+                     && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
+       }
       pos = val.bufpos;
     }
 
@@ -1504,11 +1767,11 @@ try_window_id (window)
 
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin,
-                       min (ZV, beg_unchanged + BEG), height + 1, 0,
+                       min (ZV, beg_unchanged + BEG), height, 0,
                        width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
-      if (PT < bp.bufpos && !bp.contin)
+      if (PT < bp.bufpos)
        {
          /* All changes are below the frame, and point is on the frame.
             We don't need to change the frame at all.
@@ -1519,7 +1782,7 @@ try_window_id (window)
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
-         return 1;
+         goto findpoint;
        }
       return 0;
     }
@@ -1826,6 +2089,7 @@ try_window_id (window)
   /* If point was not in a line that was displayed, find it */
   if (cursor_vpos < 0)
     {
+    findpoint:
       val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
@@ -1917,9 +2181,9 @@ redisplay_region (buf, start, end)
     }
 
   /* Increment the buffer's time stamp, but also increment the save
-     and autosave timestamps, so as not to screw up that timekeeping. */
-  if (BUF_MODIFF (buf) == buf->save_modified)
-    buf->save_modified++;
+     and autosave timestamps, so as not to screw up that timekeeping.  */
+  if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
+    BUF_SAVE_MODIFF (buf)++;
   if (BUF_MODIFF (buf) == buf->auto_save_modified)
     buf->auto_save_modified++;
 
@@ -1947,7 +2211,7 @@ copy_part_of_rope (f, to, s, from, len, face)
   int last_code = -1;
   int last_merged = 0;
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
   if (! FRAME_TERMCAP_P (f))
     while (n--)
       {
@@ -1992,7 +2256,7 @@ fix_glyph (f, glyph, cface)
      GLYPH glyph;
      int cface;
 {
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
   if (! FRAME_TERMCAP_P (f))
     {
       if (FAST_GLYPH_FACE (glyph) != 0)
@@ -2050,6 +2314,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   struct position val;
   int lastpos;
   int invis;
+  int last_invis_skip = 0;
+  Lisp_Object last_invis_prop;
   int hscroll = XINT (w->hscroll);
   int truncate = (hscroll
                  || (truncate_partial_width_windows
@@ -2068,13 +2334,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register struct Lisp_Vector *dp = window_display_table (w);
 
   Lisp_Object default_invis_vector[3];
-  /* Nonzero means display something where there are invisible lines.
-     The precise value is the number of glyphs to display.  */
+  /* Number of characters of ellipsis to display after an invisible line
+     if it calls for an ellipsis.
+     Note that this value can be nonzero regardless of whether
+     selective display is enabled--you must check that separately.  */
   int selective_rlen
-    = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
+    = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
        ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
-       : selective && !NILP (current_buffer->selective_display_ellipses)
-       ? 3 : 0);
+       : !NILP (current_buffer->selective_display_ellipses) ? 3 : 0);
   /* This is the sequence of Lisp objects to display
      when there are invisible lines.  */
   Lisp_Object *invis_vector_contents
@@ -2135,10 +2402,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
          minibuf_prompt_width
            = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
                               XSTRING (minibuf_prompt)->size, hpos,
-                              (!truncate ? continuer : truncator),
-                              1, -1, -1)
+                              /* Display a space if we truncate.  */
+                              ' ',
+                              1, -1,
+                              /* Truncate the prompt a little before the
+                                 margin, so user input can at least start
+                                 on the first line.  */
+                              w->width > 10 ? w->width - 4 : -1)
               - hpos);
          hpos += minibuf_prompt_width;
+         taboffset -= minibuf_prompt_width;
        }
       else
        minibuf_prompt_width = 0;
@@ -2242,12 +2515,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (XFASTINT (limit) > pos + 50)
                XSETFASTINT (limit, pos + 50);
              endpos = Fnext_single_property_change (position, Qinvisible,
-                                               Fcurrent_buffer (), limit);
+                                                    Fcurrent_buffer (),
+                                                    limit);
              if (INTEGERP (endpos))
                next_invisible = XINT (endpos);
              else
                next_invisible = end;
-             if (! NILP (prop))
+             if (TEXT_PROP_MEANS_INVISIBLE (prop))
                {
                  if (pos < PT && next_invisible >= PT)
                    {
@@ -2255,13 +2529,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
                      cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_invisible;
+                 last_invis_skip = pos;
+                 last_invis_prop = prop;
                }
            }
          if (pos >= end)
            break;
 #endif
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Did we hit a face change?  Figure out what face we should
             use now.  We also hit this the first time through the
             loop, to see what face we should start with.  */
@@ -2290,8 +2566,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
          p = &FETCH_CHAR (pos);
        }
       c = *p++;
-      if (c >= 040 && c < 0177
-         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
+      /* Let a display table override all standard display methods.  */
+      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+       {
+         p1 = copy_part_of_rope (f, p1, leftmargin,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+                                 current_face);
+       }
+      else if (c >= 040 && c < 0177)
        {
          if (p1 >= leftmargin)
            *p1 = MAKE_GLYPH (f, c, current_face);
@@ -2300,6 +2583,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c == '\n')
        {
          invis = 0;
+         if (last_invis_skip == pos
+             && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
+           invis = 1;
          while (pos + 1 < end
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
@@ -2317,7 +2603,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
             way to the end of the frame line.  */
          if (current_face)
@@ -2354,7 +2640,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
             way to the end of the frame line.  */
          if (current_face)
@@ -2367,13 +2653,6 @@ display_text_line (w, start, vpos, hpos, taboffset)
 #endif
          break;
        }
-      else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-       {
-         p1 = copy_part_of_rope (f, p1, leftmargin,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 current_face);
-       }
       else if (c < 0200 && ctl_arrow)
        {
          if (p1 >= leftmargin)
@@ -2528,8 +2807,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
       cursor_hpos += XFASTINT (w->left);
       if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
        {
-         FRAME_CURSOR_Y (f) = cursor_vpos;
-         FRAME_CURSOR_X (f) = cursor_hpos;
+         if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
+               && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
+           {
+             FRAME_CURSOR_Y (f) = cursor_vpos;
+             FRAME_CURSOR_X (f) = cursor_hpos;
+           }
 
          if (w == XWINDOW (selected_window))
            {
@@ -2595,7 +2878,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
       if (len > width)
        len = width;
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
       if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
        {
          /* If the arrow string has text props, obey them when displaying.  */
@@ -2612,7 +2895,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
            }
        }
       else
-#endif /* HAVE_X_WINDOWS */
+#endif /* HAVE_FACES */
        {
          for (i = 0; i < len; i++)
            leftmargin[i] = p[i];
@@ -2665,10 +2948,10 @@ display_menu_bar (w)
                               XSTRING (string)->data,
                               XSTRING (string)->size,
                               hpos, 0, 0, hpos, maxendcol);
-      /* Put a gap of 3 spaces between items.  */
+      /* Put a space between items.  */
       if (hpos < maxendcol)
        {
-         int hpos1 = hpos + 3;
+         int hpos1 = hpos + 1;
          hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
                                 min (hpos1, maxendcol), maxendcol);
        }
@@ -2700,10 +2983,20 @@ display_mode_line (w)
   register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
 
   line_number_displayed = 0;
+  w->column_number_displayed = Qnil;
 
   get_display_line (f, vpos, left);
+
+  /* Temporarily make frame F's kboard the current kboard
+     so that kboard-local variables in the mode_line_format
+     will get the right values.  */
+  push_frame_kboard (f);
+
   display_mode_element (w, vpos, left, 0, right, right,
                        current_buffer->mode_line_format);
+
+  pop_frame_kboard ();
+
   FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
 
   /* Make the mode line inverse video if the entire line
@@ -2715,8 +3008,8 @@ display_mode_line (w)
   if (XFASTINT (w->width) == FRAME_WIDTH (f)
       || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
     FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
-#ifdef HAVE_X_WINDOWS
-  else if (! FRAME_TERMCAP_P (f))
+#ifdef HAVE_FACES
+  else if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
     {
       /* For a partial width window, explicitly set face of each glyph. */
       int i;
@@ -2766,11 +3059,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
 
   depth++;
 
-#ifdef SWITCH_ENUM_BUG
-  switch ((int) XTYPE (elt))
-#else
-  switch (XTYPE (elt))
-#endif
+  switch (SWITCH_ENUM_CAST (XTYPE (elt)))
     {
     case Lisp_String:
       {
@@ -2978,6 +3267,74 @@ decode_mode_spec (w, c, maxwidth)
 
   switch (c)
     {
+    case '*':
+      if (!NILP (b->read_only))
+       return "%";
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '+':
+      /* This differs from %* only for a modified read-only buffer.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      if (!NILP (b->read_only))
+       return "%";
+      return "-";
+
+    case '&':
+      /* This differs from %* in ignoring read-only-ness.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '%':
+      return "%";
+
+    case '[': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return "[[[... ";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = '[';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case ']': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return " ...]]]";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = ']';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case '-':
+      {
+       register char *p;
+       register int i;
+       
+       if (maxwidth < sizeof (lots_of_dashes))
+         return lots_of_dashes;
+       else
+         {
+           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
+             *p++ = '-';
+           *p = '\0';
+         }
+       return decode_mode_spec_buf;
+      }
+
     case 'b': 
       obj = b->name;
 #if 0
@@ -2991,6 +3348,18 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
+    case 'c':
+      {
+       int col = current_column ();
+       XSETFASTINT (w->column_number_displayed, col);
+       sprintf (decode_mode_spec_buf, "%d", col);
+       return decode_mode_spec_buf;
+      }
+
+    case 'F':
+      /* %F displays the frame name.  */
+      return (char *) XSTRING (selected_frame->name)->data;
+
     case 'f': 
       obj = b->filename;
 #if 0
@@ -3102,44 +3471,6 @@ decode_mode_spec (w, c, maxwidth)
        return " Narrow";
       break;
 
-    case '*':
-      if (!NILP (b->read_only))
-       return "%";
-      if (BUF_MODIFF (b) > b->save_modified)
-       return "*";
-      return "-";
-
-    case '+':
-      /* This differs from %* only for a modified read-only buffer.  */
-      if (BUF_MODIFF (b) > b->save_modified)
-       return "*";
-      if (!NILP (b->read_only))
-       return "%";
-      return "-";
-
-    case '&':
-      /* This differs from %* in ignoring read-only-ness.  */
-      if (BUF_MODIFF (b) > b->save_modified)
-       return "*";
-      return "-";
-
-    case 's':
-      /* status of process */
-      obj = Fget_buffer_process (w->buffer);
-      if (NILP (obj))
-       return "no process";
-#ifdef subprocesses
-      obj = Fsymbol_name (Fprocess_status (obj));
-#endif
-      break;
-
-    case 't':                  /* indicate TEXT or BINARY */
-#ifdef MODE_LINE_BINARY_TEXT
-      return MODE_LINE_BINARY_TEXT (b);
-#else
-      return "T";
-#endif
-
     case 'p':
       {
        int pos = marker_position (w->start);
@@ -3195,52 +3526,22 @@ decode_mode_spec (w, c, maxwidth)
          }
       }
 
-    case '%':
-      return "%";
-
-    case '[': 
-      {
-       int i;
-       char *p;
-
-       if (command_loop_level > 5)
-         return "[[[... ";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = '[';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
-
-    case ']': 
-      {
-       int i;
-       char *p;
-
-       if (command_loop_level > 5)
-         return " ...]]]";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = ']';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
+    case 's':
+      /* status of process */
+      obj = Fget_buffer_process (w->buffer);
+      if (NILP (obj))
+       return "no process";
+#ifdef subprocesses
+      obj = Fsymbol_name (Fprocess_status (obj));
+#endif
+      break;
 
-    case '-':
-      {
-       register char *p;
-       register int i;
-       
-       if (maxwidth < sizeof (lots_of_dashes))
-         return lots_of_dashes;
-       else
-         {
-           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
-             *p++ = '-';
-           *p = '\0';
-         }
-       return decode_mode_spec_buf;
-      }
+    case 't':                  /* indicate TEXT or BINARY */
+#ifdef MODE_LINE_BINARY_TEXT
+      return MODE_LINE_BINARY_TEXT (b);
+#else
+      return "T";
+#endif
     }
 
   if (STRINGP (obj))
@@ -3280,7 +3581,7 @@ display_scan_buffer (start, count, shortage)
      check only for newlines.  */
   if (! (!NILP (current_buffer->selective_display)
         && !INTEGERP (current_buffer->selective_display)))
-    return scan_buffer ('\n', start, count, shortage, 0);
+    return scan_buffer ('\n', start, 0, count, shortage, 0);
 
   /* The code that follows is like scan_buffer
      but checks for either newline or carriage return.  */
@@ -3479,8 +3780,14 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c == 0)
        break;
 
-      if (c >= 040 && c < 0177
-         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
+      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+       {
+         p1 = copy_part_of_rope (f, p1, start,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+                                 0);
+       }
+      else if (c >= 040 && c < 0177)
        {
          if (p1 >= start)
            *p1 = c;
@@ -3496,13 +3803,6 @@ display_string (w, vpos, string, length, hpos, truncate,
            }
          while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
        }
-      else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-       {
-         p1 = copy_part_of_rope (f, p1, start,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 0);
-       }
       else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
        {
          if (p1 >= start)
@@ -3556,6 +3856,86 @@ display_string (w, vpos, string, length, hpos, truncate,
   }
 }
 \f
+/* This is like a combination of memq and assq.
+   Return 1 if PROPVAL appears as an element of LIST
+   or as the car of an element of LIST.
+   If PROPVAL is a list, compare each element against LIST
+   in that way, and return 1 if any element of PROPVAL is found in LIST.
+   Otherwise return 0.
+   This function cannot quit.  */
+
+int
+invisible_p (propval, list)
+     register Lisp_Object propval;
+     Lisp_Object list;
+{
+  register Lisp_Object tail, proptail;
+  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      register Lisp_Object tem;
+      tem = XCONS (tail)->car;
+      if (EQ (propval, tem))
+       return 1;
+      if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
+       return 1;
+    }
+  if (CONSP (propval))
+    for (proptail = propval; CONSP (proptail);
+        proptail = XCONS (proptail)->cdr)
+      {
+       Lisp_Object propelt;
+       propelt = XCONS (proptail)->car;
+       for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+         {
+           register Lisp_Object tem;
+           tem = XCONS (tail)->car;
+           if (EQ (propelt, tem))
+             return 1;
+           if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
+             return 1;
+         }
+      }
+  return 0;
+}
+
+/* Return 1 if PROPVAL appears as the car of an element of LIST
+   and the cdr of that element is non-nil.
+   If PROPVAL is a list, check each element of PROPVAL in that way,
+   and the first time some element is found,
+   return 1 if the cdr of that element is non-nil.
+   Otherwise return 0.
+   This function cannot quit.  */
+
+int
+invisible_ellipsis_p (propval, list)
+     register Lisp_Object propval;
+     Lisp_Object list;
+{
+  register Lisp_Object tail, proptail;
+  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      register Lisp_Object tem;
+      tem = XCONS (tail)->car;
+      if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
+       return ! NILP (XCONS (tem)->cdr);
+    }
+  if (CONSP (propval))
+    for (proptail = propval; CONSP (proptail);
+        proptail = XCONS (proptail)->cdr)
+      {
+       Lisp_Object propelt;
+       propelt = XCONS (proptail)->car;
+       for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+         {
+           register Lisp_Object tem;
+           tem = XCONS (tail)->car;
+           if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
+             return ! NILP (XCONS (tem)->cdr);
+         }
+      }
+  return 0;
+}
+\f
 void
 syms_of_xdisp ()
 {
@@ -3631,6 +4011,20 @@ and is used only on frames for which no explicit name has been set\n\
                                                Fcons (intern ("system-name"),
                                                               Qnil)))),
                           Qnil)));
+
+  DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
+    "Maximum number of lines to keep in the message log buffer.\n\
+If nil, disable message logging.  If t, log messages but don't truncate\n\
+the buffer when it becomes large.");
+  XSETFASTINT (Vmessage_log_max, 50);
+
+  DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
+    "Functions called before redisplay, if window sizes have changed.\n\
+The value should be a list of functions that take one argument.\n\
+Just before redisplay, for each frame, if any of its windows have changed\n\
+size since the last redisplay, or have been split or deleted,\n\
+all the functions in the list are called, with the frame as argument.");
+  Vwindow_size_change_functions = Qnil;
 }
 
 /* initialize the window system */