comparison lisp/window.el @ 90996:f55f9811f5d7

Merge from emacs--devo--0 Patches applied: * emacs--devo--0 (patch 824-831) - Update from CVS - Merge from emacs--rel--22 * emacs--rel--22 (patch 70-74) - Update from CVS Revision: emacs@sv.gnu.org/emacs--unicode--0--patch-238
author Miles Bader <miles@gnu.org>
date Fri, 27 Jul 2007 10:52:18 +0000
parents a66921565bcb b98604865ea0
children 424b655804ca
comparison
equal deleted inserted replaced
90995:9a391d85a79f 90996:f55f9811f5d7
8 8
9 ;; This file is part of GNU Emacs. 9 ;; This file is part of GNU Emacs.
10 10
11 ;; GNU Emacs is free software; you can redistribute it and/or modify 11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by 12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option) 13 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; any later version. 14 ;; any later version.
15 15
16 ;; GNU Emacs is distributed in the hope that it will be useful, 16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 `(let ((save-selected-window-window (selected-window)) 55 `(let ((save-selected-window-window (selected-window))
56 ;; It is necessary to save all of these, because calling 56 ;; It is necessary to save all of these, because calling
57 ;; select-window changes frame-selected-window for whatever 57 ;; select-window changes frame-selected-window for whatever
58 ;; frame that window is in. 58 ;; frame that window is in.
59 (save-selected-window-alist 59 (save-selected-window-alist
60 (mapcar (lambda (frame) (list frame (frame-selected-window frame))) 60 (mapcar (lambda (frame) (cons frame (frame-selected-window frame)))
61 (frame-list)))) 61 (frame-list))))
62 (save-current-buffer 62 (save-current-buffer
63 (unwind-protect 63 (unwind-protect
64 (progn ,@body) 64 (progn ,@body)
65 (dolist (elt save-selected-window-alist) 65 (dolist (elt save-selected-window-alist)
66 (and (frame-live-p (car elt)) 66 (and (frame-live-p (car elt))
67 (window-live-p (cadr elt)) 67 (window-live-p (cdr elt))
68 (set-frame-selected-window (car elt) (cadr elt)))) 68 (set-frame-selected-window (car elt) (cdr elt))))
69 (if (window-live-p save-selected-window-window) 69 (if (window-live-p save-selected-window-window)
70 (select-window save-selected-window-window)))))) 70 (select-window save-selected-window-window))))))
71 71
72 (defun window-body-height (&optional window) 72 (defun window-body-height (&optional window)
73 "Return number of lines in window WINDOW for actual buffer text. 73 "Return number of lines in window WINDOW for actual buffer text.
394 (bw-balance-sub wt w h))))) 394 (bw-balance-sub wt w h)))))
395 395
396 (defun bw-adjust-window (window delta horizontal) 396 (defun bw-adjust-window (window delta horizontal)
397 "Wrapper around `adjust-window-trailing-edge' with error checking. 397 "Wrapper around `adjust-window-trailing-edge' with error checking.
398 Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function." 398 Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function."
399 (condition-case err 399 ;; `adjust-window-trailing-edge' may fail if delta is too large.
400 (adjust-window-trailing-edge window delta horizontal) 400 (while (>= (abs delta) 1)
401 (error 401 (condition-case err
402 ;;(message "adjust: %s" (error-message-string err)) 402 (progn
403 ))) 403 (adjust-window-trailing-edge window delta horizontal)
404 (setq delta 0))
405 (error
406 ;;(message "adjust: %s" (error-message-string err))
407 (setq delta (/ delta 2))))))
404 408
405 (defun bw-balance-sub (wt w h) 409 (defun bw-balance-sub (wt w h)
406 (setq wt (bw-refresh-edges wt)) 410 (setq wt (bw-refresh-edges wt))
407 (unless w (setq w (- (bw-r wt) (bw-l wt)))) 411 (unless w (setq w (- (bw-r wt) (bw-l wt))))
408 (unless h (setq h (- (bw-b wt) (bw-t wt)))) 412 (unless h (setq h (- (bw-b wt) (bw-t wt))))
420 (lastchild (car (last childs))) 424 (lastchild (car (last childs)))
421 (cw (when w (/ w (if (bw-eqdir 'hor wt) (length childs) 1)))) 425 (cw (when w (/ w (if (bw-eqdir 'hor wt) (length childs) 1))))
422 (ch (when h (/ h (if (bw-eqdir 'ver wt) (length childs) 1))))) 426 (ch (when h (/ h (if (bw-eqdir 'ver wt) (length childs) 1)))))
423 (dolist (c childs) 427 (dolist (c childs)
424 (bw-balance-sub c cw ch))))) 428 (bw-balance-sub c cw ch)))))
429
430 ;;; A different solution to balance-windows
431
432 (defun window-fixed-size-p (&optional window direction)
433 "Non-nil if WINDOW cannot be resized in DIRECTION.
434 DIRECTION can be nil (i.e. any), `height' or `width'."
435 (with-current-buffer (window-buffer window)
436 (let ((fixed (and (boundp 'window-size-fixed) window-size-fixed)))
437 (when fixed
438 (not (and direction
439 (member (cons direction window-size-fixed)
440 '((height . width) (width . height)))))))))
441
442 (defvar window-area-factor 1
443 "Factor by which the window area should be over-estimated.
444 This is used by `balance-windows-area'.
445 Changing this globally has no effect.")
446
447 (defun balance-windows-area ()
448 "Make all visible windows the same area (approximately).
449 See also `window-area-factor' to change the relative size of specific buffers."
450 (interactive)
451 (let* ((unchanged 0) (carry 0) (round 0)
452 ;; Remove fixed-size windows.
453 (wins (delq nil (mapcar (lambda (win)
454 (if (not (window-fixed-size-p win)) win))
455 (window-list nil 'nomini))))
456 (changelog nil)
457 next)
458 ;; Resizing a window changes the size of surrounding windows in complex
459 ;; ways, so it's difficult to balance them all. The introduction of
460 ;; `adjust-window-trailing-edge' made it a bit easier, but it is still
461 ;; very difficult to do. `balance-window' above takes an off-line
462 ;; approach: get the whole window tree, then balance it, then try to
463 ;; adjust the windows so they fit the result.
464 ;; Here, instead, we take a "local optimization" approach, where we just
465 ;; go through all the windows several times until nothing needs to be
466 ;; changed. The main problem with this approach is that it's difficult
467 ;; to make sure it terminates, so we use some heuristic to try and break
468 ;; off infinite loops.
469 ;; After a round without any change, we allow a second, to give a chance
470 ;; to the carry to propagate a minor imbalance from the end back to
471 ;; the beginning.
472 (while (< unchanged 2)
473 ;; (message "New round")
474 (setq unchanged (1+ unchanged) round (1+ round))
475 (dolist (win wins)
476 (setq next win)
477 (while (progn (setq next (next-window next))
478 (window-fixed-size-p next)))
479 ;; (assert (eq next (or (cadr (member win wins)) (car wins))))
480 (let* ((horiz
481 (< (car (window-edges win)) (car (window-edges next))))
482 (areadiff (/ (- (* (window-height next) (window-width next)
483 (buffer-local-value 'window-area-factor
484 (window-buffer next)))
485 (* (window-height win) (window-width win)
486 (buffer-local-value 'window-area-factor
487 (window-buffer win))))
488 (max (buffer-local-value 'window-area-factor
489 (window-buffer win))
490 (buffer-local-value 'window-area-factor
491 (window-buffer next)))))
492 (edgesize (if horiz
493 (+ (window-height win) (window-height next))
494 (+ (window-width win) (window-width next))))
495 (diff (/ areadiff edgesize)))
496 (when (zerop diff)
497 ;; Maybe diff is actually closer to 1 than to 0.
498 (setq diff (/ (* 3 areadiff) (* 2 edgesize))))
499 (when (and (zerop diff) (not (zerop areadiff)))
500 (setq diff (/ (+ areadiff carry) edgesize))
501 ;; Change things smoothly.
502 (if (or (> diff 1) (< diff -1)) (setq diff (/ diff 2))))
503 (if (zerop diff)
504 ;; Make sure negligible differences don't accumulate to
505 ;; become significant.
506 (setq carry (+ carry areadiff))
507 (bw-adjust-window win diff horiz)
508 ;; (sit-for 0.5)
509 (let ((change (cons win (window-edges win))))
510 ;; If the same change has been seen already for this window,
511 ;; we're most likely in an endless loop, so don't count it as
512 ;; a change.
513 (unless (member change changelog)
514 (push change changelog)
515 (setq unchanged 0 carry 0)))))))
516 ;; We've now basically balanced all the windows.
517 ;; But there may be some minor off-by-one imbalance left over,
518 ;; so let's do some fine tuning.
519 ;; (bw-finetune wins)
520 ;; (message "Done in %d rounds" round)
521 ))
425 522
426 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 523 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
427 524
428 ;; I think this should be the default; I think people will prefer it--rms. 525 ;; I think this should be the default; I think people will prefer it--rms.
429 (defcustom split-window-keep-point t 526 (defcustom split-window-keep-point t