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