]> code.delx.au - gnu-emacs/blobdiff - lisp/window.el
Fix last fix in `display-buffer-record-window'.
[gnu-emacs] / lisp / window.el
index b1acd93926c3cb7e68bfb05b2832d4fc2343ad05..32467c393dd0797306e0104d2072fbf7b89343fb 100644 (file)
@@ -1,6 +1,6 @@
 ;;; window.el --- GNU Emacs window commands aside from those written in C
 
-;; Copyright (C) 1985, 1989, 1992-1994, 2000-2014 Free Software
+;; Copyright (C) 1985, 1989, 1992-1994, 2000-2015 Free Software
 ;; Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
@@ -237,7 +237,12 @@ displays the buffer specified by BUFFER-OR-NAME before running BODY."
              (standard-output ,buffer)
              ,window ,value)
         (with-current-buffer ,buffer
-          (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+          (setq ,window (temp-buffer-window-show
+                         ,buffer
+                         ;; Remove window-height when it's handled below.
+                         (if (functionp (cdr (assq 'window-height (cdr ,vaction))))
+                             (assq-delete-all 'window-height (copy-sequence ,vaction))
+                           ,vaction))))
 
         (let ((inhibit-read-only t)
               (inhibit-modification-hooks t))
@@ -249,6 +254,12 @@ displays the buffer specified by BUFFER-OR-NAME before running BODY."
           (ignore-errors
             (funcall (cdr (assq 'window-height (cdr ,vaction))) ,window)))
 
+        (when (consp (cdr (assq 'preserve-size (cdr ,vaction))))
+          (window-preserve-size
+           ,window t (cadr (assq 'preserve-size (cdr ,vaction))))
+         (window-preserve-size
+           ,window nil (cddr (assq 'preserve-size (cdr ,vaction)))))
+
         (if (functionp ,vquit-function)
             (funcall ,vquit-function ,window ,value)
           ,value)))))
@@ -435,6 +446,14 @@ minimum pixel width of WINDOW."
       (window-safe-min-pixel-width window)
     (window-safe-min-pixel-height window)))
 
+(defun window-min-pixel-size (&optional window horizontal)
+  "Return the minimum pixel height of WINDOW.
+Optional argument HORIZONTAL non-nil means return the minimum
+pixel width of WINDOW."
+  (if horizontal
+      (window-min-pixel-width window)
+    (window-min-pixel-height window)))
+
 (defun window-combined-p (&optional window horizontal)
   "Return non-nil if WINDOW has siblings in a given direction.
 WINDOW must be a valid window and defaults to the selected one.
@@ -1141,7 +1160,7 @@ dumping to it."
       (insert
        (format "frame pixel: %s x %s   cols/lines: %s x %s   units: %s x %s\n"
               (frame-pixel-width frame) (frame-pixel-height frame)
-              (frame-total-cols frame) (frame-text-lines frame) ; (frame-total-lines frame)
+              (frame-total-cols frame) (frame-total-lines frame)
               (frame-char-width frame) (frame-char-height frame))
        (format "frame text pixel: %s x %s   cols/lines: %s x %s\n"
               (frame-text-width frame) (frame-text-height frame)
@@ -1215,9 +1234,73 @@ unless it has no other choice (like when deleting a neighboring
 window).")
 (make-variable-buffer-local 'window-size-fixed)
 
-(defun window--size-ignore-p (window ignore)
-  "Return non-nil if IGNORE says to ignore size restrictions for WINDOW."
-  (if (window-valid-p ignore) (eq window ignore) ignore))
+(defun window--preservable-size (window &optional horizontal)
+  "Return height of WINDOW as `window-preserve-size' would preserve it.
+Optional argument HORIZONTAL non-nil means to return the width of
+WINDOW as `window-preserve-size' would preserve it."
+  (if horizontal
+      (window-body-width window t)
+    (+ (window-body-height window t)
+       (window-header-line-height window)
+       (window-mode-line-height window))))
+
+(defun window-preserve-size (&optional window horizontal preserve)
+  "Preserve height of window WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+Optional argument HORIZONTAL non-nil means preserve the width of
+WINDOW.
+
+PRESERVE t means to preserve the current height/width of WINDOW's
+body in frame and window resizing operations whenever possible.
+The height/width of WINDOW will change only if Emacs has no other
+choice.  Resizing a window whose height/width is preserved never
+throws an error.
+
+PRESERVE nil means to stop preserving the height/width of WINDOW,
+lifting the respective restraint induced by a previous call of
+`window-preserve-size' for WINDOW.  Calling `enlarge-window',
+`shrink-window', `split-window' or `fit-window-to-buffer' with
+WINDOW as argument also removes the respective restraint.
+
+Other values of PRESERVE are reserved for future use."
+  (setq window (window-normalize-window window t))
+  (let* ((parameter (window-parameter window 'window-preserved-size))
+        (width (nth 1 parameter))
+        (height (nth 2 parameter)))
+    (if horizontal
+       (set-window-parameter
+        window 'window-preserved-size
+        (list
+         (window-buffer window)
+         (and preserve (window--preservable-size window t))
+         height))
+      (set-window-parameter
+       window 'window-preserved-size
+       (list
+       (window-buffer window)
+       width
+       (and preserve (window--preservable-size window)))))))
+
+(defun window-preserved-size (&optional window horizontal)
+  "Return preserved height of window WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+Optional argument HORIZONTAL non-nil means to return preserved
+width of WINDOW."
+  (setq window (window-normalize-window window t))
+  (let* ((parameter (window-parameter window 'window-preserved-size))
+        (buffer (nth 0 parameter))
+        (width (nth 1 parameter))
+        (height (nth 2 parameter)))
+    (when (eq buffer (window-buffer window))
+      (if horizontal width height))))
+
+(defun window--preserve-size (window horizontal)
+  "Return non-nil when the height of WINDOW shall be preserved.
+Optional argument HORIZONTAL non-nil means to return non-nil when
+the width of WINDOW shall be preserved."
+  (let ((size (window-preserved-size window horizontal)))
+    (and (numberp size)
+        (= size (window--preservable-size window horizontal)))))
 
 (defun window-safe-min-size (&optional window horizontal pixelwise)
   "Return safe minimum size of WINDOW.
@@ -1244,19 +1327,20 @@ Optional argument HORIZONTAL non-nil means return the minimum
 number of columns of WINDOW; otherwise return the minimum number
 of WINDOW's lines.
 
-Optional argument IGNORE, if non-nil, means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE equals `safe', live
-windows may get as small as `window-safe-min-height' lines and
-`window-safe-min-width' columns.  If IGNORE is a window, ignore
-restrictions for that window only.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
-
-Optional argument PIXELWISE non-nil means return the minimum pixel-size
-of WINDOW."
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument PIXELWISE non-nil means
+return the minimum pixel-size of WINDOW."
   (window--min-size-1
    (window-normalize-window window) horizontal ignore pixelwise))
 
+(defun window--min-size-ignore-p (window horizontal ignore)
+  "Return non-nil if IGNORE says to ignore height restrictions for WINDOW.
+HORIZONTAL non-nil means to return non-nil if IGNORE says to
+ignore width restrictions for WINDOW."
+  (if (window-valid-p ignore)
+      (eq window ignore)
+    (not (memq ignore '(nil preserved)))))
+
 (defun window--min-size-1 (window horizontal ignore pixelwise)
   "Internal function of `window-min-size'."
   (let ((sub (window-child window)))
@@ -1283,8 +1367,7 @@ of WINDOW."
        (cond
         ((window-minibuffer-p window)
          (if pixelwise (frame-char-height (window-frame window)) 1))
-        ((and (not (window--size-ignore-p window ignore))
-              (window-size-fixed-p window horizontal))
+        ((window-size-fixed-p window horizontal ignore)
          ;; The minimum size of a fixed size window is its size.
          (window-size window horizontal pixelwise))
         ((eq ignore 'safe)
@@ -1313,12 +1396,12 @@ of WINDOW."
                     pixel-width
                   ;; Round up to next integral of columns.
                   (* (ceiling pixel-width char-size) char-size))
-                (if (window--size-ignore-p window ignore)
+                (if (window--min-size-ignore-p window horizontal ignore)
                     0
                   (window-min-pixel-width window)))
              (max
               (ceiling pixel-width char-size)
-              (if (window--size-ignore-p window ignore)
+              (if (window--min-size-ignore-p window horizontal ignore)
                   0
                 window-min-width)))))
         ((let ((char-size (frame-char-size window))
@@ -1334,11 +1417,11 @@ of WINDOW."
                     pixel-height
                   ;; Round up to next integral of lines.
                   (* (ceiling pixel-height char-size) char-size))
-                (if (window--size-ignore-p window ignore)
+                (if (window--min-size-ignore-p window horizontal ignore)
                     0
                   (window-min-pixel-height window)))
              (max (ceiling pixel-height char-size)
-                  (if (window--size-ignore-p window ignore)
+                  (if (window--min-size-ignore-p window horizontal ignore)
                       0
                     window-min-height))))))))))
 
@@ -1363,26 +1446,17 @@ columns.  If WINDOW cannot be shrunk by -DELTA lines or columns,
 return the minimum value in the range DELTA..0 by which WINDOW
 can be shrunk.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE equals `safe', live
-windows may get as small as `window-safe-min-height' lines and
-`window-safe-min-width' columns.  If IGNORE is a window, ignore
-restrictions for that window only.  Any other non-nil value means
-ignore all of the above restrictions for all windows.
-
-Optional argument PIXELWISE non-nil means interpret DELTA as
-pixels."
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument PIXELWISE non-nil means
+interpret DELTA as pixels."
   (setq window (window-normalize-window window))
   (cond
    ((< delta 0)
     (max (- (window-min-size window horizontal ignore pixelwise)
            (window-size window horizontal pixelwise))
         delta))
-   ((window--size-ignore-p window ignore)
-    delta)
    ((> delta 0)
-    (if (window-size-fixed-p window horizontal)
+    (if (window-size-fixed-p window horizontal ignore)
        0
       delta))
    (t 0)))
@@ -1399,7 +1473,7 @@ doc-string of `window-sizable'."
     (<= (window-sizable window delta horizontal ignore pixelwise)
        delta)))
 
