diff options
| author | Lars Ingebrigtsen | 2021-08-31 03:04:22 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-08-31 03:04:22 +0200 |
| commit | 50765f3f511d467ff024dda7c84530c759253d18 (patch) | |
| tree | 4e2d2c790599d7ba2a34433977557deb4cedb31b | |
| parent | d2ad64b7a524450bd1a4f59a5e0801abb0637b32 (diff) | |
| download | emacs-50765f3f511d467ff024dda7c84530c759253d18.tar.gz emacs-50765f3f511d467ff024dda7c84530c759253d18.zip | |
Make run-at-time try harder to run at integral multiples
* lisp/emacs-lisp/timer.el (timer): Add new slot integral-multiple.
(timerp): Adjust.
(timer-event-handler): Recompute the delay if requested
(bug#39099).
(run-at-time): Mark the timer as recomputable if given a t
parameter.
* src/keyboard.c (decode_timer): Adjust.
| -rw-r--r-- | etc/NEWS | 11 | ||||
| -rw-r--r-- | lisp/emacs-lisp/timer.el | 81 | ||||
| -rw-r--r-- | src/keyboard.c | 2 |
3 files changed, 59 insertions, 35 deletions
| @@ -3146,6 +3146,17 @@ work for `context-menu-mode` in Xterm. | |||
| 3146 | * Incompatible Lisp Changes in Emacs 28.1 | 3146 | * Incompatible Lisp Changes in Emacs 28.1 |
| 3147 | 3147 | ||
| 3148 | --- | 3148 | --- |
| 3149 | ** 'run-at-time' now tries harder to implement the t TIME parameter. | ||
| 3150 | If TIME is t, the timer runs at an integral multiple of REPEAT. | ||
| 3151 | (I.e., if given a REPEAT of 60, it'll run at 08:11:00, 08:12:00, | ||
| 3152 | 08:13:00.) However, when a machine goes to sleep (or otherwise didn't | ||
| 3153 | get a time slot to run when the timer was scheduled), the timer would | ||
| 3154 | then fire every 60 seconds after the time the timer was fired. This | ||
| 3155 | has now changed, and the timer code now recomputes the integral | ||
| 3156 | multiple every time it runs, which means that if the laptop wakes at | ||
| 3157 | 08:16:43, it'll fire at that time, but then at 08:17:00, 08:18:00... | ||
| 3158 | |||
| 3159 | --- | ||
| 3149 | ** 'parse-partial-sexp' now signals an error if TO is smaller than FROM. | 3160 | ** 'parse-partial-sexp' now signals an error if TO is smaller than FROM. |
| 3150 | Previously this would lead to the function interpreting FROM as TO and | 3161 | Previously this would lead to the function interpreting FROM as TO and |
| 3151 | vice versa, which would be confusing when passing in OLDSTATE, which | 3162 | vice versa, which would be confusing when passing in OLDSTATE, which |
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el index 36de29a73a8..f7715109c82 100644 --- a/lisp/emacs-lisp/timer.el +++ b/lisp/emacs-lisp/timer.el | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | (eval-when-compile (require 'cl-lib)) | 30 | (eval-when-compile (require 'cl-lib)) |
| 31 | 31 | ||
| 32 | ;; If you change this structure, you also have to change `timerp' | ||
| 33 | ;; (below) and decode_timer in keyboard.c. | ||
| 32 | (cl-defstruct (timer | 34 | (cl-defstruct (timer |
| 33 | (:constructor nil) | 35 | (:constructor nil) |
| 34 | (:copier nil) | 36 | (:copier nil) |
| @@ -46,11 +48,16 @@ | |||
| 46 | repeat-delay | 48 | repeat-delay |
| 47 | function args ;What to do when triggered. | 49 | function args ;What to do when triggered. |
| 48 | idle-delay ;If non-nil, this is an idle-timer. | 50 | idle-delay ;If non-nil, this is an idle-timer. |
| 49 | psecs) | 51 | psecs |
| 52 | ;; A timer may be created with `t' as the TIME, which means that we | ||
| 53 | ;; want to run at specific integral multiples of `repeat-delay'. We | ||
| 54 | ;; then have to recompute this (because the machine may have gone to | ||
| 55 | ;; sleep, etc). | ||
| 56 | integral-multiple) | ||
| 50 | 57 | ||
| 51 | (defun timerp (object) | 58 | (defun timerp (object) |
| 52 | "Return t if OBJECT is a timer." | 59 | "Return t if OBJECT is a timer." |
| 53 | (and (vectorp object) (= (length object) 9))) | 60 | (and (vectorp object) (= (length object) 10))) |
| 54 | 61 | ||
| 55 | (defsubst timer--check (timer) | 62 | (defsubst timer--check (timer) |
| 56 | (or (timerp timer) (signal 'wrong-type-argument (list #'timerp timer)))) | 63 | (or (timerp timer) (signal 'wrong-type-argument (list #'timerp timer)))) |
| @@ -284,6 +291,13 @@ This function is called, by name, directly by the C code." | |||
| 284 | (if (> repeats timer-max-repeats) | 291 | (if (> repeats timer-max-repeats) |
| 285 | (timer-inc-time timer (* (timer--repeat-delay timer) | 292 | (timer-inc-time timer (* (timer--repeat-delay timer) |
| 286 | repeats))))) | 293 | repeats))))) |
| 294 | ;; If we want integral multiples, we have to recompute | ||
| 295 | ;; the repetition. | ||
| 296 | (when (and (timer--integral-multiple timer) | ||
| 297 | (not (timer--idle-delay timer))) | ||
| 298 | (setf (timer--time timer) | ||
| 299 | (timer-next-integral-multiple-of-time | ||
| 300 | (current-time) (timer--repeat-delay timer)))) | ||
| 287 | ;; Place it back on the timer-list before running | 301 | ;; Place it back on the timer-list before running |
| 288 | ;; timer--function, so it can cancel-timer itself. | 302 | ;; timer--function, so it can cancel-timer itself. |
| 289 | (timer-activate timer t cell) | 303 | (timer-activate timer t cell) |
| @@ -340,45 +354,44 @@ This function returns a timer object which you can use in | |||
| 340 | `cancel-timer'." | 354 | `cancel-timer'." |
| 341 | (interactive "sRun at time: \nNRepeat interval: \naFunction: ") | 355 | (interactive "sRun at time: \nNRepeat interval: \naFunction: ") |
| 342 | 356 | ||
| 343 | (or (null repeat) | 357 | (when (and repeat |
| 344 | (and (numberp repeat) (< 0 repeat)) | 358 | (numberp repeat) |
| 345 | (error "Invalid repetition interval")) | 359 | (< repeat 0)) |
| 360 | (error "Invalid repetition interval")) | ||
| 346 | 361 | ||
| 347 | ;; Special case: nil means "now" and is useful when repeating. | 362 | (let ((timer (timer-create))) |
| 348 | (if (null time) | 363 | ;; Special case: nil means "now" and is useful when repeating. |
| 364 | (unless time | ||
| 349 | (setq time (current-time))) | 365 | (setq time (current-time))) |
| 350 | 366 | ||
| 351 | ;; Special case: t means the next integral multiple of REPEAT. | 367 | ;; Special case: t means the next integral multiple of REPEAT. |
| 352 | (if (and (eq time t) repeat) | 368 | (when (and (eq time t) repeat) |
| 353 | (setq time (timer-next-integral-multiple-of-time (current-time) repeat))) | 369 | (setq time (timer-next-integral-multiple-of-time (current-time) repeat)) |
| 370 | (setf (timer--integral-multiple timer) t)) | ||
| 354 | 371 | ||
| 355 | ;; Handle numbers as relative times in seconds. | 372 | ;; Handle numbers as relative times in seconds. |
| 356 | (if (numberp time) | 373 | (when (numberp time) |
| 357 | (setq time (timer-relative-time nil time))) | 374 | (setq time (timer-relative-time nil time))) |
| 358 | 375 | ||
| 359 | ;; Handle relative times like "2 hours 35 minutes" | 376 | ;; Handle relative times like "2 hours 35 minutes". |
| 360 | (if (stringp time) | 377 | (when (stringp time) |
| 361 | (let ((secs (timer-duration time))) | 378 | (when-let ((secs (timer-duration time))) |
| 362 | (if secs | 379 | (setq time (timer-relative-time nil secs)))) |
| 363 | (setq time (timer-relative-time nil secs))))) | 380 | |
| 364 | 381 | ;; Handle "11:23pm" and the like. Interpret it as meaning today | |
| 365 | ;; Handle "11:23pm" and the like. Interpret it as meaning today | 382 | ;; which admittedly is rather stupid if we have passed that time |
| 366 | ;; which admittedly is rather stupid if we have passed that time | 383 | ;; already. (Though only Emacs hackers hack Emacs at that time.) |
| 367 | ;; already. (Though only Emacs hackers hack Emacs at that time.) | 384 | (when (stringp time) |
| 368 | (if (stringp time) | 385 | (require 'diary-lib) |
| 369 | (progn | 386 | (let ((hhmm (diary-entry-time time)) |
| 370 | (require 'diary-lib) | 387 | (now (decode-time))) |
| 371 | (let ((hhmm (diary-entry-time time)) | 388 | (when (>= hhmm 0) |
| 372 | (now (decode-time))) | 389 | (setq time (encode-time 0 (% hhmm 100) (/ hhmm 100) |
| 373 | (if (>= hhmm 0) | 390 | (decoded-time-day now) |
| 374 | (setq time | 391 | (decoded-time-month now) |
| 375 | (encode-time 0 (% hhmm 100) (/ hhmm 100) | 392 | (decoded-time-year now) |
| 376 | (decoded-time-day now) | 393 | (decoded-time-zone now)))))) |
| 377 | (decoded-time-month now) | ||
| 378 | (decoded-time-year now) | ||
| 379 | (decoded-time-zone now))))))) | ||
| 380 | 394 | ||
| 381 | (let ((timer (timer-create))) | ||
| 382 | (timer-set-time timer time repeat) | 395 | (timer-set-time timer time repeat) |
| 383 | (timer-set-function timer function args) | 396 | (timer-set-function timer function args) |
| 384 | (timer-activate timer) | 397 | (timer-activate timer) |
diff --git a/src/keyboard.c b/src/keyboard.c index 2e4c4e6aabf..81ff9df153d 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -4234,7 +4234,7 @@ decode_timer (Lisp_Object timer, struct timespec *result) | |||
| 4234 | { | 4234 | { |
| 4235 | Lisp_Object *vec; | 4235 | Lisp_Object *vec; |
| 4236 | 4236 | ||
| 4237 | if (! (VECTORP (timer) && ASIZE (timer) == 9)) | 4237 | if (! (VECTORP (timer) && ASIZE (timer) == 10)) |
| 4238 | return false; | 4238 | return false; |
| 4239 | vec = XVECTOR (timer)->contents; | 4239 | vec = XVECTOR (timer)->contents; |
| 4240 | if (! NILP (vec[0])) | 4240 | if (! NILP (vec[0])) |