mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-04 11:00:45 -08:00
timer.el: Avoid repeated timers
https://mail.gnu.org/archive/html/emacs-devel/2022-07/msg01127.html points out that end-users can get bitten by this, accidentally calling `timer-activate` on an already activated timer. * lisp/emacs-lisp/timer.el (timer--activate): Signal an error if we try to re-add a timer that's already on the timer-list.
This commit is contained in:
parent
df263dd758
commit
eb7fe81e6d
1 changed files with 39 additions and 29 deletions
|
|
@ -159,32 +159,42 @@ SECS may be a fraction."
|
||||||
timer)
|
timer)
|
||||||
|
|
||||||
(defun timer--activate (timer &optional triggered-p reuse-cell idle)
|
(defun timer--activate (timer &optional triggered-p reuse-cell idle)
|
||||||
(if (and (timerp timer)
|
(let ((timers (if idle timer-idle-list timer-list))
|
||||||
(integerp (timer--high-seconds timer))
|
last)
|
||||||
(integerp (timer--low-seconds timer))
|
(cond
|
||||||
(integerp (timer--usecs timer))
|
((not (and (timerp timer)
|
||||||
(integerp (timer--psecs timer))
|
(integerp (timer--high-seconds timer))
|
||||||
(timer--function timer))
|
(integerp (timer--low-seconds timer))
|
||||||
(let ((timers (if idle timer-idle-list timer-list))
|
(integerp (timer--usecs timer))
|
||||||
last)
|
(integerp (timer--psecs timer))
|
||||||
;; Skip all timers to trigger before the new one.
|
(timer--function timer)))
|
||||||
(while (and timers (timer--time-less-p (car timers) timer))
|
(error "Invalid or uninitialized timer"))
|
||||||
(setq last timers
|
;; FIXME: This is not reliable because `idle-delay' is only set late,
|
||||||
timers (cdr timers)))
|
;; by `timer-activate-when-idle' :-(
|
||||||
(if reuse-cell
|
;;((not (eq (not idle)
|
||||||
(progn
|
;; (not (timer--idle-delay timer))))
|
||||||
(setcar reuse-cell timer)
|
;; (error "idle arg %S out of sync with idle-delay field of timer: %S"
|
||||||
(setcdr reuse-cell timers))
|
;; idle timer))
|
||||||
(setq reuse-cell (cons timer timers)))
|
((memq timer timers)
|
||||||
;; Insert new timer after last which possibly means in front of queue.
|
(error "Timer already activated"))
|
||||||
(setf (cond (last (cdr last))
|
(t
|
||||||
(idle timer-idle-list)
|
;; Skip all timers to trigger before the new one.
|
||||||
(t timer-list))
|
(while (and timers (timer--time-less-p (car timers) timer))
|
||||||
reuse-cell)
|
(setq last timers
|
||||||
(setf (timer--triggered timer) triggered-p)
|
timers (cdr timers)))
|
||||||
(setf (timer--idle-delay timer) idle)
|
(if reuse-cell
|
||||||
nil)
|
(progn
|
||||||
(error "Invalid or uninitialized timer")))
|
(setcar reuse-cell timer)
|
||||||
|
(setcdr reuse-cell timers))
|
||||||
|
(setq reuse-cell (cons timer timers)))
|
||||||
|
;; Insert new timer after last which possibly means in front of queue.
|
||||||
|
(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))))
|
||||||
|
|
||||||
(defun timer-activate (timer &optional triggered-p reuse-cell)
|
(defun timer-activate (timer &optional triggered-p reuse-cell)
|
||||||
"Insert TIMER into `timer-list'.
|
"Insert TIMER into `timer-list'.
|
||||||
|
|
@ -216,7 +226,7 @@ the time of the current timer. That's because the activated
|
||||||
timer will fire right away."
|
timer will fire right away."
|
||||||
(timer--activate timer (not dont-wait) reuse-cell 'idle))
|
(timer--activate timer (not dont-wait) reuse-cell 'idle))
|
||||||
|
|
||||||
(defalias 'disable-timeout 'cancel-timer)
|
(defalias 'disable-timeout #'cancel-timer)
|
||||||
|
|
||||||
(defun cancel-timer (timer)
|
(defun cancel-timer (timer)
|
||||||
"Remove TIMER from the list of active timers."
|
"Remove TIMER from the list of active timers."
|
||||||
|
|
@ -430,7 +440,7 @@ The action is to call FUNCTION with arguments ARGS.
|
||||||
|
|
||||||
This function returns a timer object which you can use in `cancel-timer'."
|
This function returns a timer object which you can use in `cancel-timer'."
|
||||||
(interactive "sRun after delay (seconds): \nNRepeat interval: \naFunction: ")
|
(interactive "sRun after delay (seconds): \nNRepeat interval: \naFunction: ")
|
||||||
(apply 'run-at-time secs repeat function args))
|
(apply #'run-at-time secs repeat function args))
|
||||||
|
|
||||||
(defun add-timeout (secs function object &optional repeat)
|
(defun add-timeout (secs function object &optional repeat)
|
||||||
"Add a timer to run SECS seconds from now, to call FUNCTION on OBJECT.
|
"Add a timer to run SECS seconds from now, to call FUNCTION on OBJECT.
|
||||||
|
|
@ -457,7 +467,7 @@ This function returns a timer object which you can use in `cancel-timer'."
|
||||||
(interactive
|
(interactive
|
||||||
(list (read-from-minibuffer "Run after idle (seconds): " nil nil t)
|
(list (read-from-minibuffer "Run after idle (seconds): " nil nil t)
|
||||||
(y-or-n-p "Repeat each time Emacs is idle? ")
|
(y-or-n-p "Repeat each time Emacs is idle? ")
|
||||||
(intern (completing-read "Function: " obarray 'fboundp t))))
|
(intern (completing-read "Function: " obarray #'fboundp t))))
|
||||||
(let ((timer (timer-create)))
|
(let ((timer (timer-create)))
|
||||||
(timer-set-function timer function args)
|
(timer-set-function timer function args)
|
||||||
(timer-set-idle-time timer secs repeat)
|
(timer-set-idle-time timer secs repeat)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue