aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Möllmann2024-11-06 05:48:46 +0100
committerGerd Möllmann2024-11-06 05:48:46 +0100
commitd27fc61755d8dd4a65db6291f1c83492003b30b1 (patch)
tree35347adfae5af89199f933a7e01452082d658dd0
parent908a18c463bf7d2da3c39ea6141cab68fd7eac30 (diff)
downloademacs-d27fc61755d8dd4a65db6291f1c83492003b30b1.tar.gz
emacs-d27fc61755d8dd4a65db6291f1c83492003b30b1.zip
Add tty-tip.el, not tooltips, but very close
-rw-r--r--lisp/tty-tip.el196
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