summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/timer.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/timer.el')
-rw-r--r--lisp/emacs-lisp/timer.el151
1 files changed, 82 insertions, 69 deletions
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index 8b1dca8cb78..a1bba2ddb6e 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -27,27 +27,34 @@
;;; Code:
-;; Layout of a timer vector:
-;; [triggered-p high-seconds low-seconds usecs repeat-delay
-;; function args idle-delay psecs]
-;; triggered-p is nil if the timer is active (waiting to be triggered),
-;; t if it is inactive ("already triggered", in theory)
-
(eval-when-compile (require 'cl-lib))
(cl-defstruct (timer
- (:constructor nil)
- (:copier nil)
- (:constructor timer-create ())
- (:type vector)
- (:conc-name timer--))
+ (:constructor nil)
+ (:copier nil)
+ (:constructor timer-create ())
+ (:type vector)
+ (:conc-name timer--))
+ ;; nil if the timer is active (waiting to be triggered),
+ ;; non-nil if it is inactive ("already triggered", in theory).
(triggered t)
- high-seconds low-seconds usecs repeat-delay function args idle-delay psecs)
+ ;; Time of next trigger: for normal timers, absolute time, for idle timers,
+ ;; time relative to idle-start.
+ high-seconds low-seconds usecs
+ ;; For normal timers, time between repetitions, or nil. For idle timers,
+ ;; non-nil iff repeated.
+ repeat-delay
+ function args ;What to do when triggered.
+ idle-delay ;If non-nil, this is an idle-timer.
+ psecs)
(defun timerp (object)
"Return t if OBJECT is a timer."
(and (vectorp object) (= (length object) 9)))
+(defsubst timer--check (timer)
+ (or (timerp timer) (signal 'wrong-type-argument (list #'timerp timer))))
+
;; Pseudo field `time'.
(defun timer--time (timer)
(list (timer--high-seconds timer)
@@ -57,17 +64,17 @@
(gv-define-simple-setter timer--time
(lambda (timer time)
- (or (timerp timer) (error "Invalid timer"))
+ (timer--check timer)
(setf (timer--high-seconds timer) (pop time))
(let ((low time) (usecs 0) (psecs 0))
(if (consp time)
- (progn
- (setq low (pop time))
- (if time
- (progn
- (setq usecs (pop time))
- (if time
- (setq psecs (car time)))))))
+ (progn
+ (setq low (pop time))
+ (if time
+ (progn
+ (setq usecs (pop time))
+ (if time
+ (setq psecs (car time)))))))
(setf (timer--low-seconds timer) low)
(setf (timer--usecs timer) usecs)
(setf (timer--psecs timer) psecs))))
@@ -83,15 +90,13 @@ fire repeatedly that many seconds apart."
timer)
(defun timer-set-idle-time (timer secs &optional repeat)
+ ;; FIXME: Merge with timer-set-time.
"Set the trigger idle time of TIMER to SECS.
SECS may be an integer, floating point number, or the internal
time format returned by, e.g., `current-idle-time'.
If optional third argument REPEAT is non-nil, make the timer
fire each time Emacs is idle for that many seconds."
- (if (consp secs)
- (setf (timer--time timer) secs)
- (setf (timer--time timer) '(0 0 0))
- (timer-inc-time timer secs))
+ (setf (timer--time timer) (if (consp secs) secs (seconds-to-time secs)))
(setf (timer--repeat-delay timer) repeat)
timer)
@@ -156,8 +161,7 @@ fire repeatedly that many seconds apart."
(defun timer-set-function (timer function &optional args)
"Make TIMER call FUNCTION with optional ARGS when triggering."
- (or (timerp timer)
- (error "Invalid timer"))
+ (timer--check timer)
(setf (timer--function timer) function)
(setf (timer--args timer) args)
timer)
@@ -181,9 +185,10 @@ fire repeatedly that many seconds apart."
(setcdr reuse-cell timers))
(setq reuse-cell (cons timer timers)))
;; Insert new timer after last which possibly means in front of queue.
- (cond (last (setcdr last reuse-cell))
- (idle (setq timer-idle-list reuse-cell))
- (t (setq timer-list reuse-cell)))
+ (setf (cond (last (cdr last))
+ (idle timer-idle-list)
+ (t timer-list))
+ reuse-cell)
(setf (timer--triggered timer) triggered-p)
(setf (timer--idle-delay timer) idle)
nil)
@@ -223,8 +228,7 @@ timer will fire right away."
(defun cancel-timer (timer)
"Remove TIMER from the list of active timers."
- (or (timerp timer)
- (error "Invalid timer"))
+ (timer--check timer)
(setq timer-list (delq timer timer-list))
(setq timer-idle-list (delq timer timer-idle-list))
nil)
@@ -283,44 +287,47 @@ This function is called, by name, directly by the C code."
(setq timer-event-last-1 timer-event-last)
(setq timer-event-last timer)
(let ((inhibit-quit t))
- (if (timerp timer)
- (let (retrigger cell)
- ;; Delete from queue. Record the cons cell that was used.
- (setq cell (cancel-timer-internal timer))
- ;; Re-schedule if requested.
- (if (timer--repeat-delay timer)
- (if (timer--idle-delay timer)
- (timer-activate-when-idle timer nil cell)
- (timer-inc-time timer (timer--repeat-delay timer) 0)
- ;; If real time has jumped forward,
- ;; perhaps because Emacs was suspended for a long time,
- ;; limit how many times things get repeated.
- (if (and (numberp timer-max-repeats)
- (< 0 (timer-until timer (current-time))))
- (let ((repeats (/ (timer-until timer (current-time))
- (timer--repeat-delay timer))))
- (if (> repeats timer-max-repeats)
- (timer-inc-time timer (* (timer--repeat-delay timer)
- repeats)))))
- (timer-activate timer t cell)
- (setq retrigger t)))
- ;; Run handler.
- ;; We do this after rescheduling so that the handler function
- ;; can cancel its own timer successfully with cancel-timer.
- (condition-case-unless-debug err
- ;; Timer functions should not change the current buffer.
- ;; If they do, all kinds of nasty surprises can happen,
- ;; and it can be hellish to track down their source.
- (save-current-buffer
- (apply (timer--function timer) (timer--args timer)))
- (error (message "Error in timer: %S" err)))
- (when (and retrigger
- ;; If the timer's been canceled, don't "retrigger" it
- ;; since it might still be in the copy of timer-list kept
- ;; by keyboard.c:timer_check (bug#14156).
- (memq timer timer-list))
- (setf (timer--triggered timer) nil)))
- (error "Bogus timer event"))))
+ (timer--check timer)
+ (let ((retrigger nil)
+ (cell
+ ;; Delete from queue. Record the cons cell that was used.
+ (cancel-timer-internal timer)))
+ ;; Re-schedule if requested.
+ (if (timer--repeat-delay timer)
+ (if (timer--idle-delay timer)
+ (timer-activate-when-idle timer nil cell)
+ (timer-inc-time timer (timer--repeat-delay timer) 0)
+ ;; If real time has jumped forward,
+ ;; perhaps because Emacs was suspended for a long time,
+ ;; limit how many times things get repeated.
+ (if (and (numberp timer-max-repeats)
+ (< 0 (timer-until timer (current-time))))
+ (let ((repeats (/ (timer-until timer (current-time))
+ (timer--repeat-delay timer))))
+ (if (> repeats timer-max-repeats)
+ (timer-inc-time timer (* (timer--repeat-delay timer)
+ repeats)))))
+ ;; Place it back on the timer-list before running
+ ;; timer--function, so it can cancel-timer itself.
+ (timer-activate timer t cell)
+ (setq retrigger t)))
+ ;; Run handler.
+ (condition-case-unless-debug err
+ ;; Timer functions should not change the current buffer.
+ ;; If they do, all kinds of nasty surprises can happen,
+ ;; and it can be hellish to track down their source.
+ (save-current-buffer
+ (apply (timer--function timer) (timer--args timer)))
+ (error (message "Error running timer%s: %S"
+ (if (symbolp (timer--function timer))
+ (format " `%s'" (timer--function timer)) "")
+ err)))
+ (when (and retrigger
+ ;; If the timer's been canceled, don't "retrigger" it
+ ;; since it might still be in the copy of timer-list kept
+ ;; by keyboard.c:timer_check (bug#14156).
+ (memq timer timer-list))
+ (setf (timer--triggered timer) nil)))))
;; This function is incompatible with the one in levents.el.
(defun timeout-event-p (event)
@@ -531,6 +538,12 @@ If the user does not answer after SECONDS seconds, return DEFAULT-VALUE."
secs
(if (string-match-p "\\`[0-9.]+\\'" string)
(string-to-number string)))))
+
+(defun internal-timer-start-idle ()
+ "Mark all idle-time timers as once again candidates for running."
+ (dolist (timer timer-idle-list)
+ (if (timerp timer) ;; FIXME: Why test?
+ (setf (timer--triggered timer) nil))))
(provide 'timer)