comparison lisp/gnus/gnus-demon.el @ 16:0293115a14e9 r19-15b91

Import from CVS: tag r19-15b91
author cvs
date Mon, 13 Aug 2007 08:49:20 +0200
parents 376386a54a3c
children ec9a17fef872
comparison
equal deleted inserted replaced
15:ad457d5f7d04 16:0293115a14e9
1 ;;; gnus-demon.el --- daemonic Gnus behaviour 1 ;;; gnus-demon.el --- daemonic Gnus behaviour
2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc. 2 ;; Copyright (C) 1995,96,97 Free Software Foundation, Inc.
3 3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> 4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Keywords: news 5 ;; Keywords: news
6 6
7 ;; This file is part of GNU Emacs. 7 ;; This file is part of GNU Emacs.
24 ;;; Commentary: 24 ;;; Commentary:
25 25
26 ;;; Code: 26 ;;; Code:
27 27
28 (require 'gnus) 28 (require 'gnus)
29 29 (require 'gnus-int)
30 (eval-when-compile (require 'cl)) 30 (require 'nnheader)
31 31 (eval-and-compile
32 (defvar gnus-demon-handlers nil 32 (if (string-match "XEmacs" (emacs-version))
33 (require 'itimer)
34 (require 'timer)))
35
36 (defgroup gnus-demon nil
37 "Demonic behaviour."
38 :group 'gnus)
39
40 (defcustom gnus-demon-handlers nil
33 "Alist of daemonic handlers to be run at intervals. 41 "Alist of daemonic handlers to be run at intervals.
34 Each handler is a list on the form 42 Each handler is a list on the form
35 43
36 \(FUNCTION TIME IDLE) 44 \(FUNCTION TIME IDLE)
37 45
40 If nil, never call. If t, call each `gnus-demon-timestep'. 48 If nil, never call. If t, call each `gnus-demon-timestep'.
41 If IDLE is t, only call if Emacs has been idle for a while. If IDLE 49 If IDLE is t, only call if Emacs has been idle for a while. If IDLE
42 is a number, only call when Emacs has been idle more than this number 50 is a number, only call when Emacs has been idle more than this number
43 of `gnus-demon-timestep's. If IDLE is nil, don't care about 51 of `gnus-demon-timestep's. If IDLE is nil, don't care about
44 idleness. If IDLE is a number and TIME is nil, then call once each 52 idleness. If IDLE is a number and TIME is nil, then call once each
45 time Emacs has been idle for IDLE `gnus-demon-timestep's.") 53 time Emacs has been idle for IDLE `gnus-demon-timestep's."
46 54 :group 'gnus-demon
47 (defvar gnus-demon-timestep 60 55 :type '(repeat (list function
48 "*Number of seconds in each demon timestep.") 56 (choice :tag "Time"
57 (const :tag "never" nil)
58 (const :tag "one" t)
59 (integer :tag "steps" 1))
60 (choice :tag "Idle"
61 (const :tag "don't care" nil)
62 (const :tag "for a while" t)
63 (integer :tag "steps" 1)))))
64
65 (defcustom gnus-demon-timestep 60
66 "*Number of seconds in each demon timestep."
67 :group 'gnus-demon
68 :type 'integer)
49 69
50 ;;; Internal variables. 70 ;;; Internal variables.
51 71
52 (defvar gnus-demon-timer nil) 72 (defvar gnus-demon-timer nil)
53 (defvar gnus-demon-idle-has-been-called nil) 73 (defvar gnus-demon-idle-has-been-called nil)
54 (defvar gnus-demon-idle-time 0) 74 (defvar gnus-demon-idle-time 0)
55 (defvar gnus-demon-handler-state nil) 75 (defvar gnus-demon-handler-state nil)
56 (defvar gnus-demon-is-idle nil) 76 (defvar gnus-demon-last-keys nil)
57 (defvar gnus-demon-last-keys nil)
58 77
59 (eval-and-compile 78 (eval-and-compile
60 (autoload 'timezone-parse-date "timezone") 79 (autoload 'timezone-parse-date "timezone")
61 (autoload 'timezone-make-arpa-date "timezone")) 80 (autoload 'timezone-make-arpa-date "timezone"))
62 81
73 (defun gnus-demon-remove-handler (function &optional no-init) 92 (defun gnus-demon-remove-handler (function &optional no-init)
74 "Remove the handler FUNCTION from the list of handlers." 93 "Remove the handler FUNCTION from the list of handlers."
75 (setq gnus-demon-handlers 94 (setq gnus-demon-handlers
76 (delq (assq function gnus-demon-handlers) 95 (delq (assq function gnus-demon-handlers)
77 gnus-demon-handlers)) 96 gnus-demon-handlers))
78 (or no-init (gnus-demon-init))) 97 (unless no-init
98 (gnus-demon-init)))
79 99
80 (defun gnus-demon-init () 100 (defun gnus-demon-init ()
81 "Initialize the Gnus daemon." 101 "Initialize the Gnus daemon."
82 (interactive) 102 (interactive)
83 (gnus-demon-cancel) 103 (gnus-demon-cancel)
84 (if (null gnus-demon-handlers) 104 (if (null gnus-demon-handlers)
85 () ; Nothing to do. 105 () ; Nothing to do.
86 ;; Set up timer. 106 ;; Set up timer.
87 (setq gnus-demon-timer 107 (setq gnus-demon-timer
88 (nnheader-run-at-time 108 (nnheader-run-at-time
89 gnus-demon-timestep gnus-demon-timestep 'gnus-demon)) 109 gnus-demon-timestep gnus-demon-timestep 'gnus-demon))
90 ;; Reset control variables. 110 ;; Reset control variables.
101 (gnus-add-shutdown 'gnus-demon-cancel 'gnus) 121 (gnus-add-shutdown 'gnus-demon-cancel 'gnus)
102 122
103 (defun gnus-demon-cancel () 123 (defun gnus-demon-cancel ()
104 "Cancel any Gnus daemons." 124 "Cancel any Gnus daemons."
105 (interactive) 125 (interactive)
106 (and gnus-demon-timer 126 (when gnus-demon-timer
107 (nnheader-cancel-timer gnus-demon-timer)) 127 (nnheader-cancel-timer gnus-demon-timer))
108 (setq gnus-demon-timer nil 128 (setq gnus-demon-timer nil
109 gnus-use-demon nil)) 129 gnus-use-demon nil)
130 (condition-case ()
131 (nnheader-cancel-function-timers 'gnus-demon)
132 (error t)))
110 133
111 (defun gnus-demon-is-idle-p () 134 (defun gnus-demon-is-idle-p ()
112 "Whether Emacs is idle or not." 135 "Whether Emacs is idle or not."
113 ;; We do this simply by comparing the 100 most recent keystrokes 136 ;; We do this simply by comparing the 100 most recent keystrokes
114 ;; with the ones we had last time. If they are the same, one might 137 ;; with the ones we had last time. If they are the same, one might
133 (string-to-number (aref dv 2)) time 156 (string-to-number (aref dv 2)) time
134 (or (aref dv 4) "UT"))) 157 (or (aref dv 4) "UT")))
135 (nseconds (gnus-time-minus 158 (nseconds (gnus-time-minus
136 (gnus-encode-date tdate) (gnus-encode-date date)))) 159 (gnus-encode-date tdate) (gnus-encode-date date))))
137 (round 160 (round
138 (/ (if (< nseconds 0) 161 (/ (+ (if (< (car nseconds) 0)
139 (+ nseconds (* 60 60 24)) 162 86400 0)
140 nseconds) gnus-demon-timestep))))) 163 (* 65536 (car nseconds))
164 (nth 1 nseconds))
165 gnus-demon-timestep)))))
141 166
142 (defun gnus-demon () 167 (defun gnus-demon ()
143 "The Gnus daemon that takes care of running all Gnus handlers." 168 "The Gnus daemon that takes care of running all Gnus handlers."
144 ;; Increase or reset the time Emacs has been idle. 169 ;; Increase or reset the time Emacs has been idle.
145 (if (gnus-demon-is-idle-p) 170 (if (gnus-demon-is-idle-p)
146 (incf gnus-demon-idle-time) 171 (incf gnus-demon-idle-time)
147 (setq gnus-demon-idle-time 0) 172 (setq gnus-demon-idle-time 0)
148 (setq gnus-demon-idle-has-been-called nil)) 173 (setq gnus-demon-idle-has-been-called nil))
149 ;; Then we go through all the handler and call those that are 174 ;; Disable all daemonic stuff if we're in the minibuffer
150 ;; sufficiently ripe. 175 (unless (window-minibuffer-p (selected-window))
151 (let ((handlers gnus-demon-handler-state) 176 ;; Then we go through all the handler and call those that are
152 handler time idle) 177 ;; sufficiently ripe.
153 (while handlers 178 (let ((handlers gnus-demon-handler-state)
154 (setq handler (pop handlers)) 179 handler time idle)
155 (cond 180 (while handlers
156 ((numberp (setq time (nth 1 handler))) 181 (setq handler (pop handlers))
157 ;; These handlers use a regular timeout mechanism. We decrease 182 (cond
158 ;; the timer if it hasn't reached zero yet. 183 ((numberp (setq time (nth 1 handler)))
159 (or (zerop time) 184 ;; These handlers use a regular timeout mechanism. We decrease
185 ;; the timer if it hasn't reached zero yet.
186 (unless (zerop time)
160 (setcar (nthcdr 1 handler) (decf time))) 187 (setcar (nthcdr 1 handler) (decf time)))
161 (and (zerop time) ; If the timer now is zero... 188 (and (zerop time) ; If the timer now is zero...
162 (or (not (setq idle (nth 2 handler))) ; Don't care about idle. 189 ;; Test for appropriate idleness
163 (and (numberp idle) ; Numerical idle... 190 (progn
164 (< idle gnus-demon-idle-time)) ; Idle timed out. 191 (setq idle (nth 2 handler))
165 gnus-demon-is-idle) ; Or just need to be idle. 192 (cond
166 ;; So we call the handler. 193 ((null idle) t) ; Don't care about idle.
167 (progn 194 ((numberp idle) ; Numerical idle...
168 (funcall (car handler)) 195 (< idle gnus-demon-idle-time)) ; Idle timed out.
169 ;; And reset the timer. 196 (t (< 0 gnus-demon-idle-time)))) ; Or just need to be idle.
170 (setcar (nthcdr 1 handler) 197 ;; So we call the handler.
171 (gnus-demon-time-to-step 198 (progn
172 (nth 1 (assq (car handler) gnus-demon-handlers))))))) 199 (funcall (car handler))
173 ;; These are only supposed to be called when Emacs is idle. 200 ;; And reset the timer.
174 ((null (setq idle (nth 2 handler))) 201 (setcar (nthcdr 1 handler)
175 ;; We do nothing. 202 (gnus-demon-time-to-step
176 ) 203 (nth 1 (assq (car handler) gnus-demon-handlers)))))))
177 ((not (numberp idle)) 204 ;; These are only supposed to be called when Emacs is idle.
178 ;; We want to call this handler each and every time that 205 ((null (setq idle (nth 2 handler)))
179 ;; Emacs is idle. 206 ;; We do nothing.
180 (funcall (car handler))) 207 )
181 (t 208 ((not (numberp idle))
182 ;; We want to call this handler only if Emacs has been idle 209 ;; We want to call this handler each and every time that
183 ;; for a specified number of timesteps. 210 ;; Emacs is idle.
184 (and (not (memq (car handler) gnus-demon-idle-has-been-called)) 211 (funcall (car handler)))
185 (< idle gnus-demon-idle-time) 212 (t
186 (progn 213 ;; We want to call this handler only if Emacs has been idle
187 (funcall (car handler)) 214 ;; for a specified number of timesteps.
188 ;; Make sure the handler won't be called once more in 215 (and (not (memq (car handler) gnus-demon-idle-has-been-called))
189 ;; this idle-cycle. 216 (< idle gnus-demon-idle-time)
190 (push (car handler) gnus-demon-idle-has-been-called)))))))) 217 (progn
218 (funcall (car handler))
219 ;; Make sure the handler won't be called once more in
220 ;; this idle-cycle.
221 (push (car handler) gnus-demon-idle-has-been-called)))))))))
191 222
192 (defun gnus-demon-add-nocem () 223 (defun gnus-demon-add-nocem ()
193 "Add daemonic NoCeM handling to Gnus." 224 "Add daemonic NoCeM handling to Gnus."
194 (gnus-demon-add-handler 'gnus-demon-scan-nocem 60 t)) 225 (gnus-demon-add-handler 'gnus-demon-scan-nocem 60 t))
195 226
196 (defun gnus-demon-scan-nocem () 227 (defun gnus-demon-scan-nocem ()
197 "Scan NoCeM groups for NoCeM messages." 228 "Scan NoCeM groups for NoCeM messages."
198 (gnus-nocem-scan-groups)) 229 (save-window-excursion
230 (gnus-nocem-scan-groups)))
199 231
200 (defun gnus-demon-add-disconnection () 232 (defun gnus-demon-add-disconnection ()
201 "Add daemonic server disconnection to Gnus." 233 "Add daemonic server disconnection to Gnus."
202 (gnus-demon-add-handler 'gnus-demon-close-connections nil 30)) 234 (gnus-demon-add-handler 'gnus-demon-close-connections nil 30))
203 235
204 (defun gnus-demon-close-connections () 236 (defun gnus-demon-close-connections ()
205 (gnus-close-backends)) 237 (save-window-excursion
238 (gnus-close-backends)))
206 239
207 (defun gnus-demon-add-scanmail () 240 (defun gnus-demon-add-scanmail ()
208 "Add daemonic scanning of mail from the mail backends." 241 "Add daemonic scanning of mail from the mail backends."
209 (gnus-demon-add-handler 'gnus-demon-scan-mail 120 60)) 242 (gnus-demon-add-handler 'gnus-demon-scan-mail 120 60))
210 243
211 (defun gnus-demon-scan-mail () 244 (defun gnus-demon-scan-mail ()
212 (let ((servers gnus-opened-servers) 245 (save-window-excursion
213 server) 246 (let ((servers gnus-opened-servers)
214 (while (setq server (car (pop servers))) 247 server)
215 (and (gnus-check-backend-function 'request-scan (car server)) 248 (while (setq server (car (pop servers)))
216 (or (gnus-server-opened server) 249 (and (gnus-check-backend-function 'request-scan (car server))
217 (gnus-open-server server)) 250 (or (gnus-server-opened server)
218 (gnus-request-scan nil server))))) 251 (gnus-open-server server))
252 (gnus-request-scan nil server))))))
253
254 (defun gnus-demon-add-rescan ()
255 "Add daemonic scanning of new articles from all backends."
256 (gnus-demon-add-handler 'gnus-demon-scan-news 120 60))
257
258 (defun gnus-demon-scan-news ()
259 (save-window-excursion
260 (when (gnus-alive-p)
261 (save-excursion
262 (set-buffer gnus-group-buffer)
263 (gnus-group-get-new-news)))))
264
265 (defun gnus-demon-add-scan-timestamps ()
266 "Add daemonic updating of timestamps in empty newgroups."
267 (gnus-demon-add-handler 'gnus-demon-scan-timestamps nil 30))
268
269 (defun gnus-demon-scan-timestamps ()
270 "Set the timestamp on all newsgroups with no unread and no ticked articles."
271 (when (gnus-alive-p)
272 (let ((cur-time (current-time))
273 (newsrc (cdr gnus-newsrc-alist))
274 info group unread has-ticked)
275 (while (setq info (pop newsrc))
276 (setq group (gnus-info-group info)
277 unread (gnus-group-unread group)
278 has-ticked (cdr (assq 'tick (gnus-info-marks info))))
279 (when (and (numberp unread)
280 (= unread 0)
281 (not has-ticked))
282 (gnus-group-set-parameter group 'timestamp cur-time))))))
219 283
220 (provide 'gnus-demon) 284 (provide 'gnus-demon)
221 285
222 ;;; gnus-demon.el ends here 286 ;;; gnus-demon.el ends here