Add arch taglines
[bpt/emacs.git] / lisp / window.el
index 5d8c9a9..0dadd41 100644 (file)
@@ -1,9 +1,10 @@
-;;; window.el --- GNU Emacs window commands aside from those written in C.
+;;; window.el --- GNU Emacs window commands aside from those written in C
 
-;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000
+;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001, 2002
 ;;  Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
+;; Keywords: internal
 
 ;; This file is part of GNU Emacs.
 
 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
-
 ;;; Commentary:
 
 ;; Window tree functions.
 
 ;;; Code:
 
+(defmacro save-selected-window (&rest body)
+  "Execute BODY, then select the window that was selected before BODY.
+Also restore the selected window of each frame as it was at the start
+of this construct.
+However, if a window has become dead, don't get an error,
+just refrain from reselecting it."
+  `(let ((save-selected-window-window (selected-window))
+        (save-selected-window-alist
+         (mapcar (lambda (frame) (list frame (frame-selected-window frame)))
+                 (frame-list))))
+     (unwind-protect
+        (progn ,@body)
+       (dolist (elt save-selected-window-alist)
+        (and (frame-live-p (car elt))
+             (window-live-p (cadr elt))
+             (set-frame-selected-window (car elt) (cadr elt))))
+       (if (window-live-p save-selected-window-window)
+          (select-window save-selected-window-window)))))
+
+(defun window-body-height (&optional window)
+  "Return number of lines in window WINDOW for actual buffer text.
+This does not include the mode line (if any) or the header line (if any)."
+  (or window (setq window (selected-window)))
+  (if (window-minibuffer-p window)
+      (window-height window)
+    (with-current-buffer (window-buffer window)
+      (max 1 (- (window-height window)
+               (if mode-line-format 1 0)
+               (if header-line-format 1 0))))))
+
 (defun one-window-p (&optional nomini all-frames)
   "Return non-nil if the selected window is the only window (in its frame).
 Optional arg NOMINI non-nil means don't count the minibuffer
@@ -84,7 +114,8 @@ Anything else means restrict to the selected frame."
              (cons walk-windows-current walk-windows-already-seen))
        (funcall proc walk-windows-current)))))
 
-(defun some-window (predicate &optional minibuf all-frames default)
+(defun get-window-with-predicate (predicate &optional minibuf
+                                           all-frames default)
   "Return a window satisfying PREDICATE.
 
 This function cycles through all visible windows using `walk-windows',
@@ -119,16 +150,11 @@ Anything else means restrict to the selected frame."
                  minibuf all-frames)
     default))
 
+(defalias 'some-window 'get-window-with-predicate)
+
 (defun minibuffer-window-active-p (window)
   "Return t if WINDOW (a minibuffer window) is now active."
   (eq window (active-minibuffer-window)))
