+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; `balance-windows' subroutines using `window-tree'
+
+;;; Translate from internal window tree format
+
+(defun bw-get-tree (&optional window-or-frame)
+ "Get a window split tree in our format.
+
+WINDOW-OR-FRAME must be nil, a frame, or a window. If it is nil,
+then the whole window split tree for `selected-frame' is returned.
+If it is a frame, then this is used instead. If it is a window,
+then the smallest tree containing that window is returned."
+ (when window-or-frame
+ (unless (or (framep window-or-frame)
+ (windowp window-or-frame))
+ (error "Not a frame or window: %s" window-or-frame)))
+ (let ((subtree (bw-find-tree-sub window-or-frame)))
+ (if (integerp subtree)
+ nil
+ (bw-get-tree-1 subtree))))
+
+(defun bw-get-tree-1 (split)
+ (if (windowp split)
+ split
+ (let ((dir (car split))
+ (edges (car (cdr split)))
+ (childs (cdr (cdr split))))
+ (list
+ (cons 'dir (if dir 'ver 'hor))
+ (cons 'b (nth 3 edges))
+ (cons 'r (nth 2 edges))
+ (cons 't (nth 1 edges))
+ (cons 'l (nth 0 edges))
+ (cons 'childs (mapcar #'bw-get-tree-1 childs))))))
+
+(defun bw-find-tree-sub (window-or-frame &optional get-parent)
+ (let* ((window (when (windowp window-or-frame) window-or-frame))
+ (frame (when (windowp window) (window-frame window)))
+ (wt (car (window-tree frame))))
+ (when (< 1 (length (window-list frame 0)))
+ (if window
+ (bw-find-tree-sub-1 wt window get-parent)
+ wt))))
+
+(defun bw-find-tree-sub-1 (tree win &optional get-parent)
+ (unless (windowp win) (error "Not a window: %s" win))
+ (if (memq win tree)
+ (if get-parent
+ get-parent
+ tree)
+ (let ((childs (cdr (cdr tree)))
+ child
+ subtree)
+ (while (and childs (not subtree))
+ (setq child (car childs))
+ (setq childs (cdr childs))
+ (when (and child (listp child))
+ (setq subtree (bw-find-tree-sub-1 child win get-parent))))
+ (if (integerp subtree)
+ (progn
+ (if (= 1 subtree)
+ tree
+ (1- subtree)))
+ subtree
+ ))))
+
+;;; Window or object edges
+
+(defun bw-l (obj)
+ "Left edge of OBJ."
+ (if (windowp obj) (nth 0 (window-edges obj)) (cdr (assq 'l obj))))
+(defun bw-t (obj)
+ "Top edge of OBJ."
+ (if (windowp obj) (nth 1 (window-edges obj)) (cdr (assq 't obj))))
+(defun bw-r (obj)
+ "Right edge of OBJ."
+ (if (windowp obj) (nth 2 (window-edges obj)) (cdr (assq 'r obj))))
+(defun bw-b (obj)
+ "Bottom edge of OBJ."
+ (if (windowp obj) (nth 3 (window-edges obj)) (cdr (assq 'b obj))))
+
+;;; Split directions
+
+(defun bw-dir (obj)
+ "Return window split tree direction if OBJ.
+If OBJ is a window return 'both. If it is a window split tree
+then return its direction."
+ (if (symbolp obj)
+ obj
+ (if (windowp obj)
+ 'both
+ (let ((dir (cdr (assq 'dir obj))))
+ (unless (memq dir '(hor ver both))
+ (error "Can't find dir in %s" obj))
+ dir))))
+
+(defun bw-eqdir (obj1 obj2)
+ "Return t if window split tree directions are equal.
+OBJ1 and OBJ2 should be either windows or window split trees in
+our format. The directions returned by `bw-dir' are compared and
+t is returned if they are `eq' or one of them is 'both."
+ (let ((dir1 (bw-dir obj1))
+ (dir2 (bw-dir obj2)))
+ (or (eq dir1 dir2)
+ (eq dir1 'both)
+ (eq dir2 'both))))
+
+;;; Building split tree
+
+(defun bw-refresh-edges (obj)
+ "Refresh the edge information of OBJ and return OBJ."
+ (unless (windowp obj)
+ (let ((childs (cdr (assq 'childs obj)))
+ (ol 1000)
+ (ot 1000)
+ (or -1)
+ (ob -1))
+ (dolist (o childs)
+ (when (> ol (bw-l o)) (setq ol (bw-l o)))
+ (when (> ot (bw-t o)) (setq ot (bw-t o)))
+ (when (< or (bw-r o)) (setq or (bw-r o)))
+ (when (< ob (bw-b o)) (setq ob (bw-b o))))
+ (setq obj (delq 'l obj))
+ (setq obj (delq 't obj))
+ (setq obj (delq 'r obj))
+ (setq obj (delq 'b obj))
+ (add-to-list 'obj (cons 'l ol))
+ (add-to-list 'obj (cons 't ot))
+ (add-to-list 'obj (cons 'r or))
+ (add-to-list 'obj (cons 'b ob))
+ ))
+ obj)
+
+;;; Balance windows
+
+(defun balance-windows (&optional window-or-frame)
+ "Make windows the same heights or widths in window split subtrees.
+
+When called non-interactively WINDOW-OR-FRAME may be either a
+window or a frame. It then balances the windows on the implied
+frame. If the parameter is a window only the corresponding window
+subtree is balanced."