error: Print 32- and 64-bit integers portably (Bug#8435).
[bpt/emacs.git] / src / xdisp.c
index 140c215..a296fb3 100644 (file)
@@ -754,7 +754,7 @@ static void setup_for_ellipsis (struct it *, int);
 static void mark_window_display_accurate_1 (struct window *, int);
 static int single_display_spec_string_p (Lisp_Object, Lisp_Object);
 static int display_prop_string_p (Lisp_Object, Lisp_Object);
-static int cursor_row_p (struct window *, struct glyph_row *);
+static int cursor_row_p (struct glyph_row *);
 static int redisplay_mode_lines (Lisp_Object, int);
 static char *decode_mode_spec_coding (Lisp_Object, char *, int);
 
@@ -774,6 +774,7 @@ static int store_mode_line_noprop (const char *, int, int);
 static void handle_stop (struct it *);
 static void handle_stop_backwards (struct it *, EMACS_INT);
 static int single_display_spec_intangible_p (Lisp_Object);
+static void vmessage (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
 static void ensure_echo_area_buffers (void);
 static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object);
 static Lisp_Object with_echo_area_buffer_unwind_data (struct window *);
@@ -802,13 +803,12 @@ static int cursor_row_fully_visible_p (struct window *, int, int);
 static int try_scrolling (Lisp_Object, int, EMACS_INT, EMACS_INT, int, int);
 static int try_cursor_movement (Lisp_Object, struct text_pos, int *);
 static int trailing_whitespace_p (EMACS_INT);
-static unsigned long int message_log_check_duplicate (EMACS_INT, EMACS_INT,
-                                                     EMACS_INT, EMACS_INT);
+static unsigned long int message_log_check_duplicate (EMACS_INT, EMACS_INT);
 static void push_it (struct it *);
 static void pop_it (struct it *);
 static void sync_frame_with_window_matrix_rows (struct window *);
 static void select_frame_for_redisplay (Lisp_Object);
-static void redisplay_internal (int);
+static void redisplay_internal (void);
 static int echo_area_display (int);
 static void redisplay_windows (Lisp_Object);
 static void redisplay_window (Lisp_Object, int);
@@ -823,11 +823,9 @@ static int display_mode_lines (struct window *);
 static int display_mode_line (struct window *, enum face_id, Lisp_Object);
 static int display_mode_element (struct it *, int, int, int, Lisp_Object, Lisp_Object, int);
 static int store_mode_line_string (const char *, Lisp_Object, int, int, int, Lisp_Object);
-static const char *decode_mode_spec (struct window *, int, int, int,
-                                    Lisp_Object *);
+static const char *decode_mode_spec (struct window *, int, int, Lisp_Object *);
 static void display_menu_bar (struct window *);
-static int display_count_lines (EMACS_INT, EMACS_INT, EMACS_INT, int,
-                               EMACS_INT *);
+static int display_count_lines (EMACS_INT, EMACS_INT, int, EMACS_INT *);
 static int display_string (const char *, Lisp_Object, Lisp_Object,
                            EMACS_INT, EMACS_INT, struct it *, int, int, int, int);
 static void compute_line_metrics (struct it *);
@@ -1147,7 +1145,7 @@ line_bottom_y (struct it *it)
        line_height = last_height;
       else if (IT_CHARPOS (*it) < ZV)
        {
-         move_it_by_lines (it, 1, 1);
+         move_it_by_lines (it, 1);
          line_height = (it->max_ascent || it->max_descent
                         ? it->max_ascent + it->max_descent
                         : last_height);
@@ -1271,7 +1269,7 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
 
       it2 = it;
       if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
-       move_it_by_lines (&it, 1, 0);
+       move_it_by_lines (&it, 1);
       if (charpos < IT_CHARPOS (it)
          || (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
        {
@@ -4420,20 +4418,18 @@ display_prop_string_p (Lisp_Object prop, Lisp_Object string)
   return 0;
 }
 
-/* Look for STRING in overlays and text properties in W's buffer,
-   between character positions FROM and TO (excluding TO).
+/* Look for STRING in overlays and text properties in the current
+   buffer, between character positions FROM and TO (excluding TO).
    BACK_P non-zero means look back (in this case, TO is supposed to be
    less than FROM).
    Value is the first character position where STRING was found, or
    zero if it wasn't found before hitting TO.
 
-   W's buffer must be current.
-
    This function may only use code that doesn't eval because it is
    called asynchronously from note_mouse_highlight.  */
 
 static EMACS_INT
-string_buffer_position_lim (struct window *w, Lisp_Object string,
+string_buffer_position_lim (Lisp_Object string,
                            EMACS_INT from, EMACS_INT to, int back_p)
 {
   Lisp_Object limit, prop, pos;
@@ -4471,27 +4467,25 @@ string_buffer_position_lim (struct window *w, Lisp_Object string,
   return found ? XINT (pos) : 0;
 }
 
-/* Determine which buffer position in W's buffer STRING comes from.
+/* Determine which buffer position in current buffer STRING comes from.
    AROUND_CHARPOS is an approximate position where it could come from.
    Value is the buffer position or 0 if it couldn't be determined.
 
-   W's buffer must be current.
-
    This function is necessary because we don't record buffer positions
    in glyphs generated from strings (to keep struct glyph small).
    This function may only use code that doesn't eval because it is
    called asynchronously from note_mouse_highlight.  */
 
-EMACS_INT
-string_buffer_position (struct window *w, Lisp_Object string, EMACS_INT around_charpos)
+static EMACS_INT
+string_buffer_position (Lisp_Object string, EMACS_INT around_charpos)
 {
   const int MAX_DISTANCE = 1000;
-  EMACS_INT found = string_buffer_position_lim (w, string, around_charpos,
+  EMACS_INT found = string_buffer_position_lim (string, around_charpos,
                                                around_charpos + MAX_DISTANCE,
                                                0);
 
   if (!found)
-    found = string_buffer_position_lim (w, string, around_charpos,
+    found = string_buffer_position_lim (string, around_charpos,
                                        around_charpos - MAX_DISTANCE, 1);
   return found;
 }
@@ -7643,7 +7637,7 @@ move_it_vertically_backward (struct it *it, int dy)
       /* DY == 0 means move to the start of the screen line.  The
         value of nlines is > 0 if continuation lines were involved.  */
       if (nlines > 0)
-       move_it_by_lines (it, nlines, 1);
+       move_it_by_lines (it, nlines);
     }
   else
     {
@@ -7687,7 +7681,7 @@ move_it_vertically_backward (struct it *it, int dy)
            {
              do
                {
-                 move_it_by_lines (it, 1, 1);
+                 move_it_by_lines (it, 1);
                }
              while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
            }
@@ -7717,7 +7711,7 @@ move_it_vertically (struct it *it, int dy)
       if (IT_CHARPOS (*it) == ZV
          && ZV > BEGV
          && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
-       move_it_by_lines (it, 0, 0);
+       move_it_by_lines (it, 0);
     }
 }
 
@@ -7737,15 +7731,14 @@ move_it_past_eol (struct it *it)
 
 /* Move IT by a specified number DVPOS of screen lines down.  DVPOS
    negative means move up.  DVPOS == 0 means move to the start of the
-   screen line.  NEED_Y_P non-zero means calculate IT->current_y.  If
-   NEED_Y_P is zero, IT->current_y will be left unchanged.
+   screen line.
 
-   Further optimization ideas: If we would know that IT->f doesn't use
+   Optimization idea: If we would know that IT->f doesn't use
    a face with proportional font, we could be faster for
    truncate-lines nil.  */
 
 void
-move_it_by_lines (struct it *it, int dvpos, int need_y_p)
+move_it_by_lines (struct it *it, int dvpos)
 {
 
   /* The commented-out optimization uses vmotion on terminals.  This
@@ -7967,7 +7960,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
              c = string_char_and_length (msg + i, &char_bytes);
              work[0] = (ASCII_CHAR_P (c)
                         ? c
-                        : multibyte_char_to_unibyte (c, Qnil));
+                        : multibyte_char_to_unibyte (c));
              insert_1_both (work, 1, 1, 1, 0, 0);
            }
        }
@@ -8008,8 +8001,8 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
              prev_bol = PT;
              prev_bol_byte = PT_BYTE;
 
-             dups = message_log_check_duplicate (prev_bol, prev_bol_byte,
-                                                 this_bol, this_bol_byte);
+             dups = message_log_check_duplicate (prev_bol_byte,
+                                                  this_bol_byte);
              if (dups)
                {
                  del_range_both (prev_bol, prev_bol_byte,
@@ -8084,8 +8077,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
    value N > 1 if we should also append " [N times]".  */
 
 static unsigned long int
-message_log_check_duplicate (EMACS_INT prev_bol, EMACS_INT prev_bol_byte,
-                            EMACS_INT this_bol, EMACS_INT this_bol_byte)
+message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte)
 {
   EMACS_INT i;
   EMACS_INT len = Z_BYTE - 1 - this_bol_byte;
@@ -8415,10 +8407,18 @@ vmessage (const char *m, va_list ap)
        {
          if (m)
            {
-             EMACS_INT len;
-
-             len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
+             char *buf = FRAME_MESSAGE_BUF (f);
+             size_t bufsize = FRAME_MESSAGE_BUF_SIZE (f);
+             int len = vsnprintf (buf, bufsize, m, ap);
+             if (len < 0)
+               len = 0;
+
+             /* Do any truncation at a character boundary.  */
+             if (0 < bufsize && bufsize <= len)
+               for (len = bufsize - 1;
+                    len && ! CHAR_HEAD_P (buf[len - 1]);
+                    len--)
+                 continue;
 
              message2 (FRAME_MESSAGE_BUF (f), len, 0);
            }
@@ -8442,22 +8442,6 @@ message (const char *m, ...)
 }
 
 
-/* The non-logging version of message.  */
-
-void
-message_nolog (const char *m, ...)
-{
-  Lisp_Object old_log_max;
-  va_list ap;
-  va_start (ap, m);
-  old_log_max = Vmessage_log_max;
-  Vmessage_log_max = Qnil;
-  vmessage (m, ap);
-  Vmessage_log_max = old_log_max;
-  va_end (ap);
-}
-
-
 /* Display the current message in the current mini-buffer.  This is
    only called from error handlers in process.c, and is not time
    critical.  */
@@ -8843,7 +8827,7 @@ resize_echo_area_exactly (void)
        {
          ++windows_or_buffers_changed;
          ++update_mode_lines;
-         redisplay_internal (0);
+         redisplay_internal ();
        }
     }
 }
@@ -9228,7 +9212,7 @@ set_message_1 (EMACS_INT a1, Lisp_Object a2, EMACS_INT nbytes, EMACS_INT multiby
              c = string_char_and_length (msg + i, &n);
              work[0] = (ASCII_CHAR_P (c)
                         ? c
-                        : multibyte_char_to_unibyte (c, Qnil));
+                        : multibyte_char_to_unibyte (c));
              insert_1_both (work, 1, 1, 1, 0, 0);
            }
        }
@@ -9384,7 +9368,7 @@ echo_area_display (int update_frame_p)
              int count = SPECPDL_INDEX ();
              specbind (Qredisplay_dont_pause, Qt);
              windows_or_buffers_changed = 1;
-             redisplay_internal (0);
+             redisplay_internal ();
              unbind_to (count, Qnil);
            }
          else if (FRAME_WINDOW_P (f) && n == 0)
@@ -11155,7 +11139,7 @@ text_outside_line_unchanged_p (struct window *w,
 void
 redisplay (void)
 {
-  redisplay_internal (0);
+  redisplay_internal ();
 }
 
 
@@ -11419,14 +11403,11 @@ do { if (polling_stopped_here) start_polling ();      \
        polling_stopped_here = 0; } while (0)
 
 
-/* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay is not in
-   response to any user action; therefore, we should preserve the echo
-   area.  (Actually, our caller does that job.)  Perhaps in the future
-   avoid recentering windows if it is not necessary; currently that
-   causes some problems.  */
+/* Perhaps in the future avoid recentering windows if it
+   is not necessary; currently that causes some problems.  */
 
 static void
-redisplay_internal (int preserve_echo_area)
+redisplay_internal (void)
 {
   struct window *w = XWINDOW (selected_window);
   struct window *sw;
@@ -12186,11 +12167,11 @@ redisplay_preserve_echo_area (int from_where)
       /* We have a previously displayed message, but no current
         message.  Redisplay the previous message.  */
       display_last_displayed_message_p = 1;
-      redisplay_internal (1);
+      redisplay_internal ();
       display_last_displayed_message_p = 0;
     }
   else
-    redisplay_internal (1);
+    redisplay_internal ();
 
   if (FRAME_RIF (SELECTED_FRAME ()) != NULL
       && FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
@@ -12731,7 +12712,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                  EMACS_INT tem;
 
                  str = glyph->object;
-                 tem = string_buffer_position_lim (w, str, pos, pos_after, 0);
+                 tem = string_buffer_position_lim (str, pos, pos_after, 0);
                  if (tem == 0  /* from overlay */
                      || pos <= tem)
                    {
@@ -13003,6 +12984,12 @@ enum
   SCROLLING_NEED_LARGER_MATRICES
 };
 
+/* If scroll-conservatively is more than this, never recenter.
+
+   If you change this, don't forget to update the doc string of
+   `scroll-conservatively' and the Emacs manual.  */
+#define SCROLL_LIMIT 100
+
 static int
 try_scrolling (Lisp_Object window, int just_this_one_p,
               EMACS_INT arg_scroll_conservatively, EMACS_INT scroll_step,
@@ -13016,7 +13003,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   int dy = 0, amount_to_scroll = 0, scroll_down_p = 0;
   int extra_scroll_margin_lines = last_line_misfit ? 1 : 0;
   Lisp_Object aggressive;
-  int scroll_limit = INT_MAX / FRAME_LINE_HEIGHT (f);
+  /* We will never try scrolling more than this number of lines.  */
+  int scroll_limit = SCROLL_LIMIT;
 
 #if GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
@@ -13032,14 +13020,14 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   else
     this_scroll_margin = 0;
 
-  /* Force arg_scroll_conservatively to have a reasonable value, to avoid
-     overflow while computing how much to scroll.  Note that the user
-     can supply scroll-conservatively equal to `most-positive-fixnum',
-     which can be larger than INT_MAX.  */
+  /* Force arg_scroll_conservatively to have a reasonable value, to
+     avoid scrolling too far away with slow move_it_* functions.  Note
+     that the user can supply scroll-conservatively equal to
+     `most-positive-fixnum', which can be larger than INT_MAX.  */
   if (arg_scroll_conservatively > scroll_limit)
     {
-      arg_scroll_conservatively = scroll_limit;
-      scroll_max = INT_MAX;
+      arg_scroll_conservatively = scroll_limit + 1;
+      scroll_max = scroll_limit * FRAME_LINE_HEIGHT (f);
     }
   else if (scroll_step || arg_scroll_conservatively || temp_scroll_step)
     /* Compute how much we should try to scroll maximally to bring
@@ -13076,13 +13064,10 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          /* Compute how many pixels below window bottom to stop searching
             for PT.  This avoids costly search for PT that is far away if
             the user limited scrolling by a small number of lines, but
-            always finds PT if arg_scroll_conservatively is set to a large
+            always finds PT if scroll_conservatively is set to a large
             number, such as most-positive-fixnum.  */
          int slack = max (scroll_max, 10 * FRAME_LINE_HEIGHT (f));
-         int y_to_move =
-           slack >= INT_MAX - it.last_visible_y
-           ? INT_MAX
-           : it.last_visible_y + slack;
+         int y_to_move = it.last_visible_y + slack;
 
          /* Compute the distance from the scroll margin to PT or to
             the scroll limit, whichever comes first.  This should
@@ -13121,6 +13106,10 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
              amount_to_scroll = float_amount;
              if (amount_to_scroll == 0 && float_amount > 0)
                amount_to_scroll = 1;
+             /* Don't let point enter the scroll margin near top of
+                the window.  */
+             if (amount_to_scroll > height - 2*this_scroll_margin + dy)
+               amount_to_scroll = height - 2*this_scroll_margin + dy;
            }
        }
 
@@ -13128,12 +13117,12 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
        return SCROLLING_FAILED;
 
       start_display (&it, w, startp);
-      if (scroll_max < INT_MAX)
+      if (arg_scroll_conservatively <= scroll_limit)
        move_it_vertically (&it, amount_to_scroll);
       else
        {
          /* Extra precision for users who set scroll-conservatively
-            to most-positive-fixnum: make sure the amount we scroll
+            to a large number: make sure the amount we scroll
             the window start is never less than amount_to_scroll,
             which was computed as distance from window bottom to
             point.  This matters when lines at window top and lines
@@ -13144,14 +13133,14 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          int start_y = line_bottom_y (&it1);
 
          do {
-           move_it_by_lines (&it, 1, 1);
+           move_it_by_lines (&it, 1);
            it1 = it;
          } while (line_bottom_y (&it1) - start_y < amount_to_scroll);
        }
 
       /* If STARTP is unchanged, move it down another screen line.  */
       if (CHARPOS (it.current.pos) == CHARPOS (startp))
-       move_it_by_lines (&it, 1, 1);
+       move_it_by_lines (&it, 1);
       startp = it.current.pos;
     }
   else
@@ -13171,16 +13160,19 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
        {
          /* Point is in the scroll margin at the top of the window or
             above what is displayed in the window.  */
-         int y0;
+         int y0, y_to_move;
 
          /* Compute the vertical distance from PT to the scroll
-            margin position.  Give up if distance is greater than
-            scroll_max.  */
+            margin position.  Move as far as scroll_max allows, or
+            one screenful, or 10 screen lines, whichever is largest.
+            Give up if distance is greater than scroll_max.  */
          SET_TEXT_POS (pos, PT, PT_BYTE);
          start_display (&it, w, pos);
          y0 = it.current_y;
+         y_to_move = max (it.last_visible_y,
+                          max (scroll_max, 10 * FRAME_LINE_HEIGHT (f)));
          move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
-                     it.last_visible_y, -1,
+                     y_to_move, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
          dy = it.current_y - y0;
          if (dy > scroll_max)
@@ -13190,8 +13182,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          start_display (&it, w, startp);
 
          if (arg_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
@@ -13204,6 +13196,12 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
                  amount_to_scroll = float_amount;
                  if (amount_to_scroll == 0 && float_amount > 0)
                    amount_to_scroll = 1;
+                 amount_to_scroll -=
+                   this_scroll_margin - dy - FRAME_LINE_HEIGHT (f);
+                 /* Don't let point enter the scroll margin near
+                    bottom of the window.  */
+                 if (amount_to_scroll > height - 2*this_scroll_margin + dy)
+                   amount_to_scroll = height - 2*this_scroll_margin + dy;
                }
            }
 
@@ -13312,7 +13310,7 @@ compute_window_start_on_continuation_line (struct window *w)
            {
              min_distance = distance;
              pos = it.current.pos;
-             move_it_by_lines (&it, 1, 0);
+             move_it_by_lines (&it, 1);
            }
 
          /* Set the window start there.  */
@@ -13457,7 +13455,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                     && row < w->current_matrix->rows
                                + w->current_matrix->nrows - 1
                     && MATRIX_ROW_START_CHARPOS (row+1) == PT
-                    && !cursor_row_p (w, row))
+                    && !cursor_row_p (row))
                ++row;
 
              /* If within the scroll margin, scroll.  Note that
@@ -13509,7 +13507,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                 skip forward over overlay strings.  */
              while (MATRIX_ROW_BOTTOM_Y (row) < last_y
                     && MATRIX_ROW_END_CHARPOS (row) == PT
-                    && !cursor_row_p (w, row))
+                    && !cursor_row_p (row))
                ++row;
 
              /* If within the scroll margin, scroll.  */
@@ -13605,7 +13603,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                {
                  if (MATRIX_ROW_START_CHARPOS (row) <= PT
                      && PT <= MATRIX_ROW_END_CHARPOS (row)
-                     && cursor_row_p (w, row))
+                     && cursor_row_p (row))
                    rv |= set_cursor_from_row (w, row, w->current_matrix,
                                               0, 0, 0, 0);
                  /* As soon as we've found the first suitable row
@@ -13644,7 +13642,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                }
              while (MATRIX_ROW_BOTTOM_Y (row) < last_y
                     && MATRIX_ROW_START_CHARPOS (row) == PT
-                    && cursor_row_p (w, row));
+                    && cursor_row_p (row));
            }
        }
     }
@@ -14201,11 +14199,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        }
     }
 
-  /* Finally, just choose place to start which centers point */
+  /* Finally, just choose a place to start which positions point
+     according to user preferences.  */
 
  recenter:
-  if (centering_position < 0)
-    centering_position = window_box_height (w) / 2;
 
 #if GLYPH_DEBUG
   debug_method_add (w, "recenter");
@@ -14217,10 +14214,77 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   if (!buffer_unchanged_p)
     w->base_line_number = Qnil;
 
-  /* Move backward half the height of the window.  */
+  /* Determine the window start relative to point.  */
   init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
   it.current_y = it.last_visible_y;
+  if (centering_position < 0)
+    {
+      int margin =
+       scroll_margin > 0
+       ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+       : 0;
+      EMACS_INT margin_pos = CHARPOS (startp);
+      int scrolling_up;
+      Lisp_Object aggressive;
+
+      /* If there is a scroll margin at the top of the window, find
+        its character position.  */
+      if (margin)
+       {
+         struct it it1;
+
+         start_display (&it1, w, startp);
+         move_it_vertically (&it1, margin);
+         margin_pos = IT_CHARPOS (it1);
+       }
+      scrolling_up = PT > margin_pos;
+      aggressive =
+       scrolling_up
+       ? BVAR (current_buffer, scroll_up_aggressively)
+       : BVAR (current_buffer, scroll_down_aggressively);
+
+      if (!MINI_WINDOW_P (w)
+         && (scroll_conservatively > SCROLL_LIMIT || NUMBERP (aggressive)))
+       {
+         int pt_offset = 0;
+
+         /* Setting scroll-conservatively overrides
+            scroll-*-aggressively.  */
+         if (!scroll_conservatively && NUMBERP (aggressive))
+           {
+             double float_amount = XFLOATINT (aggressive);
+
+             pt_offset = float_amount * WINDOW_BOX_TEXT_HEIGHT (w);
+             if (pt_offset == 0 && float_amount > 0)
+               pt_offset = 1;
+             if (pt_offset)
+               margin -= 1;
+           }
+         /* Compute how much to move the window start backward from
+            point so that point will be displayed where the user
+            wants it.  */
+         if (scrolling_up)
+           {
+             centering_position = it.last_visible_y;
+             if (pt_offset)
+               centering_position -= pt_offset;
+             centering_position -=
+               FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0));
+             /* Don't let point enter the scroll margin near top of
+                the window.  */
+             if (centering_position < margin * FRAME_LINE_HEIGHT (f))
+               centering_position = margin * FRAME_LINE_HEIGHT (f);
+           }
+         else
+           centering_position = margin * FRAME_LINE_HEIGHT (f) + pt_offset;
+       }
+      else
+       /* Set the window start half the height of the window backward
+          from point.  */
+       centering_position = window_box_height (w) / 2;
+    }
   move_it_vertically_backward (&it, centering_position);
