]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(prepare_menu_bars): Clear size-change flag before running
[gnu-emacs] / src / xdisp.c
index a4ff8d25fc6a4bc605f80f0d7ea04a6cdd13c5c2..3e25cdd35db1bae32de16ed6a5605c450084f0f7 100644 (file)
@@ -125,7 +125,7 @@ static int highlight_nonselected_windows;
 
 /* If cursor motion alone moves point off frame,
    Try scrolling this many lines up or down if that will bring it back.  */
-int scroll_step;
+static int scroll_step;
 
 /* Nonzero if try_window_id has made blank lines at window bottom
  since the last redisplay that paused */
@@ -143,11 +143,12 @@ int buffer_shared;
 static int cursor_vpos;
 static int cursor_hpos;
 
-int debug_end_pos;
+static int debug_end_pos;
 
 /* Nonzero means display mode line highlighted */
 int mode_line_inverse_video;
 
+static int message_log_check_duplicate ();
 static void echo_area_display ();
 void mark_window_display_accurate ();
 static void redisplay_windows ();
@@ -211,7 +212,7 @@ int windows_or_buffers_changed;
 int line_number_displayed;
 
 /* Maximum buffer size for which to display line numbers.  */
-int line_number_display_limit;
+static int line_number_display_limit;
 
 /* Number of lines to keep in the message log buffer.
    t means infinite.  nil means don't log at all.  */
@@ -241,6 +242,7 @@ message_dolog (m, len, nlflag)
 
       oldbuf = current_buffer;
       Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
+      current_buffer->undo_list = Qt;
       oldpoint = PT;
       oldbegv = BEGV;
       oldzv = ZV;
@@ -254,15 +256,52 @@ message_dolog (m, len, nlflag)
       if (len)
        insert_1 (m, len, 1, 0);
       if (nlflag)
-       insert_1 ("\n", 1, 1, 0);
-      if (NATNUMP (Vmessage_log_max))
        {
-         int pos = scan_buffer ('\n', PT, 0,
-                                -XFASTINT (Vmessage_log_max) - 1, 0, 1);
-         oldpoint -= min (pos, oldpoint) - BEG;
-         oldbegv -= min (pos, oldbegv) - BEG;
-         oldzv -= min (pos, oldzv) - BEG;
-         del_range_1 (BEG, pos, 0);
+         int this_bol, prev_bol, dup;
+         insert_1 ("\n", 1, 1, 0);
+
+         this_bol = scan_buffer ('\n', Z, 0, -2, 0, 0);
+         if (this_bol > BEG)
+           {
+             prev_bol = scan_buffer ('\n', this_bol, 0, -2, 0, 0);
+             dup = message_log_check_duplicate (prev_bol, this_bol);
+             if (dup)
+               {
+                 if (oldpoint > prev_bol)
+                   oldpoint -= min (this_bol, oldpoint) - prev_bol;
+                 if (oldbegv > prev_bol)
+                   oldbegv -= min (this_bol, oldbegv) - prev_bol;
+                 if (oldzv > prev_bol)
+                   oldzv -= min (this_bol, oldzv) - prev_bol;
+                 del_range_1 (prev_bol, this_bol, 0);
+                 if (dup > 1)
+                   {
+                     char dupstr[40];
+                     int duplen;
+
+                     /* If you change this format, don't forget to also
+                        change message_log_check_duplicate.  */
+                     sprintf (dupstr, " [%d times]", dup);
+                     duplen = strlen (dupstr);
+                     TEMP_SET_PT (Z-1);
+                     if (oldpoint == Z)
+                       oldpoint += duplen;
+                     if (oldzv == Z)
+                       oldzv += duplen;
+                     insert_1 (dupstr, duplen, 1, 0);
+                   }
+               }
+           }
+
+         if (NATNUMP (Vmessage_log_max))
+           {
+             int pos = scan_buffer ('\n', Z, 0,
+                                    -XFASTINT (Vmessage_log_max) - 1, 0, 0);
+             oldpoint -= min (pos, oldpoint) - BEG;
+             oldbegv -= min (pos, oldbegv) - BEG;
+             oldzv -= min (pos, oldzv) - BEG;
+             del_range_1 (BEG, pos, 0);
+           }
        }
       BEGV = oldbegv;
       ZV = oldzv;
