compare symbol names with `equal'
[bpt/emacs.git] / lisp / window.el
index d35d898..28dd6a8 100644 (file)
@@ -1,8 +1,9 @@
 ;;; window.el --- GNU Emacs window commands aside from those written in C
 
-;; Copyright (C) 1985, 1989, 1992-1994, 2000-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1989, 1992-1994, 2000-2014 Free Software
+;; Foundation, Inc.
 
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: internal
 ;; Package: emacs
 
@@ -141,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
@@ -171,16 +172,35 @@ 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)
+       (setq ,value (progn ,@body))
+       (with-current-buffer ,buffer
+        (setq ,window (temp-buffer-window-show ,buffer ,action)))
+
+       (if (functionp ,quit-function)
+          (funcall ,quit-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"))
@@ -319,10 +339,11 @@ 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.
-A value less than `window-safe-min-height' is ignored.  The value
-of this variable is honored when windows are resized or split.
+  "The minimum total height, in lines, of any window.
+The value has to accommodate one text line, a mode and header
+line, 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.
 
 Applications should never rebind this variable.  To resize a
 window to a height less than the one specified here, an
@@ -349,11 +370,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
@@ -807,13 +828,13 @@ SIDE.  Return the new window, nil if its creation window failed."
     (delete-window window)))
 
 (defun display-buffer-in-side-window (buffer alist)
-  "Display BUFFER in a window on side SIDE of the selected frame.
+  "Display BUFFER in a side window of the selected frame.
 ALIST is an association list of symbols and values.  The
-following symbols can be used:
+following special symbols can be used in ALIST.
 
-`side' denotes the side of the existing window where the new
-  window shall be located.  Valid values are `bottom', `right',
-  `top' and `left'.  The default is `bottom'.
+`side' denotes the side of the frame where the new window shall
+  be located.  Valid values are `bottom', `right', `top' and
+  `left'.  The default is `bottom'.
 
 `slot' if non-nil, specifies the window slot where to display
   BUFFER.  A value of zero or nil means use the middle slot on
@@ -1011,19 +1032,101 @@ FRAME defaults to the selected frame."
   (window--side-check frame)
   (window--atom-check frame))
 
+;; Dumping frame/window contents.
+(defun window--dump-window (&optional window erase)
+  "Dump WINDOW to buffer *window-frame-dump*.
+WINDOW must be a valid window and defaults to the selected one.
+Optional argument ERASE non-nil means erase *window-frame-dump*
+before writing to it."
+  (setq window (window-normalize-window window))
+  (with-current-buffer (get-buffer-create "*window-frame-dump*")
+    (when erase (erase-buffer))
+    (insert
+     (format "%s   parent: %s\n" window (window-parent window))
+     (format "pixel left: %s   top: %s   size: %s x %s   new: %s\n"
+            (window-pixel-left window) (window-pixel-top window)
+            (window-size window t t) (window-size window nil t)
+            (window-new-pixel window))
+     (format "char left: %s   top: %s   size: %s x %s   new: %s\n"
+            (window-left-column window) (window-top-line window)
+            (window-total-size window t) (window-total-size window)
+            (window-new-total window))
+     (format "normal: %s x %s   new: %s\n"
+            (window-normal-size window t) (window-normal-size window)
+            (window-new-normal window)))
+    (when (window-live-p window)
+      (let ((fringes (window-fringes window))
+           (margins (window-margins window)))
+       (insert
+        (format "body pixel: %s x %s   char: %s x %s\n"
+                (window-body-width window t) (window-body-height window t)
+                (window-body-width window) (window-body-height window))
+        (format "width left fringe: %s  left margin: %s  right margin: %s\n"
+                (car fringes) (or (car margins) 0) (or (cdr margins) 0))
+        (format "width right fringe: %s  scroll-bar: %s  divider: %s\n"
+                (cadr fringes)
+                (window-scroll-bar-width window)
+                (window-right-divider-width window))
+        (format "height header-line: %s  mode-line: %s  divider: %s\n"
+                (window-header-line-height window)
+                (window-mode-line-height window)
+                (window-bottom-divider-width window)))))
+    (insert "\n")))
+
+(defun window--dump-frame (&optional window-or-frame)
+  "Dump WINDOW-OR-FRAME to buffer *window-frame-dump*.
+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."
+  (let* ((window
+         (cond
+          ((or (not window-or-frame)
+               (frame-live-p window-or-frame))
+           (frame-root-window window-or-frame))
+          ((or (window-live-p window-or-frame)
+               (window-child window-or-frame))
+           window-or-frame)
+          (t
+           (frame-root-window))))
+        (frame (window-frame window)))
+    (with-current-buffer (get-buffer-create "*window-frame-dump*")
+      (erase-buffer)
+      (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-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)
+              (frame-text-cols frame) (frame-text-lines frame))
+       (format "tool: %s  scroll: %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-fringe-width frame)
+              (frame-border-width frame)
+              (frame-right-divider-width frame)
+              (frame-bottom-divider-width frame)))
+      (walk-window-tree 'window--dump-window frame t t))))
+
 ;;; Window sizes.
-(defun window-total-size (&optional window horizontal)
+(defun window-total-size (&optional window horizontal round)
   "Return the total height or width of WINDOW.
 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'."
+the total width, in columns, like `window-total-width'.
+
+Optional argument ROUND is handled as for `window-total-height'
+and `window-total-width'."
   (if horizontal
-      (window-total-width window)
-    (window-total-height window)))
+      (window-total-width window round)
+    (window-total-height window round)))
 
