(handle_fontified_prop): While running fontification
[bpt/emacs.git] / src / xdisp.c
index ba2ae57..9d9815e 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"
@@ -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.  */
 
@@ -512,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.  */
 
@@ -609,6 +624,7 @@ 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 *));
@@ -630,16 +646,15 @@ static struct glyph_row *row_containing_pos P_ ((struct window *, int,
 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, EMACS_INT, EMACS_INT, EMACS_INT),
-                                     EMACS_INT, EMACS_INT, EMACS_INT,
-                                     EMACS_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_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_INT));
-static int truncate_message_1 P_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_INT));
-static int set_message_1 P_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_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_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_INT));
-static int resize_mini_window_1 P_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_INT));
+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,
@@ -652,6 +667,7 @@ 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));
@@ -667,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));
@@ -1487,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;
@@ -1799,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,
@@ -1846,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;
+
+         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);
+           }
 
-      /* Run the hook functions.  */
-      args[0] = Qfontification_functions;
-      args[1] = pos;
-      Frun_hook_with_args (2, args);
+         UNGCPRO;
+       }
+
+      unbind_to (count, Qnil);
 
       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
         something.  This avoids an endless loop if they failed to
@@ -4252,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)
@@ -4269,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)
@@ -4334,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;
                }
@@ -4410,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)
        {
@@ -4420,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
@@ -4466,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)
@@ -4491,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
@@ -4509,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);
@@ -4521,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:
@@ -4541,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));
 }
 
 
@@ -4590,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;
@@ -4644,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.  */
@@ -4891,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 ();
@@ -5438,9 +5550,17 @@ 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];
       }
 }
 
@@ -5465,8 +5585,10 @@ static int
 with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
      struct window *w;
      int which;
-     int (*fn) P_ ((EMACS_INT, EMACS_INT, EMACS_INT, EMACS_INT));
-     EMACS_INT a1, a2, a3, a4;
+     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;
@@ -5704,7 +5826,7 @@ display_echo_area (w)
   window_height_changed_p
     = with_echo_area_buffer (w, display_last_displayed_message_p,
                             display_echo_area_1,
-                            (EMACS_INT) w, 0, 0, 0);
+                            (EMACS_INT) w, Qnil, 0, 0);
 
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
@@ -5722,7 +5844,9 @@ display_echo_area (w)
 
 static int
 display_echo_area_1 (a1, a2, a3, a4)
-     EMACS_INT a1, a2, a3, a4;
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   struct window *w = (struct window *) a1;
   Lisp_Object window;
@@ -5756,7 +5880,7 @@ resize_echo_area_axactly ()
       int resized_p;
       
       resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
-                                        (EMACS_INT) w, 0, 0, 0);
+                                        (EMACS_INT) w, Qnil, 0, 0);
       if (resized_p)
        {
          ++windows_or_buffers_changed;
@@ -5774,7 +5898,9 @@ resize_echo_area_axactly ()
 
 static int
 resize_mini_window_1 (a1, a2, a3, a4)
-     EMACS_INT a1, a2, a3, a4;
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   return resize_mini_window ((struct window *) a1, 1);
 }
@@ -5886,7 +6012,7 @@ current_message ()
   else
     {
       with_echo_area_buffer (0, 0, current_message_1,
-                            (EMACS_INT) &msg, 0, 0, 0);
+                            (EMACS_INT) &msg, Qnil, 0, 0);
       if (NILP (msg))
        echo_area_buffer[0] = Qnil;
     }
@@ -5897,7 +6023,9 @@ current_message ()
 
 static int
 current_message_1 (a1, a2, a3, a4)
-     EMACS_INT a1, a2, a3, a4;
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   Lisp_Object *msg = (Lisp_Object *) a1;
   
@@ -5980,7 +6108,7 @@ truncate_echo_area (nchars)
     {
       struct frame *sf = SELECTED_FRAME ();
       if (FRAME_MESSAGE_BUF (sf))
-       with_echo_area_buffer (0, 0, truncate_message_1, nchars, 0, 0, 0);
+       with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
     }
 }
 
