diff options
| author | Po Lu | 2021-11-26 08:41:39 +0800 |
|---|---|---|
| committer | Po Lu | 2021-11-26 11:06:43 +0800 |
| commit | db3fbe884fb992376a6e00f2a051e5de9579df85 (patch) | |
| tree | 76501c434f64b47f0f2828fe474e4ec9e4b71847 | |
| parent | 9d37be35227fcb419e7b52978f8d5a8b1379567f (diff) | |
| download | emacs-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/NEWS | 6 | ||||
| -rw-r--r-- | lisp/better-pixel-scroll.el | 145 |
2 files changed, 151 insertions, 0 deletions
| @@ -93,6 +93,12 @@ buffer isn't displayed. | |||
| 93 | This controls the thickness of the external borders of the menu bars | 93 | This controls the thickness of the external borders of the menu bars |
| 94 | and pop-up menus. | 94 | and pop-up menus. |
| 95 | 95 | ||
| 96 | --- | ||
| 97 | ** New minor mode 'better-pixel-scroll-mode'. | ||
| 98 | When enabled, using this mode with a capable scroll wheel will result | ||
| 99 | in the display being scrolled precisely according to the turning of | ||
| 100 | that 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. | ||
| 42 | Note that this function doesn't work if DELTA is larger than | ||
| 43 | the 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. | ||
| 116 | Take into account any pixel deltas in EVENT to scroll the display | ||
| 117 | according to the user's turning the mouse wheel. If EVENT does | ||
| 118 | not have precise scrolling deltas, call `mwheel-scroll' instead. | ||
| 119 | ARG 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. | ||
| 135 | When enabled, this minor mode allows to scroll the display | ||
| 136 | precisely, 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. | ||