@@ -273,6 +312,44 @@ message_dolog (m, len, nlflag)
 }
 
 
+/* We are at the end of the buffer after just having inserted a newline.
+   (Note: We depend on the fact we won't be crossing the gap.)
+   Check to see if the most recent message looks a lot like the previous one.
+   Return 0 if different, 1 if the new one should just replace it, or a
+   value N > 1 if we should also append " [N times]".  */
+
+static int
+message_log_check_duplicate (prev_bol, this_bol)
+     int prev_bol, this_bol;
+{
+  int i;
+  int len = Z - 1 - this_bol;
+  int seen_dots = 0;
+  unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
+  unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
+
+  for (i = 0; i < len; i++)
+    {
+      if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.'
+         && p1[i] != '\n')
+       seen_dots = 1;
+      if (p1[i] != p2[i])
+       return seen_dots;
+    }
+  p1 += len;
+  if (*p1 == '\n')
+    return 2;
+  if (*p1++ == ' ' && *p1++ == '[')
+    {
+      int n = 0;
+      while (*p1 >= '0' && *p1 <= '9')
+       n = n * 10 + *p1++ - '0';
+      if (strncmp (p1, " times]\n", 8) == 0)
+       return n+1;
+    }
+  return 0;
+}
+
 /* Display an echo area message M with a specified length of LEN chars.
    The string may include null characters.  If m is 0, clear out any
    existing message, and let the minibuffer text show through.
@@ -440,6 +517,19 @@ message (m, a1, a2, a3)
     }
 }
 
+/* The non-logging version of that function.  */
+void
+message_nolog (m, a1, a2, a3)
+     char *m;
+     EMACS_INT a1, a2, a3;
+{
+  Lisp_Object old_log_max;
+  old_log_max = Vmessage_log_max;
+  Vmessage_log_max = Qnil;
+  message (m, a1, a2, a3);
+  Vmessage_log_max = old_log_max;
+}
+
 void
 update_echo_area ()
 {
@@ -477,6 +567,8 @@ echo_area_display ()
                      0, 0, 0, 0, FRAME_WIDTH (f));
 
       /* If desired cursor location is on this line, put it at end of text */
+      if (cursor_in_echo_area)
+       FRAME_CURSOR_Y (f) = vpos;
       if (FRAME_CURSOR_Y (f) == vpos)
        FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
 
@@ -557,7 +649,7 @@ x_consider_frame_title (frame)
 #endif
 \f
 /* Prepare for redisplay by updating menu-bar item lists when appropriate.
-   This can't be done in `redisplay' itself because it can call eval.  */
+   This can call eval.  */
 
 void
 prepare_menu_bars ()
@@ -566,44 +658,9 @@ prepare_menu_bars ()
   int all_windows;
   struct gcpro gcpro1, gcpro2;
 
-  if (noninteractive)
-    return;
-
-  /* Set the visible flags for all frames.
-     Do this before checking for resized or garbaged frames; they want
-     to know if their frames are visible.
-     See the comment in frame.h for FRAME_SAMPLE_VISIBILITY.  */
-  {
-    Lisp_Object tail, frame;
-
-    FOR_EACH_FRAME (tail, frame)
-      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
-  }
-
-  /* Notice any pending interrupt request to change frame size.  */
-  do_pending_window_change ();
-
-  if (frame_garbaged)
-    {
-      redraw_garbaged_frames ();
-      frame_garbaged = 0;
-    }
-
   all_windows = (update_mode_lines || buffer_shared > 1
                 || clip_changed || windows_or_buffers_changed);
 
