]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
*** empty log message ***
[gnu-emacs] / src / xdisp.c
index 0171f963f34cdd029fde5d04fb756f515af50523..a82736ccd18dc83f2fadca054e882c70fb0d600c 100644 (file)
@@ -1,5 +1,5 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 99
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 99, 2000
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -170,6 +170,7 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include <stdio.h>
 #include "lisp.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
 #include "termchar.h"
@@ -182,10 +183,10 @@ Boston, MA 02111-1307, USA.  */
 #include "disptab.h"
 #include "termhooks.h"
 #include "intervals.h"
-#include "keyboard.h"
 #include "coding.h"
 #include "process.h"
 #include "region-cache.h"
+#include "fontset.h"
 
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -200,7 +201,7 @@ Boston, MA 02111-1307, USA.  */
 #define INFINITY 10000000
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
-extern void set_frame_menubar ();
+extern void set_frame_menubar P_ ((struct frame *f, int, int));
 extern int pending_menu_activation;
 #endif
 
@@ -356,7 +357,7 @@ Lisp_Object Vicon_title_format;
 
 static Lisp_Object Vwindow_size_change_functions;
 
-Lisp_Object Qmenu_bar_update_hook;
+Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
 
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 
@@ -441,7 +442,7 @@ int line_number_displayed;
 
 /* Maximum buffer size for which to display line numbers.  */
 
-static int line_number_display_limit;
+Lisp_Object Vline_number_display_limit;
 
 /* line width to consider when repostioning for line number display */
 
@@ -452,6 +453,10 @@ static int line_number_display_limit_width;
 
 Lisp_Object Vmessage_log_max;
 
+/* The name of the *Messages* buffer, a string.  */
+
+static Lisp_Object Vmessages_buffer_name;
+
 /* Current, index 0, and last displayed echo area message.  Either
    buffers from echo_buffers, or nil to indicate no message.  */
 
@@ -479,7 +484,13 @@ int message_buf_print;
    specifying a fraction of the available height, or an integer
    specifying a number of lines.  */
 
-static Lisp_Object Vmax_mini_window_height;
+Lisp_Object Vmax_mini_window_height;
+
+/* Non-zero means messages should be displayed with truncated
+   lines instead of being continued.  */
+
+int message_truncate_lines;
+Lisp_Object Qmessage_truncate_lines;
 
 /* Non-zero means we want a hollow cursor in windows that are not
    selected.  Zero means there's no cursor in such windows.  */
@@ -505,13 +516,24 @@ static int last_max_ascent, last_height;
 
 #define TEXT_PROP_DISTANCE_LIMIT 100
 
+#if GLYPH_DEBUG
+
 /* Non-zero means print traces of redisplay if compiled with
    GLYPH_DEBUG != 0.  */
 
-#if GLYPH_DEBUG
 int trace_redisplay_p;
-#endif
 
+#endif /* GLYPH_DEBUG */
+
+#ifdef DEBUG_TRACE_MOVE
+/* Non-zero means trace with TRACE_MOVE to stderr.  */
+int trace_move;
+
+#define TRACE_MOVE(x)  if (trace_move) fprintf x; else (void) 0
+#else
+#define TRACE_MOVE(x)  (void) 0
+#endif
 /* Non-zero means automatically scroll windows horizontally to make
    point visible.  */
 
@@ -602,31 +624,50 @@ enum move_it_result
 \f
 /* Function prototypes.  */
 
+static int redisplay_mode_lines P_ ((Lisp_Object, int));
+static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
+static int invisible_text_between_p P_ ((struct it *, int, int));
+static int next_element_from_ellipsis P_ ((struct it *));
+static void pint2str P_ ((char *, int, int));
+static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
+                                                       struct text_pos));
+static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
+static int text_outside_line_unchanged_p P_ ((struct window *, int, int));
+static void store_frame_title_char P_ ((char));
+static int store_frame_title P_ ((unsigned char *, int, int));
+static void x_consider_frame_title P_ ((Lisp_Object));
+static void handle_stop P_ ((struct it *));
+static int tool_bar_lines_needed P_ ((struct frame *));
+static int single_display_prop_intangible_p P_ ((Lisp_Object));
 static void ensure_echo_area_buffers P_ ((void));
 static struct glyph_row *row_containing_pos P_ ((struct window *, int,
                                                 struct glyph_row *,
                                                 struct glyph_row *));
 static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
 static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *));
+static int with_echo_area_buffer P_ ((struct window *, int,
+                                     int (*) (EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT),
+                                     EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
 static void clear_garbaged_frames P_ ((void));
-static int current_message_1 P_ ((Lisp_Object *));
-static int truncate_message_1 P_ ((int));
-static int set_message_1 P_ ((char *s, Lisp_Object, int, int));
+static int current_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int truncate_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int set_message_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
 static int display_echo_area P_ ((struct window *));
-static int display_echo_area_1 P_ ((struct window *));
+static int display_echo_area_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+static int resize_mini_window_1 P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
 static Lisp_Object unwind_redisplay P_ ((Lisp_Object));
 static int string_char_and_length P_ ((unsigned char *, int, int *));
 static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object,
                                             struct text_pos));
 static int compute_window_start_on_continuation_line P_ ((struct window *));
 static Lisp_Object eval_handler P_ ((Lisp_Object));
-static Lisp_Object eval_form P_ ((Lisp_Object));
 static void insert_left_trunc_glyphs P_ ((struct it *));
 static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
 static void extend_face_to_end_of_line P_ ((struct it *));
 static int append_space P_ ((struct it *, int));
 static void make_cursor_line_fully_visible P_ ((struct window *));
 static int try_scrolling P_ ((Lisp_Object, int, int, int, int));
+static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
 static int message_log_check_duplicate P_ ((int, int, int, int));
 int invisible_p P_ ((Lisp_Object, Lisp_Object));
@@ -642,7 +683,7 @@ static void update_menu_bar P_ ((struct frame *, int));
 static int try_window_reusing_current_matrix P_ ((struct window *));
 static int try_window_id P_ ((struct window *));
 static int display_line P_ ((struct it *));
-static void display_mode_lines P_ ((struct window *));
+static int display_mode_lines P_ ((struct window *));
 static void display_mode_line P_ ((struct window *, enum face_id,
                                   Lisp_Object));
 static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object));
@@ -1042,7 +1083,7 @@ compute_string_pos (newpos, pos, string)
                        Lisp form evaluation
  ***********************************************************************/
 
-/* Error handler for eval_form.  */
+/* Error handler for eval_form and call_function.  */
 
 static Lisp_Object
 eval_handler (arg)
@@ -1055,14 +1096,40 @@ eval_handler (arg)
 /* Evaluate SEXPR and return the result, or nil if something went
    wrong.  */
 
-static Lisp_Object
+Lisp_Object
 eval_form (sexpr)
      Lisp_Object sexpr;
 {
   int count = specpdl_ptr - specpdl;
+  struct gcpro gcpro1;
   Lisp_Object val;
+
+  GCPRO1 (sexpr);
   specbind (Qinhibit_redisplay, Qt);
   val = internal_condition_case_1 (Feval, sexpr, Qerror, eval_handler);
+  UNGCPRO;
+  return unbind_to (count, val);
+}
+
+
+/* Call function ARGS[0] with arguments ARGS[1] to ARGS[NARGS - 1].
+   Return the result, or nil if something went wrong.  */
+
+Lisp_Object
+call_function (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object val;
+  struct gcpro gcpro1;
+
+  GCPRO1 (args[0]);
+  gcpro1.nvars = nargs;
+  specbind (Qinhibit_redisplay, Qt);
+  val = internal_condition_case_2 (Ffuncall, nargs, args, Qerror,
+                                  eval_handler);
+  UNGCPRO;
   return unbind_to (count, val);
 }
 
@@ -1436,15 +1503,25 @@ start_display (it, w, pos)
         \003, or in the middle of an overlay string).  In this case
         move_it_to above will not have taken us to the start of
         the continuation line but to the end of the continued line.  */
-      if (!it->truncate_lines_p && it->current_x > 0)
+      if (!it->truncate_lines_p)
        {
-         if (it->current.dpvec_index >= 0
-             || it->current.overlay_string_index >= 0)
+         if (it->current_x > 0)
            {
-             set_iterator_to_next (it);
-             move_it_in_display_line_to (it, -1, -1, 0);
+             if (it->current.dpvec_index >= 0
+                 || it->current.overlay_string_index >= 0)
+               {
+                 set_iterator_to_next (it);
+                 move_it_in_display_line_to (it, -1, -1, 0);
+               }
+         
+             it->continuation_lines_width += it->current_x;
            }
-         it->continuation_lines_width += it->current_x;
+
+         /* We're starting a new display line, not affected by the
+            height of the continued line, so clear the appropriate
+            fields in the iterator structure.  */
+         it->max_ascent = it->max_descent = 0;
+         it->max_phys_ascent = it->max_phys_descent = 0;
        }
       
       it->current_y = first_y;
@@ -1589,6 +1666,7 @@ handle_stop (it)
 
   it->dpvec = NULL;
   it->current.dpvec_index = -1;
+  it->add_overlay_start = 0;
 
   do
     {
@@ -1598,7 +1676,7 @@ handle_stop (it)
       for (p = it_props; p->handler; ++p)
        {
          handled = p->handler (it);
-         
+
          if (handled == HANDLED_RECOMPUTE_PROPS)
            break;
          else if (handled == HANDLED_RETURN)
@@ -1747,12 +1825,12 @@ next_overlay_change (pos)
   /* Get all overlays at the given position.  */
   len = 10;
   overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-  noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL);
+  noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
   if (noverlays > len)
     {
       len = noverlays;
       overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-      noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL);
+      noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
     }
 
   /* If any of these overlays ends before endpos,
@@ -1786,7 +1864,6 @@ handle_fontified_prop (it)
 {
   Lisp_Object prop, pos;
   enum prop_handled handled = HANDLED_NORMALLY;
-  struct gcpro gcpro1;
 
   /* Get the value of the `fontified' property at IT's current buffer
      position.  (The `fontified' property doesn't have a special
@@ -1795,24 +1872,62 @@ handle_fontified_prop (it)
   if (!STRINGP (it->string)
       && it->s == NULL
       && !NILP (Vfontification_functions)
+      && !NILP (Vrun_hooks)
       && (pos = make_number (IT_CHARPOS (*it)),
          prop = Fget_char_property (pos, Qfontified, Qnil),
          NILP (prop)))
     {
-      Lisp_Object args[2];
+      int count = specpdl_ptr - specpdl;
+      Lisp_Object val;
+
+      val = Vfontification_functions;
+      specbind (Qfontification_functions, Qnil);
+      specbind (Qafter_change_functions, Qnil);
+  
+      if (!CONSP (val) || EQ (XCAR (val), Qlambda))
+       call1 (val, pos);
+      else
+       {
+         Lisp_Object globals, fn;
+         struct gcpro gcpro1, gcpro2;
+
+         globals = Qnil;
+         GCPRO2 (val, globals);
+         
+         for (; CONSP (val); val = XCDR (val))
+           {
+             fn = XCAR (val);
+             
+             if (EQ (fn, Qt))
+               {
+                 /* A value of t indicates this hook has a local
+                    binding; it means to run the global binding too.
+                    In a global value, t should not occur.  If it
+                    does, we must ignore it to avoid an endless
+                    loop.  */
+                 for (globals = Fdefault_value (Qfontification_functions);
+                      CONSP (globals);
+                      globals = XCDR (globals))
+                   {
+                     fn = XCAR (globals);
+                     if (!EQ (fn, Qt))
+                       call1 (fn, pos);
+                   }
+               }
+             else
+               call1 (fn, pos);
+           }
+
+         UNGCPRO;
+       }
 
