Mercurial > hg > xemacs-beta
comparison lisp/prim/itimer.el @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | c53a95d3c46d |
children | 4be1180a9e89 |
comparison
equal
deleted
inserted
replaced
69:804d1389bcd6 | 70:131b0175ea99 |
---|---|
1 ;;; Interval timers for GNU Emacs | 1 ;;; Interval timers for XEmacs |
2 ;;; Copyright (C) 1988, 1991, 1993, 1997 Kyle E. Jones | 2 ;;; Copyright (C) 1988, 1991, 1993 Kyle E. Jones |
3 ;;; Modified 5 Feb 91 by Jamie Zawinski <jwz@lucid.com> for Lucid Emacs | |
4 ;;; And again, 15 Dec 93. | |
3 ;;; | 5 ;;; |
4 ;;; This program is free software; you can redistribute it and/or modify | 6 ;; This file is part of XEmacs. |
5 ;;; it under the terms of the GNU General Public License as published by | 7 |
6 ;;; the Free Software Foundation; either version 2, or (at your option) | 8 ;; XEmacs is free software; you can redistribute it and/or modify it |
7 ;;; any later version. | 9 ;; under the terms of the GNU General Public License as published by |
10 ;; the Free Software Foundation; either version 2, or (at your option) | |
11 ;; any later version. | |
12 | |
13 ;; XEmacs is distributed in the hope that it will be useful, but | |
14 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 ;; General Public License for more details. | |
17 | |
18 ;; You should have received a copy of the GNU General Public License | |
19 ;; along with XEmacs; see the file COPYING. If not, write to the | |
20 ;; Free Software Foundation, 59 Temple Place - Suite 330, | |
21 ;; Boston, MA 02111-1307, USA. | |
22 | |
23 ;;; Synched up with: Not in FSF. | |
24 | |
8 ;;; | 25 ;;; |
9 ;;; This program is distributed in the hope that it will be useful, | 26 ;;; Send bug reports to kyle@uunet.uu.net. |
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | 27 |
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 28 ;; The original v18 version of this file worked by having an external program |
12 ;;; GNU General Public License for more details. | 29 ;; wake up once a second to generate an interrupt for emacs; then an emacs |
13 ;;; | 30 ;; process filter was used to schedule timers. |
14 ;;; A copy of the GNU General Public License can be obtained from this | 31 ;; |
15 ;;; program's author (send electronic mail to kyle@uunet.uu.net) or from | 32 ;; This version works by associating with each timer a "timeout" object, |
16 ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA | 33 ;; since the XEmacs/Lucid Emacs event loop has the concept of timers built |
17 ;;; 02139, USA. | 34 ;; in to it. There is no single scheduler function; instead, each timer |
18 ;;; | 35 ;; re-sets itself as it is invoked. |
19 ;;; Send bug reports to kyle_jones@wonderworks.com | 36 |
20 | 37 ;; `itimer' feature means Emacs-Lisp programers get: |
21 (provide 'itimer) | 38 ;; itimerp, itimer-value, itimer-restart, itimer-function, |
22 | 39 ;; set-itimer-value, set-itimer-restart, set-itimer-function |
23 ;; `itimer' feature means Emacs-Lisp programmers get: | 40 ;; get-itimer, start-itimer, read-itimer, delete-itimer |
24 ;; itimerp | |
25 ;; itimer-live-p | |
26 ;; itimer-value | |
27 ;; itimer-restart | |
28 ;; itimer-function | |
29 ;; itimer-uses-arguments | |
30 ;; itimer-function-arguments | |
31 ;; set-itimer-value | |
32 ;; set-itimer-restart | |
33 ;; set-itimer-function | |
34 ;; set-itimer-uses-arguments | |
35 ;; set-itimer-function-arguments | |
36 ;; get-itimer | |
37 ;; start-itimer | |
38 ;; read-itimer | |
39 ;; delete-itimer | |
40 ;; activate-itimer | |
41 ;; | 41 ;; |
42 ;; Interactive users get these commands: | 42 ;; Interactive users get these commands: |
43 ;; edit-itimers | 43 ;; edit-itimers, list-itimers, start-itimer |
44 ;; list-itimers | |
45 ;; start-itimer | |
46 ;; | 44 ;; |
47 ;; See the doc strings of these functions for more information. | 45 ;; See the doc strings of these functions for more information. |
48 | 46 |
49 (defvar itimer-version "1.05" | 47 (defvar itimer-version "1.00" |
50 "Version number of the itimer package.") | 48 "Version number of the itimer package.") |
51 | 49 |
52 (defvar itimer-list nil | 50 (defvar itimer-list nil |
53 "List of all active itimers.") | 51 "List of all active itimers.") |
54 | 52 |
55 (defvar itimer-process nil | 53 ;; not needed in XEmacs |
56 "Process that drives all itimers, if a subprocess is being used.") | 54 ;(defvar itimer-process nil |
57 | 55 ; "Process that drives all itimers.") |
58 (defvar itimer-timer nil | 56 |
59 "Emacs internal timer that drives the itimer system, if a subprocess | 57 ;; This value is maintained internally; it does not determine itimer |
60 is not being used to drive the system.") | 58 ;; granularity. Itimer granularity is 1 second, plus delays due to |
61 | 59 ;; system and Emacs internal activity that delay dealing with process |
62 (defvar itimer-timer-last-wakeup nil | 60 ;; output. |
63 "The time the timer driver function last ran.") | 61 ;; not needed in XEmacs |
64 | 62 ;(defvar itimer-process-next-wakeup 1 |
65 (defvar itimer-short-interval (if (featurep 'lisp-float-type) 1e-3 1) | 63 ; "Itimer process will wakeup to service running itimers within this |
66 "Interval used for scheduling an event a very short time in the future. | 64 ;many seconds.") |
67 Used internally to make the scheduler wake up early. | |
68 Unit is seconds.") | |
69 | |
70 ;; This value is maintained internally; it does not determine | |
71 ;; itimer granularity. Itimer granularity is 1 second if your | |
72 ;; Emacs doens't support floats or your system doesn't have a | |
73 ;; clock with microsecond granularity. Otherwise granularity is | |
74 ;; to the microsend, although you can't possibly get timers to be | |
75 ;; executed with this kind of accuracy in practice. There will | |
76 ;; be delays due to system and Emacs internal activity that delay | |
77 ;; dealing with syunchronous events and process output. | |
78 (defvar itimer-next-wakeup itimer-short-interval | |
79 "Itimer process will wakeup to service running itimers within this | |
80 many seconds.") | |
81 | 65 |
82 (defvar itimer-edit-map nil | 66 (defvar itimer-edit-map nil |
83 "Keymap used when in Itimer Edit mode.") | 67 "Keymap used when in Itimer Edit mode.") |
84 | 68 |
85 (if itimer-edit-map | 69 (if itimer-edit-map |
99 (defvar itimer-edit-start-marker nil) | 83 (defvar itimer-edit-start-marker nil) |
100 | 84 |
101 ;; macros must come first... or byte-compile'd code will throw back its | 85 ;; macros must come first... or byte-compile'd code will throw back its |
102 ;; head and scream. | 86 ;; head and scream. |
103 | 87 |
104 (defmacro itimer-decrement (variable) | 88 (defmacro itimer-decf (variable) |
105 (list 'setq variable (list '1- variable))) | 89 (list 'setq variable (list '1- variable))) |
106 | 90 |
107 (defmacro itimer-increment (variable) | 91 (defmacro itimer-incf (variable) |
108 (list 'setq variable (list '1+ variable))) | 92 (list 'setq variable (list '1+ variable))) |
109 | 93 |
110 (defmacro itimer-signum (n) | 94 (defmacro itimer-signum (n) |
111 (list 'if (list '> n 0) 1 | 95 (list 'if (list '> n 0) 1 |
112 (list 'if (list 'zerop n) 0 -1))) | 96 (list 'if (list 'zerop n) 0 -1))) |
132 (list (list 'itimerp var) var) | 116 (list (list 'itimerp var) var) |
133 (list (list 'stringp var) (list 'get-itimer var)) | 117 (list (list 'stringp var) (list 'get-itimer var)) |
134 (list t (list 'signal ''wrong-type-argument | 118 (list t (list 'signal ''wrong-type-argument |
135 (list 'list ''string-or-itimer-p var)))))) | 119 (list 'list ''string-or-itimer-p var)))))) |
136 | 120 |
137 (defmacro check-nonnegative-number (var) | 121 (defmacro itimer-check-natnum (var) |
138 "If VAR is not bound to a number, signal wrong-type-argument. | 122 "If VAR is not bound to a non-negative number, signal wrong-type-argument. |
139 If VAR is not bound to a positive number, signal args-out-of-range. | |
140 This is a macro." | 123 This is a macro." |
141 (list 'setq var | 124 (list 'setq var |
142 (list 'if (list 'not (list 'numberp var)) | 125 (list 'if (list 'natnump var) var |
143 (list 'signal ''wrong-type-argument | 126 (list 'signal ''wrong-type-argument |
144 (list 'list ''natnump var)) | 127 (list 'list ''natnump var))))) |
145 (list 'if (list '< var 0) | 128 |
146 (list 'signal ''args-out-of-range (list 'list var)) | 129 (defmacro itimer-check-string (var) |
147 var)))) | |
148 | |
149 (defmacro check-string (var) | |
150 "If VAR is not bound to a string, signal wrong-type-argument. | 130 "If VAR is not bound to a string, signal wrong-type-argument. |
151 This is a macro." | 131 This is a macro." |
152 (list 'setq var | 132 (list 'setq var |
153 (list 'if (list 'stringp var) var | 133 (list 'if (list 'stringp var) var |
154 (list 'signal ''wrong-type-argument | 134 (list 'signal ''wrong-type-argument |
156 | 136 |
157 ;; Functions to access and modify itimer attributes. | 137 ;; Functions to access and modify itimer attributes. |
158 | 138 |
159 (defun itimerp (obj) | 139 (defun itimerp (obj) |
160 "Returns non-nil iff OBJ is an itimer." | 140 "Returns non-nil iff OBJ is an itimer." |
161 (and (consp obj) (eq (length obj) 8))) | 141 (and (consp obj) (stringp (car obj)) (eq (length obj) |
162 | 142 5 ; for XEmacs |
163 (defun itimer-live-p (obj) | 143 ;4 ; original version |
164 "Returns non-nil iff OBJ is an itimer and is active. | 144 ))) |
165 ``Active'' means Emacs will run it when it expires. | |
166 `activate-timer' must be called on a itimer to make it active. | |
167 Itimers started with `start-itimer' are automatically active." | |
168 (and (itimerp obj) (memq obj itimer-list))) | |
169 | 145 |
170 (defun itimer-name (itimer) | 146 (defun itimer-name (itimer) |
171 "Returns the name of ITIMER." | 147 "Returns the name of ITIMER." |
172 (check-itimer itimer) | 148 (check-itimer itimer) |
173 (car itimer)) | 149 (car itimer)) |
187 "Returns the function of ITIMER. | 163 "Returns the function of ITIMER. |
188 This function is called each time ITIMER expires." | 164 This function is called each time ITIMER expires." |
189 (check-itimer itimer) | 165 (check-itimer itimer) |
190 (nth 3 itimer)) | 166 (nth 3 itimer)) |
191 | 167 |
192 (defun itimer-is-idle (itimer) | 168 ;; XEmacs-specific |
193 "Returns non-nil if ITIMER is an idle timer. | 169 (defun itimer-id (itimer) |
194 Normal timers expire after a set interval. Idle timers expire | 170 "Returns the timeout-id of ITIMER." |
195 only after Emacs has been idle for a specific interval. ``Idle'' | |
196 means no command events within the interval." | |
197 (check-itimer itimer) | 171 (check-itimer itimer) |
198 (nth 4 itimer)) | 172 (nth 4 itimer)) |
199 | 173 |
200 (defun itimer-uses-arguments (itimer) | 174 (defun set-itimer-value (itimer value |
201 "Returns non-nil if the function of ITIMER will be called with arguments. | 175 ;; XEmacs doesn't need this |
202 ITIMER's function is called with the arguments each time ITIMER expires. | 176 ;; &optional nowakeup |
203 The arguments themselves are retrievable with `itimer-function-arguments'." | 177 ) |
204 (check-itimer itimer) | |
205 (nth 5 itimer)) | |
206 | |
207 (defun itimer-function-arguments (itimer) | |
208 "Returns the function arguments of ITIMER as a list. | |
209 ITIMER's function is called with these argument each timer ITIMER expires." | |
210 (check-itimer itimer) | |
211 (nth 6 itimer)) | |
212 | |
213 (defun itimer-recorded-run-time (itimer) | |
214 (check-itimer itimer) | |
215 (nth 7 itimer)) | |
216 | |
217 (defun set-itimer-value (itimer value) | |
218 "Set the timeout value of ITIMER to be VALUE. | 178 "Set the timeout value of ITIMER to be VALUE. |
219 Itimer will expire is this many seconds. | 179 Itimer will expire is this many seconds. |
220 If your version of Emacs supports floating point numbers then | |
221 VALUE can be a floating point number. Otherwise it | |
222 must be an integer. | |
223 Returns VALUE." | 180 Returns VALUE." |
224 (check-itimer itimer) | 181 ;; Optional third arg NOWAKEUP non-nil means do not wakeup the itimer |
225 (check-nonnegative-number value) | 182 ;; process to recompute a correct wakeup time, even if it means this |
183 ;; itimer will expire late. itimer-process-filter uses this option. | |
184 ;; This is not meant for ordinary usage, which is why it is not | |
185 ;; mentioned in the doc string. | |
186 (check-itimer itimer) | |
187 (itimer-check-natnum value) | |
226 (let ((inhibit-quit t)) | 188 (let ((inhibit-quit t)) |
227 ;; If the itimer is in the active list, and under the new | 189 |
228 ;; timeout value would expire before we would normally | 190 ; ;; If we're allowed to wakeup the itimer process, |
229 ;; wakeup, wakeup now and recompute a new wakeup time. | 191 ; ;; and the itimer process's next wakeup needs to be recomputed, |
230 (or (and (< value itimer-next-wakeup) | 192 ; ;; and the itimer is running, then we wakeup the itimer process. |
231 (and (itimer-name itimer) (get-itimer (itimer-name itimer))) | 193 ; (or (and (not nowakeup) (< value itimer-process-next-wakeup) |
232 (progn (itimer-driver-wakeup) | 194 ; (get-itimer (itimer-name itimer)) |
233 (setcar (cdr itimer) value) | 195 ; (progn (itimer-process-wakeup) |
234 (itimer-driver-wakeup) | 196 ; (setcar (cdr itimer) value) |
235 t )) | 197 ; (itimer-process-wakeup))) |
236 (setcar (cdr itimer) value)) | 198 ; (setcar (cdr itimer) value)) |
199 | |
200 ;; the XEmacs way: | |
201 (if (itimer-id itimer) | |
202 (deactivate-itimer itimer)) | |
203 (setcar (cdr itimer) value) | |
204 (activate-itimer itimer) | |
205 | |
237 value)) | 206 value)) |
238 | |
239 ;; Same as set-itimer-value but does not wakeup the driver. | |
240 ;; Only should be used by the drivers when processing expired timers. | |
241 (defun set-itimer-value-internal (itimer value) | |
242 (check-itimer itimer) | |
243 (check-nonnegative-number value) | |
244 (setcar (cdr itimer) value)) | |
245 | 207 |
246 (defun set-itimer-restart (itimer restart) | 208 (defun set-itimer-restart (itimer restart) |
247 "Set the restart value of ITIMER to be RESTART. | 209 "Set the restart value of ITIMER to be RESTART. |
248 If RESTART is nil, ITIMER will not restart when it expires. | 210 If RESTART is nil, ITIMER will not restart when it expires. |
249 If your version of Emacs supports floating point numbers then | |
250 RESTART can be a floating point number. Otherwise it | |
251 must be an integer. | |
252 Returns RESTART." | 211 Returns RESTART." |
253 (check-itimer itimer) | 212 (check-itimer itimer) |
254 (if restart (check-nonnegative-number restart)) | 213 (if restart (itimer-check-natnum restart)) |
255 (setcar (cdr (cdr itimer)) restart)) | 214 (and restart (< restart 1) (signal 'args-out-of-range (list restart))) |
215 ;; (setcar (cdr (cdr itimer)) restart) | |
216 ;; the XEmacs way | |
217 (let ((was-active (itimer-id itimer)) | |
218 (inhibit-quit t)) | |
219 (if was-active | |
220 (deactivate-itimer itimer)) | |
221 (setcar (cdr (cdr itimer)) restart) | |
222 (if was-active | |
223 (progn | |
224 (setcar (cdr itimer) restart) | |
225 (if restart | |
226 (activate-itimer itimer))))) | |
227 restart) | |
256 | 228 |
257 (defun set-itimer-function (itimer function) | 229 (defun set-itimer-function (itimer function) |
258 "Set the function of ITIMER to be FUNCTION. | 230 "Set the function of ITIMER to be FUNCTION. |
259 FUNCTION will be called when itimer expires. | 231 FUNCTION will be called when itimer expires. |
260 Returns FUNCTION." | 232 Returns FUNCTION." |
261 (check-itimer itimer) | 233 (check-itimer itimer) |
262 (setcar (nthcdr 3 itimer) function)) | 234 (setcar (cdr (cdr (cdr itimer))) function)) |
263 | 235 |
264 (defun set-itimer-is-idle (itimer flag) | 236 ;; XEmacs-specific |
265 "Sets flag that says whether ITIMER is an idle timer. | 237 (defun set-itimer-id (itimer id) |
266 If FLAG is non-nil, then ITIMER will eb considered an idle timer. | 238 (check-itimer itimer) |
267 Returns FLAG." | 239 (setcar (cdr (cdr (cdr (cdr itimer)))) id)) |
268 (check-itimer itimer) | |
269 (setcar (nthcdr 4 itimer) flag)) | |
270 | |
271 (defun set-itimer-uses-arguments (itimer flag) | |
272 "Sets flag that says whether the function of ITIMER is called with arguments. | |
273 If FLAG is non-nil, then the function will be called with one argument, | |
274 otherwise the function will be called with no arguments. | |
275 Returns FLAG." | |
276 (check-itimer itimer) | |
277 (setcar (nthcdr 5 itimer) flag)) | |
278 | |
279 (defun set-itimer-function-arguments (itimer &optional arguments) | |
280 "Set the function arguments of ITIMER to be ARGUMENTS. | |
281 The function of ITIMER will be called with ARGUMENTS when itimer expires. | |
282 Returns ARGUMENTS." | |
283 (check-itimer itimer) | |
284 (setcar (nthcdr 6 itimer) arguments)) | |
285 | |
286 (defun set-itimer-recorded-run-time (itimer time) | |
287 (check-itimer itimer) | |
288 (setcar (nthcdr 7 itimer) time)) | |
289 | 240 |
290 (defun get-itimer (name) | 241 (defun get-itimer (name) |
291 "Return itimer named NAME, or nil if there is none." | 242 "Return itimer named NAME, or nil if there is none." |
292 (check-string name) | 243 (itimer-check-string name) |
293 (assoc name itimer-list)) | 244 (assoc name itimer-list)) |
294 | 245 |
295 (defun read-itimer (prompt &optional initial-input) | 246 (defun read-itimer (prompt &optional initial-input) |
296 "Read the name of an itimer from the minibuffer and return the itimer | 247 "Read the name of an itimer from the minibuffer and return the itimer |
297 associated with that name. The user is prompted with PROMPT. | 248 associated with that name. The user is prompted with PROMPT. |
300 (get-itimer (completing-read prompt itimer-list nil 'confirm initial-input))) | 251 (get-itimer (completing-read prompt itimer-list nil 'confirm initial-input))) |
301 | 252 |
302 (defun delete-itimer (itimer) | 253 (defun delete-itimer (itimer) |
303 "Deletes ITIMER. ITIMER may be an itimer or the name of one." | 254 "Deletes ITIMER. ITIMER may be an itimer or the name of one." |
304 (check-itimer-coerce-string itimer) | 255 (check-itimer-coerce-string itimer) |
256 (deactivate-itimer itimer) ;; for XEmacs | |
305 (setq itimer-list (delq itimer itimer-list))) | 257 (setq itimer-list (delq itimer itimer-list))) |
306 | 258 |
307 (defun start-itimer (name function value &optional restart | 259 ;jwz: this is preloaded so don't ;;;###autoload |
308 is-idle with-args &rest function-arguments) | 260 (defun start-itimer (name function value &optional restart) |
309 "Start an itimer. | 261 "Start an itimer. |
310 Arguments are | 262 Args are NAME, FUNCTION, VALUE &optional RESTART. |
311 NAME, FUNCTION, VALUE &optional RESTART, IS-IDLE, WITH-ARGS, &rest FUNCTION-ARGUMENTS. | |
312 NAME is an identifier for the itimer. It must be a string. If an itimer | 263 NAME is an identifier for the itimer. It must be a string. If an itimer |
313 already exists with this name, NAME will be modified slightly to until | 264 already exists with this name, NAME will be modified slightly to until |
314 it is unique. | 265 it is unique. |
315 FUNCTION should be a function (or symbol naming one). It | 266 FUNCTION should be a function (or symbol naming one) of no arguments. It |
316 will be called each time the itimer expires with arguments of | 267 will be called each time the itimer expires. The function can access |
317 FUNCTION-ARGUMENTS. The function can access the itimer that | 268 itimer that invoked it through the variable `current-itimer'. |
318 invoked it through the variable `current-itimer'. If WITH-ARGS | |
319 is nil then FUNCTION is called with no arguments. This is for | |
320 backward compatibility with older versions of the itimer | |
321 package which always called FUNCTION with no arguments. | |
322 VALUE is the number of seconds until this itimer expires. | 269 VALUE is the number of seconds until this itimer expires. |
323 If your version of Emacs supports floating point numbers then | |
324 you can VALUE can be a floating point number. Otherwise it | |
325 must be an integer. | |
326 Optional fourth arg RESTART non-nil means that this itimer should be | 270 Optional fourth arg RESTART non-nil means that this itimer should be |
327 restarted automatically after its function is called. Normally an itimer | 271 restarted automatically after its function is called. Normally an itimer |
328 is deleted at expiration after its function has returned. | 272 is deleted at expiration after its function has returned. |
329 If non-nil RESTART should be a number indicating the value at which the | 273 If non-nil RESTART should be a number indicating the value at which the |
330 itimer should be set at restart time. | 274 itimer should be set at restart time. |
331 Optional fifth arg IS-IDLE specified if this is an idle timer. | |
332 Normal timers eexpire after a set interval. Idle timers expire | |
333 only after Emacs has been idle for specific interval. ``Idle'' | |
334 means no command events within the interval. | |
335 Returns the newly created itimer." | 275 Returns the newly created itimer." |
336 (interactive | 276 (interactive |
337 (list (completing-read "Start itimer: " itimer-list) | 277 (list (completing-read "Start itimer: " itimer-list) |
338 (read (completing-read "Itimer function: " obarray 'fboundp)) | 278 (read (completing-read "Itimer function: " obarray 'fboundp)) |
339 (let (value) | 279 (let (value) |
340 (while (or (not (numberp value)) (< value 0)) | 280 (while (not (natnump value)) |
341 (setq value (read-from-minibuffer "Itimer value: " nil nil t))) | 281 (setq value (read-from-minibuffer "Itimer value: " nil nil t))) |
342 value) | 282 value) |
343 (let ((restart t)) | 283 (let ((restart t)) |
344 (while (and restart (or (not (numberp restart)) (< restart 0))) | 284 (while (and restart (not (natnump restart))) |
345 (setq restart (read-from-minibuffer "Itimer restart: " | 285 (setq restart (read-from-minibuffer "Itimer restart: " nil nil t))) |
346 nil nil t))) | 286 restart))) |
347 restart) | 287 (itimer-check-string name) |
348 ;; hard to imagine the user specifying these interactively | 288 (itimer-check-natnum value) |
349 nil | 289 (if restart (itimer-check-natnum restart)) |
350 nil )) | |
351 (check-string name) | |
352 (check-nonnegative-number value) | |
353 (if restart (check-nonnegative-number restart)) | |
354 ;; Make proposed itimer name unique if it's not already. | 290 ;; Make proposed itimer name unique if it's not already. |
355 (let ((oname name) | 291 (let ((oname name) |
356 (num 2)) | 292 (num 2)) |
357 (while (get-itimer name) | 293 (while (get-itimer name) |
358 (setq name (concat oname "<" num ">")) | 294 (setq name (concat oname "<" num ">")) |
359 (itimer-increment num))) | 295 (itimer-incf num))) |
360 (activate-itimer (list name value restart function is-idle | 296 ; ;; If there's no itimer process, start one now. |
361 with-args function-arguments (list 0 0 0))) | 297 ; ;; Otherwise wake up the itimer process so that seconds slept before |
362 (car itimer-list)) | 298 ; ;; the new itimer is created won't be counted against it. |
363 | 299 ; (if itimer-process |
364 (defun make-itimer () | 300 ; (itimer-process-wakeup) |
365 "Create an unactivated itimer. | 301 ; (itimer-process-start)) |
366 The itimer will not begin running until activated with `activate-itimer'. | |
367 Set the itimer's expire interval with `set-itimer-value'. | |
368 Set the itimer's function interval with `set-itimer-function'. | |
369 Once this is done, the timer can be activated." | |
370 (list nil 0 nil 'ignore nil nil nil (list 0 0 0))) | |
371 | |
372 (defun activate-itimer (itimer) | |
373 "Activate ITIMER, which was previously created with `make-itimer'. | |
374 ITIMER will be added to the global list of running itimers, | |
375 its FUNCTION will be called when it expires, and so on." | |
376 (check-itimer itimer) | |
377 (if (memq itimer itimer-list) | |
378 (error "itimer already activated")) | |
379 (if (not (numberp (itimer-value itimer))) | |
380 (error "itimer timeout value not a number: %s" (itimer-value itimer))) | |
381 (if (<= (itimer-value itimer) 0) | |
382 (error "itimer timeout value not positive: %s" (itimer-value itimer))) | |
383 ;; If there's no itimer driver/process, start one now. | |
384 ;; Otherwise wake up the itimer driver so that seconds slept before | |
385 ;; the new itimer is created won't be counted against it. | |
386 (if (or itimer-process itimer-timer) | |
387 (itimer-driver-wakeup) | |
388 (itimer-driver-start)) | |
389 ;; Roll a unique name for the timer if it doesn't have a name | |
390 ;; already. | |
391 (if (not (stringp (car itimer))) | |
392 (let ((name "itimer-0") | |
393 (oname "itimer-") | |
394 (num 1)) | |
395 (while (get-itimer name) | |
396 (setq name (concat oname "<" num ">")) | |
397 (itimer-increment num)) | |
398 (setcar itimer name)) | |
399 ;; signal an error if the timer's name matches an already | |
400 ;; activated timer. | |
401 (if (get-itimer (itimer-name itimer)) | |
402 (error "itimer named \"%s\" already existing and activated" | |
403 (itimer-name itimer)))) | |
404 (let ((inhibit-quit t)) | 302 (let ((inhibit-quit t)) |
405 ;; add the itimer to the global list | 303 ;; add the itimer to the global list |
406 (setq itimer-list (cons itimer itimer-list)) | 304 (setq itimer-list |
407 ;; If the itimer process is scheduled to wake up too late for | 305 (cons (list name value restart function nil) ; extra slot for XEmacs |
408 ;; the itimer we wake it up to calculate a correct wakeup | 306 itimer-list)) |
409 ;; value giving consideration to the newly added itimer. | 307 ; ;; If the itimer process is scheduled to wake up too late for the itimer |
410 (if (< (itimer-value itimer) itimer-next-wakeup) | 308 ; ;; we wake it up to calculate a correct wakeup value giving consideration |
411 (itimer-driver-wakeup)))) | 309 ; ;; to the newly added itimer. |
310 ; (if (< value itimer-process-next-wakeup) | |
311 ; (itimer-process-wakeup))) | |
312 ;; for XEmacs | |
313 (activate-itimer (car itimer-list)) | |
314 ) | |
315 (car itimer-list)) | |
412 | 316 |
413 ;; User level functions to list and modify existing itimers. | 317 ;; User level functions to list and modify existing itimers. |
414 ;; Itimer Edit major mode, and the editing commands thereof. | 318 ;; Itimer Edit major mode, and the editing commands thereof. |
415 | 319 |
416 (defun list-itimers () | 320 (defun list-itimers () |
425 (itimers (reverse itimer-list))) | 329 (itimers (reverse itimer-list))) |
426 (set-buffer buf) | 330 (set-buffer buf) |
427 (itimer-edit-mode) | 331 (itimer-edit-mode) |
428 (setq buffer-read-only nil) | 332 (setq buffer-read-only nil) |
429 (erase-buffer) | 333 (erase-buffer) |
430 (insert | 334 (insert "Name Value Restart Function\n" |
431 "Name Value Restart Function Idle Arguments" | 335 "---- ----- ------- --------") |
432 "\n" | |
433 "---- ----- ------- -------- ---- --------") | |
434 (if (null itimer-edit-start-marker) | 336 (if (null itimer-edit-start-marker) |
435 (setq itimer-edit-start-marker (point))) | 337 (setq itimer-edit-start-marker (point))) |
436 (while itimers | 338 (while itimers |
437 (newline 1) | 339 (newline 1) |
438 (prin1 (itimer-name (car itimers))) | 340 (prin1 (itimer-name (car itimers))) |
439 (tab-to-tab-stop) | 341 (tab-to-tab-stop) |
440 (insert (itimer-truncate-string | 342 (prin1 (itimer-value (car itimers))) |
441 (format "%5.5s" (itimer-value (car itimers))) 5)) | |
442 (tab-to-tab-stop) | 343 (tab-to-tab-stop) |
443 (insert (itimer-truncate-string | 344 (prin1 (itimer-restart (car itimers))) |
444 (format "%5.5s" (itimer-restart (car itimers))) 5)) | |
445 (tab-to-tab-stop) | 345 (tab-to-tab-stop) |
446 (insert (itimer-truncate-string | 346 (prin1 (itimer-function (car itimers))) |
447 (format "%.19s" (itimer-function (car itimers))) 19)) | |
448 (tab-to-tab-stop) | |
449 (if (itimer-is-idle (car itimers)) | |
450 (insert "yes") | |
451 (insert "no")) | |
452 (tab-to-tab-stop) | |
453 (if (itimer-uses-arguments (car itimers)) | |
454 (prin1 (itimer-function-arguments (car itimers))) | |
455 (prin1 'NONE)) | |
456 (setq itimers (cdr itimers))) | 347 (setq itimers (cdr itimers))) |
457 ;; restore point | 348 ;; restore point |
458 (goto-char opoint) | 349 (goto-char opoint) |
459 (if (< (point) itimer-edit-start-marker) | 350 (if (< (point) itimer-edit-start-marker) |
460 (goto-char itimer-edit-start-marker)) | 351 (goto-char itimer-edit-start-marker)) |
466 The major mode of the buffer containing the listing is Itimer Edit mode. | 357 The major mode of the buffer containing the listing is Itimer Edit mode. |
467 This major mode provides commands to manipulate itimers; see the documentation | 358 This major mode provides commands to manipulate itimers; see the documentation |
468 for `itimer-edit-mode' for more information." | 359 for `itimer-edit-mode' for more information." |
469 (interactive) | 360 (interactive) |
470 ;; since user is editing, make sure displayed data is reasonably up-to-date | 361 ;; since user is editing, make sure displayed data is reasonably up-to-date |
471 (if (or itimer-process itimer-timer) | 362 ; (if itimer-process |
472 (itimer-driver-wakeup)) | 363 ; (itimer-process-wakeup)) |
473 (list-itimers) | 364 (list-itimers) |
474 (select-window (get-buffer-window "*Itimer List*")) | 365 (select-window (get-buffer-window "*Itimer List*")) |
475 (goto-char itimer-edit-start-marker) | 366 (goto-char itimer-edit-start-marker) |
476 (if itimer-list | 367 (if itimer-list |
477 (progn | 368 (progn |
480 (message "type q to quit, ? for help")) | 371 (message "type q to quit, ? for help")) |
481 | 372 |
482 ;; no point in making this interactive. | 373 ;; no point in making this interactive. |
483 (defun itimer-edit-mode () | 374 (defun itimer-edit-mode () |
484 "Major mode for manipulating itimers. | 375 "Major mode for manipulating itimers. |
485 Attributes of running itimers are changed by moving the cursor to the | 376 Atrributes of running itimers are changed by moving the cursor to the |
486 desired field and typing `s' to set that field. The field will then be | 377 desired field and typing `s' to set that field. The field will then be |
487 set to the value read from the minibuffer. | 378 set to the value read from the minibuffer. |
488 | 379 |
489 Commands: | 380 Commands: |
490 TAB move forward a field | 381 TAB move forward a field |
496 (kill-all-local-variables) | 387 (kill-all-local-variables) |
497 (make-local-variable 'tab-stop-list) | 388 (make-local-variable 'tab-stop-list) |
498 (setq major-mode 'itimer-edit-mode | 389 (setq major-mode 'itimer-edit-mode |
499 mode-name "Itimer Edit" | 390 mode-name "Itimer Edit" |
500 truncate-lines t | 391 truncate-lines t |
501 tab-stop-list '(22 32 40 60 67)) | 392 tab-stop-list '(22 32 42)) |
502 (abbrev-mode 0) | 393 (abbrev-mode 0) |
503 (auto-fill-mode 0) | 394 (auto-fill-mode 0) |
504 (buffer-flush-undo (current-buffer)) | 395 (buffer-disable-undo (current-buffer)) |
505 (use-local-map itimer-edit-map) | 396 (use-local-map itimer-edit-map) |
506 (set-syntax-table emacs-lisp-mode-syntax-table)) | 397 (and lisp-mode-syntax-table (set-syntax-table lisp-mode-syntax-table))) |
507 | 398 |
508 (put 'itimer-edit-mode 'mode-class 'special) | 399 (put 'itimer-edit-mode 'mode-class 'special) |
509 | 400 |
510 (defun itimer-edit-help () | 401 (defun itimer-edit-help () |
511 "Help function for Itimer Edit." | 402 "Help function for Itimer Edit." |
542 (n 0)) | 433 (n 0)) |
543 ;; count the number of sexprs until we reach the cursor | 434 ;; count the number of sexprs until we reach the cursor |
544 ;; and use this info to determine which field the user | 435 ;; and use this info to determine which field the user |
545 ;; wants to modify. | 436 ;; wants to modify. |
546 (beginning-of-line) | 437 (beginning-of-line) |
547 (while (and (>= opoint (point)) (< n 6)) | 438 (while (and (>= opoint (point)) (< n 4)) |
548 (forward-sexp 2) | 439 (forward-sexp 2) |
549 (backward-sexp) | 440 (backward-sexp) |
550 (itimer-increment n)) | 441 (itimer-incf n)) |
551 (cond ((eq n 1) (error "Cannot change itimer name.")) | 442 (cond ((eq n 1) (error "Cannot change itimer name.")) |
552 ((eq n 2) 'value) | 443 ((eq n 2) 'value) |
553 ((eq n 3) 'restart) | 444 ((eq n 3) 'restart) |
554 ((eq n 4) 'function) | 445 ((eq n 4) 'function))))) |
555 ((eq n 5) 'is-idle) | |
556 (t 'function-argument))))) | |
557 (cond ((eq field 'value) | 446 (cond ((eq field 'value) |
558 (let ((prompt "Set itimer value: ")) | 447 ;; XEmacs: rewritten for I18N3 snarfing |
559 (while (not (natnump field-value)) | 448 (while (not (natnump field-value)) |
560 (setq field-value (read-from-minibuffer prompt nil nil t))))) | 449 (setq field-value (read-from-minibuffer "Set itimer value: " |
450 nil nil t)))) | |
561 ((eq field 'restart) | 451 ((eq field 'restart) |
562 (let ((prompt "Set itimer restart: ")) | 452 (while (and field-value (not (natnump field-value))) |
563 (while (and field-value (not (natnump field-value))) | 453 (setq field-value (read-from-minibuffer "Set itimer restart: " |
564 (setq field-value (read-from-minibuffer prompt nil nil t))))) | 454 nil nil t)))) |
565 ((eq field 'function) | 455 ((eq field 'function) |
566 (let ((prompt "Set itimer function: ")) | 456 (while (not (or (and (symbolp field-value) (fboundp field-value)) |
567 (while (not (or (and (symbolp field-value) (fboundp field-value)) | 457 (and (consp field-value) |
568 (and (consp field-value) | 458 (memq (car field-value) '(lambda macro))))) |
569 (memq (car field-value) '(lambda macro))))) | 459 (setq field-value |
570 (setq field-value | 460 (read (completing-read "Set itimer function: " |
571 (read (completing-read prompt obarray 'fboundp nil)))))) | 461 obarray 'fboundp nil)))))) |
572 ((eq field 'is-idle) | |
573 (setq field-value (not (itimer-is-idle itimer)))) | |
574 ((eq field 'function-argument) | |
575 (let ((prompt "Set itimer function argument: ")) | |
576 (setq field-value (read-expression prompt)) | |
577 (cond ((not (listp field-value)) | |
578 (setq field-value (list field-value)))) | |
579 (if (null field-value) | |
580 (set-itimer-uses-arguments itimer nil) | |
581 (set-itimer-uses-arguments itimer t))))) | |
582 ;; set the itimer field | 462 ;; set the itimer field |
583 (funcall (intern (concat "set-itimer-" (symbol-name field))) | 463 (funcall (intern (concat "set-itimer-" (symbol-name field))) |
584 itimer field-value) | 464 itimer field-value) |
585 ;; move to beginning of field to be changed | 465 ;; move to beginning of field to be changed |
586 (itimer-edit-beginning-of-field) | 466 (itimer-edit-beginning-of-field) |
621 ;; treat fields at beginning of line as if they weren't there. | 501 ;; treat fields at beginning of line as if they weren't there. |
622 (if (bolp) | 502 (if (bolp) |
623 (progn | 503 (progn |
624 (forward-sexp 2) | 504 (forward-sexp 2) |
625 (backward-sexp))) | 505 (backward-sexp))) |
626 (itimer-decrement count))) | 506 (itimer-decf count))) |
627 ((< (itimer-signum count) 0) | 507 ((< (itimer-signum count) 0) |
628 (while (not (zerop count)) | 508 (while (not (zerop count)) |
629 (backward-sexp) | 509 (backward-sexp) |
630 ;; treat fields at beginning of line as if they weren't there. | 510 ;; treat fields at beginning of line as if they weren't there. |
631 (if (bolp) | 511 (if (bolp) |
633 ;; wrap from itimer-edit-start-marker to field at eob. | 513 ;; wrap from itimer-edit-start-marker to field at eob. |
634 (if (<= (point) itimer-edit-start-marker) | 514 (if (<= (point) itimer-edit-start-marker) |
635 (progn | 515 (progn |
636 (goto-char (point-max)) | 516 (goto-char (point-max)) |
637 (backward-sexp))) | 517 (backward-sexp))) |
638 (itimer-increment count))))) | 518 (itimer-incf count))))) |
639 | 519 |
640 (defun itimer-edit-previous-field (count) | 520 (defun itimer-edit-previous-field (count) |
641 (interactive "p") | 521 (interactive "p") |
642 (itimer-edit-next-field (- count))) | 522 (itimer-edit-next-field (- count))) |
643 | 523 |
646 (back (save-excursion (backward-sexp) (point)))) | 526 (back (save-excursion (backward-sexp) (point)))) |
647 (cond ((eq forw-back back) (backward-sexp)) | 527 (cond ((eq forw-back back) (backward-sexp)) |
648 ((eq forw-back (point)) t) | 528 ((eq forw-back (point)) t) |
649 (t (backward-sexp))))) | 529 (t (backward-sexp))))) |
650 | 530 |
651 (defun itimer-truncate-string (str len) | |
652 (if (<= (length str) len) | |
653 str | |
654 (substring str 0 len))) | |
655 | 531 |
656 ;; internals of the itimer implementation. | 532 ;; internals of the itimer implementation. |
657 | 533 |
658 (defun itimer-run-expired-timers (time-elapsed) | |
659 (let ((itimers (copy-sequence itimer-list)) | |
660 (itimer) | |
661 (next-wakeup 600) | |
662 (idle-time) | |
663 (last-event-time) | |
664 (recorded-run-time) | |
665 ;; process filters can be hit by stray C-g's from the user, | |
666 ;; so we must protect this stuff appropriately. | |
667 ;; Quit's are allowed from within itimer functions, but we | |
668 ;; catch them and print a message. | |
669 (inhibit-quit t)) | |
670 (setq next-wakeup 600) | |
671 (if (and (boundp 'last-input-time) (consp last-input-time)) | |
672 (setq last-event-time (list (car last-input-time) | |
673 (cdr last-input-time) | |
674 0) | |
675 idle-time (itimer-time-difference (current-time) | |
676 last-event-time)) | |
677 ;; no way to do this under FSF Emacs yet. | |
678 (setq last-event-time '(0 0 0) | |
679 idle-time 0)) | |
680 (while itimers | |
681 (setq itimer (car itimers)) | |
682 (if (itimer-is-idle itimer) | |
683 (setq recorded-run-time (itimer-recorded-run-time itimer)) | |
684 (set-itimer-value-internal itimer (max 0 (- (itimer-value itimer) | |
685 time-elapsed)))) | |
686 (if (if (itimer-is-idle itimer) | |
687 (or (> (itimer-time-difference recorded-run-time | |
688 last-event-time) | |
689 0) | |
690 (< idle-time (itimer-value itimer))) | |
691 (> (itimer-value itimer) 0)) | |
692 (setq next-wakeup | |
693 (if (itimer-is-idle itimer) | |
694 (if (< idle-time (itimer-value itimer)) | |
695 (min next-wakeup (- (itimer-value itimer) idle-time)) | |
696 (min next-wakeup (itimer-value itimer))) | |
697 (min next-wakeup (itimer-value itimer)))) | |
698 (and (itimer-is-idle itimer) | |
699 (set-itimer-recorded-run-time itimer (current-time))) | |
700 ;; itimer has expired, we must call its function. | |
701 ;; protect our local vars from the itimer function. | |
702 ;; allow keyboard quit to occur, but catch and report it. | |
703 ;; provide the variable `current-itimer' in case the function | |
704 ;; is interested. | |
705 (unwind-protect | |
706 (condition-case condition-data | |
707 (save-match-data | |
708 (let* ((current-itimer itimer) | |
709 (quit-flag nil) | |
710 (inhibit-quit nil) | |
711 ;; for FSF Emacs timer.el emulation under XEmacs. | |
712 ;; eldoc expect this to be done, apparently. | |
713 (this-command nil) | |
714 itimer itimers time-elapsed) | |
715 (if (itimer-uses-arguments current-itimer) | |
716 (apply (itimer-function current-itimer) | |
717 (itimer-function-arguments current-itimer)) | |
718 (funcall (itimer-function current-itimer))))) | |
719 (error (message "itimer \"%s\" signaled: %s" (itimer-name itimer) | |
720 (prin1-to-string condition-data))) | |
721 (quit (message "itimer \"%s\" quit" (itimer-name itimer)))) | |
722 ;; restart the itimer if we should, otherwise delete it. | |
723 (if (null (itimer-restart itimer)) | |
724 (delete-itimer itimer) | |
725 (set-itimer-value-internal itimer (itimer-restart itimer)) | |
726 (setq next-wakeup (min next-wakeup (itimer-value itimer)))))) | |
727 (setq itimers (cdr itimers))) | |
728 ;; if user is editing itimers, update displayed info | |
729 (if (eq major-mode 'itimer-edit-mode) | |
730 (list-itimers)) | |
731 next-wakeup )) | |
732 | |
733 (defun itimer-process-filter (process string) | 534 (defun itimer-process-filter (process string) |
734 ;; If the itimer process dies and generates output while doing | 535 (error "itimer-process-filter is not used in XEmacs") |
735 ;; so, we may be called before the process-sentinel. Sanity | 536 ; ;; If the itimer process dies and generates output while doing |
736 ;; check the output just in case... | 537 ; ;; so, we may be called before the process-sentinel. Sanity |
737 (if (not (string-match "^[0-9]" string)) | 538 ; ;; check the output just in case... |
738 (progn (message "itimer process gave odd output: %s" string) | 539 ; (if (not (string-match "^[0-9]" string)) |
739 ;; it may be still alive and waiting for input | 540 ; (progn (message "itimer process gave odd output: %s" string) |
740 (process-send-string itimer-process "3\n")) | 541 ; ;; it may be still alive and waiting for input |
741 ;; if there are no active itimers, return quickly. | 542 ; (process-send-string itimer-process "3\n")) |
742 (if itimer-list | 543 ; ;; if there are no active itimers, return quickly. |
743 (let ((wakeup nil)) | 544 ; (if itimer-list |
744 (unwind-protect | 545 ; (let ((time-elapsed (string-to-int string)) |
745 (setq wakeup (itimer-run-expired-timers (string-to-int string))) | 546 ; (itimers itimer-list) |
746 (and (null wakeup) (process-send-string process "1\n"))) | 547 ; (itimer) |
747 (setq itimer-next-wakeup wakeup)) | 548 ; ;; process filters can be hit by stray C-g's from the user, |
748 (setq itimer-next-wakeup 600)) | 549 ; ;; so we must protect this stuff appropriately. |
749 ;; tell itimer-process when to wakeup again | 550 ; ;; Quit's are allowed from within itimer functions, but we |
750 (process-send-string itimer-process | 551 ; ;; catch them. |
751 (concat (int-to-string itimer-next-wakeup) | 552 ; (inhibit-quit t)) |
752 "\n")))) | 553 ; (setq itimer-process-next-wakeup 600) |
554 ; (while itimers | |
555 ; (setq itimer (car itimers)) | |
556 ; (set-itimer-value itimer (max 0 (- (itimer-value itimer) time-elapsed)) t) | |
557 ; (if (> (itimer-value itimer) 0) | |
558 ; (setq itimer-process-next-wakeup | |
559 ; (min itimer-process-next-wakeup (itimer-value itimer))) | |
560 ; ;; itimer has expired, we must call its function. | |
561 ; ;; protect our local vars from the itimer function. | |
562 ; ;; allow keyboard quit to occur, but catch and report it. | |
563 ; ;; provide the variable `current-itimer' in case the function | |
564 ; ;; is interested. | |
565 ; (condition-case condition-data | |
566 ; (let* ((current-itimer itimer) | |
567 ; itimer itimers time-elapsed | |
568 ; quit-flag inhibit-quit) | |
569 ; (funcall (itimer-function current-itimer))) | |
570 ; (error (message "itimer \"%s\" signaled: %s" (itimer-name itimer) | |
571 ; (prin1-to-string condition-data))) | |
572 ; (quit (message "itimer \"%s\" quit" (itimer-name itimer)))) | |
573 ; ;; restart the itimer if we should, otherwise delete it. | |
574 ; (if (null (itimer-restart itimer)) | |
575 ; (delete-itimer itimer) | |
576 ; (set-itimer-value itimer (itimer-restart itimer) t) | |
577 ; (setq itimer-process-next-wakeup | |
578 ; (min itimer-process-next-wakeup (itimer-value itimer))))) | |
579 ; (setq itimers (cdr itimers))) | |
580 ; ;; if user is editing itimers, update displayed info | |
581 ; (if (eq major-mode 'itimer-edit-mode) | |
582 ; (list-itimers))) | |
583 ; (setq itimer-process-next-wakeup 600)) | |
584 ; ;; tell itimer-process when to wakeup again | |
585 ; (process-send-string itimer-process | |
586 ; (concat (int-to-string itimer-process-next-wakeup) | |
587 ; "\n"))) | |
588 ) | |
753 | 589 |
754 (defun itimer-process-sentinel (process message) | 590 (defun itimer-process-sentinel (process message) |
591 (error "itimer-process-sentinel is not used in XEmacs") | |
592 ; (let ((inhibit-quit t)) | |
593 ; (if (eq (process-status process) 'stop) | |
594 ; (continue-process process) | |
595 ; ;; not stopped, so it must have died. | |
596 ; ;; cleanup first... | |
597 ; (delete-process process) | |
598 ; (setq itimer-process nil) | |
599 ; ;; now, if there are any active itimers then we need to immediately | |
600 ; ;; start another itimer process, otherwise we can wait until the next | |
601 ; ;; start-itimer call, which will start one automatically. | |
602 ; (if (null itimer-list) | |
603 ; () | |
604 ; ;; there may have been an error message in the echo area; | |
605 ; ;; give the user at least a little time to read it. | |
606 ; (sit-for 2) | |
607 ; (message "itimer process %s... respawning." (substring message 0 -1)) | |
608 ; (itimer-process-start)))) | |
609 ) | |
610 | |
611 (defun itimer-process-start () | |
612 (error "itimer-process-start is not used in XEmacs") | |
613 ; (let ((inhibit-quit t) | |
614 ; (process-connection-type nil)) | |
615 ; (setq itimer-process (start-process "itimer" nil "itimer")) | |
616 ; (process-kill-without-query itimer-process) | |
617 ; (set-process-filter itimer-process 'itimer-process-filter) | |
618 ; (set-process-sentinel itimer-process 'itimer-process-sentinel) | |
619 ; ;; Tell itimer process to wake up quickly, so that a correct wakeup | |
620 ; ;; time can be computed. Zero instead of one here loses because of | |
621 ; ;; underlying itimer implementations that use 0 to mean `disable the | |
622 ; ;; itimer'. | |
623 ; (setq itimer-process-next-wakeup 1) | |
624 ; (process-send-string itimer-process "1\n")) | |
625 ) | |
626 | |
627 (defun itimer-process-wakeup () | |
628 (error "itimer-process-wakeup is not used in XEmacs") | |
629 ; (interrupt-process itimer-process) | |
630 ; (accept-process-output) | |
631 ) | |
632 | |
633 | |
634 ;; XEmacs-specific code | |
635 | |
636 (defun activate-itimer (itimer) | |
755 (let ((inhibit-quit t)) | 637 (let ((inhibit-quit t)) |
756 (if (eq (process-status process) 'stop) | 638 (set-itimer-id itimer |
757 (continue-process process) | 639 (add-timeout (itimer-value itimer) |
758 ;; not stopped, so it must have died. | 640 'itimer-callback |
759 ;; cleanup first... | 641 itimer |
760 (delete-process process) | 642 (itimer-restart itimer)))) |
761 (setq itimer-process nil) | 643 itimer) |
762 ;; now, if there are any active itimers then we need to immediately | 644 |
763 ;; start another itimer process, otherwise we can wait until the next | 645 (defun deactivate-itimer (itimer) |
764 ;; start-itimer call, which will start one automatically. | |
765 (if (null itimer-list) | |
766 () | |
767 ;; there may have been an error message in the echo area; | |
768 ;; give the user at least a little time to read it. | |
769 (sit-for 2) | |
770 (message "itimer process %s... respawning." (substring message 0 -1)) | |
771 (itimer-process-start))))) | |
772 | |
773 (defun itimer-process-start () | |
774 (let ((inhibit-quit t) | 646 (let ((inhibit-quit t) |
775 (process-connection-type nil)) | 647 (id (itimer-id itimer))) |
776 (setq itimer-process (start-process "itimer" nil "itimer")) | 648 (and id (disable-timeout id)) |
777 (process-kill-without-query itimer-process) | 649 (set-itimer-id itimer nil)) |
778 (set-process-filter itimer-process 'itimer-process-filter) | 650 itimer) |
779 (set-process-sentinel itimer-process 'itimer-process-sentinel) | 651 |
780 ;; Tell itimer process to wake up quickly, so that a correct | 652 (defun itimer-callback (current-itimer) |
781 ;; wakeup time can be computed. Zero loses because of | 653 (funcall (itimer-function current-itimer))) |
782 ;; underlying itimer implementations that use 0 to mean | 654 |
783 ;; `disable the itimer'. | 655 |
784 (setq itimer-next-wakeup itimer-short-interval) | 656 ;;; itimer-driven auto-saves |
785 (process-send-string itimer-process | 657 |
786 (format "%s\n" itimer-next-wakeup)))) | 658 ;jwz: this is preloaded so don't ;;;###autoload |
787 | 659 (defvar auto-save-timeout 30 |
788 (defun itimer-process-wakeup () | 660 "*Number of seconds idle time before auto-save. |
789 (interrupt-process itimer-process) | 661 Zero or nil means disable auto-saving due to idleness. |
790 (accept-process-output)) | 662 |
791 | 663 The actual amount of idle time between auto-saves is logarithmically related |
792 (defun itimer-timer-start () | 664 to the size of the current buffer. This variable is the number of seconds |
793 (let ((inhibit-quit t)) | 665 after which an auto-save will happen when the current buffer is 50k or less; |
794 (setq itimer-next-wakeup itimer-short-interval | 666 the timeout will be 2 1/4 times this in a 200k buffer, 3 3/4 times this in a |
795 itimer-timer-last-wakeup (current-time) | 667 1000k buffer, and 4 1/2 times this in a 2000k buffer. |
796 itimer-timer (add-timeout itimer-short-interval | 668 |
797 'itimer-timer-driver nil nil)))) | 669 See also the variable `auto-save-interval', which controls auto-saving based |
798 | 670 on the number of characters typed.") |
799 (defun itimer-timer-wakeup () | 671 |
800 (let ((inhibit-quit t)) | 672 ;jwz: this is preloaded so don't ;;;###autoload |
801 (cond ((fboundp 'disable-timeout) | 673 (defvar auto-gc-threshold (/ gc-cons-threshold 3) |
802 (disable-timeout itimer-timer)) | 674 "*GC when this many bytes have been consed since the last GC, |
803 ((fboundp 'cancel-timer) | 675 and the user has been idle for `auto-save-timeout' seconds.") |
804 (cancel-timer itimer-timer))) | 676 |
805 (setq itimer-timer (add-timeout itimer-short-interval | 677 (defun auto-save-itimer () |
806 'itimer-timer-driver nil nil)))) | 678 "For use as a itimer callback function. |
807 | 679 Auto-saves and garbage-collects based on the size of the current buffer |
808 (defun itimer-time-difference (t1 t2) | 680 and the value of `auto-save-timeout', `auto-gc-threshold', and the current |
809 (let (usecs secs 65536-secs carry) | 681 keyboard idle-time." |
810 (setq usecs (- (nth 2 t1) (nth 2 t2))) | 682 (if (or (null auto-save-timeout) |
811 (if (< usecs 0) | 683 (<= auto-save-timeout 0) |
812 (setq carry 1 | 684 (eq (minibuffer-window) (selected-window))) |
813 usecs (+ usecs 1000000)) | 685 nil |
814 (setq carry 0)) | 686 (let ((buf-size (1+ (ash (buffer-size) -8))) |
815 (setq secs (- (nth 1 t1) (nth 1 t2) carry)) | 687 (delay-level 0) |
816 (if (< secs 0) | 688 (now (current-time)) |
817 (setq carry 1 | 689 delay) |
818 secs (+ secs 65536)) | 690 (while (> buf-size 64) |
819 (setq carry 0)) | 691 (setq delay-level (1+ delay-level) |
820 (setq 65536-secs (- (nth 0 t1) (nth 0 t2) carry)) | 692 buf-size (- buf-size (ash buf-size -2)))) |
821 ;; loses for interval larger than the maximum signed Lisp integer. | 693 (if (< delay-level 4) |
822 ;; can't really be helped. | 694 (setq delay-level 4)) |
823 (+ (* 65536-secs 65536) | 695 ;; delay_level is 4 for files under around 50k, 7 at 100k, 9 at 200k, |
824 secs | 696 ;; 11 at 300k, and 12 at 500k, 15 at 1 meg, and 17 at 2 meg. |
825 (/ usecs (if (featurep 'lisp-float-type) 1e6 1000000))))) | 697 (setq delay (/ (* delay-level auto-save-timeout) 4)) |
826 | 698 (let ((idle-time (if (or (not (consp last-input-time)) |
827 (defun itimer-timer-driver (&rest ignored) | 699 (/= (car now) (car last-input-time))) |
828 ;; inhibit quit because if the user quits at an inopportune | 700 (1+ delay) |
829 ;; time, the timer process won't bne launched again and the | 701 (- (car (cdr now)) (cdr last-input-time))))) |
830 ;; system stops working. itimer-run-expired-timers allows | 702 (and (> idle-time delay) |
831 ;; individual timer function to be aborted, so the user can | 703 (do-auto-save)) |
832 ;; escape a feral timer function. | 704 (and (> idle-time auto-save-timeout) |
833 (let* ((inhibit-quit t) | 705 (> (consing-since-gc) auto-gc-threshold) |
834 (now (current-time)) | 706 (garbage-collect))))) |
835 (elapsed (itimer-time-difference now itimer-timer-last-wakeup)) | 707 ;; Look at the itimer that's currently running; if the user has changed |
836 (sleep nil)) | 708 ;; the value of auto-save-timeout, modify this itimer to have the correct |
837 (setq itimer-timer-last-wakeup now) | 709 ;; restart time. There will be some latency between when the user changes |
838 (unwind-protect | 710 ;; this variable and when it takes effect, but it will happen eventually. |
839 (setq sleep (itimer-run-expired-timers elapsed)) | 711 (let ((self (get-itimer "auto-save"))) |
840 (and (null sleep) (add-timeout 1 'itimer-timer-driver nil nil))) | 712 (or self (error "auto-save-itimer can't find itself")) |
841 (setq itimer-next-wakeup sleep | 713 (if (and auto-save-timeout (> auto-save-timeout 4)) |
842 itimer-timer (add-timeout sleep 'itimer-timer-driver nil nil)))) | 714 (or (= (itimer-restart self) (/ auto-save-timeout 4)) |
843 | 715 (set-itimer-restart self (/ auto-save-timeout 4))))) |
844 (defun itimer-driver-start () | 716 nil) |
845 (if (fboundp 'add-timeout) | 717 |
846 (itimer-timer-start) | 718 (defun itimer-init-auto-gc () |
847 (itimer-process-start))) | 719 (or noninteractive ; may be being run from after-init-hook in -batch mode. |
848 | 720 (get-itimer "auto-save") |
849 (defun itimer-driver-wakeup () | 721 ;; the time here is just the first interval; if the user changes it |
850 (if (fboundp 'add-timeout) | 722 ;; later, it will adjust. |
851 (itimer-timer-wakeup) | 723 (let ((time (max 2 (/ (or auto-save-timeout 30) 4)))) |
852 (itimer-process-wakeup))) | 724 (start-itimer "auto-save" 'auto-save-itimer time time)))) |
725 | |
726 (cond (purify-flag | |
727 ;; This file is being preloaded into an emacs about to be dumped. | |
728 ;; So arrange for the auto-save itimer to be started once emacs | |
729 ;; is launched. | |
730 (add-hook 'after-init-hook 'itimer-init-auto-gc)) | |
731 (t | |
732 ;; Otherwise, this file is being loaded into a normal, interactive | |
733 ;; emacs. Start the auto-save timer now. | |
734 (itimer-init-auto-gc))) | |
735 | |
736 | |
737 (provide 'itimer) |