thirdparty/color-theme.el
changeset 55 d4adcd3d5ef9
parent 54 e1b82f67f96e
child 56 7446c9ffe828
equal deleted inserted replaced
54:e1b82f67f96e 55:d4adcd3d5ef9
     1 ;;; color-theme.el --- install color themes
       
     2 
       
     3 ;; Copyright (C) 1999, 2000  Jonadab the Unsightly One <[email protected]>
       
     4 ;; Copyright (C) 2000, 2001, 2002, 2003  Alex Schroeder <[email protected]>
       
     5 ;; Copyright (C) 2003, 2004, 2005, 2006  Xavier Maillard <[email protected]>
       
     6 
       
     7 ;; Version: 6.6.0
       
     8 ;; Keywords: faces
       
     9 ;; Author: Jonadab the Unsightly One <[email protected]>
       
    10 ;; Maintainer: Xavier Maillard <[email protected]>
       
    11 ;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?ColorTheme
       
    12 
       
    13 ;; This file is not (YET) part of GNU Emacs.
       
    14 
       
    15 ;; This is free software; you can redistribute it and/or modify it under
       
    16 ;; the terms of the GNU General Public License as published by the Free
       
    17 ;; Software Foundation; either version 2, or (at your option) any later
       
    18 ;; version.
       
    19 ;;
       
    20 ;; This is distributed in the hope that it will be useful, but WITHOUT
       
    21 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    22 ;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    23 ;; for more details.
       
    24 ;;
       
    25 ;; You should have received a copy of the GNU General Public License
       
    26 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
       
    27 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
       
    28 ;; MA 02111-1307, USA.
       
    29 
       
    30 ;;; Commentary:
       
    31 
       
    32 ;; Please read README and BUGS files for any relevant help.
       
    33 ;; Contributors (not themers) should also read HACKING file.
       
    34 
       
    35 ;;; Thanks
       
    36 
       
    37 ;; Deepak Goel  <[email protected]>
       
    38 ;; S. Pokrovsky <[email protected]> for ideas and discussion.
       
    39 ;; Gordon Messmer <[email protected]> for ideas and discussion.
       
    40 ;; Sriram Karra <[email protected]> for the color-theme-submit stuff.
       
    41 ;; Olgierd `Kingsajz' Ziolko <[email protected]> for the spec-filter idea.
       
    42 ;; Brian Palmer for color-theme-library ideas and code
       
    43 ;; All the users that contributed their color themes.
       
    44 
       
    45 
       
    46 
       
    47 ;;; Code:
       
    48 (eval-when-compile
       
    49   (require 'easymenu)
       
    50   (require 'reporter)
       
    51   (require 'sendmail))
       
    52 
       
    53 (require 'cl); set-difference is a function...
       
    54 
       
    55 ;; for custom-face-attributes-get or face-custom-attributes-get
       
    56 (require 'cus-face)
       
    57 (require 'wid-edit); for widget-apply stuff in cus-face.el
       
    58 
       
    59 (defconst color-theme-maintainer-address "[email protected]"
       
    60   "Address used by `submit-color-theme'.")
       
    61 
       
    62 ;; Emacs / XEmacs compatibility and workaround layer
       
    63 
       
    64 (cond ((and (facep 'tool-bar)
       
    65 	    (not (facep 'toolbar)))
       
    66        (put 'toolbar 'face-alias 'tool-bar))
       
    67       ((and (facep 'toolbar)
       
    68 	    (not (facep 'tool-bar)))
       
    69        (put 'tool-bar 'face-alias 'toolbar)))
       
    70 
       
    71 (defvar color-theme-xemacs-p (and (featurep 'xemacs) 
       
    72                                   (string-match "XEmacs" emacs-version))
       
    73   "Non-nil if running XEmacs.")
       
    74 
       
    75 ;; Add this since it appears to miss in emacs-2x
       
    76 (or (fboundp 'replace-in-string)
       
    77     (defun replace-in-string (target old new)
       
    78       (replace-regexp-in-string old new  target)))
       
    79 
       
    80 ;; face-attr-construct has a problem in Emacs 20.7 and older when
       
    81 ;; dealing with inverse-video faces.  Here is a short test to check
       
    82 ;; wether you are affected.
       
    83 
       
    84 ;; (set-background-color "wheat")
       
    85 ;; (set-foreground-color "black")
       
    86 ;; (setq a (make-face 'a-face))
       
    87 ;; (face-spec-set a '((t (:background "white" :foreground "black" :inverse-video t))))
       
    88 ;; (face-attr-construct a)
       
    89 ;;     => (:background "black" :inverse-video t)
       
    90 
       
    91 ;; The expected response is the original specification:
       
    92 ;;     => (:background "white" :foreground "black" :inverse-video t)
       
    93 
       
    94 ;; That's why we depend on cus-face.el functionality.
       
    95 
       
    96 (cond ((fboundp 'custom-face-attributes-get)
       
    97        (defun color-theme-face-attr-construct (face frame)
       
    98          (if (atom face)
       
    99              (custom-face-attributes-get face frame)
       
   100              (if (and (consp face) (eq (car face) 'quote))
       
   101                  (custom-face-attributes-get (cadr face) frame)
       
   102                  (custom-face-attributes-get (car face) frame)))))
       
   103       ((fboundp 'face-custom-attributes-get)
       
   104        (defalias 'color-theme-face-attr-construct
       
   105 	 'face-custom-attributes-get))
       
   106       (t
       
   107        (defun color-theme-face-attr-construct (&rest ignore)
       
   108 	 (error "Unable to construct face attributes"))))
       
   109 
       
   110 (defun color-theme-alist (plist)
       
   111   "Transform PLIST into an alist if it is a plist and return it.
       
   112 If the first element of PLIST is a cons cell, we just return PLIST,
       
   113 assuming PLIST to be an alist.  If the first element of plist is not a
       
   114 symbol, this is an error: We cannot distinguish a plist from an ordinary
       
   115 list, but a list that doesn't start with a symbol is certainly no plist
       
   116 and no alist.
       
   117 
       
   118 This is used to make sure `default-frame-alist' really is an alist and not
       
   119 a plist.  In XEmacs, the alist is deprecated; a plist is used instead."
       
   120   (cond ((consp (car plist))
       
   121 	 plist)
       
   122 	((not (symbolp (car plist)))
       
   123 	 (error "Wrong type argument: plist, %S" plist))
       
   124 	((featurep 'xemacs)
       
   125 	 (plist-to-alist plist)))); XEmacs only
       
   126 
       
   127 ;; Customization
       
   128 
       
   129 (defgroup color-theme nil
       
   130   "Color Themes for Emacs.
       
   131 A color theme consists of frame parameter settings, variable settings,
       
   132 and face definitions."
       
   133   :version "20.6"
       
   134   :group 'faces)
       
   135 
       
   136 (defcustom color-theme-legal-frame-parameters "\\(color\\|mode\\)$"
       
   137   "Regexp that matches frame parameter names.
       
   138 Only frame parameter names that match this regexp can be changed as part
       
   139 of a color theme."
       
   140   :type '(choice (const :tag "Colors only" "\\(color\\|mode\\)$")
       
   141 		 (const :tag "Colors, fonts, and size"
       
   142 			"\\(color\\|mode\\|font\\|height\\|width\\)$")
       
   143 		 (regexp :tag "Custom regexp"))
       
   144   :group 'color-theme
       
   145   :link '(info-link "(elisp)Window Frame Parameters"))
       
   146 
       
   147 (defcustom color-theme-legal-variables "\\(color\\|face\\)$"
       
   148   "Regexp that matches variable names.
       
   149 Only variables that match this regexp can be changed as part of a color
       
   150 theme.  In addition to matching this name, the variables have to be user
       
   151 variables (see function `user-variable-p')."
       
   152   :type 'regexp
       
   153   :group 'color-theme)
       
   154 
       
   155 (defcustom color-theme-illegal-faces "^w3-"
       
   156   "Regexp that matches face names forbidden in themes.
       
   157 The default setting \"^w3-\" excludes w3 faces since these
       
   158 are created dynamically."
       
   159   :type 'regexp
       
   160   :group 'color-theme
       
   161   :link '(info-link "(elisp)Faces for Font Lock")
       
   162   :link '(info-link "(elisp)Standard Faces"))
       
   163 
       
   164 (defcustom color-theme-illegal-default-attributes '(:family :height :width)
       
   165   "A list of face properties to be ignored when installing faces.
       
   166 This prevents Emacs from doing terrible things to your display just because
       
   167 a theme author likes weird fonts."
       
   168   :type '(repeat symbol)
       
   169   :group 'color-theme)
       
   170 
       
   171 (defcustom color-theme-is-global t
       
   172   "*Determines wether a color theme is installed on all frames or not.
       
   173 If non-nil, color themes will be installed for all frames.
       
   174 If nil, color themes will be installed for the selected frame only.
       
   175 
       
   176 A possible use for this variable is dynamic binding. Here is a larger
       
   177 example to put in your ~/.emacs; it will make the Blue Sea color theme
       
   178 the default used for the first frame, and it will create two additional
       
   179 frames with different color themes.
       
   180 
       
   181 setup:
       
   182     \(require 'color-theme)
       
   183     ;; set default color theme
       
   184     \(color-theme-blue-sea)
       
   185     ;; create some frames with different color themes
       
   186     \(let ((color-theme-is-global nil))
       
   187       \(select-frame (make-frame))
       
   188       \(color-theme-gnome2)
       
   189       \(select-frame (make-frame))
       
   190       \(color-theme-standard))
       
   191 
       
   192 Please note that using XEmacs and and a nil value for
       
   193 color-theme-is-global will ignore any variable settings for the color
       
   194 theme, since XEmacs doesn't have frame-local variable bindings.
       
   195 
       
   196 Also note that using Emacs and a non-nil value for color-theme-is-global
       
   197 will install a new color theme for all frames.  Using XEmacs and a
       
   198 non-nil value for color-theme-is-global will install a new color theme
       
   199 only on those frames that are not using a local color theme."
       
   200   :type 'boolean
       
   201   :group 'color-theme)
       
   202 
       
   203 (defcustom color-theme-is-cumulative t
       
   204   "*Determines wether new color themes are installed on top of each other.
       
   205 If non-nil, installing a color theme will undo all settings made by
       
   206 previous color themes."
       
   207   :type 'boolean
       
   208   :group 'color-theme)
       
   209 
       
   210 (defcustom color-theme-directory nil
       
   211   "Directory where we can find additionnal themes (personnal).
       
   212 Note that there is at least one directory shipped with the official
       
   213 color-theme distribution where all contributed themes are located.
       
   214 This official selection can't be changed with that variable. 
       
   215 However, you still can decide to turn it on or off and thus,
       
   216 not be shown with all themes but yours."
       
   217   :type '(repeat string)
       
   218   :group 'color-theme)
       
   219 
       
   220 (defcustom color-theme-libraries (directory-files 
       
   221                                   (concat 
       
   222                                    (file-name-directory (locate-library "color-theme"))
       
   223                                    "/themes") t "^color-theme")
       
   224   "A list of files, which will be loaded in color-theme-initialize depending
       
   225 on `color-theme-load-all-themes' value. 
       
   226 This allows a user to prune the default color-themes (which can take a while
       
   227 to load)."
       
   228   :type '(repeat string)
       
   229   :group 'color-theme)
       
   230 
       
   231 (defcustom color-theme-load-all-themes t
       
   232   "When t, load all color-theme theme files
       
   233 as presented by `color-theme-libraries'. Else
       
   234 do not load any of this themes."
       
   235   :type 'boolean
       
   236   :group 'color-theme)
       
   237 
       
   238 (defcustom color-theme-mode-hook nil
       
   239   "Hook for color-theme-mode."
       
   240   :type 'hook
       
   241   :group 'color-theme)
       
   242 
       
   243 (defvar color-theme-mode-map
       
   244   (let ((map (make-sparse-keymap)))
       
   245     (define-key map (kbd "RET") 'color-theme-install-at-point)
       
   246     (define-key map (kbd "c") 'list-colors-display)
       
   247     (define-key map (kbd "d") 'color-theme-describe)
       
   248     (define-key map (kbd "f") 'list-faces-display)
       
   249     (define-key map (kbd "i") 'color-theme-install-at-point)
       
   250     (define-key map (kbd "l") 'color-theme-install-at-point-for-current-frame)
       
   251     (define-key map (kbd "p") 'color-theme-print)
       
   252     (define-key map (kbd "q") 'bury-buffer)
       
   253     (define-key map (kbd "?") 'color-theme-describe)
       
   254     (if color-theme-xemacs-p
       
   255 	(define-key map (kbd "<button2>") 'color-theme-install-at-mouse)
       
   256       (define-key map (kbd "<mouse-2>") 'color-theme-install-at-mouse))
       
   257     map)
       
   258   "Mode map used for the buffer created by `color-theme-select'.")
       
   259 
       
   260 (defvar color-theme-initialized nil
       
   261   "Internal variable determining whether color-theme-initialize has been invoked yet")
       
   262 
       
   263 (defvar color-theme-buffer-name "*Color Theme Selection*"
       
   264   "Name of the color theme selection buffer.")
       
   265 
       
   266 (defvar color-theme-original-frame-alist nil
       
   267   "nil until one of the color themes has been installed.")
       
   268 
       
   269 (defvar color-theme-history nil
       
   270   "List of color-themes called, in reverse order")
       
   271 
       
   272 (defcustom color-theme-history-max-length nil
       
   273   "Max length of history to maintain.
       
   274 Two other values are acceptable: t means no limit, and
       
   275 nil means that no history is maintained."
       
   276   :type '(choice (const :tag "No history" nil)
       
   277 		 (const :tag "Unlimited length" t)
       
   278 		 integer)
       
   279   :group 'color-theme)
       
   280 
       
   281 (defvar color-theme-counter 0
       
   282   "Counter for every addition to `color-theme-history'.
       
   283 This counts how many themes were installed, regardless
       
   284 of `color-theme-history-max-length'.")
       
   285 
       
   286 (defvar color-theme-entry-path (cond
       
   287                                 ;; Emacs 22.x and later
       
   288                                 ((lookup-key global-map [menu-bar tools])
       
   289                                  '("tools"))
       
   290                                 ;; XEmacs
       
   291                                 ((featurep 'xemacs)
       
   292                                  (setq tool-entry '("Tools")))
       
   293                                 ;; Emacs < 22
       
   294                                 (t
       
   295                                  '("Tools")))
       
   296   "Menu tool entry path.")
       
   297 
       
   298 (defun color-theme-add-to-history (name)
       
   299   "Add color-theme NAME to `color-theme-history'."
       
   300   (setq color-theme-history
       
   301 	(cons (list name color-theme-is-cumulative)
       
   302 	      color-theme-history)
       
   303 	color-theme-counter (+ 1 color-theme-counter))
       
   304   ;; Truncate the list if necessary.
       
   305   (when (and (integerp color-theme-history-max-length)
       
   306 	     (>= (length color-theme-history)
       
   307 		 color-theme-history-max-length))
       
   308     (setcdr (nthcdr (1- color-theme-history-max-length)
       
   309 		    color-theme-history)
       
   310 	    nil)))
       
   311 
       
   312 ;; (let ((l '(1 2 3 4 5)))
       
   313 ;;   (setcdr (nthcdr 2 l) nil)
       
   314 ;;   l)
       
   315 
       
   316 
       
   317 
       
   318 ;; List of color themes used to create the *Color Theme Selection*
       
   319 ;; buffer.
       
   320 
       
   321 (defvar color-themes
       
   322   '((color-theme-aalto-dark "Aalto Dark" "Jari Aalto <[email protected]>")
       
   323     (color-theme-aalto-light "Aalto Light" "Jari Aalto <[email protected]>")
       
   324     (color-theme-aliceblue "Alice Blue" "Girish Bharadwaj <[email protected]>")
       
   325     (color-theme-andreas "Andreas" "Andreas Busch <[email protected]>")
       
   326     (color-theme-arjen "Arjen" "Arjen Wiersma <[email protected]>")
       
   327     (color-theme-beige-diff "Beige Diff" "Alex Schroeder <[email protected]>" t)
       
   328     (color-theme-bharadwaj "Bharadwaj" "Girish Bharadwaj <[email protected]>")
       
   329     (color-theme-bharadwaj-slate "Bharadwaj Slate" "Girish Bharadwaj <[email protected]>")
       
   330     (color-theme-billw "Billw" "Bill White <[email protected]>")
       
   331     (color-theme-black-on-gray "BlackOnGray" "Sudhir Bhojwani <[email protected]>")
       
   332     (color-theme-blippblopp "Blipp Blopp" "Thomas Sicheritz-Ponten<[email protected]>")
       
   333     (color-theme-simple-1 "Black" "Jonadab <[email protected]>")
       
   334     (color-theme-blue-erc "Blue ERC" "Alex Schroeder <[email protected]>" t)
       
   335     (color-theme-blue-gnus "Blue Gnus" "Alex Schroeder <[email protected]>" t)
       
   336     (color-theme-blue-mood "Blue Mood" "Nelson Loyola <[email protected]>")
       
   337     (color-theme-blue-sea "Blue Sea" "Alex Schroeder <[email protected]>")
       
   338     (color-theme-calm-forest "Calm Forest" "Artur Hefczyc <[email protected]>")
       
   339     (color-theme-charcoal-black "Charcoal Black" "Lars Chr. Hausmann <[email protected]>")
       
   340     (color-theme-goldenrod "Cheap Goldenrod" "Alex Schroeder <[email protected]>")
       
   341     (color-theme-clarity "Clarity and Beauty" "Richard Wellum <[email protected]>")
       
   342     (color-theme-classic "Classic" "Frederic Giroud <[email protected]>")
       
   343     (color-theme-comidia "Comidia" "Marcelo Dias de Toledo <[email protected]>")
       
   344     (color-theme-jsc-dark "Cooper Dark" "John S Cooper <[email protected]>")
       
   345     (color-theme-jsc-light "Cooper Light" "John S Cooper <[email protected]>")
       
   346     (color-theme-jsc-light2 "Cooper Light 2" "John S Cooper <[email protected]>")
       
   347     (color-theme-dark-blue "Dark Blue" "Chris McMahan <[email protected]>")
       
   348     (color-theme-dark-blue2 "Dark Blue 2" "Chris McMahan <[email protected]>")
       
   349     (color-theme-dark-green "Dark Green" "[email protected]")
       
   350     (color-theme-dark-laptop "Dark Laptop" "Laurent Michel <[email protected]>")
       
   351     (color-theme-deep-blue "Deep Blue" "Tomas Cerha <[email protected]>")
       
   352     (color-theme-digital-ofs1 "Digital OFS1" "Gareth Owen <[email protected]>")
       
   353     (color-theme-euphoria "Euphoria" "[email protected]")
       
   354     (color-theme-feng-shui "Feng Shui" "Walter Higgins <[email protected]>")
       
   355     (color-theme-fischmeister "Fischmeister"
       
   356 			      "Sebastian Fischmeister <[email protected]>")
       
   357     (color-theme-gnome "Gnome" "Jonadab <[email protected]>")
       
   358     (color-theme-gnome2 "Gnome 2" "Alex Schroeder <[email protected]>")
       
   359     (color-theme-gray1 "Gray1" "Paul Pulli <[email protected]>")
       
   360     (color-theme-gray30 "Gray30" "Girish Bharadwaj <[email protected]>")
       
   361     (color-theme-kingsajz "Green Kingsajz" "Olgierd `Kingsajz' Ziolko <[email protected]>")
       
   362     (color-theme-greiner "Greiner" "Kevin Greiner <[email protected]>")
       
   363     (color-theme-gtk-ide "GTK IDE" "Gordon Messmer <[email protected]>")
       
   364     (color-theme-high-contrast "High Contrast" "Alex Schroeder <[email protected]>")
       
   365     (color-theme-hober "Hober" "Edward O'Connor <[email protected]>")
       
   366     (color-theme-infodoc "Infodoc" "Frederic Giroud <[email protected]>")
       
   367     (color-theme-jb-simple "JB Simple" "[email protected]")
       
   368     (color-theme-jedit-grey "Jedit Grey" "Gordon Messmer <[email protected]>")
       
   369     (color-theme-jonadabian "Jonadab" "Jonadab <[email protected]>")
       
   370     (color-theme-jonadabian-slate "Jonadabian Slate" "Jonadab <[email protected]>")
       
   371     (color-theme-katester "Katester" "[email protected]")
       
   372     (color-theme-late-night "Late Night" "Alex Schroeder <[email protected]>")
       
   373     (color-theme-lawrence "Lawrence" "lawrence mitchell <[email protected]>")
       
   374     (color-theme-lethe "Lethe" "Ivica Loncar <[email protected]>")
       
   375     (color-theme-ld-dark "Linh Dang Dark" "Linh Dang <[email protected]>")
       
   376     (color-theme-marine "Marine" "Girish Bharadwaj <[email protected]>")
       
   377     (color-theme-matrix "Matrix" "Walter Higgins <[email protected]>")
       
   378     (color-theme-marquardt "Marquardt" "Colin Marquardt <[email protected]>")
       
   379     (color-theme-midnight "Midnight" "Gordon Messmer <[email protected]>")
       
   380     (color-theme-mistyday "Misty Day" "Hari Kumar <[email protected]>")
       
   381     (color-theme-montz "Montz" "Brady Montz <[email protected]>")
       
   382     (color-theme-oswald "Oswald" "Tom Oswald <[email protected]>")
       
   383     (color-theme-parus "Parus" "Jon K Hellan <[email protected]>")
       
   384     (color-theme-pierson "Pierson" "Dan L. Pierson <[email protected]>")
       
   385     (color-theme-ramangalahy "Ramangalahy" "Solofo Ramangalahy <[email protected]>")
       
   386     (color-theme-raspopovic "Raspopovic" "Pedja Raspopovic <[email protected]>")
       
   387     (color-theme-renegade "Renegade" "Dave Benjamin <[email protected]>")
       
   388     (color-theme-resolve "Resolve" "Damien Elmes <[email protected]>")
       
   389     (color-theme-retro-green "Retro Green" "Alex Schroeder <[email protected]>")
       
   390     (color-theme-retro-orange "Retro Orange" "Alex Schroeder <[email protected]>")
       
   391     (color-theme-robin-hood "Robin Hood" "Alex Schroeder <[email protected]>")
       
   392     (color-theme-rotor "Rotor" "Jinwei Shen <[email protected]>")
       
   393     (color-theme-ryerson "Ryerson" "Luis Fernandes <[email protected]>")
       
   394     (color-theme-salmon-diff "Salmon Diff" "Alex Schroeder <[email protected]>" t)
       
   395     (color-theme-salmon-font-lock "Salmon Font-Lock" "Alex Schroeder <[email protected]>" t)
       
   396     (color-theme-scintilla "Scintilla" "Gordon Messmer <[email protected]>")
       
   397     (color-theme-shaman "Shaman" "[email protected]")
       
   398     (color-theme-sitaramv-nt "Sitaram NT"
       
   399 			     "Sitaram Venkatraman <[email protected]>")
       
   400     (color-theme-sitaramv-solaris "Sitaram Solaris"
       
   401 				  "Sitaram Venkatraman <[email protected]>")
       
   402     (color-theme-snow "Snow" "Nicolas Rist <[email protected]>")
       
   403     (color-theme-snowish "Snowish" "Girish Bharadwaj <[email protected]>")
       
   404     (color-theme-standard-ediff "Standard Ediff" "Emacs Team, added by Alex Schroeder <[email protected]>" t)
       
   405     (color-theme-standard "Standard Emacs 20" "Emacs Team, added by Alex Schroeder <[email protected]>")
       
   406     (color-theme-emacs-21 "Standard Emacs 21" "Emacs Team, added by Alex Schroeder <[email protected]>")
       
   407     (color-theme-emacs-nw "Standard Emacs 21 No Window" "Emacs Team, added by D. Goel <[email protected]>")
       
   408     (color-theme-xemacs "Standard XEmacs" "XEmacs Team, added by Alex Schroeder <[email protected]>")
       
   409     (color-theme-subtle-blue "Subtle Blue" "Chris McMahan <[email protected]>")
       
   410     (color-theme-subtle-hacker "Subtle Hacker" "Colin Walters <[email protected]>")
       
   411     (color-theme-taming-mr-arneson "Taming Mr Arneson" "Erik Arneson <[email protected]>")
       
   412     (color-theme-taylor "Taylor" "Art Taylor <[email protected]>")
       
   413     (color-theme-tty-dark "TTY Dark" "O Polite <[email protected]>")
       
   414     (color-theme-vim-colors "Vim Colors" "Michael Soulier <[email protected]>")
       
   415     (color-theme-whateveryouwant "Whateveryouwant" "Fabien Penso <[email protected]>, color by Scott Jaderholm <[email protected]>")
       
   416     (color-theme-wheat "Wheat" "Alex Schroeder <[email protected]>")
       
   417     (color-theme-pok-wob "White On Black" "S. Pokrovsky <[email protected]>")
       
   418     (color-theme-pok-wog "White On Grey" "S. Pokrovsky <[email protected]>")
       
   419     (color-theme-word-perfect "WordPerfect" "Thomas Gehrlein <[email protected]>")
       
   420     (color-theme-xp "XP" "Girish Bharadwaj <[email protected]>"))
       
   421   "List of color themes.
       
   422 
       
   423 Each THEME is itself a three element list (FUNC NAME MAINTAINER &optional LIBRARY).
       
   424 
       
   425 FUNC is a color theme function which does the setup.  The function
       
   426 FUNC may call `color-theme-install'.  The color theme function may be
       
   427 interactive.
       
   428 
       
   429 NAME is the name of the theme and MAINTAINER is the name and/or email of
       
   430 the maintainer of the theme.
       
   431 
       
   432 If LIBRARY is non-nil, the color theme will be considered a library and
       
   433 may not be shown in the default menu.
       
   434 
       
   435 If you defined your own color theme and want to add it to this list,
       
   436 use something like this:
       
   437 
       
   438   (add-to-list 'color-themes '(color-theme-gnome2 \"Gnome2\" \"Alex\"))")
       
   439 
       
   440 ;;; Functions
       
   441 
       
   442 (defun color-theme-backup-original-values ()
       
   443   "Back up the original `default-frame-alist'.
       
   444 The values are stored in `color-theme-original-frame-alist' on
       
   445 startup."
       
   446   (if (null color-theme-original-frame-alist)
       
   447       (setq color-theme-original-frame-alist
       
   448 	    (color-theme-filter (frame-parameters (selected-frame))
       
   449 				color-theme-legal-frame-parameters))))
       
   450 (add-hook 'after-init-hook 'color-theme-backup-original-values)
       
   451 
       
   452 ;;;###autoload
       
   453 (defun color-theme-select (&optional arg)
       
   454   "Displays a special buffer for selecting and installing a color theme.
       
   455 With optional prefix ARG, this buffer will include color theme libraries
       
   456 as well.  A color theme library is in itself not complete, it must be
       
   457 used as part of another color theme to be useful.  Thus, color theme
       
   458 libraries are mainly useful for color theme authors."
       
   459   (interactive "P")
       
   460   (unless color-theme-initialized (color-theme-initialize))
       
   461   (switch-to-buffer (get-buffer-create color-theme-buffer-name))
       
   462   (setq buffer-read-only nil)
       
   463   (erase-buffer)
       
   464   ;; recreate the snapshot if necessary
       
   465   (when (or (not (assq 'color-theme-snapshot color-themes))
       
   466 	    (not (commandp 'color-theme-snapshot)))
       
   467     (fset 'color-theme-snapshot (color-theme-make-snapshot))
       
   468     (setq color-themes (delq (assq 'color-theme-snapshot color-themes)
       
   469 			     color-themes)
       
   470 	  color-themes (delq (assq 'bury-buffer color-themes)
       
   471 			     color-themes)
       
   472 	  color-themes (append '((color-theme-snapshot
       
   473 				  "[Reset]" "Undo changes, if possible.")
       
   474 				 (bury-buffer
       
   475 				  "[Quit]" "Bury this buffer."))
       
   476 			     color-themes)))
       
   477   (dolist (theme color-themes)
       
   478     (let ((func (nth 0 theme))
       
   479 	  (name (nth 1 theme))
       
   480 	  (author (nth 2 theme))
       
   481 	  (library (nth 3 theme))
       
   482 	  (desc))
       
   483       (when (or (not library) arg)
       
   484 	(setq desc (format "%-23s %s" 
       
   485 			   (if library (concat name " [lib]") name)
       
   486 			   author))
       
   487 	(put-text-property 0 (length desc) 'color-theme func desc)
       
   488 	(put-text-property 0 (length name) 'face 'bold desc)
       
   489 	(put-text-property 0 (length name) 'mouse-face 'highlight desc)
       
   490 	(insert desc)
       
   491 	(newline))))
       
   492   (goto-char (point-min))
       
   493   (setq buffer-read-only t)
       
   494   (set-buffer-modified-p nil)
       
   495   (color-theme-mode))
       
   496 
       
   497 (when (require 'easymenu)
       
   498   (easy-menu-add-item nil color-theme-entry-path "--")
       
   499   (easy-menu-add-item  nil color-theme-entry-path
       
   500                        ["Color Themes" color-theme-select t]))
       
   501 
       
   502 (defun color-theme-mode ()
       
   503   "Major mode to select and install color themes.
       
   504 
       
   505 Use \\[color-theme-install-at-point] to install a color theme on all frames.
       
   506 Use \\[color-theme-install-at-point-for-current-frame] to install a color theme for the current frame only.
       
   507 
       
   508 The changes are applied on top of your current setup.  This is a
       
   509 feature.
       
   510 
       
   511 Some of the themes should be considered extensions to the standard color
       
   512 theme: they modify only a limited number of faces and variables.  To
       
   513 verify the final look of a color theme, install the standard color
       
   514 theme, then install the other color theme.  This is a feature. It allows
       
   515 you to mix several color themes.
       
   516 
       
   517 Use \\[color-theme-describe] to read more about the color theme function at point.
       
   518 If you want to install the color theme permanently, put the call to the
       
   519 color theme function into your ~/.emacs:
       
   520 
       
   521     \(require 'color-theme)
       
   522     \(color-theme-gnome2)
       
   523 
       
   524 If you worry about the size of color-theme.el: You are right.  Use
       
   525 \\[color-theme-print] to print the current color theme and save the resulting buffer
       
   526 as ~/.emacs-color-theme.  Now you can install only this specific color
       
   527 theme in your .emacs:
       
   528 
       
   529     \(load-file \"~/.emacs-color-theme\")
       
   530     \(my-color-theme)
       
   531 
       
   532 The Emacs menu is not affected by color themes within Emacs.  Depending
       
   533 on the toolkit you used to compile Emacs, you might have to set specific
       
   534 X ressources.  See the info manual for more information.  Here is an
       
   535 example ~/.Xdefaults fragment:
       
   536 
       
   537     emacs*Background: DarkSlateGray
       
   538     emacs*Foreground: wheat
       
   539 
       
   540 \\{color-theme-mode-map}
       
   541 
       
   542 The color themes are listed in `color-themes', which see."
       
   543   (kill-all-local-variables)
       
   544   (setq major-mode 'color-theme-mode)
       
   545   (setq mode-name "Color Themes")
       
   546   (use-local-map color-theme-mode-map)
       
   547   (when (functionp 'goto-address); Emacs
       
   548     (goto-address))
       
   549   (run-hooks 'color-theme-mode-hook))
       
   550 
       
   551 ;;; Commands in Color Theme Selection mode
       
   552 
       
   553 ;;;###autoload
       
   554 (defun color-theme-describe ()
       
   555   "Describe color theme listed at point.
       
   556 This shows the documentation of the value of text-property color-theme
       
   557 at point.  The text-property color-theme should be a color theme
       
   558 function.  See `color-themes'."
       
   559   (interactive)
       
   560   (describe-function (get-text-property (point) 'color-theme)))
       
   561 
       
   562 ;;;###autoload
       
   563 (defun color-theme-install-at-mouse (event)
       
   564   "Install color theme clicked upon using the mouse.
       
   565 First argument EVENT is used to set point.  Then
       
   566 `color-theme-install-at-point' is called."
       
   567   (interactive "e")
       
   568   (save-excursion
       
   569     (mouse-set-point event)
       
   570     (color-theme-install-at-point)))
       
   571 
       
   572 ;;;autoload
       
   573 (defun color-theme-install-at-point ()
       
   574   "Install color theme at point.
       
   575 This calls the value of the text-property `color-theme' at point.
       
   576 The text-property `color-theme' should be a color theme function.
       
   577 See `color-themes'."
       
   578   (interactive)
       
   579   (let ((func (get-text-property (point) 'color-theme)))
       
   580     ;; install theme
       
   581     (if func
       
   582 	(funcall func))
       
   583     ;; If goto-address is being used, remove all overlays in the current
       
   584     ;; buffer and run it again.  The face used for the mail addresses in
       
   585     ;; the the color theme selection buffer is based on the variable
       
   586     ;; goto-address-mail-face.  Changes in that variable will not affect
       
   587     ;; existing overlays, however, thereby confusing users.
       
   588     (when (functionp 'goto-address); Emacs
       
   589       (dolist (o (overlays-in (point-min) (point-max)))
       
   590 	(delete-overlay o))
       
   591       (goto-address))))
       
   592 
       
   593 ;;;###autoload
       
   594 (defun color-theme-install-at-point-for-current-frame ()
       
   595   "Install color theme at point for current frame only.
       
   596 Binds `color-theme-is-global' to nil and calls
       
   597 `color-theme-install-at-point'."
       
   598   (interactive)
       
   599   (let ((color-theme-is-global nil))
       
   600     (color-theme-install-at-point)))
       
   601 
       
   602 
       
   603 
       
   604 ;; Taking a snapshot of the current color theme and pretty printing it.
       
   605 
       
   606 (defun color-theme-filter (old-list regexp &optional exclude)
       
   607   "Filter OLD-LIST.
       
   608 The resulting list will be newly allocated and contains only elements
       
   609 with names matching REGEXP.  OLD-LIST may be a list or an alist.  If you
       
   610 want to filter a plist, use `color-theme-alist' to convert your plist to
       
   611 an alist, first.
       
   612 
       
   613 If the optional argument EXCLUDE is non-nil, then the sense is
       
   614 reversed: only non-matching elements will be retained."
       
   615   (let (elem new-list)
       
   616     (dolist (elem old-list)
       
   617       (setq name (symbol-name (if (listp elem) (car elem) elem)))
       
   618       (when (or (and (not exclude)
       
   619 		     (string-match regexp name))
       
   620 		(and exclude
       
   621 		     (not (string-match regexp name))))
       
   622 	;; Now make sure that if elem is a cons cell, and the cdr of
       
   623 	;; that cons cell is a string, then we need a *new* string in
       
   624 	;; the new list.  Having a new cons cell is of no use because
       
   625 	;; modify-frame-parameters will modify this string, thus
       
   626 	;; modifying our color theme functions!
       
   627 	(when (and (consp elem)
       
   628 		   (stringp (cdr elem)))
       
   629 	  (setq elem (cons (car elem)
       
   630 			   (copy-sequence (cdr elem)))))
       
   631 	;; Now store elem
       
   632 	(setq new-list (cons elem new-list))))
       
   633     new-list))
       
   634 
       
   635 (defun color-theme-spec-filter (spec)
       
   636   "Filter the attributes in SPEC.
       
   637 This makes sure that SPEC has the form ((t (PLIST ...))).
       
   638 Only properties not in `color-theme-illegal-default-attributes'
       
   639 are included in the SPEC returned."
       
   640   (let ((props (cadar spec))
       
   641 	result prop val)
       
   642     (while props
       
   643       (setq prop (nth 0 props)
       
   644 	    val (nth 1 props)
       
   645 	    props (nthcdr 2 props))
       
   646       (unless (memq prop color-theme-illegal-default-attributes)
       
   647 	(setq result (cons val (cons prop result)))))
       
   648     `((t ,(nreverse result)))))
       
   649 
       
   650 ;; (color-theme-spec-filter '((t (:background "blue3"))))
       
   651 ;; (color-theme-spec-filter '((t (:stipple nil :background "Black" :foreground "SteelBlue" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :width semi-condensed :family "misc-fixed"))))
       
   652 
       
   653 (defun color-theme-plist-delete (plist prop)
       
   654   "Delete property PROP from property list PLIST by side effect.
       
   655 This modifies PLIST."
       
   656   ;; deal with prop at the start
       
   657   (while (eq (car plist) prop)
       
   658     (setq plist (cddr plist)))
       
   659   ;; deal with empty plist
       
   660   (when plist
       
   661     (let ((lastcell (cdr plist))
       
   662 	  (l (cddr plist)))
       
   663       (while l
       
   664 	(if (eq (car l) prop)
       
   665 	    (progn
       
   666 	      (setq l (cddr l))
       
   667 	      (setcdr lastcell l))
       
   668 	  (setq lastcell (cdr l)
       
   669 		l (cddr l))))))
       
   670   plist)
       
   671 
       
   672 ;; (color-theme-plist-delete '(a b c d e f g h) 'a)
       
   673 ;; (color-theme-plist-delete '(a b c d e f g h) 'b)
       
   674 ;; (color-theme-plist-delete '(a b c d e f g h) 'c)
       
   675 ;; (color-theme-plist-delete '(a b c d e f g h) 'g)
       
   676 ;; (color-theme-plist-delete '(a b c d c d e f g h) 'c)
       
   677 ;; (color-theme-plist-delete '(a b c d e f c d g h) 'c)
       
   678 
       
   679 (if (or (featurep 'xemacs)
       
   680 	(< emacs-major-version 21))
       
   681     (defalias 'color-theme-spec-compat 'identity)
       
   682   (defun color-theme-spec-compat (spec)
       
   683     "Filter the attributes in SPEC such that is is never invalid.
       
   684 Example: Eventhough :bold works in Emacs, it is not recognized by
       
   685 `customize-face' -- and then the face is uncustomizable.  This
       
   686 function replaces a :bold attribute with the corresponding :weight
       
   687 attribute, if there is no :weight, or deletes it.  This undoes the
       
   688 doings of `color-theme-spec-canonical-font', more or less."
       
   689     (let ((props (cadar spec)))
       
   690       (when (plist-member props :bold)
       
   691 	(setq props (color-theme-plist-delete props :bold))
       
   692 	(unless (plist-member props :weight)
       
   693 	  (setq props (plist-put props :weight 'bold))))
       
   694       (when (plist-member props :italic)
       
   695 	(setq props (color-theme-plist-delete props :italic))
       
   696 	(unless (plist-member props :slant)
       
   697 	  (setq props (plist-put props :slant 'italic))))
       
   698       `((t ,props)))))
       
   699 
       
   700 ;; (color-theme-spec-compat '((t (:foreground "blue" :bold t))))
       
   701 ;; (color-theme-spec-compat '((t (:bold t :foreground "blue" :weight extra-bold))))
       
   702 ;; (color-theme-spec-compat '((t (:italic t :foreground "blue"))))
       
   703 ;; (color-theme-spec-compat '((t (:slant oblique :italic t :foreground "blue"))))
       
   704 
       
   705 (defun color-theme-spec-canonical-font (atts)
       
   706   "Add :bold and :italic attributes if necessary."
       
   707   ;; add these to the front of atts -- this will keept the old value for
       
   708   ;; customize-face in Emacs 21.
       
   709   (when (and (memq (plist-get atts :weight)
       
   710 		   '(ultra-bold extra-bold bold semi-bold))
       
   711 	     (not (plist-get atts :bold)))
       
   712     (setq atts (cons :bold (cons t atts))))
       
   713   (when (and (not (memq (plist-get atts :slant)
       
   714 			'(normal nil)))
       
   715 	     (not (plist-get atts :italic)))
       
   716     (setq atts (cons :italic (cons t atts))))
       
   717   atts)
       
   718 ;; (color-theme-spec-canonical-font (color-theme-face-attr-construct 'bold (selected-frame)))
       
   719 ;; (defface foo '((t (:weight extra-bold))) "foo")
       
   720 ;; (color-theme-spec-canonical-font (color-theme-face-attr-construct 'foo (selected-frame)))
       
   721 ;; (face-spec-set 'foo '((t (:weight extra-bold))) nil)
       
   722 ;; (face-spec-set 'foo '((t (:bold t))) nil)
       
   723 ;; (face-spec-set 'foo '((t (:bold t :weight extra-bold))) nil)
       
   724 
       
   725 ;; Handle :height according to NEWS file for Emacs 21
       
   726 (defun color-theme-spec-resolve-height (old new)
       
   727   "Return the new height given OLD and NEW height.
       
   728 OLD is the current setting, NEW is the setting inherited from."
       
   729   (cond ((not old)
       
   730 	 new)
       
   731 	((integerp old)
       
   732 	 old)
       
   733 	((and (floatp old)
       
   734 	      (integerp new))
       
   735 	 (round (* old new)))
       
   736 	((and (floatp old)
       
   737 	      (floatp new))
       
   738 	 (* old new))
       
   739 	((and (functionp old)
       
   740 	      (integerp new))
       
   741 	 (round (funcall old new)))
       
   742 	((and (functionp old)
       
   743 	      (float new))
       
   744 	 `(lambda (f) (* (funcall ,old f) ,new)))
       
   745 	((and (functionp old)
       
   746 	      (functionp new))
       
   747 	 `(lambda (f) (* (funcall ,old (funcall ,new f)))))
       
   748 	(t
       
   749 	 (error "Illegal :height attributes: %S or %S" old new))))
       
   750 ;; (color-theme-spec-resolve-height 12 1.2)
       
   751 ;; (color-theme-spec-resolve-height 1.2 1.2)
       
   752 ;; (color-theme-spec-resolve-height 1.2 12)
       
   753 ;; (color-theme-spec-resolve-height 1.2 'foo)
       
   754 ;; (color-theme-spec-resolve-height (lambda (f) (* 2 f)) 5)
       
   755 ;; (color-theme-spec-resolve-height (lambda (f) (* 2 f)) 2.0)
       
   756 ;; the following lambda is the result from the above calculation
       
   757 ;; (color-theme-spec-resolve-height (lambda (f) (* (funcall (lambda (f) (* 2 f)) f) 2.0)) 5)
       
   758 
       
   759 (defun color-theme-spec-resolve-inheritance (atts)
       
   760   "Resolve all occurences of the :inherit attribute."
       
   761   (let ((face (plist-get atts :inherit)))
       
   762     ;; From the Emacs 21 NEWS file: "Attributes from inherited faces are
       
   763     ;; merged into the face like an underlying face would be." --
       
   764     ;; therefore properties of the inherited face only add missing
       
   765     ;; attributes.
       
   766     (when face
       
   767       ;; remove :inherit face from atts -- this assumes only one
       
   768       ;; :inherit attribute.
       
   769       (setq atts (delq ':inherit (delq face atts)))
       
   770       (let ((more-atts (color-theme-spec-resolve-inheritance
       
   771 			(color-theme-face-attr-construct
       
   772 			 face (selected-frame))))
       
   773 	    att val)
       
   774 	(while more-atts
       
   775 	  (setq att (car more-atts)
       
   776 		val (cadr more-atts)
       
   777 		more-atts (cddr more-atts))
       
   778 	  ;; Color-theme assumes that no value is ever 'unspecified.
       
   779 	  (cond ((eq att ':height); cumulative effect!
       
   780 		 (setq atts (plist-put atts 
       
   781 				       ':height 
       
   782 				       (color-theme-spec-resolve-height
       
   783 					(plist-get atts att) 
       
   784 					val))))
       
   785 		;; Default: Only put if it has not been specified before.
       
   786 		((not (plist-get atts att))
       
   787 		 (setq atts (cons att (cons val atts))))
       
   788 		  
       
   789 ))))
       
   790     atts))
       
   791 ;; (color-theme-spec-resolve-inheritance '(:bold t))
       
   792 ;; (color-theme-spec-resolve-inheritance '(:bold t :foreground "blue"))
       
   793 ;; (color-theme-face-attr-construct 'font-lock-comment-face (selected-frame))
       
   794 ;; (color-theme-spec-resolve-inheritance '(:bold t :inherit font-lock-comment-face))
       
   795 ;; (color-theme-spec-resolve-inheritance '(:bold t :foreground "red" :inherit font-lock-comment-face))
       
   796 ;; (color-theme-face-attr-construct 'Info-title-2-face (selected-frame))
       
   797 ;; (color-theme-face-attr-construct 'Info-title-3-face (selected-frame))
       
   798 ;; (color-theme-face-attr-construct 'Info-title-4-face (selected-frame))
       
   799 ;; (color-theme-spec-resolve-inheritance '(:inherit Info-title-2-face))
       
   800 
       
   801 ;; The :inverse-video attribute causes Emacs to swap foreground and
       
   802 ;; background colors, XEmacs does not.  Therefore, if anybody chooses
       
   803 ;; the inverse-video attribute, we 1. swap the colors ourselves in Emacs
       
   804 ;; and 2. we remove the inverse-video attribute in Emacs and XEmacs.
       
   805 ;; Inverse-video is only useful on a monochrome tty.
       
   806 (defun color-theme-spec-maybe-invert (atts)
       
   807   "Remove the :inverse-video attribute from ATTS.
       
   808 If ATTS contains :inverse-video t, remove it and swap foreground and
       
   809 background color.  Return ATTS."
       
   810   (let ((inv (plist-get atts ':inverse-video)))
       
   811     (if inv
       
   812 	(let (result att)
       
   813 	  (while atts
       
   814 	    (setq att (car atts)
       
   815 		  atts (cdr atts))
       
   816 	    (cond ((and (eq att :foreground) (not color-theme-xemacs-p))
       
   817 		   (setq result (cons :background result)))
       
   818 		  ((and (eq att :background) (not color-theme-xemacs-p))
       
   819 		   (setq result (cons :foreground result)))
       
   820 		  ((eq att :inverse-video)
       
   821 		   (setq atts (cdr atts))); this prevents using dolist
       
   822 		  (t
       
   823 		   (setq result (cons att result)))))
       
   824 	  (nreverse result))
       
   825       ;; else
       
   826       atts)))
       
   827 ;; (color-theme-spec-maybe-invert '(:bold t))
       
   828 ;; (color-theme-spec-maybe-invert '(:foreground "blue"))
       
   829 ;; (color-theme-spec-maybe-invert '(:background "red"))
       
   830 ;; (color-theme-spec-maybe-invert '(:inverse-video t))
       
   831 ;; (color-theme-spec-maybe-invert '(:inverse-video t :foreground "red"))
       
   832 ;; (color-theme-spec-maybe-invert '(:inverse-video t :background "red"))
       
   833 ;; (color-theme-spec-maybe-invert '(:inverse-video t :background "red" :foreground "blue" :bold t))
       
   834 ;; (color-theme-spec-maybe-invert '(:inverse-video nil :background "red" :foreground "blue" :bold t))
       
   835 
       
   836 (defun color-theme-spec (face)
       
   837   "Return a list for FACE which has the form (FACE SPEC).
       
   838 See `defface' for the format of SPEC.  In this case we use only one
       
   839 DISPLAY, t, and determine ATTS using `color-theme-face-attr-construct'.
       
   840 If ATTS is nil, (nil) is used  instead.
       
   841 
       
   842 If ATTS contains :inverse-video t, we remove it and swap foreground and
       
   843 background color using `color-theme-spec-maybe-invert'.  We do this
       
   844 because :inverse-video is handled differently in Emacs and XEmacs.  We
       
   845 will loose on a tty without colors, because in that situation,
       
   846 :inverse-video means something."
       
   847   (let ((atts
       
   848 	 (color-theme-spec-canonical-font
       
   849 	  (color-theme-spec-maybe-invert
       
   850 	   (color-theme-spec-resolve-inheritance
       
   851 	    (color-theme-face-attr-construct face (selected-frame)))))))
       
   852     (if atts
       
   853 	`(,face ((t ,atts)))
       
   854       `(,face ((t (nil)))))))
       
   855 
       
   856 (defun color-theme-get-params ()
       
   857   "Return a list of frame parameter settings usable in a color theme.
       
   858 Such an alist may be installed by `color-theme-install-frame-params'.  The
       
   859 frame parameters returned must match `color-theme-legal-frame-parameters'."
       
   860   (let ((params (color-theme-filter (frame-parameters (selected-frame))
       
   861 				    color-theme-legal-frame-parameters)))
       
   862     (sort params (lambda (a b) (string< (symbol-name (car a))
       
   863 					(symbol-name (car b)))))))
       
   864 
       
   865 (defun color-theme-get-vars ()
       
   866   "Return a list of variable settings usable in a color theme.
       
   867 Such an alist may be installed by `color-theme-install-variables'.
       
   868 The variable names must match `color-theme-legal-variables', and the
       
   869 variable must be a user variable according to `user-variable-p'."
       
   870   (let ((vars)
       
   871 	(val))
       
   872     (mapatoms (lambda (v)
       
   873 		(and (boundp v)
       
   874 		     (user-variable-p v)
       
   875 		     (string-match color-theme-legal-variables
       
   876 				   (symbol-name v))
       
   877 		     (setq val (eval v))
       
   878 		     (add-to-list 'vars (cons v val)))))
       
   879     (sort vars (lambda (a b) (string< (car a) (car b))))))
       
   880 
       
   881 (defun color-theme-print-alist (alist)
       
   882   "Print ALIST."
       
   883   (insert "\n     " (if alist "(" "nil"))
       
   884   (dolist (elem alist)
       
   885     (when (= (preceding-char) ?\))
       
   886       (insert "\n      "))
       
   887     (prin1 elem (current-buffer)))
       
   888   (when (= (preceding-char) ?\)) (insert ")")))
       
   889 
       
   890 (defun color-theme-get-faces ()
       
   891   "Return a list of faces usable in a color theme.
       
   892 Such an alist may be installed by `color-theme-install-faces'.  The
       
   893 faces returned must not match `color-theme-illegal-faces'."
       
   894   (let ((faces (color-theme-filter (face-list) color-theme-illegal-faces t)))
       
   895     ;; default face must come first according to comments in
       
   896     ;; custom-save-faces, the rest is to be sorted by name
       
   897     (cons 'default (sort (delq 'default faces) 'string-lessp))))
       
   898 
       
   899 (defun color-theme-get-face-definitions ()
       
   900   "Return face settings usable in a color-theme."
       
   901   (let ((faces (color-theme-get-faces)))
       
   902     (mapcar 'color-theme-spec faces)))
       
   903 
       
   904 (defun color-theme-print-faces (faces)
       
   905   "Print face settings for all faces returned by `color-theme-get-faces'."
       
   906   (when faces
       
   907     (insert "\n     "))
       
   908   (dolist (face faces)
       
   909     (when (= (preceding-char) ?\))
       
   910       (insert "\n     "))
       
   911     (prin1 face (current-buffer))))
       
   912 
       
   913 (defun color-theme-reset-faces ()
       
   914   "Reset face settings for all faces returned by `color-theme-get-faces'."
       
   915   (let ((faces (color-theme-get-faces))
       
   916 	(face) (spec) (entry)
       
   917 	(frame (if color-theme-is-global nil (selected-frame))))
       
   918     (while faces
       
   919       (setq entry (color-theme-spec (car faces)))
       
   920       (setq face (nth 0 entry))
       
   921       (setq spec '((t (nil))))
       
   922       (setq faces (cdr faces))
       
   923       (if (functionp 'face-spec-reset-face)
       
   924 	  (face-spec-reset-face face frame)
       
   925 	(face-spec-set face spec frame)
       
   926 	(if color-theme-is-global
       
   927 	    (put face 'face-defface-spec spec))))))
       
   928 
       
   929 (defun color-theme-print-theme (func doc params vars faces)
       
   930   "Print a theme into the current buffer.
       
   931 FUNC is the function name, DOC the doc string, PARAMS the
       
   932 frame parameters, VARS the variable bindings, and FACES
       
   933 the list of faces and their specs."
       
   934   (insert "(defun " (symbol-name func) " ()\n"
       
   935 	  "  \"" doc "\"\n"
       
   936 	  "  (interactive)\n"
       
   937 	  "  (color-theme-install\n"
       
   938 	  "   '(" (symbol-name func))
       
   939   ;; alist of frame parameters
       
   940   (color-theme-print-alist params)
       
   941   ;; alist of variables
       
   942   (color-theme-print-alist vars)
       
   943   ;; remaining elements of snapshot: face specs
       
   944   (color-theme-print-faces faces)
       
   945   (insert ")))\n")
       
   946   (insert "(add-to-list 'color-themes '(" (symbol-name func) " "
       
   947           " \"THEME NAME\" \"YOUR NAME\"))")
       
   948   (goto-char (point-min)))
       
   949 
       
   950 ;;;###autoload
       
   951 (defun color-theme-print (&optional buf)
       
   952   "Print the current color theme function.
       
   953 
       
   954 You can contribute this function to <URL:news:gnu.emacs.sources> or
       
   955 paste it into your .emacs file and call it.  That should recreate all
       
   956 the settings necessary for your color theme.
       
   957 
       
   958 Example:
       
   959 
       
   960     \(require 'color-theme)
       
   961     \(defun my-color-theme ()
       
   962       \"Color theme by Alex Schroeder, created 2000-05-17.\"
       
   963       \(interactive)
       
   964       \(color-theme-install
       
   965        '(...
       
   966 	 ...
       
   967 	 ...)))
       
   968     \(my-color-theme)
       
   969 
       
   970 If you want to use a specific color theme function, you can call the
       
   971 color theme function in your .emacs directly.
       
   972 
       
   973 Example:
       
   974 
       
   975     \(require 'color-theme)
       
   976     \(color-theme-gnome2)"
       
   977   (interactive)
       
   978   (message "Pretty printing current color theme function...")
       
   979   (switch-to-buffer (if buf
       
   980 			buf
       
   981 		      (get-buffer-create "*Color Theme*")))
       
   982   (unless buf
       
   983     (setq buffer-read-only nil)
       
   984     (erase-buffer))
       
   985   ;; insert defun
       
   986   (insert "(eval-when-compile"
       
   987           "    (require 'color-theme))\n")
       
   988   (color-theme-print-theme 'my-color-theme
       
   989 			   (concat "Color theme by "
       
   990 				   (if (string= "" user-full-name)
       
   991 				       (user-login-name)
       
   992 				     user-full-name)
       
   993 				   ", created " (format-time-string "%Y-%m-%d") ".")
       
   994 			   (color-theme-get-params)
       
   995 			   (color-theme-get-vars)
       
   996 			   (mapcar 'color-theme-spec (color-theme-get-faces)))
       
   997   (unless buf
       
   998     (emacs-lisp-mode))
       
   999   (goto-char (point-min))
       
  1000   (message "Pretty printing current color theme function... done"))
       
  1001 
       
  1002 (defun color-theme-analyze-find-theme (code)
       
  1003   "Find the sexpr that calls `color-theme-install'."
       
  1004   (let (theme)
       
  1005     (while (and (not theme) code)
       
  1006       (when (eq (car code) 'color-theme-install)
       
  1007 	(setq theme code))
       
  1008       (when (listp (car code))
       
  1009 	(setq theme (color-theme-analyze-find-theme (car code))))
       
  1010       (setq code (cdr code)))
       
  1011     theme))
       
  1012 
       
  1013 ;; (equal (color-theme-analyze-find-theme
       
  1014 ;; 	'(defun color-theme-blue-eshell ()
       
  1015 ;; 	   "Color theme for eshell faces only."
       
  1016 ;; 	   (color-theme-install
       
  1017 ;; 	    '(color-theme-blue-eshell
       
  1018 ;; 	      nil
       
  1019 ;; 	      (eshell-ls-archive-face ((t (:bold t :foreground "IndianRed"))))
       
  1020 ;; 	      (eshell-ls-backup-face ((t (:foreground "Grey"))))))))
       
  1021 ;;        '(color-theme-install
       
  1022 ;; 	 (quote
       
  1023 ;; 	  (color-theme-blue-eshell
       
  1024 ;; 	   nil
       
  1025 ;; 	   (eshell-ls-archive-face ((t (:bold t :foreground "IndianRed"))))
       
  1026 ;; 	   (eshell-ls-backup-face ((t (:foreground "Grey")))))))))
       
  1027 
       
  1028 (defun color-theme-analyze-add-face (a b regexp faces)
       
  1029   "If only one of A or B are in FACES, the other is added, and FACES is returned.
       
  1030 If REGEXP is given, this is only done if faces contains a match for regexps."
       
  1031   (when (or (not regexp)
       
  1032 	    (catch 'found
       
  1033 	      (dolist (face faces)
       
  1034 		(when (string-match regexp (symbol-name (car face)))
       
  1035 		  (throw 'found t)))))
       
  1036     (let ((face-a (assoc a faces))
       
  1037 	  (face-b (assoc b faces)))
       
  1038       (if (and face-a (not face-b))
       
  1039 	  (setq faces (cons (list b (nth 1 face-a))
       
  1040 			    faces))
       
  1041 	(if (and (not face-a) face-b)
       
  1042 	    (setq faces (cons (list a (nth 1 face-b))
       
  1043 			      faces))))))
       
  1044   faces)
       
  1045 
       
  1046 ;; (equal (color-theme-analyze-add-face
       
  1047 ;; 	'blue 'violet nil
       
  1048 ;; 	'((blue ((t (:foreground "blue"))))
       
  1049 ;; 	  (bold ((t (:bold t))))))
       
  1050 ;;        '((violet ((t (:foreground "blue"))))
       
  1051 ;; 	 (blue ((t (:foreground "blue"))))
       
  1052 ;; 	 (bold ((t (:bold t))))))
       
  1053 ;; (equal (color-theme-analyze-add-face
       
  1054 ;; 	'violet 'blue nil
       
  1055 ;; 	'((blue ((t (:foreground "blue"))))
       
  1056 ;; 	  (bold ((t (:bold t))))))
       
  1057 ;;        '((violet ((t (:foreground "blue"))))
       
  1058 ;; 	 (blue ((t (:foreground "blue"))))
       
  1059 ;; 	 (bold ((t (:bold t))))))
       
  1060 ;; (equal (color-theme-analyze-add-face
       
  1061 ;; 	'violet 'blue "foo"
       
  1062 ;; 	'((blue ((t (:foreground "blue"))))
       
  1063 ;; 	  (bold ((t (:bold t))))))
       
  1064 ;;        '((blue ((t (:foreground "blue"))))
       
  1065 ;; 	 (bold ((t (:bold t))))))
       
  1066 ;; (equal (color-theme-analyze-add-face
       
  1067 ;; 	'violet 'blue "blue"
       
  1068 ;; 	'((blue ((t (:foreground "blue"))))
       
  1069 ;; 	  (bold ((t (:bold t))))))
       
  1070 ;;        '((violet ((t (:foreground "blue"))))
       
  1071 ;; 	 (blue ((t (:foreground "blue"))))
       
  1072 ;; 	 (bold ((t (:bold t))))))
       
  1073 
       
  1074 (defun color-theme-analyze-add-faces (faces)
       
  1075   "Add missing faces to FACES and return it."
       
  1076   ;; The most important thing is to add missing faces for the other
       
  1077   ;; editor.  These are the most important faces to check.  The
       
  1078   ;; following rules list two faces, A and B.  If either of the two is
       
  1079   ;; part of the theme, the other must be, too.  The optional third
       
  1080   ;; argument specifies a regexp.  Only if an existing face name
       
  1081   ;; matches this regexp, is the rule applied.
       
  1082   (let ((rules '((font-lock-builtin-face font-lock-reference-face)
       
  1083 		 (font-lock-doc-face font-lock-doc-string-face)
       
  1084 		 (font-lock-constant-face font-lock-preprocessor-face)
       
  1085 		 ;; In Emacs 21 `modeline' is just an alias for
       
  1086 		 ;; `mode-line'.  I recommend the use of
       
  1087 		 ;; `modeline' until further notice.
       
  1088 		 (modeline mode-line)
       
  1089 		 (modeline modeline-buffer-id)
       
  1090 		 (modeline modeline-mousable)
       
  1091 		 (modeline modeline-mousable-minor-mode)
       
  1092 		 (region primary-selection)
       
  1093 		 (region zmacs-region)
       
  1094 		 (font-lock-string-face dired-face-boring "^dired")
       
  1095 		 (font-lock-function-name-face dired-face-directory "^dired")
       
  1096 		 (default dired-face-executable "^dired")
       
  1097 		 (font-lock-warning-face dired-face-flagged "^dired")
       
  1098 		 (font-lock-warning-face dired-face-marked "^dired")
       
  1099 		 (default dired-face-permissions "^dired")
       
  1100 		 (default dired-face-setuid "^dired")
       
  1101 		 (default dired-face-socket "^dired")
       
  1102 		 (font-lock-keyword-face dired-face-symlink "^dired")
       
  1103 		 (tool-bar menu))))
       
  1104     (dolist (rule rules)
       
  1105       (setq faces (color-theme-analyze-add-face
       
  1106 		   (nth 0 rule) (nth 1 rule) (nth 2 rule) faces))))
       
  1107   ;; The `fringe' face defines what the left and right borders of the
       
  1108   ;; frame look like in Emacs 21.  To give them default fore- and
       
  1109   ;; background colors, use (fringe ((t (nil)))) in your color theme.
       
  1110   ;; Usually it makes more sense to choose a color slightly lighter or
       
  1111   ;; darker from the default background.
       
  1112   (unless (assoc 'fringe faces)
       
  1113     (setq faces (cons '(fringe ((t (nil)))) faces)))
       
  1114   ;; The tool-bar should not be part of the frame-parameters, since it
       
  1115   ;; should not appear or disappear depending on the color theme.  The
       
  1116   ;; apppearance of the toolbar, however, can be changed by the color
       
  1117   ;; theme.  For Emacs 21, use the `tool-bar' face.  The easiest way
       
  1118   ;; to do this is to give it the default fore- and background colors.
       
  1119   ;; This can be achieved using (tool-bar ((t (nil)))) in the theme.
       
  1120   ;; Usually it makes more sense, however, to provide the same colors
       
  1121   ;; as used in the `menu' face, and to specify a :box attribute.  In
       
  1122   ;; order to alleviate potential Emacs/XEmacs incompatibilities,
       
  1123   ;; `toolbar' will be defined as an alias for `tool-bar' if it does
       
  1124   ;; not exist, and vice-versa.  This is done eventhough the face
       
  1125   ;; `toolbar' seems to have no effect on XEmacs.  If you look at
       
  1126   ;; XEmacs lisp/faces.el, however, you will find that it is in fact
       
  1127   ;; referenced for XPM stuff.
       
  1128   (unless (assoc 'tool-bar faces)
       
  1129     (setq faces (cons '(tool-bar ((t (nil)))) faces)))
       
  1130   ;; Move the default face back to the front, and sort the rest.
       
  1131   (unless (eq (caar faces) 'default)
       
  1132     (let ((face (assoc 'default faces)))
       
  1133       (setq faces (cons face
       
  1134 			(sort (delete face faces)
       
  1135 			      (lambda (a b)
       
  1136 				(string-lessp (car a) (car b))))))))
       
  1137   faces)
       
  1138 
       
  1139 (defun color-theme-analyze-remove-heights (faces)
       
  1140   "Remove :height property where it is an integer and return FACES."
       
  1141   ;; I don't recommend making font sizes part of a color theme.  Most
       
  1142   ;; users would be surprised to see their font sizes change when they
       
  1143   ;; install a color-theme.  Therefore, remove all :height attributes
       
  1144   ;; if the value is an integer.  If the value is a float, this is ok
       
  1145   ;; -- the value is relative to the default height.  One notable
       
  1146   ;; exceptions is for a color-theme created for visually impaired
       
  1147   ;; people.  These *must* use a larger font in order to be usable.
       
  1148   (let (result)
       
  1149     (dolist (face faces)
       
  1150       (let ((props (cadar (nth 1 face))))
       
  1151 	(if (and (plist-member props :height)
       
  1152 		 (integerp (plist-get props :height)))
       
  1153 	    (setq props (color-theme-plist-delete props :height)
       
  1154 		  result (cons (list (car face) `((t ,props)))
       
  1155 			       result))
       
  1156 	  (setq result (cons face result)))))
       
  1157     (nreverse result)))
       
  1158 
       
  1159 ;; (equal (color-theme-analyze-remove-heights
       
  1160 ;; 	'((blue ((t (:foreground "blue" :height 2))))
       
  1161 ;; 	  (bold ((t (:bold t :height 1.0))))))
       
  1162 ;;        '((blue ((t (:foreground "blue"))))
       
  1163 ;; 	 (bold ((t (:bold t :height 1.0))))))
       
  1164 
       
  1165 ;;;###autoload
       
  1166 (defun color-theme-analyze-defun ()
       
  1167   "Once you have a color-theme printed, check for missing faces.
       
  1168 This is used by maintainers who receive a color-theme submission
       
  1169 and want to make sure it follows the guidelines by the color-theme
       
  1170 author."
       
  1171   ;; The support for :foreground and :background attributes works for
       
  1172   ;; Emacs 20 and 21 as well as for XEmacs.  :inverse-video is taken
       
  1173   ;; care of while printing color themes.
       
  1174   (interactive)
       
  1175   ;; Parse the stuff and find the call to color-theme-install
       
  1176   (save-excursion
       
  1177     (save-restriction
       
  1178       (narrow-to-defun)
       
  1179       ;; define the function
       
  1180       (eval-defun nil)
       
  1181       (goto-char (point-min))
       
  1182       (let* ((code (read (current-buffer)))
       
  1183 	     (theme (color-theme-canonic
       
  1184 		     (eval
       
  1185 		      (cadr
       
  1186 		       (color-theme-analyze-find-theme
       
  1187 			code)))))
       
  1188 	     (func (color-theme-function theme))
       
  1189 	     (doc (documentation func t))
       
  1190 	     (variables (color-theme-variables theme))
       
  1191 	     (faces (color-theme-faces theme))
       
  1192 	     (params (color-theme-frame-params theme)))
       
  1193 	(setq faces (color-theme-analyze-remove-heights
       
  1194 		     (color-theme-analyze-add-faces faces)))
       
  1195 	;; Remove any variable bindings of faces that point to their
       
  1196 	;; symbol?  Perhaps not, because another theme might want to
       
  1197 	;; change this, so it is important to be able to reset them.
       
  1198 	;; 	(let (result)
       
  1199 	;; 	  (dolist (var variables)
       
  1200 	;; 	    (unless (eq (car var) (cdr var))
       
  1201 	;; 	      (setq result (cons var result))))
       
  1202 	;; 	  (setq variables (nreverse result)))
       
  1203 	;; Now modify the theme directly.
       
  1204 	(setq theme (color-theme-analyze-find-theme code))
       
  1205 	(setcdr (cadadr theme) (list params variables faces))
       
  1206 	(message "Pretty printing analysed color theme function...")
       
  1207 	(with-current-buffer (get-buffer-create "*Color Theme*")
       
  1208 	  (setq buffer-read-only nil)
       
  1209 	  (erase-buffer)
       
  1210 	  ;; insert defun
       
  1211 	  (color-theme-print-theme func doc params variables faces)
       
  1212 	  (emacs-lisp-mode))
       
  1213 	(message "Pretty printing analysed color theme function... done")
       
  1214 	(ediff-buffers (current-buffer)
       
  1215 		       (get-buffer "*Color Theme*"))))))
       
  1216 
       
  1217 ;;; Creating a snapshot of the current color theme
       
  1218 
       
  1219 (defun color-theme-snapshot nil)
       
  1220 
       
  1221 ;;;###autoload
       
  1222 (defun color-theme-make-snapshot ()
       
  1223   "Return the definition of the current color-theme.
       
  1224 The function returned will recreate the color-theme in use at the moment."
       
  1225   (eval `(lambda ()
       
  1226 	   "The color theme in use when the selection buffer was created.
       
  1227 \\[color-theme-select] creates the color theme selection buffer.  At the
       
  1228 same time, this snapshot is created as a very simple undo mechanism.
       
  1229 The snapshot is created via `color-theme-snapshot'."
       
  1230 	   (interactive)
       
  1231 	   (color-theme-install
       
  1232 	    '(color-theme-snapshot
       
  1233 	      ;; alist of frame parameters
       
  1234 	      ,(color-theme-get-params)
       
  1235 	      ;; alist of variables
       
  1236 	      ,(color-theme-get-vars)
       
  1237 	      ;; remaining elements of snapshot: face specs
       
  1238 	      ,@(color-theme-get-face-definitions))))))
       
  1239 
       
  1240 
       
  1241 
       
  1242 ;;; Handling the various parts of a color theme install
       
  1243 
       
  1244 (defvar color-theme-frame-param-frobbing-rules
       
  1245   '((foreground-color default foreground)
       
  1246     (background-color default background))
       
  1247   "List of rules to use when frobbing faces based on frame parameters.
       
  1248 This is only necessary for XEmacs, because in Emacs 21 changing the
       
  1249 frame paramters automatically affects the relevant faces.")
       
  1250 
       
  1251 ;; fixme: silent the bytecompiler with set-face-property
       
  1252 (defun color-theme-frob-faces (params)
       
  1253   "Change certain faces according to PARAMS.
       
  1254 This uses `color-theme-frame-param-frobbing-rules'."
       
  1255   (dolist (rule color-theme-frame-param-frobbing-rules)
       
  1256     (let* ((param (nth 0 rule))
       
  1257 	   (face (nth 1 rule))
       
  1258 	   (prop (nth 2 rule))
       
  1259 	   (val (cdr (assq param params)))
       
  1260 	   (frame (if color-theme-is-global nil (selected-frame))))
       
  1261       (when val
       
  1262 	(set-face-property face prop val frame)))))
       
  1263 
       
  1264 (defun color-theme-alist-reduce (old-list)
       
  1265   "Reduce OLD-LIST.
       
  1266 The resulting list will be newly allocated and will not contain any elements
       
  1267 with duplicate cars.  This will speed the installation of new themes by
       
  1268 only installing unique attributes."
       
  1269   (let (new-list)
       
  1270     (dolist (elem old-list)
       
  1271       (when (not (assq (car elem) new-list))
       
  1272 	(setq new-list (cons elem new-list))))
       
  1273     new-list))
       
  1274 
       
  1275 (defun color-theme-install-frame-params (params)
       
  1276   "Change frame parameters using alist PARAMETERS.
       
  1277 
       
  1278 If `color-theme-is-global' is non-nil, all frames are modified using
       
  1279 `modify-frame-parameters' and the PARAMETERS are prepended to
       
  1280 `default-frame-alist'.  The value of `initial-frame-alist' is not
       
  1281 modified.  If `color-theme-is-global' is nil, only the selected frame is
       
  1282 modified.  If `color-theme-is-cumulative' is nil, the frame parameters
       
  1283 are restored from `color-theme-original-frame-alist'.
       
  1284 
       
  1285 If the current frame parameters have a parameter `minibuffer' with
       
  1286 value `only', then the frame parameters are not installed, since this
       
  1287 indicates a dedicated minibuffer frame.
       
  1288 
       
  1289 Called from `color-theme-install'."
       
  1290   (setq params (color-theme-filter
       
  1291 		params color-theme-legal-frame-parameters))
       
  1292   ;; We have a new list in params now, therefore we may use
       
  1293   ;; destructive nconc.
       
  1294   (if color-theme-is-global
       
  1295       (let ((frames (frame-list)))
       
  1296 	(if (or color-theme-is-cumulative
       
  1297 		(null color-theme-original-frame-alist))
       
  1298 	    (setq default-frame-alist
       
  1299 		  (append params (color-theme-alist default-frame-alist))
       
  1300 		  minibuffer-frame-alist
       
  1301 		  (append params (color-theme-alist minibuffer-frame-alist)))
       
  1302 	  (setq default-frame-alist
       
  1303 		(append params color-theme-original-frame-alist)
       
  1304 		minibuffer-frame-alist
       
  1305 		(append params (color-theme-alist minibuffer-frame-alist))))
       
  1306 	(setq default-frame-alist
       
  1307 	      (color-theme-alist-reduce default-frame-alist)
       
  1308 	      minibuffer-frame-alist
       
  1309 	      (color-theme-alist-reduce minibuffer-frame-alist))
       
  1310 	(dolist (frame frames)
       
  1311 	  (let ((params (if (eq 'only (cdr (assq 'minibuffer (frame-parameters frame))))
       
  1312 			    minibuffer-frame-alist
       
  1313 			  default-frame-alist)))
       
  1314 	    (condition-case var
       
  1315 		(modify-frame-parameters frame params)
       
  1316 	      (error (message "Error using params %S: %S" params var))))))
       
  1317     (condition-case var
       
  1318 	(modify-frame-parameters (selected-frame) params)
       
  1319       (error (message "Error using params %S: %S" params var))))
       
  1320   (when color-theme-xemacs-p
       
  1321     (color-theme-frob-faces params)))
       
  1322 
       
  1323 ;; (setq default-frame-alist (cons '(height . 30) default-frame-alist))
       
  1324 
       
  1325 (defun color-theme-install-variables (vars)
       
  1326   "Change variables using alist VARS.
       
  1327 All variables matching `color-theme-legal-variables' are set.
       
  1328 
       
  1329 If `color-theme-is-global' and `color-theme-xemacs-p' are nil, variables
       
  1330 are made frame-local before setting them.  Variables are set using `set'
       
  1331 in either case.  This may lead to problems if changing the variable
       
  1332 requires the usage of the function specified with the :set tag in
       
  1333 defcustom declarations.
       
  1334 
       
  1335 Called from `color-theme-install'."
       
  1336   (let ((vars (color-theme-filter vars color-theme-legal-variables)))
       
  1337     (dolist (var vars)
       
  1338       (if (or color-theme-is-global color-theme-xemacs-p)
       
  1339 	  (set (car var) (cdr var))
       
  1340 	(make-variable-frame-local (car var))
       
  1341 	(modify-frame-parameters (selected-frame) (list var))))))
       
  1342 
       
  1343 (defun color-theme-install-faces (faces)
       
  1344   "Change faces using FACES.
       
  1345 
       
  1346 Change faces for all frames and create any faces listed in FACES which
       
  1347 don't exist.  The modified faces will be marked as \"unchanged from
       
  1348 its standard setting\".  This is OK, since the changes made by
       
  1349 installing a color theme should never by saved in .emacs by
       
  1350 customization code.
       
  1351 
       
  1352 FACES should be a list where each entry has the form:
       
  1353 
       
  1354   (FACE SPEC)
       
  1355 
       
  1356 See `defface' for the format of SPEC.
       
  1357 
       
  1358 If `color-theme-is-global' is non-nil, faces are modified on all frames
       
  1359 using `face-spec-set'.  If `color-theme-is-global' is nil, faces are
       
  1360 only modified on the selected frame.  Non-existing faces are created
       
  1361 using `make-empty-face' in either case.  If `color-theme-is-cumulative'
       
  1362 is nil, all faces are reset before installing the new faces.
       
  1363 
       
  1364 Called from `color-theme-install'."
       
  1365   ;; clear all previous faces
       
  1366   (when (not color-theme-is-cumulative)
       
  1367     (color-theme-reset-faces))
       
  1368   ;; install new faces
       
  1369   (let ((faces (color-theme-filter faces color-theme-illegal-faces t))
       
  1370 	(frame (if color-theme-is-global nil (selected-frame))))
       
  1371     (dolist (entry faces)
       
  1372       (let ((face (nth 0 entry))
       
  1373 	    (spec (nth 1 entry)))
       
  1374 	(or (facep face)
       
  1375 	    (make-empty-face face))
       
  1376 	;; remove weird properties from the default face only
       
  1377 	(when (eq face 'default)
       
  1378 	  (setq spec (color-theme-spec-filter spec)))
       
  1379 	;; Emacs/XEmacs customization issues: filter out :bold when
       
  1380 	;; the spec contains :weight, etc, such that the spec remains
       
  1381 	;; "valid" for custom.
       
  1382 	(setq spec (color-theme-spec-compat spec))
       
  1383 	;; using a spec of ((t (nil))) to reset a face doesn't work
       
  1384 	;; in Emacs 21, we use the new function face-spec-reset-face
       
  1385 	;; instead
       
  1386 	(if (and (functionp 'face-spec-reset-face)
       
  1387 		 (equal spec '((t (nil)))))
       
  1388 	    (face-spec-reset-face face frame)
       
  1389 	  (condition-case var
       
  1390 	      (progn
       
  1391 		(face-spec-set face spec frame)
       
  1392 		(if color-theme-is-global
       
  1393 		    (put face 'face-defface-spec spec)))
       
  1394 	    (error (message "Error using spec %S: %S" spec var))))))))
       
  1395 
       
  1396 ;; `custom-set-faces' is unusable here because it doesn't allow to set
       
  1397 ;; the faces for one frame only.
       
  1398 
       
  1399 ;; Emacs `face-spec-set': If FRAME is nil, the face is created and
       
  1400 ;; marked as a customized face.  This is achieved by setting the
       
  1401 ;; `face-defface-spec' property.  If we don't, new frames will not be
       
  1402 ;; created using the face we installed because `face-spec-set' is
       
  1403 ;; broken: If given a FRAME of nil, it will not set the default faces;
       
  1404 ;; instead it will walk through all the frames and set modify the faces.
       
  1405 ;; If we do set a property (`saved-face' or `face-defface-spec'),
       
  1406 ;; `make-frame' will correctly use the faces we defined with our color
       
  1407 ;; theme.  If we used the property `saved-face',
       
  1408 ;; `customize-save-customized' will save all the faces installed as part
       
  1409 ;; of a color-theme in .emacs.  That's why we use the
       
  1410 ;; `face-defface-spec' property.
       
  1411 
       
  1412 
       
  1413 
       
  1414 ;;; Theme accessor functions, canonicalization, merging, comparing
       
  1415 
       
  1416 (defun color-theme-canonic (theme)
       
  1417   "Return the canonic form of THEME.
       
  1418 This deals with all the backwards compatibility stuff."
       
  1419   (let (function frame-params variables faces)
       
  1420     (when (functionp (car theme))
       
  1421       (setq function (car theme)
       
  1422 	    theme (cdr theme)))
       
  1423     (setq frame-params (car theme)
       
  1424 	  theme (cdr theme))
       
  1425     ;; optional variable defintions (for backwards compatibility)
       
  1426     (when (listp (caar theme))
       
  1427       (setq variables (car theme)
       
  1428 	    theme (cdr theme)))
       
  1429     ;; face definitions
       
  1430     (setq faces theme)
       
  1431     (list function frame-params variables faces)))
       
  1432 
       
  1433 (defun color-theme-function (theme)
       
  1434   "Return function used to create THEME."
       
  1435   (nth 0 theme))
       
  1436 
       
  1437 (defun color-theme-frame-params (theme)
       
  1438   "Return frame-parameters defined by THEME."
       
  1439   (nth 1 theme))
       
  1440 
       
  1441 (defun color-theme-variables (theme)
       
  1442   "Return variables set by THEME."
       
  1443   (nth 2 theme))
       
  1444 
       
  1445 (defun color-theme-faces (theme)
       
  1446   "Return faces defined by THEME."
       
  1447   (nth 3 theme))
       
  1448 
       
  1449 (defun color-theme-merge-alists (&rest alists)
       
  1450   "Merges all the alist arguments into one alist.
       
  1451 Only the first instance of every key will be part of the resulting
       
  1452 alist.  Membership will be tested using `assq'."
       
  1453   (let (result)
       
  1454     (dolist (l alists)
       
  1455       (dolist (entry l)
       
  1456 	(unless (assq (car entry) result)
       
  1457 	  (setq result (cons entry result)))))
       
  1458     (nreverse result)))
       
  1459 ;; (color-theme-merge-alists '((a . 1) (b . 2)))
       
  1460 ;; (color-theme-merge-alists '((a . 1) (b . 2) (a . 3)))
       
  1461 ;; (color-theme-merge-alists '((a . 1) (b . 2)) '((a . 3)))
       
  1462 ;; (color-theme-merge-alists '((a . 1) (b . 2)) '((c . 3)))
       
  1463 ;; (color-theme-merge-alists '((a . 1) (b . 2)) '((c . 3) (d . 4)))
       
  1464 ;; (color-theme-merge-alists '((a . 1) (b . 2)) '((c . 3) (d . 4) (b . 5)))
       
  1465 
       
  1466 ;;;###autoload
       
  1467 (defun color-theme-compare (theme-a theme-b)
       
  1468   "Compare two color themes.
       
  1469 This will print the differences between installing THEME-A and
       
  1470 installing THEME-B.  Note that the order is important: If a face is
       
  1471 defined in THEME-A and not in THEME-B, then this will not show up as a
       
  1472 difference, because there is no reset before installing THEME-B.  If a
       
  1473 face is defined in THEME-B and not in THEME-A, then this will show up as
       
  1474 a difference."
       
  1475   (interactive
       
  1476    (list
       
  1477     (intern
       
  1478      (completing-read "Theme A: "
       
  1479 		      (mapcar (lambda (i) (list (symbol-name (car i))))
       
  1480 			      color-themes)
       
  1481 		      (lambda (i) (string-match "color-theme" (car i)))))
       
  1482     (intern
       
  1483      (completing-read "Theme B: "
       
  1484 		      (mapcar (lambda (i) (list (symbol-name (car i))))
       
  1485 			      color-themes)
       
  1486 		      (lambda (i) (string-match "color-theme" (car i)))))))
       
  1487   ;; install the themes in a new frame and get the definitions
       
  1488   (let ((color-theme-is-global nil))
       
  1489     (select-frame (make-frame))
       
  1490     (funcall theme-a)
       
  1491     (setq theme-a (list theme-a
       
  1492 			(color-theme-get-params)
       
  1493 			(color-theme-get-vars)
       
  1494 			(color-theme-get-face-definitions)))
       
  1495     (funcall theme-b)
       
  1496     (setq theme-b (list theme-b
       
  1497 			(color-theme-get-params)
       
  1498 			(color-theme-get-vars)
       
  1499 			(color-theme-get-face-definitions)))
       
  1500     (delete-frame))
       
  1501   (let ((params (set-difference
       
  1502 		 (color-theme-frame-params theme-b)
       
  1503 		 (color-theme-frame-params theme-a)
       
  1504 		 :test 'equal))
       
  1505 	(vars (set-difference
       
  1506 	       (color-theme-variables theme-b)
       
  1507 	       (color-theme-variables theme-a)
       
  1508 	       :test 'equal))
       
  1509 	(faces (set-difference
       
  1510 		(color-theme-faces theme-b)
       
  1511 		(color-theme-faces theme-a)
       
  1512 		:test 'equal)))
       
  1513     (list 'diff
       
  1514 	  params
       
  1515 	  vars
       
  1516 	  faces)))
       
  1517 
       
  1518 
       
  1519 
       
  1520 ;;; Installing a color theme
       
  1521 ;;;###autoload
       
  1522 (defun color-theme-install (theme)
       
  1523   "Install a color theme defined by frame parameters, variables and faces.
       
  1524 
       
  1525 The theme is installed for all present and future frames; any missing
       
  1526 faces are created.  See `color-theme-install-faces'.
       
  1527 
       
  1528 THEME is a color theme definition.  See below for more information.
       
  1529 
       
  1530 If you want to install a color theme from your .emacs, use the output
       
  1531 generated by `color-theme-print'.  This produces color theme function
       
  1532 which you can copy to your .emacs.
       
  1533 
       
  1534 A color theme definition is a list:
       
  1535 \([FUNCTION] FRAME-PARAMETERS VARIABLE-SETTINGS FACE-DEFINITIONS)
       
  1536 
       
  1537 FUNCTION is the color theme function which called `color-theme-install'.
       
  1538 This is no longer used.  There was a time when this package supported
       
  1539 automatic factoring of color themes.  This has been abandoned.
       
  1540 
       
  1541 FRAME-PARAMETERS is an alist of frame parameters.  These are installed
       
  1542 with `color-theme-install-frame-params'.  These are installed last such
       
  1543 that any changes to the default face can be changed by the frame
       
  1544 parameters.
       
  1545 
       
  1546 VARIABLE-DEFINITIONS is an alist of variable settings.  These are
       
  1547 installed with `color-theme-install-variables'.
       
  1548 
       
  1549 FACE-DEFINITIONS is an alist of face definitions.  These are installed
       
  1550 with `color-theme-install-faces'.
       
  1551 
       
  1552 If `color-theme-is-cumulative' is nil, a color theme will undo face and
       
  1553 frame-parameter settings of previous color themes."
       
  1554   (setq theme (color-theme-canonic theme))
       
  1555   (color-theme-install-variables (color-theme-variables theme))
       
  1556   (color-theme-install-faces (color-theme-faces theme))
       
  1557   ;; frame parameters override faces
       
  1558   (color-theme-install-frame-params (color-theme-frame-params theme))
       
  1559   (when color-theme-history-max-length
       
  1560     (color-theme-add-to-history
       
  1561      (car theme))))
       
  1562 
       
  1563 
       
  1564 
       
  1565 ;; Sharing your stuff
       
  1566 ;;;###autoload
       
  1567 (defun color-theme-submit ()
       
  1568   "Submit your color-theme to the maintainer."
       
  1569   (interactive)
       
  1570   (require 'reporter)
       
  1571   (let ((reporter-eval-buffer (current-buffer))
       
  1572 	final-resting-place
       
  1573 	after-sep-pos
       
  1574 	(reporter-status-message "Formatting buffer...")
       
  1575 	(reporter-status-count 0)
       
  1576 	(problem "Yet another color-theme")
       
  1577 	(agent (reporter-compose-outgoing))
       
  1578 	(mailbuf (current-buffer))
       
  1579 	hookvar)
       
  1580     ;; do the work
       
  1581     (require 'sendmail)
       
  1582     ;; If mailbuf did not get made visible before, make it visible now.
       
  1583     (let (same-window-buffer-names same-window-regexps)
       
  1584       (pop-to-buffer mailbuf)
       
  1585       ;; Just in case the original buffer is not visible now, bring it
       
  1586       ;; back somewhere
       
  1587       (and pop-up-windows (display-buffer reporter-eval-buffer)))
       
  1588     (goto-char (point-min))
       
  1589     (mail-position-on-field "to")
       
  1590     (insert color-theme-maintainer-address)
       
  1591     (mail-position-on-field "subject")
       
  1592     (insert problem)
       
  1593     ;; move point to the body of the message
       
  1594     (mail-text)
       
  1595     (setq after-sep-pos (point))
       
  1596     (unwind-protect
       
  1597 	(progn
       
  1598 	  (setq final-resting-place (point-marker))
       
  1599 	  (goto-char final-resting-place))
       
  1600       (color-theme-print (current-buffer))
       
  1601       (goto-char final-resting-place)
       
  1602       (insert "\n\n")
       
  1603       (goto-char final-resting-place)
       
  1604       (insert "Hello there!\n\nHere's my color theme named: ")
       
  1605       (set-marker final-resting-place nil))
       
  1606     ;; compose the minibuf message and display this.
       
  1607     (let* ((sendkey-whereis (where-is-internal
       
  1608 			     (get agent 'sendfunc) nil t))
       
  1609 	   (abortkey-whereis (where-is-internal
       
  1610 			      (get agent 'abortfunc) nil t))
       
  1611 	   (sendkey (if sendkey-whereis
       
  1612 			(key-description sendkey-whereis)
       
  1613 		      "C-c C-c")); TBD: BOGUS hardcode
       
  1614 	   (abortkey (if abortkey-whereis
       
  1615 			 (key-description abortkey-whereis)
       
  1616 		       "M-x kill-buffer"))); TBD: BOGUS hardcode
       
  1617       (message "Enter a message and type %s to send or %s to abort."
       
  1618 	       sendkey abortkey))))
       
  1619 
       
  1620 
       
  1621 
       
  1622 ;; Use this to define themes
       
  1623 (defmacro define-color-theme (name author description &rest forms)
       
  1624   (let ((n name))
       
  1625     `(progn 
       
  1626        (add-to-list 'color-themes
       
  1627                     (list ',n
       
  1628                           (upcase-initials
       
  1629                            (replace-in-string
       
  1630                             (replace-in-string 
       
  1631                              (symbol-name ',n) "^color-theme-" "") "-" " "))
       
  1632                           ,author))
       
  1633        (defun ,n ()
       
  1634 	 ,description
       
  1635 	 (interactive)
       
  1636          ,@forms))))
       
  1637 
       
  1638 
       
  1639 ;;; FIXME: is this useful ??
       
  1640 ;;;###autoload
       
  1641 (defun color-theme-initialize ()
       
  1642   "Initialize the color theme package by loading color-theme-libraries."
       
  1643   (interactive)
       
  1644 
       
  1645   (cond ((and (not color-theme-load-all-themes)
       
  1646               color-theme-directory)
       
  1647          (setq color-theme-libraries 
       
  1648                (directory-files color-theme-directory t "^color-theme")))
       
  1649         (color-theme-directory
       
  1650          (push (cdr (directory-files color-theme-directory t "^color-theme")) 
       
  1651                color-theme-libraries)))
       
  1652   (dolist (library color-theme-libraries)
       
  1653     (load library)))
       
  1654 
       
  1655 (when nil
       
  1656   (setq color-theme-directory "themes/"
       
  1657         color-theme-load-all-themes nil)
       
  1658   (color-theme-initialize)
       
  1659 )
       
  1660 ;; TODO: I don't like all those function names cluttering up my namespace.
       
  1661 ;; Instead, a hashtable for the color-themes should be created. Now that 
       
  1662 ;; define-color-theme is around, it should be easy to change in just the
       
  1663 ;; one place. 
       
  1664 
       
  1665 
       
  1666 (provide 'color-theme)
       
  1667 
       
  1668 ;;; color-theme.el ends here