]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(display_text_line): Enter a char in charstarts
[gnu-emacs] / src / xdisp.c
index fd08f443c0fead1f7db12d51accf069427ee5854..4ac9b9c4c2436c63d1d0165a532fd3b543554927 100644 (file)
@@ -54,6 +54,8 @@ static int message_log_need_newline;
 
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #define max(a, b) ((a) > (b) ? (a) : (b))
+#define minmax(floor, val, ceil) \
+       ((val) < (floor) ? (floor) : (val) > (ceil) ? (ceil) : (val))
 
 /* The buffer position of the first character appearing
  entirely or partially on the current frame line.
@@ -120,12 +122,17 @@ Lisp_Object Qmenu_bar_update_hook;
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 static int overlay_arrow_seen;
 
+/* Nonzero if visible end of buffer has already been displayed once
+   in this window.  (We need this variable in case there are overlay
+   strings that get displayed there.)  */
+static int zv_strings_seen;
+
 /* Nonzero means highlight the region even in nonselected windows.  */
 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,7 +150,7 @@ 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;
@@ -153,7 +160,6 @@ static void echo_area_display ();
 void mark_window_display_accurate ();
 static void redisplay_windows ();
 static void redisplay_window ();
-static void update_menu_bars ();
 static void update_menu_bar ();
 static void try_window ();
 static int try_window_id ();
@@ -212,7 +218,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.  */
@@ -242,6 +248,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;
@@ -316,6 +323,7 @@ message_dolog (m, len, nlflag)
    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;
@@ -323,8 +331,8 @@ message_log_check_duplicate (prev_bol, this_bol)
   int i;
   int len = Z - 1 - this_bol;
   int seen_dots = 0;
-  char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
-  char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
+  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++)
     {
@@ -515,6 +523,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 ()
 {
@@ -552,6 +573,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];
 
@@ -608,7 +631,23 @@ x_consider_frame_title (frame)
 
   if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
     return;
-  multiple_frames = !EQ (Fnext_frame (frame, Qnil), frame);
+
+  /* Do we have more than one visible frame on this X display?  */
+  {
+    Lisp_Object tail;
+
+    for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
+      {
+       FRAME_PTR tf = XFRAME (XCONS (tail)->car);
+
+       if (tf != f && tf->kboard == f->kboard && !FRAME_MINIBUF_ONLY_P (tf)
+           && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
+         break;
+      }
+
+    multiple_frames = CONSP (tail);
+  }
+
   obuf = current_buffer;
   Fset_buffer (XWINDOW (f->selected_window)->buffer);
   fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
@@ -632,7 +671,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 ()
@@ -641,50 +680,18 @@ 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.  */
   if (all_windows)
     {
       Lisp_Object tail, frame;
+      int count = specpdl_ptr - specpdl;
+
+      record_unwind_protect (Fstore_match_data, Fmatch_data ());
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -693,6 +700,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))
@@ -701,15 +710,32 @@ prepare_menu_bars ()
                  functions = XCONS (functions)->cdr;
                }
              UNGCPRO;
-             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
            }
          GCPRO1 (tail);
-         update_menu_bar (XFRAME (frame));
+         update_menu_bar (XFRAME (frame), 0);
          UNGCPRO;
        }
+
+      unbind_to (count, Qnil);
     }
   else
-    update_menu_bar (selected_frame);
+    update_menu_bar (selected_frame, 1);
+
+  /* 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.
@@ -757,7 +783,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.  */
@@ -769,6 +801,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 ()))
@@ -848,6 +882,7 @@ redisplay ()
        {
          cursor_vpos = -1;
          overlay_arrow_seen = 0;
+         zv_strings_seen = 0;
          display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
                             pos_tab_offset (w, tlbufpos));
          /* If line contains point, is not continued,
@@ -894,21 +929,25 @@ 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,
+                                0,
                                 PT, 2, - (1 << (SHORTBITS - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
                                 pos_tab_offset (w, tlbufpos), w);
          if (pos.vpos < 1)
            {
+             int width = window_internal_width (w) - 1;
              FRAME_CURSOR_X (selected_frame)
-               = XFASTINT (w->left) + max (pos.hpos, 0);
+               = XFASTINT (w->left) + minmax (0, pos.hpos, width);
              FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
              goto update;
            }
@@ -994,7 +1033,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)
@@ -1170,15 +1211,19 @@ mark_window_display_accurate (window, flag)
 \f
 /* Update the menu bar item list for frame F.
    This has to be done before we start to fill in any display lines,
-   because it can call eval.  */
+   because it can call eval.
+
+   If SAVE_MATCH_DATA is 1, we must save and restore it here.  */
 
 static void
-update_menu_bar (f)
+update_menu_bar (f, save_match_data)
      FRAME_PTR f;
+     int save_match_data;
 {
   struct buffer *old = current_buffer;
   Lisp_Object window;
   register struct window *w;
+
   window = FRAME_SELECTED_WINDOW (f);
   w = XWINDOW (window);
   
@@ -1207,6 +1252,11 @@ update_menu_bar (f)
                  <= BUF_SAVE_MODIFF (XBUFFER (w->buffer)))))
        {
          struct buffer *prev = current_buffer;
+         int count = specpdl_ptr - specpdl;
+
+         if (!save_match_data)
+           record_unwind_protect (Fstore_match_data, Fmatch_data ());
+
          call1 (Vrun_hooks, Qmenu_bar_update_hook);
          current_buffer = XBUFFER (w->buffer);
          FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
@@ -1214,6 +1264,8 @@ update_menu_bar (f)
 #ifdef USE_X_TOOLKIT
          set_frame_menubar (f, 0);
 #endif /* USE_X_TOOLKIT */
+
+         unbind_to (count, Qnil);
        }
     }
 }
@@ -1388,13 +1440,14 @@ redisplay_window (window, just_this_one)
        {
          /* If point does not appear, move point so it does appear */
          pos = *compute_motion (startp, 0,
-                               ((EQ (window, minibuf_window) && startp == 1)
-                                ? minibuf_prompt_width : 0)
-                               +
-                               (hscroll ? 1 - hscroll : 0),
-                               ZV, height / 2,
-                               - (1 << (SHORTBITS - 1)),
-                               width, hscroll, pos_tab_offset (w, startp), w);
+                                (((EQ (window, minibuf_window)
+                                   && startp == BEG)
+                                  ? minibuf_prompt_width : 0)
+                                 + (hscroll ? 1 - hscroll : 0)),
+                                0,
+                                ZV, height / 2,
+                                - (1 << (SHORTBITS - 1)),
+                                width, hscroll, pos_tab_offset (w, startp), w);
          BUF_PT (current_buffer) = pos.bufpos;
          if (w != XWINDOW (selected_window))
            Fset_marker (w->pointm, make_number (PT), Qnil);