-#ifdef HAVE_X_WINDOWS
-  if (windows_or_buffers_changed)
-    {
-      Lisp_Object tail, frame;
-
-      FOR_EACH_FRAME (tail, frame)
-       if (FRAME_VISIBLE_P (XFRAME (frame))
-           || FRAME_ICONIFIED_P (XFRAME (frame)))
-         x_consider_frame_title (frame);
-    }
-#endif
-
   /* Update the menu bar item lists, if appropriate.
      This has to be done before any actual redisplay
      or generation of display lines.  */
@@ -618,6 +675,8 @@ prepare_menu_bars ()
          if (FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)))
            {
              Lisp_Object functions;
+             /* Clear flag first in case we get error below.  */
+             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
              functions = Vwindow_size_change_functions;
              GCPRO2 (tail, functions);
              while (CONSP (functions))
@@ -626,7 +685,6 @@ prepare_menu_bars ()
                  functions = XCONS (functions)->cdr;
                }
              UNGCPRO;
-             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
            }
          GCPRO1 (tail);
          update_menu_bar (XFRAME (frame));
@@ -635,6 +693,22 @@ prepare_menu_bars ()
     }
   else
     update_menu_bar (selected_frame);
+
+  /* Update all frame titles based on their buffer names, etc.
+     We do this after the menu bars so that the frame will first
+     create its menu bar using the name `emacs' if no other name
+     has yet been specified.  */
+#ifdef HAVE_X_WINDOWS
+  if (windows_or_buffers_changed)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+       if (FRAME_VISIBLE_P (XFRAME (frame))
+           || FRAME_ICONIFIED_P (XFRAME (frame)))
+         x_consider_frame_title (frame);
+    }
+#endif
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -670,7 +744,6 @@ redisplay ()
   int all_windows;
   register int tlbufpos, tlendpos;
   struct position pos;
-  extern int input_pending;
 
   if (noninteractive)
     return;
@@ -683,7 +756,13 @@ redisplay ()
     Lisp_Object tail, frame;
 
     FOR_EACH_FRAME (tail, frame)
-      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+      {
+       FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+
+       /* Clear out all the display lines in which we will generate the
+          glyphs to display.  */
+       init_desired_glyphs (XFRAME (frame));
+      }
   }
 
   /* Notice any pending interrupt request to change frame size.  */
@@ -695,6 +774,8 @@ redisplay ()
       frame_garbaged = 0;
     }
 
+  prepare_menu_bars ();
+
   if (clip_changed || windows_or_buffers_changed
       || (!NILP (w->column_number_displayed)
          && XFASTINT (w->column_number_displayed) != current_column ()))
@@ -789,7 +870,6 @@ redisplay ()
                  int left = XFASTINT (w->left);
                  int *charstart_next_line
                    = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
-                 int i;
                  int adjust;
 
                  if (Z - tlendpos == ZV)
@@ -821,10 +901,12 @@ redisplay ()
            }
          goto update;
        }
-      /* If highlighting the region, we can't just move the cursor.  */
+      /* If highlighting the region, or if the cursor is in the echo area,
+        then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && NILP (w->region_showing))
+              && NILP (w->region_showing)
+              && !cursor_in_echo_area)
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
@@ -873,19 +955,22 @@ redisplay ()
       FOR_EACH_FRAME (tail, frame)
        {
          FRAME_PTR f = XFRAME (frame);
+         if (! FRAME_TERMCAP_P (f) || f == selected_frame)
+           {
 
-         /* Mark all the scroll bars to be removed; we'll redeem the ones
-            we want when we redisplay their windows.  */
-         if (condemn_scroll_bars_hook)
-           (*condemn_scroll_bars_hook) (f);
+             /* Mark all the scroll bars to be removed; we'll redeem the ones
+                we want when we redisplay their windows.  */
+             if (condemn_scroll_bars_hook)
+               (*condemn_scroll_bars_hook) (f);
 