-      GCPRO1 (pos);
-      /* Run the hook functions.  */
-      args[0] = Qfontification_functions;
-      args[1] = pos;
-      Frun_hook_with_args (2, args);
+      unbind_to (count, Qnil);
 
       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
         something.  This avoids an endless loop if they failed to
         fontify the text for which reason ever.  */
       if (!NILP (Fget_char_property (pos, Qfontified, Qnil)))
        handled = HANDLED_RECOMPUTE_PROPS;
-      UNGCPRO;
     }
 
   return handled;
@@ -2110,6 +2225,7 @@ handle_invisible_prop (it)
            = TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop);
 
          handled = HANDLED_RECOMPUTE_PROPS;
+         it->add_overlay_start = IT_CHARPOS (*it);
          
          /* Loop skipping over invisible text.  The loop is left at
             ZV or with IT on the first char being visible again.  */
@@ -2270,8 +2386,8 @@ display_prop_end (it, object, start_pos)
   Lisp_Object end;
   struct text_pos end_pos;
 
-  end = next_single_char_property_change (make_number (CHARPOS (start_pos)),
-                                         Qdisplay, object, Qnil);
+  end = Fnext_single_char_property_change (make_number (CHARPOS (start_pos)),
+                                          Qdisplay, object, Qnil);
   CHARPOS (end_pos) = XFASTINT (end);
   if (STRINGP (object))
     compute_string_pos (&end_pos, start_pos, it->string);
@@ -2300,7 +2416,6 @@ handle_single_display_prop (it, prop, object, position)
 {
   Lisp_Object value;
   int space_or_image_found_p = 0;
-
   Lisp_Object form;
 
   /* If PROP is a list of the form `(when FORM . VALUE)', FORM is
@@ -2368,20 +2483,18 @@ handle_single_display_prop (it, prop, object, position)
                steps = - steps;
              it->face_id = smaller_face (it->f, it->face_id, steps);
            }
-         else if (SYMBOLP (it->font_height))
+         else if (FUNCTIONP (it->font_height))
            {
              /* Call function with current height as argument.
                 Value is the new height.  */
-             Lisp_Object form, height;
-             struct gcpro gcpro1;
+             Lisp_Object args[2], height;
+             
+             args[0] = it->font_height;
+             args[1] = face->lface[LFACE_HEIGHT_INDEX];
+             height = call_function (2, args);
              
-             height = face->lface[LFACE_HEIGHT_INDEX];
-             form = Fcons (it->font_height, Fcons (height, Qnil));
-             GCPRO1 (form);
-             height = eval_form (form);
              if (NUMBERP (height))
                new_height = XFLOATINT (height);
-             UNGCPRO;
            }
          else if (NUMBERP (it->font_height))
            {
@@ -2557,6 +2670,77 @@ handle_single_display_prop (it, prop, object, position)
 }
 
 
+/* Check if PROP is a display sub-property value whose text should be
+   treated as intangible.  */
+
+static int
+single_display_prop_intangible_p (prop)
+     Lisp_Object prop;
+{
+  /* Skip over `when FORM'.  */
+  if (CONSP (prop) && EQ (XCAR (prop), Qwhen))
+    {
+      prop = XCDR (prop);
+      if (!CONSP (prop))
+       return 0;
+      prop = XCDR (prop);
+    }
+
+  if (!CONSP (prop))
+    return 0;
+
+  /* Skip over `margin LOCATION'.  If LOCATION is in the margins,
+     we don't need to treat text as intangible.  */
+  if (EQ (XCAR (prop), Qmargin))
+    {
+      prop = XCDR (prop);
+      if (!CONSP (prop))
+       return 0;
+
+      prop = XCDR (prop);
+      if (!CONSP (prop)
+         || EQ (XCAR (prop), Qleft_margin)
+         || EQ (XCAR (prop), Qright_margin))
+       return 0;
+    }
+  
+  return CONSP (prop) && EQ (XCAR (prop), Qimage);
+}
+
+
+/* Check if PROP is a display property value whose text should be
+   treated as intangible.  */
+
+int
+display_prop_intangible_p (prop)
+     Lisp_Object prop;
+{
+  if (CONSP (prop)
+      && CONSP (XCAR (prop))
+      && !EQ (Qmargin, XCAR (XCAR (prop))))
+    {
+      /* A list of sub-properties.  */
+      while (CONSP (prop))
+       {
+         if (single_display_prop_intangible_p (XCAR (prop)))
+           return 1;
+         prop = XCDR (prop);
+       }
+    }
+  else if (VECTORP (prop))
+    {
+      /* A vector of sub-properties.  */
+      int i;
+      for (i = 0; i < XVECTOR (prop)->size; ++i)
+       if (single_display_prop_intangible_p (XVECTOR (prop)->contents[i]))
+         return 1;
+    }
+  else
+    return single_display_prop_intangible_p (prop);
+
+  return 0;
+}
+
 \f
 /***********************************************************************
                        `composition' property
@@ -2625,6 +2809,7 @@ handle_composition_prop (it)
 
 struct overlay_entry
 {
+  Lisp_Object overlay;
   Lisp_Object string;
   int priority;
   int after_string_p;
@@ -2638,13 +2823,10 @@ static enum prop_handled
 handle_overlay_change (it)
      struct it *it;
 {
-  /* Overlays are handled in current_buffer only.  */
-  if (STRINGP (it->string))
-    return HANDLED_NORMALLY;
+  if (!STRINGP (it->string) && get_overlay_strings (it))
+    return HANDLED_RECOMPUTE_PROPS;
   else
-    return (get_overlay_strings (it)
-           ? HANDLED_RECOMPUTE_PROPS
-           : HANDLED_NORMALLY);
+    return HANDLED_NORMALLY;
 }
 
 
@@ -2673,6 +2855,12 @@ next_overlay_string (it)
       SET_TEXT_POS (it->current.string_pos, -1, -1);
       it->n_overlay_strings = 0;
       it->method = next_element_from_buffer;
+
+      /* If we're at the end of the buffer, record that we have
+        processed the overlay strings there already, so that
+        next_element_from_buffer doesn't try it again.  */
+      if (IT_CHARPOS (*it) >= it->end_charpos)
+       it->overlay_strings_at_end_processed_p = 1;
     }
   else
     {
@@ -2702,7 +2890,8 @@ next_overlay_string (it)
    comparison function for qsort in load_overlay_strings.  Overlay
    strings for the same position are sorted so that
 
-   1. All after-strings come in front of before-strings.
+   1. All after-strings come in front of before-strings, except
+   when they come from the same overlay.
    
    2. Within after-strings, strings are sorted so that overlay strings
    from overlays with higher priorities come first.
@@ -2722,8 +2911,14 @@ compare_overlay_entries (e1, e2)
   int result;
 
   if (entry1->after_string_p != entry2->after_string_p)
-    /* Let after-strings appear in front of before-strings.  */
-    result = entry1->after_string_p ? -1 : 1;
+    {
+      /* Let after-strings appear in front of before-strings if
+        they come from different overlays.  */
+      if (EQ (entry1->overlay, entry2->overlay))
+       result = entry1->after_string_p ? 1 : -1;
+      else
+       result = entry1->after_string_p ? -1 : 1;
+    }
   else if (entry1->after_string_p)
     /* After-strings sorted in order of decreasing priority.  */
     result = entry2->priority - entry1->priority;
@@ -2745,6 +2940,15 @@ compare_overlay_entries (e1, e2)
    strings that have already been loaded by previous calls to this
    function.
 
+   IT->add_overlay_start contains an additional overlay start
+   position to consider for taking overlay strings from, if non-zero.
+   This position comes into play when the overlay has an `invisible'
+   property, and both before and after-strings.  When we've skipped to
+   the end of the overlay, because of its `invisible' property, we
+   nevertheless want its before-string to appear.
+   IT->add_overlay_start will contain the overlay start position
+   in this case.
+
    Overlay strings are sorted so that after-string strings come in
    front of before-string strings.  Within before and after-strings,
    strings are sorted by overlay priority.  See also function
@@ -2783,18 +2987,16 @@ load_overlay_strings (it)
        }                                                               \
                                                                        \
       entries[n].string = (STRING);                                    \
+      entries[n].overlay = (OVERLAY);                                  \
       priority = Foverlay_get ((OVERLAY), Qpriority);                  \
-      entries[n].priority                                              \
-       = INTEGERP (priority) ? XFASTINT (priority) : 0;                \
+      entries[n].priority = INTEGERP (priority) ? XINT (priority) : 0;  \
       entries[n].after_string_p = (AFTER_P);                           \
       ++n;                                                             \
     }                                                                  \
   while (0)
 
   /* Process overlay before the overlay center.  */
-  for (ov = current_buffer->overlays_before;
-       CONSP (ov);
-       ov = XCDR (ov))
+  for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCDR (ov))
     {
       overlay = XCAR (ov);
       xassert (OVERLAYP (overlay));
@@ -2806,7 +3008,9 @@ load_overlay_strings (it)
 
       /* Skip this overlay if it doesn't start or end at IT's current
         position.  */
-      if (end != IT_CHARPOS (*it) && start != IT_CHARPOS (*it))
+      if (end != IT_CHARPOS (*it)
+         && start != IT_CHARPOS (*it)
+         && it->add_overlay_start != IT_CHARPOS (*it))
        continue;
       
       /* Skip this overlay if it doesn't apply to IT->w.  */
@@ -2815,7 +3019,8 @@ load_overlay_strings (it)
        continue;
 
       /* If overlay has a non-empty before-string, record it.  */
-      if (start == IT_CHARPOS (*it)
+      if ((start == IT_CHARPOS (*it)
+          || start == it->add_overlay_start)
          && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
          && XSTRING (str)->size)
        RECORD_OVERLAY_STRING (overlay, str, 0);
@@ -2828,9 +3033,7 @@ load_overlay_strings (it)
     }
       
   /* Process overlays after the overlay center.  */
-  for (ov = current_buffer->overlays_after;
-       CONSP (ov);
-       ov = XCDR (ov))
+  for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCDR (ov))
     {
       overlay = XCAR (ov);
       xassert (OVERLAYP (overlay));
@@ -2842,7 +3045,9 @@ load_overlay_strings (it)
       
       /* Skip this overlay if it doesn't start or end at IT's current
         position.  */
-      if (end != IT_CHARPOS (*it) && start != IT_CHARPOS (*it))
+      if (end != IT_CHARPOS (*it)
+         && start != IT_CHARPOS (*it)
+         && it->add_overlay_start != IT_CHARPOS (*it))
        continue;
 
       /* Skip this overlay if it doesn't apply to IT->w.  */
@@ -2851,7 +3056,8 @@ load_overlay_strings (it)
        continue;
       
       /* If overlay has a non-empty before-string, record it.  */
-      if (start == IT_CHARPOS (*it)
+      if ((start == IT_CHARPOS (*it)
+          || start == it->add_overlay_start)
          && (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str))
          && XSTRING (str)->size)
        RECORD_OVERLAY_STRING (overlay, str, 0);
@@ -2866,7 +3072,8 @@ load_overlay_strings (it)
 #undef RECORD_OVERLAY_STRING
    
   /* Sort entries.  */
-  qsort (entries, n, sizeof *entries, compare_overlay_entries);
+  if (n)
+    qsort (entries, n, sizeof *entries, compare_overlay_entries);
 
   /* Record the total number of strings to process.  */
   it->n_overlay_strings = n;
@@ -2878,7 +3085,7 @@ load_overlay_strings (it)
   j = it->current.overlay_string_index;
   while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
     it->overlay_strings[i++] = entries[j++].string;
-  
+
   CHECK_IT (it);
 }
 
