Function: balance-windows-area
balance-windows-area is an interactive and byte-compiled function
defined in window.el.gz.
Signature
(balance-windows-area)
Documentation
Make all visible windows the same area (approximately).
See also window-area-factor to change the relative size of
specific buffers.
Probably introduced at or before Emacs version 23.1.
Key Bindings
Source Code
;; Defined in /usr/src/emacs/lisp/window.el.gz
(defun balance-windows-area ()
"Make all visible windows the same area (approximately).
See also `window-area-factor' to change the relative size of
specific buffers."
(interactive)
(let* ((unchanged 0) (carry 0) (round 0)
;; Remove fixed-size windows.
(wins (delq nil (mapcar (lambda (win)
(if (not (window-fixed-size-p win)) win))
(window-list nil 'nomini))))
(changelog nil)
(pixelwise window-resize-pixelwise)
next)
;; Resizing a window changes the size of surrounding windows in complex
;; ways, so it's difficult to balance them all. The introduction of
;; `adjust-window-trailing-edge' made it a bit easier, but it is still
;; very difficult to do. `balance-window' above takes an off-line
;; approach: get the whole window tree, then balance it, then try to
;; adjust the windows so they fit the result.
;; Here, instead, we take a "local optimization" approach, where we just
;; go through all the windows several times until nothing needs to be
;; changed. The main problem with this approach is that it's difficult
;; to make sure it terminates, so we use some heuristic to try and break
;; off infinite loops.
;; After a round without any change, we allow a second, to give a chance
;; to the carry to propagate a minor imbalance from the end back to
;; the beginning.
(while (< unchanged 2)
;; (message "New round")
(setq unchanged (1+ unchanged) round (1+ round))
(dolist (win wins)
(setq next win)
(while (progn (setq next (next-window next))
(window-fixed-size-p next)))
;; (assert (eq next (or (cadr (member win wins)) (car wins))))
(let* ((horiz
(< (car (window-pixel-edges win)) (car (window-pixel-edges next))))
(areadiff (/ (- (* (window-size next nil pixelwise)
(window-size next t pixelwise)
(buffer-local-value 'window-area-factor
(window-buffer next)))
(* (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
(window-buffer win))
(buffer-local-value 'window-area-factor
(window-buffer next)))))
(edgesize (if horiz
(+ (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.
(setq diff (/ (* 3 areadiff) (* 2 edgesize))))
(when (and (zerop diff) (not (zerop areadiff)))
(setq diff (/ (+ areadiff carry) edgesize))
;; Change things smoothly.
(if (or (> diff 1) (< diff -1)) (setq diff (/ diff 2))))
(if (zerop diff)
;; Make sure negligible differences don't accumulate to
;; become significant.
(setq carry (+ carry areadiff))
;; This used `adjust-window-trailing-edge' before and uses
;; `window-resize' now. Error wrapping is still needed.
(balance-windows-area-adjust win diff horiz pixelwise)
;; (sit-for 0.5)
(let ((change (cons win (window-pixel-edges win))))
;; If the same change has been seen already for this window,
;; we're most likely in an endless loop, so don't count it as
;; a change.
(unless (member change changelog)
(push change changelog)
(setq unchanged 0 carry 0)))))))
;; We've now basically balanced all the windows.
;; But there may be some minor off-by-one imbalance left over,
;; so let's do some fine tuning.
;; (bw-finetune wins)
;; (message "Done in %d rounds" round)
))