+ min_distance = distance;
+ pos = it.current.pos;
+ move_it_by_lines (&it, 1, 0);
+ }
+
+ /* Set the window start there. */
+ SET_MARKER_FROM_TEXT_POS (w->start, pos);
+ window_start_changed_p = 1;
+ }
+ }
+
+ return window_start_changed_p;
+}
+
+
+/* Try cursor movement in case text has not changes in window WINDOW,
+ with window start STARTP. Value is
+
+ 1 if successful
+
+ 0 if this method cannot be used
+
+ -1 if we know we have to scroll the display. *SCROLL_STEP is
+ set to 1, under certain circumstances, if we want to scroll as
+ if scroll-step were set to 1. See the code. */
+
+static int
+try_cursor_movement (window, startp, scroll_step)
+ Lisp_Object window;
+ struct text_pos startp;
+ int *scroll_step;
+{
+ struct window *w = XWINDOW (window);
+ struct frame *f = XFRAME (w->frame);
+ int rc = 0;
+
+ /* Handle case where text has not changed, only point, and it has
+ not moved off the frame. */
+ if (/* Point may be in this window. */
+ PT >= CHARPOS (startp)
+ /* If we don't check this, we are called to move the cursor in a
+ horizontally split window with a current matrix that doesn't
+ fit the display. */
+ && !windows_or_buffers_changed
+ /* Selective display hasn't changed. */
+ && !current_buffer->clip_changed
+ /* If force-mode-line-update was called, really redisplay;
+ that's how redisplay is forced after e.g. changing
+ buffer-invisibility-spec. */
+ && NILP (w->update_mode_line)
+ /* Can't use this case if highlighting a region. When a
+ region exists, cursor movement has to do more than just
+ set the cursor. */
+ && !(!NILP (Vtransient_mark_mode)
+ && !NILP (current_buffer->mark_active))
+ && NILP (w->region_showing)
+ && NILP (Vshow_trailing_whitespace)
+ /* Right after splitting windows, last_point may be nil. */
+ && INTEGERP (w->last_point)
+ /* This code is not used for mini-buffer for the sake of the case
+ of redisplaying to replace an echo area message; since in
+ that case the mini-buffer contents per se are usually
+ unchanged. This code is of no real use in the mini-buffer
+ since the handling of this_line_start_pos, etc., in redisplay
+ handles the same cases. */
+ && !EQ (window, minibuf_window)
+ /* When splitting windows or for new windows, it happens that
+ redisplay is called with a nil window_end_vpos or one being
+ larger than the window. This should really be fixed in
+ window.c. I don't have this on my list, now, so we do
+ approximately the same as the old redisplay code. --gerd. */
+ && INTEGERP (w->window_end_vpos)
+ && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
+ && (FRAME_WINDOW_P (f)
+ || !MARKERP (Voverlay_arrow_position)
+ || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+ {
+ int this_scroll_margin;
+ struct glyph_row *row;
+
+#if GLYPH_DEBUG
+ debug_method_add (w, "cursor movement");
+#endif
+
+ /* Scroll if point within this distance from the top or bottom
+ of the window. This is a pixel value. */
+ this_scroll_margin = max (0, scroll_margin);
+ this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
+ this_scroll_margin *= CANON_Y_UNIT (f);
+
+ /* 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
+ || w->last_cursor.vpos >= w->current_matrix->nrows)
+ rc = -1;
+ else
+ {
+ row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
+ if (row->mode_line_p)
+ ++row;
+ if (!row->enabled_p)
+ rc = -1;
+ }
+
+ if (rc == 0)
+ {
+ int scroll_p = 0;
+
+ if (PT > XFASTINT (w->last_point))
+ {
+ /* Point has moved forward. */
+ int last_y = window_text_bottom_y (w) - this_scroll_margin;
+
+ while (MATRIX_ROW_END_CHARPOS (row) < PT
+ && MATRIX_ROW_BOTTOM_Y (row) < last_y)
+ {
+ xassert (row->enabled_p);
+ ++row;
+ }
+
+ /* The end position of a row equals the start position
+ of the next row. If PT is there, we would rather
+ display it in the next line. Exceptions are when the
+ row ends in the middle of a character, or ends in
+ ZV. */
+ if (MATRIX_ROW_BOTTOM_Y (row) < last_y
+ && MATRIX_ROW_END_CHARPOS (row) == PT
+ && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)
+ && !row->ends_at_zv_p)
+ {
+ xassert (row->enabled_p);
+ ++row;
+ }
+
+ /* If within the scroll margin, scroll. Note that
+ MATRIX_ROW_BOTTOM_Y gives the pixel position at which
+ the next line would be drawn, and that
+ this_scroll_margin can be zero. */
+ if (MATRIX_ROW_BOTTOM_Y (row) > last_y
+ || PT > MATRIX_ROW_END_CHARPOS (row)
+ /* Line is completely visible last line in window
+ and PT is to be set in the next line. */
+ || (MATRIX_ROW_BOTTOM_Y (row) == last_y
+ && PT == MATRIX_ROW_END_CHARPOS (row)
+ && !row->ends_at_zv_p
+ && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+ scroll_p = 1;
+ }
+ else if (PT < XFASTINT (w->last_point))
+ {
+ /* Cursor has to be moved backward. Note that PT >=
+ 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
+ || CHARPOS (startp) == BEGV))
+ {
+ xassert (row->enabled_p);
+ --row;
+ }
+
+ /* Consider the following case: Window starts at BEGV,
+ there is invisible, intangible text at BEGV, so that
+ display starts at some point START > BEGV. It can
+ happen that we are called with PT somewhere between
+ BEGV and START. Try to handle that case. */
+ if (row < w->current_matrix->rows
+ || row->mode_line_p)
+ {
+ row = w->current_matrix->rows;
+ if (row->mode_line_p)
+ ++row;
+ }
+
+ /* Due to newlines in overlay strings, we may have to
+ skip forward over overlay strings. */
+ while (MATRIX_ROW_END_CHARPOS (row) == PT
+ && MATRIX_ROW_ENDS_IN_OVERLAY_STRING_P (row)
+ && !row->ends_at_zv_p)
+ ++row;
+
+ /* If within the scroll margin, scroll. */
+ if (row->y < this_scroll_margin
+ && CHARPOS (startp) != BEGV)
+ scroll_p = 1;
+ }
+
+ if (PT < MATRIX_ROW_START_CHARPOS (row)
+ || PT > MATRIX_ROW_END_CHARPOS (row))
+ {
+ /* if PT is not in the glyph row, give up. */
+ rc = -1;
+ }
+ else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+ {
+ /* If we end up in a partially visible line, let's make it
+ fully visible, except when it's taller than the window,
+ in which case we can't do much about it. */
+ if (row->height > window_box_height (w))
+ {
+ *scroll_step = 1;
+ rc = -1;
+ }
+ else
+ {
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ try_window (window, startp);
+ make_cursor_line_fully_visible (w);
+ rc = 1;
+ }
+ }
+ else if (scroll_p)
+ rc = -1;
+ else
+ {
+ set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+ rc = 1;