@@ -3675,15 +3882,14 @@ next_element_from_display_vector (it)
 
       /* The entry may contain a face id to use.  Such a face id is
         the id of a Lisp face, not a realized face.  A face id of
-        zero means no face.  */
+        zero means no face is specified.  */
       lface_id = FAST_GLYPH_FACE (g);
       if (lface_id)
        {
+         /* The function returns -1 if lface_id is invalid.  */
          int face_id = ascii_face_of_lisp_face (it->f, lface_id);
          if (face_id >= 0)
-           {
-             it->face_id = face_id;
-           }
+           it->face_id = face_id;
        }
     }
   else
@@ -4112,7 +4318,7 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 
   while (1)
     {
-      int x, i;
+      int x, i, ascent = 0, descent = 0;
       
       /* Stop when ZV or TO_CHARPOS reached.  */
       if (!get_next_display_element (it)
@@ -4129,6 +4335,15 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
         x-position before this display element in case it does not
         fit on the line.  */
       x = it->current_x;
+      
+      /* Remember the line height so far in case the next element doesn't
+        fit on the line.  */
+      if (!it->truncate_lines_p)
+       {
+         ascent = it->max_ascent;
+         descent = it->max_descent;
+       }
+      
       PRODUCE_GLYPHS (it);
 
       if (it->area != TEXT_AREA)
@@ -4194,8 +4409,14 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                        set_iterator_to_next (it);
                    }
                  else
-                   it->current_x = x;
-
+                   {
+                     it->current_x = x;
+                     it->max_ascent = ascent;
+                     it->max_descent = descent;
+                   }
+                 
+                 TRACE_MOVE ((stderr, "move_it_in: continued at %d\n",
+                              IT_CHARPOS (*it)));
                  result = MOVE_LINE_CONTINUED;
                  break;
                }
@@ -4270,8 +4491,9 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
 {
   enum move_it_result skip, skip2 = MOVE_X_REACHED;
   int line_height;
+  int reached = 0;
 
-  while (1)
+  for (;;)
     {
       if (op & MOVE_TO_VPOS)
        {
@@ -4280,31 +4502,46 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
          if ((op & (MOVE_TO_X | MOVE_TO_POS)) == 0)
            {
              if (it->vpos == to_vpos)
-               break;
-             skip = move_it_in_display_line_to (it, -1, -1, 0);
+               {
+                 reached = 1;
+                 break;
+               }
+             else
+               skip = move_it_in_display_line_to (it, -1, -1, 0);
            }
          else
            {
              /* TO_VPOS >= 0 means stop at TO_X in the line at
                 TO_VPOS, or at TO_POS, whichever comes first.  */
+             if (it->vpos == to_vpos)
+               {
+                 reached = 2;
+                 break;
+               }
+             
              skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
 
              if (skip == MOVE_POS_MATCH_OR_ZV || it->vpos == to_vpos)
-               break;
+               {
+                 reached = 3;
+                 break;
+               }
              else if (skip == MOVE_X_REACHED && it->vpos != to_vpos)
                {
                  /* We have reached TO_X but not in the line we want.  */
                  skip = move_it_in_display_line_to (it, to_charpos,
                                                     -1, MOVE_TO_POS);
                  if (skip == MOVE_POS_MATCH_OR_ZV)
-                   break;
+                   {
+                     reached = 4;
+                     break;
+                   }
                }
            }
        }
       else if (op & MOVE_TO_Y)
        {
          struct it it_backup;
-         int done_p;
          
          /* TO_Y specified means stop at TO_X in the line containing
             TO_Y---or at TO_CHARPOS if this is reached first.  The
@@ -4326,22 +4563,27 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
 
          /* If TO_CHARPOS is reached or ZV, we don't have to do more.  */
          if (skip == MOVE_POS_MATCH_OR_ZV)
-           break;
+           {
+             reached = 5;
+             break;
+           }
          
          /* If TO_X was reached, we would like to know whether TO_Y
             is in the line.  This can only be said if we know the
             total line height which requires us to scan the rest of
             the line.  */
-         done_p = 0;
          if (skip == MOVE_X_REACHED)
            {
              it_backup = *it;
+             TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
              skip2 = move_it_in_display_line_to (it, to_charpos, -1,
                                                  op & MOVE_TO_POS);
+             TRACE_MOVE ((stderr, "move_it: to %d\n", IT_CHARPOS (*it)));
            }
 
          /* Now, decide whether TO_Y is in this line.  */
          line_height = it->max_ascent + it->max_descent;
+         TRACE_MOVE ((stderr, "move_it: line_height = %d\n", line_height));
          
          if (to_y >= it->current_y
              && to_y < it->current_y + line_height)
@@ -4351,16 +4593,16 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
                   we scanned too far.  We have to restore IT's settings
                   to the ones before skipping.  */
                *it = it_backup;
-             done_p = 1;
+             reached = 6;
            }
          else if (skip == MOVE_X_REACHED)
            {
              skip = skip2;
              if (skip == MOVE_POS_MATCH_OR_ZV)
-               done_p = 1;
+               reached = 7;
            }
 
-         if (done_p)
+         if (reached)
            break;
        }
       else
@@ -4369,7 +4611,8 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
       switch (skip)
        {
        case MOVE_POS_MATCH_OR_ZV:
-         return;
+         reached = 8;
+         goto out;
 
        case MOVE_NEWLINE_OR_CR:
          set_iterator_to_next (it);
@@ -4381,7 +4624,10 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
          reseat_at_next_visible_line_start (it, 0);
          if ((op & MOVE_TO_POS) != 0
              && IT_CHARPOS (*it) > to_charpos)
-           goto out;
+           {
+             reached = 9;
+             goto out;
+           }
          break;
 
        case MOVE_LINE_CONTINUED:
@@ -4401,7 +4647,10 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
       last_max_ascent = it->max_ascent;
       it->max_ascent = it->max_descent = 0;
     }
- out:;
+  
+ out:
+
+  TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
 }
 
 
@@ -4450,6 +4699,7 @@ move_it_vertically_backward (it, dy)
              MOVE_TO_POS | MOVE_TO_VPOS);
   xassert (IT_CHARPOS (*it) >= BEGV);
   line_height = it2.max_ascent + it2.max_descent;
+  
   move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
   xassert (IT_CHARPOS (*it) >= BEGV);
   h = it2.current_y - it->current_y;
@@ -4504,8 +4754,10 @@ move_it_vertically (it, dy)
     move_it_vertically_backward (it, -dy);
   else if (dy > 0)
     {
+      TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy));
       move_it_to (it, ZV, -1, it->current_y + dy, -1,
                  MOVE_TO_POS | MOVE_TO_Y);
+      TRACE_MOVE ((stderr, "move_it_v: to %d\n", IT_CHARPOS (*it)));
 
       /* If buffer ends in ZV without a newline, move to the start of
         the line to satisfy the post-condition.  */
@@ -4537,9 +4789,9 @@ invisible_text_between_p (it, start_charpos, end_charpos)
     invisible_found_p = 1;
   else
     {
-      limit = next_single_char_property_change (make_number (start_charpos),
-                                               Qinvisible, Qnil,
-                                               make_number (end_charpos));
+      limit = Fnext_single_char_property_change (make_number (start_charpos),
+                                                Qinvisible, Qnil,
+                                                make_number (end_charpos));
       invisible_found_p = XFASTINT (limit) < end_charpos;
     }
 
@@ -4751,7 +5003,7 @@ message_dolog (m, len, nlflag, multibyte)
 
       old_deactivate_mark = Vdeactivate_mark;
       oldbuf = current_buffer;
-      Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
+      Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
       current_buffer->undo_list = Qt;
 
       oldpoint = Fpoint_marker ();
@@ -5298,13 +5550,22 @@ ensure_echo_area_buffers ()
        || NILP (XBUFFER (echo_buffer[i])->name))
       {
        char name[30];
+       Lisp_Object old_buffer;
+       int j;
+
+       old_buffer = echo_buffer[i];
        sprintf (name, " *Echo Area %d*", i);
        echo_buffer[i] = Fget_buffer_create (build_string (name));
+       XBUFFER (echo_buffer[i])->truncate_lines = Qnil;
+
+       for (j = 0; j < 2; ++j)
+         if (EQ (old_buffer, echo_area_buffer[j]))
+           echo_area_buffer[j] = echo_buffer[i];
       }
 }
 
 
-/* Call FN with args A1..A5 with either the current or last displayed
+/* Call FN with args A1..A4 with either the current or last displayed
    echo_area_buffer as current buffer.
 
    WHICH zero means use the current message buffer
@@ -5321,11 +5582,13 @@ ensure_echo_area_buffers ()
    Value is what FN returns. */
 
 static int
-with_echo_area_buffer (w, which, fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
      struct window *w;
      int which;
-     int (*fn) ();
-     int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
+     int (*fn) P_ ((EMACS_INT, Lisp_Object, EMACS_INT, EMACS_INT));
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   Lisp_Object buffer;
   int this_one, the_other, clear_buffer_p, rc;
@@ -5381,7 +5644,7 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
       w->buffer = buffer;
       set_marker_both (w->pointm, buffer, BEG, BEG_BYTE);
     }
-  current_buffer->truncate_lines = Qnil;
+
   current_buffer->undo_list = Qt;
   current_buffer->read_only = Qnil;
 
@@ -5391,7 +5654,7 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
   xassert (BEGV >= BEG);
   xassert (ZV <= Z && ZV >= BEGV);
 
-  rc = fn (a1, a2, a3, a4, a5);
+  rc = fn (a1, a2, a3, a4);
 
   xassert (BEGV >= BEG);
   xassert (ZV <= Z && ZV >= BEGV);
@@ -5515,6 +5778,7 @@ setup_echo_area_for_printing (multibyte_p)
          Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
        }
 
+      message_log_maybe_newline ();
       message_buf_print = 1;
     }
   else
@@ -5561,7 +5825,8 @@ display_echo_area (w)
   
   window_height_changed_p
     = with_echo_area_buffer (w, display_last_displayed_message_p,
-                            (int (*) ()) display_echo_area_1, w);
+                            display_echo_area_1,
+                            (EMACS_INT) w, Qnil, 0, 0);
 
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
@@ -5572,14 +5837,18 @@ display_echo_area (w)
 
 
 /* Helper for display_echo_area.  Display the current buffer which
-   contains the current echo area message in window W, a mini-window.
+   contains the current echo area message in window W, a mini-window,
+   a pointer to which is passed in A1.  A2..A4 are currently not used.
    Change the height of W so that all of the message is displayed.
    Value is non-zero if height of W was changed.  */
 
 static int
-display_echo_area_1 (w)
-     struct window *w;
+display_echo_area_1 (a1, a2, a3, a4)
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
+  struct window *w = (struct window *) a1;
   Lisp_Object window;
   struct text_pos start;
   int window_height_changed_p = 0;
@@ -5610,9 +5879,8 @@ resize_echo_area_axactly ()
       struct window *w = XWINDOW (echo_area_window);
       int resized_p;
       