-(defun window-size (&optional window horizontal pixelwise)
+(defun window-size (&optional window horizontal pixelwise round)
   "Return the height or width of WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 
@@ -1032,14 +1135,18 @@ WINDOW, in lines, like `window-total-height'.  Otherwise return
 the total width, in columns, like `window-total-width'.
 
 Optional argument PIXELWISE means return the pixel size of WINDOW
-like `window-pixel-height' and `window-pixel-width'."
+like `window-pixel-height' and `window-pixel-width'.
+
+Optional argument ROUND is ignored if PIXELWISE is non-nil and
+handled as for `window-total-height' and `window-total-width'
+otherwise."
   (if horizontal
       (if pixelwise
          (window-pixel-width window)
-       (window-total-width window))
+       (window-total-width window round))
     (if pixelwise
        (window-pixel-height window)
-      (window-total-height window))))
+      (window-total-height window round))))
 
 (defvar window-size-fixed nil
   "Non-nil in a buffer means windows displaying the buffer are fixed-size.
@@ -1132,55 +1239,46 @@ of WINDOW."
          ;; windows such that the new (or resized) windows can get a
          ;; size less than the user-specified `window-min-height' and
          ;; `window-min-width'.
-         (let ((frame (window-frame window))
-               (fringes (window-fringes window))
-               (scroll-bars (window-scroll-bars window)))
+         (let* ((char-size (frame-char-size window t))
+                (fringes (window-fringes window))
+                (pixel-width
+                 (+ (window-safe-min-size window t t)
+                    (car fringes) (cadr fringes)
+                    (window-scroll-bar-width window)
+                    (window-right-divider-width window))))
            (if pixelwise
                (max
-                (+ (window-safe-min-size window t t)
-                   (car fringes) (cadr fringes)
-                   (cond
-                    ((memq (nth 2 scroll-bars) '(left right))
-                     (nth 1 scroll-bars))
-                    ((memq (frame-parameter frame 'vertical-scroll-bars)
-                           '(left right))
-                     (frame-parameter frame 'scroll-bar-width))
-                    (t 0)))
+                (if window-resize-pixelwise
+                    pixel-width
+                  ;; Round up to next integral of columns.
+                  (* (ceiling pixel-width char-size) char-size))
                 (if (window--size-ignore-p window ignore)
                     0
                   (window-min-pixel-width)))
              (max
-              (+ window-safe-min-width
-                 (ceiling (car fringes) (frame-char-width frame))
-                 (ceiling (cadr fringes) (frame-char-width frame))
-                 (cond
-                  ((memq (nth 2 scroll-bars) '(left right))
-                   (nth 1 scroll-bars))
-                ((memq (frame-parameter frame 'vertical-scroll-bars)
-                       '(left right))
-                 (ceiling (or (frame-parameter frame 'scroll-bar-width) 14)
-                          (frame-char-width)))
-                (t 0)))
+              (ceiling pixel-width char-size)
               (if (window--size-ignore-p window ignore)
                   0
                 window-min-width)))))
-        (pixelwise
-         (max 
-          (+ (window-safe-min-size window nil t)
-             (window-header-line-height window)
-             (window-mode-line-height window))
-          (if (window--size-ignore-p window ignore)
-              0
-            (window-min-pixel-height))))
-        (t
-         ;; For the minimum height of a window take any mode- or
-         ;; header-line into account.
-         (max (+ window-safe-min-height
-                 (if header-line-format 1 0)
-                 (if mode-line-format 1 0))
-              (if (window--size-ignore-p window ignore)
-                  0
-                window-min-height))))))))
+        ((let ((char-size (frame-char-size window))
+               (pixel-height
+                (+ (window-safe-min-size window nil t)
+                   (window-header-line-height window)
+                   (window-mode-line-height window)
+                   (window-bottom-divider-width window))))
+           (if pixelwise
+               (max
+                (if window-resize-pixelwise
+                    pixel-height
+                  ;; Round up to next integral of lines.
+                  (* (ceiling pixel-height char-size) char-size))
+                (if (window--size-ignore-p window ignore)
+                    0
+                  (window-min-pixel-height)))
+             (max (ceiling pixel-height char-size)
+                  (if (window--size-ignore-p window ignore)
+                      0
+                    window-min-height))))))))))
 
 (defun window-sizable (window delta &optional horizontal ignore pixelwise)
   "Return DELTA if DELTA lines can be added to WINDOW.
@@ -1315,9 +1413,10 @@ WINDOW can be resized in the desired direction.  The function
            (unless (eq sub window)
              (setq delta
                    (min delta
-                        (- (window-size sub horizontal pixelwise)
-                           (window-min-size
-                            sub horizontal ignore pixelwise)))))
+                        (max (- (window-size sub horizontal pixelwise 'ceiling)
+                                (window-min-size
+                                 sub horizontal ignore pixelwise))
+                             0))))
            (setq sub (window-right sub))))
        (if noup
            delta
@@ -1355,7 +1454,7 @@ 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."
   (setq window (window-normalize-window window))
-  (let ((size (window-size window horizontal pixelwise))
+  (let ((size (window-size window horizontal pixelwise 'floor))
        (minimum (window-min-size window horizontal ignore pixelwise)))
     (cond
      (nodown
@@ -1392,9 +1491,11 @@ by which WINDOW can be shrunk."
                 (t
                  (setq delta
                        (+ delta
-                          (- (window-size sub horizontal pixelwise)
-                             (window-min-size
-                              sub horizontal ignore pixelwise))))))
+                          (max
+                           (- (window-size sub horizontal pixelwise 'floor)
+                              (window-min-size
+                               sub horizontal ignore pixelwise))
+                           0)))))
                (setq sub (window-right sub))))
          ;; For an ortho-combination throw DELTA when at least one
          ;; child window is fixed-size.
@@ -1592,16 +1693,17 @@ 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.
@@ -1719,7 +1821,7 @@ SIDE can be any of the symbols `left', `top', `right' or
 ;; Neither of these allow to selectively ignore specific windows
 ;; (windows whose `no-other-window' parameter is non-nil) as targets of
 ;; the movement.
-(defun window-in-direction (direction &optional window ignore)
+(defun window-in-direction (direction &optional window ignore sign wrap mini)
   "Return window in DIRECTION as seen from WINDOW.
 More precisely, return the nearest window in direction DIRECTION
 as seen from the position of `window-point' in window WINDOW.
@@ -1732,6 +1834,21 @@ non-nil, try to find another window in the indicated direction.
 If, however, the optional argument IGNORE is non-nil, return that
 window even if its `no-other-window' parameter is non-nil.
 
+Optional argument SIGN a negative number means to use the right
+or bottom edge of WINDOW as reference position instead of
+`window-point'.  SIGN a positive number means to use the left or
+top edge of WINDOW as reference position.
+
+Optional argument WRAP non-nil means to wrap DIRECTION around
+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
+return the minibuffer window even when it's not active.  However,
+if WRAP non-nil, always act as if MINI were nil.
+
 Return nil if no suitable window can be found."
   (setq window (window-normalize-window window t))
   (unless (memq direction '(above below left right))
@@ -1742,12 +1859,22 @@ Return nil if no suitable window can be found."
                    (window-pixel-left window)
                  (window-pixel-top window)))
         (last (+ first (window-size window hor t)))
-        (posn-cons (nth 2 (posn-at-point (window-point window) window)))
         ;; The column / row value of `posn-at-point' can be nil for the
         ;; mini-window, guard against that.
-        (posn (if hor
-                  (+ (or (cdr posn-cons) 1) (window-pixel-top window))
-                (+ (or (car posn-cons) 1) (window-pixel-left window))))
+        (posn
+         (cond
+          ((and (numberp sign) (< sign 0))
+           (if hor
+               (1- (+ (window-pixel-top window) (window-pixel-height window)))
+             (1- (+ (window-pixel-left window) (window-pixel-width window)))))
+          ((and (numberp sign) (> sign 0))
+           (if hor
+               (window-pixel-top window)
+             (window-pixel-left window)))
+          ((let ((posn-cons (nth 2 (posn-at-point (window-point window) window))))
+             (if hor
+                 (+ (or (cdr posn-cons) 1) (window-pixel-top window))
+               (+ (or (car posn-cons) 1) (window-pixel-left window)))))))
         (best-edge
          (cond
           ((eq direction 'below) (frame-pixel-height frame))
@@ -1772,9 +1899,15 @@ Return nil if no suitable window can be found."
                  (< posn (+ w-top (window-pixel-height w))))
             ;; W is to the left or right of WINDOW and covers POSN.
             (when (or (and (eq direction 'left)
-                           (<= w-left first) (> w-left best-edge))
+                           (or (and (<= w-left first) (> w-left best-edge))
+                               (and wrap
+                                    (window-at-side-p window 'left)
+                                    (window-at-side-p w 'right))))
                       (and (eq direction 'right)
-                           (>= w-left last) (< w-left best-edge)))
+                           (or (and (>= w-left last) (< w-left best-edge))
+                               (and wrap
+                                    (window-at-side-p window 'right)
+                                    (window-at-side-p w 'left)))))
               (setq best-edge w-left)
               (setq best w)))
            ((and (or (and (eq direction 'left)
@@ -1792,32 +1925,40 @@ Return nil if no suitable window can be found."
             (setq best-edge-2 w-left)
             (setq best-diff-2 best-diff-2-new)
             (setq best-2 w))))
-         (t
-          (cond
-           ((and (<= w-left posn)
-                 (< posn (+ w-left (window-pixel-width w))))
-            ;; W is above or below WINDOW and covers POSN.
-            (when (or (and (eq direction 'above)
-                           (<= w-top first) (> w-top best-edge))
-                      (and (eq direction 'below)
-                           (>= w-top first) (< w-top best-edge)))
-              (setq best-edge w-top)
-              (setq best w)))
-           ((and (or (and (eq direction 'above)
-                          (<= (+ w-top (window-pixel-height w)) first))
-                     (and (eq direction 'below) (<= last w-top)))
-                 ;; W is above or below WINDOW but does not cover POSN.
-                 (setq best-diff-2-new
-                       (window--in-direction-2 w posn hor))
-                 (or (< best-diff-2-new best-diff-2)
-                     (and (= best-diff-2-new best-diff-2)
-                          (if (eq direction 'above)
-                              (> w-top best-edge-2)
-                            (< w-top best-edge-2)))))
-            (setq best-edge-2 w-top)
-            (setq best-diff-2 best-diff-2-new)
-            (setq best-2 w)))))))
-     frame)
+         ((and (<= w-left posn)
+               (< posn (+ w-left (window-pixel-width w))))
+          ;; W is above or below WINDOW and covers POSN.
+          (when (or (and (eq direction 'above)
+                         (or (and (<= w-top first) (> w-top best-edge))
+                             (and wrap
+                                  (window-at-side-p window 'top)
+                                  (if (active-minibuffer-window)
+                                      (minibuffer-window-active-p w)
+                                    (window-at-side-p w 'bottom)))))
+                    (and (eq direction 'below)
+                         (or (and (>= w-top first) (< w-top best-edge))
+                             (and wrap
+                                  (if (active-minibuffer-window)
+                                      (minibuffer-window-active-p window)
+                                    (window-at-side-p window 'bottom))
+                                  (window-at-side-p w 'top)))))
+            (setq best-edge w-top)
+            (setq best w)))
+         ((and (or (and (eq direction 'above)
+                        (<= (+ w-top (window-pixel-height w)) first))
+                   (and (eq direction 'below) (<= last w-top)))
+               ;; W is above or below WINDOW but does not cover POSN.
+               (setq best-diff-2-new
+                     (window--in-direction-2 w posn hor))
+               (or (< best-diff-2-new best-diff-2)
+                   (and (= best-diff-2-new best-diff-2)
+                        (if (eq direction 'above)
+                            (> w-top best-edge-2)
+                          (< w-top best-edge-2)))))
+          (setq best-edge-2 w-top)
+          (setq best-diff-2 best-diff-2-new)
+          (setq best-2 w)))))
+     frame nil (and mini t))
     (or best best-2)))
 
 (defun get-window-with-predicate (predicate &optional minibuf all-frames default)
@@ -2039,30 +2180,16 @@ WINDOW's frame if the option `window-resize-pixelwise' is nil."
          size)
       (* size char-size))))
 
