(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / xdisp.c
index 8108387..1b2324c 100644 (file)
@@ -42,6 +42,8 @@ extern void set_frame_menubar ();
 extern int interrupt_input;
 extern int command_loop_level;
 
+extern Lisp_Object Qface;
+
 /* Nonzero means print newline before next minibuffer message.  */
 
 int noninteractive_need_newline;
@@ -83,6 +85,10 @@ char *previous_echo_glyphs;
 /* Nonzero means truncate lines in all windows less wide than the frame */
 int truncate_partial_width_windows;
 
+/* Nonzero means we have more than one non-minibuffer-only frame.
+   Not guaranteed to be accurate except while parsing frame-title-format.  */
+int multiple_frames;
+
 Lisp_Object Vglobal_mode_string;
 
 /* Marker for where to display an arrow on top of the buffer text.  */
@@ -91,9 +97,17 @@ Lisp_Object Voverlay_arrow_position;
 /* String to display for the arrow.  */
 Lisp_Object Voverlay_arrow_string;
 
+/* Like mode-line-format, but for the titlebar on a visible frame.  */
+Lisp_Object Vframe_title_format;
+
+/* Like mode-line-format, but for the titlebar on an iconified frame.  */
+Lisp_Object Vicon_title_format;
+
 /* Values of those variables at last redisplay.  */
 static Lisp_Object last_arrow_position, last_arrow_string;
 
+Lisp_Object Qmenu_bar_update_hook;
+
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 static int overlay_arrow_seen;
 
@@ -108,7 +122,8 @@ int scroll_step;
  since the last redisplay that paused */
 static int blank_end_of_window;
 
-/* Number of windows showing the buffer of the selected window.
+/* Number of windows showing the buffer of the selected window
+   (or another buffer with the same base buffer).
    keyboard.c refers to this.  */
 int buffer_shared;
 
@@ -142,7 +157,7 @@ static void display_menu_bar ();
 static int display_count_lines ();
 
 /* Prompt to display in front of the minibuffer contents */
-char *minibuf_prompt;
+Lisp_Object minibuf_prompt;
 
 /* Width in columns of current minibuffer prompt.  */
 int minibuf_prompt_width;
@@ -186,6 +201,9 @@ int windows_or_buffers_changed;
    and it displayed a line number.  */
 int line_number_displayed;
 
+/* Nonzero if display_mode_line needs to handle %c.  */
+int column_number_displayed;
+
 /* Maximum buffer size for which to display line numbers.  */
 int line_number_display_limit;
 \f
@@ -237,6 +255,8 @@ message2 (m, len)
       echo_area_display ();
       update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
       do_pending_window_change ();
+      if (frame_up_to_date_hook != 0 && ! gc_in_progress)
+       (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
     }
 }
 
@@ -271,6 +291,7 @@ int message_buf_print;
 void
 message (m, a1, a2, a3)
      char *m;
+     EMACS_INT a1, a2, a3;
 {
   if (noninteractive)
     {
@@ -307,7 +328,7 @@ message (m, a1, a2, a3)
            {
              int len;
 #ifdef NO_ARG_ARRAY
-             int a[3];
+             EMACS_INT a[3];
              a[0] = a1;
              a[1] = a2;
              a[2] = a3;
@@ -331,6 +352,12 @@ message (m, a1, a2, a3)
     }
 }
 
+void
+update_echo_area ()
+{
+  message2 (echo_area_glyphs, echo_area_glyphs_length);
+}
+
 static void
 echo_area_display ()
 {
@@ -388,31 +415,57 @@ echo_area_display ()
 }
 
 #ifdef HAVE_X_WINDOWS
-/* I'm trying this out because I saw Unimpress use it, but it's
-   possible that this may mess adversely with some window managers.  -jla
+static char frame_title_buf[512];
+static char *frame_title_ptr;
 
-   Wouldn't it be nice to use something like mode-line-format to
-   describe frame titles?  -JimB  */
+static int
+store_frame_title (str, mincol, maxcol)
+     char *str;
+     int mincol, maxcol;
+{
+  char *limit;
+  if (maxcol < 0 || maxcol >= sizeof(frame_title_buf))
+    maxcol = sizeof (frame_title_buf);
+  limit = &frame_title_buf[maxcol];
+  while (*str != '\0' && frame_title_ptr < limit)
+    *frame_title_ptr++ = *str++;
+  while (frame_title_ptr < &frame_title_buf[mincol])
+    *frame_title_ptr++ = ' ';
+  return frame_title_ptr - frame_title_buf;
+}
 
-/* Change the title of the frame to the name of the buffer displayed
-   in the currently selected window.  Don't do this for minibuffer frames,
-   and don't do it when there's only one non-minibuffer frame.  */
 static void
 x_consider_frame_title (frame)
      Lisp_Object frame;
 {
+  Lisp_Object fmt;
+  struct buffer *obuf;
+  int len;
   FRAME_PTR f = XFRAME (frame);
 
-  if (FRAME_X_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
-    {
-      Lisp_Object title = Qnil;
-
-      if (! EQ (Fnext_frame (frame, Qnil), frame))
-       title = XBUFFER (XWINDOW (f->selected_window)->buffer)->name;
-
-      x_implicitly_set_name (f, title, Qnil);
-    }
+  if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
+    return;
+  multiple_frames = !EQ (Fnext_frame (frame, Qnil), frame);
+  obuf = current_buffer;
+  Fset_buffer (XWINDOW (f->selected_window)->buffer);
+  fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
+  frame_title_ptr = frame_title_buf;
+  len = display_mode_element (XWINDOW (f->selected_window), 0, 0, 0,
+                             0, sizeof (frame_title_buf), fmt);
+  frame_title_ptr = 0;
+  set_buffer_internal (obuf);
+  /* Set the name only if it's changed.  This avoids consing
+     in the common case where it hasn't.  (If it turns out that we've
+     already wasted too much time by walking through the list with
+     display_mode_element, then we might need to optimize at a higher
+     level than this.)  */
+  if (! STRINGP (f->name) || XSTRING (f->name)->size != len
+      || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
+    x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
 }
+#else
+#define frame_title_ptr ((char *)0)
+#define store_frame_title(str, mincol, maxcol) 0
 #endif
 \f
 /* Prepare for redisplay by updating menu-bar item lists when appropriate.
@@ -447,25 +500,20 @@ prepare_menu_bars ()
       frame_garbaged = 0;
     }
 
-  if (clip_changed || windows_or_buffers_changed)
-    update_mode_lines++;
+  all_windows = (update_mode_lines || buffer_shared > 1
+                || clip_changed || windows_or_buffers_changed);
 
-  /* Detect case that we need to write a star in the mode line.  */
-  if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= current_buffer->save_modified)
+#ifdef HAVE_X_WINDOWS
+  if (windows_or_buffers_changed)
     {
-      w->update_mode_line = Qt;
-      if (buffer_shared > 1)
-       update_mode_lines++;
-    }
-
-  all_windows = update_mode_lines || buffer_shared > 1;
+      Lisp_Object tail, frame;
 
-  /* If specs for an arrow have changed, do thorough redisplay
-     to ensure we remove any arrow that should no longer exist.  */
-  if (! EQ (Voverlay_arrow_position, last_arrow_position)
-      || ! EQ (Voverlay_arrow_string, last_arrow_string))
-    all_windows = 1, clip_changed = 1;
+      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
@@ -475,15 +523,10 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
 
       FOR_EACH_FRAME (tail, frame)
-       {
-         FRAME_PTR f = XFRAME (frame);
-
-         if (FRAME_VISIBLE_P (f))
-           update_menu_bars (FRAME_ROOT_WINDOW (f));
-       }
+       update_menu_bar (XFRAME (frame));
     }
-  else if (FRAME_VISIBLE_P (selected_frame))
-    update_menu_bar (selected_window);
+  else
+    update_menu_bar (selected_frame);
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -504,6 +547,12 @@ prepare_menu_bars ()
    See Fcall_process; if you called it from here, it could be
    entered recursively.  */
 
+static int do_verify_charstarts;
+
+/* Counter is used to clear the face cache
+   no more than once ever 1000 redisplays.  */
+static int clear_face_cache_count;
+
 void
 redisplay ()
 {
@@ -538,12 +587,12 @@ redisplay ()
       frame_garbaged = 0;
     }
 
-  if (clip_changed || windows_or_buffers_changed)
+  if (clip_changed || windows_or_buffers_changed || column_number_displayed)
     update_mode_lines++;
 
   /* Detect case that we need to write a star in the mode line.  */
   if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= current_buffer->save_modified)
