declare smobs in alloc.c
[bpt/emacs.git] / lisp / tool-bar.el
CommitLineData
e8af40ee 1;;; tool-bar.el --- setting up the tool bar
e9bffc61 2
ba318903 3;; Copyright (C) 2000-2014 Free Software Foundation, Inc.
e9bffc61 4
ec7f4585
DL
5;; Author: Dave Love <fx@gnu.org>
6;; Keywords: mouse frames
bd78fa1d 7;; Package: emacs
ec7f4585
DL
8
9;; This file is part of GNU Emacs.
10
eb3fa2cf 11;; GNU Emacs is free software: you can redistribute it and/or modify
ec7f4585 12;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
ec7f4585
DL
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
eb3fa2cf 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
ec7f4585
DL
23
24;;; Commentary:
25
02d709c0 26;; Provides `tool-bar-mode' to control display of the tool-bar and
ec7f4585
DL
27;; bindings for the global tool bar with convenience functions
28;; `tool-bar-add-item' and `tool-bar-add-item-from-menu'.
29
9a4b8870 30;; The normal global binding for [tool-bar] (below) uses the value of
c129b5ef
DL
31;; `tool-bar-map' as the actual keymap to define the tool bar. Modes
32;; may either bind items under the [tool-bar] prefix key of the local
33;; map to add to the global bar or may set `tool-bar-map'
b28e72df 34;; buffer-locally to override it. (Some items are removed from the
9a4b8870 35;; global bar in modes which have `special' as their `mode-class'
b011dcb0 36;; property.)
9a4b8870 37
adf7d3a8
DL
38;; Todo: Somehow make tool bars easily customizable by the naive?
39
ec7f4585
DL
40;;; Code:
41
646cb69e
RS
42;; The autoload cookie doesn't work when preloading.
43;; Deleting it means invoking this command won't work
44;; when you are on a tty. I hope that won't cause too much trouble -- rms.
ec7f4585 45(define-minor-mode tool-bar-mode
06e21633
CY
46 "Toggle the tool bar in all graphical frames (Tool Bar mode).
47With a prefix argument ARG, enable Tool Bar mode if ARG is
48positive, and disable it otherwise. If called from Lisp, enable
49Tool Bar mode if ARG is omitted or nil.
ec7f4585
DL
50
51See `tool-bar-add-item' and `tool-bar-add-item-from-menu' for
52conveniently adding tool bar items."
6431f2e6 53 :init-value t
ec7f4585 54 :global t
9d794026
GM
55 ;; It's defined in C/cus-start, this stops the d-m-m macro defining it again.
56 :variable tool-bar-mode
6431f2e6
CY
57 (let ((val (if tool-bar-mode 1 0)))
58 (dolist (frame (frame-list))
4ad11f8c
CY
59 (set-frame-parameter frame 'tool-bar-lines val))
60 ;; If the user has given `default-frame-alist' a `tool-bar-lines'
61 ;; parameter, replace it.
62 (if (assq 'tool-bar-lines default-frame-alist)
63 (setq default-frame-alist
64 (cons (cons 'tool-bar-lines val)
65 (assq-delete-all 'tool-bar-lines
66 default-frame-alist)))))
67 (and tool-bar-mode
68 (= 1 (length (default-value 'tool-bar-map))) ; not yet setup
69 (tool-bar-setup)))
ec7f4585 70
929e8487 71;;;###autoload
6a5af08f
KL
72;; Used in the Show/Hide menu, to have the toggle reflect the current frame.
73(defun toggle-tool-bar-mode-from-frame (&optional arg)
74 "Toggle tool bar on or off, based on the status of the current frame.
75See `tool-bar-mode' for more information."
76 (interactive (list (or current-prefix-arg 'toggle)))
77 (if (eq arg 'toggle)
78 (tool-bar-mode (if (> (frame-parameter nil 'tool-bar-lines) 0) 0 1))
79 (tool-bar-mode arg)))
80
9a4b8870
DL
81(defvar tool-bar-map (make-sparse-keymap)
82 "Keymap for the tool bar.
83Define this locally to override the global tool bar.")
84
85(global-set-key [tool-bar]
1e8780b1 86 `(menu-item ,(purecopy "tool bar") ignore
c8fcd943
SM
87 :filter tool-bar-make-keymap))
88
aa360da1
GM
89(declare-function image-mask-p "image.c" (spec &optional frame))
90
b8067901
CY
91(defconst tool-bar-keymap-cache (make-hash-table :weakness t :test 'equal))
92
06b60517 93(defun tool-bar-make-keymap (&optional _ignore)
c8fcd943
SM
94 "Generate an actual keymap from `tool-bar-map'.
95Its main job is to figure out which images to use based on the display's
96color capability and based on the available image libraries."
b8067901
CY
97 (let ((key (cons (frame-terminal) tool-bar-map)))
98 (or (gethash key tool-bar-keymap-cache)
99 (puthash key (tool-bar-make-keymap-1) tool-bar-keymap-cache))))
100
101(defun tool-bar-make-keymap-1 ()
102 "Generate an actual keymap from `tool-bar-map', without caching."
c8fcd943 103 (mapcar (lambda (bind)
71928058 104 (let (image-exp plist)
c8fcd943 105 (when (and (eq (car-safe (cdr-safe bind)) 'menu-item)
71928058
CY
106 ;; For the format of menu-items, see node
107 ;; `Extended Menu Items' in the Elisp manual.
108 (setq plist (nthcdr (if (consp (nth 4 bind)) 5 4)
109 bind))
110 (setq image-exp (plist-get plist :image))
111 (consp image-exp)
112 (not (eq (car image-exp) 'image))
113 (fboundp (car image-exp)))
114 (if (not (display-images-p))
115 (setq bind nil)
116 (let ((image (eval image-exp)))
6a9cbb85 117 (unless (and image (image-mask-p image))
71928058
CY
118 (setq image (append image '(:mask heuristic))))
119 (setq bind (copy-sequence bind)
120 plist (nthcdr (if (consp (nth 4 bind)) 5 4)
121 bind))
122 (plist-put plist :image image))))
123 bind))
c8fcd943
SM
124 tool-bar-map))
125
ec7f4585 126;;;###autoload
9a4b8870 127(defun tool-bar-add-item (icon def key &rest props)
ec7f4585
DL
128 "Add an item to the tool bar.
129ICON names the image, DEF is the key definition and KEY is a symbol
9a4b8870
DL
130for the fake function key in the menu keymap. Remaining arguments
131PROPS are additional items to add to the menu item specification. See
132Info node `(elisp)Tool Bar'. Items are added from left to right.
ec7f4585 133
cb4aae04 134ICON is the base name of a file containing the image to use. The
d36b11e2 135function will first try to use low-color/ICON.xpm if `display-color-cells'
968d6127 136is less or equal to 256, then ICON.xpm, then ICON.pbm, and finally
cb4aae04 137ICON.xbm, using `find-image'.
9a4b8870 138
ca1b34c8
RS
139Use this function only to make bindings in the global value of `tool-bar-map'.
140To define items in any other map, use `tool-bar-local-item'."
141 (apply 'tool-bar-local-item icon def key tool-bar-map props))
142
94975270
CY
143(defun tool-bar--image-expression (icon)
144 "Return an expression that evaluates to an image spec for ICON."
145 (let* ((fg (face-attribute 'tool-bar :foreground))
146 (bg (face-attribute 'tool-bar :background))
147 (colors (nconc (if (eq fg 'unspecified) nil (list :foreground fg))
148 (if (eq bg 'unspecified) nil (list :background bg))))
149 (xpm-spec (list :type 'xpm :file (concat icon ".xpm")))
150 (xpm-lo-spec (list :type 'xpm :file
151 (concat "low-color/" icon ".xpm")))
152 (pbm-spec (append (list :type 'pbm :file
153 (concat icon ".pbm")) colors))
154 (xbm-spec (append (list :type 'xbm :file
155 (concat icon ".xbm")) colors)))
156 `(find-image (cond ((not (display-color-p))
157 ',(list pbm-spec xbm-spec xpm-lo-spec xpm-spec))
158 ((< (display-color-cells) 256)
159 ',(list xpm-lo-spec xpm-spec pbm-spec xbm-spec))
160 (t
161 ',(list xpm-spec pbm-spec xbm-spec))))))
162
ca1b34c8
RS
163;;;###autoload
164(defun tool-bar-local-item (icon def key map &rest props)
165 "Add an item to the tool bar in map MAP.
166ICON names the image, DEF is the key definition and KEY is a symbol
167for the fake function key in the menu keymap. Remaining arguments
168PROPS are additional items to add to the menu item specification. See
169Info node `(elisp)Tool Bar'. Items are added from left to right.
170
171ICON is the base name of a file containing the image to use. The
c8fcd943 172function will first try to use low-color/ICON.xpm if `display-color-cells'
968d6127 173is less or equal to 256, then ICON.xpm, then ICON.pbm, and finally
ca1b34c8 174ICON.xbm, using `find-image'."
94975270 175 (let* ((image-exp (tool-bar--image-expression icon)))
c8fcd943
SM
176 (define-key-after map (vector key)
177 `(menu-item ,(symbol-name key) ,def :image ,image-exp ,@props))))
ec7f4585 178
c2156508 179;;;###autoload
ec7f4585 180(defun tool-bar-add-item-from-menu (command icon &optional map &rest props)
7c064859 181 "Define tool bar binding for COMMAND in keymap MAP using the given ICON.
ca1b34c8
RS
182This makes a binding for COMMAND in `tool-bar-map', copying its
183binding from the menu bar in MAP (which defaults to `global-map'), but
184modifies the binding by adding an image specification for ICON. It
185finds ICON just like `tool-bar-add-item'. PROPS are additional
186properties to add to the binding.
187
188MAP must contain appropriate binding for `[menu-bar]' which holds a keymap.
189
190Use this function only to make bindings in the global value of `tool-bar-map'.
7c064859 191To define items in any other map, use `tool-bar-local-item-from-menu'."
03a8bf7d
SM
192 (apply 'tool-bar-local-item-from-menu command icon
193 (default-value 'tool-bar-map) map props))
ca1b34c8
RS
194
195;;;###autoload
196(defun tool-bar-local-item-from-menu (command icon in-map &optional from-map &rest props)
7c064859 197 "Define local tool bar binding for COMMAND using the given ICON.
ca1b34c8
RS
198This makes a binding for COMMAND in IN-MAP, copying its binding from
199the menu bar in FROM-MAP (which defaults to `global-map'), but
200modifies the binding by adding an image specification for ICON. It
201finds ICON just like `tool-bar-add-item'. PROPS are additional
202properties to add to the binding.
203
7c064859
NR
204FROM-MAP must contain appropriate binding for `[menu-bar]' which
205holds a keymap."
ca1b34c8
RS
206 (unless from-map
207 (setq from-map global-map))
208 (let* ((menu-bar-map (lookup-key from-map [menu-bar]))
ec7f4585 209 (keys (where-is-internal command menu-bar-map))
94975270 210 (image-exp (tool-bar--image-expression icon))
ec7f4585 211 submap key)
c8fcd943
SM
212 ;; We'll pick up the last valid entry in the list of keys if
213 ;; there's more than one.
9ae0c310 214 ;; FIXME: Aren't they *all* "valid"?? --Stef
c8fcd943
SM
215 (dolist (k keys)
216 ;; We're looking for a binding of the command in a submap of
217 ;; the menu bar map, so the key sequence must be two or more
218 ;; long.
219 (if (and (vectorp k)
220 (> (length k) 1))
221 (let ((m (lookup-key menu-bar-map (substring k 0 -1)))
222 ;; Last element in the bound key sequence:
223 (kk (aref k (1- (length k)))))
224 (if (and (keymapp m)
7ac82b84 225 (symbolp kk))
c8fcd943
SM
226 (setq submap m
227 key kk)))))
7ac82b84
J
228 (when (and (symbolp submap) (boundp submap))
229 (setq submap (eval submap)))
230 (let ((defn (assq key (cdr submap))))
231 (if (eq (cadr defn) 'menu-item)
232 (define-key-after in-map (vector key)
233 (append (cdr defn) (list :image image-exp) props))
234 (setq defn (cdr defn))
c8fcd943 235 (define-key-after in-map (vector key)
7ac82b84
J
236 (let ((rest (cdr defn)))
237 ;; If the rest of the definition starts
238 ;; with a list of menu cache info, get rid of that.
239 (if (and (consp rest) (consp (car rest)))
240 (setq rest (cdr rest)))
241 (append `(menu-item ,(car defn) ,rest)
242 (list :image image-exp) props)))))))
ec7f4585
DL
243
244;;; Set up some global items. Additions/deletions up for grabs.
245
e4779829 246(defun tool-bar-setup ()
94975270
CY
247 (setq tool-bar-separator-image-expression
248 (tool-bar--image-expression "separator"))
d2bd5189
JD
249 (tool-bar-add-item-from-menu 'find-file "new" nil :label "New File"
250 :vert-only t)
251 (tool-bar-add-item-from-menu 'menu-find-file-existing "open" nil
4039c786 252 :label "Open" :vert-only t)
d2bd5189
JD
253 (tool-bar-add-item-from-menu 'dired "diropen" nil :vert-only t)
254 (tool-bar-add-item-from-menu 'kill-this-buffer "close" nil :vert-only t)
94975270 255 (tool-bar-add-item-from-menu 'save-buffer "save" nil
c940c054 256 :label "Save")
4039c786 257 (define-key-after (default-value 'tool-bar-map) [separator-1] menu-bar-separator)
900503ae 258 (tool-bar-add-item-from-menu 'undo "undo" nil)
4039c786 259 (define-key-after (default-value 'tool-bar-map) [separator-2] menu-bar-separator)
e4779829 260 (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [cut])
c940c054 261 "cut" nil :vert-only t)
e4779829 262 (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [copy])
d2bd5189 263 "copy" nil :vert-only t)
e4779829 264 (tool-bar-add-item-from-menu (lookup-key menu-bar-edit-menu [paste])
c940c054 265 "paste" nil :vert-only t)
4039c786 266 (define-key-after (default-value 'tool-bar-map) [separator-3] menu-bar-separator)
900503ae
CY
267 (tool-bar-add-item-from-menu 'isearch-forward "search"
268 nil :label "Search" :vert-only t)
e4779829
CY
269 ;;(tool-bar-add-item-from-menu 'ispell-buffer "spell")
270
271 ;; There's no icon appropriate for News and we need a command rather
272 ;; than a lambda for Read Mail.
273 ;;(tool-bar-add-item-from-menu 'compose-mail "mail/compose")
274
900503ae
CY
275 ;; Help button on a tool bar is rather non-standard...
276 ;; (let ((tool-bar-map (default-value 'tool-bar-map)))
277 ;; (tool-bar-add-item "help" (lambda ()
278 ;; (interactive)
279 ;; (popup-menu menu-bar-help-menu))
280 ;; 'help
281 ;; :help "Pop up the Help menu"))
282)
ec7f4585 283
8cf1771a
JD
284(if (featurep 'move-toolbar)
285 (defcustom tool-bar-position 'top
286 "Specify on which side the tool bar shall be.
287Possible values are `top' (tool bar on top), `bottom' (tool bar at bottom),
288`left' (tool bar on left) and `right' (tool bar on right).
289Customize `tool-bar-mode' if you want to show or hide the tool bar."
2bed3f04 290 :version "24.1"
8cf1771a
JD
291 :type '(choice (const top)
292 (const bottom)
293 (const left)
294 (const right))
295 :group 'frames
296 :initialize 'custom-initialize-default
297 :set (lambda (sym val)
298 (set-default sym val)
9d794026 299 (modify-all-frames-parameters
8cf1771a
JD
300 (list (cons 'tool-bar-position val))))))
301
ec7f4585 302
c044516d 303(provide 'tool-bar)
9d794026 304
ec7f4585 305;;; tool-bar.el ends here