-(defun window--pixel-to-size (window size &optional horizontal round-up)
-  "For WINDOW convert SIZE pixels to lines.
-WINDOW must be a valid window and defaults to the selected one.
-Optional argument HORIZONTAL non-nil means convert SIZE pixels to
-columns.  Optional argument ROUND-UP means to round up the return
-value."
-  (let ((char-size (frame-char-size
-                   (window-normalize-window window) horizontal)))
-    (if round-up
-       (/ (+ size char-size -1) char-size)
-      (/ size char-size))))
-
 (defun window--pixel-to-total-1 (window horizontal char-size)
   "Subroutine of `window--pixel-to-total'."
   (let ((child (window-child window)))
     (if (window-combination-p window horizontal)
        ;; In an iso-combination distribute sizes proportionally.
        (let ((remainder (window-new-total window))
-             size best-child best-size)
+             size best-child rem best-rem)
          ;; Initialize total sizes to each child's floor.
          (while child
-           (setq size (window--pixel-to-size
-                       child (window-size child horizontal t)
-                       horizontal))
+           (setq size (max (/ (window-size child horizontal t) char-size) 1))
            (set-window-new-total child size)
            (setq remainder (- remainder size))
            (setq child (window-next-sibling child)))
@@ -2070,15 +2197,15 @@ value."
          (while (> remainder 0)
            (setq child (window-last-child window))
            (setq best-child nil)
-           (setq best-size 0)
-           ;; We want those auxiliary fields in the window structure to
-           ;; avoid this.
+           (setq best-rem 0)
            (while child
-             (setq size (- (/ (window-size child horizontal t) char-size)
-                           (window-new-total child)))
-             (when (> size best-size)
-               (setq best-child child)
-               (setq best-size size))
+             (when (and (<= (window-new-total child)
+                            (/ (window-size child horizontal t) char-size))
+                        (> (setq rem (% (window-size child horizontal t)
+                                        char-size))
+                           best-rem))
+                  (setq best-child child)
+                  (setq best-rem rem))
              (setq child (window-prev-sibling child)))
            ;; We MUST have a best-child here.
            (set-window-new-total best-child 1 t)
@@ -2102,15 +2229,39 @@ FRAME must be a live frame and defaults to the selected frame.
 Optional argument HORIZONTAL non-nil means assign new total
 window widths from pixel widths."
   (setq frame (window-normalize-frame frame))
-  (let ((root (frame-root-window))
-       (char-size (frame-char-size frame horizontal))
-       (mini (minibuffer-window frame)))
-    (set-window-new-total
-     root (window--pixel-to-size
-          root (window-size root horizontal t) horizontal))
+  (let* ((char-size (frame-char-size frame horizontal))
+        (root (frame-root-window))
+        (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.
+        (mini (let ((mini (minibuffer-window frame)))
+                (and (eq (window-frame mini) frame)
+                     (not (eq mini root)) mini)))
+        (mini-size (and mini (window-size mini horizontal t))))
+    ;; We round the line/column sizes of windows here to the nearest
+    ;; integer.  In some cases this can make windows appear _larger_
+    ;; than the containing frame (line/column-wise) because the latter's
+    ;; sizes are not (yet) rounded.  We might eventually fix that.
+    (if (and mini (not horizontal))
+       (let (lines)
+         (set-window-new-total root (max (/ root-size char-size) 1))
+         (set-window-new-total mini (max (/ mini-size char-size) 1))
+         (setq lines (- (round (+ root-size mini-size) char-size)
+                        (+ (window-new-total root) (window-new-total mini))))
+         (while (> lines 0)
+           (if (>= (% root-size (window-new-total root))
+                   (% mini-size (window-new-total mini)))
+               (set-window-new-total root 1 t)
+             (set-window-new-total mini 1 t))
+           (setq lines (1- lines))))
+      (set-window-new-total root (round root-size char-size))
+      (when mini
+       ;; This is taken in the horizontal case only.
+       (set-window-new-total mini (round mini-size char-size))))
     (unless (window-buffer root)
-      (window--pixel-to-total-1 root horizontal char-size)))
-  (window-resize-apply-total frame horizontal))
+      (window--pixel-to-total-1 root horizontal char-size))
+    ;; Apply the new sizes.
+    (window-resize-apply-total frame horizontal)))
 
 (defun window--resize-reset (&optional frame horizontal)
   "Reset resize values for all windows on FRAME.
@@ -2259,9 +2410,11 @@ instead."
        ;; Otherwise, resize all other windows in the same combination.
        (window--resize-siblings window delta horizontal ignore))
       (when (window--resize-apply-p frame horizontal)
-       (window-resize-apply frame horizontal)
-       (window--pixel-to-total frame horizontal)
-       (run-window-configuration-change-hook frame)))
+       (if (window-resize-apply frame horizontal)
+           (progn
+             (window--pixel-to-total frame horizontal)
+             (run-window-configuration-change-hook frame))
+         (error "Failed to apply resizing %s" window))))
      (t
       (error "Cannot resize window %s" window)))))
 
