From: Po Lu Date: Sat, 12 Aug 2023 02:21:34 +0000 (+0800) Subject: Improve precision pixel scrolling X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1da4fca0647ebf1d5d6f12817301a17661560810;p=emacs.git Improve precision pixel scrolling * lisp/pixel-scroll.el (pixel-scroll-precision-scroll-down-page) (pixel-scroll-precision-scroll-up-page): Use pos-visible-in-window-p to opt between the next line or to the window start rather than computing the next position by hand. (pixel-scroll-precision-mode): Disable make-cursor-line-fully-visible. (bug#65214) * src/image.c (jpeg_load_body): Fix crash if libjpeg detects an error before ximg is initialized. * src/xdisp.c (display_and_set_cursor): Don't display cursor in vscrolled-away row. --- diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el index ac867a1351c..488f6781254 100644 --- a/lisp/pixel-scroll.el +++ b/lisp/pixel-scroll.el @@ -519,38 +519,41 @@ the height of the current window." (desired-vscroll (if start-posn (- delta (cdr (posn-x-y start-posn))) (+ current-vs delta))) - (edges (window-edges nil t)) - (usable-height (- (nth 3 edges) - (nth 1 edges))) - (next-pos (save-excursion - (goto-char desired-start) - (when (zerop (vertical-motion (1+ scroll-margin))) - (set-window-start nil desired-start) - (signal 'end-of-buffer nil)) - (while (when-let ((posn (posn-at-point))) - (< (cdr (posn-x-y posn)) delta)) - (when (zerop (vertical-motion 1)) - (set-window-start nil desired-start) - (signal 'end-of-buffer nil))) - (point))) (scroll-preserve-screen-position nil) - (auto-window-vscroll nil)) - (when (and (or (< (point) next-pos)) - (let ((pos-visibility (pos-visible-in-window-p next-pos nil t))) - (and pos-visibility - (or (eq (length pos-visibility) 2) - (when-let* ((posn (posn-at-point next-pos))) - (> (cdr (posn-object-width-height posn)) - usable-height)))))) - (goto-char next-pos)) - (set-window-start nil (if (zerop (window-hscroll)) - desired-start - (save-excursion - (goto-char desired-start) - (beginning-of-visual-line) - (point))) - t) - (set-window-vscroll nil desired-vscroll t t))) + (auto-window-vscroll nil) + (new-start-position (if (zerop (window-hscroll)) + desired-start + (save-excursion + (goto-char desired-start) + (beginning-of-visual-line) + (point))))) + (set-window-start nil new-start-position + (not (zerop desired-vscroll))) + (set-window-vscroll nil desired-vscroll t t) + ;; Constrain point to a location that will not result in + ;; recentering, if it is no longer completely visible. + (unless (pos-visible-in-window-p (point)) + ;; If desired-vscroll is 0, target the window start itself. But + ;; in any other case, target the line immediately below the + ;; window start, unless that line is itself invisible. This + ;; improves the appearance of the window by maintaining the + ;; cursor row in a fully visible state. + (if (zerop desired-vscroll) + (goto-char new-start-position) + (let ((line-after (save-excursion + (goto-char new-start-position) + (if (zerop (vertical-motion 1)) + (progn + (set-window-vscroll nil 0 t t) + nil) ; nil means move to new-start-position. + (point))))) + (if (not line-after) + (progn + (goto-char new-start-position) + (signal 'end-of-buffer nil)) + (if (pos-visible-in-window-p line-after nil t) + (goto-char line-after) + (goto-char new-start-position)))))))) (defun pixel-scroll-precision-scroll-down (delta) "Scroll the current window down by DELTA pixels." @@ -569,27 +572,12 @@ the height of the current window." (let* ((edges (window-edges nil t nil t)) (max-y (- (nth 3 edges) (nth 1 edges))) - (usable-height max-y) (posn (posn-at-x-y 0 (+ (window-tab-line-height) (window-header-line-height) (- max-y delta)))) - (point (posn-point posn)) - (up-point (and point - (save-excursion - (goto-char point) - (vertical-motion (- (1+ scroll-margin))) - (point))))) - (when (and point (> (point) up-point)) - (when (let ((pos-visible (pos-visible-in-window-p up-point nil t))) - (or (eq (length pos-visible) 2) - (when-let* ((posn (posn-at-point up-point)) - (edges (window-edges nil t)) - (usable-height (- (nth 3 edges) - (nth 1 edges)))) - (> (cdr (posn-object-width-height posn)) - usable-height)))) - (goto-char up-point))) - (let ((current-vscroll (window-vscroll nil t))) + (point (posn-point posn))) + (let ((current-vscroll (window-vscroll nil t)) + (wanted-pos (window-start))) (setq delta (- delta current-vscroll)) (set-window-vscroll nil 0 t t) (when (> delta 0) @@ -598,16 +586,25 @@ the height of the current window." start nil nil nil t)) (height (nth 1 dims)) (position (nth 2 dims))) - (set-window-start nil position t) - ;; If the line above is taller than the window height (i.e. there's - ;; a very tall image), keep point on it. - (when (> height usable-height) - (goto-char position)) + (setq wanted-pos position) (when (or (not position) (eq position start)) (signal 'beginning-of-buffer nil)) (setq delta (- delta height)))) + (set-window-start nil wanted-pos + (not (zerop delta))) (when (< delta 0) - (set-window-vscroll nil (- delta) t t))))) + (set-window-vscroll nil (- delta) t t)) + ;; vscroll and the window start are now set. Move point to a + ;; position where redisplay will not recenter, if it is now + ;; outside the window. + (unless (pos-visible-in-window-p (point)) + (let ((up-pos (save-excursion + (goto-char point) + (vertical-motion -1) + (point)))) + (if (pos-visible-in-window-p up-pos nil t) + (goto-char up-pos) + (goto-char (window-start)))))))) (defun pixel-scroll-precision-interpolate (delta &optional old-window factor) "Interpolate a scroll of DELTA pixels. @@ -860,7 +857,9 @@ precisely, according to the turning of the mouse wheel." :group 'mouse :keymap pixel-scroll-precision-mode-map (setq mwheel-coalesce-scroll-events - (not pixel-scroll-precision-mode))) + (not pixel-scroll-precision-mode)) + (setq-default make-cursor-line-fully-visible + (not pixel-scroll-precision-mode))) (provide 'pixel-scroll) ;;; pixel-scroll.el ends here diff --git a/src/image.c b/src/image.c index 29e88f0d752..7849675b6cc 100644 --- a/src/image.c +++ b/src/image.c @@ -8838,7 +8838,8 @@ jpeg_load_body (struct frame *f, struct image *img, jpeg_destroy_decompress (&mgr->cinfo); /* If we already have an XImage, free that. */ - image_destroy_x_image (ximg); + if (ximg) + image_destroy_x_image (ximg); /* Free pixmap and colors. */ image_clear_image (f, img); return 0; diff --git a/src/xdisp.c b/src/xdisp.c index d055bb3bf6a..69aa9bb9c33 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -33790,6 +33790,7 @@ display_and_set_cursor (struct window *w, bool on, completely erased, to avoid the extra work of erasing the cursor twice. In other words, phys_cursor_on_p can be true and the cursor still not be visible, or it has only been partly erased. */ + if (on) { w->phys_cursor_ascent = glyph_row->ascent; @@ -33803,9 +33804,15 @@ display_and_set_cursor (struct window *w, bool on, w->phys_cursor.vpos = vpos; } - FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, - new_cursor_type, new_cursor_width, - on, active_cursor); + /* If make_cursor_line_fully_visible is nil and the row is in fact + vscrolled out of the window, then glyph_row->y + + glyph_row->height will be less than or equal to 0. Eschew + displaying the cursor in that case. */ + + if (MATRIX_ROW_BOTTOM_Y (glyph_row) > 0) + FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, + new_cursor_type, new_cursor_width, + on, active_cursor); }