master 68a9c61fa9b 1/2: Merge from origin/emacs-31

Paul Eggert <[email protected]> Wed, 15 Jul 2026 15:53:48 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: master
commit 68a9c61fa9b5bed72349bc2905b2da8f6328dd13
Merge: 71a81c9853e 407de5142c2
Author: Paul Eggert <[email protected]>
Commit: Paul Eggert <[email protected]>

    Merge from origin/emacs-31
    
    407de5142c2 Port pdumper to m68k
    0818bb3eb38 ; * etc/NEWS: Presentational fixes and improvements.
    f620924322d ; Improve doc-strings of window rotation commands
    937de3fa927 ; Fix typos in preceding commit
    48a481ac8d8 ; Improve documentation of window-rotation commands
    afc5fc709b7 browse-url-with-browser-kind: Use strings for DEF
    4be321d5115 Fix issues related to window layout changes (Bug#81406)
    86b65d82c7f Turn off combination resizing in 'window--transpose-1' (B...
    7a9c0049249 ; Clarify documentation of 'filter-buffer-substring'
    b6412271e13 Fix copy-by-mouse in *Backtrace* buffers
    eebc9c7fe72 ; * etc/DEBUG: Info about -g3 on OpenBSD (bug#81109).
    2b8aa16b0b8 Support javascript "using" keyword (bug#81351)
    
    # Conflicts:
    #       etc/NEWS
---
 doc/lispref/text.texi                |   8 +-
 doc/lispref/windows.texi             |  40 ++++---
 etc/DEBUG                            |  11 +-
 etc/NEWS.31                          |  29 +++--
 lisp/emacs-lisp/backtrace.el         |   6 +-
 lisp/net/browse-url.el               |   4 +-
 lisp/progmodes/js.el                 |  31 +++--
 lisp/progmodes/typescript-ts-mode.el |   2 +-
 lisp/simple.el                       |   6 +-
 lisp/window-x.el                     | 213 +++++++++++++++++++++--------------
 src/pdumper.c                        |  22 +++-
 src/window.c                         |   5 +-
 12 files changed, 244 insertions(+), 133 deletions(-)

diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 0b9dc4951a5..db2410fbf30 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -238,7 +238,10 @@ reordering of bidirectional text, use the
 @defun filter-buffer-substring start end &optional delete
 This function filters the buffer text between @var{start} and @var{end}
 using a function specified by the variable
-@code{filter-buffer-substring-function}, and returns the result.
+@code{filter-buffer-substring-function}, and returns the result.  The
+order of buffer positions specified by @var{start} and @var{end} should
+not matter, since this function is frequently used for extracting text
+passed to kill functions (@pxref{Kill Functions}).
 
 The default filter function consults the obsolete wrapper hook
 @code{filter-buffer-substring-functions} (see the documentation string
@@ -264,6 +267,9 @@ will call to do the actual work.  The function receives three
 arguments, the same as those of @code{filter-buffer-substring},
 which it should treat as per the documentation of that function.  It
 should return the filtered text (and optionally delete the source text).
+Note that it must process the @var{start} and @var{end} arguments
+regardless of the order of the buffer positions they specify, to comply
+with the protocol of extracting text for the purposes of killing it.
 @end defvar
 
 @noindent The following two variables are obsoleted by
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 9caaa5e6901..ddc8524ddb6 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -2025,6 +2025,13 @@ combination.
 The default is @code{nil}.  Other values are reserved for future use.  A
 specific split operation may ignore the value of this variable if it is
 affected by a non-@code{nil} value of @code{window-combination-limit}.
+
+If you plan to use a sequence of @code{split-window} calls to produce a
+specific, predefined layout of windows on a frame, bind this variable
+temporarily to @code{nil}.  @code{window-state-put} (@pxref{Window
+Configurations}) and the functions which change window layouts
+(@pxref{Changing Window Layouts}) do that in order to restore a previous
+or systematically changed layout of a frame.
 @end defopt
 
   To illustrate the effect of @code{window-combination-resize}, consider
@@ -2302,9 +2309,9 @@ below, we shall always assume that the windows displayed constitute
 their frame's main window and the @var{window} argument is @code{nil}
 unless stated otherwise.
 
-   The first two commands rotate a window layout either clockwise or
-counterclockwise.
 @cindex rotate window layout
+   The first two commands rotate an entire window layout either
+clockwise or counterclockwise.
 
 @deffn Command window-layout-rotate-clockwise &optional window
 This command rotates the window layout clockwise by 90 degrees.  Imagine
@@ -2344,9 +2351,10 @@ layout in the opposite direction as demonstrated in the example below.
 @end smallexample
 @end deffn
 
-The next two commands @sc{flip} the window layout---rotate it around an
-imaginary horizontal or vertical axis.
 @cindex flip window layout
+The next two commands @sc{flip} the window layout---rotate it around an
+imaginary horizontal or vertical axis.  If the number of windows to be
+flipped is odd, the window in the middle remains in its original place.
 
 @deffn Command window-layout-flip-topdown &optional window
 This command flips windows such that windows on the bottom become
@@ -2368,7 +2376,7 @@ windows on the top and vice-versa as in the example below.
 
 @deffn Command window-layout-flip-leftright &optional window
 This command rearranges window in a way that the windows on the right
-become the window on the left, and vice-versa.
+become the windows on the left, and vice-versa.
 
 @smallexample
 @group
@@ -2406,16 +2414,22 @@ becomes a vertical split and vice versa.
 @end smallexample
 @end deffn
 
-The final two commands can be used to rotate windows within the existing
+@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.
-@cindex rotating windows
+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.
 
 @deffn Command rotate-windows &optional window reverse
-This rotate windows under @var{window} in cyclic ordering.  The optional
-argument @var{reverse} means to rotate windows backward, in reverse
-cyclic order.
+This command rotates @var{window}'c child windows in cyclic ordering.
+The optional argument @var{reverse} means to rotate windows backwards,
+in reverse cyclic order.
 
 @smallexample
 @group
@@ -2432,7 +2446,7 @@ cyclic order.
 @end deffn
 
 @deffn Command rotate-windows-back &optional window
-This command rotates windows under @var{window} backward in cyclic
+This command rotates @var{window}'s child windows backwards in cyclic
 ordering.
 
 @smallexample
@@ -2455,7 +2469,7 @@ The last two commands are subject to the following option.
 If this is @code{nil}, the selected window will remain unaffected by
 @code{rotate-windows} and @code{rotate-windows-back}.  Otherwise, the
 selected window will change to the window that appears at the location
-of the selected window before any of these commands were invoked.
+of the window selected before any of these commands were invoked.
 @end defopt
 
 
diff --git a/etc/DEBUG b/etc/DEBUG
index e70fe8de390..ff0e1932dce 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -25,8 +25,15 @@ happens only with optimized code, you may need to enable optimizations.
 If that happens, try using -Og first instead of -O2, as -Og disables
 some optimizations that make debugging some code exceptionally hard.
 
-Older versions of GCC may need more than just the -g3 flag.  For more,
-search for "analyze failed assertions" below.
+The -g3 option is needed to allow GDB expand macros, which the Emacs C
+code uses a lot; without it, you will need to look up the macro
+definitions in the C headers and source files, and expand them by hand,
+before using them in expressions you want GDB to evaluate.  Older
+versions of GCC may need more than just the -g3 flag.  Also, Emacs
+compiled with -g3 reportedly causes GDB to crash on OpenBSD, so on that
+OS you should instead use either -ggdb or just -g (and the macro
+information will be unavailable to GDB, unfortunately).  For more about
+-g3, search for "analyze failed assertions" below.
 
 The 2 --enable-* switches are optional.  They don't have any effect on
 debugging with GDB, but will compile additional code that might catch
diff --git a/etc/NEWS.31 b/etc/NEWS.31
index 4609e9b6910..27512710eb1 100644
--- a/etc/NEWS.31
+++ b/etc/NEWS.31
@@ -29,6 +29,9 @@ applies, and please also update docstrings as needed.
 The traditional unexec dumper, deprecated since Emacs 27, has been
 removed.
 
++++
+*** The portable dumper now works on m68k a.out targets.
+
 ---
 ** Emacs's old 'ctags' program is no longer built or installed.
 You are encouraged to use Universal Ctags <https://ctags.io/> instead.
@@ -357,14 +360,24 @@ increments as with Emacs 24 through Emacs 30 you now have to set
 ** Windows
 
 +++
-*** New commands to modify window layouts.
-
-- 'C-x w t' and 'C-x w r <left>/<right>' rotate the window layout.
-- 'C-x w o <left>/<right>' rotate the windows within the current layout.
-- 'C-x w f <left>/<right>/<up>/<down>' flip window layouts.
-
-By default, these commands operate on the selected frame's root window.
-With a prefix argument, they operate on the selected window's parent.
+*** New commands to modify window layouts of frames.
+'window-layout-rotate-clockwise' ('C-x w r <right>') and its counterpart
+'window-layout-rotate-anticlockwise' ('C-x w r <left>') rotate an entire
+window layout.
+'window-layout-flip-topdown' ('C-x w f <down>', 'C-x w f <up>') and
+'window-layout-flip-leftright' ('C-x w f <left>', 'C-x w f <right>')
+flip the window layout vertically and horizontally.
+'window-layout-transpose' ('C-x w t') reorganizes windows such that
+every horizontal split becomes a vertical split and vice versa.
+'rotate-windows' ('C-x w o <right>') and its counterpart
+'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.
 
 +++
 *** Windmove commands now move to skipped windows if invoked twice in a row.
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el
index 440061e6e29..dfdd026dd4f 100644
--- a/lisp/emacs-lisp/backtrace.el
+++ b/lisp/emacs-lisp/backtrace.el
@@ -813,7 +813,11 @@ Fall back to `prin1' if there is an error."
 
 (defun backtrace--filter-visible (beg end &optional _delete)
   "Return the visible text between BEG and END."
-  (let ((result ""))
+  (let ((result "")
+        (b (min beg end))
+        (e (max beg end)))
+    ;; Make sure BEG and END are in the correct order.
+    (setq beg b end e)
     (while (< beg end)
       (let ((next (next-single-char-property-change beg 'invisible)))
         (unless (get-char-property beg 'invisible)
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index b75c4f119a0..6700211cda3 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -988,8 +988,8 @@ opposite of the browser kind of `browse-url-browser-function'."
           (default (if (eq (browse-url--browser-kind
                             browse-url-browser-function (car url-arg))
                            'internal)
-                       'external
-                     'internal))
+                       "external"
+                     "internal"))
           (k (intern (completing-read
                       (format-prompt "Browser kind" default)
                       '(internal external)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 3f2deca317c..bd58b16d342 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -289,7 +289,7 @@ Match group 1 is the name of the macro.")
      "instanceof" "interface" "native" "new" "of" "package"
      "private" "protected" "public" "return" "static"
      "super" "switch" "synchronized" "throw"
-     "throws" "transient" "try" "typeof" "var" "void" "let"
+     "throws" "transient" "try" "typeof" "using" "var" "void" "let"
      "yield" "volatile" "while" "with"))
   "Regexp matching any JavaScript keyword.")
 
@@ -1740,7 +1740,7 @@ point of view of font-lock.  It applies highlighting directly with
 
     ;; variable declarations
     ,(list
-      (concat "\\_<\\(const\\|var\\|let\\)\\_>\\|" js--basic-type-re)
+      (concat "\\_<\\(const\\|var\\|let\\|using\\)\\_>\\|" js--basic-type-re)
       (list #'js--variable-decl-matcher nil nil nil))
 
     ;; class instantiation
@@ -2352,7 +2352,7 @@ testing for syntax only valid as JSX."
   "Regexp matching keywords optionally followed by an opening brace.")
 
 (defconst js--declaration-keyword-re
-  (regexp-opt '("var" "let" "const") 'words)
+  (regexp-opt '("var" "let" "const" "using") 'words)
   "Regular expression matching variable declaration keywords.")
 
 (defconst js--indent-operator-re
@@ -3581,6 +3581,14 @@ characters of the current line."
     "typeof" "var" "void" "while" "with" "yield")
   "JavaScript keywords for tree-sitter font-locking.")
 
+
+;; "using" support was only added in tree-sitter-javascript 0.25.0, in
+;; https://github.com/tree-sitter/tree-sitter-javascript/commit/ebdb4f17a4da79a70344a41ae76bb95b2415a653
+;; So make it optional
+(defvar js--treesit-optional-keywords
+  '("using")
+  "JavaScript optional keywords for tree-sitter font-locking.")
+
 (defvar js--treesit-operators
   '("=" "+=" "-=" "*=" "/=" "%=" "**=" "<<=" ">>=" ">>>=" "&=" "^="
     "|=" "&&=" "||=" "??=" "==" "!=" "===" "!==" ">" ">=" "<" "<=" "+"
@@ -3605,8 +3613,10 @@ characters of the current line."
 
    :language 'javascript
    :feature 'keyword
-   `([,@js--treesit-keywords] @font-lock-keyword-face
-     [(this) (super)] @font-lock-keyword-face)
+   (treesit-query-with-optional 'javascript
+     `([,@js--treesit-keywords] @font-lock-keyword-face
+       [(this) (super)] @font-lock-keyword-face)
+     `([,@js--treesit-optional-keywords] @font-lock-keyword-face))
 
    :language 'javascript
    :feature 'string
@@ -3789,7 +3799,7 @@ Return nil if there is no name or if NODE is not a defun node."
   (treesit-node-text
    (treesit-node-child-by-field-name
     (pcase (treesit-node-type node)
-      ((or "lexical_declaration" "variable_declaration")
+      ((or "lexical_declaration" "variable_declaration" "using_declaration")
        (treesit-search-subtree node "variable_declarator" nil nil 1))
       ((or "function_declaration" "method_definition" "class_declaration")
        node))
@@ -3799,7 +3809,7 @@ Return nil if there is no name or if NODE is not a defun node."
 (defun js--treesit-valid-imenu-entry (node)
   "Return nil if NODE is a non-top-level lexical/variable declaration."
   (pcase (treesit-node-type node)
-    ((or "lexical_declaration" "variable_declaration")
+    ((or "lexical_declaration" "variable_declaration" "using_declaration")
      (not (treesit-node-top-level
            node (rx bos (or "class_declaration"
                             "method_definition"
@@ -3930,6 +3940,7 @@ Currently there are `js-mode' and `js-ts-mode'."
     "labeled_statement"
     "variable_declaration"
     "lexical_declaration"
+    "using_declaration"
     "jsx_opening_element"
     "jsx_attribute"
     "jsx_closing_element")
@@ -3997,7 +4008,8 @@ See `treesit-thing-settings' for more information.")
     ("Method" "\\`method_definition\\'" nil nil)
     ("Function" "\\`function_declaration\\'" nil nil)
     ("Variable" ,(rx bos (or "lexical_declaration"
-                             "variable_declaration")
+                             "variable_declaration"
+                             "using_declaration")
                      eos)
      ,#'js--treesit-valid-imenu-entry nil))
   "Settings for `treesit-simple-imenu'.")
@@ -4015,7 +4027,8 @@ See `treesit-thing-settings' for more information.")
               "method_definition"
               "function_declaration"
               "lexical_declaration"
-              "variable_declaration")
+              "variable_declaration"
+              "using_declaration")
       eos)
   "Settings for `treesit-defun-type-regexp'.")
 
diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el
index cf13363e48a..dc951811bb3 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -225,7 +225,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
     "get" "if" "implements" "import" "in" "instanceof" "interface" "is" "infer"
     "keyof" "let" "namespace" "new" "of" "private" "protected"
     "public" "readonly" "return" "satisfies" "set" "static" "switch"
-    "target" "throw" "try" "type" "typeof" "var" "void"
+    "target" "throw" "try" "type" "typeof" "using" "var" "void"
     "while" "with" "yield")
   "TypeScript keywords for tree-sitter font-locking.")
 
diff --git a/lisp/simple.el b/lisp/simple.el
index d92abe331c8..1f7d57f299a 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -5579,12 +5579,14 @@ These commands include \\[set-mark-command] and \\[start-kbd-macro]."
   "Function to perform the filtering in `filter-buffer-substring'.
 The function is called with the same 3 arguments (BEG END DELETE)
 that `filter-buffer-substring' received.  It should return the
-buffer substring between BEG and END, after filtering.  If DELETE is
-non-nil, it should delete the text between BEG and END from the buffer.")
+buffer substring between BEG and END, regardless of the order of
+BEG and END, after filtering.  If DELETE is non-nil, it should
+delete the text between BEG and END from the buffer.")
 
 (defun filter-buffer-substring (beg end &optional delete)
   "Return the buffer substring between BEG and END, after filtering.
 If DELETE is non-nil, delete the text between BEG and END from the buffer.
+The order of BEG and END does not matter.
 
 This calls the function that `filter-buffer-substring-function' specifies
 \(passing the same three arguments that it received) to do the work,
diff --git a/lisp/window-x.el b/lisp/window-x.el
index 813b8aed9f3..8cb24a06674 100644
--- a/lisp/window-x.el
+++ b/lisp/window-x.el
@@ -29,17 +29,8 @@
 
 ;;; Code:
 
-(defcustom rotate-windows-change-selected t
-  "If nil the selected window will not change with `rotate-windows'.
-
-The selected window before and after the function call will stay
-unchanged if nil.  `rotate-windows-back' is also affected."
-  :type 'boolean
-  :group 'windows)
-
 (defun window-tree-normal-sizes (window &optional next)
   "Return normal sizes of all windows rooted at WINDOW.
-
 The return value is a list of the form (SPLIT-TYPE PARENT-WIN
 PARENT-WIN-HEIGHT PARENT-WIN-WIDTH . WS), where SPLIT-TYPE is non-nil if
 PARENT-WIN is split horizontally; PARENT-WIN is the internal window;
@@ -47,7 +38,7 @@ PARENT-WIN-HEIGHT and PARENT-WIN-WIDTH are the normal heights of
 PARENT-WIN; and WS is a list of lists the form (WINDOW HEIGHT WIDTH)
 where HEIGHT and WIDTH are the normal height and width of the window.
 
-(fn WINDOW)"
+\(fn WINDOW)"
   (let (list)
     (while window
       (setq list
@@ -77,97 +68,117 @@ where HEIGHT and WIDTH are the normal height and width of the window.
   (if current-prefix-arg (window-parent) (window-main-window)))
 
 ;;;###autoload
-(defun window-layout-rotate-anticlockwise (&optional window)
-  "Rotate window layout of WINDOW counterclockwise by 90 degrees.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to rotate the parent window of the
-selected window."
+(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.
+
+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."
   (interactive (list (window--rotate-interactive-arg)))
-  (window--transpose window '(right . above) nil))
+  (window--transpose (or window (window-main-window)) '(left . below) nil))
 
 ;;;###autoload
-(defun window-layout-rotate-clockwise (&optional window)
-  "Rotate window layout under WINDOW clockwise by 90 degrees.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to rotate the parent window of the
-selected window."
+(defun window-layout-rotate-anticlockwise (&optional window)
+  "Rotate layout of WINDOW's child windows counterclockwise 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
+counterclockwise the layout of the child windows of the selected
+window's parent.  Signal an error if WINDOW is not a parent window.
+
+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."
   (interactive (list (window--rotate-interactive-arg)))
-  (window--transpose window '(left . below) nil))
+  (window--transpose (or window (window-main-window)) '(right . above) nil))
 
 ;;;###autoload
 (defun window-layout-flip-leftright (&optional window)
-  "Horizontally flip windows under WINDOW.
-
-Flip the window layout so that the window on the right becomes the
-window on the left, and vice-versa.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to flip the parent window of the
-selected window."
+  "Flip WINDOW's child windows horizontally.
+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.
+
+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."
   (interactive (list (window--rotate-interactive-arg)))
-  (window--transpose window '(below . left) t))
+  (window--transpose (or window (window-main-window)) '(below . left) t))
 
 ;;;###autoload
 (defun window-layout-flip-topdown (&optional window)
-  "Vertically flip windows under WINDOW.
-
-Flip the window layout so that the top window becomes the bottom window,
-and vice-versa.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to flip the parent window of the
-selected window."
+  "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.
+
+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."
   (interactive (list (window--rotate-interactive-arg)))
-  (window--transpose window '(above . right) t))
+  (window--transpose (or window (window-main-window)) '(above . right) t))
 
 ;;;###autoload
 (defun window-layout-transpose (&optional window)
-  "Transpose windows under WINDOW.
-
-Reorganize the windows under WINDOW so that every horizontal split
-becomes a vertical split, and vice versa.  This is equivalent to
-diagonally flipping.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to transpose the parent window of
-the selected window."
+  "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.
+
+Recursively reorganize WINDOW's child windows so that each horizontal
+split becomes a vertical split and vice versa."
   (interactive (list (window--rotate-interactive-arg)))
-  (window--transpose window '(right . below) nil))
-
-;;;###autoload
-(defun rotate-windows-back (&optional window)
-  "Rotate windows under WINDOW backward in cyclic ordering.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
+  (window--transpose (or window (window-main-window)) '(right . below) nil))
 
-Interactively, a prefix argument says to rotate the parent window of the
-selected window."
-  (interactive (list (window--rotate-interactive-arg)))
-  (rotate-windows window t))
+(defcustom rotate-windows-change-selected t
+  "Whether rotating windows will change the selected window.
+If this is nil, `rotate-windows' and `rotate-windows-back' do not change
+a frame's selected window.  Otherwise, the new selected window will be
+the window that appears at the location of the previously selected
+window."
+  :type 'boolean
+  :version "31.1"
+  :group 'windows)
 
 ;;;###autoload
 (defun rotate-windows (&optional window reverse)
-  "Rotate windows under WINDOW in cyclic ordering.
-
-Optional argument REVERSE says to rotate windows backward, in reverse
-cyclic order.
-
-If WINDOW is nil, it defaults to the root window of the selected frame.
-
-Interactively, a prefix argument says to rotate the parent window of the
-selected window."
+  "Rotate child windows of WINDOW 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 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.
+
+Rotating windows leaves the way a frame layout has been produced via
+splitting, deleting and resizing windows unaltered.  It only \"moves\"
+windows within that layout such that the space formerly occupied by any
+window is now occupied by the window preceding (following if REVERSE is
+non-nil) it in the cycling ordering.
+
+If you want to rotate the entire layout of windows, consider using the
+function `window-layout-rotate-clockwise' instead.  If you want to
+rotate a layout twice in a row in order to have a window on the bottom
+appear on the top and a window on the right appear on the left (or
+vice-versa), consider running `window-layout-flip-leftright' and
+`window-layout-flip-topdown' instead."
   (interactive (list (window--rotate-interactive-arg)))
-  (when (or (not window) (window-live-p window))
+  (setq window (or window (window-main-window)))
+  (when (window-live-p window)
     (user-error "No windows to rotate"))
   (let* ((frame (window-frame window))
 	 (selected-window (frame-selected-window window))
+         (x-y (and rotate-windows-change-selected
+                   (cons (1+ (window-pixel-left selected-window))
+                         (1+ (window-pixel-top selected-window)))))
 	 (win-tree (car (window-tree-normal-sizes window)))
 	 (winls (or
                  (seq-filter
@@ -175,11 +186,12 @@ selected window."
                     (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")))
 	 (rotated-ls (if reverse
 			 (append (cdr winls) (list (car winls)))
 		       (append (last winls) winls)))
-	 (other-window-arg (if reverse 1 -1))
 	 (first-window (car rotated-ls))
 	 (new-win-tree
           ;; Recursively process `win-tree' and construct a new tree
@@ -193,14 +205,40 @@ selected window."
              (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 atom windows"))
+      (user-error "Cannot rotate windows due to fixed size or atomic windows"))
     (delete-other-windows-internal first-window window)
     (window--transpose-1 new-win-tree first-window '(below . right) t nil)
-    (set-frame-selected-window frame selected-window)
-    (when rotate-windows-change-selected
-      (other-window other-window-arg)
-      (while (not (memq (selected-window) winls))
-        (other-window other-window-arg)))))
+    (when x-y
+      ;; Try to select the window at the position previously occupied by
+      ;; the selected window.
+      (let ((window-at-x-y (window-at-x-y (car x-y) (cdr x-y) frame t)))
+        (when window-at-x-y
+          (setq selected-window window-at-x-y))))
+
+    (set-frame-selected-window frame selected-window)))
+
+;;;###autoload
+(defun rotate-windows-back (&optional window)
+  "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.
+
+Rotating windows backwards leaves the way a frame layout has been
+produced via splitting, deleting and resizing windows unaltered.  It
+only \"moves\" windows within that layout such that the space formerly
+occupied by any window is now occupied by the window following it in
+the cycling ordering.
+
+If you want to rotate the entire layout of windows backwards, consider
+using the function `window-layout-rotate-anticlockwise' instead.  If you
+want to rotate a layout backwards twice in a row, consider running
+`window-layout-flip-leftright' and `window-layout-flip-topdown'
+instead."
+  (interactive (list (window--rotate-interactive-arg)))
+  (rotate-windows window t))
 
 (defun window--transpose (window conf no-resize)
   "Rearrange windows under WINDOW recursively.
@@ -243,7 +281,9 @@ ones in `window--transpose'."
   ;; `flen' is max size the window could be converted to the opposite
   ;; of the given split type.
   (let ((parent-window-is-set t)
-	(flen (if (xor no-resize (car subtree))
+        ;; Make sure combination resizing is turned off (Bug#81406).
+        window-combination-resize
+        (flen (if (xor no-resize (car subtree))
 		  (float (window-pixel-width cwin))
 		(float (window-pixel-height cwin)))))
     (mapc
@@ -422,8 +462,7 @@ absolute value of ARG.  Return the new frame."
       (let ((comb (window-get-split-combination main arg)))
         (window-state-put (window-state-get comb)
 			  (window-main-window (make-frame)))
-        (delete-window comb))
-      ))))
+        (delete-window comb))))))
 
 (provide 'window-x)
 ;;; window-x.el ends here
diff --git a/src/pdumper.c b/src/pdumper.c
index 039768b022b..02f93a954e1 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -268,10 +268,20 @@ struct dump_table_locator
 enum
   {
    DUMP_RELOC_TYPE_BITS = 5,
-   DUMP_RELOC_ALIGNMENT_BITS = 2,
 
-   /* Minimum alignment required by dump file format.  */
-   DUMP_RELOCATION_ALIGNMENT = 1 << DUMP_RELOC_ALIGNMENT_BITS,
+   /* Minimum alignment required by dump file format.  Although this can
+      be any integer power of 2 up to alignof (Lisp_Alignment),
+      larger values help dump_reloc_set_offset support larger offsets.
+      The fix for bug#44531 was discovered late during Emacs 31 development,
+      so on Emacs 31 the value is 4 except on hosts where 4 is known to fail.
+      The only known failure is m68k a.out, so work around the problem
+      only if __mc68000__ is defined and the Lisp_Object alignment is 2,
+      which is a known property of the m68k a.out format.  */
+#ifdef __mc68000__
+   DUMP_RELOCATION_ALIGNMENT = min (4, alignof (Lisp_Object)),
+#else
+   DUMP_RELOCATION_ALIGNMENT = 4,
+#endif
 
    /* The alignment granularity (in bytes) for objects we store in the
       dump.  Always suitable for heap objects; may be more aligned.  */
@@ -303,14 +313,14 @@ dump_reloc_set_type (struct dump_reloc *reloc, enum dump_reloc_type type)
 static dump_off
 dump_reloc_get_offset (struct dump_reloc reloc)
 {
-  return reloc.raw_offset << DUMP_RELOC_ALIGNMENT_BITS;
+  return reloc.raw_offset * DUMP_RELOCATION_ALIGNMENT;
 }
 
 static void
 dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset)
 {
-  eassert (offset >= 0);
-  reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS;
+  eassume (offset >= 0);
+  reloc->raw_offset = offset / DUMP_RELOCATION_ALIGNMENT;
   if (dump_reloc_get_offset (*reloc) != offset)
     error ("dump relocation out of range");
 }
diff --git a/src/window.c b/src/window.c
index f5f2e1b91f0..78a5a4436f1 100644
--- a/src/window.c
+++ b/src/window.c
@@ -9483,7 +9483,10 @@ windows in the same combination.
 Other values are reserved for future use.
 
 A specific split operation may ignore the value of this variable if it
-is affected by a non-nil value of `window-combination-limit'.  */);
+is affected by a non-nil value of `window-combination-limit'.  If you
+want to use a sequence of `split-window' calls to produce a specific,
+predefined layout of windows on a frame, bind this variable temporarily
+to nil.  */);
   Vwindow_combination_resize = Qnil;
 
   DEFVAR_LISP ("window-combination-limit", Vwindow_combination_limit,