@@ -2502,7 +2655,7 @@ already set by this routine."
          (setq best-value most-negative-fixnum)
          (while sub
            (when (and (consp (window-new-normal sub))
-                      (not (zerop (car (window-new-normal sub))))
+                      (not (<= (car (window-new-normal sub)) 0))
                       (> (cdr (window-new-normal sub)) best-value))
              (setq best-window sub)
              (setq best-value (cdr (window-new-normal sub))))
@@ -2518,7 +2671,7 @@ already set by this routine."
             best-window
             (if (= (car (window-new-normal best-window)) best-delta)
                 'skip      ; We can't shrink best-window any further.
-              (cons (1- (car (window-new-normal best-window)))
+              (cons (- (car (window-new-normal best-window)) best-delta)
                     (- (/ (float (window-new-pixel best-window))
                           parent-total)
                        (window-normal-size best-window horizontal))))))))
@@ -2753,7 +2906,7 @@ zero, this function can resize fixed-size windows in order to
 recover the necessary lines.  Return the number of lines that
 were recovered.
 
-Third argument PIXELWISE non-nil means to intepret DELTA as
+Third argument PIXELWISE non-nil means to interpret DELTA as
 pixels and return the number of pixels that were recovered.
 
 This function is called by the minibuffer window resizing
@@ -2883,7 +3036,7 @@ 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 nil nil nil pixelwise))
+                           left delta horizontal nil 'after nil nil pixelwise))
          (unless (zerop this-delta)
            (window--resize-this-window
             left this-delta horizontal nil t 'before
@@ -2912,7 +3065,7 @@ move it as far as possible in the desired direction."
          ;; Try to enlarge RIGHT.
          (setq this-delta
                (window--resizable
-                right (- delta) horizontal nil nil nil nil pixelwise))
+                right (- delta) horizontal nil 'before nil nil pixelwise))
          (unless (zerop this-delta)
            (window--resize-this-window
             right this-delta horizontal nil t 'after
@@ -3000,7 +3153,7 @@ Also see the `window-min-height' variable."
             (window-max-delta nil horizontal))
        horizontal)))))
 
-(defun maximize-window (&optional window pixelwise)
+(defun maximize-window (&optional window)
   "Maximize WINDOW.
 Make WINDOW as large as possible without deleting any windows.
 WINDOW must be a valid window and defaults to the selected one.
@@ -3016,7 +3169,7 @@ WINDOW pixelwise."
    window (window-max-delta window t nil nil nil nil window-resize-pixelwise)
    t nil window-resize-pixelwise))
 
-(defun minimize-window (&optional window pixelwise)
+(defun minimize-window (&optional window)
   "Minimize WINDOW.
 Make WINDOW as small as possible without deleting any windows.
 WINDOW must be a valid window and defaults to the selected one.
@@ -3189,7 +3342,7 @@ Return 'frame if deleting WINDOW should also delete its frame."
   (setq window (window-normalize-window window))
 
   (unless (or ignore-window-parameters
-             (eq (window-parameter window 'delete-window) t)) 
+             (eq (window-parameter window 'delete-window) t))
     ;; Handle atomicity.
     (when (window-parameter window 'window-atom)
       (setq window (window-atom-root window))))
@@ -4093,7 +4246,7 @@ window provided SIZE is negative) including space reserved for
 fringes and the scrollbar or a divider column.  Any other non-nil
 value for SIDE is currently handled like t (or `right').
 
-PIXELWISE, if non-nil, means to intepret SIZE pixelwise.
+PIXELWISE, if non-nil, means to interpret SIZE pixelwise.
 
 If the variable `ignore-window-parameters' is non-nil or the
 `split-window' parameter of WINDOW equals t, do not process any
@@ -4190,7 +4343,7 @@ frame.  The selected window is not changed by this function."
             (old-pixel-size (window-size window horizontal t))
             ;; `new-size' is the specified or calculated size of the
             ;; new window.
-            new-pixel-size new new-parent new-normal)
+            new-pixel-size new-parent new-normal)
        (cond
         ((not pixel-size)
          (setq new-pixel-size
@@ -4490,7 +4643,7 @@ is non-nil)."
     (setq sub first)
     (while (and sub (> rest 0))
       (unless (window--resize-child-windows-skip-p window)
-       (set-window-new-pixel sub char-size t)
+       (set-window-new-pixel sub (min rest char-size) t)
        (setq rest (- rest char-size)))
       (setq sub (window-right sub)))
 
@@ -4499,7 +4652,7 @@ is non-nil)."
     (setq sub first)
     (while (and sub (> rest 0))
       (unless (eq (window-new-normal sub) 'ignore)
-       (set-window-new-pixel sub char-size t)
+       (set-window-new-pixel sub (min rest char-size) t)
        (setq rest (- rest char-size)))
       (setq sub (window-right sub)))
 
@@ -4557,7 +4710,7 @@ window."
     (window--resize-reset (window-frame window) t)
     (balance-windows-1 window t)
     (when (window--resize-apply-p frame t)
-      (window-resize-apply frame)
+      (window-resize-apply frame t)
       (window--pixel-to-total frame t)
       (run-window-configuration-change-hook frame))))
 
@@ -4631,12 +4784,12 @@ specific buffers."
         ;; (assert (eq next (or (cadr (member win wins)) (car wins))))
         (let* ((horiz
                 (< (car (window-pixel-edges win)) (car (window-pixel-edges next))))
-               (areadiff (/ (- (* (window-height next pixelwise)
-                                 (window-width next pixelwise)
+               (areadiff (/ (- (* (window-size next nil pixelwise)
+                                 (window-size next t pixelwise)
                                   (buffer-local-value 'window-area-factor
                                                       (window-buffer next)))
-                               (* (window-height win pixelwise)
-                                 (window-width win pixelwise)
+                               (* (window-size win nil pixelwise)
+                                 (window-size win t pixelwise)
                                   (buffer-local-value 'window-area-factor
                                                       (window-buffer win))))
                             (max (buffer-local-value 'window-area-factor
@@ -4644,10 +4797,10 @@ specific buffers."
                                  (buffer-local-value 'window-area-factor
                                                      (window-buffer next)))))
                (edgesize (if horiz
-                             (+ (window-height win pixelwise)
-                               (window-height next pixelwise))
-                           (+ (window-width win pixelwise)
-                             (window-width next pixelwise))))
+                             (+ (window-size win nil pixelwise)
+                               (window-size next nil pixelwise))
+                           (+ (window-size win t pixelwise)
+                             (window-size next t pixelwise))))
                (diff (/ areadiff edgesize)))
           (when (zerop diff)
             ;; Maybe diff is actually closer to 1 than to 0.
@@ -4968,14 +5121,32 @@ value can be also stored on disk and read back in a new session."
   "Put window state STATE into WINDOW.
 STATE should be the state of a window returned by an earlier
 invocation of `window-state-get'.  Optional argument WINDOW must
-specify a live window and defaults to the selected one.
+specify a valid window and defaults to the selected one.  If
+WINDOW is not live, replace WINDOW by a live one before putting
+STATE into it.
 
 Optional argument IGNORE non-nil means ignore minimum window
 sizes and fixed size restrictions.  IGNORE equal `safe' means
 windows can get as small as `window-safe-min-height' and
 `window-safe-min-width'."
   (setq window-state-put-stale-windows nil)
-  (setq window (window-normalize-window window t))
+  (setq window (window-normalize-window window))
+
+  ;; When WINDOW is internal, reduce it to a live one to put STATE into,
+  ;; see Bug#16793.
+  (unless (window-live-p window)
+    (let ((root (frame-root-window window)))
+      (if (eq window root)
+         (setq window (frame-first-window root))
+       (setq root window)
+       (setq window (catch 'live
+                      (walk-window-subtree
+                       (lambda (window)
+                         (when (window-live-p window)
+                           (throw 'live window)))
+                       root))))
+      (delete-other-windows-internal window root)))
+
   (let* ((frame (window-frame window))
         (head (car state))
         ;; We check here (1) whether the total sizes of root window of
@@ -5718,8 +5889,7 @@ live."
        (set-window-dedicated-p window dedicated))
       (when (memq type '(window frame))
        (set-window-prev-buffers window nil)))
-    (let ((frame (window-frame window))
-         (parameter (window-parameter window 'quit-restore))
+    (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))))
@@ -5733,8 +5903,7 @@ live."
         ((consp size)
          (let ((width (car size))
                (height (cdr size))
-               (frame (window-frame window))
-               delta)
+               (frame (window-frame window)))
            (when (and (numberp width) (numberp height))
              (set-frame-height
               frame (+ (frame-height frame)
@@ -5797,7 +5966,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.
@@ -5851,13 +6020,8 @@ This is a list of elements (CONDITION . ACTION), where:
 
 `display-buffer' scans this alist until it either finds a
 matching regular expression or the function specified by a
-condition returns non-nil.  It can pass (no-display-ok . t) in
-its action alist to indicate readiness for the case of not
-displaying the buffer and FUNCTION can safely return a non-window
-value to suppress displaying.
-
-In any of these cases, it adds the associated action to the list
-of actions it will try."
+condition returns non-nil.  In any of these cases, it adds the
+associated action to the list of actions it will try."
   :type `(alist :key-type
                (choice :tag "Condition"
                        regexp
@@ -5939,8 +6103,9 @@ ALIST is an arbitrary association list (alist).
 Each such FUNCTION should accept two arguments: the buffer to
 display and an alist.  Based on those arguments, it should
 display the buffer and return the window.  If the caller is
-prepared to handle the case of not displaying the buffer it
-should pass (no-display-ok . t) as an element of the ALIST.
+prepared to handle the case of not displaying the buffer
+and returning nil from `display-buffer' it should pass
+\(allow-no-window . t) as an element of the ALIST.
 
 The `display-buffer' function builds a function list and an alist
 by combining the functions and alists specified in
@@ -5995,6 +6160,10 @@ Recognized alist entries include:
     argument - a new window.  The function is supposed to adjust
     the width of the window; its return value is ignored.
 
+ `allow-no-window' -- A non-nil value indicates readiness for the case
+    of not displaying the buffer and FUNCTION can safely return
+    a non-window value to suppress displaying.
+
 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
@@ -6205,7 +6374,9 @@ This either splits the selected window or reuses the window below
 the selected one."
   (let (window)
     (or (and (not (frame-parameter nil 'unsplittable))
-            (setq window (window--try-to-split-window (selected-window) alist))
+            (let ((split-height-threshold 0)
+                  split-width-threshold)
+              (setq window (window--try-to-split-window (selected-window) alist)))
             (window--display-buffer
              buffer window 'window alist display-buffer-mark-dedicated))
        (and (setq window (window-in-direction 'below))
@@ -6326,7 +6497,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)))
@@ -6337,6 +6508,16 @@ that frame."
        (unless (cdr (assq 'inhibit-switch-frame alist))
          (window--maybe-raise-frame (window-frame window)))))))
 
+(defun display-buffer-no-window (_buffer alist)
+  "Display BUFFER in no window.
+If ALIST has a non-nil `allow-no-window' entry, then don't display
+a window at all.  This makes possible to override the default action
+and avoid displaying the buffer.  It is assumed that when the caller
+specifies a non-nil `allow-no-window' then it can handle a nil value
+returned from `display-buffer' in this case."
+  (when (cdr (assq 'allow-no-window alist))
+    'fail))
+
 ;;; Display + selection commands:
 (defun pop-to-buffer (buffer &optional action norecord)
   "Select buffer BUFFER in some window, preferably a different one.
@@ -6653,34 +6834,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
@@ -6750,7 +6923,6 @@ See also `fit-frame-to-buffer-margins'."
   :group 'help)
 
 (declare-function x-display-pixel-height "xfns.c" (&optional terminal))
-(declare-function tool-bar-lines-needed "xdisp.c" (&optional frame))
 
 (defun window--sanitize-margin (margin left right)
   "Return MARGIN if it's a number between LEFT and RIGHT."
@@ -6758,29 +6930,29 @@ 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,
 MAX-WIDTH and MIN-WIDTH specify bounds on the new total size of
-FRAME's root window.
+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)
-  (or (fboundp 'x-display-pixel-height)
-      (user-error "Cannot resize frame in non-graphic Emacs"))
+  (unless (and (fboundp 'x-display-pixel-height)
+              ;; We need the respective sizes now.
+              (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))
@@ -6794,20 +6966,30 @@ FRAME."
             ;; Handle margins.
             (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins)
                          fit-frame-to-buffer-margins))
-            (left-margin (or (window--sanitize-margin
-                              (nth 0 margins) 0 display-width)
-                             (nth 0 workarea)))
-            (top-margin (or (window--sanitize-margin
-                             (nth 1 margins) 0 display-height)
-                            (nth 1 workarea)))
+            (left-margin (if (nth 0 margins)
+                             (or (window--sanitize-margin
+                                  (nth 0 margins) 0 display-width)
+                                 0)
+                           (nth 0 workarea)))
+            (top-margin (if (nth 1 margins)
+                            (or (window--sanitize-margin
+                                 (nth 1 margins) 0 display-height)
+                                0)
+                          (nth 1 workarea)))
             (workarea-width (nth 2 workarea))
-            (right-margin (or (window--sanitize-margin
-                               (nth 2 margins) left-margin display-width)
-                              (+ left-margin workarea-width)))
+            (right-margin (if (nth 2 margins)
+                              (- display-width
+                                 (or (window--sanitize-margin
+                                      (nth 2 margins) left-margin display-width)
+                                     0))
+                            (nth 2 workarea)))
             (workarea-height (nth 3 workarea))
-            (bottom-margin (or (window--sanitize-margin
-                                (nth 3 margins) top-margin display-height)
-                               (+ top-margin workarea-height)))
+            (bottom-margin (if (nth 3 margins)
+                               (- display-height
+                                  (or (window--sanitize-margin
+                                       (nth 3 margins) top-margin display-height)
+                                      0))
+                             (nth 3 workarea)))
             ;; The pixel width of FRAME (which does not include the
             ;; window manager's decorations).
             (frame-width (frame-pixel-width))
@@ -6857,11 +7039,7 @@ FRAME."
                            (not (zerop lines)))
                       (1- lines)
                     0))))
-            ;; The maximum height we can use for fitting.
-            (fit-height
-             (- workarea-height extra-height toolbar-extra-height))
-            ;; The pixel position of FRAME's top border.  We usually
-            ;; try to leave this alone.
+            ;; The pixel position of FRAME's top border.
             (top
              (let ((top (frame-parameter nil 'top)))
                (if (consp top)
@@ -6873,83 +7051,74 @@ FRAME."
             (max-height
              (cond
               ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height))
-              ((numberp max-height) (* max-height char-height))))
+              ((numberp max-height) (* max-height char-height))
+              (t display-height)))
             (min-height
              (cond
               ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height))
-              ((numberp min-height) (* min-height char-height))))
+              ((numberp min-height) (* min-height char-height))
+              (t (* window-min-height char-height))))
             (max-width
              (cond
               ((numberp (nth 2 sizes))
                (- (* (nth 2 sizes) char-width) window-extra-width))
               ((numberp max-width)
-               (- (* max-width char-width) window-extra-width))))
+               (- (* max-width char-width) window-extra-width))
+              (t display-width)))
             (min-width
              (cond
               ((numberp (nth 3 sizes))
                (- (* (nth 3 sizes) char-width) window-extra-width))
               ((numberp min-width)
-               (- (* min-width char-width) window-extra-width))))
+               (- (* min-width char-width) window-extra-width))
+              (t (* window-min-width char-width))))
             ;; Note: Currently, for a new frame the sizes of the header
             ;; and mode line may be estimated incorrectly
             (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)))