@@ -5990,7 +6118,9 @@ truncate_echo_area (nchars)
 
 static int
 truncate_message_1 (nchars, a2, a3, a4)
-     EMACS_INT nchars, a2, a3, a4;
+     EMACS_INT nchars;
+     Lisp_Object a2;
+     EMACS_INT a3, a4;
 {
   if (BEG + nchars < Z)
     del_range (BEG + nchars, Z);
@@ -6033,10 +6163,12 @@ set_message (s, string, nbytes, multibyte_p)
 
 static int
 set_message_1 (a1, a2, nbytes, multibyte_p)
-     EMACS_INT a1, a2, nbytes, multibyte_p;
+     EMACS_INT a1;
+     Lisp_Object a2;
+     EMACS_INT nbytes, multibyte_p;
 {
   char *s = (char *) a1;
-  Lisp_Object string = (Lisp_Object) a2;
+  Lisp_Object string = a2;
   
   xassert (BEG == Z);
   
@@ -6199,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);
            }
@@ -7410,7 +7552,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
@@ -7523,7 +7665,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)
@@ -7719,7 +7861,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)
@@ -7764,9 +7906,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)
     {
@@ -7786,6 +7928,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
@@ -7800,81 +7943,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;
+      /* 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 ();
 
-         f = XFRAME (XCAR (tail));
-
-         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;
@@ -7882,29 +8004,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
@@ -7961,7 +8076,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)
@@ -8330,6 +8446,7 @@ make_cursor_line_fully_visible (w)
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
+  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.  */
@@ -8339,31 +8456,32 @@ make_cursor_line_fully_visible (w)
   matrix = w->desired_matrix;
   row = MATRIX_ROW (matrix, w->cursor.vpos);
 
-  if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row)
-      /* The row may be partially visible at the top because we
-        already have chosen a vscroll to align the bottom of the
-        row with the bottom of the window.  This happens for rows
-        taller than the window.  */
-      && row->y + row->height < window_box_height (w))
+  /* If the cursor row is not partially visible, there's nothing
+     to do.  */
+  if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+    return;
+
+  /* If the row the cursor is in is taller than the window's height,
+     it's not clear what to do, so do nothing.  */
+  window_height = window_box_height (w);
+  if (row->height >= window_height)
+    return;
+
+  if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
     {
       int dy = row->height - row->visible_height;
       w->vscroll = 0;
       w->cursor.y += dy;
       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
     }
-  else if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)
-          /* The row may be partially visible at the bottom because
-             we chose a vscroll to align the row's top with the
-             window's top.  This happens for rows taller than the
-             window.  */
-          && row->y > WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w))
+  else /* MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)) */
     {
       int dy = - (row->height - row->visible_height);
       w->vscroll = dy;
       w->cursor.y += dy;
       shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
     }
-
+  
   /* When we change the cursor y-position of the selected window,
      change this_line_y as well so that the display optimization for
      the cursor line of the selected window in redisplay_internal uses
@@ -8464,7 +8582,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);
@@ -8475,6 +8593,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;
       
@@ -8659,6 +8778,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.  */
 
@@ -8679,6 +9011,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;
@@ -8839,7 +9172,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);
@@ -8894,13 +9226,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),
@@ -8934,170 +9268,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)
-       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))
+      if (rc == -1)
        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)
@@ -10463,8 +10641,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.  */
@@ -10772,10 +10950,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),
@@ -10795,7 +10974,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",
@@ -11123,7 +11306,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;
@@ -11436,8 +11619,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))
@@ -11888,23 +12071,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;
 }
 
 
@@ -12288,6 +12554,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.  */
     {
@@ -13019,6 +13286,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;
@@ -13028,22 +13296,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;
 }
 
@@ -13186,6 +13457,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'.");