+      && XFASTINT (w->last_modified) <= SAVE_MODIFF)
     {
       w->update_mode_line = Qt;
       if (buffer_shared > 1)
@@ -588,8 +637,8 @@ redisplay ()
       && current_buffer == XBUFFER (w->buffer)
       && NILP (w->force_start)
       /* Point must be on the line that we have info recorded about */
-      && point >= tlbufpos
-      && point <= Z - tlendpos
+      && PT >= tlbufpos
+      && PT <= Z - tlendpos
       /* All text outside that line, including its final newline,
         must be unchanged */
       && (XFASTINT (w->last_modified) >= MODIFF
@@ -597,7 +646,7 @@ redisplay ()
              && GPT >= tlbufpos
              /* If selective display, can't optimize
                 if the changes start at the beginning of the line.  */
-             && ((XTYPE (current_buffer->selective_display) == Lisp_Int
+             && ((INTEGERP (current_buffer->selective_display)
                   && XINT (current_buffer->selective_display) > 0
                   ? (beg_unchanged >= tlbufpos
                      && GPT > tlbufpos)
@@ -622,6 +671,30 @@ redisplay ()
          if (cursor_vpos >= 0 && this_line_bufpos
              && this_line_endpos == tlendpos)
            {
+             /* If this is not the window's last line,
+                we must adjust the charstarts of the lines below.  */
+             if (this_line_vpos + 1
+                 < XFASTINT (w->top) + window_internal_height (w))
+               {
+                 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)
+                   /* This line ends at end of (accessible part of) buffer.
+                      There is no newline to count.  */
+                   adjust = Z - tlendpos - charstart_next_line[left];
+                 else
+                   /* This line ends in a newline.
+                      Must take account of the newline and the rest of the
+                      text that follows.  */
+                   adjust = Z - tlendpos + 1 - charstart_next_line[left];
+
+                 adjust_window_charstarts (w, this_line_vpos, adjust);
+               }
+
              if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
                preserve_other_columns (w);
              goto update;
@@ -629,7 +702,7 @@ redisplay ()
          else
            goto cancel;
        }
-      else if (point == XFASTINT (w->last_point))
+      else if (PT == XFASTINT (w->last_point))
        {
          if (!must_finish)
            {
@@ -645,10 +718,10 @@ redisplay ()
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
-                                point, 2, - (1 << (SHORTBITS - 1)),
+                                PT, 2, - (1 << (SHORTBITS - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
-                                pos_tab_offset (w, tlbufpos));
+                                pos_tab_offset (w, tlbufpos), w);
          if (pos.vpos < 1)
            {
              FRAME_CURSOR_X (selected_frame)
@@ -667,14 +740,20 @@ redisplay ()
   this_line_bufpos = 0;
   all_windows |= buffer_shared > 1;
 
+  clear_face_cache_count++;
+
   if (all_windows)
     {
       Lisp_Object tail, frame;
 
-#ifdef HAVE_X_WINDOWS
-      /* Since we're doing a thorough redisplay, we might as well
-        recompute all our display faces.  */
-      clear_face_vector ();
+#ifdef HAVE_FACES
+      /* Clear the face cache, only when we do a full redisplay
+        and not too often either.  */
+      if (clear_face_cache_count > 1000)
+       {
+         clear_face_cache ();
+         clear_face_cache_count = 0;
+       }
 #endif
 
       /* Recompute # windows showing selected buffer.
@@ -692,11 +771,6 @@ redisplay ()
 
          if (FRAME_VISIBLE_P (f))
            redisplay_windows (FRAME_ROOT_WINDOW (f));
-#ifdef HAVE_X_WINDOWS
-         else if (FRAME_ICONIFIED_P (f)
-                  && ! MINI_WINDOW_P (XWINDOW (f->selected_window)))
-           x_consider_frame_title (frame);
-#endif
 
          /* Any scroll bars which redisplay_windows should have nuked
             should now go away.  */
@@ -730,7 +804,7 @@ update:
        {
          FRAME_PTR f;
 
-         if (XTYPE (XCONS (tail)->car) != Lisp_Frame)
+         if (!FRAMEP (XCONS (tail)->car))
            continue;
 
          f = XFRAME (XCONS (tail)->car);
@@ -738,7 +812,11 @@ update:
            {
              pause |= update_frame (f, 0, 0);
              if (!pause)
-               mark_window_display_accurate (f->root_window, 1);
+               {
+                 mark_window_display_accurate (f->root_window, 1);
+                 if (frame_up_to_date_hook != 0)
+                   (*frame_up_to_date_hook) (f);
+               }
            }
        }
     }
@@ -754,8 +832,8 @@ update:
         above call to update_frame would not have caught it.  Catch
         it here.  */
       {
-       FRAME_PTR mini_frame =
-         XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
+       FRAME_PTR mini_frame
+         XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
        
        if (mini_frame != selected_frame)
          pause |= update_frame (mini_frame, 0, 0);
@@ -793,19 +871,23 @@ update:
       beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
       end_unchanged = BUF_Z (b) - BUF_GPT (b);
 
-      XFASTINT (w->last_point) = BUF_PT (b);
-      XFASTINT (w->last_point_x) = FRAME_CURSOR_X (selected_frame);
-      XFASTINT (w->last_point_y) = FRAME_CURSOR_Y (selected_frame);
+      XSETFASTINT (w->last_point, BUF_PT (b));
+      XSETFASTINT (w->last_point_x, FRAME_CURSOR_X (selected_frame));
+      XSETFASTINT (w->last_point_y, FRAME_CURSOR_Y (selected_frame));
 
       if (all_windows)
        mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
       else
        {
          w->update_mode_line = Qnil;
-         XFASTINT (w->last_modified) = BUF_MODIFF (b);
-         w->window_end_valid = Qt;
+         XSETFASTINT (w->last_modified, BUF_MODIFF (b));
+         w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
+         if (do_verify_charstarts)
+           verify_charstarts (w);
+         if (frame_up_to_date_hook != 0)
+           (*frame_up_to_date_hook) (selected_frame);
        }
       update_mode_lines = 0;
       windows_or_buffers_changed = 0;
@@ -824,6 +906,11 @@ update:
 
   /* Change frame size now if a change is pending.  */
   do_pending_window_change ();
+
+  /* If we just did a pending size change, redisplay again
+     for the new size.  */
+  if (windows_or_buffers_changed && !pause)
+    redisplay ();
 }
 
 /* Redisplay, but leave alone any recent echo area message
@@ -855,15 +942,13 @@ mark_window_display_accurate (window, flag)
 
   for (;!NILP (window); window = w->next)
     {
-      if (XTYPE (window) != Lisp_Window) abort ();
+      if (!WINDOWP (window)) abort ();
       w = XWINDOW (window);
 
       if (!NILP (w->buffer))
        {
-         XFASTINT (w->last_modified)
-           = !flag ? 0
-             : XBUFFER (w->buffer) == current_buffer
-               ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
+         XSETFASTINT (w->last_modified,
+                      !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
 
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
@@ -873,7 +958,7 @@ mark_window_display_accurate (window, flag)
                               : Qnil);
        }
 
-      w->window_end_valid = Qt;
+      w->window_end_valid = w->buffer;
       w->update_mode_line = Qnil;
 
       if (!NILP (w->vchild))
@@ -895,55 +980,30 @@ mark_window_display_accurate (window, flag)
     }
 }
 \f
-/* Update the menu bar item lists for WINDOW
-   and its subwindows and siblings.
+/* 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.  */
 
 static void
-update_menu_bars (window)
-     Lisp_Object window;
-{
-  for (; !NILP (window); window = XWINDOW (window)->next)
-    update_menu_bar (window);
-}
-
-/* Update the menu bar item list for window WINDOW and its subwindows.  */
-
-static void
-update_menu_bar (window)
-     Lisp_Object window;
+update_menu_bar (f)
+     FRAME_PTR f;
 {
-  register struct window *w = XWINDOW (window);
   struct buffer *old = current_buffer;
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
-
-  /* If this is a combination window, do its children; that's all.  */
-
-  if (!NILP (w->vchild))
-    {
-      update_menu_bars (w->vchild);
-      return;
-    }
-  if (!NILP (w->hchild))
-    {
-      update_menu_bars (w->hchild);
-      return;
-    }
-  if (NILP (w->buffer))
-    abort ();
+  Lisp_Object window;
+  register struct window *w;
+  window = FRAME_SELECTED_WINDOW (f);
+  w = XWINDOW (window);
   
   if (update_mode_lines)
     w->update_mode_line = Qt;
 
-  /* When we reach a frame's selected window, redo the frame's menu bar.  */
-  if (!NILP (w->update_mode_line)
+  if (
 #ifdef USE_X_TOOLKIT
-      && FRAME_EXTERNAL_MENU_BAR (f) 
+      FRAME_EXTERNAL_MENU_BAR (f) 
 #else
-      && FRAME_MENU_BAR_LINES (f) > 0
+      FRAME_MENU_BAR_LINES (f) > 0
 #endif
-      && EQ (FRAME_SELECTED_WINDOW (f), window))
+      )
     {
       /* If the user has switched buffers or windows, we need to
         recompute to reflect the new bindings.  But we'll
@@ -953,17 +1013,18 @@ update_menu_bar (window)
         the rest of the redisplay algorithm is about the same as
         windows_or_buffers_changed anyway.  */
       if (windows_or_buffers_changed
-         || update_mode_lines
+         || !NILP (w->update_mode_line)
          || (XFASTINT (w->last_modified) < MODIFF
              && (XFASTINT (w->last_modified)
-                 <= XBUFFER (w->buffer)->save_modified)))
+                 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer)))))
        {
          struct buffer *prev = current_buffer;
+         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));
          current_buffer = prev;
 #ifdef USE_X_TOOLKIT
-         set_frame_menubar (f);
+         set_frame_menubar (f, 0);
 #endif /* USE_X_TOOLKIT */
        }
     }
@@ -991,13 +1052,13 @@ redisplay_window (window, just_this_one)
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
   int height;
-  register int lpoint = point;
+  register int lpoint = PT;
   struct buffer *old = current_buffer;
   register int width = window_internal_width (w) - 1;
   register int startp;
   register int hscroll = XINT (w->hscroll);
   struct position pos;
-  int opoint = point;
+  int opoint = PT;
   int tem;
   int window_needs_modeline;
 
@@ -1050,31 +1111,62 @@ redisplay_window (window, just_this_one)
 
   /* Otherwise set up data on this window; select its buffer and point value */
 
-  current_buffer = XBUFFER (w->buffer);
-  opoint = point;
+  set_buffer_temp (XBUFFER (w->buffer));
+  opoint = PT;
 
-  /* Count number of windows showing the selected buffer.  */
+  /* Count number of windows showing the selected buffer.
+     An indirect buffer counts as its base buffer.  */
 
-  if (!just_this_one
-      && current_buffer == XBUFFER (XWINDOW (selected_window)->buffer))
-    buffer_shared++;
+  if (!just_this_one)
+    {
+      struct buffer *current_base, *window_base;
+      current_base = current_buffer;
+      window_base = XBUFFER (XWINDOW (selected_window)->buffer);
+      if (current_base->base_buffer)
+       current_base = current_base->base_buffer;
+      if (window_base->base_buffer)
+       window_base = window_base->base_buffer;
+      if (current_base == window_base)
+       buffer_shared++;
+    }
 
   /* POINT refers normally to the selected window.
      For any other window, set up appropriate value.  */
 
   if (!EQ (window, selected_window))
     {
-      SET_PT (marker_position (w->pointm));
-      if (point < BEGV)
+      int new_pt = marker_position (w->pointm);
+      if (new_pt < BEGV)
        {
-         SET_PT (BEGV);
-         Fset_marker (w->pointm, make_number (point), Qnil);
+         new_pt = BEGV;
+         Fset_marker (w->pointm, make_number (new_pt), Qnil);
        }
-      else if (point > (ZV - 1))
+      else if (new_pt > (ZV - 1))
        {
-         SET_PT (ZV);
-         Fset_marker (w->pointm, make_number (point), Qnil);
+         new_pt = ZV;
+         Fset_marker (w->pointm, make_number (new_pt), Qnil);
        }
+      /* We don't use SET_PT so that the point-motion hooks don't run.  */
+      BUF_PT (current_buffer) = new_pt;
+    }
+
+  /* If any of the character widths specified in the display table
+     have changed, invalidate the width run cache.  It's true that this
+     may be a bit late to catch such changes, but the rest of
+     redisplay goes (non-fatally) haywire when the display table is
+     changed, so why should we worry about doing any better?  */
+  if (current_buffer->width_run_cache)
+    {
+      struct Lisp_Vector *disptab = buffer_display_table ();
+
+      if (! disptab_matches_widthtab (disptab,
+                                      XVECTOR (current_buffer->width_table)))
+        {
+          invalidate_region_cache (current_buffer,
+                                   current_buffer->width_run_cache,
+                                   BEG, Z);
+          recompute_width_table (current_buffer, disptab);
+        }
     }
 
   /* If window-start is screwed up, choose a new one.  */
@@ -1091,13 +1183,12 @@ redisplay_window (window, just_this_one)
       w->base_line_number = Qnil;
       w->update_mode_line = Qt;
       w->force_start = Qnil;
-      XFASTINT (w->last_modified) = 0;
+      XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
       if (startp > ZV)   startp = ZV;
       try_window (window, startp);
       if (cursor_vpos < 0)
        {
-         /* ??? What should happen here if highlighting a region?  */
          /* If point does not appear, move point so it does appear */
          pos = *compute_motion (startp, 0,
                                ((EQ (window, minibuf_window) && startp == 1)
@@ -1106,17 +1197,25 @@ redisplay_window (window, just_this_one)
                                (hscroll ? 1 - hscroll : 0),
                                ZV, height / 2,
                                - (1 << (SHORTBITS - 1)),
-                               width, hscroll, pos_tab_offset (w, startp));
-         SET_PT (pos.bufpos);
+                               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 (point), Qnil);
+           Fset_marker (w->pointm, make_number (PT), Qnil);
          else
            {
              if (current_buffer == old)
-               lpoint = point;
+               lpoint = PT;
              FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
+         /* If we are highlighting the region,
+            then we just changed the region, so redisplay to show it.  */
+         if (!NILP (Vtransient_mark_mode)
+             && !NILP (current_buffer->mark_active))
+           {
+             cancel_my_columns (XWINDOW (window));
+             try_window (window, startp);
+           }
        }
       goto done;
     }
@@ -1132,16 +1231,19 @@ redisplay_window (window, just_this_one)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
-      && point >= startp && !clip_changed
+      && PT >= startp && !clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
       /* Can't use this case if highlighting a region.  */
       && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
       && NILP (w->region_showing)
+      /* If end pos is out of date, scroll bar and percentage will be wrong */
+      && INTEGERP (w->window_end_vpos)
+      && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
       && !EQ (window, minibuf_window))
     {
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
-                           point, height + 1, 10000, width, hscroll,
-                           pos_tab_offset (w, startp));
+                           PT, height + 1, 10000, width, hscroll,
+                           pos_tab_offset (w, startp), w);
 
       if (pos.vpos < height)
        {
@@ -1167,13 +1269,13 @@ redisplay_window (window, just_this_one)
   /* 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)
-          && !(startp == BEGV
+          && !(startp <= BEGV
                || FETCH_CHAR (startp - 1) == '\n'))
     {
       goto recenter;
     }
   else if (just_this_one && !MINI_WINDOW_P (w)
-          && point >= startp
+          && PT >= startp
           && XFASTINT (w->last_modified)
           /* or else vmotion on first line won't work.  */
           && ! NILP (w->start_at_line_beg)
@@ -1216,14 +1318,14 @@ redisplay_window (window, just_this_one)
        cancel_my_columns (w);
     }
 
