Initial Commit
[packages] / xemacs-packages / time / time.el
1 ;;; time.el --- display time and load in mode line of Emacs.
2
3 ;; Copyright (C) 1985, 86, 87, 93, 94, 1996 Free Software Foundation, Inc.
4
5 ;; Maintainer: FSF for the original version. 
6 ;;             XEmacs add-ons and rewrite (C) by Jens Lautenbacher
7 ;;                            mail <jens@lemming0.lem.uni-karlsruhe.de>
8 ;;                            for comments/fixes about the enhancements.
9
10 ;; This file is part of XEmacs.
11
12 ;; XEmacs is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; XEmacs is distributed in the hope that it will be useful, but
18 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with XEmacs; see the file COPYING.  If not, write to the Free
24 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 ;; 02111-1307, USA.
26
27 ;;; Version: 1.17  (I choose the version number starting at 1.1
28 ;;;                to indicate that 1.0 was the old version
29 ;;;                before I hacked away on it -jtl)
30
31 ;;; Synched up with: Not synched with FSF.
32
33 ;;; Commentary:
34
35 ;; Facilities to display current time/date and a new-mail indicator
36 ;; in the Emacs mode line.  The single entry point is `display-time'.
37
38 ;; See also reportmail.el.
39 ;; This uses the XEmacs timeout-event mechanism, via a version
40 ;; of Kyle Jones' itimer package.
41
42 ;;; jtl: This is in a wide part reworked for XEmacs so it won't use
43 ;;;      the old mechanism for specifying what is to be displayed.
44 ;;;      The starting variable to look at is `display-time-form-list'
45
46 ;;; It's more advanced features include heavy use of `balloon-help' a
47 ;;; package again written by Kyle Jones. You need to load this
48 ;;; explicitly on your own because I don't think a package should make
49 ;;; decisions which have a global effect (if you want to use it, a
50 ;;; (require 'balloon-help) in your .emacs should work. But look at the
51 ;;; documentation in balloon-help.el itself).
52
53 ;;; Thanks to Mike Scheidler for the idea to make the time led's fore- and
54 ;;; background color customizable
55
56 ;;; Code:
57
58 (require 'itimer)
59 ;;; Not sure for now...
60 ;;;(require 'balloon-help)
61
62 (defconst display-time-version-number "1.15" "Version number of time.el")
63 (defconst display-time-version (format "Time.el version %s for XEmacs"
64                                        display-time-version-number)
65   "The full version string for time.el")
66
67 ;;; Doesn't work by now....
68 ;;;(defvar display-time-keymap nil)
69 ;;;
70 ;;;(if display-time-keymap ()
71 ;;;  (setq display-time-keymap (make-sparse-keymap)) 
72 ;;;  (suppress-keymap display-time-keymap)
73 ;;;  (define-key display-time-keymap 'button1 'balloon-help))
74
75 (defgroup display-time nil
76   "Facilities to display the current time/date/load and a new-mail indicator
77 in the XEmacs mode line or echo area."
78   :group 'applications)
79
80 (defgroup display-time-balloon nil
81   "Fancy add-ons to display-time for using the `balloon-help' feature.
82 balloon-help must be loaded before these settings take effect."
83   :group 'display-time)
84
85
86 (defcustom display-time-mail-file nil
87   "*File name of mail inbox file, for indicating existence of new mail.
88 Non-nil and not a string means don't check for mail.  nil means use
89 default, which is system-dependent, and is the same as used by Rmail."
90   :group 'display-time)
91
92 ;;;###autoload
93 (defcustom display-time-day-and-date nil
94   "*Non-nil means \\[display-time] should display day,date and time.
95 This affects the spec 'date in the variable display-time-form-list."
96   :group 'display-time
97   :type 'boolean)
98
99 (defcustom display-time-interval 20
100   "*Seconds between updates of time in the mode line."
101   :group 'display-time
102   :type 'integer)
103
104 (defcustom display-time-24hr-format nil
105   "*Non-nil indicates time should be displayed as hh:mm, 0 <= hh <= 23.
106 Nil means 1 <= hh <= 12, and an AM/PM suffix is used.
107 This affects the spec 'time in the variable display-time-form-list."
108   :group 'display-time
109   :type 'boolean)
110
111 (defcustom display-time-echo-area nil
112   "*If non-nil, display-time will use the echo area instead of the mode line."
113   :group 'display-time
114   :type 'boolean)
115
116 (defvar display-time-string nil)
117
118 (defcustom display-time-hook nil
119   "*List of functions to be called when the time is updated on the mode line."
120   :group 'display-time
121   :type 'hook)
122
123 (defvar display-time-server-down-time nil
124    "Time when mail file's file system was recorded to be down.
125 If that file system seems to be up, the value is nil.")
126
127 (defcustom display-time-ignore-read-mail t
128   "*Non-nil means display the mail icon on any non-empty mailbox."
129   :group 'display-time
130   :type 'boolean)
131
132 ;;;###autoload
133 (defun display-time ()
134   "Display current time, load level, and mail flag in mode line of each buffer.
135 Updates automatically every minute.
136 If `display-time-day-and-date' is non-nil, the current day and date
137 are displayed as well.
138 After each update, `display-time-hook' is run with `run-hooks'.
139 If `display-time-echo-area' is non-nil, the time is displayed in the
140 echo area instead of in the mode-line."
141   (interactive)
142   (or display-time-insinuated
143       (display-time-insinuate))
144   ;; if the "display-time" itimer already exists, nuke it first.
145   (let ((old (get-itimer "display-time")))
146     (if old (delete-itimer old)))
147
148   (if (memq 'display-time-string global-mode-string)
149       (setq global-mode-string
150             (remove 'display-time-string global-mode-string)))
151   ;; If we're not displaying the time in the echo area
152   ;; and the global mode string does not have a non-nil value
153   ;; then initialize the global mode string's value.
154   (or display-time-echo-area
155       global-mode-string
156       (setq global-mode-string '("")))
157   ;; If we're not displaying the time in the echo area
158   ;; then we add our variable to the list.  This will make the time
159   ;; appear on the modeline.
160   (or display-time-echo-area
161       (setq global-mode-string
162                 (append global-mode-string '(display-time-string))))
163   ;; Display the time initially...
164   (display-time-function)
165   ;; ... and start an itimer to do it automatically thereafter.
166   ;;
167   ;; If we wanted to be really clever about this, we could have the itimer
168   ;; not be automatically restarted, but have it re-add itself each time.
169   ;; Then we could look at (current-time) and arrange for the itimer to
170   ;; wake up exactly at the minute boundary.  But that's just a little
171   ;; more work than it's worth...
172   (start-itimer "display-time" 'display-time-function
173                 display-time-interval display-time-interval))
174
175 (defun display-time-stop ()
176   (interactive)
177   (delete-itimer "display-time")
178   (setq display-time-string nil))
179
180 (defcustom display-time-show-icons-maybe t
181   "Use icons for time, load and mail status if possible
182 and not specified different explicitly"
183   :group 'display-time
184   :type 'boolean)  
185
186 (defvar display-time-icons-dir (locate-data-directory "time"))
187
188 (defcustom display-time-mail-sign-string " Mail" 
189   "The string used as mail indicator in the echo area 
190 (and in the modeline if display-time-show-icons-maybe is nil)
191 if display-time-echo-area is t"
192 :group 'display-time
193 :type 'string)
194
195 (defcustom display-time-no-mail-sign-string ""
196   "The string used as no-mail indicator in the echo area
197 (and in the modeline if display-time-show-icons-maybe is nil)
198 if display-time-echo-area is t"
199 :group 'display-time
200 :type 'string)
201
202 (defcustom display-time-display-pad  "grey35"
203   "How the load indicator's trapezoidal \"pad\" is to be displayed.
204 This can be 'transparent or a string describing the color it should have"
205   :group 'display-time
206   :type '(choice :tag "Value"
207                  (const transparent)
208                  (string :tag "Color")))
209
210 (defcustom display-time-display-time-foreground  "firebrick"
211   "How the time LEDs foreground is to be displayed.
212 This can be 'modeline (foreground color of the Modeline)
213 or a string describing the color it should have"
214   :group 'display-time
215   :type '(choice :tag "Value"
216                  (const modeline)
217                  (string :tag "Color")))
218
219 (defcustom display-time-display-time-background  'transparent
220   "How the time LEDs background is to be displayed.
221 This can be 'transparent or a string describing the color it should have"
222   :group 'display-time
223   :type '(choice :tag "Value"
224                  (const transparent)
225                  (string :tag "Color")))
226
227 (defcustom display-time-mail-balloon 'display-time-mail-balloon
228   "What to use to generate the balloon frame of the \"mail\" glyph
229 if balloon-help is loaded. This can be the function
230 display-time-mail-balloon, nil or a string."
231   :group 'display-time-balloon 
232   :type '(choice (const display-time-mail-balloon)
233                  (const nil)
234                  (string)))
235
236 (defcustom display-time-no-mail-balloon "No mail is good mail."
237   "The string used in the balloon frame of the \"no mail\" glyph
238 if balloon-help is loaded. This can also be nil"
239   :group 'display-time-balloon
240   :type '(choice (const nil)
241                  (string)))
242
243 (defcustom display-time-mail-balloon-show-gnus-group nil
244   "Show the mail group gnus would put this message in.
245 This is only useful if you use gnus to read your mail and have set the variable
246 nnmail-split-methods to split your incoming mail into different groups.
247 Look at the documentation for gnus. If you don't know what we're talking about,
248 don't care and leave this set to nil"
249   :group 'display-time-balloon
250   :type 'boolean)
251
252 (defface display-time-mail-balloon-enhance-face '((t (:background  "orange")))
253   "Face used for entries in the mail balloon which match the regexp
254 display-time-mail-balloon-enhance"
255   :group 'display-time-balloon)
256
257 (defface display-time-time-balloon-face '((t (:foreground  "red")))
258   "Face used in the time balloon to display the full date and load.
259 It is also used in the mail balloon for the \"You have mail:\" heading."
260   :group 'display-time-balloon) 
261
262 (defface display-time-mail-balloon-gnus-group-face '((t (:foreground "blue")))
263   "Face used for the gnus group entry in the mail balloon
264 if display-time-mail-balloon-show-gnus-group is t (see the documentation there
265 before you set it to t)"
266   :group 'display-time-balloon)
267
268 (defcustom display-time-mail-balloon-max-displayed 10
269   "The maximum number of messaged which are displayed in the mail balloon.
270 You need to have balloon-help loaded to use this."
271   :group 'display-time-balloon
272   :type 'number)
273
274 (defcustom display-time-mail-balloon-from-width 20
275   "The width of the `From:' part of the mail balloon.
276 You need to have balloon-help loaded to use this"
277   :group 'display-time-balloon
278   :type 'number)
279
280 (defcustom display-time-mail-balloon-subject-width 25
281   "The width of the `Subject:' part of the mail balloon.
282 You need to have balloon-help loaded to use this"
283   :group 'display-time-balloon
284   :type 'number)
285
286 (defcustom display-time-mail-balloon-gnus-split-width 10
287   "The width of the `Gnus Mail Group' part of the mail balloon.
288 This denotes the mail group gnus would decide to put this message in.
289 For getting this information, it consults the relevant variables from gnus
290 (nnmail-split-methods).
291 You need to have balloon-help loaded to use this"
292   :group 'display-time-balloon
293   :type 'number)
294
295 (defcustom display-time-mail-balloon-enhance nil
296   "A list of regular expressions describing which messages should be highlighted
297 in the mail balloon. The regexp will be matched against the complete header block
298 of an email. You need to load balloon-help to use this"
299   :group 'display-time-balloon
300   :type '(repeat (string :tag "Regexp")))
301
302 (defcustom display-time-mail-balloon-suppress nil
303   "A list of regular expressions describing which messages should be completely suppressed
304 in the mail balloon. The regexp will be matched against the complete header block
305 of an email. It will only take effect if the message is not matched already
306 by display-time-mail-balloon-enhance.
307 You need to load balloon-help to use this"
308   :group 'display-time-balloon
309   :type '(repeat (string :tag "Regexp")))
310
311 (defcustom display-time-mail-balloon-enhance-gnus-group nil
312   "A list of regular expressions describing which messages should be highlighted
313 in the mail balloon. The regexp will be matched against the group gnus would stuff
314 this message into. It will only take effect if the message is not matched already
315 by display-time-mail-balloon-suppress.
316
317 This requires display-time-mail-balloon-show-gnus-group to be t
318 and balloon-help to be loaded"
319   :group 'display-time-balloon
320   :type '(repeat (string :tag "Regexp")))
321
322 (defcustom display-time-mail-balloon-suppress-gnus-group nil
323   "A list of regular expressions describing which messages should be completely suppressed
324 in the mail balloon. The regexp will be matched against the group gnus would stuff
325 this message into. It will only take effect if the message is not matched already
326 by display-time-mail-balloon-enhance or display-time-mail-balloon-enhance-gnus-group.
327
328 This requires display-time-mail-balloon-show-gnus-group to be t
329 and balloon-help to be loaded"
330   :group 'display-time-balloon
331   :type '(repeat (string :tag "Regexp")))
332
333 (defvar display-time-spool-file-modification nil)
334
335 (defvar display-time-mail-header nil)
336
337 (defvar display-time-temp-buffer " *Display-time-temp-buffer*")
338
339 (defvar display-time-display-pad-old nil)
340
341 (defvar display-time-display-time-fg-old nil)
342
343 (defvar display-time-display-time-bg-old nil)
344
345 (defcustom display-time-load-list
346   (list 0.2 0.5 0.8 1.1 1.8 2.6)
347   "*A list giving six thresholds for the load
348 which correspond to the six different icons to be displayed
349 as a load indicator"
350   :group 'display-time
351   :type '(list (number :tag "Threshold 1")
352                (number :tag "Threshold 2")
353                (number :tag "Threshold 3")
354                (number :tag "Threshold 4")
355                (number :tag "Threshold 5")
356                (number :tag "Threshold 6")))
357
358 (defcustom display-time-compatible nil 
359   "*This variable may be set to t to get the old behaviour of display-time.
360 It should be considered obsolete and only be used if you really want the
361 old behaviour (eq. you made extensive customizations yourself).
362 This means no display of a spiffy mail icon or use of the
363 display-time-form-list instead of the old display-time-string-form."
364   :group 'display-time
365   :type 'boolean)
366
367 (defun display-time-string-to-char-list (str)
368   (mapcar (function identity) str))
369
370 (defun display-time-generate-load-glyphs (&optional force)
371   (let* ((pad-color (if (symbolp display-time-display-pad)
372                         (list "pad-color" '(face-background 'modeline))
373                       (list "pad-color" display-time-display-pad)))
374          (xpm-color-symbols (append (list pad-color) xpm-color-symbols)))
375     (if (and (featurep 'xpm)
376              (or force (not (equal display-time-display-pad
377                                    display-time-display-pad-old))))
378         (progn
379           (setq display-time-load-0.0-glyph
380                 (cons (make-extent nil nil)
381                       (make-glyph
382                        (concat display-time-icons-dir "l-0.0.xpm"))))
383           (setq display-time-load-0.5-glyph
384                 (cons (make-extent nil nil)
385                       (make-glyph
386                        (concat display-time-icons-dir "l-0.5.xpm"))))
387           (setq display-time-load-1.0-glyph
388                 (cons (make-extent nil nil)
389                       (make-glyph
390                        (concat display-time-icons-dir "l-1.0.xpm"))))
391           (setq display-time-load-1.5-glyph
392                 (cons (make-extent nil nil)
393                       (make-glyph
394                        (concat display-time-icons-dir "l-1.5.xpm"))))
395           (setq display-time-load-2.0-glyph
396                 (cons (make-extent nil nil)
397                       (make-glyph
398                        (concat display-time-icons-dir "l-2.0.xpm"))))
399           (setq display-time-load-2.5-glyph
400                 (cons (make-extent nil nil)
401                       (make-glyph
402                        (concat display-time-icons-dir "l-2.5.xpm"))))
403           (setq display-time-load-3.0-glyph
404           (cons (make-extent nil nil)
405                 (make-glyph
406                  (concat display-time-icons-dir "l-3.0.xpm"))))
407           (setq display-time-display-pad-old display-time-display-pad)
408           ))))
409
410
411 (defun display-time-generate-time-glyphs (&optional force)
412   (let* ((ledbg (if (symbolp display-time-display-time-background)
413                     (list "ledbg" '(face-background 'modeline))
414                   (list "ledbg" display-time-display-time-background)))
415          (ledfg (if (symbolp display-time-display-time-foreground)
416                     (list "ledfg" '(face-foreground 'modeline))
417                   (list "ledfg" display-time-display-time-foreground)))
418          (xpm-color-symbols (append (list ledbg)
419                                     (list ledfg) xpm-color-symbols)))
420     (if (and (featurep 'xpm)
421              (or force (not (equal display-time-display-time-background
422                                    display-time-display-time-bg-old))
423                  (not (equal display-time-display-time-foreground
424                              display-time-display-time-fg-old))))
425         (progn
426           (setq display-time-1-glyph 
427                 (cons (make-extent nil nil) 
428                       (make-glyph (concat display-time-icons-dir "1.xpm"))))
429           (setq display-time-2-glyph
430                 (cons (make-extent nil nil)
431                       (make-glyph (concat display-time-icons-dir "2.xpm"))))
432           (setq display-time-3-glyph
433                 (cons (make-extent nil nil)
434                       (make-glyph (concat display-time-icons-dir "3.xpm"))))
435           (setq display-time-4-glyph
436                 (cons (make-extent nil nil)
437                       (make-glyph (concat display-time-icons-dir "4.xpm"))))
438           (setq display-time-5-glyph
439                 (cons (make-extent nil nil)
440                       (make-glyph (concat display-time-icons-dir "5.xpm"))))
441           (setq display-time-6-glyph
442                 (cons (make-extent nil nil)
443                       (make-glyph (concat display-time-icons-dir "6.xpm"))))
444           (setq display-time-7-glyph
445                 (cons (make-extent nil nil)
446                       (make-glyph (concat display-time-icons-dir "7.xpm"))))
447           (setq display-time-8-glyph
448                 (cons (make-extent nil nil)
449                       (make-glyph (concat display-time-icons-dir "8.xpm"))))
450           (setq display-time-9-glyph
451                 (cons (make-extent nil nil)
452                       (make-glyph (concat display-time-icons-dir "9.xpm"))))
453           (setq display-time-0-glyph
454                 (cons (make-extent nil nil)
455                       (make-glyph (concat display-time-icons-dir "0.xpm"))))
456           (setq display-time-:-glyph
457                 (cons (make-extent nil nil)
458                       (make-glyph (concat display-time-icons-dir "dp.xpm"))))
459           (setq display-time-am-glyph
460                 (cons (make-extent nil nil)
461                       (make-glyph (concat display-time-icons-dir "am.xpm"))))
462           (setq display-time-pm-glyph
463                 (cons (make-extent nil nil)
464                       (make-glyph (concat display-time-icons-dir "pm.xpm"))))
465           (setq display-time-display-time-fg-old
466                 display-time-display-time-foreground
467                 display-time-display-time-bg-old
468                 display-time-display-time-background)
469           ))))
470
471 (defun display-time-init-glyphs ()
472   "This is a hack to have all glyphs be displayed one time at startup.
473 It helps avoiding problems with the background color of the glyphs if a
474 balloon-help frame is open and a not yet displayed glyph is going to be
475 displayed."
476   (let ((i 0)
477         (list '("am" "pm" ":"))
478         elem mlist)
479     (while (< i 10)
480       (push (eval (intern-soft (concat "display-time-"
481                                        (number-to-string i)
482                                        "-glyph"))) mlist)
483       (setq i (1+ i)))
484     (setq i 0.0)
485     (while (<= i 3.0)
486       (push (eval (intern-soft (concat "display-time-load-"
487                                        (number-to-string i)
488                                        "-glyph"))) mlist)
489       (setq i (+ i 0.5)))
490     (while (setq elem (pop list))
491       (push (eval (intern-soft (concat "display-time-"
492                                        elem "-glyph"))) mlist))
493     (let ((global-mode-string mlist))
494       (redisplay-frame))
495     ))
496
497 (defvar display-time-insinuated nil)
498
499 ;; This used to be at top-level!
500 (defun display-time-insinuate ()
501   (when (featurep 'xpm)
502     (defvar display-time-mail-sign
503       (cons (make-extent nil nil)
504             (make-glyph  (concat display-time-icons-dir "letter.xpm"))))
505     (set-extent-property (car display-time-mail-sign) 'balloon-help
506                          'display-time-mail-balloon)
507 ;;;      (set-extent-keymap (car display-time-mail-sign)
508 ;;;                         display-time-keymap)
509     (defvar display-time-no-mail-sign
510       (cons (make-extent nil nil)
511             (make-glyph  (concat display-time-icons-dir "no-letter.xpm"))))
512     (set-extent-property (car display-time-no-mail-sign) 'balloon-help
513                          display-time-no-mail-balloon)
514 ;;;      (set-extent-keymap (car display-time-no-mail-sign)
515 ;;;                         display-time-keymap)
516     (defvar display-time-1-glyph  nil)
517     (defvar display-time-2-glyph  nil)
518     (defvar display-time-3-glyph  nil)
519     (defvar display-time-4-glyph  nil)
520     (defvar display-time-5-glyph  nil)
521     (defvar display-time-6-glyph  nil)
522     (defvar display-time-7-glyph  nil)
523     (defvar display-time-8-glyph  nil)
524     (defvar display-time-9-glyph  nil)
525     (defvar display-time-0-glyph  nil)
526     (defvar display-time-:-glyph  nil)
527     (defvar display-time-am-glyph nil)
528     (defvar display-time-pm-glyph nil)
529     (defvar display-time-load-0.0-glyph nil)
530     (defvar display-time-load-0.5-glyph nil)
531     (defvar display-time-load-1.0-glyph nil)
532     (defvar display-time-load-1.5-glyph nil)
533     (defvar display-time-load-2.0-glyph nil)
534     (defvar display-time-load-2.5-glyph nil)
535     (defvar display-time-load-3.0-glyph nil)
536     (display-time-generate-time-glyphs 'force)
537     (display-time-generate-load-glyphs 'force)  
538     (display-time-init-glyphs)
539     (sit-for 0))
540   (setq display-time-insinuated t))
541
542
543 (defun display-time-can-do-graphical-display (&optional textual)
544   (and display-time-show-icons-maybe
545        (not textual)
546        (console-on-window-system-p)
547        (featurep 'xpm)
548        (not display-time-echo-area)))
549        
550        
551 (defun display-time-convert-num (time-string &optional textual)
552   (let ((list (display-time-string-to-char-list time-string))
553         elem tmp balloon-help balloon-ext)
554     (if (not (display-time-can-do-graphical-display textual)) time-string 
555       (display-time-generate-time-glyphs)
556       (setq balloon-help
557             (format "%s, %s %s %s %s" dayname day monthname year
558                     (concat "   Average load:"
559                             (if (not (equal load ""))
560                                 load
561                               " 0"))))
562       (setq balloon-ext (make-extent 0 (length balloon-help) balloon-help))
563       (set-extent-property balloon-ext 'face 'display-time-time-balloon-face)
564       (set-extent-property balloon-ext 'duplicable 't)
565       (while (setq elem (pop list))
566         (setq elem
567               (eval (intern-soft (concat "display-time-"
568                                          (char-to-string elem)
569                                          "-glyph"))))
570         (set-extent-property (car elem) 'balloon-help balloon-help)
571         (set-extent-property (car elem) 'help-echo 
572                              (format "%s, %s %s %s"
573                                      dayname day monthname year))
574 ;;;     (set-extent-keymap (car elem) display-time-keymap)
575         (push elem tmp))
576       (reverse tmp))))
577
578 (defun display-time-convert-load (load-string &optional textual)
579   (let ((load-number (string-to-number load-string))
580         (alist (list (cons 0.0 0.0)
581                     (cons 0.5 (car display-time-load-list))
582                     (cons 1.0 (cadr display-time-load-list))
583                     (cons 1.5 (caddr display-time-load-list))
584                     (cons 2.0 (cadddr display-time-load-list))
585                     (cons 2.5 (cadr (cdddr display-time-load-list)))
586                     (cons 3.0 (caddr (cdddr display-time-load-list)))
587                     (cons 100000 100000)))
588         elem load-elem)
589     (if (not (display-time-can-do-graphical-display textual))
590         load-string
591       (display-time-generate-load-glyphs)
592       (while (>= load-number (cdr (setq elem (pop alist))))
593         (setq load-elem elem))
594       (eval (intern-soft (concat "display-time-load-"
595                                  (number-to-string (car load-elem))
596                                  "-glyph"))))))
597
598 (defun display-time-convert-am-pm (ampm-string &optional textual)
599   (if (not (display-time-can-do-graphical-display textual))
600       ampm-string
601     (cond ((equal ampm-string "am") display-time-am-glyph)
602           ((equal ampm-string "pm") display-time-pm-glyph))))
603
604 (defun display-time-mail-balloon (&rest ciao)
605   (let* ((mail-spool-file (or display-time-mail-file
606                               (getenv "MAIL")
607                               (concat rmail-spool-directory
608                                       (user-login-name))))
609          (show-split (and display-time-mail-balloon-show-gnus-group
610                           (or (featurep 'nnmail) (require 'nnmail))))
611          (display-time-mail-balloon-gnus-split-width
612           (if (not show-split) 0
613             (+ 3 display-time-mail-balloon-gnus-split-width))) ; -><space>... = +3
614          (mod (nth 5 (file-attributes mail-spool-file)))
615          header header-ext)
616     (setq header "You have mail:")
617     (setq header-ext
618           (make-extent 0 (length header) header))
619     (set-extent-property header-ext 'face 'display-time-time-balloon-face)
620     (set-extent-property header-ext 'duplicable t)
621     (setq header (concat header "\n"
622                          (make-string (+ display-time-mail-balloon-from-width
623                                          display-time-mail-balloon-subject-width
624                                          display-time-mail-balloon-gnus-split-width
625                                          3) (string-to-char "-"))))
626     (if (not (equal
627               mod display-time-spool-file-modification))
628         (progn
629           (setq display-time-spool-file-modification mod)
630           (setq display-time-mail-header
631                 (display-time-scan-mail-file mail-spool-file show-split))))
632     (setq header (concat header display-time-mail-header))
633     ))
634
635
636 (defun display-time-scan-mail-file (file show-split)
637   (let ((mail-headers "")
638         (nntp-server-buffer (get-buffer-create " *Display-Time-Split-Buffer*"))
639         (suppress-count 0)
640         (not-displayed 0)
641         (i 0)
642         (suppress-list display-time-mail-balloon-suppress)
643         (enhance-list display-time-mail-balloon-enhance)
644         (gnus-suppress-list display-time-mail-balloon-suppress-gnus-group)
645         (gnus-enhance-list display-time-mail-balloon-enhance-gnus-group)
646         mail-headers-list start end from subject gnus-group tmp
647         suppress enhance line line-ext
648         gnus-suppress-reg gnus-enhance-reg suppress-reg enhance-reg)
649     
650     (erase-buffer (get-buffer-create display-time-temp-buffer))
651     (message "Scanning spool file...")
652     (while (setq tmp (pop enhance-list))
653       (setq enhance-reg
654             (if (car enhance-list) (concat enhance-reg tmp "\\|")
655               (concat enhance-reg tmp))))
656     (while (setq tmp (pop suppress-list))
657       (setq suppress-reg
658             (if (car suppress-list) (concat suppress-reg tmp "\\|")
659               (concat suppress-reg tmp))))
660     (while (setq tmp (pop gnus-enhance-list))
661       (setq gnus-enhance-reg
662             (if (car gnus-enhance-list) (concat gnus-enhance-reg tmp "\\|")
663               (concat gnus-enhance-reg tmp))))
664     (while (setq tmp (pop gnus-suppress-list))
665       (setq gnus-suppress-reg
666             (if (car gnus-suppress-list) (concat gnus-suppress-reg tmp "\\|")
667               (concat gnus-suppress-reg tmp))))
668     (save-excursion
669       (set-buffer display-time-temp-buffer)
670       (setq case-fold-search nil)
671       (insert-file-contents file)
672       (goto-char (point-min))
673       (while (setq start (re-search-forward "^From " nil t))
674         (save-excursion
675           (setq end (re-search-forward "^$" nil t))
676           (narrow-to-region start end)
677           (goto-char (point-min))
678           (setq enhance
679                 (save-excursion
680                   (if display-time-mail-balloon-enhance
681                       (re-search-forward enhance-reg nil t))))
682           (if show-split
683               (save-excursion
684                 (goto-char (point-min))
685                 (nnmail-article-group '(lambda (name) (setq gnus-group name)))))
686             
687           (if enhance () ; this takes prejudice over everything else
688             (setq suppress ; maybe set suppress only if not already enhanced
689                   (save-excursion
690                     (if display-time-mail-balloon-suppress
691                         (re-search-forward suppress-reg nil t))))
692             (if suppress ()
693               (or (setq enhance      ;;maybe we enhance because of the gnus group name
694                         (save-excursion
695                           (if (and show-split gnus-group
696                                    display-time-mail-balloon-enhance-gnus-group)
697                               (string-match gnus-enhance-reg gnus-group))))
698                   (setq suppress  ;; if we didn't enhance then maybe we have to
699                                   ;; suppress it?
700                         (save-excursion
701                           (if (and show-split gnus-group
702                                    display-time-mail-balloon-suppress-gnus-group)
703                               (string-match gnus-suppress-reg gnus-group)))))))
704           
705           (setq from
706                 (save-excursion
707                   (re-search-forward "^From: \\(.*\\)" nil t)
708                   (mail-extract-address-components (match-string 1))))
709           (setq subject
710                 (save-excursion
711                   (re-search-forward "^Subject: \\(.*\\)" nil t)
712                   (match-string 1)))
713           (if suppress (setq suppress-count (1+ suppress-count))
714             (if (car from) (setq from (car from))
715               (setq from (cadr from)))
716             (if (> (length from) display-time-mail-balloon-from-width)
717                 (setq from (substring from 0
718                                       display-time-mail-balloon-from-width)))
719             (if (> (length subject) display-time-mail-balloon-subject-width)
720                 (setq subject (substring subject 0
721                                          display-time-mail-balloon-subject-width)))
722             (if (and show-split gnus-group
723                      (> (length gnus-group)
724                         (- display-time-mail-balloon-gnus-split-width 3)))
725                 (setq gnus-group (substring gnus-group 0
726                                             (- display-time-mail-balloon-gnus-split-width 3))))
727                 
728             (setq line (format (concat
729                                 "\n%-"(number-to-string
730                                        display-time-mail-balloon-from-width)
731                                 "s [%-"(number-to-string
732                                         display-time-mail-balloon-subject-width)
733                                 "s]")
734                                from subject))
735             (if (and show-split gnus-group)
736                 (setq line (concat line
737                                    (format
738                                     (concat
739                                      "-> %" (number-to-string
740                                              (- display-time-mail-balloon-gnus-split-width 3))
741                                      "s") gnus-group))))
742             (if enhance
743                 (progn
744                   (setq line-ext (make-extent 1 (length line) line))
745                   (set-extent-property line-ext 'face
746                                        'display-time-mail-balloon-enhance-face)
747                   (set-extent-property line-ext 'duplicable t)
748                   (set-extent-property line-ext 'end-open t)))
749             (if (and show-split gnus-group)
750                 (progn
751                   (setq line-ext (make-extent (- (length line)
752                                                  display-time-mail-balloon-gnus-split-width)
753                                               (length line) line))
754                   (set-extent-property line-ext 'face
755                                        'display-time-mail-balloon-gnus-group-face)
756                   (set-extent-property line-ext 'duplicable t)
757                   (set-extent-property line-ext 'end-open t)))
758             (push line mail-headers-list))
759           (goto-char (point-max))
760           (setq suppress nil
761                 gnus-group nil
762                 enhance nil)
763           (widen)
764           )))
765     (kill-buffer display-time-temp-buffer)
766     (if (> (length mail-headers-list) display-time-mail-balloon-max-displayed)
767         (setq not-displayed (- (length mail-headers-list)
768                                display-time-mail-balloon-max-displayed)))
769     (while (< i display-time-mail-balloon-max-displayed)
770       (setq mail-headers (concat mail-headers (pop mail-headers-list))) 
771       (setq i (1+ i)))
772     (if (and (equal mail-headers "") (> suppress-count 0))
773              (setq mail-headers "\nOnly junk mail..."))
774     (concat mail-headers "\n"
775             (make-string (+ display-time-mail-balloon-from-width
776                             display-time-mail-balloon-subject-width
777                             display-time-mail-balloon-gnus-split-width
778                             3) (string-to-char "-"))
779             "\n"
780              (if (> not-displayed 0)
781                  (concat "More:       " (number-to-string not-displayed)"\n"))
782              (if (> suppress-count 0)
783                  (concat "Suppressed: " (number-to-string suppress-count)))
784              )))
785
786
787 (defun display-time-mail-sign (&optional textual)
788   "*A function giving back the object indicating 'mail' which
789 is the value of display-time-mail-sign when running under X,
790 display-time-echo-area is nil and display-time-show-icons-maybe is t.
791 It is the value of display-time-mail-sign-string otherwise or when
792 the optional parameter TEXTUAL is non-nil." 
793   (if (not (display-time-can-do-graphical-display textual))
794       display-time-mail-sign-string
795     (list " " display-time-mail-sign " ")))
796
797 (defun display-time-no-mail-sign (&optional textual)
798   "*A function giving back the object indicating 'no mail' which
799 is the value of display-time-no-mail-sign when running under X,
800 display-time-echo-area is nil and display-time-show-icons-maybe is t.
801 It is the value of display-time-no-mail-sign-string otherwise or when
802 the optional parameter TEXTUAL is non-nil." 
803   (if (not (display-time-can-do-graphical-display textual))
804       display-time-no-mail-sign-string
805     (list " " display-time-no-mail-sign " ")))
806
807 (defcustom display-time-form-list
808   (list 'date 'time 'load 'mail)
809   "*This list describes the format of the strings/glyphs
810 which are to be displayed by display-time.
811 The old variable display-time-string-forms is only used if
812 display-time-compatible is non-nil. It is a list consisting of
813 strings or any of the following symbols:
814
815 There are three complex specs whose behaviour is changed via
816 the setting of various variables 
817
818 date:          This prints out the date in a manner compatible to
819                the default value of the obsolete variable
820                display-time-string-forms. It respects the variable
821                display-time-day-and-date. If this is t it will print
822                out the current date in the form DAYNAME MONTH DAY
823                otherwise it will print nothing.
824               
825 time:          This prints out the time in a manner compatible to 
826                the default value of the obsolete variable
827                display-time-string-forms. It respects the variable
828                display-time-24hr-format. If this is t it will print
829                out the current hours in 24-hour format, if nil the
830                hours will be printed in 12-hour format and the
831                minutes will be followed by 'AM' or 'PM'.
832               
833 time-text:     The same as above, but will not use a glyph
834               
835 The other specs are simpler, as their meaning is not changed via
836 variables.
837
838 24-hours:      This prints the hours in 24-hours format
839               
840 24-hours-text: The same as above, but will not use a glyph
841               
842 12-hours:      This prints the hours in 12-hours format
843               
844 12-hours-text: The same as above, but will not use a glyph
845               
846 am-pm:         This prints am or pm.
847
848 Timezone:      This prints out the local timezone
849               
850 am-pm-text:    The same as above, but will not use a glyph
851               
852 minutes:       This prints the minutes.
853               
854 minutes-text:  The same as above, but will not use a glyph
855               
856 day:           This prints out the current day as a number. 
857               
858 dayname:       This prints out today's name.
859               
860 month:         This prints out the current month as a number
861               
862 monthname:     This prints out the current month's name
863
864 year:          This prints out the current year.
865               
866 load:          This prints out the system's load.
867               
868 load-text:     The same as above, but will not use a glyph
869               
870 mail:          This displays a mail indicator. Under X this will 
871                normally be a small icon which changes depending if 
872                there is new mail or not.
873               
874 mail-text:     The same as above, but will not use a glyph"
875   :group 'display-time
876   :type '(repeat (choice :tag "Symbol/String"
877                          (const :tag "Date" date)
878                          (const :tag "Time" time)
879                          (const :tag "Time (text)" time-text)
880                          (const :tag "24 hour format" 24-hours)
881                          (const :tag "24 hour format (text)" 24-hours-text)
882                          (const :tag "12 hour format" 12-hours)
883                          (const :tag "12 hour format (text)" 12-hours-text)
884                          (const :tag "AM/PM indicator" am-pm)
885                          (const :tag "AM/PM indicator (text)" am-pm-text)
886                          (const :tag "Timezone" timezone)
887                          (const :tag "Minutes" minutes)
888                          (const :tag "Minutes (text)" minutes-text)
889                          (const :tag "Day" day)
890                          (const :tag "Dayname" dayname)
891                          (const :tag "Month" month)
892                          (const :tag "Monthname" monthname)
893                          (const :tag "Year" year)
894                          (const :tag "Load" load)
895                          (const :tag "Load (text)" load-text)
896                          (const :tag "Mail sign" mail)
897                          (const :tag "Mail sign (text)" mail-text)
898                          (string :tag "String"))))
899
900 (defun display-time-evaluate-list ()
901   "Evaluate the variable display-time-form-list"
902   (let ((list display-time-form-list) elem tmp result)
903     (while (setq elem (pop list))
904       (cond ((stringp elem) (push elem tmp))
905             ((eq elem 'date)
906              (push (if display-time-day-and-date
907                        (format "%s %s %s " dayname monthname day) "") tmp))
908             ((eq elem 'time)
909              (progn
910                (push (display-time-convert-num
911                       (format "%s:%s"
912                               (if display-time-24hr-format 24-hours 12-hours)
913                               minutes)) tmp) 
914                (if (not display-time-24hr-format)
915                    (push (display-time-convert-am-pm am-pm) tmp))))
916             ((eq elem 'time-text)
917              (push (display-time-convert-num
918                     (format "%s:%s"
919                            (if display-time-24hr-format 24-hours 12-hours)
920                            minutes) t) tmp)
921              (if (not display-time-24hr-format)
922                  (push (display-time-convert-am-pm am-pm t) tmp)))
923             ((eq elem 'day) (push day tmp))
924             ((eq elem 'dayname) (push dayname tmp))
925             ((eq elem 'month) (push month tmp))
926             ((eq elem 'monthname) (push monthname tmp))
927             ((eq elem '24-hours)
928              (push (display-time-convert-num 24-hours) tmp))
929             ((eq elem 'year)
930              (push year tmp))
931             ((eq elem '24-hours-text)
932              (push (display-time-convert-num 24-hours t) tmp))
933             ((eq elem '12-hours)
934              (push (display-time-convert-num 12-hours) tmp))
935             ((eq elem '12-hours-text)
936              (push (display-time-convert-num 12-hours t) tmp))
937             ((eq elem 'minutes)
938              (push (display-time-convert-num minutes) tmp))
939             ((eq elem 'seconds)
940              (push (display-time-convert-num seconds) tmp))
941             ((eq elem 'minutes-text)
942              (push (display-time-convert-num minutes t) tmp))
943             ((eq elem 'am-pm)
944              (push (display-time-convert-am-pm am-pm) tmp))
945             ((eq elem 'am-pm-text)
946              (push (display-time-convert-am-pm am-pm t) tmp))
947             ((eq elem 'timezone)
948              (push time-zone tmp))
949             ((eq elem 'load)
950              (push (display-time-convert-load load) tmp))
951             ((eq elem 'load-text)
952              (push (display-time-convert-load load t) tmp))
953             ((eq elem 'mail)
954              (push (if mail (display-time-mail-sign)
955                      (display-time-no-mail-sign)) tmp))
956             ((eq elem 'mail-text)
957              (push (if mail (display-time-mail-sign t)
958                      (display-time-no-mail-sign t)) tmp))
959             ))
960     ;; We know that we have a list containing only of strings if
961     ;; display-time-echo-area is t. So we construct this string from
962     ;; the list. Else we just reverse the list and give it as result.
963     (if (not display-time-echo-area) (setq result (reverse tmp))
964       (while (setq elem (pop tmp))
965         (setq result (concat elem result))))
966     result))
967     
968             
969 (defvar display-time-string-forms
970   '((if display-time-day-and-date
971         (format "%s %s %s " dayname monthname day)
972       "")
973     (format "%s:%s%s"
974             (if display-time-24hr-format 24-hours 12-hours)
975             minutes
976             (if display-time-24hr-format "" am-pm))
977     load
978     (if mail " Mail" ""))
979     "*It will only be used if display-time-compatible is t.
980 A list of expressions governing display of the time in the mode line.
981 This expression is a list of expressions that can involve the keywords
982 `load', `day', `month', and `year', `12-hours', `24-hours', `minutes',
983 `seconds', all numbers in string form, and `monthname', `dayname', `am-pm',
984 and `time-zone' all alphabetic strings and `mail' a true/nil string value.
985
986 For example, the form
987
988   '((substring year -2) \"/\" month \"/\" day
989     \" \" 24-hours \":\" minutes \":\" seconds
990     (if time-zone \" (\") time-zone (if time-zone \")\"))
991
992 would give mode line times like `94/12/30 21:07:48 (UTC)'.")
993
994 (make-obsolete-variable 'display-time-string-forms
995                         "You should use the new facilities for `display-time'.
996 Look at display-time-form-list.")   
997
998 (defun display-time-function ()
999   (let* ((now (current-time))
1000          (nowhigh (* (- (nth 0 now) (* (/ (nth 0 now) 10) 10)) 65536))
1001          (time (current-time-string now))
1002          (load (condition-case ()
1003                    (if (zerop (car (load-average))) ""
1004                      (let ((str (format " %03d" (car (load-average)))))
1005                        (concat (substring str 0 -2) "." (substring str -2))))
1006                  (error "")))
1007          (mail-spool-file (or display-time-mail-file
1008                               (getenv "MAIL")
1009                               (concat rmail-spool-directory
1010                                       (user-login-name))))
1011          (mail (and (stringp mail-spool-file)
1012                     (or (null display-time-server-down-time)
1013                         ;; If have been down for 20 min, try again.
1014                         (> (- (+ (nth 1 now) nowhigh)
1015                               display-time-server-down-time)
1016                            1200))
1017                     (let ((start-time (current-time)))
1018                       (prog1
1019                           (display-time-file-nonempty-p mail-spool-file)
1020                         (setq now (current-time)
1021                               nowhigh (* (- (nth 0 now) (* (/ (nth 0 now) 10) 10)) 65536))
1022                         (if (> (- (+ (nth 1 now) nowhigh)
1023                                   (+ (nth 1 start-time)
1024                                      (* (- (nth 0 start-time) (* (/ (nth 0 start-time) 10) 10)) 65536)))
1025                                20)
1026                             ;; Record that mail file is not accessible.
1027                             (setq display-time-server-down-time 
1028                                   (+ (nth 1 now) nowhigh))
1029                           ;; Record that mail file is accessible.
1030                           (setq display-time-server-down-time nil))))))
1031          (24-hours (substring time 11 13))
1032          (hour (string-to-int 24-hours))
1033          (12-hours (int-to-string (1+ (% (+ hour 11) 12))))
1034          (am-pm (if (>= hour 12) "pm" "am"))
1035          (minutes (substring time 14 16))
1036          (seconds (substring time 17 19))
1037          (time-zone (car (cdr (current-time-zone now))))
1038          (day (substring time 8 10))
1039          (year (substring time 20 24))
1040          (monthname (substring time 4 7))
1041          (month
1042           (cdr
1043            (assoc
1044             monthname
1045             '(("Jan" . "1") ("Feb" . "2") ("Mar" . "3") ("Apr" . "4")
1046               ("May" . "5") ("Jun" . "6") ("Jul" . "7") ("Aug" . "8")
1047               ("Sep" . "9") ("Oct" . "10") ("Nov" . "11") ("Dec" . "12")))))
1048          (dayname (substring time 0 3)))
1049     (setq display-time-string
1050           (if display-time-compatible
1051               (mapconcat 'eval display-time-string-forms "")
1052             (display-time-evaluate-list)))
1053     ;; This is inside the let binding, but we are not going to document
1054     ;; what variables are available.
1055     (run-hooks 'display-time-hook))
1056   (if display-time-echo-area
1057       (or (> (minibuffer-depth) 0)
1058           ;; don't stomp echo-area-buffer if reading from minibuffer now.
1059           (save-excursion
1060             (save-window-excursion
1061               (select-window (minibuffer-window))
1062               (erase-buffer)
1063               (indent-to (- (frame-width) (length display-time-string) 1))
1064               (insert display-time-string)
1065               (message (buffer-string)))))
1066     (force-mode-line-update)
1067     ;; Do redisplay right now, if no input pending.
1068     (sit-for 0)))
1069
1070 (defun display-time-file-nonempty-p (file)
1071   (let ((attributes (file-attributes (file-chase-links file))))
1072     (and attributes
1073          (< 0 (nth 7 attributes))
1074          (or display-time-ignore-read-mail
1075              (> (car (nth 5 attributes)) (car (nth 4 attributes)))
1076              (and (= (car (nth 5 attributes)) (car (nth 4 attributes)))
1077                   (> (cadr (nth 5 attributes)) (cadr (nth 4 attributes))))))))
1078
1079 (provide 'time)
1080
1081 ;;; time.el ends here