diff options
| author | Gerd Möllmann | 2024-11-06 05:48:46 +0100 |
|---|---|---|
| committer | Gerd Möllmann | 2024-11-06 05:48:46 +0100 |
| commit | d27fc61755d8dd4a65db6291f1c83492003b30b1 (patch) | |
| tree | 35347adfae5af89199f933a7e01452082d658dd0 | |
| parent | 908a18c463bf7d2da3c39ea6141cab68fd7eac30 (diff) | |
| download | emacs-d27fc61755d8dd4a65db6291f1c83492003b30b1.tar.gz emacs-d27fc61755d8dd4a65db6291f1c83492003b30b1.zip | |
Add tty-tip.el, not tooltips, but very close
| -rw-r--r-- | lisp/tty-tip.el | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el new file mode 100644 index 00000000000..92a115b2008 --- /dev/null +++ b/lisp/tty-tip.el | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | ;;; -*- lexical-binding: t; symbol-packages: t; -*- | ||
| 2 | ;;; tty-tip.el --- Display help in kind of tooltips on ttys | ||
| 3 | |||
| 4 | ;; Copyright (C) 2024 Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | ;; it under the terms of the GNU General Public License as published by | ||
| 8 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 9 | ;; (at your option) any later version. | ||
| 10 | |||
| 11 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;; GNU General Public License for more details. | ||
| 15 | |||
| 16 | ;; You should have received a copy of the GNU General Public License | ||
| 17 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | ;;; Commentary: | ||
| 20 | |||
| 21 | ;; This uses tty child frames to display help which looks and feels much | ||
| 22 | ;; like using tooltips (but they really aren't). | ||
| 23 | |||
| 24 | ;; Use `tty-tip-mode' to activate or toggle this feature. | ||
| 25 | ;; | ||
| 26 | ;; You can customize face `tooltip', `tooltip-short-delay', | ||
| 27 | ;; `tooltip-delay', `tooltip-recent-seconds'. | ||
| 28 | |||
| 29 | (require 'tooltip) | ||
| 30 | |||
| 31 | (defvar tty-tip--frame nil) | ||
| 32 | |||
| 33 | (defun tty-tip--make-buffer (text) | ||
| 34 | (with-current-buffer | ||
| 35 | (get-buffer-create " *tty-tip*") | ||
| 36 | ;; Redirect focus to parent. | ||
| 37 | (add-hook 'pre-command-hook #'tty-tip--delete-frame nil t) | ||
| 38 | ;; Use an empty keymap. | ||
| 39 | (use-local-map (make-keymap)) | ||
| 40 | (dolist (var '((mode-line-format . nil) | ||
| 41 | (header-line-format . nil) | ||
| 42 | (tab-line-format . nil) | ||
| 43 | (tab-bar-format . nil) ;; Emacs 28 tab-bar-format | ||
| 44 | (frame-title-format . "") | ||
| 45 | (truncate-lines . t) | ||
| 46 | (cursor-in-non-selected-windows . nil) | ||
| 47 | (cursor-type . nil) | ||
| 48 | (show-trailing-whitespace . nil) | ||
| 49 | (display-line-numbers . nil) | ||
| 50 | (left-fringe-width . nil) | ||
| 51 | (right-fringe-width . nil) | ||
| 52 | (left-margin-width . 0) | ||
| 53 | (right-margin-width . 0) | ||
| 54 | (fringes-outside-margins . 0) | ||
| 55 | (buffer-read-only . t))) | ||
| 56 | (set (make-local-variable (car var)) (cdr var))) | ||
| 57 | (let ((inhibit-modification-hooks t) | ||
| 58 | (inhibit-read-only t)) | ||
| 59 | (erase-buffer) | ||
| 60 | (insert text) | ||
| 61 | (goto-char (point-min))) | ||
| 62 | (current-buffer))) | ||
| 63 | |||
| 64 | (defvar tty-tip-frame-parameters | ||
| 65 | `((visibility . nil) | ||
| 66 | (background-color . "lightyellow") | ||
| 67 | (foreground-color . "black") | ||
| 68 | (width . 0) (height . 0) | ||
| 69 | (min-width . t) (min-height . t) | ||
| 70 | (no-accept-focus . t) | ||
| 71 | (no-focus-on-map . t) | ||
| 72 | (border-width . 0) | ||
| 73 | (child-frame-border-width . 1) | ||
| 74 | (left-fringe . 0) | ||
| 75 | (right-fringe . 0) | ||
| 76 | (vertical-scroll-bars . nil) | ||
| 77 | (horizontal-scroll-bars . nil) | ||
| 78 | (menu-bar-lines . 0) | ||
| 79 | (tool-bar-lines . 0) | ||
| 80 | (tab-bar-lines . 0) | ||
| 81 | (no-other-frame . t) | ||
| 82 | (no-other-window . t) | ||
| 83 | (no-delete-other-windows . t) | ||
| 84 | (unsplittable . t) | ||
| 85 | (undecorated . t) | ||
| 86 | (cursor-type . nil) | ||
| 87 | (no-special-glyphs . t) | ||
| 88 | (desktop-dont-save . t))) | ||
| 89 | |||
| 90 | (defun tty-tip--frame-parameters () | ||
| 91 | (let ((params (copy-sequence tty-tip-frame-parameters)) | ||
| 92 | (fg (face-attribute 'tooltip :foreground)) | ||
| 93 | (bg (face-attribute 'tooltip :background))) | ||
| 94 | (when (stringp fg) | ||
| 95 | (setf (alist-get 'foreground-color params) fg)) | ||
| 96 | (when (stringp bg) | ||
| 97 | (setf (alist-get 'background-color params) bg)) | ||
| 98 | params)) | ||
| 99 | |||
| 100 | (defun tty-tip--delete-frame () | ||
| 101 | (when tty-tip--frame | ||
| 102 | (delete-frame tty-tip--frame) | ||
| 103 | (setq tty-tip--frame nil) | ||
| 104 | t)) | ||
| 105 | |||
| 106 | (defun tty-tip--compute-position () | ||
| 107 | (let* ((pos (mouse-position)) | ||
| 108 | (mouse-x (car (cdr pos))) | ||
| 109 | (mouse-y (cdr (cdr pos))) | ||
| 110 | (x (+ mouse-x 1)) | ||
| 111 | (y (+ mouse-y 1)) | ||
| 112 | (tip-width (frame-width tty-tip--frame)) | ||
| 113 | (tip-height (frame-height tty-tip--frame)) | ||
| 114 | (tty-width (display-pixel-width)) | ||
| 115 | (tty-height (display-pixel-height))) | ||
| 116 | (when (> (+ x tip-width) tty-width) | ||
| 117 | (setq x (max 0 (- x tip-width 1)))) | ||
| 118 | (when (> (+ y tip-height) tty-height) | ||
| 119 | (setq y (max 0 (- y tip-height 1)))) | ||
| 120 | (cons x y))) | ||
| 121 | |||
| 122 | (defun tty-tip--create-frame (text) | ||
| 123 | (let* ((minibuffer (minibuffer-window (window-frame))) | ||
| 124 | (buffer (tty-tip--make-buffer text)) | ||
| 125 | (window-min-height 1) | ||
| 126 | (window-min-width 1) | ||
| 127 | after-make-frame-functions | ||
| 128 | (text-lines (string-lines text))) | ||
| 129 | (setq tty-tip--frame | ||
| 130 | (make-frame | ||
| 131 | `((parent-frame . ,(car (mouse-position))) | ||
| 132 | (minibuffer . ,minibuffer) | ||
| 133 | ,@(tty-tip--frame-parameters)))) | ||
| 134 | (let ((win (frame-root-window tty-tip--frame))) | ||
| 135 | (set-window-buffer win buffer) | ||
| 136 | (set-window-dedicated-p win t) | ||
| 137 | (set-frame-size tty-tip--frame | ||
| 138 | (apply #'max (mapcar #'string-width text-lines)) | ||
| 139 | (length text-lines)) | ||
| 140 | (let* ((pos (tty-tip--compute-position)) | ||
| 141 | (x (car pos)) | ||
| 142 | (y (cdr pos))) | ||
| 143 | (set-frame-position tty-tip--frame x y)) | ||
| 144 | (make-frame-visible tty-tip--frame)))) | ||
| 145 | |||
| 146 | (defvar tty-tip--help-message nil) | ||
| 147 | (defvar tty-tip--hide-time nil) | ||
| 148 | (defvar tty-tip--timeout-id nil) | ||
| 149 | |||
| 150 | (defun tty-tip--delay () | ||
| 151 | (if (and tty-tip--hide-time | ||
| 152 | (time-less-p (time-since tty-tip--hide-time) | ||
| 153 | tooltip-recent-seconds)) | ||
| 154 | tooltip-short-delay | ||
| 155 | tooltip-delay)) | ||
| 156 | |||
| 157 | (defun tty-tip--cancel-delayed-tip () | ||
| 158 | (when tty-tip--timeout-id | ||
| 159 | (cancel-timer tty-tip--timeout-id) | ||
| 160 | (setq tty-tip--timeout-id nil))) | ||
| 161 | |||
| 162 | (defun tty-tip--start-delayed-tip () | ||
| 163 | (setq tty-tip--timeout-id | ||
| 164 | (run-with-timer (tty-tip--delay) nil | ||
| 165 | (lambda () | ||
| 166 | (tty-tip--create-frame | ||
| 167 | tty-tip--help-message))))) | ||
| 168 | |||
| 169 | (defun tty-tip--hide (&optional _ignored-arg) | ||
| 170 | (tty-tip--cancel-delayed-tip) | ||
| 171 | (when (tty-tip--delete-frame) | ||
| 172 | (setq tty-tip--hide-time (float-time)))) | ||
| 173 | |||
| 174 | (defun tty-tip--show-help (msg) | ||
| 175 | (let ((previous-help tty-tip--help-message)) | ||
| 176 | (setq tty-tip--help-message msg) | ||
| 177 | (cond ((null msg) | ||
| 178 | (tty-tip--hide)) | ||
| 179 | ((equal previous-help msg) | ||
| 180 | nil) | ||
| 181 | (t | ||
| 182 | (tty-tip--hide) | ||
| 183 | (tty-tip--start-delayed-tip))))) | ||
| 184 | |||
| 185 | ;;;###autoload | ||
| 186 | (define-minor-mode tty-tip-mode | ||
| 187 | "Global minor mode for displaying help in tty child frames." | ||
| 188 | :global t :group 'help | ||
| 189 | (unless (display-graphic-p) | ||
| 190 | (if tty-tip-mode | ||
| 191 | (setq show-help-function #'tty-tip--show-help) | ||
| 192 | (setq show-help-function nil)))) | ||
| 193 | |||
| 194 | (provide 'tty-tip) | ||
| 195 | |||
| 196 | ;;; End | ||