-  XFASTINT (w->last_modified) = 0;
+  XSETFASTINT (w->last_modified, 0);
   w->update_mode_line = Qt;
 
   /* Try to scroll by specified few lines */
 
   if (scroll_step && !clip_changed)
     {
-      if (point > startp)
+      if (PT > startp)
        {
          pos = *vmotion (Z - XFASTINT (w->window_end_pos),
                          scroll_step, width, hscroll, window);
@@ -1231,10 +1333,10 @@ redisplay_window (window, just_this_one)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
+      pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
                      width, hscroll, window);
 
-      if (point >= pos.bufpos)
+      if (PT >= pos.bufpos)
        {
          try_window (window, pos.bufpos);
          if (cursor_vpos >= 0)
@@ -1256,19 +1358,19 @@ recenter:
   /* Forget any previously recorded base line for line number display.  */
   w->base_line_number = Qnil;
 
-  pos = *vmotion (point, - (height / 2), width, hscroll, window);
+  pos = *vmotion (PT, - (height / 2), width, hscroll, window);
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
-  w->start_at_line_beg 
-    (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
+  w->start_at_line_beg 
+    (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
   if ((!NILP (w->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)
-       || INTEGERP (w->base_line_pos))
+       || INTEGERP (w->base_line_pos) || column_number_displayed)
       && height != XFASTINT (w->height))
     display_mode_line (w);
   if (! line_number_displayed
@@ -1323,9 +1425,9 @@ done:
       (*redeem_scroll_bar_hook) (w);
     }
 
-  SET_PT (opoint);
-  current_buffer = old;
-  SET_PT (lpoint);
+  BUF_PT (current_buffer) = opoint;
+  set_buffer_temp (old);
+  BUF_PT (current_buffer) = lpoint;
 }
 \f
 /* Do full redisplay on one window, starting at position `pos'. */
@@ -1379,8 +1481,8 @@ try_window (window, pos)
     w->update_mode_line = Qt;
 
   /* Say where last char on frame will be, once redisplay is finished.  */
-  XFASTINT (w->window_end_pos) = Z - pos;
-  XFASTINT (w->window_end_vpos) = last_text_vpos - XFASTINT (w->top);
+  XSETFASTINT (w->window_end_pos, Z - pos);
+  XSETFASTINT (w->window_end_vpos, last_text_vpos - XFASTINT (w->top));
   /* But that is not valid info until redisplay finishes.  */
   w->window_end_valid = Qnil;
 }
@@ -1409,10 +1511,9 @@ try_window_id (window)
   register int i, tem;
   int last_text_vpos = 0;
   int stop_vpos;
-  int selective
-    = XTYPE (current_buffer->selective_display) == Lisp_Int
-      ? XINT (current_buffer->selective_display)
-       : !NILP (current_buffer->selective_display) ? -1 : 0;
+  int selective = (INTEGERP (current_buffer->selective_display)
+                  ? XINT (current_buffer->selective_display)
+                  : !NILP (current_buffer->selective_display) ? -1 : 0);
 
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
@@ -1430,10 +1531,10 @@ 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,
-                       width, hscroll, pos_tab_offset (w, start));
+                       width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
-      if (point < bp.bufpos && !bp.contin)
+      if (PT < bp.bufpos && !bp.contin)
        {
          /* All changes are below the frame, and point is on the frame.
             We don't need to change the frame at all.
@@ -1441,9 +1542,9 @@ try_window_id (window)
             any change in buffer size.  */
          bp = *compute_motion (start, 0, lmargin,
                                Z, height, 0,
-                               width, hscroll, pos_tab_offset (w, start));
-         XFASTINT (w->window_end_vpos) = height;
-         XFASTINT (w->window_end_pos) = Z - bp.bufpos;
+                               width, hscroll, pos_tab_offset (w, start), w);
+         XSETFASTINT (w->window_end_vpos, height);
+         XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
          return 1;
        }
       return 0;