-
-(defmacro save-selected-window (&rest body)
-  "Execute BODY, then select the window that was selected before BODY."
-  `(let ((save-selected-window-window (selected-window)))
-     (unwind-protect
-        (progn ,@body)
-       (select-window save-selected-window-window))))
 \f
 (defun count-windows (&optional minibuf)
    "Return the number of visible windows.
@@ -143,7 +169,8 @@ even if it is inactive."
      count))
 
 (defun window-safely-shrinkable-p (&optional window)
-  "Non-nil if the WINDOW can be shrunk without shrinking other windows."
+  "Non-nil if the WINDOW can be shrunk without shrinking other windows.
+If WINDOW is nil or omitted, it defaults to the currently selected window."
   (save-selected-window
     (when window (select-window window))
     (or (and (not (eq window (frame-first-window)))
@@ -155,49 +182,73 @@ even if it is inactive."
 (defun balance-windows ()
   "Make all visible windows the same height (approximately)."
   (interactive)
-  (let ((count -1) levels newsizes size
+  (let ((count -1) levels newsizes level-size
        ;; Don't count the lines that are above the uppermost windows.
        ;; (These are the menu bar lines, if any.)
-       (mbl (nth 1 (window-edges (frame-first-window (selected-frame))))))
+       (mbl (nth 1 (window-edges (frame-first-window (selected-frame)))))
+       (last-window (previous-window (frame-first-window (selected-frame))))
+       ;; Don't count the lines that are past the lowest main window.
+       total)
+    ;; Bottom edge of last window determines what size we have to work with.
+    (setq total
+         (+ (window-height last-window)
+            (nth 1 (window-edges last-window))))
+
     ;; Find all the different vpos's at which windows start,
     ;; then count them.  But ignore levels that differ by only 1.
-    (save-window-excursion
-      (let (tops (prev-top -2))
-       (walk-windows (function (lambda (w)
-                                 (setq tops (cons (nth 1 (window-edges w))
-                                                  tops))))
-                     'nomini)
-       (setq tops (sort tops '<))
-       (while tops
-         (if (> (car tops) (1+ prev-top))
-             (setq prev-top (car tops)
-                   count (1+ count)))
-         (setq levels (cons (cons (car tops) count) levels))
-         (setq tops (cdr tops)))
-       (setq count (1+ count))))
-    ;; Subdivide the frame into that many vertical levels.
-    (setq size (/ (- (frame-height) mbl) count))
-    (walk-windows (function
-                  (lambda (w)
-                    (select-window w)
-                    (let ((newtop (cdr (assq (nth 1 (window-edges))
-                                             levels)))
-                          (newbot (or (cdr (assq (+ (window-height)
-                                                    (nth 1 (window-edges)))
-                                                 levels))
-                                      count)))
-                      (setq newsizes
-                            (cons (cons w (* size (- newbot newtop)))
-                                  newsizes)))))
-                 'nomini)
-    (walk-windows (function (lambda (w)
-                             (select-window w)
-                             (let ((newsize (cdr (assq w newsizes))))
-                               (enlarge-window (- newsize
-                                                  (window-height))))))
-                 'nomini)))
+    (let (tops (prev-top -2))
+      (walk-windows (function (lambda (w)
+                               (setq tops (cons (nth 1 (window-edges w))
+                                                tops))))
+                   'nomini)
+      (setq tops (sort tops '<))
+      (while tops
+       (if (> (car tops) (1+ prev-top))
+           (setq prev-top (car tops)
+                 count (1+ count)))
+       (setq levels (cons (cons (car tops) count) levels))
+       (setq tops (cdr tops)))
+      (setq count (1+ count)))
+    ;; Subdivide the frame into desired number of vertical levels.
+    (setq level-size (/ (- total mbl) count))
+    (save-selected-window
+      ;; Set up NEWSIZES to map windows to their desired sizes.
+      ;; If a window ends at the bottom level, don't include
+      ;; it in NEWSIZES.  Those windows get the right sizes
+      ;; by adjusting the ones above them.
+      (walk-windows (function
+                    (lambda (w)
+                      (let ((newtop (cdr (assq (nth 1 (window-edges w))
+                                               levels)))
+                            (newbot (cdr (assq (+ (window-height w)
+                                                  (nth 1 (window-edges w)))
+                                               levels))))
+                        (if newbot
+                            (setq newsizes
+                                  (cons (cons w (* level-size (- newbot newtop)))
+                                        newsizes))))))
+                   'nomini)
+      ;; Make walk-windows start with the topmost window.
+      (select-window (previous-window (frame-first-window (selected-frame))))
+      (let (done (count 0))
+       ;; Give each window its precomputed size, or at least try.
+       ;; Keep trying until they all get the intended sizes,
+       ;; but not more than 3 times (to prevent infinite loop).
+       (while (and (not done) (< count 3))
+         (setq done t)
+         (setq count (1+ count))
+         (walk-windows (function (lambda (w)
+                                   (select-window w)
+                                   (let ((newsize (cdr (assq w newsizes))))
+                                     (when newsize
+                                       (enlarge-window (- newsize
+                                                          (window-height))
+                                                       nil t)
+                                       (unless (= (window-height) newsize)
+                                         (setq done nil))))))
+                       'nomini))))))
 \f
-;;; I think this should be the default; I think people will prefer it--rms.
+;; I think this should be the default; I think people will prefer it--rms.
 (defcustom split-window-keep-point t
   "*If non-nil, split windows keeps the original point in both children.
 This is often more convenient for editing.
@@ -258,13 +309,11 @@ new mode line."
 (defvar view-return-to-alist)
 
 (defun split-window-save-restore-data (new-w old-w)
-  (save-excursion
-    (set-buffer (window-buffer))
+  (with-current-buffer (window-buffer)
     (if view-mode
        (let ((old-info (assq old-w view-return-to-alist)))
-         (setq view-return-to-alist
-               (cons (cons new-w (cons (and old-info (car (cdr old-info))) t))
-                     view-return-to-alist))))
+         (push (cons new-w (cons (and old-info (car (cdr old-info))) t))
+               view-return-to-alist)))
     new-w))
 
 (defun split-window-horizontally (&optional arg)
@@ -280,59 +329,6 @@ to the window's right, if any.  No arg means split equally."
     (and size (< size 0)
         (setq size (+ (window-width) size)))
     (split-window-save-restore-data (split-window nil size t) old-w)))
-\f
-(defcustom mode-line-window-height-fudge nil
-  "*Fudge factor returned by `mode-line-window-height-fudge' on graphic displays.
-If non-nil, it should be the number of lines to add to the sizes of
-windows to compensate for the extra height of the mode-line, so it
-doesn't't obscure the last line of text.
-
-If nil, an attempt is made to calculate reasonable value.
-
-This is a kluge."
-  :type '(choice (const :tag "Guess" nil)
-                (integer :tag "Extra lines" :value 1))
-  :group 'windows)
-
-;; List of face attributes that might change a face's height
-(defconst height-affecting-face-attributes
-  '(:family :height :box :font :inherit))
-
-(defsubst mode-line-window-height-fudge (&optional face)
-  "Return a fudge factor to compensate for the extra height of graphic mode-lines.
-On a non-graphic display, return 0.
-
-FACE is the face used to display the mode-line; it defaults to `mode-line'.
-
-If the variable `mode-line-window-height-fudge' has a non-nil value, it
-is returned.  Otherwise, the `mode-line' face is checked to see if it
-contains any attributes that might affect its height; if it does, 1 is
-returned, otherwise 0.
-
-\[Because mode-lines on a graphics capable display may have a height
-larger than a normal text line, a window who's size is calculated to
-exactly show some text, including 1 line for the mode-line, may be
-displayed with the last text line obscured by the mode-line.
-
-To work-around this problem, call `mode-line-window-height-fudge', and
-add the return value to the requested window size.]
-
-This is a kluge."
-  (if (display-graphic-p)
-      (or
-       ;; Return user-specified value
-       mode-line-window-height-fudge
-       ;; Try and detect whether mode-line face has any attributes that
-       ;; could make it bigger than a default text line, and return a
-       ;; fudge factor of 1 if so.
-       (let ((attrs height-affecting-face-attributes)
-            (fudge 0))
-        (while attrs
-          (let ((val (face-attribute (or face 'mode-line) (pop attrs))))
-            (unless (or (null val) (eq val 'unspecified))
-              (setq fudge 1 attrs nil))))
-        fudge))
-    0))
 
 \f
 (defun set-window-text-height (window height)
@@ -420,6 +416,7 @@ in some window."
 
 (defun fit-window-to-buffer (&optional window max-height min-height)
   "Make WINDOW the right size to display its contents exactly.
+If WINDOW is omitted or nil, it defaults to the selected window.
 If the optional argument MAX-HEIGHT is supplied, it is the maximum height
   the window is allowed to be, defaulting to the frame height.
 If the optional argument MIN-HEIGHT is supplied, it is the minimum
@@ -505,6 +502,7 @@ header-line."
 
 (defun shrink-window-if-larger-than-buffer (&optional window)
   "Shrink the WINDOW to be as small as possible to display its contents.
+If WINDOW is omitted or nil, it defaults to the selected window.
 Do not shrink to less than `window-min-height' lines.
 Do nothing if the buffer contains more lines than the present window height,
 or if some of the window's contents are scrolled out of view,
@@ -522,8 +520,13 @@ Return non-nil if the window was shrunk."
             (pos-visible-in-window-p (point-min) window)
             (not (eq mini 'only))
             (or (not mini)
-                (< (nth 3 edges) (nth 1 (window-edges mini)))
-                (> (nth 1 edges) (frame-parameter frame 'menu-bar-lines))))
+                (let ((mini-window (minibuffer-window frame)))
+                  (or (null mini-window)
+                      (not (eq frame (window-frame mini-window)))
+                      (< (nth 3 edges)
+                         (nth 1 (window-edges mini-window)))
+                      (> (nth 1 edges)
+                         (frame-parameter frame 'menu-bar-lines))))))
        (fit-window-to-buffer window (window-height window)))))
 
 (defun kill-buffer-and-window ()
@@ -582,6 +585,15 @@ and the buffer that is killed or buried is the one in that window."
     (and window (not window-handled) (not window-solitary)
         (delete-window window))))
 
+(defun handle-select-window (event)
+  "Handle select-window events."
+  (interactive "e")
+  (let ((window (posn-window (event-start event))))
+    (if (and (window-live-p window)
+            (or (not (window-minibuffer-p window))
+                (minibuffer-window-active-p window)))
+       (select-window window))))
+
 (define-key ctl-x-map "2" 'split-window-vertically)
 (define-key ctl-x-map "3" 'split-window-horizontally)
 (define-key ctl-x-map "}" 'enlarge-window-horizontally)
@@ -590,4 +602,5 @@ and the buffer that is killed or buried is the one in that window."
 (define-key ctl-x-map "+" 'balance-windows)
 (define-key ctl-x-4-map "0" 'kill-buffer-and-window)
 
+;;; arch-tag: b508dfcc-c353-4c37-89fa-e773fe10cea9
 ;;; window.el ends here