;;; window.el --- GNU Emacs window commands aside from those written in C
-;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001
+;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Maintainer: FSF
;;; Code:
+(defmacro save-selected-window (&rest body)
+ "Execute BODY, then select the window that was selected before BODY.
+However, if that window has become dead, don't get an error,
+just refrain from switching to it."
+ `(let ((save-selected-window-window (selected-window)))
+ (unwind-protect
+ (progn ,@body)
+ (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
(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.
(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.
(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)
(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)