comparison 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
comparison
equal deleted inserted replaced
2140:9da6e6c569f7 2141:6bca5896aab2
469 ignored. Specifically, instancing over a frame looks first for frame 469 ignored. Specifically, instancing over a frame looks first for frame
470 locales, then device locales, then the @code{global} locale. Instancing 470 locales, then device locales, then the @code{global} locale. Instancing
471 over a device domain looks only for device locales and the @code{global} 471 over a device domain looks only for device locales and the @code{global}
472 locale. 472 locale.
473 473
474 Note that specifiers are instanced on @emph{every} redisplay. (This is
475 the concept; of course the implementation keeps track of changes and
476 doesn't reinstance unchanged specifiers.) That means that changes in
477 specifiers controlling appearance are reflected immediately in the UI.
478 Also, since specifiers are instanced completely, removing a
479 specification can be just as effective as adding one.
480
481 @emph{E.g.}, Giacomo Boffi wanted a modeline that indicates whether the
482 frame containing it is selected or not. The first proposed implementation
483 is natural in a world of ``local'' variables. The later implementations
484 apply the power of specifiers.
485
486 (The copyright notice and permission statement below apply to the code in
487 example format, up to the ``@code{;;; end of neon-modeline.el}''
488 comment.)
489
490 @example
491 ;;; neon-modeline.el
492
493 ;; Copyright (c) 2004 Stephen J. Turnbull <stephen@@xemacs.org>
494
495 ;; Based on a suggestion by Giacomo Boffi
496
497 ;; This code may be used and redistributed under the GNU GPL, v.2 or any
498 ;; later version as published by the FSF, or under the license used for
499 ;; XEmacs Texinfo manuals, at your option.
500 @end example
501
502 A few customizations:
503
504 @example
505 ;; Placate the specifier and Customize gods.
506
507 (unless (valid-specifier-tag-p 'modeline-background)
508 (define-specifier-tag 'modeline-background))
509
510 (defgroup lisp-demos nil "Demos for Lisp programming techniques.")
511
512 (defgroup neon-modeline nil "Neon modeline identifies selected frame."
513 :group 'lisp-demos)
514
515 (defcustom neon-modeline-selected-background "LemonChiffon"
516 "Background color for modeline in selected frames."
517 :type 'color
518 :group 'neon-modeline)
519
520 (defcustom neon-modeline-deselected-background "Wheat"
521 "Background color for modeline in unselected frames."
522 :type 'color
523 :group 'neon-modeline)
524
525 @end example
526
527 Our first try uses three functions, a setup and two hook functions.
528 Separate hooks are defined for entry into a frame and exit from it.
529 Since we're using hooks, it's a fairly natural approach: we operate on
530 the background on each event corresponding to an appearance change we
531 want to make. This doesn't depend on the specifier API, ``frame-local''
532 variables would serve as well.
533
534 @example
535 (defun select-modeline ()
536 (set-face-background 'modeline neon-modeline-selected-background
537 (selected-frame)))
538
539 (defun deselect-modeline ()
540 (set-face-background 'modeline neon-modeline-deselected-background
541 (selected-frame)))
542 @end example
543
544 Note that the initialization removes no specifications, and therefore is
545 not idempotent. Cruft will accumulate in the specifier if the
546 @samp{-setup} function is called repeatedly. This shouldn't cause a
547 performance problem; specifiers are quite efficient for their purpose.
548 But it's ugly, and wastes a small amount of space.
549
550 @example
551 (defun neon-modeline-setup ()
552 (interactive)
553 (set-face-background 'modeline neon-modeline-deselected-background)
554 ;; Add the distinguished background on pointer entry to the frame;
555 (add-hook 'select-frame-hook 'select-modeline)
556 ;; restore the ordinary background on pointer exit from the frame.
557 (add-hook 'deselect-frame-hook 'deselect-modeline)
558 @end example
559
560 This approach causes a decided flicker on Boffi's platform, because the
561 two hook functions are executed in response to separate GUI events.
562
563 The following code should be an improvement. First, the hook function.
564
565 @example
566 (defun neon-modeline-reselect ()
567 (set-face-background 'modeline neon-modeline-deselected-background
568 (selected-frame) '(modeline-background)
569 'remove-locale-type))
570 @end example
571
572 Only one event triggers the configuration change, which should reduce
573 flicker. Because this is implemented as a specifier, we can use the
574 specifier API to reset all frame-local specifications (the
575 @code{remove-locale-type} argument). This leaves the @code{global}
576 specification alone, but removes all existing frame-local
577 specifications. Then it adds the selected-frame background
578 specification for the newly selected frame. @emph{I.e.}, this
579 effectively implements a ``move specification from frame to frame''
580 operation.
581
582 Why does it give the desired result? By ensuring that only one frame
583 has the selected-frame modeline background. Frame-local specifications
584 have precedence over global ones, so when the modeline background is
585 instantiated in the selected frame, it matches the specification set up
586 for it and gets the right color. On the other hand, in any other frame,
587 it does not match the selected frame, so it falls through the
588 frame-local specifications and picks up the global specification. Again
589 we get the desired color, in this case for unselected frames.
590
591 Here the @code{modeline-background} tag is simply good practice
592 (identifying an application's specifications allows it to avoid
593 interfering with other applications, and other well-behaved applications
594 and Customize should not munge specifications with our tag on them).
595 However, an alternative implementation of this functionality would be
596
597 @example
598 (defun neon-modeline-reselect-2 ()
599 (set-face-background 'modeline neon-modeline-deselected-background
600 (selected-frame) '(modeline-background)
601 'remove-tag-set-prepend))
602 @end example
603
604 @code{neon-modeline-reselect} may be a preferable implementation here, if we
605 really want only one frame to have a local specification. The
606 @code{neon-modeline-reselect-2} style would be useful if we had groups of
607 frames which have @emph{different} modeline backgrounds when deselected.
608
609 Here's the initialization function, with different semantics from above.
610 Note that it is destructive, unless the user saves off the state of the
611 modeline face before invoking the function. This is only a problem if
612 you remove specifications and expect the older ones to persist. In this
613 example it should not be an issue. We use the customizations defined
614 above.
615
616 @example
617 (defun neon-modeline-modified-setup ()
618 (interactive)
619 (set-face-background 'modeline neon-modeline-selected-background
620 'global nil 'remove-all)
621 (add-hook 'select-frame-hook 'neon-modeline-reselect)
622
623 ;;; end of neon-modeline.el
624 @end example
625
626 Note the use of @code{'remove-all} to clear out stale specifications.
627 Thus it will be idempotent.
628
629
474 @node Specifier Types 630 @node Specifier Types
475 @section Specifier Types 631 @section Specifier Types
476 632
477 There are various different types of specifiers. The type of a 633 There are various different types of specifiers. The type of a
478 specifier controls what sorts of instantiators are valid, how an 634 specifier controls what sorts of instantiators are valid, how an