+
   xassert (IT_CHARPOS (it) >= BEGV);
 
   /* The function move_it_vertically_backward may move over more
@@ -14237,8 +14301,9 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
   it.current_x = it.hpos = 0;
 
-  /* Set startp here explicitly in case that helps avoid an infinite loop
-     in case the window-scroll-functions functions get errors.  */
+  /* Set the window start position here explicitly, to avoid an
+     infinite loop in case the functions in window-scroll-functions
+     get errors.  */
   set_marker_both (w->start, Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
 
   /* Run scroll hooks.  */
@@ -14274,13 +14339,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          && PT >= Z - XFASTINT (w->window_end_pos))
        {
          clear_glyph_matrix (w->desired_matrix);
-         move_it_by_lines (&it, 1, 0);
+         move_it_by_lines (&it, 1);
          try_window (window, it.current.pos, 0);
        }
       else if (PT < IT_CHARPOS (it))
        {
          clear_glyph_matrix (w->desired_matrix);
-         move_it_by_lines (&it, -1, 0);
+         move_it_by_lines (&it, -1);
          try_window (window, it.current.pos, 0);
        }
       else
@@ -14643,8 +14708,6 @@ try_window_reusing_current_matrix (struct window *w)
 
   if (CHARPOS (new_start) <= CHARPOS (start))
     {
-      int first_row_y;
-
       /* Don't use this method if the display starts with an ellipsis
         displayed for invisible text.  It's not easy to handle that case
         below, and it's certainly not worth the effort since this is
@@ -14659,7 +14722,6 @@ try_window_reusing_current_matrix (struct window *w)
         text.  Note that it.vpos == 0 if or if not there is a
          header-line; it's not the same as the MATRIX_ROW_VPOS!  */
       start_display (&it, w, new_start);
-      first_row_y = it.current_y;
       w->cursor.vpos = -1;
       last_text_row = last_reused_text_row = NULL;
 
@@ -16971,11 +17033,11 @@ highlight_trailing_whitespace (struct frame *f, struct glyph_row *row)
 }
 
 
