]> code.delx.au - gnu-emacs/blobdiff - lisp/window.el
Merge from emacs-24; up to 2014-07-27T09:41:59Z!ttn@gnu.org
[gnu-emacs] / lisp / window.el
index 357d49d02a2def4ea7b5b4d69c7b31b50cc2029c..91a0e159a8442e2f2be936d98a555eb4130fe484 100644 (file)
@@ -108,7 +108,7 @@ Return the buffer."
       ;; Return the buffer.
       buffer)))
 
-(defun temp-buffer-window-show (&optional buffer action)
+(defun temp-buffer-window-show (buffer &optional action)
   "Show temporary buffer BUFFER in a window.
 Return the window showing BUFFER.  Pass ACTION as action argument
 to `display-buffer'."
@@ -142,28 +142,28 @@ to `display-buffer'."
        ;; Return the window.
        window))))
 
-;; Doc is very similar to with-output-to-temp-buffer.
 (defmacro with-temp-buffer-window (buffer-or-name action quit-function &rest body)
   "Bind `standard-output' to BUFFER-OR-NAME, eval BODY, show the buffer.
-BUFFER-OR-NAME must specify either a live buffer, or the name of a
-buffer (if it does not exist, this macro creates it).
+BUFFER-OR-NAME must specify either a live buffer, or the name of
+buffer (if it does not exist, this macro creates it).
 
-This construct makes buffer BUFFER-OR-NAME empty before running BODY.
-It does not make the buffer current for BODY.
-Instead it binds `standard-output' to that buffer, so that output
+Make the buffer specified by BUFFER-OR-NAME empty before running
+BODY and bind `standard-output' to that buffer, so that output
 generated with `prin1' and similar functions in BODY goes into
-the buffer.
-
-At the end of BODY, this marks the specified buffer unmodified and
-read-only, and displays it in a window (but does not select it, or make
-the buffer current).  The display happens by calling `display-buffer'
-with the ACTION argument.  If `temp-buffer-resize-mode' is enabled,
-the relevant window shrinks automatically.
-
-This returns the value returned by BODY, unless QUIT-FUNCTION specifies
-a function.  In that case, it runs the function with two arguments -
+that buffer.  Do not make that buffer current for running the
+forms in BODY.  Use `with-current-buffer-window' instead if you
+need to run BODY with that buffer current.
+
+At the end of BODY, mark the specified buffer unmodified and
+read-only, and display it in a window (but do not select it).
+The display happens by calling `display-buffer' passing it the
+ACTION argument.  If `temp-buffer-resize-mode' is enabled, the
+corresponding window may be resized automatically.
+
+Return the value returned by BODY, unless QUIT-FUNCTION specifies
+a function.  In that case, run that function with two arguments -
 the window showing the specified buffer and the value returned by
-BODY - and returns the value returned by that function.
+BODY - and return the value returned by that function.
 
 If the buffer is displayed on a new frame, the window manager may
 decide to select that frame.  In that case, it's usually a good
@@ -172,30 +172,86 @@ before reading any value from the minibuffer; for example, when
 asking a `yes-or-no-p' question.
 
 This runs the hook `temp-buffer-window-setup-hook' before BODY,
-with the specified buffer temporarily current.  It runs the
-hook `temp-buffer-window-show-hook' after displaying the buffer,
-with that buffer temporarily current, and the window that was used to
+with the specified buffer temporarily current.  It runs the hook
+`temp-buffer-window-show-hook' after displaying the buffer, with
+that buffer temporarily current, and the window that was used to
 display it temporarily selected.
 
-This construct is similar to `with-output-to-temp-buffer', but
-runs different hooks.  In particular, it does not run
-`temp-buffer-setup-hook', which usually puts the buffer in Help mode.
-Also, it does not call `temp-buffer-show-function' (the ACTION
+This construct is similar to `with-output-to-temp-buffer' but,
+neither runs `temp-buffer-setup-hook' which usually puts the
+buffer in Help mode, nor `temp-buffer-show-function' (the ACTION
 argument replaces this)."
   (declare (debug t))
   (let ((buffer (make-symbol "buffer"))
        (window (make-symbol "window"))
        (value (make-symbol "value")))
-    `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name))
-           (standard-output ,buffer)
-           ,window ,value)
-       (with-current-buffer ,buffer
-        (setq ,value (progn ,@body))
-        (setq ,window (temp-buffer-window-show ,buffer ,action)))
+    (macroexp-let2 nil vbuffer-or-name buffer-or-name
+      (macroexp-let2 nil vaction action
+       (macroexp-let2 nil vquit-function quit-function
+         `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+                 (standard-output ,buffer)
+                 ,window ,value)
+            (setq ,value (progn ,@body))
+            (with-current-buffer ,buffer
+              (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+
+            (if (functionp ,vquit-function)
+                (funcall ,vquit-function ,window ,value)
+              ,value)))))))
+
+(defmacro with-current-buffer-window (buffer-or-name action quit-function &rest body)
+  "Evaluate BODY with a buffer BUFFER-OR-NAME current and show that buffer.
+This construct is like `with-temp-buffer-window' but unlike that
+makes the buffer specified by BUFFER-OR-NAME current for running
+BODY."
+  (declare (debug t))
+  (let ((buffer (make-symbol "buffer"))
+       (window (make-symbol "window"))
+       (value (make-symbol "value")))
+    (macroexp-let2 nil vbuffer-or-name buffer-or-name
+      (macroexp-let2 nil vaction action
+       (macroexp-let2 nil vquit-function quit-function
+         `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+                 (standard-output ,buffer)
+                 ,window ,value)
+            (with-current-buffer ,buffer
+              (setq ,value (progn ,@body))
+              (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+
+            (if (functionp ,vquit-function)
+                (funcall ,vquit-function ,window ,value)
+              ,value)))))))
+
+(defmacro with-displayed-buffer-window (buffer-or-name action quit-function &rest body)
+  "Show a buffer BUFFER-OR-NAME and evaluate BODY in that buffer.
+This construct is like `with-current-buffer-window' but unlike that
+displays the buffer specified by BUFFER-OR-NAME before running BODY."
+  (declare (debug t))
+  (let ((buffer (make-symbol "buffer"))
+       (window (make-symbol "window"))
+       (value (make-symbol "value")))
+    (macroexp-let2 nil vbuffer-or-name buffer-or-name
+      (macroexp-let2 nil vaction action
+       (macroexp-let2 nil vquit-function quit-function
+         `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+                 (standard-output ,buffer)
+                 ,window ,value)
+            (with-current-buffer ,buffer
+              (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+
+            (let ((inhibit-read-only t)
+                  (inhibit-modification-hooks t))
+              (setq ,value (progn ,@body)))
+
+            (set-window-point ,window (point-min))
 
-       (if (functionp ,quit-function)
-          (funcall ,quit-function ,window ,value)
-        ,value))))
+            (when (functionp (cdr (assq 'window-height (cdr ,vaction))))
+              (ignore-errors
+                (funcall (cdr (assq 'window-height (cdr ,vaction))) ,window)))
+
+            (if (functionp ,vquit-function)
+                (funcall ,vquit-function ,window ,value)
+              ,value)))))))
 
 ;; The following two functions are like `window-next-sibling' and
 ;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so
@@ -320,8 +376,9 @@ Anything less might crash Emacs.")
      (frame-char-size (window-normalize-window window))))
 
 (defcustom window-min-height 4
-  "The minimum number of lines of any window.
-The value has to accommodate a mode- or header-line if present.
+  "The minimum total height, in lines, of any window.
+The value has to accommodate one text line, a mode and header
+line, a horizontal scroll bar and a bottom divider, if present.
 A value less than `window-safe-min-height' is ignored.  The value
 of this variable is honored when windows are resized or split.
 
@@ -350,11 +407,11 @@ Anything less might crash Emacs.")
      (frame-char-size (window-normalize-window window) t)))
 
 (defcustom window-min-width 10
-  "The minimum number of columns of any window.
-The value has to accommodate margins, fringes, or scrollbars if
-present.  A value less than `window-safe-min-width' is ignored.
-The value of this variable is honored when windows are resized or
-split.
+  "The minimum total width, in columns, of any window.
+The value has to accommodate two text columns as well as margins,
+fringes, a scroll bar and a right divider, if present.  A value
+less than `window-safe-min-width' is ignored.  The value of this
+variable is honored when windows are resized or split.
 
 Applications should never rebind this variable.  To resize a
 window to a width less than the one specified here, an
@@ -686,6 +743,15 @@ number of slots on that side."
      (integer :tag "Number" :value 3 :size 5)))
   :group 'windows)
 
