diff options
| -rw-r--r-- | modules/org-agenda-frame.el | 16 | ||||
| -rw-r--r-- | tests/test-org-agenda-frame.el | 32 |
2 files changed, 46 insertions, 2 deletions
diff --git a/modules/org-agenda-frame.el b/modules/org-agenda-frame.el index fd911a97..2604f979 100644 --- a/modules/org-agenda-frame.el +++ b/modules/org-agenda-frame.el @@ -658,8 +658,20 @@ out-of-range window-start nor steals focus." (buffer (cj/--agenda-frame-sticky-buffer)) (window (and (frame-live-p frame) (buffer-live-p buffer) (get-buffer-window buffer frame)))) - (when (window-live-p window) - (let ((prev-window (selected-window))) + (when (and (window-live-p window) + ;; Skip the tick while a minibuffer is active anywhere -- + ;; reselecting windows under an active minibuffer session can + ;; break it, and the next tick catches up. + (not (active-minibuffer-window))) + (let ((prev-window (selected-window)) + ;; The rebuild takes visible time, and for its duration the + ;; agenda window is the selected window. Without inhibiting + ;; redisplay the user's cursor visibly goes hollow for the whole + ;; rebuild every tick -- indistinguishable from focus theft. + ;; The rebuild blocks Emacs either way (it is synchronous), so + ;; this hides the selection flicker at no extra cost; redisplay + ;; resumes after the selection is restored. + (inhibit-redisplay t)) (unwind-protect (progn (select-window window t) diff --git a/tests/test-org-agenda-frame.el b/tests/test-org-agenda-frame.el index 29b6a36f..972df6ec 100644 --- a/tests/test-org-agenda-frame.el +++ b/tests/test-org-agenda-frame.el @@ -875,6 +875,38 @@ showing the launch buffer." (should (eq (cj/--agenda-frame-spawn) 'af)) (should (eq timed 'af))))) +(ert-deftest test-org-agenda-frame-safe-redo-inhibits-redisplay () + "Normal: the tick runs with redisplay inhibited. +The rebuild takes visible time; without this, the agenda window is the +selected window for the whole rebuild and the user watches their cursor +go hollow every five minutes -- indistinguishable from focus theft." + (let (seen (prev (selected-window))) + (cl-letf (((symbol-function 'cj/--agenda-frame) (lambda () 'af)) + ((symbol-function 'cj/--agenda-frame-sticky-buffer) + (lambda () (current-buffer))) + ((symbol-function 'frame-live-p) (lambda (_f) t)) + ((symbol-function 'get-buffer-window) (lambda (&rest _) prev)) + ((symbol-function 'cj/--agenda-frame-do-redo) + (lambda (&rest _) (setq seen inhibit-redisplay)))) + (cj/--agenda-frame-safe-redo) + (should (eq seen t))))) + +(ert-deftest test-org-agenda-frame-safe-redo-skips-during-minibuffer () + "Boundary: a tick while a minibuffer is active is skipped entirely. +Reselecting windows under an active minibuffer session can break it; the +next tick catches up." + (let (redone (prev (selected-window))) + (cl-letf (((symbol-function 'active-minibuffer-window) (lambda () 'mini)) + ((symbol-function 'cj/--agenda-frame) (lambda () 'af)) + ((symbol-function 'cj/--agenda-frame-sticky-buffer) + (lambda () (current-buffer))) + ((symbol-function 'frame-live-p) (lambda (_f) t)) + ((symbol-function 'get-buffer-window) (lambda (&rest _) prev)) + ((symbol-function 'cj/--agenda-frame-do-redo) + (lambda (&rest _) (setq redone t)))) + (cj/--agenda-frame-safe-redo) + (should-not redone)))) + (ert-deftest test-org-agenda-frame-safe-redo-noop-when-not-shown () "Boundary: a tick with the buffer not shown in the frame does not redo or error." (let (redone) |
