]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Merged in changes from CVS trunk.
[gnu-emacs] / src / xdisp.c
index 4a79521f65da02739be0e1de30b2252192098803..90399c060312e6b48bf74c766038bb5a3e7e05ba 100644 (file)
@@ -198,8 +198,6 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #ifdef MAC_OS
 #include "macterm.h"
-
-Cursor No_Cursor;
 #endif
 
 #ifndef FRAME_X_OUTPUT
@@ -304,10 +302,11 @@ Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
 Lisp_Object Qslice;
 Lisp_Object Qcenter;
 Lisp_Object Qmargin, Qpointer;
-Lisp_Object Qline_height;
+Lisp_Object Qline_height, Qtotal;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
 extern Lisp_Object Qscroll_bar;
+extern Lisp_Object Qcursor;
 
 /* Non-nil means highlight trailing whitespace.  */
 
@@ -672,10 +671,6 @@ EMACS_INT hscroll_margin;
 /* How much to scroll horizontally when point is inside the above margin.  */
 Lisp_Object Vhscroll_step;
 
-/* A list of symbols, one for each supported image type.  */
-
-Lisp_Object Vimage_types;
-
 /* The variable `resize-mini-windows'.  If nil, don't resize
    mini-windows.  If t, always resize them to fit the text they
    display.  If `grow-only', let mini-windows grow only until they
@@ -2069,6 +2064,9 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
     {
       if (NATNUMP (current_buffer->extra_line_spacing))
        it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
+      else if (FLOATP (current_buffer->extra_line_spacing))
+       it->extra_line_spacing = (XFLOAT_DATA (current_buffer->extra_line_spacing)
+                                 * FRAME_LINE_HEIGHT (it->f));
       else if (it->f->extra_line_spacing > 0)
        it->extra_line_spacing = it->f->extra_line_spacing;
     }
@@ -2086,6 +2084,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
   it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
   it->space_width = Qnil;
   it->font_height = Qnil;
+  it->override_ascent = -1;
 
   /* Are control characters displayed as `^C'?  */
   it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow);
@@ -2726,19 +2725,10 @@ next_overlay_change (pos)
   int noverlays;
   int endpos;
   Lisp_Object *overlays;
-  int len;
   int i;
 
   /* Get all overlays at the given position.  */
-  len = 10;
-  overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-  noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-  if (noverlays > len)
-    {
-      len = noverlays;
-      overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-      noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-    }
+  GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
 
   /* If any of these overlays ends before endpos,
      use its ending point instead.  */
@@ -4564,6 +4554,14 @@ back_to_previous_visible_line_start (it)
            visible_p = 0;
        }
 
+      if (visible_p)
+       {
+         struct it it2 = *it;
+
+         if (handle_display_prop (&it2) == HANDLED_RETURN)
+           visible_p = 0;
+       }
+
       /* Back one more newline if the current one is invisible.  */
       if (!visible_p)
        back_to_previous_line_start (it);
