]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
*** empty log message ***
[gnu-emacs] / src / xdisp.c
index 28067a7ee51d381916f646118656303305926dcf..a82736ccd18dc83f2fadca054e882c70fb0d600c 100644 (file)
@@ -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"
@@ -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.  */
 
@@ -516,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.  */
 
@@ -613,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 *));
@@ -655,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));
@@ -670,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));
@@ -1859,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
@@ -4265,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)
@@ -4282,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)
@@ -4347,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;
                }
@@ -4423,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)
        {
@@ -4433,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
@@ -4479,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)
@@ -4504,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
@@ -4522,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);
@@ -4534,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:
@@ -4554,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));
 }
 
 
@@ -4603,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;
@@ -4657,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.  */
@@ -6232,32 +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, of course.
-            
-            Likewise if input is pending, because the pending input
-            can have interrupted a previous redisplay, or redisplay
-            wasn't called because of the pending input (see
-            keyboard.c).  In both cases, we would display the message
-            fine, but the rest of the display would be garbage.
-
-            Otherwise, we can do with updating just what we displayed
-            above.  */
+         int n = 0;
 
-         if (window_height_changed_p || detect_input_pending ())
+         /* 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)
            {
-             int count = specpdl_ptr - specpdl;
-             
-             specbind (Qredisplay_dont_pause, Qt);
-             ++windows_or_buffers_changed;
-             ++update_mode_lines;
+             /* Must update other windows.  */
+             windows_or_buffers_changed = 1;
              redisplay_internal (0);
-             unbind_to (count, Qnil);
            }
-         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);
            }
@@ -6749,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;
 
@@ -6758,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
@@ -6769,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))
@@ -6810,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
@@ -7455,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
@@ -7568,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)
@@ -7764,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)
@@ -7809,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)
     {
@@ -7831,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
@@ -7845,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;
@@ -7927,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
@@ -8006,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)
@@ -8511,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);
@@ -8522,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;
       
@@ -8706,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.  */
 
@@ -8726,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;
@@ -8886,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);
@@ -8983,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)
-       goto try_to_scroll;
-      row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
-      if (row->mode_line_p)
-       ++row;
-      if (!row->enabled_p)
+      if (rc == -1)
        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)
@@ -9615,7 +9745,6 @@ 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;
-
   
   if (/* This function doesn't handle terminal frames.  */
       !FRAME_WINDOW_P (f)
@@ -9659,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)
@@ -9675,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.  */
@@ -9718,8 +9850,8 @@ 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);
@@ -9738,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;
 
@@ -9757,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;
            }
        }
 
@@ -9819,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)
@@ -9851,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
@@ -9887,6 +10020,8 @@ 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));
@@ -9900,11 +10035,9 @@ try_window_reusing_current_matrix (w)
 
       /* 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)
@@ -9914,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.  */
@@ -10512,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.  */
@@ -10824,8 +10956,8 @@ dump_glyph_row (matrix, vpos, with_glyphs_p)
   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 %4d %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),
@@ -11490,7 +11622,7 @@ 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.  */
@@ -11942,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;
 }
 
 
@@ -12342,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.  */
     {
@@ -13073,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;
@@ -13082,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;
 }
 
@@ -13427,6 +13647,11 @@ Each element of the list is a symbol for a supported image type.");
     "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.");
+
 }