@@ -1489,7 +1590,7 @@ try_window_id (window)
   /* Compute the cursor position after that newline.  */
   ep = *compute_motion (pos, vpos, val.hpos, tem,
                        height, - (1 << (SHORTBITS - 1)),
-                       width, hscroll, pos_tab_offset (w, bp.bufpos));
+                       width, hscroll, pos_tab_offset (w, bp.bufpos), w);
 
   /* If changes reach past the text available on the frame,
      just display rest of frame.  */
@@ -1520,7 +1621,7 @@ try_window_id (window)
       epto = pos_tab_offset (w, ep.bufpos);
       xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
                            Z - XFASTINT (w->window_end_pos),
-                           10000, 0, width, hscroll, epto);
+                           10000, 0, width, hscroll, epto, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
 
       /* Is everything on frame below the changes whitespace?
@@ -1534,24 +1635,26 @@ try_window_id (window)
       if (i == xp.bufpos)
        return -2;
 
-      XFASTINT (w->window_end_vpos) += scroll_amount;
+      XSETFASTINT (w->window_end_vpos,
+                  XFASTINT (w->window_end_vpos) + scroll_amount);
 
       /* Before doing any scrolling, verify that point will be on frame. */
-      if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
+      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
        {
-         if (point <= xp.bufpos)
+         if (PT <= xp.bufpos)
            {
              pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
-                                   point, height, - (1 << (SHORTBITS - 1)),
-                                   width, hscroll, epto);
+                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   width, hscroll, epto, w);
            }
          else
            {
              pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
-                                   point, height, - (1 << (SHORTBITS - 1)),
-                                   width, hscroll, pos_tab_offset (w, xp.bufpos));
+                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   width, hscroll,
+                                   pos_tab_offset (w, xp.bufpos), w);
            }
-         if (pp.bufpos < point || pp.vpos == height)
+         if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
          cursor_hpos = pp.hpos + XFASTINT (w->left);
@@ -1572,7 +1675,14 @@ try_window_id (window)
          blank_end_of_window = 1;
        }
       else if (!scroll_amount)
-       {}
+       {
+         /* Even if we don't need to scroll, we must adjust the
+            charstarts of subsequent lines (that we won't redisplay)
+            according to the amount of text inserted or deleted.  */
+         int oldpos = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
+         int adjust = ep.bufpos - oldpos;
+         adjust_window_charstarts (w, ep.vpos + top - 1, adjust);
+       }
       else if (bp.bufpos == Z - end_unchanged)
        {
          /* If reprinting everything is nearly as fast as scrolling,
@@ -1589,9 +1699,26 @@ try_window_id (window)
             following line from being overwritten by scrolling
             and therefore having to be redrawn.  */
          tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
-                                    top + height - max (0, scroll_amount),
-                                    scroll_amount);
-         if (!tem) stop_vpos = height;
+                                   top + height - max (0, scroll_amount),
+                                   scroll_amount, bp.bufpos);
+         if (!tem)
+           stop_vpos = height;
+         else
+           {
+             /* scroll_frame_lines did not properly adjust subsequent
+                lines' charstarts in the case where the text of the
+                screen line at bp.vpos has changed.
+                (This can happen in a deletion that ends in mid-line.)
+                To adjust properly, we need to make things constent at
+                the position ep.
+                So do a second adjust to make that happen.
+                Note that stop_vpos >= ep.vpos, so it is sufficient
+                to update the charstarts for lines at ep.vpos and below.  */
+             int oldstart
+               = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
+             adjust_window_charstarts (w, ep.vpos + top - 1,
+                                       ep.bufpos - oldstart);
+           }
        }
       else if (scroll_amount)
        {
@@ -1609,7 +1736,7 @@ try_window_id (window)
            return -2;
          tem = scroll_frame_lines (f, ep.vpos + top - scroll_amount,
                                     top + height - max (0, scroll_amount),
-                                    scroll_amount);
+                                    scroll_amount, ep.bufpos);
          if (!tem) stop_vpos = height;
        }
     }
@@ -1655,8 +1782,8 @@ try_window_id (window)
         include the split character in the text considered on the frame */
       if (val.hpos < lmargin)
        val.bufpos++;
-      XFASTINT (w->window_end_vpos) = last_text_vpos;
-      XFASTINT (w->window_end_pos) = Z - val.bufpos;
+      XSETFASTINT (w->window_end_vpos, last_text_vpos);
+      XSETFASTINT (w->window_end_pos, Z - val.bufpos);
     }
 
   /* If scrolling made blank lines at window bottom,
@@ -1695,7 +1822,7 @@ try_window_id (window)
       /* Here is a case where display_text_line sets cursor_vpos wrong.
         Make it be fixed up, below.  */
       if (xp.bufpos == ZV
-         && xp.bufpos == point)
+         && xp.bufpos == PT)
        cursor_vpos = -1;
     }
 
@@ -1714,8 +1841,9 @@ try_window_id (window)
        {
          val = *vmotion (Z - XFASTINT (w->window_end_pos),
                          delta, width, hscroll, window);
-         XFASTINT (w->window_end_pos) = Z - val.bufpos;
-         XFASTINT (w->window_end_vpos) += val.vpos;
+         XSETFASTINT (w->window_end_pos, Z - val.bufpos);
+         XSETFASTINT (w->window_end_vpos,
+                      XFASTINT (w->window_end_vpos) + val.vpos);
        }
     }
 
