Make nnmairix always select the correct article
[gnus] / lisp / gnus-demon.el
1 ;;; gnus-demon.el --- daemonic Gnus behavior
2
3 ;; Copyright (C) 1995-2015 Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Keywords: news
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27 (eval-when-compile (require 'cl))
28
29 (require 'gnus)
30 (require 'gnus-int)
31 (require 'nnheader)
32 (require 'nntp)
33 (require 'nnmail)
34
35 (defgroup gnus-demon nil
36   "Demonic behavior."
37   :group 'gnus)
38
39 (defcustom gnus-demon-handlers nil
40   "Alist of daemonic handlers to be run at intervals.
41 Each handler is a list on the form
42
43 \(FUNCTION TIME IDLE)
44
45 FUNCTION is the function to be called.  TIME is the number of
46 `gnus-demon-timestep's between each call.
47 If nil, never call. If t, call each `gnus-demon-timestep'.
48
49 If IDLE is t, only call each time Emacs has been idle for TIME.
50 If IDLE is a number, only call when Emacs has been idle more than
51 this number of `gnus-demon-timestep's.
52 If IDLE is nil, don't care about idleness.
53 If IDLE is a number and TIME is nil, then call once each time
54 Emacs has been idle for IDLE `gnus-demon-timestep's."
55   :group 'gnus-demon
56   :type '(repeat (list function
57                        (choice :tag "Time"
58                                (const :tag "never" nil)
59                                (const :tag "one" t)
60                                (integer :tag "steps" 1))
61                        (choice :tag "Idle"
62                                (const :tag "don't care" nil)
63                                (const :tag "for a while" t)
64                                (integer :tag "steps" 1)))))
65
66 (defcustom gnus-demon-timestep 60
67   "Number of seconds in each demon timestep."
68   :group 'gnus-demon
69   :type 'integer)
70
71 ;;; Internal variables.
72
73 (defvar gnus-demon-timers nil
74   "Plist of idle timers which are running.")
75 (defvar gnus-inhibit-demon nil
76   "If non-nil, no daemonic function will be run.")
77
78 ;;; Functions.
79
80 (defun gnus-demon-add-handler (function time idle)
81   "Add the handler FUNCTION to be run at TIME and IDLE."
82   ;; First remove any old handlers that use this function.
83   (gnus-demon-remove-handler function)
84   ;; Then add the new one.
85   (push (list function time idle) gnus-demon-handlers)
86   (gnus-demon-init))
87
88 (defun gnus-demon-remove-handler (function &optional no-init)
89   "Remove the handler FUNCTION from the list of handlers."
90   (gnus-alist-pull function gnus-demon-handlers)
91   (unless no-init
92     (gnus-demon-init)))
93
94 (defun gnus-demon-idle-since ()
95   "Return the number of seconds since when Emacs is idle."
96   (if (featurep 'xemacs)
97       (itimer-time-difference (current-time) last-command-event-time)
98     (float-time (or (current-idle-time)
99                     '(0 0 0)))))
100
101 (defun gnus-demon-run-callback (func &optional idle time special)
102   "Run FUNC if Emacs has been idle for longer than IDLE seconds.
103 If not, and a TIME is given, restart a new idle timer, so FUNC
104 can be called at the next opportunity. Such a special idle run is
105 marked with SPECIAL."
106   (unless gnus-inhibit-demon
107     (block run-callback
108       (when (eq idle t)
109         (setq idle 0.001))
110       (cond (special
111              (setq gnus-demon-timers
112                    (plist-put gnus-demon-timers func
113                               (run-with-timer time time 'gnus-demon-run-callback
114                                               func idle time))))
115             ((and idle (> idle (gnus-demon-idle-since)))
116              (when time
117                (nnheader-cancel-timer (plist-get gnus-demon-timers func))
118                (setq gnus-demon-timers
119                      (plist-put gnus-demon-timers func
120                                 (run-with-idle-timer idle nil
121                                                      'gnus-demon-run-callback
122                                                      func idle time t))))
123              (return-from run-callback)))
124       (with-local-quit
125         (ignore-errors
126           (funcall func))))))
127
128 (defun gnus-demon-init ()
129   "Initialize the Gnus daemon."
130   (interactive)
131   (gnus-demon-cancel)
132   (dolist (handler gnus-demon-handlers)
133     ;; Set up the timer.
134     (let* ((func (nth 0 handler))
135            (time (nth 1 handler))
136            (idle (nth 2 handler))
137            ;; Compute time according with timestep.
138            ;; If t, replace by 1
139            (time (cond ((eq time t)
140                         gnus-demon-timestep)
141                        ((null time)
142                         nil)
143                        ((stringp time)
144                         (* (gnus-demon-time-to-step time) gnus-demon-timestep))
145                        (t
146                         (* time gnus-demon-timestep))))
147            (idle (cond ((numberp idle)
148                         (* idle gnus-demon-timestep))
149                        ((and (eq idle t) (numberp time))
150                         time)
151                        (t
152                         idle)))
153
154            (timer
155             (cond
156              ;; (func nil number)
157              ;; Only call when Emacs has been idle for `idle'
158              ((and (null time) (numberp idle))
159               (run-with-idle-timer idle t 'gnus-demon-run-callback func))
160              ;; (func number any)
161              ;; Call every `time'
162              ((integerp time)
163               (run-with-timer time time 'gnus-demon-run-callback
164                               func idle time))
165              ;; (func string any)
166              ((stringp time)
167               (run-with-