dot/emacs, el/dot-emacs.el: Another `display-window' hack: fallback.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 29 Apr 2024 10:03:33 +0000 (11:03 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 29 Apr 2024 10:05:46 +0000 (11:05 +0100)
Allow a window in each frame to be declared as the `victim' for random
pop-up buffers, overriding the usual policy.

dot/emacs
el/dot-emacs.el

index 5588a43..8749882 100644 (file)
--- a/dot/emacs
+++ b/dot/emacs
   (global-set-key [?\C-c ?w ?b] 'w3m-bookmark-view)
   (global-set-key [?\C-c ?w ?c] 'mdw-set-frame-colour)
   (global-set-key [?\C-c ?w ?d] 'mdw-divvy-window)
+  (global-set-key [?\C-c ?w ?f] 'mdw-set-fallback-window)
   (global-set-key [?\C-c ?w ?h] 'windmove-left)
   (global-set-key [?\C-c ?w ?j] 'windmove-down)
   (global-set-key [?\C-c ?w ?k] 'windmove-up)
index 6cad98c..01d3ac5 100644 (file)
@@ -772,6 +772,45 @@ Pretend they don't exist.  They might be on other display devices."
       even-window-heights nil
       display-buffer-reuse-frames nil)
 
+(defvar mdw-fallback-window-alist nil
+  "Alist mapping frames to fallback windows.")
+
+(defun mdw-cleanup-fallback-window-alist ()
+  "Remove entries for dead frames and windows from the fallback alist."
+  (let ((prev nil)
+       (cursor mdw-fallback-window-alist))
+    (while cursor
+      (let* ((assoc (car cursor))
+            (tail (cdr cursor)))
+       (cond ((and (frame-live-p (car assoc))
+                   (window-live-p (cdr assoc)))
+              (setq prev cursor))
+             ((null prev)
+              (setq mdw-fallback-window-alist tail))
+             (t
+              (setcdr prev tail)))
+       (setq cursor tail)))))
+
+(defun mdw-set-fallback-window (cancel)
+  "Prefer the selected window for pop-up buffers in this frame.
+With a prefix argument, clear the fallback window."
+  (interactive "P")
+  (let* ((frame (selected-frame)) (window (selected-window))
+        (assoc (assq (selected-frame) mdw-fallback-window-alist)))
+    (cond (cancel
+          (cond (assoc
+                 (setcdr assoc nil)
+                 (message "Fallback window cleared."))
+                (t
+                 (message "No fallback window active in this frame."))))
+         ((window-dedicated-p window)
+          (error "Window is dedicated to its buffer."))
+         (t
+          (if assoc (setcdr assoc window)
+            (push (cons frame window) mdw-fallback-window-alist))
+          (message "Fallback window set.")))
+    (mdw-cleanup-fallback-window-alist)))
+
 (defun mdw-last-window-in-frame-p (window)
   "Return whether WINDOW is the last in its frame."
   (catch 'done
@@ -790,10 +829,17 @@ Begone, foul DWIMmerlaik!
 This is all totally subject to arbitrary change in the future, but the
 emphasis is on predictability rather than crazy DWIMmery."
   (let* ((selected (selected-window)) chosen
+        (fallback (assq (selected-frame) mdw-fallback-window-alist))
         (full-height-p (window-full-height-p selected))
         (full-width-p (window-full-width-p selected)))
     (cond
 
+     ((and fallback (window-live-p (cdr fallback)))
+      ;; There's a fallback window set for this frame.  Use it.
+
+      (setq chosen (cdr fallback))
+      (display-buffer-record-window 'window chosen buffer))
+
      ((and full-height-p full-width-p)
       ;; We're basically the only window in the frame.  If we want to get
       ;; anywhere, we'll have to split the window.