(redisplay, mark_window_display_accurate, try_window_id, display_text_line,
[bpt/emacs.git] / src / xdisp.c
index 88f9e9c..b78da76 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,6 +97,12 @@ 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;
 
@@ -275,6 +287,7 @@ int message_buf_print;
 void
 message (m, a1, a2, a3)
      char *m;
+     EMACS_INT a1, a2, a3;
 {
   if (noninteractive)
     {
@@ -311,7 +324,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;
@@ -335,6 +348,12 @@ message (m, a1, a2, a3)
     }
 }
 
+void
+update_echo_area ()
+{
+  message2 (echo_area_glyphs, echo_area_glyphs_length);
+}
+
 static void
 echo_area_display ()
 {
@@ -392,32 +411,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;
-
-      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.
@@ -594,7 +638,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)
@@ -746,7 +790,7 @@ update:
        {
          FRAME_PTR f;
 
-         if (XTYPE (XCONS (tail)->car) != Lisp_Frame)
+         if (!FRAMEP (XCONS (tail)->car))
            continue;
 
          f = XFRAME (XCONS (tail)->car);
@@ -884,7 +928,7 @@ 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))
@@ -1069,17 +1113,19 @@ redisplay_window (window, just_this_one)
 
   if (!EQ (window, selected_window))
     {
-      SET_PT (marker_position (w->pointm));
-      if (PT < BEGV)
+      int new_pt = marker_position (w->pointm);
+      if (new_pt < BEGV)
        {
-         SET_PT (BEGV);
-         Fset_marker (w->pointm, make_number (PT), Qnil);
+         new_pt = BEGV;
+         Fset_marker (w->pointm, make_number (new_pt), Qnil);
        }
-      else if (PT > (ZV - 1))
+      else if (new_pt > (ZV - 1))
        {
-         SET_PT (ZV);
-         Fset_marker (w->pointm, make_number (PT), 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 window-start is screwed up, choose a new one.  */
@@ -1112,7 +1158,7 @@ redisplay_window (window, just_this_one)
                                ZV, height / 2,
                                - (1 << (SHORTBITS - 1)),
                                width, hscroll, pos_tab_offset (w, startp), w);
-         SET_PT (pos.bufpos);
+         BUF_PT (current_buffer) = pos.bufpos;
          if (w != XWINDOW (selected_window))
            Fset_marker (w->pointm, make_number (PT), Qnil);
          else
@@ -1175,7 +1221,7 @@ 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;
@@ -1268,8 +1314,8 @@ recenter:
   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)
@@ -1331,9 +1377,9 @@ done:
       (*redeem_scroll_bar_hook) (w);
     }
 
-  SET_PT (opoint);
+  BUF_PT (current_buffer) = opoint;
   current_buffer = old;
-  SET_PT (lpoint);
+  BUF_PT (current_buffer) = lpoint;
 }
 \f
 /* Do full redisplay on one window, starting at position `pos'. */
@@ -1417,10 +1463,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;
@@ -1987,10 +2032,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
     = !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);
 
@@ -1998,20 +2042,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
@@ -2185,7 +2229,7 @@ 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 >= leftmargin)
            *p1 = MAKE_GLYPH (f, c, current_face);
@@ -2261,7 +2305,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
 #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, leftmargin,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
@@ -2271,7 +2315,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c < 0200 && ctl_arrow)
        {
          if (p1 >= leftmargin)
-           *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)) : '^'),
                             current_face);
          p1++;
@@ -2282,7 +2326,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else
        {
          if (p1 >= leftmargin)
-           *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)) : '\\'),
                             current_face);
          p1++;
@@ -2305,7 +2349,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (p1 != p1prev)
            {
              int *p2x = &charstart[p1prev - p1start];
-             int *p2 = &charstart[p1 - p1start];
+             int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
 
              /* The window's left column should always
                 contain a character position.
@@ -2464,7 +2508,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]);
@@ -2473,10 +2520,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;
@@ -2486,8 +2533,28 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
       if (len > width)
        len = width;
-      for (i = 0; i < len; i++)
-       leftmargin[i] = p[i];
+#ifdef HAVE_X_WINDOWS
+      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;
+
+             XFASTINT (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_X_WINDOWS */
+       {
+         for (i = 0; i < len; i++)
+           leftmargin[i] = p[i];
+       }
 
       /* Bug in SunOS 4.1.1 compiler requires this intermediate variable.  */
       arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
@@ -2657,8 +2724,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 == '%' */
              {
@@ -2683,11 +2753,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);
+                 }
              }
          }
       }
@@ -2706,10 +2780,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; }
@@ -2730,11 +2810,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.  */
@@ -2750,12 +2830,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;
@@ -2780,11 +2860,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,
@@ -2798,13 +2878,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
@@ -2822,6 +2908,7 @@ decode_mode_spec (w, c, maxwidth)
   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))
@@ -2830,7 +2917,7 @@ decode_mode_spec (w, c, maxwidth)
   switch (c)
     {
     case 'b': 
-      obj = current_buffer->name;
+      obj = b->name;
 #if 0
       if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
        {
@@ -2843,11 +2930,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,
@@ -2871,7 +2958,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;
@@ -2888,7 +2975,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.  */
@@ -2900,15 +2987,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;
+           XFASTINT (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;
 
@@ -2945,32 +3032,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) > b->save_modified)
        return "*";
       return "-";
 
     case '+':
       /* This differs from %* only for a modified read-only buffer.  */
-      if (MODIFF > current_buffer->save_modified)
+      if (BUF_MODIFF (b) > b->save_modified)
        return "*";
-      if (!NILP (current_buffer->read_only))
+      if (!NILP (b->read_only))
        return "%";
       return "-";
 
+    case '&':
+      /* This differs from %* in ignoring read-only-ness.  */
+      if (BUF_MODIFF (b) > b->save_modified)
+       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
@@ -2979,29 +3072,29 @@ decode_mode_spec (w, c, maxwidth)
       break;
 
     case 't':                  /* indicate TEXT or BINARY */
-#ifdef MSDOS
-      return NILP (current_buffer->buffer_file_type) ? "T" : "B";
-#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)
@@ -3015,24 +3108,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);
@@ -3070,7 +3163,7 @@ decode_mode_spec (w, c, maxwidth)
        *p = 0;
        return decode_mode_spec_buf;
       }
-      
+
     case '-':
       {
        register char *p;
@@ -3087,12 +3180,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, 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.
@@ -3113,7 +3307,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;
@@ -3173,7 +3367,7 @@ display_string (w, vpos, string, length, hpos, truncate,
   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);
 
@@ -3192,7 +3386,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
@@ -3224,7 +3418,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;
@@ -3240,7 +3434,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,
@@ -3250,7 +3444,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++;
@@ -3261,7 +3455,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++;
@@ -3348,6 +3542,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 */