aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2021-11-26 08:41:39 +0800
committerPo Lu2021-11-26 11:06:43 +0800
commitdb3fbe884fb992376a6e00f2a051e5de9579df85 (patch)
tree76501c434f64b47f0f2828fe474e4ec9e4b71847
parent9d37be35227fcb419e7b52978f8d5a8b1379567f (diff)
downloademacs-db3fbe884fb992376a6e00f2a051e5de9579df85.tar.gz
emacs-db3fbe884fb992376a6e00f2a051e5de9579df85.zip
Add `better-pixel-scroll-mode'
* etc/NEWS: Announce `better-pixel-scroll-mode'. * lisp/better-pixel-scroll.el: New file.
-rw-r--r--etc/NEWS6
-rw-r--r--lisp/better-pixel-scroll.el145
2 files changed, 151 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index da56d0a338a..329de2f8110 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -93,6 +93,12 @@ buffer isn't displayed.
93This controls the thickness of the external borders of the menu bars 93This controls the thickness of the external borders of the menu bars
94and pop-up menus. 94and pop-up menus.
95 95
96---
97** New minor mode 'better-pixel-scroll-mode'.
98When enabled, using this mode with a capable scroll wheel will result
99in the display being scrolled precisely according to the turning of
100that wheel.
101
96** Terminal Emacs 102** Terminal Emacs
97 103
98--- 104---
diff --git a/lisp/better-pixel-scroll.el b/lisp/better-pixel-scroll.el
new file mode 100644
index 00000000000..ac342a425a2
--- /dev/null
+++ b/lisp/better-pixel-scroll.el
@@ -0,0 +1,145 @@
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 (when (zerop (vertical-motion -1))
92 (set-window-vscroll nil 0)
93 (signal 'beginning-of-buffer nil))
94 (setq current-y (- current-y (line-pixel-height)))))
95 (while (> delta 0)
96 (set-window-start nil (save-excursion
97 (goto-char (window-start))
98 (when (zerop (vertical-motion -1))
99 (set-window-vscroll nil 0)
100 (signal 'beginning-of-buffer nil))
101 (setq delta (- delta (line-pixel-height)))
102 (point))
103 t))
104 (when (< delta 0)
105 (when-let* ((desired-pos (posn-at-x-y 0 (+ (- delta)
106 (window-tab-line-height)
107 (window-header-line-height))))
108 (desired-start (posn-point desired-pos))
109 (desired-vscroll (cdr (posn-object-x-y desired-pos))))
110 (unless (eq (window-start) desired-start)
111 (set-window-start nil desired-start t))
112 (set-window-vscroll nil desired-vscroll t))))
113
114(defun better-pixel-scroll (event &optional arg)
115 "Scroll the display according to EVENT.
116Take into account any pixel deltas in EVENT to scroll the display
117according to the user's turning the mouse wheel. If EVENT does
118not have precise scrolling deltas, call `mwheel-scroll' instead.
119ARG is passed to `mwheel-scroll', should that be called."
120 (interactive (list last-input-event current-prefix-arg))
121 (if (nth 4 event)
122 (let ((delta (round (cdr (nth 4 event))))
123 (window (mwheel-event-window event)))
124 (if (> (abs delta) (window-text-height window t))
125 (mwheel-scroll event arg)
126 (with-selected-window window
127 (if (< delta 0)
128 (better-pixel-scroll-scroll-down (- delta))
129 (better-pixel-scroll-scroll-up delta)))))
130 (mwheel-scroll event arg)))
131
132;;;###autoload
133(define-minor-mode better-pixel-scroll-mode
134 "Toggle pixel scrolling.
135When enabled, this minor mode allows to scroll the display
136precisely, according to the turning of the mouse wheel."
137 :global t
138 :group 'mouse
139 :keymap better-pixel-scroll-mode-map
140 (setq x-coalesce-scroll-events
141 (not better-pixel-scroll-mode)))
142
143(provide 'better-pixel-scroll)
144
145;;; better-pixel-scroll.el ends here.