@@ -5648,9 +5646,13 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
     {
       int x, i, ascent = 0, descent = 0;
 
-      /* Stop when ZV or TO_CHARPOS reached.  */
+      /* Stop when ZV reached.
+         We used to stop here when TO_CHARPOS reached as well, but that is
+         too soon if this glyph does not fit on this line.  So we handle it
+         explicitly below.  */
       if (!get_next_display_element (it)
-         || BUFFER_POS_REACHED_P ())
+         || (it->truncate_lines_p
+             && BUFFER_POS_REACHED_P ()))
        {
          result = MOVE_POS_MATCH_OR_ZV;
          break;
@@ -5710,6 +5712,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
              /* We want to leave anything reaching TO_X to the caller.  */
              if ((op & MOVE_TO_X) && new_x > to_x)
                {
+                 if (BUFFER_POS_REACHED_P ())
+                   goto buffer_pos_reached;
                  it->current_x = x;
                  result = MOVE_X_REACHED;
                  break;
@@ -5737,12 +5741,19 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
-                             if (!get_next_display_element (it)
-                                 || BUFFER_POS_REACHED_P ())
+                             if (!get_next_display_element (it))
                                {
                                  result = MOVE_POS_MATCH_OR_ZV;
                                  break;
                                }
+                             if (BUFFER_POS_REACHED_P ())
+                               {
+                                 if (ITERATOR_AT_END_OF_LINE_P (it))
+                                   result = MOVE_POS_MATCH_OR_ZV;
+                                 else
+                                   result = MOVE_LINE_CONTINUED;
+                                 break;
+                               }
                              if (ITERATOR_AT_END_OF_LINE_P (it))
                                {
                                  result = MOVE_NEWLINE_OR_CR;
@@ -5764,6 +5775,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                  result = MOVE_LINE_CONTINUED;
                  break;
                }
+             else if (BUFFER_POS_REACHED_P ())
+               goto buffer_pos_reached;
              else if (new_x > it->first_visible_x)
                {
                  /* Glyph is visible.  Increment number of glyphs that
@@ -5780,6 +5793,15 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
          if (result != MOVE_UNDEFINED)
            break;
        }
+      else if (BUFFER_POS_REACHED_P ())
+       {
+       buffer_pos_reached:
+         it->current_x = x;
+         it->max_ascent = ascent;
+         it->max_descent = descent;
+         result = MOVE_POS_MATCH_OR_ZV;
+         break;
+       }
       else if ((op & MOVE_TO_X) && it->current_x >= to_x)
        {
          /* Stop when TO_X specified and reached.  This check is
@@ -6314,6 +6336,7 @@ add_to_log (format, arg1, arg2)
   char *buffer;
   int len;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  USE_SAFE_ALLOCA;
 
   /* Do nothing if called asynchronously.  Inserting text into
      a buffer may call after-change-functions and alike and
@@ -6330,10 +6353,12 @@ add_to_log (format, arg1, arg2)
   msg = Fformat (3, args);
 
   len = SBYTES (msg) + 1;
-  buffer = (char *) alloca (len);
+  SAFE_ALLOCA (buffer, char *, len);
   bcopy (SDATA (msg), buffer, len);
 
   message_dolog (buffer, len - 1, 1, 0);
+  SAFE_FREE (len);
+
   UNGCPRO;
 }
 
@@ -10353,7 +10378,7 @@ redisplay_internal (preserve_echo_area)
    This is useful in situations where you need to redisplay but no
    user action has occurred, making it inappropriate for the message
    area to be cleared.  See tracking_off and
-   wait_reading_process_input for examples of these situations.
+   wait_reading_process_output for examples of these situations.
 
    FROM_WHERE is an integer saying from where this function was
    called.  This is useful for debugging.  */
@@ -10619,6 +10644,7 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
 {
   struct glyph *glyph = row->glyphs[TEXT_AREA];
   struct glyph *end = glyph + row->used[TEXT_AREA];
+  struct glyph *cursor = NULL;
   /* The first glyph that starts a sequence of glyphs from string.  */
   struct glyph *string_start;
   /* The X coordinate of string_start.  */
@@ -10628,6 +10654,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
   /* The last known character position before string_start.  */
   int string_before_pos;
   int x = row->x;
+  int cursor_x = x;
+  int cursor_from_overlay_pos = 0;
   int pt_old = PT - delta;
 
   /* Skip over glyphs not having an object at the start of the row.
@@ -10653,6 +10681,12 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
          string_start = NULL;
          x += glyph->pixel_width;
          ++glyph;
+         if (cursor_from_overlay_pos
+             && last_pos > cursor_from_overlay_pos)
+           {
+             cursor_from_overlay_pos = 0;
+             cursor = 0;
+           }
        }
       else
        {
@@ -10660,12 +10694,40 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
          string_start = glyph;
          string_start_x = x;
          /* Skip all glyphs from string.  */
-         SKIP_GLYPHS (glyph, end, x, STRINGP (glyph->object));
+         do
+           {
+             int pos;
+             if ((cursor == NULL || glyph > cursor)
+                 && !NILP (Fget_char_property (make_number ((glyph)->charpos),
+                                               Qcursor, (glyph)->object))
+                 && (pos = string_buffer_position (w, glyph->object,
+                                                   string_before_pos),
+                     (pos == 0   /* From overlay */
+                      || pos == pt_old)))
+               {
+                 /* Estimate overlay buffer position from the buffer
+                    positions of the glyphs before and after the overlay.
+                    Add 1 to last_pos so that if point corresponds to the
+                    glyph right after the overlay, we still use a 'cursor'
+                    property found in that overlay.  */
+                 cursor_from_overlay_pos = pos == 0 ? last_pos+1 : 0;
+                 cursor = glyph;
+                 cursor_x = x;
+               }
+             x += glyph->pixel_width;
+             ++glyph;
+           }
+         while (glyph < end && STRINGP (glyph->object));
        }
     }
 
-  if (string_start
-      && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
+  if (cursor != NULL)
+    {
+      glyph = cursor;
+      x = cursor_x;
+    }
+  else if (string_start
+          && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
     {
       /* We may have skipped over point because the previous glyphs
         are from string.  As there's no easy way to know the
@@ -11003,7 +11065,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          aggressive = current_buffer->scroll_up_aggressively;
          height = WINDOW_BOX_TEXT_HEIGHT (w);
          if (NUMBERP (aggressive))
-           amount_to_scroll = XFLOATINT (aggressive) * height;
+           {
+             double float_amount = XFLOATINT (aggressive) * height;
+             amount_to_scroll = float_amount;
+             if (amount_to_scroll == 0 && float_amount > 0)
+               amount_to_scroll = 1;
+           }
        }
 
       if (amount_to_scroll <= 0)
@@ -11052,8 +11119,8 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          start_display (&it, w, startp);
 
          if (scroll_conservatively)
-           amount_to_scroll =
-             max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step));
+           amount_to_scroll
+             max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step));
          else if (scroll_step || temp_scroll_step)
            amount_to_scroll = scroll_max;
          else
@@ -11061,7 +11128,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
              aggressive = current_buffer->scroll_down_aggressively;
              height = WINDOW_BOX_TEXT_HEIGHT (w);
              if (NUMBERP (aggressive))
-               amount_to_scroll = XFLOATINT (aggressive) * height;
+               {
+                 double float_amount = XFLOATINT (aggressive) * height;
+                 amount_to_scroll = float_amount;
+                 if (amount_to_scroll == 0 && float_amount > 0)
+                   amount_to_scroll = 1;
+               }
            }
 
          if (amount_to_scroll <= 0)
@@ -11256,7 +11328,7 @@ try_cursor_movement (window, startp, scroll_step)
       && (FRAME_WINDOW_P (f)
          || !overlay_arrow_in_current_buffer_p ()))
     {
-      int this_scroll_margin;
+      int this_scroll_margin, top_scroll_margin;
       struct glyph_row *row = NULL;
 
 #if GLYPH_DEBUG
@@ -11269,6 +11341,10 @@ try_cursor_movement (window, startp, scroll_step)
       this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
       this_scroll_margin *= FRAME_LINE_HEIGHT (f);
 
+      top_scroll_margin = this_scroll_margin;
+      if (WINDOW_WANTS_HEADER_LINE_P (w))
+       top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w);
+
       /* Start with the row the cursor was displayed during the last
         not paused redisplay.  Give up if that row is not valid.  */
       if (w->last_cursor.vpos < 0
@@ -11323,13 +11399,12 @@ try_cursor_movement (window, startp, scroll_step)
          else if (PT < XFASTINT (w->last_point))
            {
              /* Cursor has to be moved backward.  Note that PT >=
-                CHARPOS (startp) because of the outer
-                if-statement.  */
+                CHARPOS (startp) because of the outer if-statement.  */
              while (!row->mode_line_p
                     && (MATRIX_ROW_START_CHARPOS (row) > PT
                         || (MATRIX_ROW_START_CHARPOS (row) == PT
                             && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
-                    && (row->y > this_scroll_margin
+                    && (row->y > top_scroll_margin
                         || CHARPOS (startp) == BEGV))
                {
                  xassert (row->enabled_p);
@@ -11357,7 +11432,7 @@ try_cursor_movement (window, startp, scroll_step)
                ++row;
 
              /* If within the scroll margin, scroll.  */
-             if (row->y < this_scroll_margin
+             if (row->y < top_scroll_margin
                  && CHARPOS (startp) != BEGV)
                scroll_p = 1;
            }
@@ -11838,8 +11913,8 @@ redisplay_window (window, just_this_one_p)
             buffer.  */
          || !NILP (Vwindow_scroll_functions)
          || MINI_WINDOW_P (w)
-         || !(used_current_matrix_p =
-              try_window_reusing_current_matrix (w)))
+         || !(used_current_matrix_p
+              try_window_reusing_current_matrix (w)))
        {
          IF_DEBUG (debug_method_add (w, "1"));
          try_window (window, startp);
@@ -11968,8 +12043,8 @@ redisplay_window (window, just_this_one_p)
       || !NILP (Vwindow_scroll_functions)
       || !just_this_one_p
       || MINI_WINDOW_P (w)
-      || !(used_current_matrix_p =
-          try_window_reusing_current_matrix (w)))
+      || !(used_current_matrix_p
+          try_window_reusing_current_matrix (w)))
     try_window (window, startp);
 
   /* If new fonts have been loaded (due to fontsets), give up.  We
@@ -12328,10 +12403,36 @@ try_window_reusing_current_matrix (w)
       last_text_row = last_reused_text_row = NULL;
 
       while (it.current_y < it.last_visible_y
-            && IT_CHARPOS (it) < CHARPOS (start)
             && !fonts_changed_p)
-       if (display_line (&it))
-         last_text_row = it.glyph_row - 1;
+       {
+         /* If we have reached into the characters in the START row,
+            that means the line boundaries have changed.  So we
+            can't start copying with the row START.  Maybe it will
+            work to start copying with the following row.  */
+         while (IT_CHARPOS (it) > CHARPOS (start))
+           {
+             /* Advance to the next row as the "start".  */
+             start_row++;
+             start = start_row->start.pos;
+             /* If there are no more rows to try, or just one, give up.  */
+             if (start_row == MATRIX_MODE_LINE_ROW (w->current_matrix) - 1
+                 || w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (start_row)
+                 || CHARPOS (start) == ZV)
+               {
+                 clear_glyph_matrix (w->desired_matrix);
+                 return 0;
+               }
+
+             start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
+           }
+         /* If we have reached alignment,
+            we can copy the rest of the rows.  */
+         if (IT_CHARPOS (it) == CHARPOS (start))
+           break;
+
+         if (display_line (&it))
+           last_text_row = it.glyph_row - 1;
+       }
 
       /* A value of current_y < last_visible_y means that we stopped
         at the previous window start, which in turn means that we
@@ -12339,12 +12440,12 @@ try_window_reusing_current_matrix (w)
       if (it.current_y < it.last_visible_y)
        {
          /* IT.vpos always starts from 0; it counts text lines.  */
-         nrows_scrolled = it.vpos;
+         nrows_scrolled = it.vpos - (start_row - MATRIX_FIRST_TEXT_ROW (w->current_matrix));
 
          /* Find PT if not already found in the lines displayed.  */
          if (w->cursor.vpos < 0)
            {
-             int dy = it.current_y - first_row_y;
+             int dy = it.current_y - start_row->y;
 
              row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
              row = row_containing_pos (w, PT, row, NULL, dy);
@@ -12364,7 +12465,7 @@ try_window_reusing_current_matrix (w)
             scroll_run_hook will clear the cursor, and use the
             current matrix to get the height of the row the cursor is
             in.  */
-         run.current_y = first_row_y;
+         run.current_y = start_row->y;
          run.desired_y = it.current_y;
          run.height = it.last_visible_y - it.current_y;
 
@@ -12530,9 +12631,8 @@ try_window_reusing_current_matrix (w)
         position.  */
       if (pt_row)
        {
-         w->cursor.vpos -= MATRIX_ROW_VPOS (first_reusable_row,
-                                            w->current_matrix);
-         w->cursor.y -= first_reusable_row->y;
+         w->cursor.vpos -= nrows_scrolled;
+         w->cursor.y -= first_reusable_row->y - start_row->y;
        }
 
       /* Scroll the display.  */
@@ -12577,6 +12677,29 @@ try_window_reusing_current_matrix (w)
       for (row -= nrows_scrolled; row < bottom_row; ++row)
        row->enabled_p = 0;
 
+      /* Point may have moved to a different line, so we cannot assume that
+        the previous cursor position is valid; locate the correct row.  */
+      if (pt_row)
+       {
+         for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+              row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row);
+              row++)
+           {
+             w->cursor.vpos++;
+             w->cursor.y = row->y;
+           }
+         if (row < bottom_row)
+           {
+             struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
+             while (glyph->charpos < PT)
+               {
+                 w->cursor.hpos++;
+                 w->cursor.x += glyph->pixel_width;
+                 glyph++;
+               }
+           }
+       }
+
       /* Adjust window end.  A null value of last_text_row means that
         the window end is in reused rows which in turn means that
         only its vpos can have changed.  */
@@ -13360,9 +13483,9 @@ try_window_id (w)
 
     if ((w->cursor.y < this_scroll_margin
         && CHARPOS (start) > BEGV)
-       /* Don't take scroll margin into account at the bottom because
-          old redisplay didn't do it either.  */
-       || w->cursor.y + cursor_height > it.last_visible_y)
+       /* Old redisplay didn't take scroll margin into account at the bottom,
+          but then global-hl-line-mode doesn't scroll.  KFS 2004-06-14 */
+       || w->cursor.y + cursor_height + this_scroll_margin > it.last_visible_y)
       {
        w->cursor.vpos = -1;
        clear_glyph_matrix (w->desired_matrix);
@@ -14201,7 +14324,7 @@ append_space_for_newline (it, default_face_p)
 
          PRODUCE_GLYPHS (it);
 
-         it->use_default_face = 0;
+         it->override_ascent = -1;
          it->constrain_row_ascent_descent_p = 0;
          it->current_x = saved_x;
          it->object = saved_object;
@@ -14425,9 +14548,13 @@ display_line (it)
   /* We always start displaying at hpos zero even if hscrolled.  */
   xassert (it->hpos == 0 && it->current_x == 0);
 
-  /* We must not display in a row that's not a text row.  */
-  xassert (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
-          < it->w->desired_matrix->nrows);
+  if (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
+      >= it->w->desired_matrix->nrows)
+    {
+      it->w->nrows_scale_factor++;
+      fonts_changed_p = 1;
+      return 0;
+    }
 
   /* Is IT->w showing the region?  */
   it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil;
@@ -15233,6 +15360,10 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
            Lisp_Object oprops, aelt;
            oprops = Ftext_properties_at (make_number (0), elt);
 
+           /* If the starting string's properties are not what
+              we want, translate the string.  Also, if the string
+              is risky, do that anyway.  */
+
            if (NILP (Fequal (props, oprops)) || risky)
              {
                /* If the starting string has properties,
@@ -15609,7 +15740,8 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
    The mode_line_string_face face property is always added to the string.
  */
 
-static int store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props)
+static int
+store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props)
      char *string;
      Lisp_Object lisp_string;
      int copy_string;
@@ -15691,15 +15823,16 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width
 
 
 DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
-       0, 3, 0,
+       0, 4, 0,
        doc: /* Return the mode-line of selected window as a string.
 First optional arg FORMAT specifies a different format string (see
 `mode-line-format' for details) to use.  If FORMAT is t, return
 the buffer's header-line.  Second optional arg WINDOW specifies a
 different window to use as the context for the formatting.
-If third optional arg NO-PROPS is non-nil, string is not propertized.  */)
-     (format, window, no_props)
-     Lisp_Object format, window, no_props;
+If third optional arg NO-PROPS is non-nil, string is not propertized.
+Fourth optional arg BUFFER specifies which buffer to use.  */)
+  (format, window, no_props, buffer)
+     Lisp_Object format, window, no_props, buffer;
 {
   struct it it;
   int len;
@@ -15711,42 +15844,46 @@ If third optional arg NO-PROPS is non-nil, string is not propertized.  */)
     window = selected_window;
   CHECK_WINDOW (window);
   w = XWINDOW (window);
-  CHECK_BUFFER (w->buffer);
 
-  if (XBUFFER (w->buffer) != current_buffer)
+  if (NILP (buffer))
+    buffer = w->buffer;
+
+  CHECK_BUFFER (buffer);
+
+  if (XBUFFER (buffer) != current_buffer)
     {
       old_buffer = current_buffer;
-      set_buffer_internal_1 (XBUFFER (w->buffer));
+      set_buffer_internal_1 (XBUFFER (buffer));
     }
 
   if (NILP (format) || EQ (format, Qt))
     {
-      face_id = NILP (format)
-       ? CURRENT_MODE_LINE_FACE_ID (w) :
-       HEADER_LINE_FACE_ID;
-      format = NILP (format)
-       ? current_buffer->mode_line_format
-       : current_buffer->header_line_format;
+      face_id = (NILP (format)
+                ? CURRENT_MODE_LINE_FACE_ID (w)
+                : HEADER_LINE_FACE_ID);
+      format = (NILP (format)
+               ? current_buffer->mode_line_format
+               : current_buffer->header_line_format);
     }
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
 
   if (NILP (no_props))
     {
-      mode_line_string_face =
-       (face_id == MODE_LINE_FACE_ID ? Qmode_line :
-        face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive :
-        face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
+      mode_line_string_face
+       = (face_id == MODE_LINE_FACE_ID ? Qmode_line
+          : face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive
+          : face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
 
-      mode_line_string_face_prop =
-       NILP (mode_line_string_face) ? Qnil :
-       Fcons (Qface, Fcons (mode_line_string_face, Qnil));
+      mode_line_string_face_prop
+       = (NILP (mode_line_string_face) ? Qnil
+          : Fcons (Qface, Fcons (mode_line_string_face, Qnil)));
 
       /* We need a dummy last element in mode_line_string_list to
         indicate we are building the propertized mode-line string.
         Using mode_line_string_face_prop here GC protects it.  */
-      mode_line_string_list =
-       Fcons (mode_line_string_face_prop, Qnil);
+      mode_line_string_list
+       Fcons (mode_line_string_face_prop, Qnil);
       frame_title_ptr = NULL;
     }
   else
@@ -16019,7 +16156,10 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
    generated by character C.  PRECISION >= 0 means don't return a
    string longer than that value.  FIELD_WIDTH > 0 means pad the
    string returned with spaces to that value.  Return 1 in *MULTIBYTE
-   if the result is multibyte text.  */
+   if the result is multibyte text.
+
+   Note we operate on the current buffer for most purposes,
+   the exception being w->base_line_pos.  */
 
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
@@ -16033,7 +16173,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
-  struct buffer *b = XBUFFER (w->buffer);
+  struct buffer *b = current_buffer;
 
   obj = Qnil;
   *multibyte = 0;
@@ -16335,7 +16475,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
 
     case 's':
       /* status of process */
-      obj = Fget_buffer_process (w->buffer);
+      obj = Fget_buffer_process (Fcurrent_buffer ());
       if (NILP (obj))
        return "no process";
 #ifdef subprocesses
@@ -16362,8 +16502,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
          {
            /* No need to mention EOL here--the terminal never needs
               to do EOL conversion.  */
-           p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
-           p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+           p = decode_mode_spec_coding (FRAME_KEYBOARD_CODING (f)->symbol, p, 0);
+           p = decode_mode_spec_coding (FRAME_TERMINAL_CODING (f)->symbol, p, 0);
          }
        p = decode_mode_spec_coding (b->buffer_file_coding_system,
                                     p, eol_flag);
@@ -18098,6 +18238,11 @@ append_glyph (it)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else if (!fonts_changed_p)
+    {
+      it->w->ncols_scale_factor++;
+      fonts_changed_p = 1;
+    }
 }
 
 /* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
@@ -18135,6 +18280,11 @@ append_composite_glyph (it)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else if (!fonts_changed_p)
+    {
+      it->w->ncols_scale_factor++;
+      fonts_changed_p = 1;
+    }
 }
 
 
@@ -18304,6 +18454,11 @@ produce_image_glyph (it)
          glyph->font_type = FONT_TYPE_UNKNOWN;
          ++it->glyph_row->used[area];
        }
+      else if (!fonts_changed_p)
+       {
+         it->w->ncols_scale_factor++;
+         fonts_changed_p = 1;
+       }
     }
 }
 
@@ -18347,6 +18502,11 @@ append_stretch_glyph (it, object, width, height, ascent)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else if (!fonts_changed_p)
+    {
+      it->w->ncols_scale_factor++;
+      fonts_changed_p = 1;
+    }
 }
 
 
@@ -18509,6 +18669,107 @@ produce_stretch_glyph (it)
   take_vertical_position_into_account (it);
 }
 
+/* Calculate line-height and line-spacing properties.
+   An integer value specifies explicit pixel value.
+   A float value specifies relative value to current face height.
+   A cons (float . face-name) specifies relative value to
+   height of specified face font.
+
+   Returns height in pixels, or nil.  */
+
+static Lisp_Object
+calc_line_height_property (it, prop, font, boff, total)
+     struct it *it;
+     Lisp_Object prop;
+     XFontStruct *font;
+     int boff, *total;
+{
+  Lisp_Object position, val;
+  Lisp_Object face_name = Qnil;
+  int ascent, descent, height, override;
+
+  if (STRINGP (it->object))
+    position = make_number (IT_STRING_CHARPOS (*it));
+  else
+    position = make_number (IT_CHARPOS (*it));
+
+  val = Fget_char_property (position, prop, it->object);
+
+  if (NILP (val))
+    return val;
+
+  if (total && CONSP (val) && EQ (XCAR (val), Qtotal))
+    {
+      *total = 1;
+      val = XCDR (val);
+    }
+
+  if (INTEGERP (val))
+    return val;
+
+  if (CONSP (val))
+    {
+      face_name = XCDR (val);
+      val = XCAR (val);
+    }
+  else if (SYMBOLP (val))
+    {
+      face_name = val;
+      val = Qnil;
+    }
+
+  override = EQ (prop, Qline_height);
+
+  if (NILP (face_name))
+    {
+      font = FRAME_FONT (it->f);
+      boff = FRAME_BASELINE_OFFSET (it->f);
+    }
+  else if (EQ (face_name, Qt))
+    {
+      override = 0;
+    }
+  else
+    {
+      int face_id;
+      struct face *face;
+      struct font_info *font_info;
+
+      face_id = lookup_named_face (it->f, face_name, ' ');
+      if (face_id < 0)
+       return make_number (-1);
+
+      face = FACE_FROM_ID (it->f, face_id);
+      font = face->font;
+      if (font == NULL)
+       return make_number (-1);
+
+      font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+      boff = font_info->baseline_offset;
+      if (font_info->vertical_centering)
+       boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+    }
+
+  ascent = FONT_BASE (font) + boff;
+  descent = FONT_DESCENT (font) - boff;
+
+  if (override)
+    {
+      it->override_ascent = ascent;
+      it->override_descent = descent;
+      it->override_boff = boff;
+    }
+
+  height = ascent + descent;
+  if (FLOATP (val))
+    height = (int)(XFLOAT_DATA (val) * height);
+  else if (INTEGERP (val))
+    height *= XINT (val);
+
+  return make_number (height);
+}
+
+
 /* RIF:
    Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct display_iterator in
@@ -18595,17 +18856,20 @@ x_produce_glyphs (it)
 
          it->nglyphs = 1;
 
-         if (it->use_default_face)
-           {
-             font = FRAME_FONT (it->f);
-             boff = FRAME_BASELINE_OFFSET (it->f);
-           }
-         pcm = FRAME_RIF (it->f)->per_char_metric
+          pcm = FRAME_RIF (it->f)->per_char_metric
             (font, &char2b, FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
 
-         it->ascent = FONT_BASE (font) + boff;
-         it->descent = FONT_DESCENT (font) - boff;
+         if (it->override_ascent >= 0)
+           {
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
+           }
 
          if (pcm)
            {
@@ -18708,26 +18972,27 @@ x_produce_glyphs (it)
             But if previous part of the line set a height, don't
             increase that height */
 
-         Lisp_Object lsp, lh;
+         Lisp_Object height;
 
+         it->override_ascent = -1;
          it->pixel_width = 0;
          it->nglyphs = 0;
 
-         lh = Fget_text_property (make_number (IT_CHARPOS (*it)),
-                                  Qline_height, it->object);
+         height = calc_line_height_property(it, Qline_height, font, boff, 0);
 
-         if (EQ (lh, Qt))
+         if (it->override_ascent >= 0)
            {
-             it->use_default_face = 1;
-             font = FRAME_FONT (it->f);
-             boff = FRAME_BASELINE_OFFSET (it->f);
-             font_info = NULL;
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
            }
 
-         it->ascent = FONT_BASE (font) + boff;
-         it->descent = FONT_DESCENT (font) - boff;
-
-         if (EQ (lh, make_number (0)))
+         if (EQ (height, make_number(0)))
            {
              if (it->descent > it->max_descent)
                {
@@ -18746,7 +19011,9 @@ x_produce_glyphs (it)
            }
          else
            {
-             int explicit_height = -1;
+             Lisp_Object spacing;
+             int total = 0;
+
              it->phys_ascent = it->ascent;
              it->phys_descent = it->descent;
 
@@ -18757,23 +19024,18 @@ x_produce_glyphs (it)
                  it->ascent += face->box_line_width;
                  it->descent += face->box_line_width;
                }
-             if (INTEGERP (lh))
-               explicit_height = XINT (lh);
-             else if (FLOATP (lh))
-               explicit_height = (it->phys_ascent + it->phys_descent)
-                 * XFLOAT_DATA (lh);
-
-             if (explicit_height > it->ascent + it->descent)
-               it->ascent = explicit_height - it->descent;
-           }
+             if (!NILP (height)
+                 && XINT (height) > it->ascent + it->descent)
+               it->ascent = XINT (height) - it->descent;
 
-         lsp = Fget_text_property (make_number (IT_CHARPOS (*it)),
-                                   Qline_spacing, it->object);
-         if (INTEGERP (lsp))
-           extra_line_spacing = XINT (lsp);
-         else if (FLOATP (lsp))
-           extra_line_spacing = (it->phys_ascent + it->phys_descent)
-             * XFLOAT_DATA (lsp);
+             spacing = calc_line_height_property(it, Qline_spacing, font, boff, &total);
+             if (INTEGERP (spacing))
+               {
+                 extra_line_spacing = XINT (spacing);
+                 if (total)
+                   extra_line_spacing -= (it->phys_ascent + it->phys_descent);
+               }
+           }
        }
       else if (it->char_to_display == '\t')
        {
@@ -19150,7 +19412,8 @@ x_produce_glyphs (it)
   if (it->area == TEXT_AREA)
     it->current_x += it->pixel_width;
 
-  it->descent += extra_line_spacing;
+  if (extra_line_spacing > 0)
+    it->descent += extra_line_spacing;
 
   it->max_ascent = max (it->max_ascent, it->ascent);
   it->max_descent = max (it->max_descent, it->descent);
@@ -20520,11 +20783,7 @@ define_frame_cursor1 (f, cursor, pointer)
        cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
     }
 
-#ifndef HAVE_CARBON
   if (cursor != No_Cursor)
-#else
-  if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
-#endif
     FRAME_RIF (f)->define_frame_cursor (f, cursor);
 }
 
@@ -20707,7 +20966,8 @@ note_mouse_highlight (f, x, y)
 
   if (part == ON_VERTICAL_BORDER)
     cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
-  else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+  else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
+          || part == ON_SCROLL_BAR)
     cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
   else
     cursor = FRAME_X_OUTPUT (f)->text_cursor;
