diff options
| author | Eli Zaretskii | 2005-12-10 12:21:44 +0000 |
|---|---|---|
| committer | Eli Zaretskii | 2005-12-10 12:21:44 +0000 |
| commit | 614b38a99518cb219f3b24016ca8aa638f0581be (patch) | |
| tree | 521b480c0564a03759ae4210b7d8468c61527dc5 | |
| parent | a8514f71b97588fa340bba69a53bec9358e72d9e (diff) | |
| download | emacs-614b38a99518cb219f3b24016ca8aa638f0581be.tar.gz emacs-614b38a99518cb219f3b24016ca8aa638f0581be.zip | |
(bw-get-tree, bw-get-tree-1, bw-find-tree-sub)
(bw-find-tree-sub-1, bw-l, bw-t, bw-r, bw-b, bw-dir, bw-eqdir)
(bw-refresh-edges, bw-adjust-window, bw-balance-sub): New functions.
(balance-windows): Rewrite using the above new functions.
| -rw-r--r-- | lisp/ChangeLog | 7 | ||||
| -rw-r--r-- | lisp/window.el | 262 |
2 files changed, 201 insertions, 68 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0da509f20e9..e3df313ecb0 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2005-12-10 Lennart Borgman <lennart.borgman.073@student.lu.se> | ||
| 2 | |||
| 3 | * window.el (bw-get-tree, bw-get-tree-1, bw-find-tree-sub) | ||
| 4 | (bw-find-tree-sub-1, bw-l, bw-t, bw-r, bw-b, bw-dir, bw-eqdir) | ||
| 5 | (bw-refresh-edges, bw-adjust-window, bw-balance-sub): New functions. | ||
| 6 | (balance-windows): Rewrite using the above new functions. | ||
| 7 | |||
| 1 | 2005-12-10 David Koppelman <koppel@ece.lsu.edu> | 8 | 2005-12-10 David Koppelman <koppel@ece.lsu.edu> |
| 2 | 9 | ||
| 3 | * hi-lock.el: (hi-lock-mode) Renamed from hi-lock-buffer-mode; | 10 | * hi-lock.el: (hi-lock-mode) Renamed from hi-lock-buffer-mode; |
diff --git a/lisp/window.el b/lisp/window.el index cd4b22f3e7e..6cb553c3799 100644 --- a/lisp/window.el +++ b/lisp/window.el | |||
| @@ -228,75 +228,201 @@ If WINDOW is nil or omitted, it defaults to the currently selected window." | |||
| 228 | (or (= (nth 2 edges) (nth 2 (window-edges (previous-window)))) | 228 | (or (= (nth 2 edges) (nth 2 (window-edges (previous-window)))) |
| 229 | (= (nth 0 edges) (nth 0 (window-edges (next-window)))))))) | 229 | (= (nth 0 edges) (nth 0 (window-edges (next-window)))))))) |
| 230 | 230 | ||
| 231 | 231 | ||
| 232 | (defun balance-windows () | 232 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 233 | "Make all visible windows the same height (approximately)." | 233 | ;;; `balance-windows' subroutines using `window-tree' |
| 234 | |||
| 235 | ;;; Translate from internal window tree format | ||
| 236 | |||
| 237 | (defun bw-get-tree (&optional window-or-frame) | ||
| 238 | "Get a window split tree in our format. | ||
| 239 | |||
| 240 | WINDOW-OR-FRAME must be nil, a frame, or a window. If it is nil, | ||
| 241 | then the whole window split tree for `selected-frame' is returned. | ||
| 242 | If it is a frame, then this is used instead. If it is a window, | ||
| 243 | then the smallest tree containing that window is returned." | ||
| 244 | (when window-or-frame | ||
| 245 | (unless (or (framep window-or-frame) | ||
| 246 | (windowp window-or-frame)) | ||
| 247 | (error "Not a frame or window: %s" window-or-frame))) | ||
| 248 | (let ((subtree (bw-find-tree-sub window-or-frame))) | ||
| 249 | (if (integerp subtree) | ||
| 250 | nil | ||
| 251 | (bw-get-tree-1 subtree)))) | ||
| 252 | |||
| 253 | (defun bw-get-tree-1 (split) | ||
| 254 | (if (windowp split) | ||
| 255 | split | ||
| 256 | (let ((dir (car split)) | ||
| 257 | (edges (car (cdr split))) | ||
| 258 | (childs (cdr (cdr split)))) | ||
| 259 | (list | ||
| 260 | (cons 'dir (if dir 'ver 'hor)) | ||
| 261 | (cons 'b (nth 3 edges)) | ||
| 262 | (cons 'r (nth 2 edges)) | ||
| 263 | (cons 't (nth 1 edges)) | ||
| 264 | (cons 'l (nth 0 edges)) | ||
| 265 | (cons 'childs (mapcar #'bw-get-tree-1 childs)))))) | ||
| 266 | |||
| 267 | (defun bw-find-tree-sub (window-or-frame &optional get-parent) | ||
| 268 | (let* ((window (when (windowp window-or-frame) window-or-frame)) | ||
| 269 | (frame (when (windowp window) (window-frame window))) | ||
| 270 | (wt (car (window-tree frame)))) | ||
| 271 | (when (< 1 (length (window-list frame 0))) | ||
| 272 | (if window | ||
| 273 | (bw-find-tree-sub-1 wt window get-parent) | ||
| 274 | wt)))) | ||
| 275 | |||
| 276 | (defun bw-find-tree-sub-1 (tree win &optional get-parent) | ||
| 277 | (unless (windowp win) (error "Not a window: %s" win)) | ||
| 278 | (if (memq win tree) | ||
| 279 | (if get-parent | ||
| 280 | get-parent | ||
| 281 | tree) | ||
| 282 | (let ((childs (cdr (cdr tree))) | ||
| 283 | child | ||
| 284 | subtree) | ||
| 285 | (while (and childs (not subtree)) | ||
| 286 | (setq child (car childs)) | ||
| 287 | (setq childs (cdr childs)) | ||
| 288 | (when (and child (listp child)) | ||
| 289 | (setq subtree (bw-find-tree-sub-1 child win get-parent)))) | ||
| 290 | (if (integerp subtree) | ||
| 291 | (progn | ||
| 292 | (if (= 1 subtree) | ||
| 293 | tree | ||
| 294 | (1- subtree))) | ||
| 295 | subtree | ||
| 296 | )))) | ||
| 297 | |||
| 298 | ;;; Window or object edges | ||
| 299 | |||
| 300 | (defun bw-l(obj) | ||
| 301 | "Left edge of OBJ." | ||
| 302 | (if (windowp obj) (nth 0 (window-edges obj)) (cdr (assq 'l obj)))) | ||
| 303 | (defun bw-t(obj) | ||
| 304 | "Top edge of OBJ." | ||
| 305 | (if (windowp obj) (nth 1 (window-edges obj)) (cdr (assq 't obj)))) | ||
| 306 | (defun bw-r(obj) | ||
| 307 | "Right edge of OBJ." | ||
| 308 | (if (windowp obj) (nth 2 (window-edges obj)) (cdr (assq 'r obj)))) | ||
| 309 | (defun bw-b(obj) | ||
| 310 | "Bottom edge of OBJ." | ||
| 311 | (if (windowp obj) (nth 3 (window-edges obj)) (cdr (assq 'b obj)))) | ||
| 312 | |||
| 313 | ;;; Split directions | ||
| 314 | |||
| 315 | (defun bw-dir(obj) | ||
| 316 | "Return window split tree direction if OBJ. | ||
| 317 | If OBJ is a window return 'both. If it is a window split tree | ||
| 318 | then return its direction." | ||
| 319 | (if (symbolp obj) | ||
| 320 | obj | ||
| 321 | (if (windowp obj) | ||
| 322 | 'both | ||
| 323 | (let ((dir (cdr (assq 'dir obj)))) | ||
| 324 | (unless (memq dir '(hor ver both)) | ||
| 325 | (error "Can't find dir in %s" obj)) | ||
| 326 | dir)))) | ||
| 327 | |||
| 328 | (defun bw-eqdir(obj1 obj2) | ||
| 329 | "Return t if window split tree directions are equal. | ||
| 330 | OBJ1 and OBJ2 should be either windows or window split trees in | ||
| 331 | our format. The directions returned by `bw-dir' are compared and | ||
| 332 | t is returned if they are `eq' or one of them is 'both." | ||
| 333 | (let ((dir1 (bw-dir obj1)) | ||
| 334 | (dir2 (bw-dir obj2))) | ||
| 335 | (or (eq dir1 dir2) | ||
| 336 | (eq dir1 'both) | ||
| 337 | (eq dir2 'both)))) | ||
| 338 | |||
| 339 | ;;; Building split tree | ||
| 340 | |||
| 341 | (defun bw-refresh-edges(obj) | ||
| 342 | "Refresh the edge information of OBJ and return OBJ." | ||
| 343 | (unless (windowp obj) | ||
| 344 | (let ((childs (cdr (assq 'childs obj))) | ||
| 345 | (ol 1000) | ||
| 346 | (ot 1000) | ||
| 347 | (or -1) | ||
| 348 | (ob -1)) | ||
| 349 | (dolist (o childs) | ||
| 350 | (when (> ol (bw-l o)) (setq ol (bw-l o))) | ||
| 351 | (when (> ot (bw-t o)) (setq ot (bw-t o))) | ||
| 352 | (when (< or (bw-r o)) (setq or (bw-r o))) | ||
| 353 | (when (< ob (bw-b o)) (setq ob (bw-b o)))) | ||
| 354 | (setq obj (delq 'l obj)) | ||
| 355 | (setq obj (delq 't obj)) | ||
| 356 | (setq obj (delq 'r obj)) | ||
| 357 | (setq obj (delq 'b obj)) | ||
| 358 | (add-to-list 'obj (cons 'l ol)) | ||
| 359 | (add-to-list 'obj (cons 't ot)) | ||
| 360 | (add-to-list 'obj (cons 'r or)) | ||
| 361 | (add-to-list 'obj (cons 'b ob)) | ||
| 362 | )) | ||
| 363 | obj) | ||
| 364 | |||
| 365 | ;;; Balance windows | ||
| 366 | |||
| 367 | (defun balance-windows(&optional window-or-frame) | ||
| 368 | "Make windows the same heights or widths in window split subtrees. | ||
| 369 | |||
| 370 | When called non-interactively WINDOW-OR-FRAME may be either a | ||
| 371 | window or a frame. It then balances the windows on the implied | ||
| 372 | frame. If the parameter is a window only the corresponding window | ||
| 373 | subtree is balanced." | ||
| 234 | (interactive) | 374 | (interactive) |
| 235 | (let ((count -1) levels newsizes level-size | 375 | (let ( |
| 236 | ;; Don't count the lines that are above the uppermost windows. | 376 | (wt (bw-get-tree window-or-frame)) |
| 237 | ;; (These are the menu bar lines, if any.) | 377 | (w) |
| 238 | (mbl (nth 1 (window-edges (frame-first-window (selected-frame))))) | 378 | (h) |
| 239 | (last-window (previous-window (frame-first-window (selected-frame)))) | 379 | (tried-sizes) |
| 240 | ;; Don't count the lines that are past the lowest main window. | 380 | (last-sizes) |
| 241 | total) | 381 | (windows (window-list nil 0)) |
| 242 | ;; Bottom edge of last window determines what size we have to work with. | 382 | (counter 0)) |
| 243 | (setq total | 383 | (when wt |
| 244 | (+ (window-height last-window) | 384 | (while (not (member last-sizes tried-sizes)) |
| 245 | (nth 1 (window-edges last-window)))) | 385 | (when last-sizes (setq tried-sizes (cons last-sizes tried-sizes))) |
| 246 | 386 | (setq last-sizes (mapcar (lambda(w) | |
| 247 | ;; Find all the different vpos's at which windows start, | 387 | (window-edges w)) |
| 248 | ;; then count them. But ignore levels that differ by only 1. | 388 | windows)) |
| 249 | (let (tops (prev-top -2)) | 389 | (when (eq 'hor (bw-dir wt)) |
| 250 | (walk-windows (function (lambda (w) | 390 | (setq w (- (bw-r wt) (bw-l wt)))) |
| 251 | (setq tops (cons (nth 1 (window-edges w)) | 391 | (when (eq 'ver (bw-dir wt)) |
| 252 | tops)))) | 392 | (setq h (- (bw-b wt) (bw-t wt)))) |
| 253 | 'nomini) | 393 | (bw-balance-sub wt w h))))) |
| 254 | (setq tops (sort tops '<)) | 394 | |
| 255 | (while tops | 395 | (defun bw-adjust-window(window delta horizontal) |
| 256 | (if (> (car tops) (1+ prev-top)) | 396 | "Wrapper around `adjust-window-trailing-edge' with error checking. |
| 257 | (setq prev-top (car tops) | 397 | Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function." |
| 258 | count (1+ count))) | 398 | (condition-case err |
| 259 | (setq levels (cons (cons (car tops) count) levels)) | 399 | (adjust-window-trailing-edge window delta horizontal) |
| 260 | (setq tops (cdr tops))) | 400 | (error |
| 261 | (setq count (1+ count))) | 401 | ;;(message "adjust: %s" (error-message-string err)) |
| 262 | ;; Subdivide the frame into desired number of vertical levels. | 402 | ))) |
| 263 | (setq level-size (/ (- total mbl) count)) | 403 | |
| 264 | (save-selected-window | 404 | (defun bw-balance-sub(wt w h) |
| 265 | ;; Set up NEWSIZES to map windows to their desired sizes. | 405 | (setq wt (bw-refresh-edges wt)) |
| 266 | ;; If a window ends at the bottom level, don't include | 406 | (unless w (setq w (- (bw-r wt) (bw-l wt)))) |
| 267 | ;; it in NEWSIZES. Those windows get the right sizes | 407 | (unless h (setq h (- (bw-b wt) (bw-t wt)))) |
| 268 | ;; by adjusting the ones above them. | 408 | (if (windowp wt) |
| 269 | (walk-windows (function | 409 | (progn |
| 270 | (lambda (w) | 410 | (when w |
| 271 | (let ((newtop (cdr (assq (nth 1 (window-edges w)) | 411 | (let ((dw (- w (- (bw-r wt) (bw-l wt))))) |
| 272 | levels))) | 412 | (when (/= 0 dw) |
| 273 | (newbot (cdr (assq (+ (window-height w) | 413 | (bw-adjust-window wt dw t)))) |
| 274 | (nth 1 (window-edges w))) | 414 | (when h |
| 275 | levels)))) | 415 | (let ((dh (- h (- (bw-b wt) (bw-t wt))))) |
| 276 | (if newbot | 416 | (when (/= 0 dh) |
| 277 | (setq newsizes | 417 | (bw-adjust-window wt dh nil))))) |
| 278 | (cons (cons w (* level-size (- newbot newtop))) | 418 | (let* ((childs (cdr (assq 'childs wt))) |
| 279 | newsizes)))))) | 419 | (lastchild (car (last childs))) |
| 280 | 'nomini) | 420 | (cw (when w (/ w (if (bw-eqdir 'hor wt) (length childs) 1)))) |
| 281 | ;; Make walk-windows start with the topmost window. | 421 | (ch (when h (/ h (if (bw-eqdir 'ver wt) (length childs) 1))))) |
| 282 | (select-window (previous-window (frame-first-window (selected-frame)))) | 422 | (dolist (c childs) |
| 283 | (let (done (count 0)) | 423 | (bw-balance-sub c cw ch))))) |
| 284 | ;; Give each window its precomputed size, or at least try. | 424 | |
| 285 | ;; Keep trying until they all get the intended sizes, | 425 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 286 | ;; but not more than 3 times (to prevent infinite loop). | ||
| 287 | (while (and (not done) (< count 3)) | ||
| 288 | (setq done t) | ||
| 289 | (setq count (1+ count)) | ||
| 290 | (walk-windows (function (lambda (w) | ||
| 291 | (select-window w) | ||
| 292 | (let ((newsize (cdr (assq w newsizes)))) | ||
| 293 | (when newsize | ||
| 294 | (enlarge-window (- newsize | ||
| 295 | (window-height)) | ||
| 296 | nil) | ||
| 297 | (unless (= (window-height) newsize) | ||
| 298 | (setq done nil)))))) | ||
| 299 | 'nomini)))))) | ||
| 300 | 426 | ||
| 301 | ;; I think this should be the default; I think people will prefer it--rms. | 427 | ;; I think this should be the default; I think people will prefer it--rms. |
| 302 | (defcustom split-window-keep-point t | 428 | (defcustom split-window-keep-point t |