Mercurial > hg > xemacs-beta
diff man/lispref/specifiers.texi @ 2141:6bca5896aab2
[xemacs-hg @ 2004-06-18 07:18:38 by stephent]
neon modeline example <874qp9jpx1.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Fri, 18 Jun 2004 07:18:40 +0000 |
parents | 2ba4f06a264d |
children | c7d4a681eb2c |
line wrap: on
line diff
--- a/man/lispref/specifiers.texi Fri Jun 18 04:06:50 2004 +0000 +++ b/man/lispref/specifiers.texi Fri Jun 18 07:18:40 2004 +0000 @@ -471,6 +471,162 @@ over a device domain looks only for device locales and the @code{global} locale. +Note that specifiers are instanced on @emph{every} redisplay. (This is +the concept; of course the implementation keeps track of changes and +doesn't reinstance unchanged specifiers.) That means that changes in +specifiers controlling appearance are reflected immediately in the UI. +Also, since specifiers are instanced completely, removing a +specification can be just as effective as adding one. + +@emph{E.g.}, Giacomo Boffi wanted a modeline that indicates whether the +frame containing it is selected or not. The first proposed implementation +is natural in a world of ``local'' variables. The later implementations +apply the power of specifiers. + +(The copyright notice and permission statement below apply to the code in +example format, up to the ``@code{;;; end of neon-modeline.el}'' +comment.) + +@example +;;; neon-modeline.el + +;; Copyright (c) 2004 Stephen J. Turnbull <stephen@@xemacs.org> + +;; Based on a suggestion by Giacomo Boffi + +;; This code may be used and redistributed under the GNU GPL, v.2 or any +;; later version as published by the FSF, or under the license used for +;; XEmacs Texinfo manuals, at your option. +@end example + +A few customizations: + +@example +;; Placate the specifier and Customize gods. + +(unless (valid-specifier-tag-p 'modeline-background) + (define-specifier-tag 'modeline-background)) + +(defgroup lisp-demos nil "Demos for Lisp programming techniques.") + +(defgroup neon-modeline nil "Neon modeline identifies selected frame." + :group 'lisp-demos) + +(defcustom neon-modeline-selected-background "LemonChiffon" + "Background color for modeline in selected frames." + :type 'color + :group 'neon-modeline) + +(defcustom neon-modeline-deselected-background "Wheat" + "Background color for modeline in unselected frames." + :type 'color + :group 'neon-modeline) + +@end example + +Our first try uses three functions, a setup and two hook functions. +Separate hooks are defined for entry into a frame and exit from it. +Since we're using hooks, it's a fairly natural approach: we operate on +the background on each event corresponding to an appearance change we +want to make. This doesn't depend on the specifier API, ``frame-local'' +variables would serve as well. + +@example +(defun select-modeline () + (set-face-background 'modeline neon-modeline-selected-background + (selected-frame))) + +(defun deselect-modeline () + (set-face-background 'modeline neon-modeline-deselected-background + (selected-frame))) +@end example + +Note that the initialization removes no specifications, and therefore is +not idempotent. Cruft will accumulate in the specifier if the +@samp{-setup} function is called repeatedly. This shouldn't cause a +performance problem; specifiers are quite efficient for their purpose. +But it's ugly, and wastes a small amount of space. + +@example +(defun neon-modeline-setup () + (interactive) + (set-face-background 'modeline neon-modeline-deselected-background) + ;; Add the distinguished background on pointer entry to the frame; + (add-hook 'select-frame-hook 'select-modeline) + ;; restore the ordinary background on pointer exit from the frame. + (add-hook 'deselect-frame-hook 'deselect-modeline) +@end example + +This approach causes a decided flicker on Boffi's platform, because the +two hook functions are executed in response to separate GUI events. + +The following code should be an improvement. First, the hook function. + +@example +(defun neon-modeline-reselect () + (set-face-background 'modeline neon-modeline-deselected-background + (selected-frame) '(modeline-background) + 'remove-locale-type)) +@end example + +Only one event triggers the configuration change, which should reduce +flicker. Because this is implemented as a specifier, we can use the +specifier API to reset all frame-local specifications (the +@code{remove-locale-type} argument). This leaves the @code{global} +specification alone, but removes all existing frame-local +specifications. Then it adds the selected-frame background +specification for the newly selected frame. @emph{I.e.}, this +effectively implements a ``move specification from frame to frame'' +operation. + +Why does it give the desired result? By ensuring that only one frame +has the selected-frame modeline background. Frame-local specifications +have precedence over global ones, so when the modeline background is +instantiated in the selected frame, it matches the specification set up +for it and gets the right color. On the other hand, in any other frame, +it does not match the selected frame, so it falls through the +frame-local specifications and picks up the global specification. Again +we get the desired color, in this case for unselected frames. + +Here the @code{modeline-background} tag is simply good practice +(identifying an application's specifications allows it to avoid +interfering with other applications, and other well-behaved applications +and Customize should not munge specifications with our tag on them). +However, an alternative implementation of this functionality would be + +@example +(defun neon-modeline-reselect-2 () + (set-face-background 'modeline neon-modeline-deselected-background + (selected-frame) '(modeline-background) + 'remove-tag-set-prepend)) +@end example + +@code{neon-modeline-reselect} may be a preferable implementation here, if we +really want only one frame to have a local specification. The +@code{neon-modeline-reselect-2} style would be useful if we had groups of +frames which have @emph{different} modeline backgrounds when deselected. + +Here's the initialization function, with different semantics from above. +Note that it is destructive, unless the user saves off the state of the +modeline face before invoking the function. This is only a problem if +you remove specifications and expect the older ones to persist. In this +example it should not be an issue. We use the customizations defined +above. + +@example +(defun neon-modeline-modified-setup () + (interactive) + (set-face-background 'modeline neon-modeline-selected-background + 'global nil 'remove-all) + (add-hook 'select-frame-hook 'neon-modeline-reselect) + +;;; end of neon-modeline.el +@end example + +Note the use of @code{'remove-all} to clear out stale specifications. +Thus it will be idempotent. + + @node Specifier Types @section Specifier Types