emacs-31 321f6a07e85: Handle transposing and rotating of dedicated windows (Bug#81406)

Martin Rudalics via Mailing list for Emacs changes <[email protected]>
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: emacs-31
commit 321f6a07e85bd1bd48007eeae4d65bf2b1de7d1a
Author: Martin Rudalics <[email protected]>
Commit: Martin Rudalics <[email protected]>

    Handle transposing and rotating of dedicated windows (Bug#81406)
    
    * lisp/window-x.el (transpose-dedicated-windows): New option.
    (window-layout-rotate-clockwise)
    (window-layout-rotate-anticlockwise)
    (window-layout-flip-leftright, window-layout-flip-topdown)
    (window-layout-transpose, rotate-windows-back): Say that these
    functions may signal an error when they encounter dedicated,
    fixed-size or atomic windows.
    (rotate-windows): Handle dedicated windows like the other
    transpose functions.
    (window--transpose): Handle 'transpose-dedicated-windows'.
    * doc/lispref/windows.texi (Changing Window Layouts): Describe new
    option 'transpose-dedicated-windows'.
    * etc/NEWS: Announce new option 'transpose-dedicated-windows'.
---
 doc/lispref/windows.texi | 32 ++++++++++------
 etc/NEWS                 |  6 +++
 lisp/window-x.el         | 95 ++++++++++++++++++++++++++++++++----------------
 3 files changed, 90 insertions(+), 43 deletions(-)

diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index ddc8524ddb6..13e99ec5cdb 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -2298,7 +2298,10 @@ windows by deleting them first and resurrecting them
 (@pxref{Resurrecting Windows}) in their new locations afterwards.  No
 window gets lost and no window is added or duplicated.  Where possible,
 these commands try to preserve the relative size of windows as well as
-all other non-geometric properties including parameters.
+all other non-geometric properties including parameters.  These commands
+will signal an error if windows chosen to transpose or rotate are atomic
+or of fixed size.  The option @code{transpose-dedicated-windows} below
+decides whether dedicated windows may be transposed or rotated.
 
    The @var{window} argument of all functions described in this section
 must specify a valid parent window (@pxref{Windows and Frames}).  If it
@@ -2415,16 +2418,14 @@ becomes a vertical split and vice versa.
 @end deffn
 
 @cindex rotating windows
-The final two commands can be used to @dfn{rotate} windows within the existing
-layout.  They are like the commands that rotate the layout but leave the
-underlying structure of the layout unchanged.  What actually changes are
-the positions of windows within the existing layout.  This happens in a
-way that the space formerly occupied by any window will be occupied by
-the window preceding (following if @var{reverse} is non-@code{nil}) it
-in the cyclic ordering of windows (@pxref{Cyclic Window Ordering}) on
-@var{window}'s frame.  These commands may signal an error if windows
-chosen to rotate are dedicated to their buffers, atomic or of fixed
-size.
+The final two commands can be used to @dfn{rotate} windows within the
+existing layout.  They are like the commands that rotate the layout but
+leave the underlying structure of the layout unchanged.  What actually
+changes are the positions of windows within the existing layout.  This
+happens in a way that the space formerly occupied by any window will be
+occupied by the window preceding (following if @var{reverse} is
+non-@code{nil}) it in the cyclic ordering of windows (@pxref{Cyclic
+Window Ordering}) on @var{window}'s frame.
 
 @deffn Command rotate-windows &optional window reverse
 This command rotates @var{window}'c child windows in cyclic ordering.
@@ -2463,6 +2464,15 @@ ordering.
 @end smallexample
 @end deffn
 
+All commands described above are subject to the following option.
+
+@defopt transpose-dedicated-windows
+If this is @code{nil}, the functions described in this section will
+report an error when they encounter a dedicated window (@pxref{Dedicated
+Windows}).  If this is @code{t}, they handle dedicated windows like
+non-dedicated ones.
+@end defopt
+
 The last two commands are subject to the following option.
 
 @defopt rotate-windows-change-selected
diff --git a/etc/NEWS b/etc/NEWS
index ffbc142cad1..f3665321bd5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -373,12 +373,18 @@ every horizontal split becomes a vertical split and vice versa.
 'rotate-windows-back' ('C-x w o <LEFT>') rotate windows in cyclic
 ordering.
 
++++
 *** New user option 'rotate-windows-change-selected'.
 This controls whether 'rotate-windows' and 'rotate-windows-back' change
 the selected window.  If nil, the selected window does not change.
 The default is t, which means the new selected window will be the one
 that winds up at the location of the previously-selected window.
 
++++
+*** New user option 'transpose-dedicated-windows'.
+This controls how functions transposing or rotating windows handle
+dedicated windows.
+
 +++
 *** Windmove commands now move to skipped windows if invoked twice in a row.
 The new user option 'windmove-allow-repeated-command-override' controls
diff --git a/lisp/window-x.el b/lisp/window-x.el
index 8cb24a06674..c3c69738760 100644
--- a/lisp/window-x.el
+++ b/lisp/window-x.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2025-2026 Free Software Foundation, Inc.
 
-;; Author: Pranshu Sharma <[email protected]>
+;; Author: Pranshu Sharma <[email protected]>
 ;;         Martin Rudalics <[email protected]>
 ;; Maintainer: [email protected]
 ;; Keywords: window, convenience
@@ -67,18 +67,32 @@ where HEIGHT and WIDTH are the normal height and width of the window.
   "Return interactive window argument for window rotation commands."
   (if current-prefix-arg (window-parent) (window-main-window)))
 
+(defcustom transpose-dedicated-windows nil
+  "Whether dedicated windows may be transposed.
+If this is nil, functions for transposing, flipping or rotating the
+window layout and functions for rotating windows will report an error
+when they encounter a dedicated window.  If this is t, they handle
+dedicated windows like non-dedicated ones."
+  :type 'boolean
+  :version "31.1"
+  :group 'windows)
+
 ;;;###autoload
 (defun window-layout-rotate-clockwise (&optional window)
   "Rotate layout of WINDOW's child windows clockwise by 90 degrees.
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, rotate clockwise
-the layout of the child windows of the selected window's parent.  Signal
-an error if WINDOW is not a parent window.
+the layout of the child windows of the selected window's parent.
 
 Recursively rotate the entire layout of WINDOW's child windows clockwise
 by 90 degrees.  Do not change the selected window of WINDOW's frame.  If
 you want to rotate windows within their frame's layout, consider using
-`rotate-windows' instead."
+`rotate-windows' instead.
+
+Signal an error if WINDOW is not a parent window or some descendants of
+WINDOW are of fixed size or atomic.  Also signal an error if
+`transpose-dedicated-windows' is nil and a descendant window is
+dedicated."
   (interactive (list (window--rotate-interactive-arg)))
   (window--transpose (or window (window-main-window)) '(left . below) nil))
 
@@ -88,12 +102,17 @@ you want to rotate windows within their frame's layout, consider using
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, rotate
 counterclockwise the layout of the child windows of the selected
-window's parent.  Signal an error if WINDOW is not a parent window.
+window's parent.
 
 Recursively rotate the entire layout of WINDOW's child windows
 counterclockwise by 90 degrees.  Do not change the selected window of
 WINDOW's frame.  If you want to rotate windows within their frame's
-layout, consider using `rotate-windows-back' instead."
+layout, consider using `rotate-windows-back' instead.
+
+Signal an error if WINDOW is not a parent window or one of WINDOW's
+descendants is of fixed size or atomic.  Also signal an error if
+`transpose-dedicated-windows' is nil and a descendant window is
+dedicated."
   (interactive (list (window--rotate-interactive-arg)))
   (window--transpose (or window (window-main-window)) '(right . above) nil))
 
@@ -103,10 +122,14 @@ layout, consider using `rotate-windows-back' instead."
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, flip
 horizontally the layout of the child windows of the selected window's
-parent.  Signal an error if WINDOW is not a parent window.
+parent.
 
 Recursively flip the layout of WINDOW's child windows so that a child
-window on the right becomes a child window on the left and vice-versa."
+window on the right becomes a child window on the left and vice-versa.
+Signal an error if WINDOW is not a parent window or one of WINDOW's
+descendants is of fixed size or atomic.  Also signal an error if
+`transpose-dedicated-windows' is nil and a descendant window is
+dedicated."
   (interactive (list (window--rotate-interactive-arg)))
   (window--transpose (or window (window-main-window)) '(below . left) t))
 
@@ -115,11 +138,14 @@ window on the right becomes a child window on the left and vice-versa."
   "Flip WINDOW's child windows vertically.
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, flip vertically
-the layout of the child windows of the selected window's parent.  Signal
-an error if WINDOW is not a parent window.
+the layout of the child windows of the selected window's parent.
 
 Recursively flip the layout of WINDOW's child windows so that a child
-window on the top becomes a child window on the bottom and vice-versa."
+window on the top becomes a child window on the bottom and vice-versa.
+Signal an error if WINDOW is not a parent window or one of WINDOW's
+descendants is of fixed size or atomic.  Also signal an error if
+`transpose-dedicated-windows' is nil and a descendant window is
+dedicated."
   (interactive (list (window--rotate-interactive-arg)))
   (window--transpose (or window (window-main-window)) '(above . right) t))
 
@@ -128,11 +154,13 @@ window on the top becomes a child window on the bottom and vice-versa."
   "Transpose child windows of WINDOW.
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, transpose the
-layout of the child windows of the selected window's parent.  Signal an
-error if WINDOW is not a parent window.
+layout of the child windows of the selected window's parent.
 
 Recursively reorganize WINDOW's child windows so that each horizontal
-split becomes a vertical split and vice versa."
+split becomes a vertical split and vice versa.  Signal an error if
+WINDOW is not a parent window or one of WINDOW's descendants is of fixed
+size or atomic.  Also signal an error if `transpose-dedicated-windows'
+is nil and a descendant window is dedicated."
   (interactive (list (window--rotate-interactive-arg)))
   (window--transpose (or window (window-main-window)) '(right . below) nil))
 
@@ -154,9 +182,10 @@ selected frame.  Interactively, with a prefix argument, rotate the child
 windows of the selected window's parent.
 
 Optional argument REVERSE non-nil means to rotate windows backwards, in
-reverse cyclic order.  Signal an error if WINDOW is not a parent window,
-all descendants of WINDOW are dedicated or some windows are of fixed
-size or atomic.
+reverse cyclic order.  Signal an error if WINDOW is not a parent window
+or some descendants of WINDOW are of fixed size or atomic.  Also signal
+an error if `transpose-dedicated-windows' is nil and a descendant window
+is dedicated.
 
 Rotating windows leaves the way a frame layout has been produced via
 splitting, deleting and resizing windows unaltered.  It only \"moves\"
@@ -183,12 +212,8 @@ vice-versa), consider running `window-layout-flip-leftright' and
 	 (winls (or
                  (seq-filter
                   (lambda (win)
-                    (and (window-live-p win)
-                         (not (window-dedicated-p win))))
-                  (flatten-list win-tree))
-                 ;; Do we really care - the window/buffer relationship
-                 ;; should not be affected by rotating.
-                 (user-error "All windows are dedicated")))
+                    (window-live-p win))
+                  (flatten-list win-tree))))
 	 (rotated-ls (if reverse
 			 (append (cdr winls) (list (car winls)))
 		       (append (last winls) winls)))
@@ -199,13 +224,14 @@ vice-versa), consider running `window-layout-flip-leftright' and
           (named-let rec ((tree win-tree))
             (cond
              ((consp tree) (cons (rec (car tree)) (rec (cdr tree))))
-             ((and (window-live-p tree)
-                   (not (window-dedicated-p tree)))
+             ((window-live-p tree)
               (pop rotated-ls))
              (t tree)))))
     (when (or (seq-some #'window-atom-root winls)
-	      (seq-some #'window-fixed-size-p winls))
-      (user-error "Cannot rotate windows due to fixed size or atomic windows"))
+	      (seq-some #'window-fixed-size-p winls)
+              (and (not transpose-dedicated-windows)
+                   (seq-some #'window-dedicated-p winls)))
+      (user-error "Cannot rotate windows due to dedicated, fixed size or atomic window"))
     (delete-other-windows-internal first-window window)
     (window--transpose-1 new-win-tree first-window '(below . right) t nil)
     (when x-y
@@ -222,9 +248,12 @@ vice-versa), consider running `window-layout-flip-leftright' and
   "Rotate child windows of WINDOW backwards in cyclic ordering.
 WINDOW must be a parent window and defaults to the main window of the
 selected frame.  Interactively, with a prefix argument, rotate backwards
-the child windows of the selected window's parent.  Signal an error if
-WINDOW is not a parent window, all descendants of WINDOW are dedicated
-or some of them are of fixed size or atomic.
+the child windows of the selected window's parent.
+
+Signal an error if WINDOW is not a parent window or descendants of
+WINDOW are of fixed size or atomic.  Also signal an error if
+`transpose-dedicated-windows' is nil and a descendant window is
+dedicated.
 
 Rotating windows backwards leaves the way a frame layout has been
 produced via splitting, deleting and resizing windows unaltered.  It
@@ -260,8 +289,10 @@ with the same proportion of the total split."
     (unless (and (not (eq (car atom-windows) window))
 	         (or no-resize
 		     (and (not atom-windows)
-		          (not (seq-some #'window-fixed-size-p win-list)))))
-      (user-error "Cannot rotate windows due to fixed size or atom windows"))
+		          (not (seq-some #'window-fixed-size-p win-list))
+                          (or transpose-dedicated-windows
+                              (not (seq-some #'window-dedicated-p win-list))))))
+      (user-error "Cannot transpose windows due to dedicated, fixed size or atomic window"))
     (delete-dups atom-windows)
     (while (not (window-live-p first-window))
       (setq first-window (window-child first-window)))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.