@@ -1402,7 +1455,8 @@ redisplay_window (window, just_this_one)
            {
              if (current_buffer == old)
                lpoint = PT;
-             FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
+             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+                                   + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
          /* If we are highlighting the region,
@@ -1442,7 +1496,7 @@ redisplay_window (window, just_this_one)
       && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
       && !EQ (window, minibuf_window))
     {
-      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
+      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
                            PT, height, 0, width, hscroll,
                            pos_tab_offset (w, startp), w);
 
@@ -1452,7 +1506,8 @@ redisplay_window (window, just_this_one)
          if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
            {
              /* These variables are supposed to be origin 1 */
-             FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
+             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+                                   + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
          /* This doesn't do the trick, because if a window to the right of
@@ -1535,14 +1590,12 @@ redisplay_window (window, just_this_one)
     {
       if (PT > startp)
        {
-         pos = *vmotion (Z - XFASTINT (w->window_end_pos),
-                         scroll_step, width, hscroll, window);
+         pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, w);
          if (pos.vpos >= height)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
-                     width, hscroll, window);
+      pos = *vmotion (startp, (PT < startp ? - scroll_step : scroll_step), w);
 
       if (PT >= pos.bufpos)
        {
@@ -1566,11 +1619,11 @@ recenter:
   /* Forget any previously recorded base line for line number display.  */
   w->base_line_number = Qnil;
 
-  pos = *vmotion (PT, - (height / 2), width, hscroll, window);
+  pos = *vmotion (PT, - (height / 2), w);
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
-  w->start_at_line_beg 
+  w->start_at_line_beg
     = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
@@ -1662,6 +1715,7 @@ try_window (window, pos)
   Fset_marker (w->start, make_number (pos), Qnil);
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
+  zv_strings_seen = 0;
   val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
 
   while (--height >= 0)
@@ -1732,6 +1786,7 @@ try_window_id (window)
   int width = window_internal_width (w) - 1;
   int hscroll = XINT (w->hscroll);
   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
+  int did_motion;
   register int vpos;
   register int i, tem;
   int last_text_vpos = 0;
@@ -1754,7 +1809,7 @@ try_window_id (window)
     return 0;                  /* Give up if changes go above top of window */
 
   /* Find position before which nothing is changed.  */
-  bp = *compute_motion (start, 0, lmargin,
+  bp = *compute_motion (start, 0, lmargin, 0,
                        min (ZV, beg_unchanged + BEG), height, 0,
                        width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
@@ -1765,7 +1820,7 @@ try_window_id (window)
             We don't need to change the frame at all.
             But we need to update window_end_pos to account for
             any change in buffer size.  */
-         bp = *compute_motion (start, 0, lmargin,
+         bp = *compute_motion (start, 0, lmargin, 0,
                                Z, height, 0,
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
@@ -1778,13 +1833,14 @@ try_window_id (window)
   vpos = bp.vpos;
 
   /* Find beginning of that frame line.  Must display from there.  */
-  bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
+  bp = *vmotion (bp.bufpos, 0, w);
 
   pos = bp.bufpos;
   val.hpos = lmargin;
   if (pos < start)
     return -1;
 
+  did_motion = 0;
   /* If about to start displaying at the beginning of a continuation line,
      really start with previous frame line, in case it was not
      continued when last redisplayed */
@@ -1793,7 +1849,7 @@ try_window_id (window)
       /* Likewise if we have to worry about selective display.  */
       (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
     {
-      bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
+      bp = *vmotion (bp.bufpos, -1, w);
       --vpos;
       pos = bp.bufpos;
     }
@@ -1801,6 +1857,7 @@ try_window_id (window)
   if (bp.contin && bp.hpos != lmargin)
     {
       val.hpos = bp.prevhpos - width + lmargin;
+      did_motion = 1;
       pos--;
     }
 
@@ -1813,7 +1870,7 @@ try_window_id (window)
       tem = find_next_newline (tem, 1);
 
   /* Compute the cursor position after that newline.  */
-  ep = *compute_motion (pos, vpos, val.hpos, tem,
+  ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
                        height, - (1 << (SHORTBITS - 1)),
                        width, hscroll, pos_tab_offset (w, bp.bufpos), w);
 
@@ -1837,6 +1894,7 @@ try_window_id (window)
 
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
+  zv_strings_seen = 0;
 
   /* If changes do not reach to bottom of window,
      figure out how much to scroll the rest of the window */
@@ -1844,7 +1902,7 @@ try_window_id (window)
     {
       /* Now determine how far up or down the rest of the window has moved */
       epto = pos_tab_offset (w, ep.bufpos);
-      xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
+      xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
                            Z - XFASTINT (w->window_end_pos),
                            10000, 0, width, hscroll, epto, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
@@ -1868,13 +1926,13 @@ try_window_id (window)
        {
          if (PT <= xp.bufpos)
            {
-             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
+             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
                                    PT, height, - (1 << (SHORTBITS - 1)),
                                    width, hscroll, epto, w);
            }
          else
            {
-             pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
+             pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
                                    PT, height, - (1 << (SHORTBITS - 1)),
                                    width, hscroll,
                                    pos_tab_offset (w, xp.bufpos), w);
@@ -1882,7 +1940,7 @@ try_window_id (window)
          if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
-         cursor_hpos = pp.hpos + XFASTINT (w->left);
+         cursor_hpos = XFASTINT (w->left) + minmax (0, pp.hpos, width);
        }
 
       if (stop_vpos - scroll_amount >= height
@@ -2064,8 +2122,7 @@ try_window_id (window)
          || (delta > 0 && xp.bufpos <= ZV)
          || (delta == 0 && xp.hpos))
        {
-         val = *vmotion (Z - XFASTINT (w->window_end_pos),
-                         delta, width, hscroll, window);
+         val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, w);
          XSETFASTINT (w->window_end_pos, Z - val.bufpos);
          XSETFASTINT (w->window_end_vpos,
                       XFASTINT (w->window_end_vpos) + val.vpos);
@@ -2078,7 +2135,7 @@ try_window_id (window)
   if (cursor_vpos < 0)
     {
     findpoint:
-      val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
+      val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
@@ -2088,15 +2145,15 @@ try_window_id (window)
          return 0;
        }
       cursor_vpos = val.vpos + top;
-      cursor_hpos = val.hpos + XFASTINT (w->left);
+      cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
     }
 
-  FRAME_CURSOR_X (f) = max (0, cursor_hpos);
+  FRAME_CURSOR_X (f) = cursor_hpos;
   FRAME_CURSOR_Y (f) = cursor_vpos;
 
   if (debug_end_pos)
     {
-      val = *compute_motion (start, 0, lmargin, ZV,
+      val = *compute_motion (start, 0, lmargin, 0, ZV,
                             height, - (1 << (SHORTBITS - 1)),
                             width, hscroll, pos_tab_offset (w, start), w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
@@ -2287,13 +2344,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register int pos = start;
   register int c;
   register GLYPH *p1;
-  int end;
   register int pause;
   register unsigned char *p;
   GLYPH *endp;
   register GLYPH *leftmargin;
-  register GLYPH *p1prev = 0;
+  register GLYPH *p1prev;
   register GLYPH *p1start;
+  int prevpos;
   int *charstart;
   FRAME_PTR f = XFRAME (w->frame);
   int tab_width = XINT (current_buffer->tab_width);
@@ -2346,11 +2403,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
      to overlays or text property changes.  */
   int next_face_change;
 
-#ifdef USE_TEXT_PROPERTIES
-  /* The next location where the `invisible' property changes */
-  int next_invisible;
-#endif
-  
+  /* The next location where the `invisible' property changes, or an
+     overlay starts or ends.  */
+  int next_boundary;
+
   /* The face we're currently using.  */
   int current_face = 0;
   int i;
@@ -2382,7 +2438,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
     region_beg = region_end = -1;
 
   if (MINI_WINDOW_P (w)
-      && start == 1
+      && start == BEG
       && vpos == XFASTINT (w->top))
     {
       if (! NILP (minibuf_prompt))
@@ -2405,16 +2461,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
        minibuf_prompt_width = 0;
     }
 
-  end = ZV;
-
   /* If we're hscrolled at all, use compute_motion to skip over any
      text off the left edge of the window.  compute_motion may know
      tricks to do this faster than we can.  */
   if (hpos < 0)
     {
       struct position *left_edge
-        = compute_motion (pos, vpos, hpos,
-                          end, vpos, 0,
+        = compute_motion (pos, vpos, hpos, 0,
+                          ZV, vpos, 0,
                           width, hscroll, taboffset, w);
 
       /* Retrieve the buffer position and column provided by
@@ -2460,70 +2514,82 @@ display_text_line (w, start, vpos, hpos, taboffset)
      or at face change.  */
   pause = pos;
   next_face_change = pos;
-#ifdef USE_TEXT_PROPERTIES
-  next_invisible = pos;
-#endif
+  next_boundary = pos;
+  p1prev = p1;
+  prevpos = pos;
   while (1)
     {
-      /* Record which glyph starts a character,
-        and the character position of that character.  */
-      if (p1 >= leftmargin)
-       charstart[p1 - p1start] = pos;
-
-      if (p1 >= endp)
-       break;
-
-      p1prev = p1;
       if (pos >= pause)
        {
-         /* Did we hit the end of the visible region of the buffer?
-            Stop here.  */
-         if (pos >= end)
-           break;
-
-         /* Did we reach point?  Record the cursor location.  */
-         if (pos == PT && cursor_vpos < 0)
+         while (pos == next_boundary)
            {
-             cursor_vpos = vpos;
-             cursor_hpos = p1 - leftmargin;
-           }
+             Lisp_Object position, limit, prop, ww;
+
+             /* Display the overlay strings here, unless we're at ZV
+                and have already displayed the appropriate strings
+                on an earlier line.  */
+             if (pos < ZV || !zv_strings_seen++)
+               {
+                 int ovlen;
+                 char *ovstr;
+                 ovlen = overlay_strings (pos, w, &ovstr);
+                 for (; ovlen; ovlen--, ovstr++)
+                   {
+                     if (p1 >= leftmargin && p1 < endp)
+                       *p1 = MAKE_GLYPH (f, *ovstr, current_face);
+                     p1++;
+                   }
+               }
+
+             /* Did we reach point?  Record the cursor location.  */
+             if (pos == PT && cursor_vpos < 0)
+               {
+                 cursor_vpos = vpos;
+                 cursor_hpos = p1 - leftmargin;
+               }
+
+             if (pos >= ZV)
+               break;
 
-#ifdef USE_TEXT_PROPERTIES
-         /* if the `invisible' property is set to t, we can skip to
-            the next property change */
-         while (pos == next_invisible && pos < end)
-           {
-             Lisp_Object position, limit, endpos, prop, ww;
              XSETFASTINT (position, pos);
-             XSETWINDOW (ww, w);
-             prop = Fget_char_property (position, Qinvisible, ww);
+             limit = Fnext_overlay_change (position);
+#ifdef USE_TEXT_PROPERTIES
              /* This is just an estimate to give reasonable
                 performance; nothing should go wrong if it is too small.  */
-             limit = Fnext_overlay_change (position);
              if (XFASTINT (limit) > pos + 50)
                XSETFASTINT (limit, pos + 50);
-             endpos = Fnext_single_property_change (position, Qinvisible,
-                                                    Fcurrent_buffer (),
-                                                    limit);
-             if (INTEGERP (endpos))
-               next_invisible = XINT (endpos);
-             else
-               next_invisible = end;
+             limit = Fnext_single_property_change (position, Qinvisible,
+                                                   Fcurrent_buffer (), limit);
+#endif
+             next_boundary = XFASTINT (limit);
+             /* if the `invisible' property is set, we can skip to
+                the next property change.  */
+             XSETWINDOW (ww, w);
+             prop = Fget_char_property (position, Qinvisible, ww);
              if (TEXT_PROP_MEANS_INVISIBLE (prop))
                {
-                 if (pos < PT && next_invisible >= PT)
+                 if (pos < PT && next_boundary >= PT)
                    {
                      cursor_vpos = vpos;
                      cursor_hpos = p1 - leftmargin;
                    }
-                 pos = next_invisible;
+                 pos = next_boundary;
                  last_invis_skip = pos;
                  last_invis_prop = prop;
                }
            }
-         if (pos >= end)
+
+         /* Did we reach point?  Record the cursor location.  */
+         if (pos == PT && cursor_vpos < 0)
+           {
+             cursor_vpos = vpos;
+             cursor_hpos = p1 - leftmargin;
+           }
+
+         /* Did we hit the end of the visible region of the buffer?
+            Stop here.  */
+         if (pos >= ZV)
            break;
-#endif
 
 #ifdef HAVE_FACES
          /* Did we hit a face change?  Figure out what face we should
@@ -2535,12 +2601,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
                                              &next_face_change, pos + 50, 0);
 #endif
 
-         pause = end;
+         pause = ZV;
 
-#ifdef USE_TEXT_PROPERTIES       
-         if (pos < next_invisible && next_invisible < pause)
-           pause = next_invisible;
-#endif
+         if (pos < next_boundary && next_boundary < pause)
+           pause = next_boundary;
          if (pos < next_face_change && next_face_change < pause)
            pause = next_face_change;
 
@@ -2553,6 +2617,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
          p = &FETCH_CHAR (pos);
        }
+
+      if (p1 >= endp)
+       break;
+
+      p1prev = p1;
+
       c = *p++;
       /* Let a display table override all standard display methods.  */
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
@@ -2574,7 +2644,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (last_invis_skip == pos
              && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
            invis = 1;
-         while (pos + 1 < end
+         while (pos + 1 < ZV
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
            {
@@ -2602,6 +2672,25 @@ display_text_line (w, start, vpos, hpos, taboffset)
                *p1++ = FAST_MAKE_GLYPH (' ', current_face);
            }
 #endif
+
+         /* Update charstarts for the newline that ended this line.  */
+         /* Do nothing here for a char that's entirely off the left edge
+            or if it starts at the right edge.  */
+         if (p1 >= leftmargin && p1prev != endp)
+           {
+             /* Store the newline's position into charstarts
+                for the column where the newline starts.
+                Store -1 for the rest of the glyphs it occupies.  */
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
+             int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
+
+             *p2x++ = pos;
+             while (p2x < p2)
+               *p2x++ = -1;
+           }
+
          break;
        }
       else if (c == '\t')
@@ -2639,6 +2728,24 @@ display_text_line (w, start, vpos, hpos, taboffset)
                *p1++ = FAST_MAKE_GLYPH (' ', current_face);
            }
 #endif
+
+         /* Update charstarts for the ^M that ended this line.  */
+         /* Do nothing here for a char that's entirely off the left edge
+            or if it starts at the right edge.  */
+         if (p1 >= leftmargin && p1prev != endp)
+           {
+             /* Store the newline's position into charstarts
+                for the column where the newline starts.
+                Store -1 for the rest of the glyphs it occupies.  */
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
+             int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
+
+             *p2x++ = pos;
+             while (p2x < p2)
+               *p2x++ = -1;
+           }
          break;
        }
       else if (c < 0200 && ctl_arrow)
@@ -2670,32 +2777,30 @@ display_text_line (w, start, vpos, hpos, taboffset)
          p1++;
        }
 
+      prevpos = pos;
+      pos++;
+
+      /* Update charstarts for the character just output.  */
+
       /* Do nothing here for a char that's entirely off the left edge.  */
       if (p1 >= leftmargin)
        {
-         /* For all the glyphs occupied by this character, except for the
-            first, store -1 in charstarts.  */
+         /* Store the char's position into charstarts
+            for the first glyph occupied by this char.
+            Store -1 for the rest of the glyphs it occupies.  */
          if (p1 != p1prev)
            {
-             int *p2x = &charstart[p1prev - p1start];
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
              int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
 
-             /* The window's left column should always
-                contain a character position.
-                And don't clobber anything to the left of that.  */
-             if (p1prev < leftmargin)
-               {
-                 p2x = charstart + (leftmargin - p1start);
-                 *p2x = pos;
-               }
-
-             /* This loop skips over the char p2x initially points to.  */
-             while (++p2x < p2)
-               *p2x = -1;
+             if (p2x < p2)
+               *p2x++ = prevpos;
+             while (p2x < p2)
+               *p2x++ = -1;
            }
        }
-
-      pos++;
     }
 
   val.hpos = - XINT (w->hscroll);
@@ -2795,8 +2900,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))
            {
@@ -2970,20 +3079,17 @@ display_mode_line (w)
   w->column_number_displayed = Qnil;
 
   get_display_line (f, vpos, left);
-#ifdef MULTI_KBOARD
-  {
-    /* Sigh, mode-line-format can reference kboard-local variables like
-       defining-kbd-macro.  Use the one associated with the frame we're
-       updating.  */
-    KBOARD *orig_kboard = current_kboard;
-    current_kboard = FRAME_KBOARD (f);
-#endif
-    display_mode_element (w, vpos, left, 0, right, right,
-                         current_buffer->mode_line_format);
-#ifdef MULTI_KBOARD
-    current_kboard = orig_kboard;
-  }
-#endif
+
+  /* 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
@@ -2996,7 +3102,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;
@@ -3254,6 +3360,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
@@ -3267,6 +3441,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
@@ -3282,14 +3468,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);
@@ -3386,44 +3564,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);
@@ -3479,52 +3619,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))
@@ -3969,8 +4079,10 @@ If this is zero, point is always centered after it moves off frame.");
   highlight_nonselected_windows = 1;
 
   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
-    "Non-nil means more than one frame is in use, not counting minibuffer frames.\n\
-Not guaranteed to be accurate except while parsing frame-title-format.");
+    "Non-nil if more than one frame is visible on this display.\n\
+Minibuffer-only frames don't count, but iconified frames do.\n\
+This variable is not guaranteed to be accurate except while parsing\n\
+frame-title-format.");
 
   DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
     "Template for displaying the titlebar of visible frames.\n\