@@ -1724,8 +1852,8 @@ try_window_id (window)
   /* If point was not in a line that was displayed, find it */
   if (cursor_vpos < 0)
     {
-      val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
-                            width, hscroll, pos_tab_offset (w, start));
+      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 */
       if (val.vpos >= height)
        {
@@ -1744,7 +1872,7 @@ try_window_id (window)
     {
       val = *compute_motion (start, 0, lmargin, ZV,
                             height, - (1 << (SHORTBITS - 1)),
-                            width, hscroll, pos_tab_offset (w, start));
+                            width, hscroll, pos_tab_offset (w, start), w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
        abort ();
       if (XFASTINT (w->window_end_pos)
@@ -1788,7 +1916,15 @@ redisplay_region (buf, start, end)
       start = end; end = temp;
     }
 
-  if (buf != current_buffer)
+  /* If this is a buffer not in the selected window,
+     we must do other windows.  */
+  if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
+    windows_or_buffers_changed = 1;
+  /* If it's not current, we can't use beg_unchanged, end_unchanged for it.  */
+  else if (buf != current_buffer)
+    windows_or_buffers_changed = 1;
+  /* If multiple windows show this buffer, we must do other windows.  */
+  else if (buffer_shared > 1)
     windows_or_buffers_changed = 1;
   else
     {
@@ -1807,9 +1943,9 @@ redisplay_region (buf, start, end)
     }
 
   /* Increment the buffer's time stamp, but also increment the save
-     and autosave timestamps, so as not to screw up that timekeeping. */
-  if (BUF_MODIFF (buf) == buf->save_modified)
-    buf->save_modified++;
+     and autosave timestamps, so as not to screw up that timekeeping.  */
+  if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
+    BUF_SAVE_MODIFF (buf)++;
   if (BUF_MODIFF (buf) == buf->auto_save_modified)
     buf->auto_save_modified++;
 
@@ -1837,11 +1973,11 @@ copy_part_of_rope (f, to, s, from, len, face)
   int last_code = -1;
   int last_merged = 0;
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
   if (! FRAME_TERMCAP_P (f))
     while (n--)
       {
-       int glyph = XFASTINT (*fp);
+       int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        int facecode;
 
        if (FAST_GLYPH_FACE (glyph) == 0)
@@ -1866,7 +2002,7 @@ copy_part_of_rope (f, to, s, from, len, face)
 #endif
     while (n--)
       {
-       if (to >= s) *to = XFASTINT (*fp);
+       if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        ++to;
        ++fp;
       }
@@ -1877,29 +2013,36 @@ copy_part_of_rope (f, to, s, from, len, face)
    with a displayable computed face code.  */
 
 static GLYPH
-fix_glyph (f, glyph, current_face)
+fix_glyph (f, glyph, cface)
      FRAME_PTR f;
      GLYPH glyph;
-     int current_face;
+     int cface;
 {
-#ifdef HAVE_X_WINDOWS
-  if (! FRAME_TERMCAP_P (f) && FAST_GLYPH_FACE (glyph) != 0)
-    return FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph),
-                           compute_glyph_face (f, FAST_GLYPH_FACE (glyph),
-                                               current_face));
+#ifdef HAVE_FACES
+  if (! FRAME_TERMCAP_P (f))
+    {
+      if (FAST_GLYPH_FACE (glyph) != 0)
+       cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
+      glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
+    }
 #endif
   return glyph;
 }
 \f
-/* Display one line of window w, starting at position START in W's buffer.
-   Display starting at horizontal position HPOS, which is normally zero
-   or negative.  A negative value causes output up to hpos = 0 to be discarded.
-   This is done for negative hscroll, or when this is a continuation line
-   and the continuation occurred in the middle of a multi-column character.
+/* Display one line of window W, starting at position START in W's buffer.
+
+   Display starting at horizontal position HPOS, expressed relative to
+   W's left edge.  In situations where the text at START shouldn't
+   start at the left margin (i.e. when the window is hscrolled, or
+   we're continuing a line which left off in the midst of a
+   multi-column character), HPOS should be negative; we throw away
+   characters up 'til hpos = 0.  So, HPOS must take hscrolling into
+   account.
 
    TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
 
-   Display on position VPOS on the frame.  (origin 0).
+   Display on position VPOS on the frame.  It is origin 0, relative to
+   the top of the frame, not W.
 
    Returns a STRUCT POSITION giving character to start next line with
    and where to display it, including a zero or negative hpos.
@@ -1922,8 +2065,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register int pause;
   register unsigned char *p;
   GLYPH *endp;
-  register GLYPH *startp;
+  register GLYPH *leftmargin;
   register GLYPH *p1prev = 0;
+  register GLYPH *p1start;
+  int *charstart;
   FRAME_PTR f = XFRAME (w->frame);
   int tab_width = XINT (current_buffer->tab_width);
   int ctl_arrow = !NILP (current_buffer->ctl_arrow);
@@ -1932,20 +2077,19 @@ display_text_line (w, start, vpos, hpos, taboffset)
   int lastpos;
   int invis;
   int hscroll = XINT (w->hscroll);
-  int truncate = hscroll
-    || (truncate_partial_width_windows
-       && XFASTINT (w->width) < FRAME_WIDTH (f))
-    || !NILP (current_buffer->truncate_lines);
+  int truncate = (hscroll
+                 || (truncate_partial_width_windows
+                     && XFASTINT (w->width) < FRAME_WIDTH (f))
+                 || !NILP (current_buffer->truncate_lines));
 
   /* 1 if we should highlight the region.  */
   int highlight_region
     = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
   int region_beg, region_end;
 
-  int selective
-    = XTYPE (current_buffer->selective_display) == Lisp_Int
-      ? XINT (current_buffer->selective_display)
-       : !NILP (current_buffer->selective_display) ? -1 : 0;
+  int selective = (INTEGERP (current_buffer->selective_display)
+                  ? XINT (current_buffer->selective_display)
+                  : !NILP (current_buffer->selective_display) ? -1 : 0);
   register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
   register struct Lisp_Vector *dp = window_display_table (w);
 
@@ -1953,20 +2097,20 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* Nonzero means display something where there are invisible lines.
      The precise value is the number of glyphs to display.  */
   int selective_rlen
-    = (selective && dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
+    = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
        ? XVECTOR (DISP_INVIS_VECTOR (dp))->size
        : selective && !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
-    = (dp && XTYPE (DISP_INVIS_VECTOR (dp)) == Lisp_Vector
+    = (dp && VECTORP (DISP_INVIS_VECTOR (dp))
        ? XVECTOR (DISP_INVIS_VECTOR (dp))->contents
        : default_invis_vector);
 
-  GLYPH truncator = (dp == 0 || XTYPE (DISP_TRUNC_GLYPH (dp)) != Lisp_Int
+  GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
                     ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
-  GLYPH continuer = (dp == 0 || XTYPE (DISP_CONTINUE_GLYPH (dp)) != Lisp_Int
+  GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
                     ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
 
   /* The next buffer location at which the face should change, due
@@ -1980,8 +2124,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
   
   /* The face we're currently using.  */
   int current_face = 0;
+  int i;
 
-  XFASTINT (default_invis_vector[2]) = '.';
+  XSETFASTINT (default_invis_vector[2], '.');
   default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
 
   hpos += XFASTINT (w->left);
@@ -2007,21 +2152,70 @@ display_text_line (w, start, vpos, hpos, taboffset)
   else
     region_beg = region_end = -1;
 
-  if (MINI_WINDOW_P (w) && start == 1
+  if (MINI_WINDOW_P (w)
+      && start == 1
       && vpos == XFASTINT (w->top))
     {
-      if (minibuf_prompt)
-       hpos = display_string (w, vpos, minibuf_prompt, -1, hpos,
-                              (!truncate ? continuer : truncator),
-                              1, -1, -1);
-      minibuf_prompt_width = hpos;
+      if (! NILP (minibuf_prompt))
+       {
+         minibuf_prompt_width
+           = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
+                              XSTRING (minibuf_prompt)->size, hpos,
+                              /* Display a space if we truncate.  */
+                              ' ',
+                              1, -1,
+                              /* Truncate the prompt a little before the
+                                 margin, so user input can at least start
+                                 on the first line.  */
+                              w->width > 10 ? w->width - 4 : -1)
+              - hpos);
+         hpos += minibuf_prompt_width;
+       }
+      else
+       minibuf_prompt_width = 0;
     }
 
-  desired_glyphs->bufp[vpos] = pos;
-  p1 = desired_glyphs->glyphs[vpos] + hpos;
   end = ZV;
-  startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
-  endp = startp + width;
+
+  /* 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,
+                          width, hscroll, taboffset, w);
+
+      /* Retrieve the buffer position and column provided by
+         compute_motion.  We can't assume that the column will be
+         zero, because you may have multi-column characters crossing
+         the left margin.  
+
+         compute_motion may have moved us past the screen position we
+         requested, if we hit a multi-column character, or the end of
+         the line.  If so, back up.  */
+      if (left_edge->vpos > vpos
+          || left_edge->hpos > 0)
+        {
+          pos = left_edge->bufpos - 1;
+          hpos = left_edge->prevhpos;
+        }
+      else
+        {
+          pos = left_edge->bufpos;
+          hpos = left_edge->hpos;
+        }
+    }
+
+  desired_glyphs->bufp[vpos] = start;
+  p1 = desired_glyphs->glyphs[vpos] + hpos;
+  p1start = p1;
+  charstart = desired_glyphs->charstarts[vpos] + hpos;
+  /* In case we don't ever write anything into it...  */
+  desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
+  leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+  endp = leftmargin + width;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
      display_text_line on only one line at a time, in which case this
@@ -2039,8 +2233,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
 #ifdef USE_TEXT_PROPERTIES
   next_invisible = pos;
 #endif
-  while (p1 < endp)
+  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)
        {
@@ -2050,10 +2252,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
            break;
 
          /* Did we reach point?  Record the cursor location.  */
-         if (pos == point && cursor_vpos < 0)
+         if (pos == PT && cursor_vpos < 0)
            {
              cursor_vpos = vpos;
-             cursor_hpos = p1 - startp;
+             cursor_hpos = p1 - leftmargin;
            }
 
 #ifdef USE_TEXT_PROPERTIES
@@ -2062,14 +2264,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
          while (pos == next_invisible && pos < end)
            {
              Lisp_Object position, limit, endpos, prop, ww;
-             XFASTINT (position) = pos;
-             XSET (ww, Lisp_Window, w);
+             XSETFASTINT (position, pos);
+             XSETWINDOW (ww, w);
              prop = Fget_char_property (position, Qinvisible, ww);
              /* 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)
-               XFASTINT (limit) = pos + 50;
+               XSETFASTINT (limit, pos + 50);
              endpos = Fnext_single_property_change (position, Qinvisible,
                                                Fcurrent_buffer (), limit);
              if (INTEGERP (endpos))
@@ -2078,10 +2280,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
                next_invisible = end;
              if (! NILP (prop))
                {
-                 if (pos < point && next_invisible >= point)
+                 if (pos < PT && next_invisible >= PT)
                    {
                      cursor_vpos = vpos;
-                     cursor_hpos = p1 - startp;
+                     cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_invisible;
                }
@@ -2090,14 +2292,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
            break;
 #endif
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Did we hit a face change?  Figure out what face we should
             use now.  We also hit this the first time through the
             loop, to see what face we should start with.  */
          if (pos >= next_face_change && FRAME_X_P (f))
            current_face = compute_char_face (f, w, pos,
                                              region_beg, region_end,
-                                             &next_face_change, pos + 50);
+                                             &next_face_change, pos + 50, 0);
 #endif
 
          pause = end;
@@ -2111,8 +2313,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
          /* Wouldn't you hate to read the next line to someone over
              the phone?  */
-         if (pos < point && point < pause)
-           pause = point;
+         if (pos < PT && PT < pause)
+           pause = PT;
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
@@ -2120,16 +2322,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
        }
       c = *p++;
       if (c >= 040 && c < 0177
-         && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
+         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
        {
-         if (p1 >= startp)
+         if (p1 >= leftmargin)
            *p1 = MAKE_GLYPH (f, c, current_face);
          p1++;
        }
       else if (c == '\n')
        {
          invis = 0;
-         while (pos < end
+         while (pos + 1 < end
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
            {
@@ -2138,20 +2340,24 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (FETCH_CHAR (pos - 1) == '\n')
                pos--;
            }
-         if (invis && selective_rlen > 0 && p1 >= startp)
+         if (invis && selective_rlen > 0 && p1 >= leftmargin)
            {
              p1 += selective_rlen;
-             if (p1 - startp > width)
+             if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
             way to the end of the frame line.  */
          if (current_face)
-           while (p1 < endp)
-             *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+           {
+             if (p1 < leftmargin)
+               p1 = leftmargin;
+             while (p1 < endp)
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+           }
 #endif
          break;
        }
@@ -2159,11 +2365,11 @@ display_text_line (w, start, vpos, hpos, taboffset)
        {
          do
            {
-             if (p1 >= startp && p1 < endp)
+             if (p1 >= leftmargin && p1 < endp)
                *p1 = MAKE_GLYPH (f, ' ', current_face);
              p1++;
            }
-         while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
+         while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
                 % tab_width);
        }
       else if (c == Ctl ('M') && selective == -1)
@@ -2174,56 +2380,85 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (selective_rlen > 0)
            {
              p1 += selective_rlen;
-             if (p1 - startp > width)
+             if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
             way to the end of the frame line.  */
          if (current_face)
-           while (p1 < endp)
-             *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+           {
+             if (p1 < leftmargin)
+               p1 = leftmargin;
+             while (p1 < endp)
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+           }
 #endif
          break;
        }
-      else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
+      else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
-         p1 = copy_part_of_rope (f, p1, startp,
+         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 >= startp)
-           *p1 = fix_glyph (f, (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
+         if (p1 >= leftmargin)
+           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
                                 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
                             current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
          p1++;
        }
       else
        {
-         if (p1 >= startp)
-           *p1 = fix_glyph (f, (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
+         if (p1 >= leftmargin)
+           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
                                 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
                             current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
          p1++;
        }
 
+      /* 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.  */
+         if (p1 != p1prev)
+           {
+             int *p2x = &charstart[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;
+           }
+       }
+
       pos++;
     }
 
@@ -2235,6 +2470,18 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   lastpos = pos;
 
+  /* Store 0 in this charstart line for the positions where
+     there is no character.  But do leave what was recorded
+     for the character that ended the line.  */
+  /* Add 1 in the endtest to compensate for the fact that ENDP was
+     made from WIDTH, which is 1 less than the window's actual
+     internal width.  */
+  i = p1 - p1start + 1;
+  if (p1 < leftmargin)
+    i += leftmargin - p1;
+  for (; i < endp - p1start + 1; i++)
+    charstart[i] = 0;
+
   /* Handle continuation in middle of a character */
   /* by backing up over it */
   if (p1 > endp)
@@ -2261,8 +2508,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
   if (pos < ZV)
     {
       if (FETCH_CHAR (pos) == '\n')
-       /* If stopped due to a newline, start next line after it */
-       pos++;
+       {
+         /* If stopped due to a newline, start next line after it */
+         pos++;
+         /* Check again for hidden lines, in case the newline occurred exactly
+            at the right margin.  */
+         while (pos < ZV && selective > 0
+                && indented_beyond_p (pos, selective))
+           pos = find_next_newline (pos, 1);
+       }
       else
        /* Stopped due to right margin of window */
        {
@@ -2272,7 +2526,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
              /* Truncating => start next line after next newline,
                 and point is on this line if it is before the newline,
                 and skip none of first char of next line */
-             pos = find_next_newline (pos, 1);
+             do
+               pos = find_next_newline (pos, 1);
+             while (pos < ZV && selective > 0
+                    && indented_beyond_p (pos, selective));
              val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
 
              lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
@@ -2289,10 +2546,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If point is at eol or in invisible text at eol,
      record its frame location now.  */
 
-  if (start <= point && point <= lastpos && cursor_vpos < 0)
+  if (start <= PT && PT <= lastpos && cursor_vpos < 0)
     {
       cursor_vpos = vpos;
-      cursor_hpos = p1 - startp;
+      cursor_hpos = p1 - leftmargin;
     }
 
   if (cursor_vpos == vpos)
@@ -2328,15 +2585,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If hscroll and line not empty, insert truncation-at-left marker */
   if (hscroll && lastpos != start)
     {
-      *startp = fix_glyph (f, truncator, 0);
-      if (p1 <= startp)
-       p1 = startp + 1;
+      *leftmargin = fix_glyph (f, truncator, 0);
+      if (p1 <= leftmargin)
+       p1 = leftmargin + 1;
     }
 
   if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
     {
       endp++;
-      if (p1 < startp) p1 = startp;
+      if (p1 < leftmargin) p1 = leftmargin;
       while (p1 < endp) *p1++ = SPACEGLYPH;
 
       /* Don't draw vertical bars if we're using scroll bars.  They're
@@ -2344,7 +2601,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
          them when the scroll bar windows are flickering around to be
          reconfigured.  */
       *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
-              ? ' ' : '|');
+              ? ' '
+              : (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
+                 ? DISP_BORDER_GLYPH (dp)
+                 : '|'));
     }
   desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
                                   p1 - desired_glyphs->glyphs[vpos]);
@@ -2353,10 +2613,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If the start of this line is the overlay arrow-position,
      then put the arrow string into the display-line.  */
 
-  if (XTYPE (Voverlay_arrow_position) == Lisp_Marker
+  if (MARKERP (Voverlay_arrow_position)
       && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
       && start == marker_position (Voverlay_arrow_position)
-      && XTYPE (Voverlay_arrow_string) == Lisp_String
+      && STRINGP (Voverlay_arrow_string)
       && ! overlay_arrow_seen)
     {
       unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
@@ -2366,11 +2626,31 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
       if (len > width)
        len = width;
-      for (i = 0; i < len; i++)
-       startp[i] = p[i];
+#ifdef HAVE_FACES
+      if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
+       {
+         /* If the arrow string has text props, obey them when displaying.  */
+         for (i = 0; i < len; i++)
+           {
+             int c = p[i];
+             Lisp_Object face, ilisp;
+             int newface;
+
+             XSETFASTINT (ilisp, i);
+             face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
+             newface = compute_glyph_face_1 (f, face, 0);
+             leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
+           }
+       }
+      else
+#endif /* HAVE_FACES */
+       {
+         for (i = 0; i < len; i++)
+           leftmargin[i] = p[i];
+       }
 
       /* Bug in SunOS 4.1.1 compiler requires this intermediate variable.  */
-      arrow_end = (startp - desired_glyphs->glyphs[vpos]) + len;
+      arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
       if (desired_glyphs->used[vpos] < arrow_end)
        desired_glyphs->used[vpos] = arrow_end;
 
@@ -2409,7 +2689,7 @@ display_menu_bar (w)
       if (NILP (string))
        break;
 
-      XFASTINT (XVECTOR (items)->contents[i + 2]) = hpos;
+      XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
 
       if (hpos < maxendcol)
        hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
@@ -2451,6 +2731,7 @@ display_mode_line (w)
   register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
 
   line_number_displayed = 0;
+  column_number_displayed = 0;
 
   get_display_line (f, vpos, left);
   display_mode_element (w, vpos, left, 0, right, right,
@@ -2466,7 +2747,7 @@ display_mode_line (w)
   if (XFASTINT (w->width) == FRAME_WIDTH (f)
       || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
     FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_FACES
   else if (! FRAME_TERMCAP_P (f))
     {
       /* For a partial width window, explicitly set face of each glyph. */
@@ -2476,11 +2757,6 @@ display_mode_line (w)
        ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
     }
 #endif
-
-#ifdef HAVE_X_WINDOWS
-  if (w == XWINDOW (f->selected_window))
-    x_consider_frame_title (WINDOW_FRAME (w));
-#endif
 }
 
 /* Contribute ELT to the mode line for window W.
@@ -2542,8 +2818,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
            if (this - 1 != last)
              {
                register int lim = --this - last + hpos;
-               hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
-                                      hpos, min (lim, maxendcol));
+               if (frame_title_ptr)
+                 hpos = store_frame_title (last, hpos, min (lim, maxendcol));
+               else
+                 hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
+                                        hpos, min (lim, maxendcol));
              }
            else /* c == '%' */
              {
@@ -2568,11 +2847,15 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                                               spec_width, maxendcol,
                                               Vglobal_mode_string);
                else if (c != 0)
-                 hpos = display_string (w, vpos,
-                                        decode_mode_spec (w, c,
-                                                          maxendcol - hpos),
-                                        -1,
-                                        hpos, 0, 1, spec_width, maxendcol);
+                 {
+                   char *spec = decode_mode_spec (w, c, maxendcol - hpos);
+                   if (frame_title_ptr)
+                     hpos = store_frame_title (spec, spec_width, maxendcol);
+                   else
+                     hpos = display_string (w, vpos, spec, -1,
+                                            hpos, 0, 1,
+                                            spec_width, maxendcol);
+                 }
              }
          }
       }
@@ -2591,10 +2874,16 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
            tem = Fsymbol_value (elt);
            /* If value is a string, output that string literally:
               don't check for % within it.  */
-           if (XTYPE (tem) == Lisp_String)
-             hpos = display_string (w, vpos, XSTRING (tem)->data,
-                                    XSTRING (tem)->size,
-                                    hpos, 0, 1, minendcol, maxendcol);
+           if (STRINGP (tem))
+             {
+               if (frame_title_ptr)
+                 hpos = store_frame_title (XSTRING (tem)->data,
+                                           minendcol, maxendcol);
+               else
+                 hpos = display_string (w, vpos, XSTRING (tem)->data,
+                                        XSTRING (tem)->size,
+                                        hpos, 0, 1, minendcol, maxendcol);
+             }
            /* Give up right away for nil or t.  */
            else if (!EQ (tem, elt))
              { elt = tem; goto tail_recurse; }
@@ -2615,11 +2904,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
           If first element is a symbol, process the cadr or caddr recursively
           according to whether the symbol's value is non-nil or nil.  */
        car = XCONS (elt)->car;
-       if (XTYPE (car) == Lisp_Symbol)
+       if (SYMBOLP (car))
          {
            tem = Fboundp (car);
            elt = XCONS (elt)->cdr;
-           if (XTYPE (elt) != Lisp_Cons)
+           if (!CONSP (elt))
              goto invalid;
            /* elt is now the cdr, and we know it is a cons cell.
               Use its car if CAR has a non-nil value.  */
@@ -2635,12 +2924,12 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
            elt = XCONS (elt)->cdr;
            if (NILP (elt))
              break;
-           else if (XTYPE (elt) != Lisp_Cons)
+           else if (!CONSP (elt))
              goto invalid;
            elt = XCONS (elt)->car;
            goto tail_recurse;
          }
-       else if (XTYPE (car) == Lisp_Int)
+       else if (INTEGERP (car))
          {
            register int lim = XINT (car);
            elt = XCONS (elt)->cdr;
@@ -2665,11 +2954,11 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
              }
            goto tail_recurse;
          }
-       else if (XTYPE (car) == Lisp_String || XTYPE (car) == Lisp_Cons)
+       else if (STRINGP (car) || CONSP (car))
          {
            register int limit = 50;
            /* LIMIT is to protect against circular lists.  */
-           while (XTYPE (elt) == Lisp_Cons && --limit > 0
+           while (CONSP (elt) && --limit > 0
                   && hpos < maxendcol)
              {
                hpos = display_mode_element (w, vpos, hpos, depth,
@@ -2683,13 +2972,19 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
 
     default:
     invalid:
-      return (display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
-                             minendcol, maxendcol));
+      if (frame_title_ptr)
+       hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
+      else
+       hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
+                              minendcol, maxendcol);
+      return hpos;
     }
 
- end:
   if (minendcol > hpos)
-    hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
+    if (frame_title_ptr)
+      hpos = store_frame_title ("", minendcol, maxendcol);
+    else
+      hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
   return hpos;
 }
 \f
@@ -2704,17 +2999,19 @@ decode_mode_spec (w, c, maxwidth)
      register char c;
      register int maxwidth;
 {
-  Lisp_Object obj = Qnil;
+  Lisp_Object obj;
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
   char *decode_mode_spec_buf = (char *) FRAME_TEMP_GLYPHS (f)->total_contents;
+  struct buffer *b = XBUFFER (w->buffer);
 
+  obj = Qnil;
   if (maxwidth > FRAME_WIDTH (f))
     maxwidth = FRAME_WIDTH (f);
 
   switch (c)
     {
     case 'b': 
-      obj = current_buffer->name;
+      obj = b->name;
 #if 0
       if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
        {
@@ -2727,11 +3024,11 @@ decode_mode_spec (w, c, maxwidth)
       break;
 
     case 'f': 
-      obj = current_buffer->filename;
+      obj = b->filename;
 #if 0
       if (NILP (obj))
        return "[none]";
-      else if (XTYPE (obj) == Lisp_String && XSTRING (obj)->size > maxwidth)
+      else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
        {
          bcopy ("...", decode_mode_spec_buf, 3);
          bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
@@ -2741,6 +3038,11 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
+    case 'c':
+      column_number_displayed = 1;
+      sprintf (decode_mode_spec_buf, "%d", current_column ());
+      return decode_mode_spec_buf;
+
     case 'l':
       {
        int startpos = marker_position (w->start);
@@ -2755,7 +3057,7 @@ decode_mode_spec (w, c, maxwidth)
          return "??";
 
        /* If the buffer is very big, don't waste time.  */
-       if (ZV - BEGV > line_number_display_limit)
+       if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
          {
            w->base_line_pos = Qnil;
            w->base_line_number = Qnil;
@@ -2772,7 +3074,7 @@ decode_mode_spec (w, c, maxwidth)
        else
          {
            line = 1;
-           linepos = BEGV;
+           linepos = BUF_BEGV (b);
          }
 
        /* Count lines from base line to window start position.  */
@@ -2784,15 +3086,15 @@ decode_mode_spec (w, c, maxwidth)
           or too far away, or if we did not have one.
           "Too close" means it's plausible a scroll-down would
           go back past it.  */
-       if (startpos == BEGV)
+       if (startpos == BUF_BEGV (b))
          {
-           XFASTINT (w->base_line_number) = topline;
-           XFASTINT (w->base_line_pos) = BEGV;
+           XSETFASTINT (w->base_line_number, topline);
+           XSETFASTINT (w->base_line_pos, BUF_BEGV (b));
          }
        else if (nlines < height + 25 || nlines > height * 3 + 50
-                || linepos == BEGV)
+                || linepos == BUF_BEGV (b))
          {
-           int limit = BEGV;
+           int limit = BUF_BEGV (b);
            int position;
            int distance = (height * 2 + 30) * 200;
 
@@ -2812,8 +3114,8 @@ decode_mode_spec (w, c, maxwidth)
                return "??";
              }
 
-           XFASTINT (w->base_line_number) = topline - nlines;
-           XFASTINT (w->base_line_pos) = position;
+           XSETFASTINT (w->base_line_number, topline - nlines);
+           XSETFASTINT (w->base_line_pos, position);
          }
 
        /* Now count lines from the start pos to point.  */
@@ -2829,29 +3131,38 @@ decode_mode_spec (w, c, maxwidth)
       break;
 
     case 'm': 
-      obj = current_buffer->mode_name;
+      obj = b->mode_name;
       break;
 
     case 'n':
-      if (BEGV > BEG || ZV < Z)
+      if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b))
        return " Narrow";
       break;
 
     case '*':
-      if (!NILP (current_buffer->read_only))
+      if (!NILP (b->read_only))
        return "%";
-      if (MODIFF > current_buffer->save_modified)
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
        return "*";
       return "-";
 
     case '+':
-      if (MODIFF > current_buffer->save_modified)
+      /* 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 (Fcurrent_buffer ());
+      obj = Fget_buffer_process (w->buffer);
       if (NILP (obj))
        return "no process";
 #ifdef subprocesses
@@ -2860,32 +3171,29 @@ decode_mode_spec (w, c, maxwidth)
       break;
 
     case 't':                  /* indicate TEXT or BINARY */
-#ifdef MSDOS
-      decode_mode_spec_buf[0]
-       = NILP (current_buffer->buffer_file_type) ? "T" : "B";
-      decode_mode_spec_buf[1] = 0;
-      return decode_mode_spec_buf;
-#else /* not MSDOS */
+#ifdef MODE_LINE_BINARY_TEXT
+      return MODE_LINE_BINARY_TEXT (b);
+#else
       return "T";
-#endif /* not MSDOS */
+#endif
 
     case 'p':
       {
        int pos = marker_position (w->start);
-       int total = ZV - BEGV;
+       int total = BUF_ZV (b) - BUF_BEGV (b);
 
-       if (XFASTINT (w->window_end_pos) <= Z - ZV)
+       if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
          {
-           if (pos <= BEGV)
+           if (pos <= BUF_BEGV (b))
              return "All";
            else
              return "Bottom";
          }
-       else if (pos <= BEGV)
+       else if (pos <= BUF_BEGV (b))
          return "Top";
        else
          {
-           total = ((pos - BEGV) * 100 + total - 1) / total;
+           total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
@@ -2899,24 +3207,24 @@ decode_mode_spec (w, c, maxwidth)
     case 'P':
       {
        int toppos = marker_position (w->start);
-       int botpos = Z - XFASTINT (w->window_end_pos);
-       int total = ZV - BEGV;
+       int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
+       int total = BUF_ZV (b) - BUF_BEGV (b);
 
-       if (botpos >= ZV)
+       if (botpos >= BUF_ZV (b))
          {
-           if (toppos <= BEGV)
+           if (toppos <= BUF_BEGV (b))
              return "All";
            else
              return "Bottom";
          }
        else
          {
-           total = ((botpos - BEGV) * 100 + total - 1) / total;
+           total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
              total = 99;
-           if (toppos <= BEGV)
+           if (toppos <= BUF_BEGV (b))
              sprintf (decode_mode_spec_buf, "Top%2d%%", total);
            else
              sprintf (decode_mode_spec_buf, "%2d%%", total);
@@ -2954,7 +3262,7 @@ decode_mode_spec (w, c, maxwidth)
        *p = 0;
        return decode_mode_spec_buf;
       }
-      
+
     case '-':
       {
        register char *p;
@@ -2971,12 +3279,113 @@ decode_mode_spec (w, c, maxwidth)
        return decode_mode_spec_buf;
       }
     }
-  
-  if (XTYPE (obj) == Lisp_String)
+
+  if (STRINGP (obj))
     return (char *) XSTRING (obj)->data;
   else
     return "";
 }
+\f
+/* Search for COUNT instances of a line boundary, which means either a
+   newline or (if selective display enabled) a carriage return.
+   Start at START.  If COUNT is negative, search backwards.
+
+   If we find COUNT instances, set *SHORTAGE to zero, and return the
+   position after the COUNTth match.  Note that for reverse motion
+   this is not the same as the usual convention for Emacs motion commands.
+
+   If we don't find COUNT instances before reaching the end of the
+   buffer (or the beginning, if scanning backwards), set *SHORTAGE to
+   the number of line boundaries left unfound, and return the end of the
+   buffer we bumped up against.  */
+
+static int
+display_scan_buffer (start, count, shortage)
+     int *shortage, start;
+     register int count;
+{
+  int limit = ((count > 0) ? ZV - 1 : BEGV);
+  int direction = ((count > 0) ? 1 : -1);
+
+  register unsigned char *cursor;
+  unsigned char *base;
+
+  register int ceiling;
+  register unsigned char *ceiling_addr;
+
+  /* If we are not in selective display mode,
+     check only for newlines.  */
+  if (! (!NILP (current_buffer->selective_display)
+        && !INTEGERP (current_buffer->selective_display)))
+    return scan_buffer ('\n', start, 0, count, shortage, 0);
+
+  /* The code that follows is like scan_buffer
+     but checks for either newline or carriage return.  */
+
+  if (shortage != 0)
+    *shortage = 0;
+
+  if (count > 0)
+    while (start != limit + 1)
+      {
+       ceiling =  BUFFER_CEILING_OF (start);
+       ceiling = min (limit, ceiling);
+       ceiling_addr = &FETCH_CHAR (ceiling) + 1;
+       base = (cursor = &FETCH_CHAR (start));
+       while (1)
+         {
+           while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
+             ;
+           if (cursor != ceiling_addr)
+             {
+               if (--count == 0)
+                 {
+                   immediate_quit = 0;
+                   return (start + cursor - base + 1);
+                 }
+               else
+                 if (++cursor == ceiling_addr)
+                   break;
+             }
+           else
+             break;
+         }
+       start += cursor - base;
+      }
+  else
+    {
+      start--;                 /* first character we scan */
+      while (start > limit - 1)
+       {                       /* we WILL scan under start */
+         ceiling =  BUFFER_FLOOR_OF (start);
+         ceiling = max (limit, ceiling);
+         ceiling_addr = &FETCH_CHAR (ceiling) - 1;
+         base = (cursor = &FETCH_CHAR (start));
+         cursor++;
+         while (1)
+           {
+             while (--cursor != ceiling_addr
+                    && *cursor != '\n' && *cursor != 015)
+               ;
+             if (cursor != ceiling_addr)
+               {
+                 if (++count == 0)
+                   {
+                     immediate_quit = 0;
+                     return (start + cursor - base + 1);
+                   }
+               }
+             else
+               break;
+           }
+         start += cursor - base;
+       }
+    }
+
+  if (shortage != 0)
+    *shortage = count * direction;
+  return (start + ((direction == 1 ? 0 : 1)));
+}
 
 /* Count up to N lines starting from FROM.
    But don't go beyond LIMIT.
@@ -2997,7 +3406,7 @@ display_count_lines (from, limit, n, pos_ptr)
   else
     ZV = limit;
 
-  *pos_ptr = scan_buffer ('\n', from, n, &shortage, 0);
+  *pos_ptr = display_scan_buffer (from, n, &shortage);
 
   ZV = oldzv;
   BEGV = oldbegv;
@@ -3055,8 +3464,9 @@ display_string (w, vpos, string, length, hpos, truncate,
   /* Use the standard display table, not the window's display table.
      We don't want the mode line in rot13.  */
   register struct Lisp_Vector *dp = 0;
+  int i;
 
-  if (XTYPE (Vstandard_display_table) == Lisp_Vector
+  if (VECTORP (Vstandard_display_table)
       && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
     dp = XVECTOR (Vstandard_display_table);
 
@@ -3075,7 +3485,7 @@ display_string (w, vpos, string, length, hpos, truncate,
            {
              int i;
 
-             for (i = 0; i < VERTICAL_SCROLL_BAR_WIDTH; i++)
+             for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
                *end-- = ' ';
            }
          else
@@ -3087,6 +3497,10 @@ display_string (w, vpos, string, length, hpos, truncate,
       || (maxcol >= 0 && end - desired_glyphs->glyphs[vpos] > maxcol))
     end = desired_glyphs->glyphs[vpos] + maxcol;
 
+  /* Store 0 in charstart for these columns.  */
+  for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
+    desired_glyphs->charstarts[vpos][i] = 0;
+
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
@@ -3103,7 +3517,7 @@ display_string (w, vpos, string, length, hpos, truncate,
        break;
 
       if (c >= 040 && c < 0177
-         && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
+         && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c))))
        {
          if (p1 >= start)
            *p1 = c;
@@ -3119,7 +3533,7 @@ display_string (w, vpos, string, length, hpos, truncate,
            }
          while ((p1 - start + hscroll - (hscroll > 0)) % tab_width);
        }
-      else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
+      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,
@@ -3129,7 +3543,7 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
        {
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
+           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
                                 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
                             0);
          p1++;
@@ -3140,7 +3554,7 @@ display_string (w, vpos, string, length, hpos, truncate,
       else
        {
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
+           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
                                 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
                             0);
          p1++;
@@ -3182,6 +3596,9 @@ display_string (w, vpos, string, length, hpos, truncate,
 void
 syms_of_xdisp ()
 {
+  staticpro (&Qmenu_bar_update_hook);
+  Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+
   staticpro (&last_arrow_position);
   staticpro (&last_arrow_string);
   last_arrow_position = Qnil;
@@ -3224,6 +3641,33 @@ If this is zero, point is always centered after it moves off frame.");
   DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
     "*Non-nil means highlight region even in nonselected windows.");
   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.");
+
+  DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
+    "Template for displaying the titlebar of visible frames.\n\
+\(Assuming the window manager supports this feature.)\n\
+This variable has the same structure as `mode-line-format' (which see),\n\
+and is used only on frames for which no explicit name has been set\n\
+\(see `modify-frame-parameters').");
+  DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
+    "Template for displaying the titlebar of an iconified frame.\n\
+\(Assuming the window manager supports this feature.)\n\
+This variable has the same structure as `mode-line-format' (which see),\n\
+and is used only on frames for which no explicit name has been set\n\
+\(see `modify-frame-parameters').");
+  Vicon_title_format
+    = Vframe_title_format
+    = Fcons (intern ("multiple-frames"),
+            Fcons (build_string ("%b"),
+                   Fcons (Fcons (build_string (""),
+                                 Fcons (intern ("invocation-name"),
+                                        Fcons (build_string ("@"),
+                                               Fcons (intern ("system-name"),
+                                                              Qnil)))),
+                          Qnil)));
 }
 
 /* initialize the window system */
@@ -3246,12 +3690,12 @@ init_xdisp ()
   if (!noninteractive)
     {
       FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
-      XFASTINT (XWINDOW (root_window)->top) = 0;
+      XSETFASTINT (XWINDOW (root_window)->top, 0);
       set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
-      XFASTINT (mini_w->top) = FRAME_HEIGHT (f) - 1;
+      XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
       set_window_height (minibuf_window, 1, 0);
 
-      XFASTINT (XWINDOW (root_window)->width) = FRAME_WIDTH (f);
-      XFASTINT (mini_w->width) = FRAME_WIDTH (f);
+      XSETFASTINT (XWINDOW (root_window)->width, FRAME_WIDTH (f));
+      XSETFASTINT (mini_w->width, FRAME_WIDTH (f));
     }
 }