-            remainder)
-       (unless window-resize-pixelwise
-         ;; Round sizes to character sizes.
-         (setq remainder (% width char-width))
-         (unless (zerop remainder)
-           (setq width (+ width (- char-width remainder))))
-         (setq remainder (% height char-height))
-         (setq height (+ height (- char-height remainder))))
-       ;; Now make sure that we don't get larger than our rounded
-       ;; maximum lines and columns.
-       (when (> width fit-width)
-         (setq width (- fit-width (% fit-width char-width))))
-       (when (> height fit-height)
-         (setq height (- fit-height (% fit-height char-height))))
+            (height (+ (cdr value) (window-bottom-divider-width))))
        ;; 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 'height)
-         (setq height nil))
-        ((eq window-size-fixed 'width)
+        ((or (eq window-size-fixed 'width) (eq only 'vertically))
+         (setq width nil))
+        ((or (eq window-size-fixed 'height) (eq only 'horizontally))
          (setq height nil)))
+       ;; Fit width to constraints.
        (when width
+         (unless frame-resize-pixelwise
+           ;; Round to character sizes.
+           (setq width (* (/ (+ width char-width -1) char-width)
+                          char-width)))
          ;; Fit to maximum and minimum widths.
-         (when max-width
-           (setq width (min width max-width)))
-         (when min-width
-           (setq width (max width min-width)))
+         (setq width (max (min width max-width) min-width))
          ;; Add extra width.
          (setq width (+ width extra-width))
-         ;; Preserve right margin.
-         (let ((right (+ left width extra-width))
-               (max-right (- workarea-width right-margin)))
+         ;; Preserve margins.
+         (let ((right (+ left width)))
            (cond
-            ((> right max-right)
-             ;; Move FRAME to left.
-             (setq left (max 0 (- left (- right max-right)))))
+            ((> right right-margin)
+             ;; Move frame to left (we don't know its real width).
+             (setq left (max left-margin (- left (- right right-margin)))))
             ((< left left-margin)
              ;; Move frame to right.
              (setq left left-margin)))))
+       ;; Fit height to constraints.
        (when height
+         (unless frame-resize-pixelwise
+           (setq height (* (/ (+ height char-height -1) char-height)
+                           char-height)))
          ;; Fit to maximum and minimum heights.
-         (when max-height
-           (setq height (min height max-height)))
-         (when min-height
-           (setq height (max height min-height)))
+         (setq height (max (min height max-height) min-height))
          ;; Add extra height.
          (setq height (+ height extra-height))
-         ;; Preserve bottom and top margins.
-         (let ((bottom (+ top height extra-height))
-               (max-bottom (- workarea-height bottom-margin)))
+         ;; Preserve margins.
+         (let ((bottom (+ top height)))
            (cond
-            ((> bottom max-bottom)
-             ;; Move FRAME to left.
-             (setq top (max 0 (- top (- bottom max-bottom)))))
+            ((> bottom bottom-margin)
+             ;; Move frame up (we don't know its real height).
+             (setq top (max top-margin (- top (- bottom bottom-margin)))))
             ((< top top-margin)
              ;; Move frame down.
              (setq top top-margin)))))
@@ -6966,29 +7135,29 @@ FRAME."
        (set-frame-size
         frame
         (if width
-            (if window-resize-pixelwise
+            (if frame-resize-pixelwise
                 width
               (/ width char-width))
           (frame-text-width))
         (if height
-            (if window-resize-pixelwise
+            (if frame-resize-pixelwise
                 height
               (/ height char-height))
           (frame-text-height))
-        window-resize-pixelwise)))))
+        frame-resize-pixelwise)))))
 
 (defun fit-window-to-buffer (&optional window max-height min-height max-width min-width)
   "Adjust size of WINDOW to display its buffer's contents exactly.
 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
@@ -6998,11 +7167,11 @@ 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.
 
@@ -7018,13 +7187,13 @@ 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)
-            (frame (window-frame))
             (char-height (frame-char-height))
             (char-width (frame-char-width))
