Mercurial > hg > xemacs-beta
comparison lisp/prim/itimer.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; Interval timers for XEmacs | |
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. | |
5 ;;; | |
6 ;; This file is part of XEmacs. | |
7 | |
8 ;; XEmacs is free software; you can redistribute it and/or modify it | |
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 Free | |
20 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | |
22 ;;; Synched up with: Not in FSF. | |
23 | |
24 ;;; | |
25 ;;; Send bug reports to kyle@uunet.uu.net. | |
26 | |
27 ;; The original v18 version of this file worked by having an external program | |
28 ;; wake up once a second to generate an interrupt for emacs; then an emacs | |
29 ;; process filter was used to schedule timers. | |
30 ;; | |
31 ;; This version works by associating with each timer a "timeout" object, | |
32 ;; since the XEmacs/Lucid Emacs event loop has the concept of timers built | |
33 ;; in to it. There is no single scheduler function; instead, each timer | |
34 ;; re-sets itself as it is invoked. | |
35 | |
36 ;; `itimer' feature means Emacs-Lisp programers get: | |
37 ;; itimerp, itimer-value, itimer-restart, itimer-function, | |
38 ;; set-itimer-value, set-itimer-restart, set-itimer-function | |
39 ;; get-itimer, start-itimer, read-itimer, delete-itimer | |
40 ;; | |
41 ;; Interactive users get these commands: | |
42 ;; edit-itimers, list-itimers, start-itimer | |
43 ;; | |
44 ;; See the doc strings of these functions for more information. | |
45 | |
46 (defvar itimer-version "1.00" | |
47 "Version number of the itimer package.") | |
48 | |
49 (defvar itimer-list nil | |
50 "List of all active itimers.") | |
51 | |
52 ;; not needed in XEmacs | |
53 ;(defvar itimer-process nil | |
54 ; "Process that drives all itimers.") | |
55 | |
56 ;; This value is maintained internally; it does not determine itimer | |
57 ;; granularity. Itimer granularity is 1 second, plus delays due to | |
58 ;; system and Emacs internal activity that delay dealing with process | |
59 ;; output. | |
60 ;; not needed in XEmacs | |
61 ;(defvar itimer-process-next-wakeup 1 | |
62 ; "Itimer process will wakeup to service running itimers within this | |
63 ;many seconds.") | |
64 | |
65 (defvar itimer-edit-map nil | |
66 "Keymap used when in Itimer Edit mode.") | |
67 | |
68 (if itimer-edit-map | |
69 () | |
70 (setq itimer-edit-map (make-sparse-keymap)) | |
71 (define-key itimer-edit-map "s" 'itimer-edit-set-field) | |
72 (define-key itimer-edit-map "d" 'itimer-edit-delete-itimer) | |
73 (define-key itimer-edit-map "q" 'itimer-edit-quit) | |
74 (define-key itimer-edit-map "\t" 'itimer-edit-next-field) | |
75 (define-key itimer-edit-map " " 'next-line) | |
76 (define-key itimer-edit-map "n" 'next-line) | |
77 (define-key itimer-edit-map "p" 'previous-line) | |
78 (define-key itimer-edit-map "\C-?" 'itimer-edit-previous-field) | |
79 (define-key itimer-edit-map "x" 'start-itimer) | |
80 (define-key itimer-edit-map "?" 'itimer-edit-help)) | |
81 | |
82 (defvar itimer-edit-start-marker nil) | |
83 | |
84 ;; macros must come first... or byte-compile'd code will throw back its | |
85 ;; head and scream. | |
86 | |
87 (defmacro itimer-decf (variable) | |
88 (list 'setq variable (list '1- variable))) | |
89 | |
90 (defmacro itimer-incf (variable) | |
91 (list 'setq variable (list '1+ variable))) | |
92 | |
93 (defmacro itimer-signum (n) | |
94 (list 'if (list '> n 0) 1 | |
95 (list 'if (list 'zerop n) 0 -1))) | |
96 | |
97 ;; Itimer access functions should behave as if they were subrs. These | |
98 ;; macros are used to check the arguments to the itimer functions and | |
99 ;; signal errors appropriately if the arguments are not valid. | |
100 | |
101 (defmacro check-itimer (var) | |
102 "If VAR is not bound to an itimer, signal wrong-type-argument. | |
103 This is a macro." | |
104 (list 'setq var | |
105 (list 'if (list 'itimerp var) var | |
106 (list 'signal ''wrong-type-argument | |
107 (list 'list ''itimerp var))))) | |
108 | |
109 (defmacro check-itimer-coerce-string (var) | |
110 "If VAR is not bound to a string, look up the itimer that it names and | |
111 bind VAR to it. Otherwise if VAR is not bound to an itimer, signal | |
112 wrong-type-argument. This is a macro." | |
113 (list 'setq var | |
114 (list 'cond | |
115 (list (list 'itimerp var) var) | |
116 (list (list 'stringp var) (list 'get-itimer var)) | |
117 (list t (list 'signal ''wrong-type-argument | |
118 (list 'list ''string-or-itimer-p var)))))) | |
119 | |
120 (defmacro itimer-check-natnum (var) | |
121 "If VAR is not bound to a non-negative number, signal wrong-type-argument. | |
122 This is a macro." | |
123 (list 'setq var | |
124 (list 'if (list 'natnump var) var | |
125 (list 'signal ''wrong-type-argument | |
126 (list 'list ''natnump var))))) | |
127 | |
128 (defmacro itimer-check-string (var) | |
129 "If VAR is not bound to a string, signal wrong-type-argument. | |
130 This is a macro." | |
131 (list 'setq var | |
132 (list 'if (list 'stringp var) var | |
133 (list 'signal ''wrong-type-argument | |
134 (list 'list ''stringp var))))) | |
135 | |
136 ;; Functions to access and modify itimer attributes. | |
137 | |
138 (defun itimerp (obj) | |
139 "Returns non-nil iff OBJ is an itimer." | |
140 (and (consp obj) (stringp (car obj)) (eq (length obj) | |
141 5 ; for XEmacs | |
142 ;4 ; original version | |
143 ))) | |
144 | |
145 (defun itimer-name (itimer) | |
146 "Returns the name of ITIMER." | |
147 (check-itimer itimer) | |
148 (car itimer)) | |
149 | |
150 (defun itimer-value (itimer) | |
151 "Returns the number of seconds until ITIMER expires." | |
152 (check-itimer itimer) | |
153 (nth 1 itimer)) | |
154 | |
155 (defun itimer-restart (itimer) | |
156 "Returns the value to which ITIMER will be set at restart. | |
157 nil is returned if this itimer doesn't restart." | |
158 (check-itimer itimer) | |
159 (nth 2 itimer)) | |
160 | |
161 (defun itimer-function (itimer) | |
162 "Returns the function of ITIMER. | |
163 This function is called each time ITIMER expires." | |
164 (check-itimer itimer) | |
165 (nth 3 itimer)) | |
166 | |
167 ;; XEmacs-specific | |
168 (defun itimer-id (itimer) | |
169 "Returns the timeout-id of ITIMER." | |
170 (check-itimer itimer) | |
171 (nth 4 itimer)) | |
172 | |
173 (defun set-itimer-value (itimer value | |
174 ;; XEmacs doesn't need this | |
175 ;; &optional nowakeup | |
176 ) | |
177 "Set the timeout value of ITIMER to be VALUE. | |
178 Itimer will expire is this many seconds. | |
179 Returns VALUE." | |
180 ;; Optional third arg NOWAKEUP non-nil means do not wakeup the itimer | |
181 ;; process to recompute a correct wakeup time, even if it means this | |
182 ;; itimer will expire late. itimer-process-filter uses this option. | |
183 ;; This is not meant for ordinary usage, which is why it is not | |
184 ;; mentioned in the doc string. | |
185 (check-itimer itimer) | |
186 (itimer-check-natnum value) | |
187 (let ((inhibit-quit t)) | |
188 | |
189 ; ;; If we're allowed to wakeup the itimer process, | |
190 ; ;; and the itimer process's next wakeup needs to be recomputed, | |
191 ; ;; and the itimer is running, then we wakeup the itimer process. | |
192 ; (or (and (not nowakeup) (< value itimer-process-next-wakeup) | |
193 ; (get-itimer (itimer-name itimer)) | |
194 ; (progn (itimer-process-wakeup) | |
195 ; (setcar (cdr itimer) value) | |
196 ; (itimer-process-wakeup))) | |
197 ; (setcar (cdr itimer) value)) | |
198 | |
199 ;; the XEmacs way: | |
200 (if (itimer-id itimer) | |
201 (deactivate-itimer itimer)) | |
202 (setcar (cdr itimer) value) | |
203 (activate-itimer itimer) | |
204 | |
205 value)) | |
206 | |
207 (defun set-itimer-restart (itimer restart) | |
208 "Set the restart value of ITIMER to be RESTART. | |
209 If RESTART is nil, ITIMER will not restart when it expires. | |
210 Returns RESTART." | |
211 (check-itimer itimer) | |
212 (if restart (itimer-check-natnum restart)) | |
213 (and restart (< restart 1) (signal 'args-out-of-range (list restart))) | |
214 ;; (setcar (cdr (cdr itimer)) restart) | |
215 ;; the XEmacs way | |
216 (let ((was-active (itimer-id itimer)) | |
217 (inhibit-quit t)) | |
218 (if was-active | |
219 (deactivate-itimer itimer)) | |
220 (setcar (cdr (cdr itimer)) restart) | |
221 (if was-active | |
222 (progn | |
223 (setcar (cdr itimer) restart) | |
224 (if restart | |
225 (activate-itimer itimer))))) | |
226 restart) | |
227 | |
228 (defun set-itimer-function (itimer function) | |
229 "Set the function of ITIMER to be FUNCTION. | |
230 FUNCTION will be called when itimer expires. | |
231 Returns FUNCTION." | |
232 (check-itimer itimer) | |
233 (setcar (cdr (cdr (cdr itimer))) function)) | |
234 | |
235 ;; XEmacs-specific | |
236 (defun set-itimer-id (itimer id) | |
237 (check-itimer itimer) | |
238 (setcar (cdr (cdr (cdr (cdr itimer)))) id)) | |
239 | |
240 (defun get-itimer (name) | |
241 "Return itimer named NAME, or nil if there is none." | |
242 (itimer-check-string name) | |
243 (assoc name itimer-list)) | |
244 | |
245 (defun read-itimer (prompt &optional initial-input) | |
246 "Read the name of an itimer from the minibuffer and return the itimer | |
247 associated with that name. The user is prompted with PROMPT. | |
248 Optional second arg INITIAL-INPUT non-nil is inserted into the | |
249 minibuffer as initial user input." | |
250 (get-itimer (completing-read prompt itimer-list nil 'confirm initial-input))) | |
251 | |
252 (defun delete-itimer (itimer) | |
253 "Deletes ITIMER. ITIMER may be an itimer or the name of one." | |
254 (check-itimer-coerce-string itimer) | |
255 (deactivate-itimer itimer) ;; for XEmacs | |
256 (setq itimer-list (delq itimer itimer-list))) | |
257 | |
258 ;jwz: this is preloaded so don't ;;;###autoload | |
259 (defun start-itimer (name function value &optional restart) | |
260 "Start an itimer. | |
261 Args are NAME, FUNCTION, VALUE &optional RESTART. | |
262 NAME is an identifier for the itimer. It must be a string. If an itimer | |
263 already exists with this name, NAME will be modified slightly to until | |
264 it is unique. | |
265 FUNCTION should be a function (or symbol naming one) of no arguments. It | |
266 will be called each time the itimer expires. The function can access | |
267 itimer that invoked it through the variable `current-itimer'. | |
268 VALUE is the number of seconds until this itimer expires. | |
269 Optional fourth arg RESTART non-nil means that this itimer should be | |
270 restarted automatically after its function is called. Normally an itimer | |
271 is deleted at expiration after its function has returned. | |
272 If non-nil RESTART should be a number indicating the value at which the | |
273 itimer should be set at restart time. | |
274 Returns the newly created itimer." | |
275 (interactive | |
276 (list (completing-read "Start itimer: " itimer-list) | |
277 (read (completing-read "Itimer function: " obarray 'fboundp)) | |
278 (let (value) | |
279 (while (not (natnump value)) | |
280 (setq value (read-from-minibuffer "Itimer value: " nil nil t))) | |
281 value) | |
282 (let ((restart t)) | |
283 (while (and restart (not (natnump restart))) | |
284 (setq restart (read-from-minibuffer "Itimer restart: " nil nil t))) | |
285 restart))) | |
286 (itimer-check-string name) | |
287 (itimer-check-natnum value) | |
288 (if restart (itimer-check-natnum restart)) | |
289 ;; Make proposed itimer name unique if it's not already. | |
290 (let ((oname name) | |
291 (num 2)) | |
292 (while (get-itimer name) | |
293 (setq name (concat oname "<" num ">")) | |
294 (itimer-incf num))) | |
295 ; ;; If there's no itimer process, start one now. | |
296 ; ;; Otherwise wake up the itimer process so that seconds slept before | |
297 ; ;; the new itimer is created won't be counted against it. | |
298 ; (if itimer-process | |
299 ; (itimer-process-wakeup) | |
300 ; (itimer-process-start)) | |
301 (let ((inhibit-quit t)) | |
302 ;; add the itimer to the global list | |
303 (setq itimer-list | |
304 (cons (list name value restart function nil) ; extra slot for XEmacs | |
305 itimer-list)) | |
306 ; ;; If the itimer process is scheduled to wake up too late for the itimer | |
307 ; ;; we wake it up to calculate a correct wakeup value giving consideration | |
308 ; ;; to the newly added itimer. | |
309 ; (if (< value itimer-process-next-wakeup) | |
310 ; (itimer-process-wakeup))) | |
311 ;; for XEmacs | |
312 (activate-itimer (car itimer-list)) | |
313 ) | |
314 (car itimer-list)) | |
315 | |
316 ;; User level functions to list and modify existing itimers. | |
317 ;; Itimer Edit major mode, and the editing commands thereof. | |
318 | |
319 (defun list-itimers () | |
320 "Pop up a buffer containing a list of all itimers. | |
321 The major mode of the buffer is Itimer Edit mode. This major mode provides | |
322 commands to manipulate itimers; see the documentation for | |
323 `itimer-edit-mode' for more information." | |
324 (interactive) | |
325 (let* ((buf (get-buffer-create "*Itimer List*")) | |
326 (opoint (point)) | |
327 (standard-output buf) | |
328 (itimers (reverse itimer-list))) | |
329 (set-buffer buf) | |
330 (itimer-edit-mode) | |
331 (setq buffer-read-only nil) | |
332 (erase-buffer) | |
333 (insert "Name Value Restart Function\n" | |
334 "---- ----- ------- --------") | |
335 (if (null itimer-edit-start-marker) | |
336 (setq itimer-edit-start-marker (point))) | |
337 (while itimers | |
338 (newline 1) | |
339 (prin1 (itimer-name (car itimers))) | |
340 (tab-to-tab-stop) | |
341 (prin1 (itimer-value (car itimers))) | |
342 (tab-to-tab-stop) | |
343 (prin1 (itimer-restart (car itimers))) | |
344 (tab-to-tab-stop) | |
345 (prin1 (itimer-function (car itimers))) | |
346 (setq itimers (cdr itimers))) | |
347 ;; restore point | |
348 (goto-char opoint) | |
349 (if (< (point) itimer-edit-start-marker) | |
350 (goto-char itimer-edit-start-marker)) | |
351 (setq buffer-read-only t) | |
352 (display-buffer buf))) | |
353 | |
354 (defun edit-itimers () | |
355 "Display a list of all itimers and select it for editing. | |
356 The major mode of the buffer containing the listing is Itimer Edit mode. | |
357 This major mode provides commands to manipulate itimers; see the documentation | |
358 for `itimer-edit-mode' for more information." | |
359 (interactive) | |
360 ;; since user is editing, make sure displayed data is reasonably up-to-date | |
361 ; (if itimer-process | |
362 ; (itimer-process-wakeup)) | |
363 (list-itimers) | |
364 (select-window (get-buffer-window "*Itimer List*")) | |
365 (goto-char itimer-edit-start-marker) | |
366 (if itimer-list | |
367 (progn | |
368 (forward-sexp 2) | |
369 (backward-sexp))) | |
370 (message "type q to quit, ? for help")) | |
371 | |
372 ;; no point in making this interactive. | |
373 (defun itimer-edit-mode () | |
374 "Major mode for manipulating itimers. | |
375 Atrributes of running itimers are changed by moving the cursor to the | |
376 desired field and typing `s' to set that field. The field will then be | |
377 set to the value read from the minibuffer. | |
378 | |
379 Commands: | |
380 TAB move forward a field | |
381 DEL move backward a field | |
382 s set a field | |
383 d delete the selected itimer | |
384 x start a new itimer | |
385 ? help" | |
386 (kill-all-local-variables) | |
387 (make-local-variable 'tab-stop-list) | |
388 (setq major-mode 'itimer-edit-mode | |
389 mode-name "Itimer Edit" | |
390 truncate-lines t | |
391 tab-stop-list '(22 32 42)) | |
392 (abbrev-mode 0) | |
393 (auto-fill-mode 0) | |
394 (buffer-disable-undo (current-buffer)) | |
395 (use-local-map itimer-edit-map) | |
396 (and lisp-mode-syntax-table (set-syntax-table lisp-mode-syntax-table))) | |
397 | |
398 (put 'itimer-edit-mode 'mode-class 'special) | |
399 | |
400 (defun itimer-edit-help () | |
401 "Help function for Itimer Edit." | |
402 (interactive) | |
403 (if (eq last-command 'itimer-edit-help) | |
404 (describe-mode) | |
405 (message "TAB, DEL select fields, (s)et field, (d)elete itimer (type ? for more help)"))) | |
406 | |
407 (defun itimer-edit-quit () | |
408 "End Itimer Edit." | |
409 (interactive) | |
410 (bury-buffer (current-buffer)) | |
411 (if (one-window-p t) | |
412 (switch-to-buffer (other-buffer (current-buffer))) | |
413 (delete-window))) | |
414 | |
415 (defun itimer-edit-set-field () | |
416 (interactive) | |
417 ;; First two lines in list buffer are headers. | |
418 ;; Cry out against the luser who attempts to change a field there. | |
419 (if (<= (point) itimer-edit-start-marker) | |
420 (error "")) | |
421 ;; field-value must be initialized to be something other than a | |
422 ;; number, symbol, or list. | |
423 (let (itimer field (field-value "")) | |
424 (setq itimer (save-excursion | |
425 ;; read the name of the itimer from the beginning of | |
426 ;; the current line. | |
427 (beginning-of-line) | |
428 (get-itimer (read (current-buffer)))) | |
429 field (save-excursion | |
430 (itimer-edit-beginning-of-field) | |
431 (let ((opoint (point)) | |
432 (n 0)) | |
433 ;; count the number of sexprs until we reach the cursor | |
434 ;; and use this info to determine which field the user | |
435 ;; wants to modify. | |
436 (beginning-of-line) | |
437 (while (and (>= opoint (point)) (< n 4)) | |
438 (forward-sexp 2) | |
439 (backward-sexp) | |
440 (itimer-incf n)) | |
441 (cond ((eq n 1) (error "Cannot change itimer name.")) | |
442 ((eq n 2) 'value) | |
443 ((eq n 3) 'restart) | |
444 ((eq n 4) 'function))))) | |
445 (cond ((eq field 'value) | |
446 ;; XEmacs: rewritten for I18N3 snarfing | |
447 (while (not (natnump field-value)) | |
448 (setq field-value (read-from-minibuffer "Set itimer value: " | |
449 nil nil t)))) | |
450 ((eq field 'restart) | |
451 (while (and field-value (not (natnump field-value))) | |
452 (setq field-value (read-from-minibuffer "Set itimer restart: " | |
453 nil nil t)))) | |
454 ((eq field 'function) | |
455 (while (not (or (and (symbolp field-value) (fboundp field-value)) | |
456 (and (consp field-value) | |
457 (memq (car field-value) '(lambda macro))))) | |
458 (setq field-value | |
459 (read (completing-read "Set itimer function: " | |
460 obarray 'fboundp nil)))))) | |
461 ;; set the itimer field | |
462 (funcall (intern (concat "set-itimer-" (symbol-name field))) | |
463 itimer field-value) | |
464 ;; move to beginning of field to be changed | |
465 (itimer-edit-beginning-of-field) | |
466 ;; modify the list buffer to reflect the change. | |
467 (let (buffer-read-only kill-ring) | |
468 (kill-sexp 1) | |
469 (kill-region (point) (progn (skip-chars-forward " \t") (point))) | |
470 (prin1 field-value (current-buffer)) | |
471 (if (not (eolp)) | |
472 (tab-to-tab-stop)) | |
473 (backward-sexp)))) | |
474 | |
475 (defun itimer-edit-delete-itimer () | |
476 (interactive) | |
477 ;; First two lines in list buffer are headers. | |
478 ;; Cry out against the luser who attempts to change a field there. | |
479 (if (<= (point) itimer-edit-start-marker) | |
480 (error "")) | |
481 (delete-itimer | |
482 (read-itimer "Delete itimer: " | |
483 (save-excursion (beginning-of-line) (read (current-buffer))))) | |
484 ;; update list information | |
485 (list-itimers)) | |
486 | |
487 (defun itimer-edit-next-field (count) | |
488 (interactive "p") | |
489 (itimer-edit-beginning-of-field) | |
490 (cond ((> (itimer-signum count) 0) | |
491 (while (not (zerop count)) | |
492 (forward-sexp) | |
493 ;; wrap from eob to itimer-edit-start-marker | |
494 (if (eobp) | |
495 (progn | |
496 (goto-char itimer-edit-start-marker) | |
497 (forward-sexp))) | |
498 (forward-sexp) | |
499 (backward-sexp) | |
500 ;; treat fields at beginning of line as if they weren't there. | |
501 (if (bolp) | |
502 (progn | |
503 (forward-sexp 2) | |
504 (backward-sexp))) | |
505 (itimer-decf count))) | |
506 ((< (itimer-signum count) 0) | |
507 (while (not (zerop count)) | |
508 (backward-sexp) | |
509 ;; treat fields at beginning of line as if they weren't there. | |
510 (if (bolp) | |
511 (backward-sexp)) | |
512 ;; wrap from itimer-edit-start-marker to field at eob. | |
513 (if (<= (point) itimer-edit-start-marker) | |
514 (progn | |
515 (goto-char (point-max)) | |
516 (backward-sexp))) | |
517 (itimer-incf count))))) | |
518 | |
519 (defun itimer-edit-previous-field (count) | |
520 (interactive "p") | |
521 (itimer-edit-next-field (- count))) | |
522 | |
523 (defun itimer-edit-beginning-of-field () | |
524 (let ((forw-back (save-excursion (forward-sexp) (backward-sexp) (point))) | |
525 (back (save-excursion (backward-sexp) (point)))) | |
526 (cond ((eq forw-back back) (backward-sexp)) | |
527 ((eq forw-back (point)) t) | |
528 (t (backward-sexp))))) | |
529 | |
530 | |
531 ;; internals of the itimer implementation. | |
532 | |
533 (defun itimer-process-filter (process string) | |
534 (error "itimer-process-filter is not used in XEmacs") | |
535 ; ;; If the itimer process dies and generates output while doing | |
536 ; ;; so, we may be called before the process-sentinel. Sanity | |
537 ; ;; check the output just in case... | |
538 ; (if (not (string-match "^[0-9]" string)) | |
539 ; (progn (message "itimer process gave odd output: %s" string) | |
540 ; ;; it may be still alive and waiting for input | |
541 ; (process-send-string itimer-process "3\n")) | |
542 ; ;; if there are no active itimers, return quickly. | |
543 ; (if itimer-list | |
544 ; (let ((time-elapsed (string-to-int string)) | |
545 ; (itimers itimer-list) | |
546 ; (itimer) | |
547 ; ;; process filters can be hit by stray C-g's from the user, | |
548 ; ;; so we must protect this stuff appropriately. | |
549 ; ;; Quit's are allowed from within itimer functions, but we | |
550 ; ;; catch them. | |
551 ; (inhibit-quit t)) | |
552 ; (setq itimer-process-next-wakeup 600) | |
553 ; (while itimers | |
554 ; (setq itimer (car itimers)) | |
555 ; (set-itimer-value itimer (max 0 (- (itimer-value itimer) time-elapsed)) t) | |
556 ; (if (> (itimer-value itimer) 0) | |
557 ; (setq itimer-process-next-wakeup | |
558 ; (min itimer-process-next-wakeup (itimer-value itimer))) | |
559 ; ;; itimer has expired, we must call its function. | |
560 ; ;; protect our local vars from the itimer function. | |
561 ; ;; allow keyboard quit to occur, but catch and report it. | |
562 ; ;; provide the variable `current-itimer' in case the function | |
563 ; ;; is interested. | |
564 ; (condition-case condition-data | |
565 ; (let* ((current-itimer itimer) | |
566 ; itimer itimers time-elapsed | |
567 ; quit-flag inhibit-quit) | |
568 ; (funcall (itimer-function current-itimer))) | |
569 ; (error (message "itimer \"%s\" signaled: %s" (itimer-name itimer) | |
570 ; (prin1-to-string condition-data))) | |
571 ; (quit (message "itimer \"%s\" quit" (itimer-name itimer)))) | |
572 ; ;; restart the itimer if we should, otherwise delete it. | |
573 ; (if (null (itimer-restart itimer)) | |
574 ; (delete-itimer itimer) | |
575 ; (set-itimer-value itimer (itimer-restart itimer) t) | |
576 ; (setq itimer-process-next-wakeup | |
577 ; (min itimer-process-next-wakeup (itimer-value itimer))))) | |
578 ; (setq itimers (cdr itimers))) | |
579 ; ;; if user is editing itimers, update displayed info | |
580 ; (if (eq major-mode 'itimer-edit-mode) | |
581 ; (list-itimers))) | |
582 ; (setq itimer-process-next-wakeup 600)) | |
583 ; ;; tell itimer-process when to wakeup again | |
584 ; (process-send-string itimer-process | |
585 ; (concat (int-to-string itimer-process-next-wakeup) | |
586 ; "\n"))) | |
587 ) | |
588 | |
589 (defun itimer-process-sentinel (process message) | |
590 (error "itimer-process-sentinel is not used in XEmacs") | |
591 ; (let ((inhibit-quit t)) | |
592 ; (if (eq (process-status process) 'stop) | |
593 ; (continue-process process) | |
594 ; ;; not stopped, so it must have died. | |
595 ; ;; cleanup first... | |
596 ; (delete-process process) | |
597 ; (setq itimer-process nil) | |
598 ; ;; now, if there are any active itimers then we need to immediately | |
599 ; ;; start another itimer process, otherwise we can wait until the next | |
600 ; ;; start-itimer call, which will start one automatically. | |
601 ; (if (null itimer-list) | |
602 ; () | |
603 ; ;; there may have been an error message in the echo area; | |
604 ; ;; give the user at least a little time to read it. | |
605 ; (sit-for 2) | |
606 ; (message "itimer process %s... respawning." (substring message 0 -1)) | |
607 ; (itimer-process-start)))) | |
608 ) | |
609 | |
610 (defun itimer-process-start () | |
611 (error "itimer-process-start is not used in XEmacs") | |
612 ; (let ((inhibit-quit t) | |
613 ; (process-connection-type nil)) | |
614 ; (setq itimer-process (start-process "itimer" nil "itimer")) | |
615 ; (process-kill-without-query itimer-process) | |
616 ; (set-process-filter itimer-process 'itimer-process-filter) | |
617 ; (set-process-sentinel itimer-process 'itimer-process-sentinel) | |
618 ; ;; Tell itimer process to wake up quickly, so that a correct wakeup | |
619 ; ;; time can be computed. Zero instead of one here loses because of | |
620 ; ;; underlying itimer implementations that use 0 to mean `disable the | |
621 ; ;; itimer'. | |
622 ; (setq itimer-process-next-wakeup 1) | |
623 ; (process-send-string itimer-process "1\n")) | |
624 ) | |
625 | |
626 (defun itimer-process-wakeup () | |
627 (error "itimer-process-wakeup is not used in XEmacs") | |
628 ; (interrupt-process itimer-process) | |
629 ; (accept-process-output) | |
630 ) | |
631 | |
632 | |
633 ;; XEmacs-specific code | |
634 | |
635 (defun activate-itimer (itimer) | |
636 (let ((inhibit-quit t)) | |
637 (set-itimer-id itimer | |
638 (add-timeout (itimer-value itimer) | |
639 'itimer-callback | |
640 itimer | |
641 (itimer-restart itimer)))) | |
642 itimer) | |
643 | |
644 (defun deactivate-itimer (itimer) | |
645 (let ((inhibit-quit t) | |
646 (id (itimer-id itimer))) | |
647 (and id (disable-timeout id)) | |
648 (set-itimer-id itimer nil)) | |
649 itimer) | |
650 | |
651 (defun itimer-callback (current-itimer) | |
652 (funcall (itimer-function current-itimer))) | |
653 | |
654 | |
655 ;;; itimer-driven auto-saves | |
656 | |
657 ;jwz: this is preloaded so don't ;;;###autoload | |
658 (defvar auto-save-timeout 30 | |
659 "*Number of seconds idle time before auto-save. | |
660 Zero or nil means disable auto-saving due to idleness. | |
661 | |
662 The actual amount of idle time between auto-saves is logarithmically related | |
663 to the size of the current buffer. This variable is the number of seconds | |
664 after which an auto-save will happen when the current buffer is 50k or less; | |
665 the timeout will be 2 1/4 times this in a 200k buffer, 3 3/4 times this in a | |
666 1000k buffer, and 4 1/2 times this in a 2000k buffer. | |
667 | |
668 See also the variable `auto-save-interval', which controls auto-saving based | |
669 on the number of characters typed.") | |
670 | |
671 ;jwz: this is preloaded so don't ;;;###autoload | |
672 (defvar auto-gc-threshold (/ gc-cons-threshold 3) | |
673 "*GC when this many bytes have been consed since the last GC, | |
674 and the user has been idle for `auto-save-timeout' seconds.") | |
675 | |
676 (defun auto-save-itimer () | |
677 "For use as a itimer callback function. | |
678 Auto-saves and garbage-collects based on the size of the current buffer | |
679 and the value of `auto-save-timeout', `auto-gc-threshold', and the current | |
680 keyboard idle-time." | |
681 (if (or (null auto-save-timeout) | |
682 (<= auto-save-timeout 0) | |
683 (eq (minibuffer-window) (selected-window))) | |
684 nil | |
685 (let ((buf-size (1+ (ash (buffer-size) -8))) | |
686 (delay-level 0) | |
687 (now (current-time)) | |
688 delay) | |
689 (while (> buf-size 64) | |
690 (setq delay-level (1+ delay-level) | |
691 buf-size (- buf-size (ash buf-size -2)))) | |
692 (if (< delay-level 4) | |
693 (setq delay-level 4)) | |
694 ;; delay_level is 4 for files under around 50k, 7 at 100k, 9 at 200k, | |
695 ;; 11 at 300k, and 12 at 500k, 15 at 1 meg, and 17 at 2 meg. | |
696 (setq delay (/ (* delay-level auto-save-timeout) 4)) | |
697 (let ((idle-time (if (or (not (consp last-input-time)) | |
698 (/= (car now) (car last-input-time))) | |
699 (1+ delay) | |
700 (- (car (cdr now)) (cdr last-input-time))))) | |
701 (and (> idle-time delay) | |
702 (do-auto-save)) | |
703 (and (> idle-time auto-save-timeout) | |
704 (> (consing-since-gc) auto-gc-threshold) | |
705 (garbage-collect))))) | |
706 ;; Look at the itimer that's currently running; if the user has changed | |
707 ;; the value of auto-save-timeout, modify this itimer to have the correct | |
708 ;; restart time. There will be some latency between when the user changes | |
709 ;; this variable and when it takes effect, but it will happen eventually. | |
710 (let ((self (get-itimer "auto-save"))) | |
711 (or self (error "auto-save-itimer can't find itself")) | |
712 (if (and auto-save-timeout (> auto-save-timeout 4)) | |
713 (or (= (itimer-restart self) (/ auto-save-timeout 4)) | |
714 (set-itimer-restart self (/ auto-save-timeout 4))))) | |
715 nil) | |
716 | |
717 (defun itimer-init-auto-gc () | |
718 (or noninteractive ; may be being run from after-init-hook in -batch mode. | |
719 (get-itimer "auto-save") | |
720 ;; the time here is just the first interval; if the user changes it | |
721 ;; later, it will adjust. | |
722 (let ((time (max 2 (/ (or auto-save-timeout 30) 4)))) | |
723 (start-itimer "auto-save" 'auto-save-itimer time time)))) | |
724 | |
725 (cond (purify-flag | |
726 ;; This file is being preloaded into an emacs about to be dumped. | |
727 ;; So arrange for the auto-save itimer to be started once emacs | |
728 ;; is launched. | |
729 (add-hook 'after-init-hook 'itimer-init-auto-gc)) | |
730 (t | |
731 ;; Otherwise, this file is being loaded into a normal, interactive | |
732 ;; emacs. Start the auto-save timer now. | |
733 (itimer-init-auto-gc))) | |
734 | |
735 | |
736 (provide 'itimer) |