diff lisp/packages/balloon-help.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 8fc7fe29b841
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/packages/balloon-help.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,392 @@
+;;; Balloon help for XEmacs (requires 19.12 or later)
+;;; Copyright (C) 1995 Kyle E. Jones
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 1, or (at your option)
+;;; any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; A copy of the GNU General Public License can be obtained from this
+;;; program's author (send electronic mail to kyle@uunet.uu.net) or from
+;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+;;; 02139, USA.
+;;;
+;;; Send bug reports to kyle@wonderworks.com
+
+;;; Synched up with: Not in FSF.
+
+;; Balloon help pops up a small frame to display help text
+;; relating to objects that the mouse cursor passes over.
+;; 
+;; Installation:
+;;
+;; Byte-compile the file balloon-help.el (with M-x byte-compile-file)
+;; and put the .elc file in a directory in your load-path.  Add the
+;; following line to your .emacs:
+;;
+;; (require 'balloon-help)
+;;
+;; For 19.12 users:
+;;    If you are using fvwm, [tv]twm or ol[v]wm, you can also add
+;;    the following lines to various configuration file to use
+;;    minimal decorations on the balloon help frames.
+;;
+;;    In .emacs:
+;;       (setq balloon-help-frame-name "balloon-help")
+;;
+;;    For ol[v]wm use this in .Xdefaults:
+;;       olvwm.NoDecor: balloon-help
+;;         or
+;;       olwm.MinimalDecor: balloon-help
+;;
+;;    For fvvm use this in your .fvwmrc:
+;;       NoTitle balloon-help
+;;    or
+;;       Style "balloon-help" NoTitle, NoHandles, BorderWidth 0
+;;
+;;    For twm use this in your .twmrc:
+;;       NoTitle { "balloon-help" }
+;; 
+;; Under 19.13 and later versions the balloon-help frame uses a
+;; transient window that is not normally decorated by window
+;; managers.  So the window manager directives should not be
+;; needed for XEmacs 19.13 and beyond.
+
+(provide 'balloon-help)
+
+(defvar balloon-help-version "1.02"
+  "Version string for Balloon Help.")
+
+(defvar balloon-help-mode t
+  "*Non-nil means Balloon help mode is enabled.")
+
+(defvar balloon-help-timeout 1500
+  "*Display help after this many milliseconds of mouse inactivity.")
+
+(defvar balloon-help-foreground "black"
+  "*The foreground color for displaying balloon help text.")
+
+(defvar balloon-help-background "rgb:c0/c0/c0"
+  "*The background color for the balloon help frame.")
+
+(defvar balloon-help-background-pixmap ""
+  "*The background pixmap for the balloon help frame.")
+
+(defvar balloon-help-font "fixed"
+  "*The font for displaying balloon help text.")
+
+(defvar balloon-help-border-color "black"
+  "*The color for displaying balloon help frame's border.")
+
+(defvar balloon-help-use-sound nil
+  "*Non-nil value means play a sound to herald the appearance
+and disappearance of the help frame.
+
+`balloon-help-appears' will be played when the frame appears.
+`balloon-help-disappears' will be played when the frame disappears.
+
+See the documentation for the function load-sound-file to see how
+define sounds.")
+
+(defvar balloon-help-frame-name nil
+  "*The frame name to use for the frame to display the balloon help.")
+
+;;;
+;;; End of user variables.
+;;;
+
+(defvar mouse-motion-hook mouse-motion-handler
+  "Hooks to be run whenever the user moves the mouse.
+Each hook is called with one argument, the mouse motion event.")
+
+(defun mouse-motion-hook (event)
+  "Run the hooks attached to mouse-motion-hook."
+  (run-hook-with-args 'mouse-motion-hook event))
+
+(setq mouse-motion-handler 'mouse-motion-hook)
+
+(defvar balloon-help-frame nil
+  "Balloon help is displayed in this frame.")
+
+(defvar balloon-help-help-object nil
+  "Object that the mouse is over that has a help property, nil otherwise.")
+
+(defvar balloon-help-help-object-x nil
+  "Last horizontal mouse position over balloon-help-help-object.")
+
+(defvar balloon-help-help-object-y nil
+  "Last vertical mouse position over balloon-help-help-object.")
+
+(defvar balloon-help-buffer nil
+  "Buffer used to display balloon help.")
+
+(defvar balloon-help-timeout-id nil
+  "Timeout id for the balloon help timeout.")
+
+(defvar balloon-help-display-pending nil
+  "Non-nil value means the help frame will be visible as soon
+as the X server gets around to displaying it.  Nil means it
+will be invisible as soon as the X server decides to hide it.")
+
+(defvar balloon-help-bar-cursor nil)
+
+(defun balloon-help-mode (&optional arg)
+  "Toggle Balloon Help mode.
+With arg, turn Balloon Help mode on iff arg is positive.
+
+With Balloon Help enabled, a small frame is displayed whenever
+the mouse rests on an object that has a help property of some
+kind.  The text of that help property is displayed in the frame.
+
+For extents, the 'balloon-help' property is
+checked.
+
+For toolbar buttons, the help-string slot of the toolbar button
+is checked.
+
+If the value is a string, it is used as the help message.
+
+If the property's value is a symbol, it is assumed to be the name
+of a function and it will be called with one argument, the object
+under the mouse, and the return value of that function will be
+used as the help message."
+  (interactive "P")
+  (setq balloon-help-mode (or (and arg (> (prefix-numeric-value arg) 0))
+			      (and (null arg) (null balloon-help-mode))))
+  (if (null balloon-help-mode)
+      (balloon-help-undisplay-help)))
+
+(defun balloon-help-displayed ()
+  (and (frame-live-p balloon-help-frame)
+       (frame-visible-p balloon-help-frame)))
+
+(defun balloon-help-motion-hook (event)
+  (cond
+   ((null balloon-help-mode) t)
+   ((button-press-event-p event)
+    (setq balloon-help-help-object nil)
+    (if balloon-help-timeout-id
+	(disable-timeout balloon-help-timeout-id))
+    (if (balloon-help-displayed)
+	(balloon-help-undisplay-help)))
+   (t
+    (let* ((buffer (event-buffer event))
+	   (frame (event-frame event))
+	   (point (and buffer (event-point event)))
+	   (glyph-extent (event-glyph-extent event))
+	   (glyph-extent (if (and glyph-extent
+				  (extent-property glyph-extent
+						   'balloon-help))
+			     glyph-extent))
+	   (extent (and point
+			(extent-at point buffer 'balloon-help)))
+	   (button (event-toolbar-button event))
+	   (button (if (and button (toolbar-button-help-string button))
+		       button
+		     nil))
+	   (object (or glyph-extent extent button))
+	   (id balloon-help-timeout-id))
+      (if (null object)
+	  (if (and balloon-help-frame
+		   (not (eq frame balloon-help-frame)))
+	      (progn
+		(setq balloon-help-help-object nil)
+		(if id
+		    (disable-timeout id))
+		(if (balloon-help-displayed)
+		    (balloon-help-undisplay-help))))
+	(let* ((params (frame-parameters frame))
+	       (top (cdr (assq 'top params)))
+	       (left (cdr (assq 'left params)))
+	       (xtop-toolbar-height
+		(if (specifier-instance top-toolbar)
+		    (specifier-instance top-toolbar-height)
+		  0))
+	       (xleft-toolbar-width
+		(if (specifier-instance left-toolbar)
+		    (specifier-instance left-toolbar-width)
+		  0))
+	       (menubar-height (if current-menubar 22 0)))
+	  (setq balloon-help-help-object-x
+		(+ left xleft-toolbar-width (event-x-pixel event))
+		balloon-help-help-object-y
+		(+ top xtop-toolbar-height menubar-height
+		   (event-y-pixel event))))
+	(cond ((eq frame balloon-help-frame) t)
+	      ((eq object balloon-help-help-object)
+	       (if (balloon-help-displayed)
+		   (balloon-help-move-help-frame)))
+	      ((balloon-help-displayed)
+	       (setq balloon-help-help-object object)
+	       (balloon-help-display-help))
+	      (t
+	       (setq balloon-help-help-object object)
+	       (if id
+		   (disable-timeout id))
+	       (setq balloon-help-timeout-id
+		     (add-timeout (/ balloon-help-timeout 1000.0)
+				  (function balloon-help-display-help)
+				  nil)))))))))
+
+(defun balloon-help-pre-command-hook (&rest ignored)
+  (setq balloon-help-help-object nil)
+  (if (balloon-help-displayed)
+      (balloon-help-undisplay-help)))
+
+(fset 'balloon-help-post-command-hook 'balloon-help-pre-command-hook)
+(fset 'balloon-help-mouse-leave-frame-hook 'balloon-help-pre-command-hook)
+(fset 'balloon-help-deselect-frame-hook 'balloon-help-pre-command-hook)
+
+(defun balloon-help-display-help (&rest ignored)
+  (setq balloon-help-timeout-id nil)
+  (if balloon-help-help-object
+      (let* ((object balloon-help-help-object)
+	     (help (or (and (extent-live-p object)
+			    (extent-property object 'balloon-help))
+		       (and (toolbar-button-p object)
+			    (toolbar-button-help-string object))
+		       (and (stringp object) object))))
+	;; if help is non-null and is not a string, run it as
+	;; function to produuce the help string.
+	(if (or (null help) (not (symbolp help)))
+	    nil
+	  (condition-case data
+	      (setq help (funcall help object))
+	    (error
+	     (setq help (format "help function signaled: %S" data)))))
+	(if (stringp help)
+	    (save-excursion
+	      (if (not (bufferp balloon-help-buffer))
+		  (setq balloon-help-buffer
+			(get-buffer-create " *balloon-help*")))
+	      (if (not (frame-live-p balloon-help-frame))
+		  (setq balloon-help-frame (balloon-help-make-help-frame)))
+	      (setq bar-cursor t)
+	      (set-buffer balloon-help-buffer)
+	      (erase-buffer)
+	      (insert help)
+	      (if (not (bolp))
+		  (insert ?\n))
+	      ;; help strings longer than 2 lines have the last
+	      ;; line stolen by the minibuffer, so make sure the
+	      ;; last line is blank.  Make the top line blank for
+	      ;; some symmetry.
+	      (if (< 2 (count-lines (point-min) (point-max)))
+		  (progn
+		    (insert ?\n)
+		    ;; add a second blank line at the end to
+		    ;; prevent the modeline bar from clipping the
+		    ;; descenders of the last line of text.
+		    (insert ?\n)
+		    (goto-char (point-min))
+		    (insert ?\n)))
+	      ;; cursor will be at point-min because we're just
+	      ;; moving point which doesn't affect window-point
+	      ;; when the window isn't selected.  Indent
+	      ;; everything so that the cursor will be over a
+	      ;; space.  The 1-pixel bar cursor will be
+	      ;; completely invisible this way.
+ 	      (indent-rigidly (point-min) (point-max) 1)
+	      (balloon-help-move-help-frame)
+	      (balloon-help-resize-help-frame)
+	      (balloon-help-expose-help-frame))))))
+
+(defun balloon-help-undisplay-help ()
+  (setq bar-cursor balloon-help-bar-cursor)
+  (balloon-help-hide-help-frame))
+
+(defun balloon-help-hide-help-frame ()
+  (if (balloon-help-displayed)
+      (progn
+	(make-frame-invisible balloon-help-frame)
+	(if (and balloon-help-use-sound balloon-help-display-pending)
+	    (play-sound 'balloon-help-disappears))
+	(setq balloon-help-display-pending nil))))
+
+(defun balloon-help-expose-help-frame ()
+  (if (not (balloon-help-displayed))
+      (progn
+	(make-frame-visible balloon-help-frame)
+	(if (and balloon-help-use-sound (null balloon-help-display-pending))
+	    (play-sound 'balloon-help-appears))
+	(setq balloon-help-display-pending t))))
+
+(defun balloon-help-resize-help-frame ()
+  (save-excursion
+    (set-buffer balloon-help-buffer)
+    (let ((longest 0)
+	  (lines 0)
+	  (done nil)
+	  (window-min-height 1)
+	  (window-min-width 1))
+      (goto-char (point-min))
+      (while (not done)
+	(end-of-line)
+	(setq longest (max longest (current-column))
+	      done (not (= 0 (forward-line))))
+	(and (not done) (setq lines (1+ lines))))
+      (set-frame-size balloon-help-frame (+ 1 longest) lines))))
+
+(defun balloon-help-make-help-frame ()
+  (save-excursion
+    (setq balloon-help-bar-cursor bar-cursor)
+    (set-buffer balloon-help-buffer)
+    (set-buffer-menubar nil)
+    (let* ((x (balloon-help-compute-help-frame-x-location))
+	   (y (balloon-help-compute-help-frame-y-location))
+	   (window-min-height 1)
+	   (window-min-width 1)
+	   (frame (make-frame (list
+			       '(initially-unmapped . t)
+			       ;; try to evade frame decorations
+			       (cons 'name (or balloon-help-frame-name
+					       "xclock"))
+			       '(border-width . 2)
+			       (cons 'border-color balloon-help-border-color)
+			       (cons 'top y)
+			       (cons 'left x)
+			       (cons 'popup (selected-frame))
+			       '(width . 3)
+			       '(height . 1)))))
+      (set-face-font 'default balloon-help-font frame)
+      (set-face-foreground 'default balloon-help-foreground frame)
+      (set-face-background 'default balloon-help-background frame)
+      (set-face-background-pixmap 'default balloon-help-background-pixmap
+				  frame)
+      (set-window-buffer (frame-selected-window frame) balloon-help-buffer)
+      (set-specifier has-modeline-p (cons frame nil))
+      (set-specifier top-toolbar-height (cons frame 0))
+      (set-specifier left-toolbar-width (cons frame 0))
+      (set-specifier right-toolbar-width (cons frame 0))
+      (set-specifier bottom-toolbar-height (cons frame 0))
+      (set-specifier top-toolbar (cons frame nil))
+      (set-specifier left-toolbar (cons frame nil))
+      (set-specifier right-toolbar (cons frame nil))
+      (set-specifier bottom-toolbar (cons frame nil))
+      (set-specifier scrollbar-width (cons frame 0))
+      (set-specifier scrollbar-height (cons frame 0))
+      (set-specifier modeline-shadow-thickness (cons frame 0))
+      (set-face-background 'modeline balloon-help-background frame)
+      frame )))
+
+(defun balloon-help-compute-help-frame-x-location ()
+  (max 0 (+ 32 balloon-help-help-object-x)))
+
+(defun balloon-help-compute-help-frame-y-location ()
+  (max 0 (+ 48 balloon-help-help-object-y)))
+
+(defun balloon-help-move-help-frame ()
+  (let ((x (balloon-help-compute-help-frame-x-location))
+	(y (balloon-help-compute-help-frame-y-location)))
+    (set-frame-position balloon-help-frame x y)))
+
+(add-hook 'mouse-motion-hook 'balloon-help-motion-hook)
+(add-hook 'pre-command-hook 'balloon-help-pre-command-hook)
+(add-hook 'post-command-hook 'balloon-help-post-command-hook)
+(add-hook 'mouse-leave-frame-hook 'balloon-help-mouse-leave-frame-hook)
+(add-hook 'deselect-frame-hook 'balloon-help-deselect-frame-hook)