-      resized_p = with_echo_area_buffer (w, 0,
-                                        (int (*) ()) resize_mini_window,
-                                        w, 1);
+      resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
+                                        (EMACS_INT) w, Qnil, 0, 0);
       if (resized_p)
        {
          ++windows_or_buffers_changed;
@@ -5623,6 +5891,21 @@ resize_echo_area_axactly ()
 }
 
 
+/* Callback function for with_echo_area_buffer, when used from
+   resize_echo_area_axactly.  A1 contains a pointer to the window to
+   resize, A2 to A4 are not used.  Value is what resize_mini_window
+   returns.  */
+
+static int
+resize_mini_window_1 (a1, a2, a3, a4)
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
+{
+  return resize_mini_window ((struct window *) a1, 1);
+}
+
+
 /* Resize mini-window W to fit the size of its contents.  EXACT:P
    means size the window exactly to the size needed.  Otherwise, it's
    only enlarged until W's buffer is empty.  Value is non-zero if
@@ -5667,13 +5950,19 @@ resize_mini_window (w, exact_p)
       max_height = min (total_height, max_height);
       
       /* Find out the height of the text in the window.  */
-      last_height = 0;
-      move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
-      if (it.max_ascent == 0 && it.max_descent == 0)
-       height = it.current_y + last_height;
+      if (it.truncate_lines_p)
+       height = 1;
       else
-       height = it.current_y + it.max_ascent + it.max_descent;
-      height = (height + unit - 1) / unit;
+       {
+         last_height = 0;
+         move_it_to (&it, ZV, -1, -1, -1, MOVE_TO_POS);
+         if (it.max_ascent == 0 && it.max_descent == 0)
+           height = it.current_y + last_height;
+         else
+           height = it.current_y + it.max_ascent + it.max_descent;
+         height -= it.extra_line_spacing;
+         height = (height + unit - 1) / unit;
+       }
       
       /* Compute a suitable window start.  */
       if (height > max_height)
@@ -5722,7 +6011,8 @@ current_message ()
     msg = Qnil;
   else
     {
-      with_echo_area_buffer (0, 0, (int (*) ()) current_message_1, &msg);
+      with_echo_area_buffer (0, 0, current_message_1,
+                            (EMACS_INT) &msg, Qnil, 0, 0);
       if (NILP (msg))
        echo_area_buffer[0] = Qnil;
     }
@@ -5732,9 +6022,13 @@ current_message ()
 
 
 static int
-current_message_1 (msg)
-     Lisp_Object *msg;
+current_message_1 (a1, a2, a3, a4)
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
+  Lisp_Object *msg = (Lisp_Object *) a1;
+  
   if (Z > BEG)
     *msg = make_buffer_string (BEG, Z, 1);
   else
@@ -5814,7 +6108,7 @@ truncate_echo_area (nchars)
     {
       struct frame *sf = SELECTED_FRAME ();
       if (FRAME_MESSAGE_BUF (sf))
-       with_echo_area_buffer (0, 0, (int (*) ()) truncate_message_1, nchars);
+       with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
     }
 }
 
@@ -5823,8 +6117,10 @@ truncate_echo_area (nchars)
    message to at most NCHARS characters.  */
 
 static int
-truncate_message_1 (nchars)
-     int nchars;
+truncate_message_1 (nchars, a2, a3, a4)
+     EMACS_INT nchars;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   if (BEG + nchars < Z)
     del_range (BEG + nchars, Z);
@@ -5854,22 +6150,26 @@ set_message (s, string, nbytes, multibyte_p)
     = ((s && multibyte_p)
        || (STRINGP (string) && STRING_MULTIBYTE (string)));
   
-  with_echo_area_buffer (0, -1, (int (*) ()) set_message_1,
-                        s, string, nbytes, multibyte_p);
+  with_echo_area_buffer (0, -1, set_message_1,
+                        (EMACS_INT) s, string, nbytes, multibyte_p);
   message_buf_print = 0;
 }
 
 
 /* Helper function for set_message.  Arguments have the same meaning
-   as there.  This function is called with the echo area buffer being
+   as there, with A1 corresponding to S and A2 corresponding to STRING
+   This function is called with the echo area buffer being
    current.  */
 
 static int
-set_message_1 (s, string, nbytes, multibyte_p)
-     char *s;
-     Lisp_Object string;
-     int nbytes, multibyte_p;
+set_message_1 (a1, a2, nbytes, multibyte_p)
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT nbytes, multibyte_p;
 {
+  char *s = (char *) a1;
+  Lisp_Object string = a2;
+  
   xassert (BEG == Z);
   
   /* Change multibyteness of the echo buffer appropriately.  */
@@ -5877,6 +6177,8 @@ set_message_1 (s, string, nbytes, multibyte_p)
       != !NILP (current_buffer->enable_multibyte_characters))
     Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
 
+  current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil;
+  
   /* Insert new message at BEG.  */
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
@@ -6029,20 +6331,30 @@ echo_area_display (update_frame_p)
       window_height_changed_p = display_echo_area (w);
       w->must_be_updated_p = 1;
 
+      /* Update the display, unless called from redisplay_internal. */
       if (update_frame_p)
        {
-         /* Not called from redisplay_internal.  If we changed
-            window configuration, we must redisplay thoroughly.
-            Otherwise, we can do with updating what we displayed
-            above.  */
+         int n = 0;
+
+         /* If the display update has been interrupted by pending
+            input, update mode lines in the frame.  Due to the
+            pending input, it might have been that redisplay hasn't
+            been called, so that mode lines above the echo area are
+            garbaged.  This looks odd, so we prevent it here.  */
+         if (!display_completed)
+           n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), 0);
+           
          if (window_height_changed_p)
            {
-             ++windows_or_buffers_changed;
-             ++update_mode_lines;
+             /* Must update other windows.  */
+             windows_or_buffers_changed = 1;
              redisplay_internal (0);
            }
-         else if (FRAME_WINDOW_P (f))
+         else if (FRAME_WINDOW_P (f) && n == 0)
            {
+             /* Window configuration is the same as before.
+                Can do with a display update of the echo area,
+                unless we displayed some mode lines.  */
              update_single_window (w, 1);
              rif->flush_display (f);
            }
@@ -6534,7 +6846,7 @@ build_desired_tool_bar_string (f)
 
       int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
       int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
-      int margin, relief;
+      int margin, relief, idx;
       extern Lisp_Object QCrelief, QCmargin, QCalgorithm, Qimage;
       extern Lisp_Object Qlaplace;
 
@@ -6543,8 +6855,6 @@ build_desired_tool_bar_string (f)
       image = PROP (TOOL_BAR_ITEM_IMAGES);
       if (VECTORP (image))
        {
-         enum tool_bar_item_image idx;
-         
          if (enabled_p)
            idx = (selected_p
                   ? TOOL_BAR_IMAGE_ENABLED_SELECTED
@@ -6554,9 +6864,11 @@ build_desired_tool_bar_string (f)
                   ? TOOL_BAR_IMAGE_DISABLED_SELECTED
                   : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
          
-         xassert (XVECTOR (image)->size >= idx);
-         image = XVECTOR (image)->contents[idx];
+         xassert (ASIZE (image) >= idx);
+         image = AREF (image, idx);
        }
+      else
+       idx = -1;
 
       /* Ignore invalid image specifications.  */
       if (!valid_image_p (image))
@@ -6595,10 +6907,11 @@ build_desired_tool_bar_string (f)
       if (margin)
        plist = Fplist_put (plist, QCmargin, make_number (margin));
          
-      /* If button is not enabled, make the image appear disabled by
+      /* If button is not enabled, and we don't have special images
+        for the disabled state, make the image appear disabled by
         applying an appropriate algorithm to it.  */
-      if (!enabled_p)
-       plist = Fplist_put (plist, QCalgorithm, Qlaplace);
+      if (!enabled_p && idx < 0)
+       plist = Fplist_put (plist, QCalgorithm, Qdisabled);
       
       /* Put a `display' text property on the string for the image to
         display.  Put a `menu-item' property on the string that gives
@@ -7240,7 +7553,7 @@ redisplay_internal (preserve_echo_area)
   ++redisplaying_p;
   
  retry:
-
+  pause = 0;
   reconsider_clip_changes (w, current_buffer);
 
   /* If new fonts have been loaded that make a glyph matrix adjustment
@@ -7353,7 +7666,7 @@ redisplay_internal (preserve_echo_area)
            clear_garbaged_frames ();
        }
     }
-  else if (w == XWINDOW (minibuf_window)
+  else if (EQ (selected_window, minibuf_window)
           && (current_buffer->clip_changed
               || XFASTINT (w->last_modified) < MODIFF
               || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF)
@@ -7549,7 +7862,7 @@ redisplay_internal (preserve_echo_area)
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && (w == XWINDOW (current_buffer->last_selected_window)
+              && (EQ (selected_window, current_buffer->last_selected_window)
                   || highlight_nonselected_windows)
               && NILP (w->region_showing)
               && NILP (Vshow_trailing_whitespace)
@@ -7594,9 +7907,9 @@ redisplay_internal (preserve_echo_area)
   ++clear_face_cache_count;
 
   
-  /* Build desired matrices.  If consider_all_windows_p is non-zero,
-     do it for all windows on all frames.  Otherwise do it for
-     selected_window, only.  */
+  /* Build desired matrices, and update the display.  If
+     consider_all_windows_p is non-zero, do it for all windows on all
+     frames.  Otherwise do it for selected_window, only.  */
 
   if (consider_all_windows_p)
     {
@@ -7616,6 +7929,7 @@ redisplay_internal (preserve_echo_area)
       FOR_EACH_FRAME (tail, frame)
        {
          struct frame *f = XFRAME (frame);
+         
          if (FRAME_WINDOW_P (f) || f == sf)
            {
              /* Mark all the scroll bars to be removed; we'll redeem
@@ -7630,81 +7944,60 @@ redisplay_internal (preserve_echo_area)
                 nuked should now go away.  */
              if (judge_scroll_bars_hook)
                (*judge_scroll_bars_hook) (f);
+
+             /* If fonts changed, display again.  */
+             if (fonts_changed_p)
+               goto retry;
+             
+             if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
+               {
+                 /* See if we have to hscroll.  */
+                 if (hscroll_windows (f->root_window))
+                   goto retry;
+
+                 /* Prevent various kinds of signals during display
+                    update.  stdio is not robust about handling
+                    signals, which can cause an apparent I/O
+                    error.  */
+                 if (interrupt_input)
+                   unrequest_sigio ();
+                 stop_polling ();
+
+                 /* Update the display.  */
+                 set_window_update_flags (XWINDOW (f->root_window), 1);
+                 pause |= update_frame (f, 0, 0);
+                 if (pause)
+                   break;
+
+                 mark_window_display_accurate (f->root_window, 1);
+                 if (frame_up_to_date_hook)
+                   frame_up_to_date_hook (f);
+               }
            }
        }
     }
-  else if (FRAME_VISIBLE_P (sf)
-          && !FRAME_OBSCURED_P (sf))
-    redisplay_window (selected_window, 1);
+  else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
+    {
+      Lisp_Object mini_window;
+      struct frame *mini_frame;
 
+      redisplay_window (selected_window, 1);
   
-  /* Compare desired and current matrices, perform output.  */
-  
-update:
+      /* Compare desired and current matrices, perform output.  */
+    update:
   
-  /* If fonts changed, display again.  */
-  if (fonts_changed_p)
-    goto retry;
-
-  /* Prevent various kinds of signals during display update.
-     stdio is not robust about handling signals,
-     which can cause an apparent I/O error.  */
-  if (interrupt_input)
-    unrequest_sigio ();
-  stop_polling ();
-
-  if (consider_all_windows_p)
-    {
-      Lisp_Object tail;
-      struct frame *f;
-      int hscrolled_p;
-
-      pause = 0;
-      hscrolled_p = 0;
-
-      /* See if we have to hscroll.  */
-      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
-       if (FRAMEP (XCAR (tail)))
-         {
-           f = XFRAME (XCAR (tail));
-           
-           if ((FRAME_WINDOW_P (f)
-                || f == sf)
-               && FRAME_VISIBLE_P (f)
-               && !FRAME_OBSCURED_P (f)
-               && hscroll_windows (f->root_window))
-             hscrolled_p = 1;
-         }
-
-      if (hscrolled_p)
+      /* If fonts changed, display again.  */
+      if (fonts_changed_p)
        goto retry;
 
-      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
-       {
-         if (!FRAMEP (XCAR (tail)))
-           continue;
-
-         f = XFRAME (XCAR (tail));
+      /* Prevent various kinds of signals during display update.
+        stdio is not robust about handling signals,
+        which can cause an apparent I/O error.  */
+      if (interrupt_input)
+       unrequest_sigio ();
+      stop_polling ();
 
-         if ((FRAME_WINDOW_P (f) || f == sf)
-             && FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
-           {
-             /* Mark all windows as to be updated.  */
-             set_window_update_flags (XWINDOW (f->root_window), 1);
-             pause |= update_frame (f, 0, 0);
-             if (!pause)
-               {
-                 mark_window_display_accurate (f->root_window, 1);
-                 if (frame_up_to_date_hook != 0)
-                   (*frame_up_to_date_hook) (f);
-               }
-           }
-       }
-    }
-  else
-    {
-      if (FRAME_VISIBLE_P (sf)
-         && !FRAME_OBSCURED_P (sf))
+      if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
        {
          if (hscroll_windows (selected_window))
            goto retry;
@@ -7712,29 +8005,22 @@ update:
          XWINDOW (selected_window)->must_be_updated_p = 1;
          pause = update_frame (sf, 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
         have put text on a frame other than the selected one, so the
         above call to update_frame would not have caught it.  Catch
         it here.  */
-      {
-       Lisp_Object mini_window;
-       struct frame *mini_frame;
-
-       mini_window = FRAME_MINIBUF_WINDOW (sf);
-       mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+      mini_window = FRAME_MINIBUF_WINDOW (sf);
+      mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
        
-       if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
-         {
-           XWINDOW (mini_window)->must_be_updated_p = 1;
-           pause |= update_frame (mini_frame, 0, 0);
-           if (!pause && hscroll_windows (mini_window))
-             goto retry;
-         }
-      }
+      if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
+       {
+         XWINDOW (mini_window)->must_be_updated_p = 1;
+         pause |= update_frame (mini_frame, 0, 0);
+         if (!pause && hscroll_windows (mini_window))
+           goto retry;
+       }
     }
 
   /* If display was paused because of pending input, make sure we do a
@@ -7791,7 +8077,8 @@ update:
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
          w->region_showing = (!NILP (Vtransient_mark_mode)
-                              && (w == XWINDOW (current_buffer->last_selected_window)
+                              && (EQ (selected_window,
+                                      current_buffer->last_selected_window)
                                   || highlight_nonselected_windows)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
@@ -8160,7 +8447,7 @@ make_cursor_line_fully_visible (w)
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
-  int header_line_height;
+  int window_height, header_line_height;
   
   /* It's not always possible to find the cursor, e.g, when a window
      is full of overlay strings.  Don't do anything in that case.  */
@@ -8170,31 +8457,32 @@ make_cursor_line_fully_visible (w)
   matrix = w->desired_matrix;
   row = MATRIX_ROW (matrix, w->cursor.vpos);
 
-  if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row)
-      /* The row may be partially visible at the top because we
-        already have chosen a vscroll to align the bottom of the
-        row with the bottom of the window.  This happens for rows
-        taller than the window.  */
-      && row->y + row->height < window_box_height (w))
+  /* If the cursor row is not partially visible, there's nothing
+     to do.  */
+  if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+    return;
+
+  /* If the row the cursor is in is taller than the window's height,
+     it's not clear what to do, so do nothing.  */
+  window_height = window_box_height (w);
+  if (row->height >= window_height)
+    return;
+
+  if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
     {
       int dy = row->height - row->visible_height;
       w->vscroll = 0;
       w->cursor.y += dy;
       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
     }
-  else if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)
-          /* The row may be partially visible at the bottom because
-             we chose a vscroll to align the row's top with the
-             window's top.  This happens for rows taller than the
-             window.  */
-          && row->y > WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w))
+  else /* MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)) */
     {
       int dy = - (row->height - row->visible_height);
       w->vscroll = dy;
       w->cursor.y += dy;
       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
     }
