From 9583ec36c459ecf14237b08ee2e29fe301a63c4e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 15 Jun 2013 12:34:20 +0300 Subject: [PATCH] Fix bug #14567 with jumpy scrolling of tall images. src/xdisp.c (Fline_pixel_height): New function, required for solving bug #14567. lisp/simple.el (line-move-partial): Don't jump to the next screen line as soon as it becomes visible. Instead, continue enlarging the vscroll until the portion of a tall screen line that's left on display is about the height of the frame's default font. --- lisp/ChangeLog | 8 +++++++ lisp/simple.el | 61 ++++++++++++++++++++++++++++++++++++-------------- src/ChangeLog | 5 +++++ src/xdisp.c | 19 ++++++++++++++++ 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index cced6eb0043..fadbabf808e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,11 @@ +2013-06-15 Eli Zaretskii + + * simple.el (line-move-partial): Don't jump to the next screen + line as soon as it becomes visible. Instead, continue enlarging + the vscroll until the portion of a tall screen line that's left on + display is about the height of the frame's default font. + (Bug#14567) + 2013-06-15 Glenn Morris * vc/vc-dispatcher.el (vc-compilation-mode): Avoid making diff --git a/lisp/simple.el b/lisp/simple.el index 3fd94e96d33..34ebc8f122f 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -4738,42 +4738,62 @@ lines." (vpos (nth 1 lh)) (ypos (nth 2 lh)) (rbot (nth 3 lh)) + (this-lh (window-line-height)) + (this-height (nth 0 this-lh)) + (this-ypos (nth 2 this-lh)) + (fch (frame-char-height)) py vs) (when (or (null lh) - (>= rbot (frame-char-height)) - (<= ypos (- (frame-char-height)))) + (>= rbot fch) + (<= ypos (- fch)) + (null this-lh) + (<= this-ypos (- fch))) (unless lh (let ((wend (pos-visible-in-window-p t nil t))) (setq rbot (nth 3 wend) vpos (nth 5 wend)))) + (unless this-lh + (let ((wstart (pos-visible-in-window-p nil nil t))) + (setq this-ypos (nth 2 wstart) + this-height (nth 4 wstart)))) + (setq py + (or (nth 1 this-lh) + (let ((ppos (posn-at-point))) + (cdr (or (posn-actual-col-row ppos) + (posn-col-row ppos)))))) (cond - ;; If last line of window is fully visible, move forward. - ((or (null rbot) (= rbot 0)) + ;; If last line of window is fully visible, and vscrolling + ;; more would make this line invisible, move forward. + ((and (or (< (setq vs (window-vscroll nil t)) fch) + (null this-height) + (<= this-height fch)) + (or (null rbot) (= rbot 0))) nil) - ;; If cursor is not in the bottom scroll margin, move forward. - ((and (> vpos 0) - (< (setq py - (or (nth 1 (window-line-height)) - (let ((ppos (posn-at-point))) - (cdr (or (posn-actual-col-row ppos) - (posn-col-row ppos)))))) + ;; If cursor is not in the bottom scroll margin, and the + ;; current line is is not too tall, move forward. + ((and (or (null this-height) (<= this-height fch)) + vpos + (> vpos 0) + (< py (min (- (window-text-height) scroll-margin 1) (1- vpos)))) nil) ;; When already vscrolled, we vscroll some more if we can, ;; or clear vscroll and move forward at end of tall image. - ((> (setq vs (window-vscroll nil t)) 0) - (when (> rbot 0) - (set-window-vscroll nil (+ vs (min rbot (frame-char-height))) t))) + ((> vs 0) + (when (or (and rbot (> rbot 0)) + (and this-height (> this-height fch))) + (set-window-vscroll nil (+ vs fch) t))) ;; If cursor just entered the bottom scroll margin, move forward, ;; but also vscroll one line so redisplay won't recenter. - ((and (> vpos 0) + ((and vpos + (> vpos 0) (= py (min (- (window-text-height) scroll-margin 1) (1- vpos)))) (set-window-vscroll nil (frame-char-height) t) (line-move-1 arg noerror to-end) t) ;; If there are lines above the last line, scroll-up one line. - ((> vpos 0) + ((and vpos (> vpos 0)) (scroll-up 1) t) ;; Finally, start vscroll. @@ -4808,7 +4828,14 @@ lines." ;; display-based motion doesn't make sense (because each ;; logical line occupies exactly one screen line). (not (> (window-hscroll) 0))) - (line-move-visual arg noerror) + (prog1 (line-move-visual arg noerror) + ;; If we moved into a tall line, set vscroll to make + ;; scrolling through tall images more smooth. + (let ((lh (line-pixel-height))) + (if (and (< arg 0) + (< (point) (window-start)) + (> lh (frame-char-height))) + (set-window-vscroll nil (- lh (frame-char-height)) t)))) (line-move-1 arg noerror to-end))))) ;; Display-based alternative to line-move-1. diff --git a/src/ChangeLog b/src/ChangeLog index ec0fbc493cb..a26577c20a3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2013-06-15 Eli Zaretskii + + * xdisp.c (Fline_pixel_height): New function, required for solving + bug #14567. + 2013-06-15 Paul Eggert * fns.c (Fcopy_sequence): Simplify XTYPE calculation. diff --git a/src/xdisp.c b/src/xdisp.c index e1d6b0c9a27..54ea325f642 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1217,6 +1217,24 @@ line_bottom_y (struct it *it) return line_top_y + line_height; } +DEFUN ("line-pixel-height", Fline_pixel_height, + Sline_pixel_height, 0, 0, 0, + doc: /* Return height in pixels of text line in the selected window. + +Value is the height in pixels of the line at point. */) + (void) +{ + struct it it; + struct text_pos pt; + struct window *w = XWINDOW (selected_window); + + SET_TEXT_POS (pt, PT, PT_BYTE); + start_display (&it, w, pt); + it.vpos = it.current_y = 0; + last_height = 0; + return make_number (line_bottom_y (&it)); +} + /* Subroutine of pos_visible_p below. Extracts a display string, if any, from the display spec given as its argument. */ static Lisp_Object @@ -28691,6 +28709,7 @@ syms_of_xdisp (void) defsubr (&Stool_bar_lines_needed); defsubr (&Slookup_image_map); #endif + defsubr (&Sline_pixel_height); defsubr (&Sformat_mode_line); defsubr (&Sinvisible_p); defsubr (&Scurrent_bidi_paragraph_direction); -- 2.39.2