aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/org-agenda-frame.el16
-rw-r--r--tests/test-org-agenda-frame.el32
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)