-
+  
   /* When we change the cursor y-position of the selected window,
      change this_line_y as well so that the display optimization for
      the cursor line of the selected window in redisplay_internal uses
@@ -8295,7 +8583,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
       
       /* Point is in the scroll margin at the bottom of the window, or
         below.  Compute a new window start that makes point visible.  */
-      
+
       /* Compute the distance from the scroll margin to PT.
         Give up if the distance is greater than scroll_max.  */
       start_display (&it, w, scroll_margin_pos);
@@ -8306,6 +8594,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
                     ? it.max_ascent + it.max_descent
                     : last_height);
       dy = it.current_y + line_height - y0;
+      
       if (dy > scroll_max)
        return 0;
       
@@ -8490,6 +8779,219 @@ compute_window_start_on_continuation_line (w)
 }
 
 
+/* Try cursor movement in case text has not changes in window WINDOW,
+   with window start STARTP.  Value is
+
+   1   if successful
+   
+   0   if this method cannot be used
+   
+   -1  if we know we have to scroll the display.  *SCROLL_STEP is
+   set to 1, under certain circumstances, if we want to scroll as
+   if scroll-step were set to 1.  See the code.  */
+
+static int
+try_cursor_movement (window, startp, scroll_step)
+     Lisp_Object window;
+     struct text_pos startp;
+     int *scroll_step;
+{
+  struct window *w = XWINDOW (window);
+  struct frame *f = XFRAME (w->frame);
+  int rc = 0;
+  
+  /* Handle case where text has not changed, only point, and it has
+     not moved off the frame.  */
+  if (/* Point may be in this window.  */
+      PT >= CHARPOS (startp)
+      /* If we don't check this, we are called to move the cursor in a
+        horizontally split window with a current matrix that doesn't
+        fit the display.  */
+      && !windows_or_buffers_changed
+      /* Selective display hasn't changed.  */
+      && !current_buffer->clip_changed
+      /* 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.  When a 
+         region exists, cursor movement has to do more than just
+         set the cursor.  */
+      && !(!NILP (Vtransient_mark_mode)
+          && !NILP (current_buffer->mark_active))
+      && NILP (w->region_showing)
+      && NILP (Vshow_trailing_whitespace)
+      /* Right after splitting windows, last_point may be nil.  */
+      && INTEGERP (w->last_point)
+      /* This code is not used for mini-buffer for the sake of the case
+        of redisplaying to replace an echo area message; since in
+        that case the mini-buffer contents per se are usually
+        unchanged.  This code is of no real use in the mini-buffer
+        since the handling of this_line_start_pos, etc., in redisplay
+        handles the same cases.  */
+      && !EQ (window, minibuf_window)
+      /* When splitting windows or for new windows, it happens that
+        redisplay is called with a nil window_end_vpos or one being
+        larger than the window.  This should really be fixed in
+        window.c.  I don't have this on my list, now, so we do
+        approximately the same as the old redisplay code.  --gerd.  */
+      && INTEGERP (w->window_end_vpos)
+      && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
+      && (FRAME_WINDOW_P (f)
+         || !MARKERP (Voverlay_arrow_position)
+         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+    {
+      int this_scroll_margin;
+      struct glyph_row *row;
+
+#if GLYPH_DEBUG
+      debug_method_add (w, "cursor movement");
+#endif
+
+      /* Scroll if point within this distance from the top or bottom
+        of the window.  This is a pixel value.  */
+      this_scroll_margin = max (0, scroll_margin);
+      this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
+      this_scroll_margin *= CANON_Y_UNIT (f);
+
+      /* Start with the row the cursor was displayed during the last
+        not paused redisplay.  Give up if that row is not valid.  */
+      if (w->last_cursor.vpos < 0
+         || w->last_cursor.vpos >= w->current_matrix->nrows)
+       rc = -1;
+      else
+       {
+         row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
+         if (row->mode_line_p)
+           ++row;
+         if (!row->enabled_p)
+           rc = -1;
+       }
+
+      if (rc == 0)
+       {
+         int scroll_p = 0;
+         
+         if (PT > XFASTINT (w->last_point))
+           {
+             /* Point has moved forward.  */
+             int last_y = window_text_bottom_y (w) - this_scroll_margin;
+         
+             while (MATRIX_ROW_END_CHARPOS (row) < PT
+                    && MATRIX_ROW_BOTTOM_Y (row) < last_y)
+               {
+                 xassert (row->enabled_p);
+                 ++row;
+               }
+
+             /* The end position of a row equals the start position
+                of the next row.  If PT is there, we would rather
+                display it in the next line.  Exceptions are when the
+                row ends in the middle of a character, or ends in
+                ZV.  */
+             if (MATRIX_ROW_BOTTOM_Y (row) < last_y
+                 && MATRIX_ROW_END_CHARPOS (row) == PT
+                 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
+                 && !row->ends_at_zv_p)
+               {
+                 xassert (row->enabled_p);
+                 ++row;
+               }
+
+             /* If within the scroll margin, scroll.  Note that
+                MATRIX_ROW_BOTTOM_Y gives the pixel position at which
+                the next line would be drawn, and that
+                this_scroll_margin can be zero.  */
+             if (MATRIX_ROW_BOTTOM_Y (row) > last_y
+                 || PT > MATRIX_ROW_END_CHARPOS (row)
+                 /* Line is completely visible last line in window
+                    and PT is to be set in the next line.  */
+                 || (MATRIX_ROW_BOTTOM_Y (row) == last_y
+                     && PT == MATRIX_ROW_END_CHARPOS (row)
+                     && !row->ends_at_zv_p
+                     && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+               scroll_p = 1;
+           }
+         else if (PT < XFASTINT (w->last_point))
+           {
+             /* Cursor has to be moved backward.  Note that PT >=
+                CHARPOS (startp) because of the outer
+                if-statement.  */
+             while (!row->mode_line_p
+                    && (MATRIX_ROW_START_CHARPOS (row) > PT
+                        || (MATRIX_ROW_START_CHARPOS (row) == PT
+                            && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
+                    && (row->y > this_scroll_margin
+                        || CHARPOS (startp) == BEGV))
+               {
+                 xassert (row->enabled_p);
+                 --row;
+               }
+
+             /* Consider the following case: Window starts at BEGV,
+                there is invisible, intangible text at BEGV, so that
+                display starts at some point START > BEGV.  It can
+                happen that we are called with PT somewhere between
+                BEGV and START.  Try to handle that case.  */
+             if (row < w->current_matrix->rows
+                 || row->mode_line_p)
+               {
+                 row = w->current_matrix->rows;
+                 if (row->mode_line_p)
+                   ++row;
+               }
+
+             /* Due to newlines in overlay strings, we may have to
+                skip forward over overlay strings.  */
+             while (MATRIX_ROW_END_CHARPOS (row) == PT
+                    && MATRIX_ROW_ENDS_IN_OVERLAY_STRING_P (row)
+                    && !row->ends_at_zv_p)
+               ++row;
+         
+             /* If within the scroll margin, scroll.  */
+             if (row->y < this_scroll_margin
+                 && CHARPOS (startp) != BEGV)
+               scroll_p = 1;
+           }
+
+         if (PT < MATRIX_ROW_START_CHARPOS (row)
+             || PT > MATRIX_ROW_END_CHARPOS (row))
+           {
+             /* if PT is not in the glyph row, give up.  */
+             rc = -1;
+           }
+         else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+           {
+             /* If we end up in a partially visible line, let's make it
+                fully visible, except when it's taller than the window,
+                in which case we can't do much about it.  */
+             if (row->height > window_box_height (w))
+               {
+                 *scroll_step = 1;
+                 rc = -1;
+               }
+             else
+               {
+                 set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+                 try_window (window, startp);
+                 make_cursor_line_fully_visible (w);
+                 rc = 1;
+               }
+           }
+         else if (scroll_p)
+           rc = -1;
+         else
+           {
+             set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+             rc = 1;
+           }
+       }
+    }
+
+  return rc;
+}
+
+
 /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P non-zero means only
    selected_window is redisplayed.  */
 
@@ -8508,9 +9010,9 @@ redisplay_window (window, just_this_one_p)
   struct it it;
   /* Record it now because it's overwritten.  */
   int current_matrix_up_to_date_p = 0;
-  int really_switched_buffer = 0;
   int temp_scroll_step = 0;
   int count = specpdl_ptr - specpdl;
+  int rc;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -8561,15 +9063,9 @@ redisplay_window (window, just_this_one_p)
 
   /* Otherwise set up data on this window; select its buffer and point
      value.  */
-  if (update_mode_line)
-    {
-      /* Really select the buffer, for the sake of buffer-local
-         variables.  */
-      set_buffer_internal_1 (XBUFFER (w->buffer));
-      really_switched_buffer = 1;
-    }
-  else
-    set_buffer_temp (XBUFFER (w->buffer));
+  /* Really select the buffer, for the sake of buffer-local
+     variables.  */
+  set_buffer_internal_1 (XBUFFER (w->buffer));
   SET_TEXT_POS (opoint, PT, PT_BYTE);
 
   current_matrix_up_to_date_p
@@ -8677,7 +9173,6 @@ redisplay_window (window, just_this_one_p)
       && CHARPOS (startp) <= ZV)
     {
       w->optional_new_start = Qnil;
-      /* This takes a mini-buffer prompt into account.  */
       start_display (&it, w, startp);
       move_it_to (&it, PT, 0, it.last_visible_y, -1,
                  MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
@@ -8709,13 +9204,6 @@ redisplay_window (window, just_this_one_p)
       if (!update_mode_line
          || ! NILP (Vwindow_scroll_functions))
        {
-         if (!really_switched_buffer)
-           {
-             set_buffer_temp (old);
-             set_buffer_internal_1 (XBUFFER (w->buffer));
-             really_switched_buffer = 1;
-           }
-         
          update_mode_line = 1;
          w->update_mode_line = Qt;
          startp = run_window_scroll_functions (window, startp);
@@ -8739,13 +9227,15 @@ redisplay_window (window, just_this_one_p)
 
       if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
        {
-         /* If point does not appear, or on a line that is not fully
-            visible, move point so it does appear.  The desired
-            matrix has been built above, so we can use it.  */
-         int height = window_box_height (w) / 2;
-         struct glyph_row *row = MATRIX_ROW (w->desired_matrix, 0);
-         
-         while (row->y < height)
+         /* If point does not appear, try to move point so it does
+            appear. The desired matrix has been built above, so we
+            can use it here.  */
+         int window_height;
+         struct glyph_row *row;
+
+         window_height = window_box_height (w) / 2;
+         row = MATRIX_FIRST_TEXT_ROW (w->desired_matrix);
+         while (MATRIX_ROW_BOTTOM_Y (row) < window_height)
            ++row;
 
          TEMP_SET_PT_BOTH (MATRIX_ROW_START_CHARPOS (row),
@@ -8779,164 +9269,14 @@ redisplay_window (window, just_this_one_p)
   /* Handle case where text has not changed, only point, and it has
      not moved off the frame.  */
   if (current_matrix_up_to_date_p
-      /* Point may be in this window.  */
-      && PT >= CHARPOS (startp)
-      /* If we don't check this, we are called to move the cursor in a
-        horizontally split window with a current matrix that doesn't
-        fit the display.  */
-      && !windows_or_buffers_changed
-      /* Selective display hasn't changed.  */
-      && !current_buffer->clip_changed
-      /* 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.  When a 
-         region exists, cursor movement has to do more than just
-         set the cursor.  */
-      && !(!NILP (Vtransient_mark_mode)
-          && !NILP (current_buffer->mark_active))
-      && NILP (w->region_showing)
-      && NILP (Vshow_trailing_whitespace)
-      /* Right after splitting windows, last_point may be nil.  */
-      && INTEGERP (w->last_point)
-      /* This code is not used for mini-buffer for the sake of the case
-        of redisplaying to replace an echo area message; since in
-        that case the mini-buffer contents per se are usually
-        unchanged.  This code is of no real use in the mini-buffer
-        since the handling of this_line_start_pos, etc., in redisplay
-        handles the same cases.  */
-      && !EQ (window, minibuf_window)
-      /* When splitting windows or for new windows, it happens that
-        redisplay is called with a nil window_end_vpos or one being
-        larger than the window.  This should really be fixed in
-        window.c.  I don't have this on my list, now, so we do
-        approximately the same as the old redisplay code.  --gerd.  */
-      && INTEGERP (w->window_end_vpos)
-      && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
-      && (FRAME_WINDOW_P (f)
-         || !MARKERP (Voverlay_arrow_position)
-         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+      && (rc = try_cursor_movement (window, startp, &temp_scroll_step),
+         rc != 0))
     {
-      int this_scroll_margin;
-      struct glyph_row *row;
-      int scroll_p;
-
-#if GLYPH_DEBUG
-      debug_method_add (w, "cursor movement");
-#endif
-
-      /* Scroll if point within this distance from the top or bottom
-        of the window.  This is a pixel value.  */
-      this_scroll_margin = max (0, scroll_margin);
-      this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
-      this_scroll_margin *= CANON_Y_UNIT (f);
-
-      /* Start with the row the cursor was displayed during the last
-        not paused redisplay.  Give up if that row is not valid.  */
-      if (w->last_cursor.vpos >= w->current_matrix->nrows)
+      if (rc == -1)
        goto try_to_scroll;
-      row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
-      if (row->mode_line_p)
-       ++row;
-      if (!row->enabled_p)
-       goto try_to_scroll;
-
-      scroll_p = 0;
-      if (PT > XFASTINT (w->last_point))
-       {
-         /* Point has moved forward.  */
-         int last_y = window_text_bottom_y (w) - this_scroll_margin;
-         
-         while ((MATRIX_ROW_END_CHARPOS (row) < PT
-                 /* The end position of a row equals the start
-                    position of the next row.  If PT is there, we
-                    would rather display it in the next line, except
-                    when this line ends in ZV.  */
-                 || (MATRIX_ROW_END_CHARPOS (row) == PT
-                     && (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
-                         || !row->ends_at_zv_p)))
-                && MATRIX_ROW_BOTTOM_Y (row) < last_y)
-           {
-             xassert (row->enabled_p);
-             ++row;
-           }
-
-         /* If within the scroll margin, scroll.  Note that
-            MATRIX_ROW_BOTTOM_Y gives the pixel position at which the
-            next line would be drawn, and that this_scroll_margin can
-            be zero.  */
-         if (MATRIX_ROW_BOTTOM_Y (row) > last_y
-             || PT > MATRIX_ROW_END_CHARPOS (row)
-             /* Line is completely visible last line in window and PT
-                is to be set in the next line.  */
-             || (MATRIX_ROW_BOTTOM_Y (row) == last_y
-                 && PT == MATRIX_ROW_END_CHARPOS (row)
-                 && !row->ends_at_zv_p
-                 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
-           scroll_p = 1;
-       }
-      else if (PT < XFASTINT (w->last_point))
-       {
-         /* Cursor has to be moved backward.  Note that PT >=
-            CHARPOS (startp) because of the outer if-statement.  */
-         while (!row->mode_line_p
-                && (MATRIX_ROW_START_CHARPOS (row) > PT
-                    || (MATRIX_ROW_START_CHARPOS (row) == PT
-                        && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
-                && (row->y > this_scroll_margin
-                    || CHARPOS (startp) == BEGV))
-           {
-             xassert (row->enabled_p);
-             --row;
-           }
-
-         /* Consider the following case: Window starts at BEGV, there
-            is invisible, intangible text at BEGV, so that display
-            starts at some point START > BEGV.  It can happen that
-            we are called with PT somewhere between BEGV and START.
-            Try to handle that case.  */
-         if (row < w->current_matrix->rows
-             || row->mode_line_p)
-           {
-             row = w->current_matrix->rows;
-             if (row->mode_line_p)
-               ++row;
-           }
-
-         /* Due to newlines in overlay strings, we may have to skip
-            forward over overlay strings.  */
-         while (MATRIX_ROW_END_CHARPOS (row) == PT
-                && MATRIX_ROW_ENDS_IN_OVERLAY_STRING_P (row)
-                && !row->ends_at_zv_p)
-           ++row;
-         
-         /* If within the scroll margin, scroll.  */
-         if (row->y < this_scroll_margin
-             && CHARPOS (startp) != BEGV)
-           scroll_p = 1;
-       }
-
-      /* if PT is not in the glyph row, give up.  */
-      if (PT < MATRIX_ROW_START_CHARPOS (row)
-         || PT > MATRIX_ROW_END_CHARPOS (row))
-       goto try_to_scroll;
-
-      /* If we end up in a partially visible line, let's make it fully
-        visible.  This can be done most easily by using the existing
-        scrolling code.  */
-      if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
-       {
-         temp_scroll_step = 1;
-         goto try_to_scroll;
-       }
-      else if (scroll_p)
-       goto try_to_scroll;
-      
-      set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-      goto done;
+      else
+       goto done;
     }
-  
   /* If current starting point was originally the beginning of a line
      but no longer is, find a new starting point.  */
   else if (!NILP (w->start_at_line_beg)
@@ -8981,13 +9321,14 @@ redisplay_window (window, just_this_one_p)
           && (tem = try_window_id (w)) != 0)
     {
 #if GLYPH_DEBUG
-      debug_method_add (w, "try_window_id");
+      debug_method_add (w, "try_window_id %d", tem);
 #endif
 
       if (fonts_changed_p)
        goto restore_buffers;
       if (tem > 0)
        goto done;
+
       /* Otherwise try_window_id has returned -1 which means that we
         don't want the alternative below this comment to execute.  */
     }
@@ -9044,12 +9385,6 @@ redisplay_window (window, just_this_one_p)
   /* Redisplay the mode line.  Select the buffer properly for that.  */
   if (!update_mode_line)
     {
-      if (!really_switched_buffer)
-       {
-         set_buffer_temp (old);
-         set_buffer_internal_1 (XBUFFER (w->buffer));
-         really_switched_buffer = 1;
-       }
       update_mode_line = 1;
       w->update_mode_line = Qt;
     }
@@ -9201,7 +9536,13 @@ redisplay_window (window, just_this_one_p)
        && (WINDOW_WANTS_MODELINE_P (w)
           || WINDOW_WANTS_HEADER_LINE_P (w)))
     {
+      Lisp_Object old_selected_frame;
+      
+      old_selected_frame = selected_frame;
+      
+      XSETFRAME (selected_frame, f);
       display_mode_lines (w);
+      selected_frame = old_selected_frame;
 
       /* If mode line height has changed, arrange for a thorough
         immediate redisplay using the correct mode line height.  */
@@ -9307,10 +9648,7 @@ redisplay_window (window, just_this_one_p)
 
   /* Restore current_buffer and value of point in it.  */
   TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
-  if (really_switched_buffer)
-    set_buffer_internal_1 (old);
-  else
-    set_buffer_temp (old);
+  set_buffer_internal_1 (old);
   TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
 
   unbind_to (count, Qnil);
@@ -9407,9 +9745,12 @@ try_window_reusing_current_matrix (w)
   struct glyph_row *last_reused_text_row;
   struct glyph_row *start_row;
   int start_vpos, min_y, max_y;
-
-  /* Right now this function doesn't handle terminal frames.  */
-  if (!FRAME_WINDOW_P (f))
+  
+  if (/* This function doesn't handle terminal frames.  */
+      !FRAME_WINDOW_P (f)
+      /* Don't try to reuse the display if windows have been split
+        or such.  */
+      || windows_or_buffers_changed)
     return 0;
 
   /* Can't do this if region may have changed.  */
@@ -9447,11 +9788,13 @@ try_window_reusing_current_matrix (w)
       
       /* Display up to a row that can be reused.  The variable
         last_text_row is set to the last row displayed that displays
-        text.  */
+        text.  Note that it.vpos == 0 if or if not there is a
+         header-line; it's not the same as the MATRIX_ROW_VPOS!  */
       start_display (&it, w, new_start);
       first_row_y = it.current_y;
       w->cursor.vpos = -1;
       last_text_row = last_reused_text_row = NULL;
+      
       while (it.current_y < it.last_visible_y
             && IT_CHARPOS (it) < CHARPOS (start)
             && !fonts_changed_p)
@@ -9463,6 +9806,7 @@ try_window_reusing_current_matrix (w)
         have at least one reusable row.  */
       if (it.current_y < it.last_visible_y)
        {
+         /* IT.vpos always starts from 0; it counts text lines.  */
          nrows_scrolled = it.vpos;
          
          /* Find PT if not already found in the lines displayed.  */
@@ -9506,13 +9850,14 @@ try_window_reusing_current_matrix (w)
          run.current_y = first_row_y;
          run.desired_y = it.current_y;
          run.height = it.last_visible_y - it.current_y;
-         if (run.height > 0
-             && run.current_y != run.desired_y)
+
+         if (run.height > 0 && run.current_y != run.desired_y)
            {
              update_begin (f);
              rif->update_window_begin_hook (w);
+             rif->clear_mouse_face (w);
              rif->scroll_run_hook (w, &run);
-             rif->update_window_end_hook (w, 0);
+             rif->update_window_end_hook (w, 0, 0);
              update_end (f);
            }
 
@@ -9525,13 +9870,14 @@ try_window_reusing_current_matrix (w)
          
          /* Disable lines not reused.  */
          for (i = 0; i < it.vpos; ++i)
-           MATRIX_ROW (w->current_matrix, i)->enabled_p = 0;
+           (start_row + i)->enabled_p = 0;
          
          /* Re-compute Y positions.  */
-         row = MATRIX_FIRST_TEXT_ROW (w->current_matrix) + nrows_scrolled;
          min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
          max_y = it.last_visible_y;
-         while (row < bottom_row)
+         for (row = start_row + nrows_scrolled;
+              row < bottom_row;
+              ++row)
            {
              row->y = it.current_y;
 
@@ -9544,13 +9890,11 @@ try_window_reusing_current_matrix (w)
                row->visible_height = row->height;
              
              it.current_y += row->height;
-             ++it.vpos;
 
              if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
                last_reused_text_row = row;
              if (MATRIX_ROW_BOTTOM_Y (row) >= it.last_visible_y)
                break;
-             ++row;
            }
        }
 
@@ -9606,7 +9950,7 @@ try_window_reusing_current_matrix (w)
       
       /* Find the row starting at new_start, if there is one.  Don't
         reuse a partially visible line at the end.  */
-      first_reusable_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+      first_reusable_row = start_row;
       while (first_reusable_row->enabled_p
             && MATRIX_ROW_BOTTOM_Y (first_reusable_row) < yb
             && (MATRIX_ROW_START_CHARPOS (first_reusable_row)
@@ -9638,10 +9982,12 @@ try_window_reusing_current_matrix (w)
       /* Start displaying at the start of first_row_to_display.  */
       xassert (first_row_to_display->y < yb);
       init_to_row_start (&it, w, first_row_to_display);
-      nrows_scrolled = MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix);
+      nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix)
+                       - start_vpos);
       it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
                 - nrows_scrolled);
-      it.current_y = first_row_to_display->y - first_reusable_row->y;
+      it.current_y = (first_row_to_display->y - first_reusable_row->y
+                     + WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
 
       /* Display lines beginning with first_row_to_display in the
          desired matrix.  Set last_text_row to the last row displayed
@@ -9674,23 +10020,24 @@ try_window_reusing_current_matrix (w)
       run.current_y = first_reusable_row->y;
       run.desired_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
       run.height = it.last_visible_y - run.current_y;
+      dy = run.current_y - run.desired_y;
+      
       if (run.height)
        {
          struct frame *f = XFRAME (WINDOW_FRAME (w));
          update_begin (f);
          rif->update_window_begin_hook (w);
+         rif->clear_mouse_face (w);
          rif->scroll_run_hook (w, &run);
-         rif->update_window_end_hook (w, 0);
+         rif->update_window_end_hook (w, 0, 0);
          update_end (f);
        }
 
       /* Adjust Y positions of reused rows.  */
       bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
-      row = first_reusable_row;
-      dy = first_reusable_row->y;
       min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
       max_y = it.last_visible_y;
-      while (row < first_row_to_display)
+      for (row = first_reusable_row; row < first_row_to_display; ++row)
        {
          row->y -= dy;
          if (row->y < min_y)
@@ -9700,7 +10047,6 @@ try_window_reusing_current_matrix (w)
              = row->height - (row->y + row->height - max_y);
          else
            row->visible_height = row->height;
-         ++row;
        }
 
       /* Disable rows not reused.  */
@@ -10127,7 +10473,11 @@ try_window_id (w)
        = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
       w->window_end_bytepos
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
-      return 1;
+
+      row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+      row = row_containing_pos (w, PT, row, NULL);
+      set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+      return 2;
     }
 
   /* Check that window start agrees with the start of the first glyph
@@ -10294,8 +10644,8 @@ try_window_id (w)
          row = row_containing_pos (w, PT,
                                    MATRIX_FIRST_TEXT_ROW (w->current_matrix),
                                    last_unchanged_at_beg_row + 1);
-         xassert (row && row <= last_unchanged_at_beg_row);
-         set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+         if (row)
+           set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
        }
 
       /* Start from first_unchanged_at_end_row looking for PT.  */
@@ -10348,8 +10698,9 @@ try_window_id (w)
       if (FRAME_WINDOW_P (f))
        {
          rif->update_window_begin_hook (w);
+         rif->clear_mouse_face (w);
          rif->scroll_run_hook (w, &run);
-         rif->update_window_end_hook (w, 0);
+         rif->update_window_end_hook (w, 0, 0);
        }
       else
        {
@@ -10558,7 +10909,7 @@ try_window_id (w)
   /* Record that display has not been completed.  */
   w->window_end_valid = Qnil;
   w->desired_matrix->no_scrolling_p = 1;
-  return 1;
+  return 3;
 }
 
 
@@ -10576,7 +10927,7 @@ static void dump_glyph_matrix P_ ((struct glyph_matrix *, int));
 /* Dump the contents of glyph matrix MATRIX on stderr.  If
    WITH_GLYPHS_P is non-zero, dump glyph contents as well.  */
 
-void
+static void
 dump_glyph_matrix (matrix, with_glyphs_p)
      struct glyph_matrix *matrix;
      int with_glyphs_p;
@@ -10602,10 +10953,11 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
 
   row = MATRIX_ROW (matrix, vpos);
   
-  fprintf (stderr, "Row Start   End Used oEI><O\\CTZF    X   Y   W\n");
-  fprintf (stderr, "=============================================\n");
+  fprintf (stderr, "Row Start   End Used oEI><O\\CTZFes     X    Y    W    H    V    A    P\n");
+  fprintf (stderr, "=======================================================================\n");
   
-  fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d\n",
+  fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d\
+%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n",
           row - matrix->rows,
           MATRIX_ROW_START_CHARPOS (row),
           MATRIX_ROW_END_CHARPOS (row),
@@ -10621,9 +10973,15 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
           row->displays_text_p,
           row->ends_at_zv_p,
           row->fill_line_p,
+          row->ends_in_middle_of_char_p,
+          row->starts_in_middle_of_char_p,
           row->x,
           row->y,
-          row->pixel_width);
+          row->pixel_width,
+          row->height,
+          row->visible_height,
+          row->ascent,
+          row->phys_ascent);
   fprintf (stderr, "%9d %5d\n", row->start.overlay_string_index,
           row->end.overlay_string_index);
   fprintf (stderr, "%9d %5d\n",
@@ -10646,7 +11004,7 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
       
       if (glyph < glyph_end)
        {
-         fprintf (stderr, "  Glyph    Type Pos   W    Code C Face LR\n");
+         fprintf (stderr, "  Glyph    Type Pos   W    Code C Face LR\n");
          prev_had_glyphs_p = 1;
        }
       else
@@ -10657,10 +11015,15 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
          if (glyph->type == CHAR_GLYPH)
            {
              fprintf (stderr,
-                      "  %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+                      "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
                       glyph - row->glyphs[TEXT_AREA],
                       'C',
                       glyph->charpos,
+                      (BUFFERP (glyph->object)
+                       ? 'B'
+                       : (STRINGP (glyph->object)
+                          ? 'S'
+                          : '-')),
                       glyph->pixel_width,
                       glyph->u.ch,
                       (glyph->u.ch < 0x80 && glyph->u.ch >= ' '
@@ -10673,10 +11036,15 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
          else if (glyph->type == STRETCH_GLYPH)
            {
              fprintf (stderr,
-                      "  %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+                      "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
                       glyph - row->glyphs[TEXT_AREA],
                       'S',
                       glyph->charpos,
+                      (BUFFERP (glyph->object)
+                       ? 'B'
+                       : (STRINGP (glyph->object)
+                          ? 'S'
+                          : '-')),
                       glyph->pixel_width,
                       0,
                       '.',
@@ -10687,10 +11055,15 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
          else if (glyph->type == IMAGE_GLYPH)
            {
              fprintf (stderr,
-                      "  %5d %4c %6d %3d 0x%05x %c %4d %1.1d%1.1d\n",
+                      "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
                       glyph - row->glyphs[TEXT_AREA],
                       'I',
                       glyph->charpos,
+                      (BUFFERP (glyph->object)
+                       ? 'B'
+                       : (STRINGP (glyph->object)
+                          ? 'S'
+                          : '-')),
                       glyph->pixel_width,
                       glyph->u.img_id,
                       '.',
@@ -10936,7 +11309,7 @@ compute_line_metrics (it)
       /* If first line's physical ascent is larger than its logical
          ascent, use the physical ascent, and make the row taller.
          This makes accented characters fully visible.  */
-      if (row == it->w->desired_matrix->rows
+      if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
          && row->phys_ascent > row->ascent)
        {
          row->height += row->phys_ascent - row->ascent;
@@ -11219,6 +11592,8 @@ display_line (it)
   row->start = it->current;
   row->continuation_lines_width = it->continuation_lines_width;
   row->displays_text_p = 1;
+  row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
+  it->starts_in_middle_of_char_p = 0;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
      display_line on only one line at a time, in which case this
@@ -11247,8 +11622,8 @@ display_line (it)
     {
       int n_glyphs_before, hpos_before, x_before;
       int x, i, nglyphs;
-      int ascent, descent, phys_ascent, phys_descent;
-      
+      int ascent = 0, descent = 0, phys_ascent = 0, phys_descent = 0;
+
       /* Retrieve the next thing to display.  Value is zero if end of
         buffer reached.  */
       if (!get_next_display_element (it))
@@ -11362,6 +11737,31 @@ display_line (it)
                      if (i == nglyphs - 1)
                        set_iterator_to_next (it);
                    }
+                 else if (CHAR_GLYPH_PADDING_P (*glyph)
+                          && !FRAME_WINDOW_P (it->f))
+                   {
+                     /* A padding glyph that doesn't fit on this line.
+                        This means the whole character doesn't fit
+                        on the line.  */
+                     row->used[TEXT_AREA] = n_glyphs_before;
+                 
+                     /* Fill the rest of the row with continuation
+                        glyphs like in 20.x.  */
+                     while (row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]
+                            < row->glyphs[1 + TEXT_AREA])
+                       produce_special_glyphs (it, IT_CONTINUATION);
+                     
+                     row->continued_p = 1;
+                     it->current_x = x_before;
+                     it->continuation_lines_width += x_before;
+                     
+                     /* Restore the height to what it was before the
+                        element not fitting on the line.  */
+                     it->max_ascent = ascent;
+                     it->max_descent = descent;
+                     it->max_phys_ascent = phys_ascent;
+                     it->max_phys_descent = phys_descent;
+                   }
                  else
                    {
                      /* Display element draws past the right edge of
@@ -11378,6 +11778,11 @@ display_line (it)
                      
                      it->current_x = x;
                      it->continuation_lines_width += x;
+                     if (nglyphs > 1 && i > 0)
+                       {
+                         row->ends_in_middle_of_char_p = 1;
+                         it->starts_in_middle_of_char_p = 1;
+                       }
                      
                      /* Restore the height to what it was before the
                         element not fitting on the line.  */
@@ -11529,16 +11934,20 @@ display_line (it)
   /* Remember the position at which this line ends.  */
   row->end = it->current;
 
-  /* Maybe set the cursor.  If you change this, it's probably a good
-     idea to also change the code in redisplay_window for cursor
-     movement in an unchanged window.  */
+  /* Maybe set the cursor.  */
   if (it->w->cursor.vpos < 0
       && PT >= MATRIX_ROW_START_CHARPOS (row)
-      && MATRIX_ROW_END_CHARPOS (row) >= PT
-      && !(MATRIX_ROW_END_CHARPOS (row) == PT
-          && (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
-              || !row->ends_at_zv_p)))
-    set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
+      && PT <= MATRIX_ROW_END_CHARPOS (row))
+    {
+      /* Also see redisplay_window, case cursor movement in unchanged
+        window.  */
+      if (MATRIX_ROW_END_CHARPOS (row) == PT
+         && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
+         && !row->ends_at_zv_p)
+       ;
+      else
+       set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
+    }
 
   /* Highlight trailing whitespace.  */
   if (!NILP (Vshow_trailing_whitespace))
@@ -11665,23 +12074,106 @@ display_menu_bar (w)
                              Mode Line
  ***********************************************************************/
 
-/* Display the mode and/or top line of window W.  */
+/* Redisplay mode lines in the window tree whose root is WINDOW.  If
+   FORCE is non-zero, redisplay mode lines unconditionally.
+   Otherwise, redisplay only mode lines that are garbaged.  Value is
+   the number of windows whose mode lines were redisplayed.  */
 
-static void
+static int
+redisplay_mode_lines (window, force)
+     Lisp_Object window;
+     int force;
+{
+  int nwindows = 0;
+  
+  while (!NILP (window))
+    {
+      struct window *w = XWINDOW (window);
+      
+      if (WINDOWP (w->hchild))
+       nwindows += redisplay_mode_lines (w->hchild, force);
+      else if (WINDOWP (w->vchild))
+       nwindows += redisplay_mode_lines (w->vchild, force);
+      else if (force
+              || FRAME_GARBAGED_P (XFRAME (w->frame))
+              || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
+       {
+         Lisp_Object old_selected_frame;
+         struct text_pos lpoint;
+         struct buffer *old = current_buffer;
+
+         /* Set the window's buffer for the mode line display.  */
+         SET_TEXT_POS (lpoint, PT, PT_BYTE);
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+         
+         /* Point refers normally to the selected window.  For any
+            other window, set up appropriate value.  */
+         if (!EQ (window, selected_window))
+           {
+             struct text_pos pt;
+             
+             SET_TEXT_POS_FROM_MARKER (pt, w->pointm);
+             if (CHARPOS (pt) < BEGV)
+               TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+             else if (CHARPOS (pt) > (ZV - 1))
+               TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+             else
+               TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
+           }
+
+         /* Temporarily set up the selected frame.  */
+         old_selected_frame = selected_frame;
+         selected_frame = w->frame;
+
+         /* Display mode lines.  */
+         clear_glyph_matrix (w->desired_matrix);
+         if (display_mode_lines (w))
+           {
+             ++nwindows;
+             w->must_be_updated_p = 1;
+           }
+
+         /* Restore old settings.  */
+         selected_frame = old_selected_frame;
+         set_buffer_internal_1 (old);
+         TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+       }
+
+      window = w->next;
+    }
+
+  return nwindows;
+}
+
+
+/* Display the mode and/or top line of window W.  Value is the number
+   of mode lines displayed.  */
+
+static int
 display_mode_lines (w)
      struct window *w;
 {
+  int n = 0;
+  
   /* These will be set while the mode line specs are processed.  */
   line_number_displayed = 0;
   w->column_number_displayed = Qnil;
 
   if (WINDOW_WANTS_MODELINE_P (w))
-    display_mode_line (w, MODE_LINE_FACE_ID,
-                      current_buffer->mode_line_format);
+    {
+      display_mode_line (w, MODE_LINE_FACE_ID,
+                        current_buffer->mode_line_format);
+      ++n;
+    }
   
   if (WINDOW_WANTS_HEADER_LINE_P (w))
-    display_mode_line (w, HEADER_LINE_FACE_ID,
-                      current_buffer->header_line_format);
+    {
+      display_mode_line (w, HEADER_LINE_FACE_ID,
+                        current_buffer->header_line_format);
+      ++n;
+    }
+
+  return n;
 }
 
 
@@ -12065,6 +12557,7 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
   Lisp_Object eoltype;
 
   val = Fget (coding_system, Qcoding_system);
+  eoltype = Qnil;
 
   if (!VECTORP (val))          /* Not yet decided.  */
     {
@@ -12257,7 +12750,8 @@ decode_mode_spec (w, c, field_width, precision)
          w->base_line_pos = Qnil;
 
        /* If the buffer is very big, don't waste time.  */
-       if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
+       if (INTEGERP (Vline_number_display_limit)
+           && BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
          {
            w->base_line_pos = Qnil;
            w->base_line_number = Qnil;
@@ -12344,7 +12838,8 @@ decode_mode_spec (w, c, field_width, precision)
          while (pad-- > 0)
            *p++ = ' ';
          *p++ = '?';
-         *p = '?';
+         *p++ = '?';
+         *p = '\0';
          return decode_mode_spec_buf;
        }
       }
@@ -12794,6 +13289,7 @@ invisible_p (propval, list)
      Lisp_Object list;
 {
   register Lisp_Object tail, proptail;
+  
   for (tail = list; CONSP (tail); tail = XCDR (tail))
     {
       register Lisp_Object tem;
@@ -12803,22 +13299,25 @@ invisible_p (propval, list)
       if (CONSP (tem) && EQ (propval, XCAR (tem)))
        return 1;
     }
+  
   if (CONSP (propval))
-    for (proptail = propval; CONSP (proptail);
-        proptail = XCDR (proptail))
-      {
-       Lisp_Object propelt;
-       propelt = XCAR (proptail);
-       for (tail = list; CONSP (tail); tail = XCDR (tail))
-         {
-           register Lisp_Object tem;
-           tem = XCAR (tail);
-           if (EQ (propelt, tem))
-             return 1;
-           if (CONSP (tem) && EQ (propelt, XCAR (tem)))
-             return 1;
-         }
-      }
+    {
+      for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
+       {
+         Lisp_Object propelt;
+         propelt = XCAR (proptail);
+         for (tail = list; CONSP (tail); tail = XCDR (tail))
+           {
+             register Lisp_Object tem;
+             tem = XCAR (tail);
+             if (EQ (propelt, tem))
+               return 1;
+             if (CONSP (tem) && EQ (propelt, XCAR (tem)))
+               return 1;
+           }
+       }
+    }
+  
   return 0;
 }
 
@@ -12945,6 +13444,8 @@ syms_of_xdisp ()
   staticpro (&Qtrailing_whitespace);
   Qimage = intern ("image");
   staticpro (&Qimage);
+  Qmessage_truncate_lines = intern ("message-truncate-lines");
+  staticpro (&Qmessage_truncate_lines);
 
   last_arrow_position = Qnil;
   last_arrow_string = Qnil;
@@ -12959,6 +13460,9 @@ syms_of_xdisp ()
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
+  Vmessages_buffer_name = build_string ("*Messages*");
+  staticpro (&Vmessages_buffer_name);
+  
   DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
     "Non-nil means highlight trailing whitespace.\n\
 The face used for trailing whitespace is `trailing-whitespace'.");
@@ -13013,13 +13517,14 @@ of the top or bottom of the window.");
     "*Non-nil means use inverse video for the mode line.");
   mode_line_inverse_video = 1;
 
-  DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
+  DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit,
     "*Maximum buffer size for which line number should be displayed.\n\
 If the buffer is bigger than this, the line number does not appear\n\
-in the mode line.");
-  line_number_display_limit = 1000000;
+in the mode line.  A value of nil means no limit.");
+  Vline_number_display_limit = Qnil;
 
-  DEFVAR_INT ("line-number-display-limit-width", &line_number_display_limit_width,
+  DEFVAR_INT ("line-number-display-limit-width",
+             &line_number_display_limit_width,
     "*Maximum line width (in characters) for line number display.\n\
 If the average length of the lines near point is bigger than this, then the\n\
 line number may be omitted from the mode line.");
@@ -13134,9 +13639,19 @@ Nil means don't display a cursor there.");
   automatic_hscrolling_p = 1;
   
   DEFVAR_LISP ("image-types", &Vimage_types,
-     "List of supported image types.\n\
+    "List of supported image types.\n\
 Each element of the list is a symbol for a supported image type.");
   Vimage_types = Qnil;
+  
+  DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
+    "If non-nil, messages are truncated instead of resizing the echo area.\n\
+Bind this around calls to `message' to let it take effect.");
+  message_truncate_lines = 0;
+
+  DEFVAR_LISP ("menu-bar-update-hook",  &Vmenu_bar_update_hook,
+    "Normal hook run for clicks on menu bar, before displaying a submenu.\n\
+Can be used to update submenus whose contents should vary.");
+
 }