* config.sub: Recognize -proelf as a basic system type.
[bpt/emacs.git] / lisp / window.el
CommitLineData
12169754 1;;; window.el --- GNU Emacs window commands aside from those written in C.
d46bac56 2
b578f267 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
b578f267
EN
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22;; Boston, MA 02111-1307, USA.
a2535589 23
d46bac56 24;;; Code:
a2535589 25
82e6d8cb
RS
26;;;; Window tree functions.
27
28(defun one-window-p (&optional nomini all-frames)
29 "Returns non-nil if the selected window is the only window (in its frame).
30Optional arg NOMINI non-nil means don't count the minibuffer
31even if it is active.
32
33The optional arg ALL-FRAMES t means count windows on all frames.
34If it is `visible', count windows on all visible frames.
35ALL-FRAMES nil or omitted means count only the selected frame,
36plus the minibuffer it uses (which may be on another frame).
37If ALL-FRAMES is neither nil nor t, count only the selected frame."
38 (let ((base-window (selected-window)))
39 (if (and nomini (eq base-window (minibuffer-window)))
40 (setq base-window (next-window base-window)))
41 (eq base-window
42 (next-window base-window (if nomini 'arg) all-frames))))
43
44(defun walk-windows (proc &optional minibuf all-frames)
45 "Cycle through all visible windows, calling PROC for each one.
46PROC is called with a window as argument.
47
48Optional second arg MINIBUF t means count the minibuffer window even
49if not active. MINIBUF nil or omitted means count the minibuffer iff
50it is active. MINIBUF neither t nor nil means not to count the
51minibuffer even if it is active.
52
53Several frames may share a single minibuffer; if the minibuffer
54counts, all windows on all frames that share that minibuffer count
5aa29df8
RS
55too. Therefore, if you are using a separate minibuffer frame
56and the minibuffer is active and MINIBUF says it counts,
82e6d8cb 57`walk-windows' includes the windows in the frame from which you
5aa29df8 58entered the minibuffer, as well as the minibuffer window.
82e6d8cb 59
04ea572f
RS
60ALL-FRAMES is the optional third argument.
61ALL-FRAMES nil or omitted means cycle within the frames as specified above.
62ALL-FRAMES = `visible' means include windows on all visible frames.
82e6d8cb 63ALL-FRAMES = 0 means include windows on all visible and iconified frames.
04ea572f 64ALL-FRAMES = t means include windows on all frames including invisible frames.
c7d031ed 65Anything else means restrict to the selected frame."
82e6d8cb
RS
66 ;; If we start from the minibuffer window, don't fail to come back to it.
67 (if (window-minibuffer-p (selected-window))
68 (setq minibuf t))
69 (let* ((walk-windows-start (selected-window))
70 (walk-windows-current walk-windows-start))
71 (while (progn
72 (setq walk-windows-current
73 (next-window walk-windows-current minibuf all-frames))
74 (funcall proc walk-windows-current)
75 (not (eq walk-windows-current walk-windows-start))))))
76
77(defun minibuffer-window-active-p (window)
78 "Return t if WINDOW (a minibuffer window) is now active."
0d624ea4 79 (eq window (active-minibuffer-window)))
7f77f3c8
KH
80
81(defmacro save-selected-window (&rest body)
82 "Execute BODY, then select the window that was selected before BODY."
83 (list 'let
84 '((save-selected-window-window (selected-window)))
85 (list 'unwind-protect
86 (cons 'progn body)
87 (list 'select-window 'save-selected-window-window))))
82e6d8cb 88\f
a2535589
JA
89(defun count-windows (&optional minibuf)
90 "Returns the number of visible windows.
c6897d8e
KH
91Optional arg MINIBUF non-nil means count the minibuffer
92even if it is inactive."
a2535589 93 (let ((count 0))
12169754 94 (walk-windows (function (lambda (w)
a2535589
JA
95 (setq count (+ count 1))))
96 minibuf)
97 count))
98
99(defun balance-windows ()
7162c5c4 100 "Makes all visible windows the same height (approximately)."
a2535589 101 (interactive)
3ca9dd8d
RS
102 (let ((count -1) levels newsizes size
103 ;; Don't count the lines that are above the uppermost windows.
104 ;; (These are the menu bar lines, if any.)
105 (mbl (nth 1 (window-edges (frame-first-window (selected-frame))))))
7162c5c4
RS
106 ;; Find all the different vpos's at which windows start,
107 ;; then count them. But ignore levels that differ by only 1.
108 (save-window-excursion
109 (let (tops (prev-top -2))
110 (walk-windows (function (lambda (w)
111 (setq tops (cons (nth 1 (window-edges w))
112 tops))))
113 'nomini)
114 (setq tops (sort tops '<))
115 (while tops
116 (if (> (car tops) (1+ prev-top))
117 (setq prev-top (car tops)
118 count (1+ count)))
119 (setq levels (cons (cons (car tops) count) levels))
120 (setq tops (cdr tops)))
121 (setq count (1+ count))))
122 ;; Subdivide the frame into that many vertical levels.
3ca9dd8d 123 (setq size (/ (- (frame-height) mbl) count))
7162c5c4
RS
124 (walk-windows (function
125 (lambda (w)
126 (select-window w)
127 (let ((newtop (cdr (assq (nth 1 (window-edges))
128 levels)))
129 (newbot (or (cdr (assq (+ (window-height)
130 (nth 1 (window-edges)))
131 levels))
132 count)))
133 (setq newsizes
134 (cons (cons w (* size (- newbot newtop)))
ce27e1b0
RS
135 newsizes)))))
136 'nomini)
a2535589 137 (walk-windows (function (lambda (w)
7162c5c4
RS
138 (select-window w)
139 (let ((newsize (cdr (assq w newsizes))))
140 (enlarge-window (- newsize
141 (window-height))))))
142 'nomini)))
82e6d8cb 143\f
69037c38 144;;; I think this should be the default; I think people will prefer it--rms.
69037c38 145(defvar split-window-keep-point t
7162c5c4
RS
146 "*If non-nil, split windows keeps the original point in both children.
147This is often more convenient for editing.
148If nil, adjust point in each of the two windows to minimize redisplay.
149This is convenient on slow terminals, but point can move strangely.")
8e4b71d8 150
a2535589
JA
151(defun split-window-vertically (&optional arg)
152 "Split current window into two windows, one above the other.
c65c1681 153The uppermost window gets ARG lines and the other gets the rest.
ab94bf9f 154Negative arg means select the size of the lowermost window instead.
c65c1681
RS
155With no argument, split equally or close to it.
156Both windows display the same buffer now current.
c65c1681 157
8e4b71d8
JB
158If the variable split-window-keep-point is non-nil, both new windows
159will get the same value of point as the current window. This is often
160more convenient for editing.
161
162Otherwise, we chose window starts so as to minimize the amount of
163redisplay; this is convenient on slow terminals. The new selected
164window is the one that the current value of point appears in. The
165value of point can change if the text around point is hidden by the
166new mode line."
a2535589
JA
167 (interactive "P")
168 (let ((old-w (selected-window))
c65c1681 169 (old-point (point))
ab94bf9f 170 (size (and arg (prefix-numeric-value arg)))
4464514e
RS
171 (window-full-p nil)
172 new-w bottom switch moved)
ab94bf9f
KH
173 (and size (< size 0) (setq size (+ (window-height) size)))
174 (setq new-w (split-window nil size))
7d7f1f33 175 (or split-window-keep-point
c65c1681 176 (progn
8e4b71d8
JB
177 (save-excursion
178 (set-buffer (window-buffer))
179 (goto-char (window-start))
4464514e 180 (setq moved (vertical-motion (window-height)))
8e4b71d8
JB
181 (set-window-start new-w (point))
182 (if (> (point) (window-point new-w))
183 (set-window-point new-w (point)))
4464514e
RS
184 (and (= moved (window-height))
185 (progn
186 (setq window-full-p t)
187 (vertical-motion -1)))
188 (setq bottom (point)))
189 (and window-full-p
190 (<= bottom (point))
191 (set-window-point old-w (1- bottom)))
192 (and window-full-p
193 (<= (window-start new-w) old-point)
194 (progn
195 (set-window-point new-w old-point)
196 (select-window new-w)))))
2ed3f64c 197 new-w))
a2535589
JA
198
199(defun split-window-horizontally (&optional arg)
200 "Split current window into two windows side by side.
0ef2c2f2
KH
201This window becomes the leftmost of the two, and gets ARG columns.
202Negative arg means select the size of the rightmost window instead.
203No arg means split equally."
a2535589 204 (interactive "P")
0ef2c2f2
KH
205 (let ((size (and arg (prefix-numeric-value arg))))
206 (and size (< size 0)
207 (setq size (+ (window-width) size)))
208 (split-window nil size t)))
82e6d8cb 209\f
a2535589
JA
210(defun enlarge-window-horizontally (arg)
211 "Make current window ARG columns wider."
212 (interactive "p")
213 (enlarge-window arg t))
214
215(defun shrink-window-horizontally (arg)
216 "Make current window ARG columns narrower."
217 (interactive "p")
218 (shrink-window arg t))
219
a0900d9f 220(defun shrink-window-if-larger-than-buffer (&optional window)
d0bee390 221 "Shrink the WINDOW to be as small as possible to display its contents.
30f2e5cc 222Do not shrink to less than `window-min-height' lines.
d0bee390 223Do nothing if the buffer contains more lines than the present window height,
3eb217a0 224or if some of the window's contents are scrolled out of view,
1de8d93d 225or if the window is not the full width of the frame,
3eb217a0 226or if the window is the only window of its frame."
d0bee390 227 (interactive)
cf1b1bf8 228 (or window (setq window (selected-window)))
a0900d9f
ER
229 (save-excursion
230 (set-buffer (window-buffer window))
cf1b1bf8
RS
231 (let* ((w (selected-window)) ;save-window-excursion can't win
232 (buffer-file-name buffer-file-name)
233 (p (point))
234 (n 0)
235 (ignore-final-newline
236 ;; If buffer ends with a newline, ignore it when counting height
237 ;; unless point is after it.
238 (and (not (eobp))
239 (eq ?\n (char-after (1- (point-max))))))
240 (buffer-read-only nil)
241 (modified (buffer-modified-p))
242 (buffer (current-buffer))
243 (params (frame-parameters (window-frame window)))
244 (mini (cdr (assq 'minibuffer params)))
245 (edges (window-edges (selected-window))))
246 (if (and (< 1 (let ((frame (selected-frame)))
247 (select-frame (window-frame window))
248 (unwind-protect
249 (count-windows)
250 (select-frame frame))))
251 (= (window-width window) (frame-width (window-frame window)))
5e2ec73e 252 (pos-visible-in-window-p (point-min) window)
c09603e9 253 (not (eq mini 'only))
5e2ec73e
KH
254 (or (not mini)
255 (< (nth 3 edges)
256 (nth 1 (window-edges mini)))
257 (> (nth 1 edges)
cf1b1bf8 258 (cdr (assq 'menu-bar-lines params)))))
d0bee390
RS
259 (unwind-protect
260 (progn
261 (select-window (or window w))
262 (goto-char (point-min))
3eb217a0
RS
263 (while (pos-visible-in-window-p
264 (- (point-max)
265 (if ignore-final-newline 1 0)))
d0bee390
RS
266 ;; defeat file locking... don't try this at home, kids!
267 (setq buffer-file-name nil)
268 (insert ?\n) (setq n (1+ n)))
e90fc792
RS
269 (if (> n 0)
270 (shrink-window (min (1- n)
271 (- (window-height)
272 window-min-height)))))
d0bee390
RS
273 (delete-region (point-min) (point))
274 (set-buffer-modified-p modified)
275 (goto-char p)
276 (select-window w)
277 ;; Make sure we unbind buffer-read-only
278 ;; with the proper current buffer.
279 (set-buffer buffer))))))
a0900d9f 280
a2535589 281(define-key ctl-x-map "2" 'split-window-vertically)
492878e4 282(define-key ctl-x-map "3" 'split-window-horizontally)
a2535589
JA
283(define-key ctl-x-map "}" 'enlarge-window-horizontally)
284(define-key ctl-x-map "{" 'shrink-window-horizontally)
a0900d9f
ER
285(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
286(define-key ctl-x-map "+" 'balance-windows)
76d7458e
ER
287
288;;; windows.el ends here