-         if (FRAME_VISIBLE_P (f))
-           redisplay_windows (FRAME_ROOT_WINDOW (f));
+             if (FRAME_VISIBLE_P (f))
+               redisplay_windows (FRAME_ROOT_WINDOW (f));
 
-         /* Any scroll bars which redisplay_windows should have nuked
-            should now go away.  */
-         if (judge_scroll_bars_hook)
-           (*judge_scroll_bars_hook) (f);
+             /* Any scroll bars which redisplay_windows should have nuked
+                should now go away.  */
+             if (judge_scroll_bars_hook)
+               (*judge_scroll_bars_hook) (f);
+           }
        }
     }
   else if (FRAME_VISIBLE_P (selected_frame))
@@ -918,7 +1003,9 @@ update:
            continue;
 
          f = XFRAME (XCONS (tail)->car);
-         if (FRAME_VISIBLE_P (f))
+
+         if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
+             && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
              if (!pause)
@@ -935,6 +1022,8 @@ update:
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
+      else
+       pause = 0;
 
       /* We may have called echo_area_display at the top of this
         function.  If the echo area is on another frame, that may
@@ -1170,7 +1259,7 @@ redisplay_window (window, just_this_one)
   struct position pos;
   int opoint = PT;
   int tem;
-  int window_needs_modeline;
+  int update_mode_line;
 
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
@@ -1190,6 +1279,7 @@ redisplay_window (window, just_this_one)
     abort ();
   
   height = window_internal_height (w);
+  update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
 
   if (MINI_WINDOW_P (w))
     {
@@ -1216,12 +1306,13 @@ redisplay_window (window, just_this_one)
        }
     }
 
-  if (update_mode_lines)
-    w->update_mode_line = Qt;
-
   /* Otherwise set up data on this window; select its buffer and point value */
 
-  set_buffer_temp (XBUFFER (w->buffer));
+  if (update_mode_line)
+    set_buffer_internal (XBUFFER (w->buffer));
+  else
+    set_buffer_temp (XBUFFER (w->buffer));
+
   opoint = PT;
 
   /* Count number of windows showing the selected buffer.
@@ -1291,7 +1382,14 @@ redisplay_window (window, just_this_one)
     {
       /* Forget any recorded base line for line number display.  */
       w->base_line_number = Qnil;
-      w->update_mode_line = Qt;
+      /* Redisplay the mode line.  Select the buffer properly for that.  */
+      if (!update_mode_line)
+       {
+         set_buffer_temp (old);
+         set_buffer_internal (XBUFFER (w->buffer));
+         update_mode_line = 1;
+         w->update_mode_line = Qt;
+       }
       w->force_start = Qnil;
       XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
@@ -1343,6 +1441,10 @@ redisplay_window (window, just_this_one)
   if (XFASTINT (w->last_modified) >= MODIFF
       && PT >= startp && !clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      /* If force-mode-line-update was called, really redisplay;
+        that's how redisplay is forced after e.g. changing
+        buffer-invisibility-spec.  */
+      && NILP (w->update_mode_line)
       /* Can't use this case if highlighting a region.  */
       && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
       && NILP (w->region_showing)
@@ -1352,7 +1454,7 @@ redisplay_window (window, just_this_one)
       && !EQ (window, minibuf_window))
     {
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
-                           PT, height + 1, 10000, width, hscroll,
+                           PT, height0, width, hscroll,
                            pos_tab_offset (w, startp), w);
 
       if (pos.vpos < height)
@@ -1429,7 +1531,14 @@ redisplay_window (window, just_this_one)
     }
 
   XSETFASTINT (w->last_modified, 0);