-(defun window--size-fixed-1 (window horizontal)
+(defun window--size-fixed-1 (window horizontal ignore)
   "Internal function for `window-size-fixed-p'."
   (let ((sub (window-child window)))
     (catch 'fixed
@@ -1410,7 +1484,7 @@ doc-string of `window-sizable'."
              ;; windows are fixed-size.
              (progn
                (while sub
-                 (unless (window--size-fixed-1 sub horizontal)
+                 (unless (window--size-fixed-1 sub horizontal ignore)
                    ;; We found a non-fixed-size child window, so
                    ;; WINDOW's size is not fixed.
                    (throw 'fixed nil))
@@ -1421,28 +1495,33 @@ doc-string of `window-sizable'."
            ;; An ortho-combination is fixed-size if at least one of its
            ;; child windows is fixed-size.
            (while sub
-             (when (window--size-fixed-1 sub horizontal)
+             (when (window--size-fixed-1 sub horizontal ignore)
                ;; We found a fixed-size child window, so WINDOW's size
                ;; is fixed.
                (throw 'fixed t))
              (setq sub (window-right sub))))
        ;; WINDOW is a live window.
-       (with-current-buffer (window-buffer window)
-         (if horizontal
-             (memq window-size-fixed '(width t))
-           (memq window-size-fixed '(height t))))))))
-
-(defun window-size-fixed-p (&optional window horizontal)
+       (and (or (not (windowp ignore)) (not (eq window ignore)))
+            (or (and (not (eq ignore 'preserved))
+                     (window--preserve-size window horizontal))
+                (with-current-buffer (window-buffer window)
+                  (if horizontal
+                      (memq window-size-fixed '(width t))
+                    (memq window-size-fixed '(height t))))))))))
+
+(defun window-size-fixed-p (&optional window horizontal ignore)
   "Return non-nil if WINDOW's height is fixed.
 WINDOW must be a valid window and defaults to the selected one.
 Optional argument HORIZONTAL non-nil means return non-nil if
-WINDOW's width is fixed.
+WINDOW's width is fixed.  The optional argument IGNORE has the
+same meaning as for `window-resizable'.
 
 If this function returns nil, this does not necessarily mean that
 WINDOW can be resized in the desired direction.  The function
 `window-resizable' can tell that."
-  (window--size-fixed-1
-   (window-normalize-window window) horizontal))
+  (when (or (windowp ignore) (memq ignore '(nil preserved)))
+    (window--size-fixed-1
+     (window-normalize-window window) horizontal ignore)))
 
 (defun window--min-delta-1 (window delta &optional horizontal ignore trail noup pixelwise)
   "Internal function for `window-min-delta'."
@@ -1463,8 +1542,7 @@ WINDOW can be resized in the desired direction.  The function
                 ((eq sub window)
                  (setq skip (eq trail 'before)))
                 (skip)
-                ((and (not (window--size-ignore-p window ignore))
-                      (window-size-fixed-p sub horizontal)))
+                ((window-size-fixed-p sub horizontal ignore))
                 (t
                  ;; We found a non-fixed-size child window.
                  (throw 'done delta)))
@@ -1493,25 +1571,18 @@ Return zero if WINDOW cannot be shrunk.
 Optional argument HORIZONTAL non-nil means return number of
 columns by which WINDOW can be shrunk.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE is a window, ignore
-restrictions for that window only.  If IGNORE equals `safe',
-live windows may get as small as `window-safe-min-height' lines
-and `window-safe-min-width' columns.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
-
-Optional argument TRAIL restricts the windows that can be enlarged.
-If its value is `before', only windows to the left of or above WINDOW
-can be enlarged.  If it is `after', only windows to the right of or
-below WINDOW can be enlarged.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument TRAIL restricts the
+windows that can be enlarged.  If its value is `before', only
+windows to the left of or above WINDOW can be enlarged.  If it is
+`after', only windows to the right of or below WINDOW can be
+enlarged.
 
 Optional argument NOUP non-nil means don't go up in the window
-tree, but try to enlarge windows within WINDOW's combination only.
-
-Optional argument NODOWN non-nil means don't check whether WINDOW
-itself (and its child windows) can be shrunk; check only whether
-at least one other window can be enlarged appropriately.
+tree, but try to enlarge windows within WINDOW's combination
+only.  Optional argument NODOWN non-nil means don't check whether
+WINDOW itself (and its child windows) can be shrunk; check only
+whether at least one other window can be enlarged appropriately.
 
 Optional argument PIXELWISE non-nil means return number of pixels
 by which WINDOW can be shrunk."
@@ -1533,14 +1604,16 @@ by which WINDOW can be shrunk."
       (window--min-delta-1
        window (- size minimum) horizontal ignore trail noup pixelwise)))))
 
-(defun frame-windows-min-size (&optional frame horizontal pixelwise)
+(defun frame-windows-min-size (&optional frame horizontal ignore pixelwise)
   "Return minimum number of lines of FRAME's windows.
 HORIZONTAL non-nil means return number of columns of FRAME's
-windows.  PIXELWISE non-nil means return sizes in pixels."
+windows.  The optional argument IGNORE has the same meaning as
+for `window-resizable'.  PIXELWISE non-nil means return sizes in
+pixels."
   (setq frame (window-normalize-frame frame))
   (let* ((root (frame-root-window frame))
         (mini (window-next-sibling root)))
-    (+ (window-min-size root horizontal nil pixelwise)
+    (+ (window-min-size root horizontal ignore pixelwise)
        (if (and mini (not horizontal))
           (window-min-size mini horizontal nil pixelwise)
         0))))
@@ -1575,8 +1648,7 @@ windows.  PIXELWISE non-nil means return sizes in pixels."
          ;; child window is fixed-size.
          (while sub
            (when (and (not (eq sub window))
-                      (not (window--size-ignore-p sub ignore))
-                      (window-size-fixed-p sub horizontal))
+                      (window-size-fixed-p sub horizontal ignore))
              (throw 'fixed delta))
            (setq sub (window-right sub))))
        (if noup
@@ -1595,32 +1667,24 @@ The return value is zero if WINDOW cannot be enlarged.
 Optional argument HORIZONTAL non-nil means return maximum number
 of columns by which WINDOW can be enlarged.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE is a window, ignore
-restrictions for that window only.  If IGNORE equals `safe',
-live windows may get as small as `window-safe-min-height' lines
-and `window-safe-min-width' columns.  Any other non-nil value means
-ignore all of the above restrictions for all windows.
-
-Optional argument TRAIL restricts the windows that can be enlarged.
-If its value is `before', only windows to the left of or above WINDOW
-can be enlarged.  If it is `after', only windows to the right of or
-below WINDOW can be enlarged.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument TRAIL restricts the
+windows that can be enlarged.  If its value is `before', only
+windows to the left of or above WINDOW can be enlarged.  If it is
+`after', only windows to the right of or below WINDOW can be
+enlarged.
 
 Optional argument NOUP non-nil means don't go up in the window
 tree but try to obtain the entire space from windows within
-WINDOW's combination.
-
-Optional argument NODOWN non-nil means do not check whether
-WINDOW itself (and its child windows) can be enlarged; check
-only whether other windows can be shrunk appropriately.
+WINDOW's combination.  Optional argument NODOWN non-nil means do
+not check whether WINDOW itself (and its child windows) can be
+enlarged; check only whether other windows can be shrunk
+appropriately.
 
 Optional argument PIXELWISE non-nil means return number of
 pixels by which WINDOW can be enlarged."
   (setq window (window-normalize-window window))
-  (if (and (not (window--size-ignore-p window ignore))
-          (not nodown) (window-size-fixed-p window horizontal))
+  (if (and (not nodown) (window-size-fixed-p window horizontal ignore))
       ;; With IGNORE and NOWDON nil return zero if WINDOW has fixed
       ;; size.
       0
@@ -1645,26 +1709,18 @@ columns.  If WINDOW cannot be shrunk by -DELTA lines or columns,
 return the minimum value in the range DELTA..0 that can be used
 for shrinking WINDOW.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE is a window, ignore
-restrictions for that window only.  If IGNORE equals `safe',
-live windows may get as small as `window-safe-min-height' lines
-and `window-safe-min-width' columns.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
-
-Optional argument TRAIL `before' means only windows to the left
-of or below WINDOW can be shrunk.  Optional argument TRAIL
-`after' means only windows to the right of or above WINDOW can be
-shrunk.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument TRAIL `before' means only
+windows to the left of or below WINDOW can be shrunk.  Optional
+argument TRAIL `after' means only windows to the right of or
+above WINDOW can be shrunk.
 
 Optional argument NOUP non-nil means don't go up in the window
 tree but check only whether space can be obtained from (or given
-to) WINDOW's siblings.
-
-Optional argument NODOWN non-nil means don't go down in the
-window tree.  This means do not check whether resizing would
-violate size restrictions of WINDOW or its child windows.
+to) WINDOW's siblings.  Optional argument NODOWN non-nil means
+don't go down in the window tree.  This means do not check
+whether resizing would violate size restrictions of WINDOW or its
+child windows.
 
 Optional argument PIXELWISE non-nil means interpret DELTA as
 number of pixels."
@@ -1714,13 +1770,14 @@ columns.  If WINDOW cannot be shrunk by -DELTA lines or columns,
 return the minimum value in the range DELTA..0 that can be used
 for shrinking WINDOW.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE is a window, ignore
-restrictions for that window only.  If IGNORE equals `safe',
-live windows may get as small as `window-safe-min-height' lines
-and `window-safe-min-width' columns.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
+Optional argument IGNORE, if non-nil, means to ignore restraints
+induced by fixed size windows or the values of the variables
+`window-min-height' and `window-min-width'.  The following values
+have special meanings: `safe' means that in addition live windows
+are allowed to get as small as `window-safe-min-height' lines and
+`window-safe-min-width' columns.  `preserved' means to ignore
+only restrictions induced by `window-preserve-size'.  If IGNORE
+is a window, then ignore restrictions for that window only.
 
 Optional argument PIXELWISE non-nil means interpret DELTA as
 pixels."
@@ -1778,6 +1835,61 @@ optional argument PIXELWISE is passed to the functions."
       (window-body-width window pixelwise)
     (window-body-height window pixelwise)))
 
+(defun window-font-width (&optional window face)
+   "Return average character width for the font of FACE used in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+If FACE is nil or omitted, the default face is used.  If FACE is
+remapped (see `face-remapping-alist'), the function returns the
+information for the remapped face."
+   (with-selected-window (window-normalize-window window t)
+     (if (display-multi-font-p)
+        (let* ((face (if face face 'default))
+               (info (font-info (face-font face)))
+               (width (aref info 11)))
+          (if (> width 0)
+             width
+            (aref info 10)))
+       (frame-char-width))))
+
+(defun window-font-height (&optional window face)
+   "Return character height for the font of FACE used in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+If FACE is nil or omitted, the default face is used.  If FACE is
+remapped (see `face-remapping-alist'), the function returns the
+information for the remapped face."
+   (with-selected-window (window-normalize-window window t)
+     (if (display-multi-font-p)
+        (let* ((face (if face face 'default))
+               (info (font-info (face-font face))))
+          (aref info 3))
+       (frame-char-height))))
+
+(defun window-max-chars-per-line (&optional window face)
+  "Return the number of characters that can be displayed on one line in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The character width of FACE is used for the calculation.  If FACE
+is nil or omitted, the default face is used.  If FACE is
+remapped (see `face-remapping-alist'), the function uses the
+remapped face.
+
+This function is different from `window-body-width' in two
+ways.  First, it accounts for the portions of the line reserved
+for the continuation glyph.  Second, it accounts for the size of
+the font."
+  (with-selected-window (window-normalize-window window t)
+    (let* ((window-width (window-body-width window t))
+          (font-width (window-font-width window face))
+          (ncols (/ window-width font-width)))
+      (if (and (display-graphic-p)
+              overflow-newline-into-fringe
+              (/= (frame-parameter nil 'left-fringe) 0)
+              (/= (frame-parameter nil 'right-fringe) 0))
+         ncols
+       (1- ncols)))))
+
 (defun window-current-scroll-bars (&optional window)
   "Return the current scroll bar types for WINDOW.
 WINDOW must be a live window and defaults to the selected one.
@@ -2419,13 +2531,14 @@ horizontally by DELTA columns.  In this case a positive DELTA
 means enlarge WINDOW by DELTA columns.  DELTA negative means
 WINDOW shall be shrunk by -DELTA columns.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE is a window, ignore
-restrictions for that window only.  If IGNORE equals `safe',
-live windows may get as small as `window-safe-min-height' lines
-and `window-safe-min-width' columns.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
+Optional argument IGNORE, if non-nil, means to ignore restraints
+induced by fixed size windows or the values of the variables
+`window-min-height' and `window-min-width'.  The following values
+have special meanings: `safe' means that in addition live windows
+are allowed to get as small as `window-safe-min-height' lines and
+`window-safe-min-width' columns.  `preserved' means to ignore
+only restrictions induced by `window-preserve-size'.  If IGNORE
+is a window, then ignore restrictions for that window only.
 
 Optional argument PIXELWISE non-nil means resize WINDOW by DELTA
 pixels.
@@ -2456,8 +2569,12 @@ instead."
       ;; nil or the minibuffer window is active, resize the minibuffer
       ;; window.
       (window--resize-mini-window minibuffer-window (- delta)))
-     ((window--resizable-p
-       window delta horizontal ignore nil nil nil t)
+     ((or (window--resizable-p
+          window delta horizontal ignore nil nil nil t)
+         (and (not ignore)
+              (setq ignore 'preserved)
+              (window--resizable-p
+               window delta horizontal ignore nil nil nil t)))
       (window--resize-reset frame horizontal)
       (window--resize-this-window window delta horizontal ignore t)
       (if (and (not window-combination-resize)
@@ -2615,13 +2732,8 @@ be a horizontally combined internal window.
 WINDOW, if specified, must denote a child window of PARENT that
 is resized by DELTA pixels.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE equals `safe', live
-windows may get as small as `window-safe-min-height' lines and
-`window-safe-min-width' columns.  If IGNORE is a window, ignore
-restrictions for that window only.  Any other non-nil value means
-ignore all of the above restrictions for all windows.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.
 
 Optional arguments TRAIL and EDGE, when non-nil, restrict the set
 of windows that shall be resized.  If TRAIL equals `before',
@@ -2692,7 +2804,7 @@ already set by this routine."
              ;; Ignore windows to skip and fixed-size child windows -
              ;; in the latter case make it a window to skip.
              (and (not ignore)
-                  (window-size-fixed-p sub horizontal)
+                  (window-size-fixed-p sub horizontal ignore)
                   (set-window-new-normal sub 'ignore))))
         ((< delta 0)
          ;; When shrinking store the number of lines/cols we can get
@@ -2798,13 +2910,8 @@ Optional argument HORIZONTAL non-nil means resize other windows
 when WINDOW is resized horizontally by DELTA pixels.  WINDOW
 itself is not resized by this function.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE equals `safe', live
-windows may get as small as `window-safe-min-height' lines and
-`window-safe-min-width' columns.  If IGNORE is a window, ignore
-restrictions for that window only.  Any other non-nil value means
-ignore all of the above restrictions for all windows.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.
 
 Optional arguments TRAIL and EDGE, when non-nil, refine the set
 of windows that shall be resized.  If TRAIL equals `before',
@@ -2831,8 +2938,7 @@ preferably only resize windows adjacent to EDGE."
                ;; Make sure this sibling is left alone when
                ;; resizing its siblings.
                (set-window-new-normal sub 'ignore))
-              ((or (window--size-ignore-p sub ignore)
-                   (not (window-size-fixed-p sub horizontal)))
+              ((not (window-size-fixed-p sub horizontal ignore))
                ;; Set this-delta to t to signal that we found a sibling
                ;; of WINDOW whose size is not fixed.
                (setq this-delta t)))
@@ -2902,16 +3008,9 @@ preferably only resize windows adjacent to EDGE."
 Optional argument HORIZONTAL non-nil means resize WINDOW
 horizontally by DELTA pixels.
 
-Optional argument IGNORE non-nil means ignore restrictions
-imposed by fixed size windows, `window-min-height' or
-`window-min-width' settings.  If IGNORE equals `safe', live
-windows may get as small as `window-safe-min-height' lines and
-`window-safe-min-width' columns.  If IGNORE is a window, ignore
-restrictions for that window only.  Any other non-nil value
-means ignore all of the above restrictions for all windows.
-
-Optional argument ADD non-nil means add DELTA to the new total
-size of WINDOW.
+The optional argument IGNORE has the same meaning as for
+`window-resizable'.  Optional argument ADD non-nil means add
+DELTA to the new total size of WINDOW.
 
 Optional arguments TRAIL and EDGE, when non-nil, refine the set
 of windows that shall be resized.  If TRAIL equals `before',
@@ -3057,7 +3156,7 @@ move it as far as possible in the desired direction."
   (let* ((frame (window-frame window))
         (minibuffer-window (minibuffer-window frame))
         (right window)
-        left this-delta min-delta max-delta)
+        left this-delta min-delta max-delta ignore)
 
     (unless pixelwise
       (setq pixelwise t)
@@ -3080,12 +3179,16 @@ move it as far as possible in the desired direction."
       (window--resize-mini-window minibuffer-window (- delta)))
      ((or (not (setq left right)) (not (setq right (window-right right))))
       (if horizontal
-         (error "No window on the right of this one")
-       (error "No window below this one")))
+         (user-error "No window on the right of this one")
+       (user-error "No window below this one")))
      (t
       ;; Set LEFT to the first resizable window on the left.  This step is
       ;; needed to handle fixed-size windows.
-      (while (and left (window-size-fixed-p left horizontal))
+      (while (and left
+                 (or (window-size-fixed-p left horizontal)
+                     (and (< delta 0)
+                          (<= (window-size left horizontal t)
+                              (window-min-size left horizontal nil t)))))
        (setq left
              (or (window-left left)
                  (progn
@@ -3093,13 +3196,31 @@ move it as far as possible in the desired direction."
                                (not (window-combined-p left horizontal))))
                    (window-left left)))))
       (unless left
-       (if horizontal
-           (error "No resizable window on the left of this one")
-         (error "No resizable window above this one")))
+       (setq ignore 'preserved)
+       (setq left window)
+       (while (and left
+                   (or (window-size-fixed-p left horizontal 'preserved)
+                       (<= (window-size left horizontal t)
+                           (window-min-size left horizontal 'preserved t))))
+         (setq left
+               (or (window-left left)
+                   (progn
+                     (while (and (setq left (window-parent left))
+                                 (not (window-combined-p left horizontal))))
+                     (window-left left)))))
+
+       (unless left
+         (if horizontal
+             (user-error "No resizable window on the left of this one")
+           (user-error "No resizable window above this one"))))
 
       ;; Set RIGHT to the first resizable window on the right.  This step
       ;; is needed to handle fixed-size windows.
-      (while (and right (window-size-fixed-p right horizontal))
+      (while (and right
+                 (or (window-size-fixed-p right horizontal)
+                     (and (> delta 0)
+                          (<= (window-size right horizontal t)
+                              (window-min-size right horizontal 'preserved t)))))
        (setq right
              (or (window-right right)
                  (progn
@@ -3107,9 +3228,22 @@ move it as far as possible in the desired direction."
                                (not (window-combined-p right horizontal))))
                    (window-right right)))))
       (unless right
-       (if horizontal
-           (error "No resizable window on the right of this one")
-         (error "No resizable window below this one")))
+       (setq ignore 'preserved)
+       (setq right (window-right window))
+       (while (and right
+                   (or (window-size-fixed-p right horizontal 'preserved))
+                   (<= (window-size right horizontal t)
+                       (window-min-size right horizontal nil t)))
+         (setq right
+               (or (window-right right)
+                   (progn
+                     (while (and (setq right (window-parent right))
+                                 (not (window-combined-p right horizontal))))
+                     (window-right right)))))
+       (unless right
+         (if horizontal
+             (user-error "No resizable window on the right of this one")
+           (user-error "No resizable window below this one"))))
 
       ;; LEFT and RIGHT (which might be both internal windows) are now the
       ;; two windows we want to resize.
@@ -3117,10 +3251,10 @@ move it as far as possible in the desired direction."
        ((> delta 0)
        (setq max-delta
              (window--max-delta-1
-              left 0 horizontal nil 'after nil pixelwise))
+              left 0 horizontal ignore 'after nil pixelwise))
        (setq min-delta
              (window--min-delta-1
-              right (- delta) horizontal nil 'before nil pixelwise))
+              right (- delta) horizontal ignore 'before nil pixelwise))
        (when (or (< max-delta delta) (> min-delta (- delta)))
          ;; We can't get the whole DELTA - move as far as possible.
          (setq delta (min max-delta (- min-delta))))
@@ -3129,26 +3263,26 @@ move it as far as possible in the desired direction."
          (window--resize-reset frame horizontal)
          ;; Try to enlarge LEFT first.
          (setq this-delta (window--resizable
-                           left delta horizontal nil 'after nil nil pixelwise))
+                           left delta horizontal ignore 'after nil nil pixelwise))
          (unless (zerop this-delta)
            (window--resize-this-window
-            left this-delta horizontal nil t 'before
+            left this-delta horizontal ignore t 'before
             (if horizontal
                 (+ (window-pixel-left left) (window-pixel-width left))
               (+ (window-pixel-top left) (window-pixel-height left)))))
          ;; Shrink windows on right of LEFT.
          (window--resize-siblings
-          left delta horizontal nil 'after
+          left delta horizontal ignore 'after
           (if horizontal
               (window-pixel-left right)
             (window-pixel-top right)))))
        ((< delta 0)
        (setq max-delta
              (window--max-delta-1
-              right 0 horizontal nil 'before nil pixelwise))
+              right 0 horizontal ignore 'before nil pixelwise))
        (setq min-delta
              (window--min-delta-1
-              left delta horizontal nil 'after nil pixelwise))
+              left delta horizontal ignore 'after nil pixelwise))
        (when (or (< max-delta (- delta)) (> min-delta delta))
          ;; We can't get the whole DELTA - move as far as possible.
          (setq delta (max (- max-delta) min-delta)))
@@ -3158,16 +3292,16 @@ move it as far as possible in the desired direction."
          ;; Try to enlarge RIGHT.
          (setq this-delta
                (window--resizable
-                right (- delta) horizontal nil 'before nil nil pixelwise))
+                right (- delta) horizontal ignore 'before nil nil pixelwise))
          (unless (zerop this-delta)
            (window--resize-this-window
-            right this-delta horizontal nil t 'after
+            right this-delta horizontal ignore t 'after
             (if horizontal
                 (window-pixel-left right)
               (window-pixel-top right))))
          ;; Shrink windows on left of RIGHT.
          (window--resize-siblings
-          right (- delta) horizontal nil 'before
+          right (- delta) horizontal ignore 'before
           (if horizontal
               (+ (window-pixel-left left) (window-pixel-width left))
             (+ (window-pixel-top left) (window-pixel-height left)))))))
@@ -3189,6 +3323,8 @@ make selected window wider by DELTA columns.  If DELTA is
 negative, shrink selected window by -DELTA lines or columns."
   (interactive "p")
   (let ((minibuffer-window (minibuffer-window)))
+    (when (window-preserved-size nil horizontal)
+      (window-preserve-size nil horizontal))
     (cond
      ((zerop delta))
      ((window-size-fixed-p nil horizontal)
@@ -3222,6 +3358,8 @@ negative, enlarge selected window by -DELTA lines or columns.
 Also see the `window-min-height' variable."
   (interactive "p")
   (let ((minibuffer-window (minibuffer-window)))
+    (when (window-preserved-size nil horizontal)
+      (window-preserve-size nil horizontal))
     (cond
      ((zerop delta))
      ((window-size-fixed-p nil horizontal)
@@ -4363,7 +4501,7 @@ frame.  The selected window is not changed by this function."
         (divider-width (if horizontal
                            (frame-right-divider-width frame)
                          (frame-bottom-divider-width frame)))
-        atom-root)
+        atom-root ignore)
     (window--check frame)
     (catch 'done
       (cond
@@ -4427,10 +4565,11 @@ frame.  The selected window is not changed by this function."
                (if resize
                    ;; When resizing try to give the new window the
                    ;; average size of a window in its combination.
-                   (min (- parent-pixel-size
-                           (window-min-size parent horizontal nil t))
-                        (/ parent-pixel-size
-                           (1+ (window-combinations parent horizontal))))
+                   (max (min (- parent-pixel-size
+                                (window-min-size parent horizontal nil t))
+                             (/ parent-pixel-size
+                                (1+ (window-combinations parent horizontal))))
+                        (window-min-pixel-size))
                  ;; Else try to give the new window half the size
                  ;; of WINDOW (plus an eventual odd pixel).
                  (/ old-pixel-size 2)))
@@ -4459,12 +4598,20 @@ frame.  The selected window is not changed by this function."
          (cond
           (resize
            ;; SIZE unspecified, resizing.
-           (unless (window-sizable-p
-                    parent (- new-pixel-size divider-width) horizontal nil t)
+           (unless (or (window-sizable-p
+                        parent (- (+ new-pixel-size divider-width)) horizontal
+                        nil t)
+                       (window-sizable-p
+                        parent (- (+ new-pixel-size divider-width)) horizontal
+                        (setq ignore 'preserved) t))
              (error "Window %s too small for splitting (1)" parent)))
-          ((> (+ new-pixel-size divider-width
-                 (window-min-size window horizontal nil t))
-              old-pixel-size)
+          ((and (> (+ new-pixel-size divider-width
+                      (window-min-size window horizontal nil t))
+                   old-pixel-size)
+                (> (+ new-pixel-size divider-width
+                      (window-min-size
+                       window horizontal (setq ignore 'preserved) t))
+                   old-pixel-size))
            ;; SIZE unspecified, no resizing.
            (error "Window %s too small for splitting (2)" window))))
         ((and (>= pixel-size 0)
@@ -4477,8 +4624,12 @@ frame.  The selected window is not changed by this function."
          (error "Window %s too small for splitting (3)" window))
         (resize
          ;; SIZE specified, resizing.
-         (unless (window-sizable-p
-                  parent (- new-pixel-size divider-width) horizontal nil t)
+         (unless (or (window-sizable-p
+                      parent (- (+ new-pixel-size divider-width)) horizontal
+                      nil t)
+                     (window-sizable-p
+                      parent (- (+ new-pixel-size divider-width)) horizontal
+                      (setq ignore 'preserved) t))
            ;; If we cannot resize the parent give up.
            (error "Window %s too small for splitting (4)" parent)))
         ((or (< new-pixel-size
@@ -4512,7 +4663,7 @@ frame.  The selected window is not changed by this function."
            ;; delete the one we create here.  Hence we do not go up.
            (progn
              (window--resize-child-windows
-              parent (- new-pixel-size) horizontal)
+              parent (- new-pixel-size) horizontal nil ignore)
              (let* ((normal (- 1.0 new-normal))
                     (sub (window-child parent)))
                (while sub
@@ -4522,10 +4673,8 @@ frame.  The selected window is not changed by this function."
          ;; Get entire space from WINDOW.
          (set-window-new-pixel
           window (- old-pixel-size new-pixel-size))
-;;       (set-window-new-pixel window (- old-pixel-size new-pixel-size))
-;;       (set-window-new-total
-;;        window (- old-size new-size))
-         (window--resize-this-window window (- new-pixel-size) horizontal)
+         (window--resize-this-window
+          window (- new-pixel-size) horizontal ignore)
          (set-window-new-normal
           window (- (if new-parent 1.0 (window-normal-size window horizontal))
                     new-normal)))
@@ -4579,7 +4728,7 @@ the original point in both windows."
 (defun split-window-below (&optional size)
   "Split the selected window into two windows, one above the other.
 The selected window is above.  The newly split-off window is
-below, and displays the same buffer.  Return the new window.
+below and displays the same buffer.  Return the new window.
 
 If optional argument SIZE is omitted or nil, both windows get the
 same height, or close to it.  If SIZE is positive, the upper
@@ -4633,7 +4782,7 @@ amount of redisplay; this is convenient on slow terminals."
 (defun split-window-right (&optional size)
   "Split the selected window into two side-by-side windows.
 The selected window is on the left.  The newly split-off window
-is on the right, and displays the same buffer.  Return the new
+is on the right and displays the same buffer.  Return the new
 window.
 
 If optional argument SIZE is omitted or nil, both windows get the
@@ -5131,7 +5280,7 @@ value can be also stored on disk and read back in a new session."
                (let ((scroll-bars (cdr (assq 'scroll-bars state))))
                  (set-window-scroll-bars
                   window (car scroll-bars) (nth 2 scroll-bars)
-                  (or (nth 3 scroll-bars) 0) (nth 5 scroll-bars)))
+                  (nth 3 scroll-bars) (nth 5 scroll-bars)))
                (set-window-vscroll window (cdr (assq 'vscroll state)))
                ;; Adjust vertically.
                (if (memq window-size-fixed '(t height))
@@ -5325,10 +5474,16 @@ element is BUFFER."
   (cond
    ((eq type 'reuse)
     (if (eq (window-buffer window) buffer)
-       ;; WINDOW shows BUFFER already.
-       (when (consp (window-parameter window 'quit-restore))
-         ;; If WINDOW has a quit-restore parameter, reset its car.
-         (setcar (window-parameter window 'quit-restore) 'same))
+       ;; WINDOW shows BUFFER already.  Update WINDOW's quit-restore
+       ;; parameter, if any.
+       (let ((quit-restore (window-parameter window 'quit-restore)))
+         (when (consp quit-restore)
+           (setcar quit-restore 'same)
+           ;; The selected-window might have changed in
+           ;; between (Bug#20353).
+           (unless (or (eq window (selected-window))
+                        (eq window (nth 2 quit-restore)))
+             (setcar (cddr quit-restore) (selected-window)))))
       ;; WINDOW shows another buffer.
       (with-current-buffer (window-buffer window)
        (set-window-parameter
@@ -5967,7 +6122,8 @@ live."
     (let ((parameter (window-parameter window 'quit-restore))
          (height (cdr (assq 'window-height alist)))
          (width (cdr (assq 'window-width alist)))
-         (size (cdr (assq 'window-size alist))))
+         (size (cdr (assq 'window-size alist)))
+         (preserve-size (cdr (assq 'preserve-size alist))))
       (cond
        ((or (eq type 'frame)
            (and (eq (car parameter) 'same)
@@ -6022,7 +6178,11 @@ live."
                       (window-combined-p window t))
              (window-resize window delta t 'safe))))
         ((functionp width)
-         (ignore-errors (funcall width window)))))))
+         (ignore-errors (funcall width window))))
+       ;; Preserve window size if asked for.
+       (when (consp preserve-size)
+         (window-preserve-size window t (car preserve-size))
+         (window-preserve-size window nil (cdr preserve-size))))))
 
     window))
 
@@ -6241,6 +6401,10 @@ Recognized alist entries include:
     of not displaying the buffer and FUNCTION can safely return
     a non-window value to suppress displaying.
 
+ `preserve-size' -- Value should be either '(t . nil)' to
+    preserve the width of the window, '(nil . t)' to preserve its
+    height or '(t . t)' to preserve both.
+
 The ACTION argument to `display-buffer' can also have a non-nil
 and non-list value.  This means to display the buffer in a window
 other than the selected one, even if it is already displayed in
@@ -7242,7 +7406,7 @@ FRAME."
           (frame-text-height))
         frame-resize-pixelwise)))))
 
-(defun fit-window-to-buffer (&optional window max-height min-height max-width min-width)
+(defun fit-window-to-buffer (&optional window max-height min-height max-width min-width preserve-size)
   "Adjust size of WINDOW to display its buffer's contents exactly.
 WINDOW must be a live window and defaults to the selected one.
 
@@ -7266,6 +7430,9 @@ and defaults to `window-min-width'.  Both MAX-WIDTH and MIN-WIDTH
 are specified in columns and include fringes, margins, a
 scrollbar and a vertical divider, if any.
 
+If the optional argument `preserve-size' is non-nil, preserve the
+size of WINDOW (see `window-preserve-size').
+
 Fit pixelwise if the option `window-resize-pixelwise' is non-nil.
 If WINDOW is its frame's root window and the option
 `fit-frame-to-buffer' is non-nil, call `fit-frame-to-buffer' to
@@ -7307,25 +7474,25 @@ accessible position."
                (max (if pixelwise
                         (* char-height window-min-height)
                       window-min-height)
-                    (window-min-size nil nil t pixelwise))))
+                    (window-min-size window nil window pixelwise))))
             (max-height
              ;; Sanitize MAX-HEIGHT.
              (if (numberp max-height)
                  (min
                   (+ total-height
                      (window-max-delta
-                      window nil nil nil nil nil pixelwise))
+                      window nil window nil nil nil pixelwise))
                   (if pixelwise
                       (* char-height max-height)
                     max-height))
                (+ total-height (window-max-delta
-                                window nil nil nil nil nil pixelwise))))
+                                window nil window nil nil nil pixelwise))))
             height)
        (cond
         ;; If WINDOW is vertically combined, try to resize it
         ;; vertically.
         ((and (not (eq fit-window-to-buffer-horizontally 'only))
-              (not (window-size-fixed-p window))
+              (not (window-size-fixed-p window 'preserved))
               (window-combined-p))
          ;; Vertically we always want to fit the entire buffer.
          ;; WINDOW'S height can't get larger than its frame's pixel
@@ -7338,14 +7505,17 @@ accessible position."
          (unless pixelwise
            (setq height (/ (+ height char-height -1) char-height)))
          (unless (= height total-height)
+           (window-preserve-size window)
            (window-resize-no-error
             window
             (- (max min-height (min max-height height)) total-height)
-            nil window pixelwise)))
+            nil window pixelwise)
+           (when preserve-size
+             (window-preserve-size window nil t))))
         ;; If WINDOW is horizontally combined, try to resize it
         ;; horizontally.
         ((and fit-window-to-buffer-horizontally
-              (not (window-size-fixed-p window t))
+              (not (window-size-fixed-p window t 'preserved))
               (window-combined-p nil t))
          (let* ((total-width (window-size window t pixelwise))
                 (min-width
@@ -7362,18 +7532,18 @@ accessible position."
                    (max (if pixelwise
                             (* char-width window-min-width)
                           window-min-width)
-                        (window-min-size nil nil t pixelwise))))
+                        (window-min-size nil nil window pixelwise))))
                 (max-width
                  ;; Sanitize MAX-WIDTH.
                  (if (numberp max-width)
                      (min (+ total-width
                              (window-max-delta
-                              nil t nil nil nil nil pixelwise))
+                              window t window nil nil nil pixelwise))
                           (if pixelwise
                               (* char-width max-width)
                             max-width))
                    (+ total-width (window-max-delta
-                                   nil t nil nil nil nil pixelwise))))
+                                   window t window nil nil nil pixelwise))))
                 ;; When fitting horizontally, assume that WINDOW's
                 ;; start position remains unaltered.  WINDOW can't get
                 ;; wider than its frame's pixel width, its height
@@ -7391,13 +7561,16 @@ accessible position."
            (unless pixelwise
              (setq width (/ (+ width char-width -1) char-width)))
            (unless (= width body-width)
+             (window-preserve-size window t)
              (window-resize-no-error
               window
               (- (max min-width
                       (min max-width
                            (+ total-width (- width body-width))))
                  total-width)
-              t window pixelwise)))))))))
+              t window pixelwise)
+             (when preserve-size
+               (window-preserve-size window t t))))))))))
 
 (defun window-safely-shrinkable-p (&optional window)
   "Return t if WINDOW can be shrunk without shrinking other windows.
@@ -7691,6 +7864,9 @@ With arg N, put point N/10 of the way from the true end."
 (defvar mouse-autoselect-window-timer nil
   "Timer used by delayed window autoselection.")
 
+(defvar mouse-autoselect-window-position-1 nil
+  "First mouse position recorded by delayed window autoselection.")
+
 (defvar mouse-autoselect-window-position nil
   "Last mouse position recorded by delayed window autoselection.")
 
@@ -7715,6 +7891,7 @@ Optional argument FORCE means cancel unconditionally."
                        (memq (nth 4 (event-end last-input-event))
                              '(handle end-scroll)))))
     (setq mouse-autoselect-window-state nil)
+    (setq mouse-autoselect-window-position-1 nil)
     (when (timerp mouse-autoselect-window-timer)
       (cancel-timer mouse-autoselect-window-timer))
     (remove-hook 'pre-command-hook 'mouse-autoselect-window-cancel)))
@@ -7756,21 +7933,32 @@ is active.  This function is run by `mouse-autoselect-window-timer'."
        ;; A menu / popup dialog is active or the mouse is not on the
        ;; text region of WINDOW: Suspend autoselection temporarily.
        (mouse-autoselect-window-start mouse-position nil t))
-      ((eq mouse-autoselect-window-state 'suspend)
+      ((or (eq mouse-autoselect-window-state 'suspend)
+          ;; When the mouse is at its first recorded position, restart
+          ;; delayed autoselection.  This works around a scenario with
+          ;; two two-window frames with identical dimensions: select the
+          ;; first window of the first frame, switch to the second
+          ;; frame, move the mouse to its second window, minimize the
+          ;; second frame.  Now the second window of the first frame
+          ;; gets selected although the mouse never really "moved" into
+          ;; that window.
+          (and (numberp mouse-autoselect-window)
+               (equal (mouse-position) mouse-autoselect-window-position-1)))
        ;; Delayed autoselection was temporarily suspended, reenable it.
        (mouse-autoselect-window-start mouse-position))
       ((and window (not (eq window (selected-window)))
            (or (not (numberp mouse-autoselect-window))
-               (and (> mouse-autoselect-window 0)
-                    ;; If `mouse-autoselect-window' is positive, select
-                    ;; window if the window is the same as before.
+               (and (>= mouse-autoselect-window 0)
+                    ;; If `mouse-autoselect-window' is non-negative,
+                    ;; select window if it's the same as before.
                     (eq window mouse-autoselect-window-window))
-               ;; Otherwise select window if the mouse is at the same
-               ;; position as before.  Observe that the first test after
-               ;; starting autoselection usually fails since the value of
-               ;; `mouse-autoselect-window-position' recorded there is the
-               ;; position where the mouse has entered the new window and
-               ;; not necessarily where the mouse has stopped moving.
+               ;; Otherwise select window iff the mouse is at the same
+               ;; position as before.  Observe that the first test
+               ;; after starting autoselection usually fails since the
+               ;; value of `mouse-autoselect-window-position' recorded
+               ;; there is the position where the mouse has entered the
+               ;; new window and not necessarily where the mouse has
+               ;; stopped moving.
                (equal mouse-position mouse-autoselect-window-position))
            ;; The minibuffer is a candidate window if it's active.
            (or (not (window-minibuffer-p window))
@@ -7814,14 +8002,14 @@ is active.  This function is run by `mouse-autoselect-window-timer'."
                     (not (minibuffer-window-active-p window)))
                ;; Don't switch when autoselection shall be delayed.
                (and (numberp mouse-autoselect-window)
-                    (not (zerop mouse-autoselect-window))
                     (not (eq mouse-autoselect-window-state 'select))
-                    (progn
+                    (let ((position (mouse-position)))
                       ;; Cancel any delayed autoselection.
                       (mouse-autoselect-window-cancel t)
                       ;; Start delayed autoselection from current mouse
                       ;; position and window.
-                      (mouse-autoselect-window-start (mouse-position) window)
+                      (setq mouse-autoselect-window-position-1 position)
+                      (mouse-autoselect-window-start position window)
                       ;; Executing a command cancels delayed autoselection.
                       (add-hook
                        'pre-command-hook 'mouse-autoselect-window-cancel))))
@@ -7847,7 +8035,107 @@ Otherwise, consult the value of `truncate-partial-width-windows'
                                       (window-buffer window))))
       (if (integerp t-p-w-w)
          (< (window-width window) t-p-w-w)
-       t-p-w-w))))
+        t-p-w-w))))
+
+\f
+;; Automatically inform subprocesses of changes to window size.
+
+(defcustom window-adjust-process-window-size-function
+  'window-adjust-process-window-size-smallest
+  "Control how Emacs chooses inferior process window sizes.
+Emacs uses this function to tell processes the space they have
+available for displaying their output.  After each window
+configuration change, Emacs calls the value of
+`window-adjust-process-window-size-function' for each process
+with a buffer being displayed in at least one window.
+This function is responsible for combining the sizes of the
+displayed windows and returning a cons (WIDTH . HEIGHT)
+describing the width and height with which Emacs will call
+`set-process-window-size' for that process.  If the function
+returns `nil', Emacs does not call `set-process-window-size'.
+
+This function is called with the process buffer as the current
+buffer and with two arguments: the process and a list of windows
+displaying process.  Modes can make this variable buffer-local;
+additionally, the `adjust-window-size-function' process property
+overrides the global or buffer-local value of
+`window-adjust-process-window-size-function'."
+  :type '(choice
+          (const :tag "Minimum area of any window"
+           window-adjust-process-window-size-smallest)
+          (const :tag "Maximum area of any window"
+           window-adjust-process-window-size-largest)
+          (const :tag "Do not adjust process window sizes" ignore)
+          function)
+  :group 'windows
+  :version "25.1")
+
+(defun window-adjust-process-window-size (reducer process windows)
+  "Adjust the process window size of PROCESS.
+WINDOWS is a list of windows associated with PROCESS.  REDUCER is
+a two-argument function used to combine the widths and heights of
+the given windows."
+  (when windows
+    (let ((width (window-body-width (car windows)))
+          (height (window-body-height (car windows))))
+      (dolist (window (cdr windows))
+        (setf width (funcall reducer width (window-body-width window)))
+        (setf height (funcall reducer height (window-body-height window))))
+      (cons width height))))
+
+(defun window-adjust-process-window-size-smallest (process windows)
+  "Adjust the process window size of PROCESS.
+WINDOWS is a list of windows associated with PROCESS.  Choose the
+smallest area available for displaying PROCESS's output."
+  (window-adjust-process-window-size #'min process windows))
+
+(defun window-adjust-process-window-size-largest (process windows)
+  "Adjust the process window size of PROCESS.
+WINDOWS is a list of windows associated with PROCESS.  Choose the
+largest area available for displaying PROCESS's output."
+  (window-adjust-process-window-size #'max process windows))
+
+(defun window--process-window-list ()
+  "Return an alist mapping processes to associated windows.
+A window is associated with a process if that window is
+displaying that processes's buffer."
+  (let ((processes (process-list))
+        (process-windows nil))
+    (walk-windows
+     (lambda (window)
+       (let ((buffer (window-buffer window))
+             (iter processes))
+         (while (let ((process (car iter)))
+                  (if (and (process-live-p process)
+                           (eq buffer (process-buffer process)))
+                      (let ((procwin (assq process process-windows)))
+                        ;; Add this window to the list of windows
+                        ;; displaying process.
+                        (if procwin
+                            (push window (cdr procwin))
+                          (push (list process window) process-windows))
+                        ;; We found our process for this window, so
+                        ;; stop iterating over the process list.
+                        nil)
+                    (setf iter (cdr iter)))))))
+     1 t)
+    process-windows))
+
+(defun window--adjust-process-windows ()
+  "Update process window sizes to match the current window configuration."
+  (dolist (procwin (window--process-window-list))
+    (let ((process (car procwin)))
+      (with-demoted-errors "Error adjusting window size: %S"
+        (with-current-buffer (process-buffer process)
+          (let ((size (funcall
+                       (or (process-get process 'adjust-window-size-function)
+                           window-adjust-process-window-size-function)
+                       process (cdr procwin))))
+            (when size
+              (set-process-window-size process (cdr size) (car size)))))))))
+
+(add-hook 'window-configuration-change-hook 'window--adjust-process-windows)
+
 \f
 ;; Some of these are in tutorial--default-keys, so update that if you
 ;; change these.