-/* Value is non-zero if glyph row ROW in window W should be
+/* Value is non-zero if glyph row ROW should be
    used to hold the cursor.  */
 
 static int
-cursor_row_p (struct window *w, struct glyph_row *row)
+cursor_row_p (struct glyph_row *row)
 {
   int result = 1;
 
@@ -17888,7 +17950,7 @@ display_line (struct it *it)
           && !MATRIX_ROW (it->w->desired_matrix, cvpos)->ends_at_zv_p))
       && PT >= MATRIX_ROW_START_CHARPOS (row)
       && PT <= MATRIX_ROW_END_CHARPOS (row)
-      && cursor_row_p (it->w, row))
+      && cursor_row_p (row))
     set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
 
   /* Highlight trailing whitespace.  */
@@ -18540,7 +18602,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
                    charpos = (STRING_MULTIBYTE (elt)
                               ? string_byte_to_char (elt, bytepos)
                               : bytepos);
-                   spec = decode_mode_spec (it->w, c, field, prec, &string);
+                   spec = decode_mode_spec (it->w, c, field, &string);
                    multibyte = STRINGP (string) && STRING_MULTIBYTE (string);
 
                    switch (mode_line_target)
@@ -19211,9 +19273,8 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_
 }
 
 /* Return a string for the output of a mode line %-spec for window W,
-   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 a Lisp string in
+   generated by character C.  FIELD_WIDTH > 0 means pad the string
+   returned with spaces to that value.  Return a Lisp string in
    *STRING if the resulting string is taken from that Lisp string.
 
    Note we operate on the current buffer for most purposes,
@@ -19223,7 +19284,7 @@ static char lots_of_dashes[] = "------------------------------------------------
 
 static const char *
 decode_mode_spec (struct window *w, register int c, int field_width,
-                 int precision, Lisp_Object *string)
+                 Lisp_Object *string)
 {
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
@@ -19412,7 +19473,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
          }
 
        /* Count lines from base line to window start position.  */
