]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
*** empty log message ***
[gnu-emacs] / src / xdisp.c
index 7788649e977041c2cb5047d95772f876d0f05c63..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,7 +183,6 @@ 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"
@@ -201,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
 
@@ -357,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.  */
 
@@ -453,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.  */
 
@@ -480,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.  */
@@ -506,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.  */
 
@@ -603,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));
@@ -643,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));
@@ -1043,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)
@@ -1056,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);
 }
 
@@ -1437,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;
@@ -1590,6 +1666,7 @@ handle_stop (it)
 
   it->dpvec = NULL;
   it->current.dpvec_index = -1;
+  it->add_overlay_start = 0;
 
   do
     {
@@ -1599,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)
@@ -1748,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,
@@ -1795,16 +1872,56 @@ 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;
 
-      /* Run the hook functions.  */
-      args[0] = Qfontification_functions;
-      args[1] = pos;
-      Frun_hook_with_args (2, args);
+         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;
+       }
+
+      unbind_to (count, Qnil);
 
       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
         something.  This avoids an endless loop if they failed to
@@ -2108,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.  */
@@ -2268,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);
@@ -2298,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
@@ -2366,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))
            {
@@ -2555,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
@@ -2623,6 +2809,7 @@ handle_composition_prop (it)
 
 struct overlay_entry
 {
+  Lisp_Object overlay;
   Lisp_Object string;
   int priority;
   int after_string_p;
@@ -2636,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;
 }
 
 
@@ -2671,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
     {
@@ -2700,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.
@@ -2720,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;
@@ -2743,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
@@ -2781,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));
@@ -2804,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.  */
@@ -2813,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);
@@ -2826,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));
@@ -2840,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.  */
@@ -2849,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);
@@ -2864,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;
@@ -2876,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);
 }
 
@@ -3673,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
@@ -4110,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)
@@ -4127,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)
@@ -4192,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;
                }
@@ -4268,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)
        {
@@ -4278,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
@@ -4324,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)
@@ -4349,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
@@ -4367,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);
@@ -4379,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:
@@ -4399,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));
 }
 
 
@@ -4448,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;
@@ -4502,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.  */
@@ -4535,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;
     }
 
@@ -4749,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 ();
@@ -5296,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
@@ -5319,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;
@@ -5379,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;
 
@@ -5389,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);
@@ -5513,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
@@ -5559,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;
@@ -5570,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;
@@ -5608,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;
@@ -5621,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
@@ -5665,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)
@@ -5720,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;
     }
@@ -5730,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
@@ -5812,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);
     }
 }
 
@@ -5821,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);
@@ -5852,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.  */
@@ -5875,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);
 
@@ -6027,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);
            }
@@ -6532,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;
 
@@ -6541,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
@@ -6552,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))
@@ -6593,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
@@ -7238,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
@@ -7351,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)
@@ -7547,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)
@@ -7592,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)
     {
@@ -7614,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
@@ -7628,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;
@@ -7710,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
@@ -7789,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)
@@ -8158,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.  */
@@ -8168,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))
-    {
-      int dy = row->height - row->visible_height;
+  /* 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
@@ -8293,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);
@@ -8304,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;
       
@@ -8488,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,6 +9012,7 @@ redisplay_window (window, just_this_one_p)
   int current_matrix_up_to_date_p = 0;
   int temp_scroll_step = 0;
   int count = specpdl_ptr - specpdl;
+  int rc;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -8668,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);
@@ -8723,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),
@@ -8763,170 +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
-                && 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 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)
@@ -8971,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.  */
     }
@@ -9394,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.  */
@@ -9434,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)
@@ -9450,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.  */
@@ -9493,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);
            }
 
@@ -9512,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;
 
@@ -9531,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;
            }
        }
 
@@ -9593,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)
@@ -9625,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
@@ -9661,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)
@@ -9687,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.  */
@@ -10114,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
@@ -10281,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.  */
@@ -10335,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
        {
@@ -10545,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;
 }
 
 
@@ -10563,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;
@@ -10589,10 +10953,11 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
 
   row = MATRIX_ROW (matrix, vpos);
   
-  fprintf (stderr, "Row Start   End Used oEI><O\\CTZFes    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%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),
@@ -10612,7 +10977,11 @@ dump_glyph_row (matrix, vpos, with_glyphs_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",
@@ -10635,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
@@ -10646,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 >= ' '
@@ -10662,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,
                       '.',
@@ -10676,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,
                       '.',
@@ -10925,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;
@@ -11238,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))
@@ -11690,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;
 }
 
 
@@ -12090,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.  */
     {
@@ -12282,7 +12750,7 @@ decode_mode_spec (w, c, field_width, precision)
          w->base_line_pos = Qnil;
 
        /* If the buffer is very big, don't waste time.  */
-       if (!INTEGERP (Vline_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;
@@ -12370,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;
        }
       }
@@ -12820,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;
@@ -12829,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;
 }
 
@@ -12971,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;
@@ -12985,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'.");
@@ -13161,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.");
+
 }