-            (display-height (display-pixel-height))
             (total-height (window-size window nil pixelwise))
             (body-height (window-body-height window pixelwise))
             (body-width (window-body-width window pixelwise))
@@ -7039,7 +7208,10 @@ accessible position."
                           (window-safe-min-pixel-height window)
                         window-safe-min-height))
                ;; Preserve header and mode line if present.
-               (window-min-size nil nil t pixelwise)))
+               (max (if pixelwise
+                        (* char-height window-min-height)
+                      window-min-height)
+                    (window-min-size nil nil t pixelwise))))
             (max-height
              ;; Sanitize MAX-HEIGHT.
              (if (numberp max-height)
@@ -7067,8 +7239,7 @@ accessible position."
                          (window-bottom-divider-width)))
          ;; Round height.
          (unless pixelwise
-           (setq height (+ (/ height char-height)
-                           (if (zerop (% height char-height)) 0 1))))
+           (setq height (/ (+ height char-height -1) char-height)))
          (unless (= height total-height)
            (window-resize-no-error
             window
@@ -7079,8 +7250,7 @@ accessible position."
         ((and fit-window-to-buffer-horizontally
               (not (window-size-fixed-p window t))
               (window-combined-p nil t))
-         (let* ((display-width (display-pixel-width))
-                (total-width (window-size window nil pixelwise))
+         (let* ((total-width (window-size window t pixelwise))
                 (min-width
                  ;; Sanitize MIN-WIDTH.
                  (if (numberp min-width)
@@ -7091,8 +7261,11 @@ accessible position."
                           (if pixelwise
                               (window-safe-min-pixel-width)
                             window-safe-min-width))
-                   ;; Preserve fringes, margines, scrollbars if present.
-                   (window-min-size nil nil t pixelwise)))
+                   ;; Preserve fringes, margins, scrollbars if present.
+                   (max (if pixelwise
+                            (* char-width window-min-width)
+                          window-min-width)
+                        (window-min-size nil nil t pixelwise))))
                 (max-width
                  ;; Sanitize MAX-WIDTH.
                  (if (numberp max-width)
@@ -7119,8 +7292,7 @@ accessible position."
                                    (if pixelwise char-height 1))))
                           (window-right-divider-width))))
            (unless pixelwise
-             (setq width (+ (/ width char-width)
-                            (if (zerop (% width char-width)) 0 1))))
+             (setq width (/ (+ width char-width -1) char-width)))
            (unless (= width body-width)
              (window-resize-no-error
               window