]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve precision pixel scrolling
authorPo Lu <luangruo@yahoo.com>
Sat, 12 Aug 2023 02:21:34 +0000 (10:21 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 12 Aug 2023 02:21:34 +0000 (10:21 +0800)
* 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.

lisp/pixel-scroll.el
src/image.c
src/xdisp.c

index ac867a1351c62d80babd6da8d198972ff006ec6e..488f67812549b5d434b4a6d96b6e01046f0a3b88 100644 (file)
@@ -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
index 29e88f0d752b0f50caf0ac224be6ae8633ad1300..7849675b6cca0cc2d3cc38a106707fcd8fcd7adf 100644 (file)
@@ -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;
index d055bb3bf6a1ddf7e9d030d4d33faf9e9f0f0264..69aa9bb9c336792d80ade1f958eed0e0db34d47f 100644 (file)
@@ -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);
 }