-  w->update_mode_line = Qt;
+  /* Redisplay the mode line.  Select the buffer properly for that.  */
+  if (!update_mode_line)
+    {
+      set_buffer_temp (old);
+      set_buffer_internal (XBUFFER (w->buffer));
+      update_mode_line = 1;
+      w->update_mode_line = Qt;
+    }
 
   /* Try to scroll by specified few lines */
 
@@ -1443,7 +1552,8 @@ redisplay_window (window, just_this_one)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
+      pos = *vmotion (startp,
+                     (PT < startp ? - scroll_step : scroll_step),
                      width, hscroll, window);
 
       if (PT >= pos.bufpos)
@@ -1476,7 +1586,7 @@ recenter:
     = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
-  if ((!NILP (w->update_mode_line)
+  if ((update_mode_line
        /* If window not full width, must redo its mode line
          if the window to its side is being redone */
        || (!just_this_one && width < FRAME_WIDTH (f) - 1)
@@ -1493,7 +1603,7 @@ done:
     }
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
-  if (!NILP (w->update_mode_line)
+  if (update_mode_line
 #ifdef USE_X_TOOLKIT
       && FRAME_EXTERNAL_MENU_BAR (f) 
 #else
@@ -1518,7 +1628,7 @@ done:
          || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
        {
          whole = ZV - BEGV;
-         start = startp - BEGV;
+         start = marker_position (w->start) - BEGV;
          /* I don't think this is guaranteed to be right.  For the
             moment, we'll pretend it is.  */
          end = (Z - XINT (w->window_end_pos)) - BEGV;
@@ -1538,7 +1648,10 @@ done:
     }
 
   BUF_PT (current_buffer) = opoint;
-  set_buffer_temp (old);
+  if (update_mode_line)
+    set_buffer_internal (old);
+  else
+    set_buffer_temp (old);
   BUF_PT (current_buffer) = lpoint;
 }
 \f
@@ -1578,15 +1691,19 @@ try_window (window, pos)
       if (val.vpos) tab_offset = 0;
       vpos++;
       if (pos != val.bufpos)
-       last_text_vpos
-         /* Next line, unless prev line ended in end of buffer with no cr */
-         = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n'
+       {
+         int invis = 0;
 #ifdef USE_TEXT_PROPERTIES
-                                || ! NILP (Fget_char_property (val.bufpos-1,
-                                                               Qinvisible,
-                                                               window))
+         Lisp_Object invis_prop;
+         invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
+         invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
 #endif
-                                ));
+
+         last_text_vpos
+           /* Next line, unless prev line ended in end of buffer with no cr */
+           = vpos - (val.vpos
+                     && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
+       }
       pos = val.bufpos;
     }
 
@@ -1650,11 +1767,11 @@ try_window_id (window)
 
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin,
-                       min (ZV, beg_unchanged + BEG), height + 1, 0,
+                       min (ZV, beg_unchanged + BEG), height, 0,
                        width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
-      if (PT < bp.bufpos && !bp.contin)
+      if (PT < bp.bufpos)
        {
          /* All changes are below the frame, and point is on the frame.
             We don't need to change the frame at all.
@@ -1665,7 +1782,7 @@ try_window_id (window)
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
-         return 1;
+         goto findpoint;
        }
       return 0;
     }
@@ -1972,6 +2089,7 @@ try_window_id (window)
   /* If point was not in a line that was displayed, find it */
   if (cursor_vpos < 0)
     {
+    findpoint:
       val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
@@ -2196,6 +2314,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   struct position val;
   int lastpos;
   int invis;
+  int last_invis_skip = 0;
+  Lisp_Object last_invis_prop;
   int hscroll = XINT (w->hscroll);
   int truncate = (hscroll
                  || (truncate_partial_width_windows
@@ -2214,13 +2334,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register struct Lisp_Vector *dp = window_display_table (w);
 
   Lisp_Object default_invis_vector[3];
-  /* Nonzero means display something where there are invisible lines.
-     The precise value is the number of glyphs to display.  */
+  /* Number of characters of ellipsis to display after an invisible line
+     if it calls for an ellipsis.
+     Note that this value can be nonzero regardless of whether
+     selective display is enabled--you must check that separately.  */
   int selective_rlen
-    = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
+    = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
        ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
-       : selective && !NILP (current_buffer->selective_display_ellipses)
-       ? 3 : 0);
+       : !NILP (current_buffer->selective_display_ellipses) ? 3 : 0);
   /* This is the sequence of Lisp objects to display
      when there are invisible lines.  */
   Lisp_Object *invis_vector_contents
@@ -2394,12 +2515,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (XFASTINT (limit) > pos + 50)
                XSETFASTINT (limit, pos + 50);
              endpos = Fnext_single_property_change (position, Qinvisible,
-                                               Fcurrent_buffer (), limit);
+                                                    Fcurrent_buffer (),
+                                                    limit);
              if (INTEGERP (endpos))
                next_invisible = XINT (endpos);
              else
                next_invisible = end;
-             if (! NILP (prop))
+             if (TEXT_PROP_MEANS_INVISIBLE (prop))
                {
                  if (pos < PT && next_invisible >= PT)
                    {
@@ -2407,6 +2529,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
                      cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_invisible;
+                 last_invis_skip = pos;
+                 last_invis_prop = prop;
                }
            }
          if (pos >= end)
@@ -2442,8 +2566,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
          p = &FETCH_CHAR (pos);
        }
       c = *p++;
-      if (c >= 040 && c < 0177
-         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
+      /* Let a display table override all standard display methods.  */
+      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+       {
+         p1 = copy_part_of_rope (f, p1, leftmargin,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+                                 current_face);
+       }
+      else if (c >= 040 && c < 0177)
        {
          if (p1 >= leftmargin)
            *p1 = MAKE_GLYPH (f, c, current_face);
@@ -2452,6 +2583,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c == '\n')
        {
          invis = 0;
+         if (last_invis_skip == pos
+             && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
+           invis = 1;
          while (pos + 1 < end
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
@@ -2519,13 +2653,6 @@ display_text_line (w, start, vpos, hpos, taboffset)
 #endif
          break;
        }
-      else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-       {
-         p1 = copy_part_of_rope (f, p1, leftmargin,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 current_face);
-       }
       else if (c < 0200 && ctl_arrow)
        {
          if (p1 >= leftmargin)
@@ -2680,8 +2807,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
       cursor_hpos += XFASTINT (w->left);
       if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
        {
-         FRAME_CURSOR_Y (f) = cursor_vpos;
-         FRAME_CURSOR_X (f) = cursor_hpos;
+         if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
+               && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
+           {
+             FRAME_CURSOR_Y (f) = cursor_vpos;
+             FRAME_CURSOR_X (f) = cursor_hpos;
+           }
 
          if (w == XWINDOW (selected_window))
            {
@@ -2817,10 +2948,10 @@ display_menu_bar (w)
                               XSTRING (string)->data,
                               XSTRING (string)->size,
                               hpos, 0, 0, hpos, maxendcol);
-      /* Put a gap of 3 spaces between items.  */
+      /* Put a space between items.  */
       if (hpos < maxendcol)
        {
-         int hpos1 = hpos + 3;
+         int hpos1 = hpos + 1;
          hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
                                 min (hpos1, maxendcol), maxendcol);
        }
@@ -2855,8 +2986,17 @@ display_mode_line (w)
   w->column_number_displayed = Qnil;
 
   get_display_line (f, vpos, left);
+
+  /* Temporarily make frame F's kboard the current kboard
+     so that kboard-local variables in the mode_line_format
+     will get the right values.  */
+  push_frame_kboard (f);
+
   display_mode_element (w, vpos, left, 0, right, right,
                        current_buffer->mode_line_format);
+
+  pop_frame_kboard ();
+
   FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
 
   /* Make the mode line inverse video if the entire line
@@ -2869,7 +3009,7 @@ display_mode_line (w)
       || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
     FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
 #ifdef HAVE_FACES
-  else if (! FRAME_TERMCAP_P (f))
+  else if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
     {
       /* For a partial width window, explicitly set face of each glyph. */
       int i;
@@ -3127,6 +3267,74 @@ decode_mode_spec (w, c, maxwidth)
 
   switch (c)
     {
+    case '*':
+      if (!NILP (b->read_only))
+       return "%";
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '+':
+      /* This differs from %* only for a modified read-only buffer.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      if (!NILP (b->read_only))
+       return "%";
+      return "-";
+
+    case '&':
+      /* This differs from %* in ignoring read-only-ness.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '%':
+      return "%";
+
+    case '[': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return "[[[... ";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = '[';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case ']': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return " ...]]]";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = ']';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case '-':
+      {
+       register char *p;
+       register int i;
+       
+       if (maxwidth < sizeof (lots_of_dashes))
+         return lots_of_dashes;
+       else
+         {
+           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
+             *p++ = '-';
+           *p = '\0';
+         }
+       return decode_mode_spec_buf;
+      }
+
     case 'b': 
       obj = b->name;
 #if 0
@@ -3140,6 +3348,18 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
+    case 'c':
+      {
+       int col = current_column ();
+       XSETFASTINT (w->column_number_displayed, col);
+       sprintf (decode_mode_spec_buf, "%d", col);
+       return decode_mode_spec_buf;
+      }
+
+    case 'F':
+      /* %F displays the frame name.  */
+      return (char *) XSTRING (selected_frame->name)->data;
+
     case 'f': 
       obj = b->filename;
 #if 0
@@ -3155,14 +3375,6 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
-    case 'c':
-      {
-       int col = current_column ();
-       XSETFASTINT (w->column_number_displayed, col);
-       sprintf (decode_mode_spec_buf, "%d", col);
-       return decode_mode_spec_buf;
-      }
-
     case 'l':
       {
        int startpos = marker_position (w->start);
@@ -3259,44 +3471,6 @@ decode_mode_spec (w, c, maxwidth)
        return " Narrow";
       break;
 
-    case '*':
-      if (!NILP (b->read_only))
-       return "%";
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      return "-";
-
-    case '+':
-      /* This differs from %* only for a modified read-only buffer.  */
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      if (!NILP (b->read_only))
-       return "%";
-      return "-";
-
-    case '&':
-      /* This differs from %* in ignoring read-only-ness.  */
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      return "-";
-
-    case 's':
-      /* status of process */
-      obj = Fget_buffer_process (w->buffer);
-      if (NILP (obj))
-       return "no process";
-#ifdef subprocesses
-      obj = Fsymbol_name (Fprocess_status (obj));
-#endif
-      break;
-
-    case 't':                  /* indicate TEXT or BINARY */
-#ifdef MODE_LINE_BINARY_TEXT
-      return MODE_LINE_BINARY_TEXT (b);
-#else
-      return "T";
-#endif
-
     case 'p':
       {
        int pos = marker_position (w->start);
@@ -3352,52 +3526,22 @@ decode_mode_spec (w, c, maxwidth)
          }
       }
 
-    case '%':
-      return "%";
-
-    case '[': 
-      {
-       int i;
-       char *p;
-
-       if (command_loop_level > 5)
-         return "[[[... ";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = '[';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
-
-    case ']': 
-      {
-       int i;
-       char *p;
-
-       if (command_loop_level > 5)
-         return " ...]]]";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = ']';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
+    case 's':
+      /* status of process */
+      obj = Fget_buffer_process (w->buffer);
+      if (NILP (obj))
+       return "no process";
+#ifdef subprocesses
+      obj = Fsymbol_name (Fprocess_status (obj));
+#endif
+      break;
 
-    case '-':
-      {
-       register char *p;
-       register int i;
-       
-       if (maxwidth < sizeof (lots_of_dashes))
-         return lots_of_dashes;
-       else
-         {
-           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
-             *p++ = '-';
-           *p = '\0';
-         }
-       return decode_mode_spec_buf;
-      }
+    case 't':                  /* indicate TEXT or BINARY */
+#ifdef MODE_LINE_BINARY_TEXT
+      return MODE_LINE_BINARY_TEXT (b);
+#else
+      return "T";
+#endif
     }
 
   if (STRINGP (obj))
@@ -3636,8 +3780,14 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c == 0)
        break;
 
-      if (c >= 040 && c < 0177
-         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
+      if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
+       {
+         p1 = copy_part_of_rope (f, p1, start,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
+                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
+                                 0);
+       }
+      else if (c >= 040 && c < 0177)
        {
          if (p1 >= start)
            *p1 = c;
@@ -3653,13 +3803,6 @@ display_string (w, vpos, string, length, hpos, truncate,
            }
          while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
        }
-      else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-       {
-         p1 = copy_part_of_rope (f, p1, start,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
-                                 XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 0);
-       }
       else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
        {
          if (p1 >= start)
@@ -3713,6 +3856,86 @@ display_string (w, vpos, string, length, hpos, truncate,
   }
 }
 \f
+/* This is like a combination of memq and assq.
+   Return 1 if PROPVAL appears as an element of LIST
+   or as the car of an element of LIST.
+   If PROPVAL is a list, compare each element against LIST
+   in that way, and return 1 if any element of PROPVAL is found in LIST.
+   Otherwise return 0.
+   This function cannot quit.  */
+
+int
+invisible_p (propval, list)
+     register Lisp_Object propval;
+     Lisp_Object list;
+{
+  register Lisp_Object tail, proptail;
+  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      register Lisp_Object tem;
+      tem = XCONS (tail)->car;
+      if (EQ (propval, tem))
+       return 1;
+      if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
+       return 1;
+    }
+  if (CONSP (propval))
+    for (proptail = propval; CONSP (proptail);
+        proptail = XCONS (proptail)->cdr)
+      {
+       Lisp_Object propelt;
+       propelt = XCONS (proptail)->car;
+       for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+         {
+           register Lisp_Object tem;
+           tem = XCONS (tail)->car;
+           if (EQ (propelt, tem))
+             return 1;
+           if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
+             return 1;
+         }
+      }
+  return 0;
+}
+
+/* Return 1 if PROPVAL appears as the car of an element of LIST
+   and the cdr of that element is non-nil.
+   If PROPVAL is a list, check each element of PROPVAL in that way,
+   and the first time some element is found,
+   return 1 if the cdr of that element is non-nil.
+   Otherwise return 0.
+   This function cannot quit.  */
+
+int
+invisible_ellipsis_p (propval, list)
+     register Lisp_Object propval;
+     Lisp_Object list;
+{
+  register Lisp_Object tail, proptail;
+  for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      register Lisp_Object tem;
+      tem = XCONS (tail)->car;
+      if (CONSP (tem) && EQ (propval, XCONS (tem)->car))
+       return ! NILP (XCONS (tem)->cdr);
+    }
+  if (CONSP (propval))
+    for (proptail = propval; CONSP (proptail);
+        proptail = XCONS (proptail)->cdr)
+      {
+       Lisp_Object propelt;
+       propelt = XCONS (proptail)->car;
+       for (tail = list; CONSP (tail); tail = XCONS (tail)->cdr)
+         {
+           register Lisp_Object tem;
+           tem = XCONS (tail)->car;
+           if (CONSP (tem) && EQ (propelt, XCONS (tem)->car))
+             return ! NILP (XCONS (tem)->cdr);
+         }
+      }
+  return 0;
+}
+\f
 void
 syms_of_xdisp ()
 {