aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2021-11-26 17:42:45 +0800
committerPo Lu2021-11-26 21:06:22 +0800
commit5d6e1c749a669d33db2936b106ae41ce59473ea1 (patch)
treeabf24c466996e9927720b51d6b802bbffe5b14e1
parent673eadaeb55de71016fab371613d8e930f6d7c04 (diff)
downloademacs-5d6e1c749a669d33db2936b106ae41ce59473ea1.tar.gz
emacs-5d6e1c749a669d33db2936b106ae41ce59473ea1.zip
Move the precision pixel scrolling feature to pixel-scroll.el
* etc/NEWS: Update NEWS entry for 'pixel-scroll-precision-mode' * lisp/better-pixel-scroll.el: Remove file. * src/pixel-scroll.el (x-coalesce-scroll-events): New variable declaration. (pixel-scroll-precision-mode-map): New variable. (pixel-scroll-precision-scroll-down): (pixel-scroll-precision-scroll-up): (pixel-scroll-precision): New functions. (pixel-scroll-precision-mode): New minor mode.
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/better-pixel-scroll.el147
-rw-r--r--lisp/pixel-scroll.el121
3 files changed, 127 insertions, 151 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 329de2f8110..3a0b46d3993 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -94,10 +94,12 @@ This controls the thickness of the external borders of the menu bars
94and pop-up menus. 94and pop-up menus.
95 95
96--- 96---
97** New minor mode 'better-pixel-scroll-mode'. 97** New minor mode 'pixel-scroll-precision-mode'.
98When enabled, using this mode with a capable scroll wheel will result 98When enabled, you can scroll the display up or down by individual
99in the display being scrolled precisely according to the turning of 99pixels in a way that corresponds with the movement of your mouse
100that wheel. 100wheel, if supported by the mouse wheel. Unlike 'pixel-scroll-mode',
101this mode scrolls the display pixel-by-pixel, as opposed to only
102animating line-by-line scrolls.
101 103
102** Terminal Emacs 104** Terminal Emacs
103 105
diff --git a/lisp/better-pixel-scroll.el b/lisp/better-pixel-scroll.el
deleted file mode 100644
index c1469108e05..00000000000
--- a/lisp/better-pixel-scroll.el
+++ /dev/null
@@ -1,147 +0,0 @@
1;;; better-pixel-scroll.el --- Pixel scrolling support -*- lexical-binding:t -*-
2
3;; Copyright (C) 2021 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Commentary:
21
22;; This enables the use of smooth scroll events provided by XInput 2
23;; or NS to scroll the display according to the user's precise turning
24;; of the mouse wheel.
25
26;;; Code:
27
28(require 'mwheel)
29(require 'subr-x)
30
31(defvar x-coalesce-scroll-events)
32
33(defvar better-pixel-scroll-mode-map
34 (let ((map (make-sparse-keymap)))
35 (define-key map [wheel-down] #'better-pixel-scroll)
36 (define-key map [wheel-up] #'better-pixel-scroll)
37 map)
38 "The key map used by `better-pixel-scroll-mode'.")
39
40(defun better-pixel-scroll-scroll-down (delta)
41 "Scroll the current window down by DELTA pixels.
42Note that this function doesn't work if DELTA is larger than
43the height of the current window."
44 (when-let* ((posn (posn-at-point))
45 (current-y (cdr (posn-x-y posn)))
46 (min-y (+ (window-tab-line-height)
47 (window-header-line-height)))
48 (cursor-height (line-pixel-height))
49 (window-height (window-text-height nil t))
50 (next-height (save-excursion
51 (vertical-motion 1)
52 (line-pixel-height))))
53 (if (and (> delta 0)
54 (<= cursor-height window-height))
55 (while (< (- current-y min-y) delta)
56 (vertical-motion 1)
57 (setq current-y (+ current-y
58 (line-pixel-height)))
59 (when (eobp)
60 (error "End of buffer")))
61 (when (< (- (cdr (posn-object-width-height posn))
62 (cdr (posn-object-x-y posn)))
63 (- window-height next-height))
64 (vertical-motion 1)
65 (setq posn (posn-at-point)
66 current-y (cdr (posn-x-y posn)))
67 (while (< (- current-y min-y) delta)
68 (vertical-motion 1)
69 (setq current-y (+ current-y
70 (line-pixel-height)))
71 (when (eobp)
72 (error "End of buffer")))))
73 (let* ((desired-pos (posn-at-x-y 0 (+ delta
74 (window-tab-line-height)
75 (window-header-line-height))))
76 (desired-start (posn-point desired-pos))
77 (desired-vscroll (cdr (posn-object-x-y desired-pos))))
78 (unless (eq (window-start) desired-start)
79 (set-window-start nil desired-start t))
80 (set-window-vscroll nil desired-vscroll t))))
81
82(defun better-pixel-scroll-scroll-up (delta)
83 "Scroll the current window up by DELTA pixels."
84 (when-let* ((max-y (- (window-text-height nil t)
85 (window-tab-line-height)
86 (window-header-line-height)))
87 (posn (posn-at-point))
88 (current-y (+ (cdr (posn-x-y posn))
89 (cdr (posn-object-width-height posn)))))
90 (while (< (- max-y current-y) delta)
91 (vertical-motion -1)
92 (setq current-y (- current-y (line-pixel-height)))))
93 (let ((current-vscroll (window-vscroll nil t)))
94 (setq delta (- delta current-vscroll))
95 (set-window-vscroll nil 0 t))
96 (while (> delta 0)
97 (set-window-start nil (save-excursion
98 (goto-char (window-start))
99 (when (zerop (vertical-motion -1))
100 (set-window-vscroll nil 0)
101 (signal 'beginning-of-buffer nil))
102 (setq delta (- delta (line-pixel-height)))
103 (point))
104 t))
105 (when (< delta 0)
106 (when-let* ((desired-pos (posn-at-x-y 0 (+ (- delta)
107 (window-tab-line-height)
108 (window-header-line-height))))
109 (desired-start (posn-point desired-pos))
110 (desired-vscroll (cdr (posn-object-x-y desired-pos))))
111 (unless (eq (window-start) desired-start)
112 (set-window-start nil desired-start t))
113 (set-window-vscroll nil desired-vscroll t))))
114
115(defun better-pixel-scroll (event &optional arg)
116 "Scroll the display according to EVENT.
117Take into account any pixel deltas in EVENT to scroll the display
118according to the user's turning the mouse wheel. If EVENT does
119not have precise scrolling deltas, call `mwheel-scroll' instead.
120ARG is passed to `mwheel-scroll', should that be called."
121 (interactive (list last-input-event current-prefix-arg))
122 (let ((window (mwheel-event-window event)))
123 (if (and (nth 4 event)
124 (zerop (window-hscroll window)))
125 (let ((delta (round (cdr (nth 4 event)))))
126 (if (> (abs delta) (window-text-height window t))
127 (mwheel-scroll event arg)
128 (with-selected-window window
129 (if (< delta 0)
130 (better-pixel-scroll-scroll-down (- delta))
131 (better-pixel-scroll-scroll-up delta)))))
132 (mwheel-scroll event arg))))
133
134;;;###autoload
135(define-minor-mode better-pixel-scroll-mode
136 "Toggle pixel scrolling.
137When enabled, this minor mode allows to scroll the display
138precisely, according to the turning of the mouse wheel."
139 :global t
140 :group 'mouse
141 :keymap better-pixel-scroll-mode-map
142 (setq x-coalesce-scroll-events
143 (not better-pixel-scroll-mode)))
144
145(provide 'better-pixel-scroll)
146
147;;; better-pixel-scroll.el ends here.
diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el
index 249484cf581..f6d1d0ff8ca 100644
--- a/lisp/pixel-scroll.el
+++ b/lisp/pixel-scroll.el
@@ -67,6 +67,7 @@
67;;; Code: 67;;; Code:
68 68
69(require 'mwheel) 69(require 'mwheel)
70(require 'subr-x)
70 71
71(defvar pixel-wait 0 72(defvar pixel-wait 0
72 "Idle time on each step of pixel scroll specified in second. 73 "Idle time on each step of pixel scroll specified in second.
@@ -90,6 +91,15 @@ is always with pixel resolution.")
90(defvar pixel-last-scroll-time 0 91(defvar pixel-last-scroll-time 0
91 "Time when the last scrolling was made, in second since the epoch.") 92 "Time when the last scrolling was made, in second since the epoch.")
92 93
94(defvar x-coalesce-scroll-events)
95
96(defvar pixel-scroll-precision-mode-map
97 (let ((map (make-sparse-keymap)))
98 (define-key map [wheel-down] #'pixel-scroll-precision)
99 (define-key map [wheel-up] #'pixel-scroll-precision)
100 map)
101 "The key map used by `pixel-scroll-precision-mode'.")
102
93(defun pixel-scroll-in-rush-p () 103(defun pixel-scroll-in-rush-p ()
94 "Return non-nil if next scroll should be non-smooth. 104 "Return non-nil if next scroll should be non-smooth.
95When scrolling request is delivered soon after the previous one, 105When scrolling request is delivered soon after the previous one,
@@ -354,5 +364,116 @@ Otherwise, redisplay will reset the window's vscroll."
354 (set-window-start nil (pixel-point-at-unseen-line) t) 364 (set-window-start nil (pixel-point-at-unseen-line) t)
355 (set-window-vscroll nil vscroll t)) 365 (set-window-vscroll nil vscroll t))
356 366
367;; FIXME: This doesn't work when DELTA is larger than the height
368;; of the current window, and someone should probably fix that
369;; at some point.
370(defun pixel-scroll-precision-scroll-down (delta)
371 "Scroll the current window down by DELTA pixels.
372Note that this function doesn't work if DELTA is larger than
373the height of the current window."
374 (when-let* ((posn (posn-at-point))
375 (current-y (cdr (posn-x-y posn)))
376 (min-y (+ (frame-char-height)
377 (window-tab-line-height)
378 (window-header-line-height)))
379 (cursor-height (line-pixel-height))
380 (window-height (window-text-height nil t))
381 (next-height (save-excursion
382 (vertical-motion 1)
383 (line-pixel-height))))
384 (if (and (> delta 0)
385 (<= cursor-height window-height))
386 (while (< (- current-y min-y) delta)
387 (vertical-motion 1)
388 (setq current-y (+ current-y
389 (line-pixel-height)))
390 (when (eobp)
391 (signal 'end-of-buffer nil)))
392 (when (< (- (cdr (posn-object-width-height posn))
393 (cdr (posn-object-x-y posn)))
394 (- window-height next-height))
395 (vertical-motion 1)
396 (setq posn (posn-at-point)
397 current-y (cdr (posn-x-y posn)))
398 (while (< (- current-y min-y) delta)
399 (vertical-motion 1)
400 (setq current-y (+ current-y
401 (line-pixel-height)))
402 (when (eobp)
403 (signal 'end-of-buffer nil)))))
404 (let* ((desired-pos (posn-at-x-y 0 (+ delta
405 (window-tab-line-height)
406 (window-header-line-height))))
407 (desired-start (posn-point desired-pos))
408 (desired-vscroll (cdr (posn-object-x-y desired-pos))))
409 (unless (eq (window-start) desired-start)
410 (set-window-start nil desired-start t))
411 (set-window-vscroll nil desired-vscroll t))))
412
413(defun pixel-scroll-precision-scroll-up (delta)
414 "Scroll the current window up by DELTA pixels."
415 (when-let* ((max-y (- (window-text-height nil t)
416 (frame-char-height)
417 (window-tab-line-height)
418 (window-header-line-height)))
419 (posn (posn-at-point))
420 (current-y (+ (cdr (posn-x-y posn))
421 (line-pixel-height))))
422 (while (< (- max-y current-y) delta)
423 (vertical-motion -1)
424 (setq current-y (- current-y (line-pixel-height)))))
425 (let ((current-vscroll (window-vscroll nil t)))
426 (setq delta (- delta current-vscroll))
427 (set-window-vscroll nil 0 t))
428 (while (> delta 0)
429 (set-window-start nil (save-excursion
430 (goto-char (window-start))
431 (when (zerop (vertical-motion -1))
432 (set-window-vscroll nil 0)
433 (signal 'beginning-of-buffer nil))
434 (setq delta (- delta (line-pixel-height)))
435 (point))
436 t))
437 (when (< delta 0)
438 (when-let* ((desired-pos (posn-at-x-y 0 (+ (- delta)
439 (window-tab-line-height)
440 (window-header-line-height))))
441 (desired-start (posn-point desired-pos))
442 (desired-vscroll (cdr (posn-object-x-y desired-pos))))
443 (unless (eq (window-start) desired-start)
444 (set-window-start nil desired-start t))
445 (set-window-vscroll nil desired-vscroll t))))
446
447;; FIXME: This doesn't work when there's an image above the current
448;; line that is taller than the window.
449(defun pixel-scroll-precision (event)
450 "Scroll the display vertically by pixels according to EVENT.
451Move the display up or down by the pixel deltas in EVENT to
452scroll the display according to the user's turning the mouse
453wheel."
454 (interactive "e")
455 (let ((window (mwheel-event-window event)))
456 (if (and (nth 4 event)
457 (zerop (window-hscroll window)))
458 (let ((delta (round (cdr (nth 4 event)))))
459 (if (> (abs delta) (window-text-height window t))
460 (mwheel-scroll event nil)
461 (with-selected-window window
462 (if (< delta 0)
463 (pixel-scroll-precision-scroll-down (- delta))
464 (pixel-scroll-precision-scroll-up delta)))))
465 (mwheel-scroll event nil))))
466
467;;;###autoload
468(define-minor-mode pixel-scroll-precision-mode
469 "Toggle pixel scrolling.
470When enabled, this minor mode allows to scroll the display
471precisely, according to the turning of the mouse wheel."
472 :global t
473 :group 'mouse
474 :keymap pixel-scroll-precision-mode-map
475 (setq x-coalesce-scroll-events
476 (not pixel-scroll-precision-mode)))
477
357(provide 'pixel-scroll) 478(provide 'pixel-scroll)
358;;; pixel-scroll.el ends here 479;;; pixel-scroll.el ends here