Major rewrite to behave more like a minor mode.
[bpt/emacs.git] / lisp / window.el
CommitLineData
12169754 1;;; window.el --- GNU Emacs window commands aside from those written in C.
d46bac56 2
8f1204db 3;;; Copyright (C) 1985, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
a2535589 4
58142744
ER
5;; Maintainer: FSF
6
a2535589
JA
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
492878e4 11;; the Free Software Foundation; either version 2, or (at your option)
a2535589
JA
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to
21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
d46bac56 23;;; Code:
a2535589
JA
24
25(defun count-windows (&optional minibuf)
26 "Returns the number of visible windows.
27Optional arg NO-MINI non-nil means don't count the minibuffer
28even if it is active."
29 (let ((count 0))
12169754 30 (walk-windows (function (lambda (w)
a2535589
JA
31 (setq count (+ count 1))))
32 minibuf)
33 count))
34
35(defun balance-windows ()
7162c5c4 36 "Makes all visible windows the same height (approximately)."
a2535589 37 (interactive)
7162c5c4
RS
38 (let ((count -1) levels newsizes size)
39 ;; Find all the different vpos's at which windows start,
40 ;; then count them. But ignore levels that differ by only 1.
41 (save-window-excursion
42 (let (tops (prev-top -2))
43 (walk-windows (function (lambda (w)
44 (setq tops (cons (nth 1 (window-edges w))
45 tops))))
46 'nomini)
47 (setq tops (sort tops '<))
48 (while tops
49 (if (> (car tops) (1+ prev-top))
50 (setq prev-top (car tops)
51 count (1+ count)))
52 (setq levels (cons (cons (car tops) count) levels))
53 (setq tops (cdr tops)))
54 (setq count (1+ count))))
55 ;; Subdivide the frame into that many vertical levels.
56 (setq size (/ (frame-height) count))
57 (walk-windows (function
58 (lambda (w)
59 (select-window w)
60 (let ((newtop (cdr (assq (nth 1 (window-edges))
61 levels)))
62 (newbot (or (cdr (assq (+ (window-height)
63 (nth 1 (window-edges)))
64 levels))
65 count)))
66 (setq newsizes
67 (cons (cons w (* size (- newbot newtop)))
68 newsizes))))))
a2535589 69 (walk-windows (function (lambda (w)
7162c5c4
RS
70 (select-window w)
71 (let ((newsize (cdr (assq w newsizes))))
72 (enlarge-window (- newsize
73 (window-height))))))
74 'nomini)))
a2535589 75
69037c38 76;;; I think this should be the default; I think people will prefer it--rms.
69037c38 77(defvar split-window-keep-point t
7162c5c4
RS
78 "*If non-nil, split windows keeps the original point in both children.
79This is often more convenient for editing.
80If nil, adjust point in each of the two windows to minimize redisplay.
81This is convenient on slow terminals, but point can move strangely.")
8e4b71d8 82
a2535589
JA
83(defun split-window-vertically (&optional arg)
84 "Split current window into two windows, one above the other.
c65c1681 85The uppermost window gets ARG lines and the other gets the rest.
ab94bf9f 86Negative arg means select the size of the lowermost window instead.
c65c1681
RS
87With no argument, split equally or close to it.
88Both windows display the same buffer now current.
c65c1681 89
8e4b71d8
JB
90If the variable split-window-keep-point is non-nil, both new windows
91will get the same value of point as the current window. This is often
92more convenient for editing.
93
94Otherwise, we chose window starts so as to minimize the amount of
95redisplay; this is convenient on slow terminals. The new selected
96window is the one that the current value of point appears in. The
97value of point can change if the text around point is hidden by the
98new mode line."
a2535589
JA
99 (interactive "P")
100 (let ((old-w (selected-window))
c65c1681 101 (old-point (point))
ab94bf9f 102 (size (and arg (prefix-numeric-value arg)))
c65c1681 103 new-w bottom switch)
ab94bf9f
KH
104 (and size (< size 0) (setq size (+ (window-height) size)))
105 (setq new-w (split-window nil size))
7d7f1f33 106 (or split-window-keep-point
c65c1681 107 (progn
8e4b71d8
JB
108 (save-excursion
109 (set-buffer (window-buffer))
110 (goto-char (window-start))
111 (vertical-motion (window-height))
112 (set-window-start new-w (point))
113 (if (> (point) (window-point new-w))
114 (set-window-point new-w (point)))
115 (vertical-motion -1)
116 (setq bottom (point)))
117 (if (<= bottom (point))
118 (set-window-point old-w (1- bottom)))
119 (if (< (window-start new-w) old-point)
120 (progn
121 (set-window-point new-w old-point)
2ed3f64c
RS
122 (select-window new-w)))))
123 new-w))
a2535589
JA
124
125(defun split-window-horizontally (&optional arg)
126 "Split current window into two windows side by side.
0ef2c2f2
KH
127This window becomes the leftmost of the two, and gets ARG columns.
128Negative arg means select the size of the rightmost window instead.
129No arg means split equally."
a2535589 130 (interactive "P")
0ef2c2f2
KH
131 (let ((size (and arg (prefix-numeric-value arg))))
132 (and size (< size 0)
133 (setq size (+ (window-width) size)))
134 (split-window nil size t)))
a2535589
JA
135
136(defun enlarge-window-horizontally (arg)
137 "Make current window ARG columns wider."
138 (interactive "p")
139 (enlarge-window arg t))
140
141(defun shrink-window-horizontally (arg)
142 "Make current window ARG columns narrower."
143 (interactive "p")
144 (shrink-window arg t))
145
a0900d9f 146(defun shrink-window-if-larger-than-buffer (&optional window)
d0bee390 147 "Shrink the WINDOW to be as small as possible to display its contents.
30f2e5cc 148Do not shrink to less than `window-min-height' lines.
d0bee390 149Do nothing if the buffer contains more lines than the present window height,
3eb217a0 150or if some of the window's contents are scrolled out of view,
1de8d93d 151or if the window is not the full width of the frame,
3eb217a0 152or if the window is the only window of its frame."
d0bee390 153 (interactive)
a0900d9f
ER
154 (save-excursion
155 (set-buffer (window-buffer window))
156 (let ((w (selected-window)) ;save-window-excursion can't win
157 (buffer-file-name buffer-file-name)
158 (p (point))
159 (n 0)
3eb217a0
RS
160 (ignore-final-newline
161 ;; If buffer ends with a newline, ignore it when counting height
162 ;; unless point is after it.
163 (and (not (eobp))
164 (eq ?\n (char-after (1- (point-max))))))
a0900d9f
ER
165 (buffer-read-only nil)
166 (modified (buffer-modified-p))
5e2ec73e
KH
167 (buffer (current-buffer))
168 (mini (cdr (assq 'minibuffer (frame-parameters))))
169 (edges (window-edges (selected-window))))
3eb217a0 170 (if (and (< 1 (count-windows))
ad656bdc 171 (= (window-width) (frame-width))
5e2ec73e 172 (pos-visible-in-window-p (point-min) window)
c09603e9 173 (not (eq mini 'only))
5e2ec73e
KH
174 (or (not mini)
175 (< (nth 3 edges)
176 (nth 1 (window-edges mini)))
177 (> (nth 1 edges)
178 (cdr (assq 'menu-bar-lines (frame-parameters))))))
d0bee390
RS
179 (unwind-protect
180 (progn
181 (select-window (or window w))
182 (goto-char (point-min))
3eb217a0
RS
183 (while (pos-visible-in-window-p
184 (- (point-max)
185 (if ignore-final-newline 1 0)))
d0bee390
RS
186 ;; defeat file locking... don't try this at home, kids!
187 (setq buffer-file-name nil)
188 (insert ?\n) (setq n (1+ n)))
e90fc792
RS
189 (if (> n 0)
190 (shrink-window (min (1- n)
191 (- (window-height)
192 window-min-height)))))
d0bee390
RS
193 (delete-region (point-min) (point))
194 (set-buffer-modified-p modified)
195 (goto-char p)
196 (select-window w)
197 ;; Make sure we unbind buffer-read-only
198 ;; with the proper current buffer.
199 (set-buffer buffer))))))
a0900d9f 200
a2535589 201(define-key ctl-x-map "2" 'split-window-vertically)
492878e4 202(define-key ctl-x-map "3" 'split-window-horizontally)
a2535589
JA
203(define-key ctl-x-map "}" 'enlarge-window-horizontally)
204(define-key ctl-x-map "{" 'shrink-window-horizontally)
a0900d9f
ER
205(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
206(define-key ctl-x-map "+" 'balance-windows)
76d7458e
ER
207
208;;; windows.el ends here