@@ -20725,7 +20985,7 @@ note_mouse_highlight (f, x, y)
       Lisp_Object object;
       Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
       Lisp_Object *overlay_vec = NULL;
-      int len, noverlays;
+      int noverlays;
       struct buffer *obuf;
       int obegv, ozv, same_region;
 
@@ -20812,19 +21072,8 @@ note_mouse_highlight (f, x, y)
 
       if (BUFFERP (object))
        {
-         /* Put all the overlays we want in a vector in overlay_vec.
-            Store the length in len.  If there are more than 10, make
-            enough space for all, and try again.  */
-         len = 10;
-         overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-         noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
-         if (noverlays > len)
-           {
-             len = noverlays;
-             overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-             noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
-           }
-
+         /* Put all the overlays we want in a vector in overlay_vec.  */
+         GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
          /* Sort overlays into increasing priority order.  */
          noverlays = sort_overlays (overlay_vec, noverlays, w);
        }
@@ -21798,6 +22047,8 @@ syms_of_xdisp ()
   staticpro (&Qcenter);
   Qline_height = intern ("line-height");
   staticpro (&Qline_height);
+  Qtotal = intern ("total");
+  staticpro (&Qtotal);
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
   QCrelative_width = intern (":relative-width");
@@ -22052,7 +22303,7 @@ all the functions in the list are called, with the frame as argument.  */);
   Vwindow_size_change_functions = Qnil;
 
   DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
-    doc: /* List of Functions to call before redisplaying a window with scrolling.
+    doc: /* List of functions to call before redisplaying a window with scrolling.
 Each function is called with two arguments, the window
 and its new display-start position.  Note that the value of `window-end'
 is not valid when these functions are called.  */);
@@ -22158,11 +22409,6 @@ Note that the lower bound for automatic hscrolling specified by `scroll-left'
 and `scroll-right' overrides this variable's effect.  */);
   Vhscroll_step = make_number (0);
 
-  DEFVAR_LISP ("image-types", &Vimage_types,
-    doc: /* List of supported image types.
-Each element of the list is a symbol for a supported image type.  */);
-  Vimage_types = Qnil;
-
   DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
     doc: /* If non-nil, messages are truncated instead of resizing the echo area.
 Bind this around calls to `message' to let it take effect.  */);