(bcopy) Use memmove instead of memcpy.
[bpt/emacs.git] / lisp / window.el
index 5101fa0..5f60dd7 100644 (file)
@@ -1,12 +1,14 @@
-;;; windows.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 Free Software Foundation, Inc.
+;;; Copyright (C) 1985, 1989, 1992, 1993 Free Software Foundation, Inc.
+
+;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Code:
 
 (defun count-windows (&optional minibuf)
    "Returns the number of visible windows.
 Optional arg NO-MINI non-nil means don't count the minibuffer
 even if it is active."
    (let ((count 0))
-     (walk-windows (function (lambda ()
+     (walk-windows (function (lambda (w)
                               (setq count (+ count 1))))
                   minibuf)
      count))
 
 (defun balance-windows ()
-  "Makes all visible windows the same size (approximately)."
+  "Makes all visible windows the same height (approximately)."
   (interactive)
-  (let ((count 0))
+  (let ((count -1) levels newsizes size)
+    ;; 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) 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))))))
     (walk-windows (function (lambda (w)
-                             (setq count (+ count 1))))
-                 'nomini)
-    (let ((size (/ (screen-height) count)))
-      (walk-windows (function (lambda (w)
-                               (select-window w)
-                               (enlarge-window (- size (window-height)))))
-                   'nomini))))
-
-;;; Many people find the minimal-redisplay window splitting annoying,
-;;; so we make it an option. 
-
-(defvar split-window-keep-point nil
-  "*If non-nil, split windows so that both windows keep the original
-value of point.  This is often more convenient for editing.
-If nil, split windows to minimize redisplay.  This is convenient on
-slow terminals, but point may be moved strangely to accommodate the
-redisplay.")
+                             (select-window w)
+                             (let ((newsize (cdr (assq w newsizes))))
+                               (enlarge-window (- newsize
+                                                  (window-height))))))
+                 'nomini)))
+
+;;; I think this should be the default; I think people will prefer it--rms.
+(defvar split-window-keep-point t
+  "*If non-nil, split windows keeps the original point in both children.
+This is often more convenient for editing.
+If nil, adjust point in each of the two windows to minimize redisplay.
+This is convenient on slow terminals, but point can move strangely.")
 
 (defun split-window-vertically (&optional arg)
   "Split current window into two windows, one above the other.
@@ -88,7 +116,8 @@ new mode line."
          (if (< (window-start new-w) old-point)
              (progn
                (set-window-point new-w old-point)
-               (select-window new-w)))))))
+               (select-window new-w)))))
+    new-w))
 
 (defun split-window-horizontally (&optional arg)
   "Split current window into two windows side by side.
@@ -107,23 +136,53 @@ ARG columns.  No arg means split equally."
   (interactive "p")
   (shrink-window arg t))
 
-(defun window-config-to-register (name)
-  "Save the current window configuration in register REG (a letter).
-It can be later retrieved using \\[M-x register-to-window-config]."
-  (interactive "cSave window configuration in register: ")
-  (set-register name (current-window-configuration)))
-
-(defun register-to-window-config (name)
-  "Restore (make current) the window configuration in register REG (a letter).
-Use with a register previously set with \\[window-config-to-register]."
-  (interactive "cRestore window configuration from register: ")
-  (set-window-configuration (get-register name)))
-
+(defun shrink-window-if-larger-than-buffer (&optional window)
+  "Shrink the WINDOW to be as small as possible to display its contents.
+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,
+or if the window is the only window of its frame."
+  (interactive)
+  (save-excursion
+    (set-buffer (window-buffer window))
+    (let ((w (selected-window)) ;save-window-excursion can't win
+         (buffer-file-name buffer-file-name)
+         (p (point))
+         (n 0)
+         (ignore-final-newline
+          ;; If buffer ends with a newline, ignore it when counting height
+          ;; unless point is after it.
+          (and (not (eobp))
+               (eq ?\n (char-after (1- (point-max))))))
+         (window-min-height 0)
+         (buffer-read-only nil)
+         (modified (buffer-modified-p))
+         (buffer (current-buffer)))
+      (if (and (< 1 (count-windows))
+              (pos-visible-in-window-p (point-min) window))
+         (unwind-protect
+             (progn
+               (select-window (or window w))
+               (goto-char (point-min))
+               (while (pos-visible-in-window-p
+                       (- (point-max)
+                          (if ignore-final-newline 1 0)))
+                 ;; defeat file locking... don't try this at home, kids!
+                 (setq buffer-file-name nil)
+                 (insert ?\n) (setq n (1+ n)))
+               (if (> n 0) (shrink-window (1- n))))
+           (delete-region (point-min) (point))
+           (set-buffer-modified-p modified)
+           (goto-char p)
+           (select-window w)
+           ;; Make sure we unbind buffer-read-only
+           ;; with the proper current buffer.
+           (set-buffer buffer))))))
+      
 (define-key ctl-x-map "2" 'split-window-vertically)
-(define-key ctl-x-map "5" 'split-window-horizontally)
-(define-key ctl-x-map "6" 'window-config-to-register)
-(define-key ctl-x-map "7" 'register-to-window-config)
+(define-key ctl-x-map "3" 'split-window-horizontally)
 (define-key ctl-x-map "}" 'enlarge-window-horizontally)
 (define-key ctl-x-map "{" 'shrink-window-horizontally)
+(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
+(define-key ctl-x-map "+" 'balance-windows)
 
 ;;; windows.el ends here