emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: The unwarranted scrolling assumption


From: Eli Zaretskii
Subject: Re: The unwarranted scrolling assumption
Date: Sun, 20 Jun 2010 18:24:18 +0300

> From: Lennart Borgman <address@hidden>
> Date: Sat, 19 Jun 2010 23:58:09 +0200
> Cc: address@hidden, address@hidden, address@hidden
> 
> Anyway the easiest way now seems that I take this trouble. I tried to
> apply your patch as sent, but I could not get it to work. Maybe you
> can just send me that function so I can replace that?

It's a bit silly to do that, when we have a dVCS, but here you go
anyway:

------------------------------------------------------------------
static int
try_scrolling (window, just_this_one_p, scroll_conservatively,
               scroll_step, temp_scroll_step, last_line_misfit)
     Lisp_Object window;
     int just_this_one_p;
     EMACS_INT scroll_conservatively, scroll_step;
     int temp_scroll_step;
     int last_line_misfit;
{
  struct window *w = XWINDOW (window);
  struct frame *f = XFRAME (w->frame);
  struct text_pos pos, startp;
  struct it it;
  int this_scroll_margin, scroll_max, rc, height;
  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);

#if GLYPH_DEBUG
  debug_method_add (w, "try_scrolling");
#endif

  SET_TEXT_POS_FROM_MARKER (startp, w->start);

  /* Compute scroll margin height in pixels.  We scroll when point is
     within this distance from the top or bottom of the window.  */
  if (scroll_margin > 0)
    this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
      * FRAME_LINE_HEIGHT (f);
  else
    this_scroll_margin = 0;

  /* Force 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.  */
  if (scroll_conservatively > scroll_limit)
    {
      scroll_conservatively = scroll_limit;
      scroll_max = INT_MAX;
    }
  else if (scroll_step || scroll_conservatively || temp_scroll_step)
    /* Compute how much we should try to scroll maximally to bring
       point into view.  */
    scroll_max = (max (scroll_step,
                       max (scroll_conservatively, temp_scroll_step))
                  * FRAME_LINE_HEIGHT (f));
  else if (NUMBERP (current_buffer->scroll_down_aggressively)
           || NUMBERP (current_buffer->scroll_up_aggressively))
    /* We're trying to scroll because of aggressive scrolling but no
       scroll_step is set.  Choose an arbitrary one.  */
    scroll_max = 10 * FRAME_LINE_HEIGHT (f);
  else
    scroll_max = 0;

 too_near_end:

  /* Decide whether to scroll down.  */
  if (PT > CHARPOS (startp))
    {
      int scroll_margin_y;

      /* Compute the pixel ypos of the scroll margin, then move it to
         either that ypos or PT, whichever comes first.  */
      start_display (&it, w, startp);
      scroll_margin_y = it.last_visible_y - this_scroll_margin
        - FRAME_LINE_HEIGHT (f) * extra_scroll_margin_lines;
      move_it_to (&it, PT, -1, scroll_margin_y - 1, -1,
                  (MOVE_TO_POS | MOVE_TO_Y));

      if (PT > CHARPOS (it.current.pos))
        {
          int y0 = line_bottom_y (&it);
          /* 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 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;

          /* Compute the distance from the scroll margin to PT or to
             the scroll limit, whichever comes first.  This should
             include the height of the cursor line, to make that line
             fully visible.  */
          move_it_to (&it, PT, -1, y_to_move,
                      -1, MOVE_TO_POS | MOVE_TO_Y);
          dy = line_bottom_y (&it) - y0;

          if (dy > scroll_max)
            return SCROLLING_FAILED;

          scroll_down_p = 1;
        }
    }

  if (scroll_down_p)
    {
      /* Point is in or below the bottom scroll margin, so move the
         window start down.  If scrolling conservatively, move it just
         enough down to make point visible.  If scroll_step is set,
         move it down by scroll_step.  */
      if (scroll_conservatively)
        amount_to_scroll
          = min (max (dy, FRAME_LINE_HEIGHT (f)),
                 FRAME_LINE_HEIGHT (f) * scroll_conservatively);
      else if (scroll_step || temp_scroll_step)
        amount_to_scroll = scroll_max;
      else
        {
          aggressive = current_buffer->scroll_up_aggressively;
          height = WINDOW_BOX_TEXT_HEIGHT (w);
          if (NUMBERP (aggressive))
            {
              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)
        return SCROLLING_FAILED;

      start_display (&it, w, startp);
      move_it_vertically (&it, 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);
      startp = it.current.pos;
    }
  else
    {
      struct text_pos scroll_margin_pos = startp;

      /* See if point is inside the scroll margin at the top of the
         window.  */
      if (this_scroll_margin)
        {
          start_display (&it, w, startp);
          move_it_vertically (&it, this_scroll_margin);
          scroll_margin_pos = it.current.pos;
        }

      if (PT < CHARPOS (scroll_margin_pos))
        {
          /* Point is in the scroll margin at the top of the window or
             above what is displayed in the window.  */
          int y0;

          /* Compute the vertical distance from PT to the scroll
             margin position.  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;
          move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
                      it.last_visible_y, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
          dy = it.current_y - y0;
          if (dy > scroll_max)
            return SCROLLING_FAILED;

          /* Compute new window start.  */
          start_display (&it, w, startp);

          if (scroll_conservatively)
            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
            {
              aggressive = current_buffer->scroll_down_aggressively;
              height = WINDOW_BOX_TEXT_HEIGHT (w);
              if (NUMBERP (aggressive))
                {
                  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)
            return SCROLLING_FAILED;

          move_it_vertically_backward (&it, amount_to_scroll);
          startp = it.current.pos;
        }
    }

  /* Run window scroll functions.  */
  startp = run_window_scroll_functions (window, startp);

  /* Display the window.  Give up if new fonts are loaded, or if point
     doesn't appear.  */
  if (!try_window (window, startp, 0))
    rc = SCROLLING_NEED_LARGER_MATRICES;
  else if (w->cursor.vpos < 0)
    {
      clear_glyph_matrix (w->desired_matrix);
      rc = SCROLLING_FAILED;
    }
  else
    {
      /* Maybe forget recorded base line for line number display.  */
      if (!just_this_one_p
          || current_buffer->clip_changed
          || BEG_UNCHANGED < CHARPOS (startp))
        w->base_line_number = Qnil;

      /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
        {
          clear_glyph_matrix (w->desired_matrix);
          ++extra_scroll_margin_lines;
          goto too_near_end;
        }
      rc = SCROLLING_SUCCESS;
    }

  return rc;
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]