-       nlines = display_count_lines (linepos, linepos_byte,
+       nlines = display_count_lines (linepos_byte,
                                      startpos_byte,
                                      startpos, &junk);
 
@@ -19441,7 +19502,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
                limit_byte = CHAR_TO_BYTE (limit);
              }
 
-           nlines = display_count_lines (startpos, startpos_byte,
+           nlines = display_count_lines (startpos_byte,
                                          limit_byte,
                                          - (height * 2 + 30),
                                          &position);
@@ -19460,7 +19521,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
          }
 
        /* Now count lines from the start pos to point.  */
-       nlines = display_count_lines (startpos, startpos_byte,
+       nlines = display_count_lines (startpos_byte,
                                      PT_BYTE, PT, &junk);
 
        /* Record that we did display the line number.  */
@@ -19630,14 +19691,14 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 }
 
 
-/* Count up to COUNT lines starting from START / START_BYTE.
+/* Count up to COUNT lines starting from START_BYTE.
    But don't go beyond LIMIT_BYTE.
    Return the number of lines thus found (always nonnegative).
 
    Set *BYTE_POS_PTR to 1 if we found COUNT lines, 0 if we hit LIMIT.  */
 
 static int
-display_count_lines (EMACS_INT start, EMACS_INT start_byte,
+display_count_lines (EMACS_INT start_byte,
                     EMACS_INT limit_byte, int count,
                     EMACS_INT *byte_pos_ptr)
 {
@@ -20401,16 +20462,15 @@ append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
 }
 
 
-/* Get face and two-byte form of character C in face FACE_ID on frame
-   F.  The encoding of C is returned in *CHAR2B.  MULTIBYTE_P non-zero
-   means we want to display multibyte text.  DISPLAY_P non-zero means
+/* Get face and two-byte form of character C in face FACE_ID on frame F.
+   The encoding of C is returned in *CHAR2B.  DISPLAY_P non-zero means
    make sure that X resources for the face returned are allocated.
    Value is a pointer to a realized face that is ready for display if
    DISPLAY_P is non-zero.  */
 
 static INLINE struct face *
 get_char_face_and_encoding (struct frame *f, int c, int face_id,
-                           XChar2b *char2b, int multibyte_p, int display_p)
+                           XChar2b *char2b, int display_p)
 {
   struct face *face = FACE_FROM_ID (f, face_id);
 
@@ -20530,7 +20590,7 @@ fill_composite_glyph_string (struct glyph_string *s, struct face *base_face,
                                       -1, Qnil);
 
          face = get_char_face_and_encoding (s->f, c, face_id,
-                                            s->char2b + i, 1, 1);
+                                            s->char2b + i, 1);
          if (face)
            {
              if (! s->face)
@@ -20729,15 +20789,13 @@ fill_image_glyph_string (struct glyph_string *s)
 
 /* Fill glyph string S from a sequence of stretch glyphs.
 
-   ROW is the glyph row in which the glyphs are found, AREA is the
-   area within the row.  START is the index of the first glyph to
-   consider, END is the index of the last + 1.
+   START is the index of the first glyph to consider,
+   END is the index of the last + 1.
 
    Value is the index of the first glyph not in S.  */
 
 static int
-fill_stretch_glyph_string (struct glyph_string *s, struct glyph_row *row,
-                          enum glyph_row_area area, int start, int end)
+fill_stretch_glyph_string (struct glyph_string *s, int start, int end)
 {
   struct glyph *glyph, *last;
   int voffset, face_id;
@@ -20771,7 +20829,7 @@ fill_stretch_glyph_string (struct glyph_string *s, struct glyph_row *row,
 }
 
 static struct font_metrics *
-get_per_char_metric (struct frame *f, struct font *font, XChar2b *char2b)
+get_per_char_metric (struct font *font, XChar2b *char2b)
 {
   static struct font_metrics metrics;
   unsigned code = (XCHAR2B_BYTE1 (char2b) << 8) | XCHAR2B_BYTE2 (char2b);
@@ -20799,7 +20857,7 @@ x_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *rig
       struct font_metrics *pcm;
 
       face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
-      if (face->font && (pcm = get_per_char_metric (f, face->font, &char2b)))
+      if (face->font && (pcm = get_per_char_metric (face->font, &char2b)))
        {
          if (pcm->rbearing > pcm->width)
            *right = pcm->rbearing - pcm->width;
@@ -21033,7 +21091,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
        {                                                                   \
         s = (struct glyph_string *) alloca (sizeof *s);                    \
         INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);              \
-        START = fill_stretch_glyph_string (s, row, area, START, END);      \
+        START = fill_stretch_glyph_string (s, START, END);                 \
         append_glyph_string (&HEAD, &TAIL, s);                             \
          s->x = (X);                                                       \
        }                                                                   \
@@ -22406,7 +22464,7 @@ x_produce_glyphs (struct it *it)
 
          if (get_char_glyph_code (it->char_to_display, font, &char2b))
            {
-             pcm = get_per_char_metric (it->f, font, &char2b);
+             pcm = get_per_char_metric (font, &char2b);
              if (pcm->width == 0
                  && pcm->rbearing == 0 && pcm->lbearing == 0)
                pcm = NULL;
@@ -22708,8 +22766,8 @@ x_produce_glyphs (struct it *it)
          if (! font_not_found_p)
            {
              get_char_face_and_encoding (it->f, c, it->face_id,
-                                         &char2b, it->multibyte_p, 0);
-             pcm = get_per_char_metric (it->f, font, &char2b);
+                                         &char2b, 0);
+             pcm = get_per_char_metric (font, &char2b);
            }
 
          /* Initialize the bounding box.  */
@@ -22757,7 +22815,6 @@ x_produce_glyphs (struct it *it)
              int ch = COMPOSITION_GLYPH (cmp, i);
              int face_id;
              struct face *this_face;
-             int this_boff;
 
              if (ch == '\t')
                ch = ' ';
@@ -22769,12 +22826,9 @@ x_produce_glyphs (struct it *it)
                pcm = NULL;
              else
                {
-                 this_boff = font->baseline_offset;
-                 if (font->vertical_centering)
-                   this_boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
                  get_char_face_and_encoding (it->f, ch, face_id,
-                                             &char2b, it->multibyte_p, 0);
-                 pcm = get_per_char_metric (it->f, font, &char2b);
+                                             &char2b, 0);
+                 pcm = get_per_char_metric (font, &char2b);
                }
              if (! pcm)
                cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
@@ -24324,7 +24378,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
             END_CHARPOS, or if they come from an overlay.  */
          if (EQ (glyph->object, before_string))
            {
-             pos = string_buffer_position (w, before_string,
+             pos = string_buffer_position (before_string,
                                            start_charpos);
              /* If pos == 0, it means before_string came from an
                 overlay, not from a buffer position.  */
@@ -24333,7 +24387,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
            }
          else if (EQ (glyph->object, after_string))
            {
-             pos = string_buffer_position (w, after_string, end_charpos);
+             pos = string_buffer_position (after_string, end_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
@@ -24375,7 +24429,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
             END_CHARPOS, or if they come from an overlay.  */
          if (EQ (glyph->object, before_string))
            {
-             pos = string_buffer_position (w, before_string, start_charpos);
+             pos = string_buffer_position (before_string, start_charpos);
              /* If pos == 0, it means before_string came from an
                 overlay, not from a buffer position.  */
              if (!pos || (pos >= start_charpos && pos < end_charpos))
@@ -24383,7 +24437,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
            }
          else if (EQ (glyph->object, after_string))
            {
-             pos = string_buffer_position (w, after_string, end_charpos);
+             pos = string_buffer_position (after_string, end_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
@@ -24441,13 +24495,13 @@ mouse_face_from_buffer_pos (Lisp_Object window,
             END_CHARPOS, or if they come from an overlay.  */
          if (EQ (end->object, before_string))
            {
-             pos = string_buffer_position (w, before_string, start_charpos);
+             pos = string_buffer_position (before_string, start_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
          else if (EQ (end->object, after_string))
            {
-             pos = string_buffer_position (w, after_string, end_charpos);
+             pos = string_buffer_position (after_string, end_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
@@ -24491,13 +24545,13 @@ mouse_face_from_buffer_pos (Lisp_Object window,
             END_CHARPOS, or if they come from an overlay.  */
          if (EQ (end->object, before_string))
            {
-             pos = string_buffer_position (w, before_string, start_charpos);
+             pos = string_buffer_position (before_string, start_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
          else if (EQ (end->object, after_string))
            {
-             pos = string_buffer_position (w, after_string, end_charpos);
+             pos = string_buffer_position (after_string, end_charpos);
              if (!pos || (pos >= start_charpos && pos < end_charpos))
                break;
            }
@@ -24974,10 +25028,9 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
              CONSP (hotspot))
          && (hotspot = XCDR (hotspot), CONSP (hotspot)))
        {
-         Lisp_Object area_id, plist;
+         Lisp_Object plist;
 
-         area_id = XCAR (hotspot);
-         /* Could check AREA_ID to see if we enter/leave this hot-spot.
+         /* Could check XCAR (hotspot) to see if we enter/leave this hot-spot.
             If so, we could look for mouse-enter, mouse-leave
             properties in PLIST (and do something...).  */
          hotspot = XCDR (hotspot);
@@ -25312,10 +25365,10 @@ note_mouse_highlight (struct frame *f, int x, int y)
                      CONSP (hotspot))
                  && (hotspot = XCDR (hotspot), CONSP (hotspot)))
                {
-                 Lisp_Object area_id, plist;
+                 Lisp_Object plist;
 
-                 area_id = XCAR (hotspot);
-                 /* Could check AREA_ID to see if we enter/leave this hot-spot.
+                 /* Could check XCAR (hotspot) to see if we enter/leave
+                    this hot-spot.
                     If so, we could look for mouse-enter, mouse-leave
                     properties in PLIST (and do something...).  */
                  hotspot = XCDR (hotspot);
@@ -25481,7 +25534,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                     check if the text under it has one.  */
                  struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
                  EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
-                 pos = string_buffer_position (w, object, start);
+                 pos = string_buffer_position (object, start);
                  if (pos > 0)
                    {
                      mouse_face = get_char_property_and_overlay
@@ -25591,7 +25644,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                    struct glyph_row *r
                      = MATRIX_ROW (w->current_matrix, vpos);
                    EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
-                   EMACS_INT p = string_buffer_position (w, obj, start);
+                   EMACS_INT p = string_buffer_position (obj, start);
                    if (p > 0)
                      {
                        help = Fget_char_property (make_number (p),
@@ -25647,7 +25700,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                      struct glyph_row *r
                        = MATRIX_ROW (w->current_matrix, vpos);
                      EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
-                     EMACS_INT p = string_buffer_position (w, obj, start);
+                     EMACS_INT p = string_buffer_position (obj, start);
                      if (p > 0)
                        pointer = Fget_char_property (make_number (p),
                                                      Qpointer, w->buffer);
@@ -26524,6 +26577,10 @@ If point moves off-screen, redisplay will scroll by up to
 onto the screen again.  If that cannot be done, then redisplay
 recenters point as usual.
 
+If the value is greater than 100, redisplay will never recenter point,
+but will always scroll just enough text to bring point into view, even
+if you move far away.
+
 A value of zero means always recenter point if it moves off screen.  */);
   scroll_conservatively = 0;