diff lisp/utils/floating-toolbar.el @ 22:8fc7fe29b841 r19-15b94

Import from CVS: tag r19-15b94
author cvs
date Mon, 13 Aug 2007 08:50:29 +0200
parents
children c53a95d3c46d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/utils/floating-toolbar.el	Mon Aug 13 08:50:29 2007 +0200
@@ -0,0 +1,378 @@
+;;; floating-toolbar.el -- popup toolbar support for XEmacs.
+;; Copyright (C) 1997 Kyle E. Jones
+
+;; Author: Kyle Jones <kyle_jones@wonderworks.com>
+;; Keywords: lisp
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Popup toolbar for XEmacs (probably require XEmacs 19.14 or later)
+;; Send bug reports to kyle_jones@wonderworks.com
+
+;; The command `floating-toolbar' pops up a small frame
+;; containing a toolbar.  The command should be bound to a
+;; button-press event.  If the mouse press happens over an
+;; extent that has a non-nil 'floating-toolbar property, the
+;; value of that property is the toolbar instantiator that will
+;; be displayed.  Otherwise the toolbar displayed is taken from
+;; the variable `floating-toolbar'.  This variable can be made
+;; buffer local to produce buffer local floating toolbars.
+;;
+;; `floating-toolbar-or-popup-mode-menu' works like `floating-toolbar'
+;; except that if no toolbar is found, `popup-mode-menu' is called.
+;;
+;; `floating-toolbar-from-extent-or-popup-mode-menu' works like
+;; `floating-toolbar-or-popup-mode-menu' except only extent local
+;; toolbars are used; the value of floating-toolbar is not used.
+;;
+;; Installation:
+;;
+;; Byte-compile the file floating-toolbar.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 'floating-toolbar)
+;;
+;; You will also need to bind a mouse click to `floating-toolbar' or to
+;; `floating-toolbar-or-popup-mode-menu'.
+;; 
+;; 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 toolbar frame.
+;;
+;;    In .emacs:
+;;       (setq floating-toolbar-frame-name "floating-toolbar")
+;;
+;;    For ol[v]wm use this in .Xdefaults:
+;;       olvwm.NoDecor: floating-toolbar
+;;         or
+;;       olwm.MinimalDecor: floating-toolbar
+;;
+;;    For fvvm use this in your .fvwmrc:
+;;       NoTitle floating-toolbar
+;;    or
+;;       Style "floating-toolbar" NoTitle, NoHandles, BorderWidth 0
+;;
+;;    For twm use this in your .twmrc:
+;;       NoTitle { "floating-toolbar" }
+;; 
+;; Under 19.13 and later versions the floating-toolbar 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.
+
+;;; Code:
+
+(provide 'floating-toolbar)
+
+(require 'toolbar)
+(require 'x)
+
+(defvar floating-toolbar-version "1.01"
+  "Version string for the floating-toolbar package.")
+
+(defvar floating-toolbar-use-sound nil
+  "*Non-nil value means play a sound to herald the appearance
+and disappearance of the floating toolbar.
+
+`floating-toolbar-appears' will be played when the toolbar appears.
+`floating-toolbar-disappears' will be played when the toolbar disappears.
+
+See the documentation for the function `load-sound-file' to see how
+define sounds.")
+
+(defvar floating-toolbar nil
+  "*Toolbar instantiator used if mouse event is not over an extent
+with a non-nil 'floating-toolbar property.  This variable can be
+made local to a buffer to have buffer local floating toolbars.")
+
+(defvar floating-toolbar-help-font nil
+  "*Non-nil value should be a font to be used to display toolbar help
+messages.  The floating toolbar frame will have a minibuffer window
+so that it can display any help text that is attached to the toolbar
+buttons.")
+
+(defvar floating-toolbar-frame-name nil
+  "*The frame name for the frame used to display the floating toolbar.")
+
+;;;
+;;; End of user variables.
+;;;
+
+(defvar floating-toolbar-frame nil
+  "The floating toolbar is displayed in this frame.")
+
+(defvar floating-toolbar-display-pending nil
+  "Non-nil value means the toolbar 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.")
+
+(defun floating-toolbar-displayed ()
+  (and (frame-live-p floating-toolbar-frame)
+       (frame-visible-p floating-toolbar-frame)))
+
+;;;###autoload
+(defun floating-toolbar (event &optional extent-local-only)
+  "Popup a toolbar near the current mouse position.
+The toolbar instantiator used is taken from the 'floating-toolbar
+property of any extent under the mouse.  If no such non-nil
+property exists for any extent under the mouse, then the value of the
+variable `floating-toolbar' is checked.  If its value si nil, then
+no toolbar will be displayed.
+
+This command should be bound to a button press event.
+
+When called from a program, first arg EVENT should be the button
+press event.  Optional second arg EXTENT-LOCAL-ONLY specifies
+that only extent local toolbars should be used; this means the
+`floating-toolbar' variable will not be consulted."
+  (interactive "_e")
+  (if (not (mouse-event-p event))
+      nil
+    (let* ((buffer (event-buffer event))
+	   (window (event-window 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
+						   'floating-toolbar))
+			     glyph-extent))
+	   (extent (or glyph-extent
+		       (and point
+			    (extent-at point buffer 'floating-toolbar))))
+	   (toolbar (or (and extent (get extent 'floating-toolbar))
+			(and (not extent-local-only)
+			     (symbol-value-in-buffer 'floating-toolbar
+						     buffer nil))))
+	   (x nil)
+	   (y nil)
+	   (echo-keystrokes 0)
+	   (awaiting-release t)
+	   (done nil))
+      (if (not (consp toolbar))
+	  nil
+	;; event-[xy]-pixel are relative to the top left corner
+	;; of the frame.  The presence of top and left toolbar
+	;; and the menubar can move this position down and
+	;; leftward, but XEmacs doesn't compensate for this in
+	;; the values returned.  So we do it here, as best we
+	;; can.
+	(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))
+	       ;; better than nothing
+	       (menubar-height (if current-menubar 22 0)))
+	  (setq x (+ left xleft-toolbar-width (event-x-pixel event))
+		y (+ top xtop-toolbar-height menubar-height
+		     (event-y-pixel event))))
+	;; for toolbar spec buffer local variable values
+	(and buffer (set-buffer buffer))
+	(floating-toolbar-display-toolbar toolbar x y)
+	(while (not done)
+	  (setq event (next-command-event))
+	  (cond ((and awaiting-release (button-release-event-p event))
+		 (setq awaiting-release nil))
+		((and (button-release-event-p event)
+		      (event-over-toolbar-p event)
+		      (eq floating-toolbar-frame (event-frame event)))
+		 (floating-toolbar-undisplay-toolbar)
+		 (and window (select-frame (window-frame window)))
+		 (and window (select-window window))
+		 (dispatch-event event)
+		 (setq done t))
+		((and (button-press-event-p event)
+		      (event-over-toolbar-p event)
+		      (eq floating-toolbar-frame (event-frame event)))
+		 (setq awaiting-release nil)
+		 (dispatch-event event))
+		(t
+		 ;; push back the event if it was in another frame.
+		 ;; eat it if it was in the toolbar frame.
+		 (if (and (event-frame event)
+			  (not (eq floating-toolbar-frame
+				   (event-frame event))))
+		     (setq unread-command-events
+			   (cons event unread-command-events)))
+		 (floating-toolbar-undisplay-toolbar)
+		 (setq done t))))
+	t ))))
+
+;;;###autoload
+(defun floating-toolbar-or-popup-mode-menu (event)
+  "Like floating-toolbar, but if no toolbar is displayed
+run popup-mode-menu."
+  (interactive "_e")
+  (or (floating-toolbar event) (popup-mode-menu)))
+
+;;;###autoload
+(defun floating-toolbar-from-extent-or-popup-mode-menu (event)
+  "Like floating-toolbar-or-popup-mode-menu, but search only for an
+extent local toolbar."
+  (interactive "_e")
+  (or (floating-toolbar event t) (popup-mode-menu)))
+
+(defun floating-toolbar-display-toolbar (toolbar x y)
+  (if (not (frame-live-p floating-toolbar-frame))
+      (setq floating-toolbar-frame (floating-toolbar-make-toolbar-frame x y)))
+  (set-specifier top-toolbar
+		 (cons (window-buffer
+			(frame-selected-window floating-toolbar-frame))
+			toolbar))
+  (floating-toolbar-resize-toolbar-frame toolbar)
+  ;; fiddle with the x value to try to center the toolbar relative to
+  ;; the mouse position.
+  (setq x (max 0 (- x (/ (frame-pixel-width floating-toolbar-frame) 2))))
+  (floating-toolbar-set-toolbar-frame-position x y)
+  (floating-toolbar-expose-toolbar-frame))
+
+(defun floating-toolbar-undisplay-toolbar ()
+  (floating-toolbar-hide-toolbar-frame))
+
+(defun floating-toolbar-hide-toolbar-frame ()
+  (if (floating-toolbar-displayed)
+      (progn
+	(make-frame-invisible floating-toolbar-frame)
+	(if (and floating-toolbar-use-sound floating-toolbar-display-pending)
+	    (play-sound 'floating-toolbar-disappears))
+	(setq floating-toolbar-display-pending nil))))
+
+(defun floating-toolbar-expose-toolbar-frame ()
+  (if (not (floating-toolbar-displayed))
+      (progn
+	(make-frame-visible floating-toolbar-frame)
+	(if (and floating-toolbar-use-sound
+		 (null floating-toolbar-display-pending))
+	    (play-sound 'floating-toolbar-appears))
+	(setq floating-toolbar-display-pending t))))
+
+(defun floating-toolbar-resize-toolbar-frame (toolbar)
+  (let ((width 0)
+	(height nil)
+	(bevel (* 2 (or (cdr (assq 'toolbar-shadow-thickness (frame-parameters)))
+			0)))
+	(captioned (specifier-instance toolbar-buttons-captioned-p))
+	button glyph glyph-list)
+    (while toolbar
+      (setq button (car toolbar))
+      (cond ((null button)
+	     (setq width (+ width 8)))
+	    ((eq (elt button 0) ':size)
+	     (setq width (+ width (elt button 1))))
+	    ((and (eq (elt button 0) ':style)
+		  (= (length button) 4)
+		  (eq (elt button 2) ':size))
+	     (setq width (+ width bevel (elt button 3))))
+	    (t
+	      (setq glyph-list (elt button 0))
+	      (if (symbolp glyph-list)
+		  (setq glyph-list (symbol-value glyph-list)))
+	      (if (and captioned (> (length glyph-list) 3))
+		  (setq glyph (or (nth 3 glyph-list)
+				  (nth 4 glyph-list)
+				  (nth 5 glyph-list)))
+		(setq glyph (car glyph-list)))
+	      (setq width (+ width bevel (glyph-width glyph)))
+	      (or height (setq height (+ bevel (glyph-height glyph))))))
+      (setq toolbar (cdr toolbar)))
+    (set-specifier top-toolbar-height height floating-toolbar-frame)
+    (set-frame-width floating-toolbar-frame
+		     (1+ (/ width (font-width (face-font 'default)
+					  floating-toolbar-frame))))))
+
+(defun floating-toolbar-set-toolbar-frame-position (x y)
+  (set-frame-position floating-toolbar-frame x y))
+
+(defun floating-toolbar-make-junk-frame ()
+  (let ((window-min-height 1)
+	(window-min-width 1))
+    (make-frame '(minibuffer t initially-unmapped t width 1 height 1))))
+
+(defun floating-toolbar-make-toolbar-frame (x y)
+  (save-excursion
+    (let ((window-min-height 1)
+	  (window-min-width 1)
+	  (bg-color (or (x-get-resource "backgroundToolBarColor"
+					"BackgroundToolBarColor"
+					'string
+					'global
+					(selected-device)
+					t)
+			"grey75"))
+	  (buffer (get-buffer-create " *floating-toolbar-buffer*"))
+	  (frame nil))
+      (set-buffer buffer)
+      (set-buffer-menubar nil)
+      (if floating-toolbar-help-font
+	  (progn (set-buffer (window-buffer (minibuffer-window)))
+		 (set-buffer-menubar nil)))
+      (setq frame (make-frame (list
+			       '(initially-unmapped . t)
+			       ;; try to evade frame decorations
+			       (cons 'name (or floating-toolbar-frame-name
+					       "xclock"))
+			       '(border-width . 2)
+			       (cons 'border-color bg-color)
+			       (cons 'top y)
+			       (cons 'left x)
+			       (cons 'popup
+				     (floating-toolbar-make-junk-frame))
+			       (if floating-toolbar-help-font
+				   '(minibuffer . only)
+				 '(minibuffer . nil))
+			       '(width . 3)
+			       '(height . 1))))
+      (set-specifier text-cursor-visible-p (cons frame nil))
+      (if floating-toolbar-help-font
+	  (set-face-font 'default floating-toolbar-help-font frame)
+	(set-face-font 'default "nil2" frame))
+      (set-face-background 'default bg-color frame)
+      (set-face-background 'modeline bg-color frame)
+      (set-specifier modeline-shadow-thickness (cons frame 1))
+      (set-specifier has-modeline-p (cons frame nil))
+      (set-face-background-pixmap 'default "" frame)
+      (set-window-buffer (frame-selected-window frame) buffer)
+      (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))
+      frame )))
+
+;; first popup should be faster if we go ahead and make the frame now.
+(or floating-toolbar-frame
+    (not (eq (device-type) 'x))
+    (setq floating-toolbar-frame (floating-toolbar-make-toolbar-frame 0 0)))
+
+;;; floating-toolbar.el ends here