*** empty log message ***
[bpt/emacs.git] / lisp / tooltip.el
CommitLineData
b670783a 1;;; tooltip.el --- show tooltip windows
7840ced1 2
0d30b337
TTN
3;; Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
7840ced1
GM
5
6;; Author: Gerd Moellmann <gerd@acm.org>
7;; Keywords: help c mouse tools
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
7840ced1
GM
25
26;;; Commentary:
27
7840ced1
GM
28;;; Code:
29
5673b222
JB
30(defvar comint-prompt-regexp)
31
7840ced1
GM
32;;; Customizable settings
33
34(defgroup tooltip nil
35 "Customization group for the `tooltip' package."
36 :group 'help
3e6ed970 37 :group 'gud
7840ced1
GM
38 :group 'mouse
39 :group 'tools
01b23b99 40 :version "21.1"
7840ced1
GM
41 :tag "Tool Tips")
42
88751b11 43(defcustom tooltip-delay 0.7
7840ced1
GM
44 "Seconds to wait before displaying a tooltip the first time."
45 :tag "Delay"
46 :type 'number
47 :group 'tooltip)
48
7840ced1
GM
49(defcustom tooltip-short-delay 0.1
50 "Seconds to wait between subsequent tooltips on different items."
51 :tag "Short delay"
52 :type 'number
53 :group 'tooltip)
54
7840ced1 55(defcustom tooltip-recent-seconds 1
01b23b99
DL
56 "Display tooltips if changing tip items within this many seconds.
57Do so after `tooltip-short-delay'."
7840ced1
GM
58 :tag "Recent seconds"
59 :type 'number
60 :group 'tooltip)
61
88751b11 62(defcustom tooltip-hide-delay 10
a93c8ba8
GM
63 "Hide tooltips automatically after this many seconds."
64 :tag "Hide delay"
65 :type 'number
66 :group 'tooltip)
67
5fddd8e6 68(defcustom tooltip-x-offset 5
37a29d46 69 "X offset, in pixels, for the display of tooltips.
e4df9b40
GM
70The offset is relative to the position of the mouse. It must
71be chosen so that the tooltip window doesn't contain the mouse
5fddd8e6 72when it pops up.
7142670a
EZ
73
74If `tooltip-frame-parameters' includes the `left' parameter,
75the value of `tooltip-x-offset' is ignored."
e4df9b40 76 :tag "X offset"
5fddd8e6 77 :type 'integer
e4df9b40
GM
78 :group 'tooltip)
79
5fddd8e6 80(defcustom tooltip-y-offset +40
37a29d46 81 "Y offset, in pixels, for the display of tooltips.
e4df9b40
GM
82The offset is relative to the position of the mouse. It must
83be chosen so that the tooltip window doesn't contain the mouse
5fddd8e6 84when it pops up.
7142670a
EZ
85
86If `tooltip-frame-parameters' includes the `top' parameter,
87the value of `tooltip-y-offset' is ignored."
e4df9b40 88 :tag "Y offset"
5fddd8e6 89 :type 'integer
e4df9b40
GM
90 :group 'tooltip)
91
7840ced1
GM
92(defcustom tooltip-frame-parameters
93 '((name . "tooltip")
5fddd8e6 94 (internal-border-width . 2)
7840ced1 95 (border-width . 1))
7142670a
EZ
96 "Frame parameters used for tooltips.
97
98If `left' or `top' parameters are included, they specify the absolute
99position to pop up the tooltip."
7840ced1
GM
100 :type 'sexp
101 :tag "Frame Parameters"
102 :group 'tooltip)
103
2621f5a9
GM
104(defface tooltip
105 '((((class color))
39440204
JPW
106 :background "lightyellow"
107 :foreground "black"
108 :inherit variable-pitch)
109 (t
110 :inherit variable-pitch))
2621f5a9 111 "Face for tooltips."
daf96a41
JL
112 :group 'tooltip
113 :group 'basic-faces)
2621f5a9 114
90aff7c6
NR
115(defcustom tooltip-use-echo-area nil
116 "Use the echo area instead of tooltip frames for help and GUD tooltips."
117 :type 'boolean
118 :tag "Use echo area"
119 :group 'tooltip)
120
7840ced1
GM
121\f
122;;; Variables that are not customizable.
123
124(defvar tooltip-hook nil
125 "Functions to call to display tooltips.
126Each function is called with one argument EVENT which is a copy of
127the last mouse movement event that occurred.")
128
7840ced1
GM
129(defvar tooltip-timeout-id nil
130 "The id of the timeout started when Emacs becomes idle.")
131
7840ced1
GM
132(defvar tooltip-last-mouse-motion-event nil
133 "A copy of the last mouse motion event seen.")
134
7840ced1
GM
135(defvar tooltip-hide-time nil
136 "Time when the last tooltip was hidden.")
137
1af98f07
RS
138(defvar gud-tooltip-mode) ;; Prevent warning.
139
7840ced1
GM
140;;; Event accessors
141
142(defun tooltip-event-buffer (event)
143 "Return the buffer over which event EVENT occurred.
144This might return nil if the event did not occur over a buffer."
145 (let ((window (posn-window (event-end event))))
146 (and window (window-buffer window))))
147
7840ced1
GM
148;;; Switching tooltips on/off
149
150;; We don't set track-mouse globally because this is a big redisplay
151;; problem in buffers having a pre-command-hook or such installed,
152;; which does a set-buffer, like the summary buffer of Gnus. Calling
153;; set-buffer prevents redisplay optimizations, so every mouse motion
154;; would be accompanied by a full redisplay.
155
8bc973e9
NR
156(define-minor-mode tooltip-mode
157 "Toggle Tooltip display.
7840ced1 158With ARG, turn tooltip mode on if and only if ARG is positive."
8bc973e9 159 :global t
d5e2843d 160 :init-value (not (or noninteractive
5eca5ecd 161 emacs-basic-display
5fc54662 162 (not (display-graphic-p))
d5e2843d 163 (not (fboundp 'x-show-tip))))
5fc54662 164 :initialize 'custom-initialize-safe-default
8bc973e9 165 :group 'tooltip
ef75a647 166 (unless (or (null tooltip-mode) (fboundp 'x-show-tip))
c6da4eb4 167 (error "Sorry, tooltips are not yet available on this system"))
a93d8344
NR
168 (if tooltip-mode
169 (progn
170 (add-hook 'pre-command-hook 'tooltip-hide)
171 (add-hook 'tooltip-hook 'tooltip-help-tips))
172 (unless (and (boundp 'gud-tooltip-mode) gud-tooltip-mode)
173 (remove-hook 'pre-command-hook 'tooltip-hide))
174 (remove-hook 'tooltip-hook 'tooltip-help-tips))
175 (setq show-help-function
90aff7c6 176 (if tooltip-mode 'tooltip-show-help nil)))
dea87733 177
7840ced1
GM
178\f
179;;; Timeout for tooltip display
180
7840ced1
GM
181(defun tooltip-delay ()
182 "Return the delay in seconds for the next tooltip."
183 (let ((delay tooltip-delay)
a1f84f6d 184 (now (float-time)))
7840ced1
GM
185 (when (and tooltip-hide-time
186 (< (- now tooltip-hide-time) tooltip-recent-seconds))
187 (setq delay tooltip-short-delay))
188 delay))
189
06f76f9f 190(defun tooltip-cancel-delayed-tip ()
7840ced1
GM
191 "Disable the tooltip timeout."
192 (when tooltip-timeout-id
193 (disable-timeout tooltip-timeout-id)
194 (setq tooltip-timeout-id nil)))
195
06f76f9f 196(defun tooltip-start-delayed-tip ()
04cedb11 197 "Add a one-shot timeout to call function `tooltip-timeout'."
7840ced1
GM
198 (setq tooltip-timeout-id
199 (add-timeout (tooltip-delay) 'tooltip-timeout nil)))
200
7840ced1 201(defun tooltip-timeout (object)
04cedb11 202 "Function called when timer with id `tooltip-timeout-id' fires."
7840ced1
GM
203 (run-hook-with-args-until-success 'tooltip-hook
204 tooltip-last-mouse-motion-event))
205
7840ced1 206\f
7840ced1
GM
207;;; Displaying tips
208
2621f5a9 209(defun tooltip-set-param (alist key value)
4b2bb9be 210 "Change the value of KEY in alist ALIST to VALUE.
f1180544 211If there's no association for KEY in ALIST, add one, otherwise
2621f5a9
GM
212change the existing association. Value is the resulting alist."
213 (let ((param (assq key alist)))
214 (if (consp param)
215 (setcdr param value)
216 (push (cons key value) alist))
217 alist))
218
cae07240 219(defun tooltip-show (text &optional use-echo-area)
7142670a
EZ
220 "Show a tooltip window displaying TEXT.
221
1d6197fb 222Text larger than `x-max-tooltip-size' is clipped.
7142670a
EZ
223
224If the alist in `tooltip-frame-parameters' includes `left' and `top'
225parameters, they determine the x and y position where the tooltip
226is displayed. Otherwise, the tooltip pops at offsets specified by
227`tooltip-x-offset' and `tooltip-y-offset' from the current mouse
1d6197fb
NR
228position.
229
cae07240
KS
230Optional second arg USE-ECHO-AREA non-nil means to show tooltip
231in echo area."
232 (if use-echo-area
72200f89 233 (message "%s" text)
e5603149 234 (condition-case error
2621f5a9
GM
235 (let ((params (copy-sequence tooltip-frame-parameters))
236 (fg (face-attribute 'tooltip :foreground))
237 (bg (face-attribute 'tooltip :background)))
06f76f9f
GM
238 (when (stringp fg)
239 (setq params (tooltip-set-param params 'foreground-color fg))
240 (setq params (tooltip-set-param params 'border-color fg)))
241 (when (stringp bg)
242 (setq params (tooltip-set-param params 'background-color bg)))
2621f5a9
GM
243 (x-show-tip (propertize text 'face 'tooltip)
244 (selected-frame)
f3b05e99 245 params
a93c8ba8 246 tooltip-hide-delay
2621f5a9
GM
247 tooltip-x-offset
248 tooltip-y-offset))
f1180544 249 (error
e5603149
GM
250 (message "Error while displaying tooltip: %s" error)
251 (sit-for 1)
252 (message "%s" text)))))
253
7840ced1
GM
254(defun tooltip-hide (&optional ignored-arg)
255 "Hide a tooltip, if one is displayed.
256Value is non-nil if tooltip was open."
06f76f9f 257 (tooltip-cancel-delayed-tip)
7840ced1 258 (when (x-hide-tip)
a1f84f6d 259 (setq tooltip-hide-time (float-time))))
7840ced1 260
7840ced1
GM
261\f
262;;; Debugger-related functions
263
264(defun tooltip-identifier-from-point (point)
265 "Extract the identifier at POINT, if any.
266Value is nil if no identifier exists at point. Identifier extraction
267is based on the current syntax table."
268 (save-excursion
269 (goto-char point)
270 (let ((start (progn (skip-syntax-backward "w_") (point))))
271 (unless (looking-at "[0-9]")
272 (skip-syntax-forward "w_")
273 (when (> (point) start)
274 (buffer-substring start (point)))))))
275
7840ced1
GM
276(defmacro tooltip-region-active-p ()
277 "Value is non-nil if the region is currently active."
278 (if (string-match "^GNU" (emacs-version))
279 `(and transient-mark-mode mark-active)
280 `(region-active-p)))
281
7840ced1
GM
282(defun tooltip-expr-to-print (event)
283 "Return an expression that should be printed for EVENT.
284If a region is active and the mouse is inside the region, print
285the region. Otherwise, figure out the identifier around the point
286where the mouse is."
287 (save-excursion
288 (set-buffer (tooltip-event-buffer event))
289 (let ((point (posn-point (event-end event))))
290 (if (tooltip-region-active-p)
291 (when (and (<= (region-beginning) point) (<= point (region-end)))
292 (buffer-substring (region-beginning) (region-end)))
293 (tooltip-identifier-from-point point)))))
294
7840ced1
GM
295(defun tooltip-process-prompt-regexp (process)
296 "Return regexp matching the prompt of PROCESS at the end of a string.
04cedb11
JB
297The prompt is taken from the value of `comint-prompt-regexp' in
298the buffer of PROCESS."
7840ced1
GM
299 (let ((prompt-regexp (save-excursion
300 (set-buffer (process-buffer process))
301 comint-prompt-regexp)))
302 ;; Most start with `^' but the one for `sdb' cannot be easily
303 ;; stripped. Code the prompt for `sdb' fixed here.
304 (if (= (aref prompt-regexp 0) ?^)
305 (setq prompt-regexp (substring prompt-regexp 1))
306 (setq prompt-regexp "\\*"))
307 (concat "\n*" prompt-regexp "$")))
308
7840ced1
GM
309(defun tooltip-strip-prompt (process output)
310 "Return OUTPUT with any prompt of PROCESS stripped from its end."
311 (let ((prompt-regexp (tooltip-process-prompt-regexp process)))
312 (save-match-data
313 (when (string-match prompt-regexp output)
314 (setq output (substring output 0 (match-beginning 0)))))
315 output))
316
7840ced1 317\f
7840ced1
GM
318;;; Tooltip help.
319
320(defvar tooltip-help-message nil
90aff7c6 321 "The last help message received via `tooltip-show-help'.")
7840ced1 322
90aff7c6 323(defun tooltip-show-help (msg)
7840ced1
GM
324 "Function installed as `show-help-function'.
325MSG is either a help string to display, or nil to cancel the display."
86f0d417 326 (let ((previous-help tooltip-help-message))
7840ced1
GM
327 (setq tooltip-help-message msg)
328 (cond ((null msg)
06f76f9f
GM
329 ;; Cancel display. This also cancels a delayed tip, if
330 ;; there is one.
7840ced1 331 (tooltip-hide))
06f76f9f
GM
332 ((equal previous-help msg)
333 ;; Same help as before (but possibly the mouse has moved).
334 ;; Keep what we have.
335 )
7840ced1 336 (t
f1180544 337 ;; A different help. Remove a previous tooltip, and
06f76f9f
GM
338 ;; display a new one, with some delay.
339 (tooltip-hide)
340 (tooltip-start-delayed-tip)))))
7840ced1 341
7840ced1
GM
342(defun tooltip-help-tips (event)
343 "Hook function to display a help tooltip.
06f76f9f 344This is installed on the hook `tooltip-hook', which is run when
04cedb11 345the timer with id `tooltip-timeout-id' fires.
7840ced1
GM
346Value is non-nil if this function handled the tip."
347 (when (stringp tooltip-help-message)
90aff7c6 348 (tooltip-show tooltip-help-message tooltip-use-echo-area)
7840ced1
GM
349 t))
350
5ce0fb91 351(provide 'tooltip)
7840ced1 352
18385083 353;; arch-tag: 3d61135e-4618-4a78-af28-183f6df5636f
7840ced1 354;;; tooltip.el ends here