+(defun window--side-window-p (window)
+  "Return non-nil if WINDOW is a side window or the parent of one."
+  (or (window-parameter window 'window-side)
+      (and (window-child window)
+          (or (window-parameter
+               (window-child window) 'window-side)
+              (window-parameter
+               (window-last-child window) 'window-side)))))
+
 (defun window--major-non-side-window (&optional frame)
   "Return the major non-side window of frame FRAME.
 The optional argument FRAME must be a live frame and defaults to
@@ -1059,7 +1125,6 @@ WINDOW-OR-FRAME can be a frame or a window and defaults to the
 selected frame.  When WINDOW-OR-FRAME is a window, dump that
 window's frame.  The buffer *window-frame-dump* is erased before
 dumping to it."
-  (interactive)
   (let* ((window
          (cond
           ((or (not window-or-frame)
@@ -1081,9 +1146,12 @@ dumping to it."
        (format "frame text pixel: %s x %s   cols/lines: %s x %s\n"
               (frame-text-width frame) (frame-text-height frame)
               (frame-text-cols frame) (frame-text-lines frame))
-       (format "tool: %s  scroll: %s  fringe: %s  border: %s  right: %s  bottom: %s\n\n"
-              (tool-bar-height frame t)
+       (format "tool: %s  scroll: %s/%s  fringe: %s  border: %s  right: %s  bottom: %s\n\n"
+              (if (fboundp 'tool-bar-height)
+                  (tool-bar-height frame t)
+                "0")
               (frame-scroll-bar-width frame)
+              (frame-scroll-bar-height frame)
               (frame-fringe-width frame)
               (frame-border-width frame)
               (frame-right-divider-width frame)
@@ -1096,8 +1164,17 @@ dumping to it."
 WINDOW must be a valid window and defaults to the selected one.
 
 If HORIZONTAL is omitted or nil, return the total height of
-WINDOW, in lines, like `window-total-height'.  Otherwise return
-the total width, in columns, like `window-total-width'.
+WINDOW, in lines.  If WINDOW is live, its total height includes,
+in addition to the height of WINDOW's text, the heights of
+WINDOW's mode and header line and a bottom divider, if any.
+
+If HORIZONTAL is non-nil, return the total width of WINDOW, in
+columns.  If WINDOW is live, its total width includes, in
+addition to the width of WINDOW's text, the widths of WINDOW's
+fringes, margins, scroll bars and its right divider, if any.
+
+If WINDOW is internal, return the respective size of the screen
+areas spanned by its children.
 
 Optional argument ROUND is handled as for `window-total-height'
 and `window-total-width'."
@@ -1204,12 +1281,14 @@ of WINDOW."
          value)
       (with-current-buffer (window-buffer 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))
          ;; The minimum size of a fixed size window is its size.
          (window-size window horizontal pixelwise))
-        ((or (eq ignore 'safe) (eq ignore window))
-         ;; If IGNORE equals `safe' or WINDOW return the safe values.
+        ((eq ignore 'safe)
+         ;; If IGNORE equals `safe' return the safe value.
          (window-safe-min-size window horizontal pixelwise))
         (horizontal
          ;; For the minimum width of a window take fringes and
@@ -1220,8 +1299,11 @@ of WINDOW."
          ;; `window-min-width'.
          (let* ((char-size (frame-char-size window t))
                 (fringes (window-fringes window))
+                (margins (window-margins window))
                 (pixel-width
                  (+ (window-safe-min-size window t t)
+                    (* (or (car margins) 0) char-size)
+                    (* (or (cdr margins) 0) char-size)
                     (car fringes) (cadr fringes)
                     (window-scroll-bar-width window)
                     (window-right-divider-width window))))
@@ -1233,7 +1315,7 @@ of WINDOW."
                   (* (ceiling pixel-width char-size) char-size))
                 (if (window--size-ignore-p window ignore)
                     0
-                  (window-min-pixel-width)))
+                  (window-min-pixel-width window)))
              (max
               (ceiling pixel-width char-size)
               (if (window--size-ignore-p window ignore)
@@ -1243,6 +1325,7 @@ of WINDOW."
                (pixel-height
                 (+ (window-safe-min-size window nil t)
                    (window-header-line-height window)
+                   (window-scroll-bar-height window)
                    (window-mode-line-height window)
                    (window-bottom-divider-width window))))
            (if pixelwise
@@ -1253,7 +1336,7 @@ of WINDOW."
                   (* (ceiling pixel-height char-size) char-size))
                 (if (window--size-ignore-p window ignore)
                     0
-                  (window-min-pixel-height)))
+                  (window-min-pixel-height window)))
              (max (ceiling pixel-height char-size)
                   (if (window--size-ignore-p window ignore)
                       0
@@ -1450,6 +1533,18 @@ 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)
+  "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."
+  (setq frame (window-normalize-frame frame))
+  (let* ((root (frame-root-window frame))
+        (mini (window-next-sibling root)))
+    (+ (window-min-size root horizontal nil pixelwise)
+       (if (and mini (not horizontal))
+          (window-min-size mini horizontal nil pixelwise)
+        0))))
+
 (defun window--max-delta-1 (window delta &optional horizontal ignore trail noup pixelwise)
   "Internal function of `window-max-delta'."
   (if (not (window-parent window))
@@ -1471,7 +1566,7 @@ by which WINDOW can be shrunk."
                  (setq delta
                        (+ delta
                           (max
-                           (- (window-size sub horizontal pixelwise 'ceiling)
+                           (- (window-size sub horizontal pixelwise 'floor)
                               (window-min-size
                                sub horizontal ignore pixelwise))
                            0)))))
@@ -1650,9 +1745,6 @@ doc-string of `window-resizable'."
 (defalias 'window-height 'window-total-height)
 (defalias 'window-width 'window-body-width)
 
-;; Eventually the following two should work pixelwise.
-
-;; See discussion in bug#4543.
 (defun window-full-height-p (&optional window)
   "Return t if WINDOW is as high as its containing frame.
 More precisely, return t if and only if the total height of
@@ -1660,8 +1752,10 @@ WINDOW equals the total height of the root window of WINDOW's
 frame.  WINDOW must be a valid window and defaults to the
 selected one."
   (setq window (window-normalize-window window))
-  (= (window-pixel-height window)
-     (window-pixel-height (frame-root-window window))))
+  (if (window-minibuffer-p window)
+      (eq window (frame-root-window (window-frame window)))
+    (= (window-pixel-height window)
+       (window-pixel-height (frame-root-window window)))))
 
 (defun window-full-width-p (&optional window)
   "Return t if WINDOW is as wide as its containing frame.
@@ -1672,40 +1766,39 @@ WINDOW must be a valid window and defaults to the selected one."
   (= (window-pixel-width window)
      (window-pixel-width (frame-root-window window))))
 
-(defun window-body-size (&optional window horizontal)
+(defun window-body-size (&optional window horizontal pixelwise)
   "Return the height or width of WINDOW's text area.
 WINDOW must be a live window and defaults to the selected one.
 
 If HORIZONTAL is omitted or nil, return the height of the text
 area, like `window-body-height'.  Otherwise, return the width of
-the text area, like `window-body-width'."
+the text area, like `window-body-width'.  In either case, the
+optional argument PIXELWISE is passed to the functions."
   (if horizontal
-      (window-body-width window)
-    (window-body-height window)))
+      (window-body-width window pixelwise)
+    (window-body-height window pixelwise)))
 
 (defun window-current-scroll-bars (&optional window)
-  "Return the current scroll bar settings for WINDOW.
+  "Return the current scroll bar types for WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
 The return value is a cons cell (VERTICAL . HORIZONTAL) where
 VERTICAL specifies the current location of the vertical scroll
-bars (`left', `right', or nil), and HORIZONTAL specifies the
-current location of the horizontal scroll bars (`top', `bottom',
-or nil).
+bar (`left', `right' or nil), and HORIZONTAL specifies the
+current location of the horizontal scroll bar (`bottom' or nil).
 
 Unlike `window-scroll-bars', this function reports the scroll bar
 type actually used, once frame defaults and `scroll-bar-mode' are
 taken into account."
   (setq window (window-normalize-window window t))
-  (let ((vert (nth 2 (window-scroll-bars window)))
-       (hor nil))
-    (when (or (eq vert t) (eq hor t))
-      (let ((fcsb (frame-current-scroll-bars (window-frame window))))
-       (if (eq vert t)
-           (setq vert (car fcsb)))
-       (if (eq hor t)
-           (setq hor (cdr fcsb)))))
-    (cons vert hor)))
+  (let ((vertical (nth 2 (window-scroll-bars window)))
+       (horizontal (nth 5 (window-scroll-bars window)))
+       (inherited (frame-current-scroll-bars (window-frame window))))
+    (when (eq vertical t)
+      (setq vertical (car inherited)))
+    (when (eq horizontal t)
+      (setq horizontal (cdr inherited)))
+    (cons vertical (and horizontal 'bottom))))
 
 (defun walk-windows (fun &optional minibuf all-frames)
   "Cycle through all live windows, calling FUN for each one.
@@ -1818,10 +1911,9 @@ or bottom edge of WINDOW as reference position instead of
 top edge of WINDOW as reference position.
 
 Optional argument WRAP non-nil means to wrap DIRECTION around
-frame borders.  This means to return for a WINDOW a the top of
-the frame and DIRECTION `above' to return the minibuffer window
-if the frame has one, and a window at the bottom of the frame
-otherwise.
+frame borders.  This means to return for WINDOW at the top of the
+frame and DIRECTION `above' the minibuffer window if the frame
+has one, and a window at the bottom of the frame otherwise.
 
 Optional argument MINI nil means to return the minibuffer window
 if and only if it is currently active.  MINI non-nil means to
@@ -2209,7 +2301,7 @@ Optional argument HORIZONTAL non-nil means assign new total
 window widths from pixel widths."
   (setq frame (window-normalize-frame frame))
   (let* ((char-size (frame-char-size frame horizontal))
-        (root (frame-root-window))
+        (root (frame-root-window frame))
         (root-size (window-size root horizontal t))
         ;; We have to care about the minibuffer window only if it
         ;; appears together with the root window on this frame.
@@ -2926,6 +3018,28 @@ routines."
         pixel-delta
        (/ pixel-delta (frame-char-height frame)))))
 
+(defun window--sanitize-window-sizes (frame horizontal)
+  "Assert that all windows on FRAME are large enough.
+If necessary and possible, make sure that every window on frame
+FRAME has its minimum height.  Optional argument HORIZONTAL
+non-nil means to make sure that every window on frame FRAME has
+its minimum width.  The minimum height/width of a window is the
+respective value returned by `window-min-size' for that window.
+
+Return t if all windows were resized appropriately.  Return nil
+if at least one window could not be resized as requested, which
+may happen when the FRAME is not large enough to accommodate it."
+  (let ((value t))
+    (walk-window-tree
+     (lambda (window)
+       (let  ((delta (- (window-min-size window horizontal nil t)
+                       (window-size window horizontal t))))
+        (when (> delta 0)
+          (if (window-resizable-p window delta horizontal nil t)
+              (window-resize window delta horizontal nil t)
+            (setq value nil))))))
+    value))
+
 (defun adjust-window-trailing-edge (window delta &optional horizontal pixelwise)
   "Move WINDOW's bottom edge by DELTA lines.
 Optional argument HORIZONTAL non-nil means move WINDOW's right
@@ -4183,20 +4297,6 @@ showing BUFFER-OR-NAME."
        ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
        (unrecord-window-buffer window buffer)))))
 \f
-;;; Splitting windows.
-(defun window-split-min-size (&optional horizontal pixelwise)
-  "Return minimum height of any window when splitting windows.
-Optional argument HORIZONTAL non-nil means return minimum width."
-  (cond
-   (pixelwise
-    (if horizontal
-       (window-min-pixel-width)
-      (window-min-pixel-height)))
-   (horizontal
-    (max window-min-width window-safe-min-width))
-   (t
-    (max window-min-height window-safe-min-height))))
-
 (defun split-window (&optional window size side pixelwise)
   "Make a new window adjacent to WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
@@ -4260,6 +4360,9 @@ frame.  The selected window is not changed by this function."
         (pixel-size
          (when (numberp size)
            (window--size-to-pixel window size horizontal pixelwise t)))
+        (divider-width (if horizontal
+                           (frame-right-divider-width frame)
+                         (frame-bottom-divider-width frame)))
         atom-root)
     (window--check frame)
     (catch 'done
@@ -4281,12 +4384,7 @@ frame.  The selected window is not changed by this function."
        ;; side window, throw an error unless `window-combination-resize'
        ;; equals 'side.
        ((and (not (eq window-combination-resize 'side))
-            (or (window-parameter window 'window-side)
-                (and (window-child window)
-                     (or (window-parameter
-                          (window-child window) 'window-side)
-                         (window-parameter
-                          (window-last-child window) 'window-side)))))
+            (window--side-window-p window))
        (error "Cannot split side window or parent of side window"))
        ;; If `window-combination-resize' is 'side and window has a side
        ;; window sibling, bind `window-combination-limit' to t.
@@ -4361,19 +4459,14 @@ frame.  The selected window is not changed by this function."
          (cond
           (resize
            ;; SIZE unspecified, resizing.
-           (when (and (not (window-sizable-p
-                            parent (- new-pixel-size) horizontal nil t))
-                      ;; Try again with minimum split size.
-                      (setq new-pixel-size
-                            (max new-pixel-size
-                                 (window-split-min-size horizontal t)))
-                      (not (window-sizable-p
-                            parent (- new-pixel-size) horizontal nil t)))
-             (error "Window %s too small for splitting 1" parent)))
-          ((> (+ new-pixel-size (window-min-size window horizontal nil t))
+           (unless (window-sizable-p
+                    parent (- new-pixel-size divider-width) horizontal nil 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)
            ;; SIZE unspecified, no resizing.
-           (error "Window %s too small for splitting 2" window))))
+           (error "Window %s too small for splitting (2)" window))))
         ((and (>= pixel-size 0)
               (or (>= pixel-size old-pixel-size)
                   (< new-pixel-size
@@ -4381,19 +4474,19 @@ frame.  The selected window is not changed by this function."
          ;; SIZE specified as new size of old window.  If the new size
          ;; is larger than the old size or the size of the new window
          ;; would be less than the safe minimum, signal an error.
-         (error "Window %s too small for splitting 3" window))
+         (error "Window %s too small for splitting (3)" window))
         (resize
          ;; SIZE specified, resizing.
          (unless (window-sizable-p
-                  parent (- new-pixel-size) horizontal nil t)
+                  parent (- new-pixel-size divider-width) horizontal nil t)
            ;; If we cannot resize the parent give up.
-           (error "Window %s too small for splitting 4" parent)))
+           (error "Window %s too small for splitting (4)" parent)))
         ((or (< new-pixel-size
                 (window-safe-min-pixel-size window horizontal))
              (< (- old-pixel-size new-pixel-size)
                 (window-safe-min-pixel-size window horizontal)))
          ;; SIZE specification violates minimum size restrictions.
-         (error "Window %s too small for splitting 5" window)))
+         (error "Window %s too small for splitting (5)" window)))
 
        (window--resize-reset frame horizontal)
 
@@ -4464,6 +4557,9 @@ frame.  The selected window is not changed by this function."
              (set-window-parameter (window-parent new) 'window-atom t))
            (set-window-parameter new 'window-atom t)))
 
+         ;; Sanitize sizes.
+         (window--sanitize-window-sizes frame horizontal)
+
          (run-window-configuration-change-hook frame)
          (run-window-scroll-functions new)
          (window--check frame)
@@ -5035,7 +5131,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)
-                  (nth 3 scroll-bars)))
+                  (or (nth 3 scroll-bars) 0) (nth 5 scroll-bars)))
                (set-window-vscroll window (cdr (assq 'vscroll state)))
                ;; Adjust vertically.
                (if (memq window-size-fixed '(t height))
@@ -5703,7 +5799,7 @@ hold:
   wide as `split-width-threshold'.
 - When WINDOW is split evenly, the emanating windows are at least
   `window-min-width' or two (whichever is larger) columns wide."
-  (when (window-live-p window)
+  (when (and (window-live-p window) (not (window--side-window-p window)))
     (with-current-buffer (window-buffer window)
       (if horizontal
          ;; A window can be split horizontally when its width is not
@@ -5945,7 +6041,7 @@ live."
 ;; FIXME: By the way, there could be more levels of dedication:
 ;; - `barely' dedicated doesn't prevent reuse of the window, only records that
 ;;   the window hasn't been used for something else yet.
-;; - `softly' dedicated only allows reuse when asked explicitly.
+;; - `soft' (`softly') dedicated only allows reuse when asked explicitly.
 ;; - `strongly' never allows reuse.
 (defvar display-buffer-mark-dedicated nil
   "If non-nil, `display-buffer' marks the windows it creates as dedicated.
@@ -5959,6 +6055,8 @@ The actual non-nil value of this variable will be copied to the
           (const display-buffer-pop-up-window)
           (const display-buffer-same-window)
           (const display-buffer-pop-up-frame)
+          (const display-buffer-below-selected)
+          (const display-buffer-at-bottom)
           (const display-buffer-in-previous-window)
           (const display-buffer-use-some-window)
           (function :tag "Other function"))
@@ -6352,7 +6450,10 @@ again with `display-buffer-pop-up-window'."
 This either splits the selected window or reuses the window below
 the selected one."
   (let (window)
-    (or (and (not (frame-parameter nil 'unsplittable))
+    (or (and (setq window (window-in-direction 'below))
+            (eq buffer (window-buffer window))
+            (window--display-buffer buffer window 'reuse alist))
+       (and (not (frame-parameter nil 'unsplittable))
             (let ((split-height-threshold 0)
                   split-width-threshold)
               (setq window (window--try-to-split-window (selected-window) alist)))
@@ -6365,13 +6466,26 @@ the selected one."
 
 (defun display-buffer-at-bottom (buffer alist)
   "Try displaying BUFFER in a window at the bottom of the selected frame.
-This either splits the window at the bottom of the frame or the
-frame's root window, or reuses an existing window at the bottom
-of the selected frame."
-  (let (bottom-window window)
+This either reuses such a window provided it shows BUFFER
+already, splits a window at the bottom of the frame or the
+frame's root window, or reuses some window at the bottom of the
+selected frame."
+  (let (bottom-window bottom-window-shows-buffer window)
     (walk-window-tree
-     (lambda (window) (setq bottom-window window)) nil nil 'nomini)
-    (or (and (not (frame-parameter nil 'unsplittable))
+     (lambda (window)
+       (cond
+       ((window-in-direction 'below window))
+       ((and (not bottom-window-shows-buffer)
+             (eq buffer (window-buffer window)))
+        (setq bottom-window-shows-buffer t)
+        (setq bottom-window window))
+       ((not bottom-window)
+        (setq bottom-window window)))
+       nil nil 'nomini))
+    (or (and bottom-window-shows-buffer
+            (window--display-buffer
+             buffer bottom-window 'reuse alist display-buffer-mark-dedicated))
+     (and (not (frame-parameter nil 'unsplittable))
             (let (split-width-threshold)
               (setq window (window--try-to-split-window bottom-window alist)))
             (window--display-buffer
@@ -6476,7 +6590,7 @@ that frame."
       ;; resize it to its old height but don't signal an error.
       (when (and (listp quad)
                 (integerp (nth 3 quad))
-                (/= (nth 3 quad) (window-total-height window)))
+                (> (nth 3 quad) (window-total-height window)))
        (condition-case nil
            (window-resize window (- (nth 3 quad) (window-total-height window)))
          (error nil)))
@@ -6813,34 +6927,26 @@ can resize windows in both dimensions."
 ;; `fit-frame-to-buffer' eventually wants to know the real frame sizes
 ;; counting title bar and outer borders.
 (defcustom fit-frame-to-buffer nil
-  "Non-nil means `fit-frame-to-buffer' can fit a frame to its buffer.
+  "Non-nil means `fit-window-to-buffer' can fit a frame to its buffer.
 A frame is fit if and only if its root window is a live window
 and this option is non-nil.  If this is `horizontally', frames
 are resized horizontally only.  If this is `vertically', frames
 are resized vertically only.  Any other non-nil value means
-frames can be resized in both dimensions.  See also
-`fit-frame-to-buffer-margins' and `fit-frame-to-buffer-sizes'.
-
-If this is non-nil and a window is the only window of its frame,
-`fit-window-to-buffer' will invoke `fit-frame-to-buffer' to fit
-the frame to its buffer."
+frames can be resized in both dimensions."
   :type 'boolean
   :version "24.4"
   :group 'help)
 
 (defcustom fit-frame-to-buffer-margins '(nil nil nil nil)
   "Margins around frame for `fit-frame-to-buffer'.
-This list specifies the numbers of pixels to be left free on the
-left, above, the right, and below a frame that shall be fit to
-its buffer.  The value specified here can be overridden for a
-specific frame by that frame's `fit-frame-to-buffer-margins'
-parameter, if present.
-
-This variable controls how fitting a frame to the size of its
-buffer coordinates with the size of your display.  If you don't
-specify a value here, the size of the display's workarea is used.
-
-See also `fit-frame-to-buffer-sizes'."
+This specifies the numbers of pixels to be left free on the left,
+above, on the right, and below a frame fitted to its buffer.  Set
+this to avoid obscuring other desktop objects like the taskbar.
+The default is nil for each side, which means to not add margins.
+
+The value specified here can be overridden for a specific frame
+by that frame's `fit-frame-to-buffer-margins' parameter, if
+present.  See also `fit-frame-to-buffer-sizes'."
   :version "24.4"
   :type '(list
          (choice
@@ -6917,7 +7023,7 @@ See also `fit-frame-to-buffer-margins'."
             (<= left (- right margin)) (<= margin right))
     margin))
 
-(defun fit-frame-to-buffer (&optional frame max-height min-height max-width min-width)
+(defun fit-frame-to-buffer (&optional frame max-height min-height max-width min-width only)
   "Adjust size of FRAME to display the contents of its buffer exactly.
 FRAME can be any live frame and defaults to the selected one.
 Fit only if FRAME's root window is live.  MAX-HEIGHT, MIN-HEIGHT,
@@ -6925,9 +7031,12 @@ MAX-WIDTH and MIN-WIDTH specify bounds on the new total size of
 FRAME's root window.  MIN-HEIGHT and MIN-WIDTH default to the values of
 `window-min-height' and `window-min-width' respectively.
 
-The option `fit-frame-to-buffer' controls whether this function
-has any effect.  New position and size of FRAME are additionally
-determined by the options `fit-frame-to-buffer-sizes' and
+If the optional argument ONLY is `vertically', resize the frame
+vertically only.  If ONLY is `horizontally', resize the frame
+horizontally only.
+
+The new position and size of FRAME can be additionally determined
+by customizing the options `fit-frame-to-buffer-sizes' and
 `fit-frame-to-buffer-margins' or the corresponding parameters of
 FRAME."
   (interactive)
@@ -6936,13 +7045,7 @@ FRAME."
               (fboundp 'display-monitor-attributes-list))
     (user-error "Cannot resize frame in non-graphic Emacs"))
   (setq frame (window-normalize-frame frame))
-  (when (and (window-live-p (frame-root-window frame))
-            fit-frame-to-buffer
-            (or (not window-size-fixed)
-                (and (eq window-size-fixed 'height)
-                     (not (eq fit-frame-to-buffer 'vertically)))
-                (and (eq window-size-fixed 'width)
-                     (not (eq fit-frame-to-buffer 'horizontally)))))
+  (when (window-live-p (frame-root-window frame))
     (with-selected-window (frame-root-window frame)
       (let* ((window (frame-root-window frame))
             (char-width (frame-char-width))
@@ -7054,7 +7157,7 @@ FRAME."
                (- (* (nth 2 sizes) char-width) window-extra-width))
               ((numberp max-width)
                (- (* max-width char-width) window-extra-width))
-              (t display-height)))
+              (t display-width)))
             (min-width
              (cond
               ((numberp (nth 3 sizes))
@@ -7067,13 +7170,16 @@ FRAME."
             (value (window-text-pixel-size
                     nil t t workarea-width workarea-height t))
             (width (+ (car value) (window-right-divider-width)))
-            (height (+ (cdr value) (window-bottom-divider-width))))
+            (height
+             (+ (cdr value)
+                (window-bottom-divider-width)
+                (window-scroll-bar-height))))
        ;; Don't change height or width when the window's size is fixed
-       ;; in either direction.
+       ;; in either direction or ONLY forbids it.
        (cond
-        ((eq window-size-fixed 'width)
+        ((or (eq window-size-fixed 'width) (eq only 'vertically))
          (setq width nil))
-        ((eq window-size-fixed 'height)
+        ((or (eq window-size-fixed 'height) (eq only 'horizontally))
          (setq height nil)))
        ;; Fit width to constraints.
        (when width
@@ -7141,27 +7247,27 @@ FRAME."
 WINDOW must be a live window and defaults to the selected one.
 
 If WINDOW is part of a vertical combination, adjust WINDOW's
-height.  The new height is calculated from the number of lines of
+height.  The new height is calculated from the actual height of
 the accessible portion of its buffer.  The optional argument
 MAX-HEIGHT specifies a maximum height and defaults to the height
 of WINDOW's frame.  The optional argument MIN-HEIGHT specifies a
 minimum height and defaults to `window-min-height'.  Both
-MAX-HEIGHT and MIN-HEIGHT are specified in lines and include the
-mode line and header line, if any.
+MAX-HEIGHT and MIN-HEIGHT are specified in lines and include mode
+and header line and a bottom divider, if any.
 
 If WINDOW is part of a horizontal combination and the value of
 the option `fit-window-to-buffer-horizontally' is non-nil, adjust
-WINDOW's height.  The new width of WINDOW is calculated from the
+WINDOW's width.  The new width of WINDOW is calculated from the
 maximum length of its buffer's lines that follow the current
 start position of WINDOW.  The optional argument MAX-WIDTH
 specifies a maximum width and defaults to the width of WINDOW's
 frame.  The optional argument MIN-WIDTH specifies a minimum width
 and defaults to `window-min-width'.  Both MAX-WIDTH and MIN-WIDTH
-are specified in columns and include fringes, margins and
-scrollbars, if any.
+are specified in columns and include fringes, margins, a
+scrollbar and a vertical divider, if any.
 
 Fit pixelwise if the option `window-resize-pixelwise' is non-nil.
-If WINDOW is its frame's root window, then if the option
+If WINDOW is its frame's root window and the option
 `fit-frame-to-buffer' is non-nil, call `fit-frame-to-buffer' to
 adjust the frame's size.
 
@@ -7177,7 +7283,9 @@ accessible position."
        ;; Fit WINDOW's frame to buffer.
        (fit-frame-to-buffer
         (window-frame window)
-        max-height min-height max-width min-width))
+        max-height min-height max-width min-width
+        (and (memq fit-frame-to-buffer '(vertically horizontally))
+             fit-frame-to-buffer)))
     (with-selected-window window
       (let* ((pixelwise window-resize-pixelwise)
             (char-height (frame-char-height))
@@ -7224,6 +7332,7 @@ accessible position."
          ;; height.  Its width remains fixed.
          (setq height (+ (cdr (window-text-pixel-size
                                nil nil t nil (frame-pixel-height) t))
+                         (window-scroll-bar-height window)
                          (window-bottom-divider-width)))
          ;; Round height.
          (unless pixelwise
@@ -7238,7 +7347,7 @@ accessible position."
         ((and fit-window-to-buffer-horizontally
               (not (window-size-fixed-p window t))
               (window-combined-p nil t))
-         (let* ((total-width (window-size window nil pixelwise))
+         (let* ((total-width (window-size window t pixelwise))
                 (min-width
                  ;; Sanitize MIN-WIDTH.
                  (if (numberp min-width)
@@ -7265,10 +7374,10 @@ accessible position."
                             max-width))
                    (+ total-width (window-max-delta
                                    nil t nil nil nil nil pixelwise))))
-                ;; When fitting vertically, assume that WINDOW's start
-                ;; position remains unaltered.  WINDOW can't get wider
-                ;; than its frame's pixel width, its height remains
-                ;; unaltered.
+                ;; When fitting horizontally, assume that WINDOW's
+                ;; start position remains unaltered.  WINDOW can't get
+                ;; wider than its frame's pixel width, its height
+                ;; remains unaltered.
                 (width (+ (car (window-text-pixel-size
                                 nil (window-start) (point-max)
                                 (frame-pixel-width)
@@ -7277,7 +7386,7 @@ accessible position."
                                 ;; overshoots when the first line below
                                 ;; the bottom is wider than the window.
                                 (* body-height
-                                   (if pixelwise char-height 1))))
+                                   (if pixelwise 1 char-height))))
                           (window-right-divider-width))))
            (unless pixelwise
              (setq width (/ (+ width char-width -1) char-width)))