(read_minibuf): New arg disable_multibyte.
[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.
30e19aee 145(defcustom 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.
30e19aee
RS
149This is convenient on slow terminals, but point can move strangely."
150 :type 'boolean
151 :group 'windows)
8e4b71d8 152
a2535589
JA
153(defun split-window-vertically (&optional arg)
154 "Split current window into two windows, one above the other.
c65c1681 155The uppermost window gets ARG lines and the other gets the rest.
ab94bf9f 156Negative arg means select the size of the lowermost window instead.
c65c1681
RS
157With no argument, split equally or close to it.
158Both windows display the same buffer now current.
c65c1681 159
8e4b71d8
JB
160If the variable split-window-keep-point is non-nil, both new windows
161will get the same value of point as the current window. This is often
162more convenient for editing.
163
164Otherwise, we chose window starts so as to minimize the amount of
165redisplay; this is convenient on slow terminals. The new selected
166window is the one that the current value of point appears in. The
167value of point can change if the text around point is hidden by the
168new mode line."
a2535589
JA
169 (interactive "P")
170 (let ((old-w (selected-window))
c65c1681 171 (old-point (point))
ab94bf9f 172 (size (and arg (prefix-numeric-value arg)))
4464514e
RS
173 (window-full-p nil)
174 new-w bottom switch moved)
ab94bf9f
KH
175 (and size (< size 0) (setq size (+ (window-height) size)))
176 (setq new-w (split-window nil size))
7d7f1f33 177 (or split-window-keep-point
c65c1681 178 (progn
8e4b71d8
JB
179 (save-excursion
180 (set-buffer (window-buffer))
181 (goto-char (window-start))
4464514e 182 (setq moved (vertical-motion (window-height)))
8e4b71d8
JB
183 (set-window-start new-w (point))
184 (if (> (point) (window-point new-w))
185 (set-window-point new-w (point)))
4464514e
RS
186 (and (= moved (window-height))
187 (progn
188 (setq window-full-p t)
189 (vertical-motion -1)))
190 (setq bottom (point)))
191 (and window-full-p
192 (<= bottom (point))
193 (set-window-point old-w (1- bottom)))
194 (and window-full-p
195 (<= (window-start new-w) old-point)
196 (progn
197 (set-window-point new-w old-point)
198 (select-window new-w)))))
c361280d
RS
199 (split-window-save-restore-data new-w old-w)))
200
201(defun split-window-save-restore-data (new-w old-w)
202 (save-excursion
203 (set-buffer (window-buffer))
204 (if view-mode
205 (let ((old-info (assq old-w view-return-to-alist)))
206 (setq view-return-to-alist
207 (cons (cons new-w (cons (and old-info (car (cdr old-info))) t))
208 view-return-to-alist))))
2ed3f64c 209 new-w))
a2535589
JA
210
211(defun split-window-horizontally (&optional arg)
212 "Split current window into two windows side by side.
0ef2c2f2
KH
213This window becomes the leftmost of the two, and gets ARG columns.
214Negative arg means select the size of the rightmost window instead.
215No arg means split equally."
a2535589 216 (interactive "P")
c361280d
RS
217 (let ((old-w (selected-window))
218 (size (and arg (prefix-numeric-value arg))))
0ef2c2f2
KH
219 (and size (< size 0)
220 (setq size (+ (window-width) size)))
c361280d 221 (split-window-save-restore-data (split-window nil size t) old-w)))
82e6d8cb 222\f
a2535589
JA
223(defun enlarge-window-horizontally (arg)
224 "Make current window ARG columns wider."
225 (interactive "p")
226 (enlarge-window arg t))
227
228(defun shrink-window-horizontally (arg)
229 "Make current window ARG columns narrower."
230 (interactive "p")
231 (shrink-window arg t))
232
a0900d9f 233(defun shrink-window-if-larger-than-buffer (&optional window)
d0bee390 234 "Shrink the WINDOW to be as small as possible to display its contents.
30f2e5cc 235Do not shrink to less than `window-min-height' lines.
d0bee390 236Do nothing if the buffer contains more lines than the present window height,
3eb217a0 237or if some of the window's contents are scrolled out of view,
1de8d93d 238or if the window is not the full width of the frame,
3eb217a0 239or if the window is the only window of its frame."
d0bee390 240 (interactive)
cf1b1bf8 241 (or window (setq window (selected-window)))
93289e14
RS
242 (let* ((ignore-final-newline
243 ;; If buffer ends with a newline, ignore it when counting height
244 ;; unless point is after it.
245 (and (not (eobp))
246 (eq ?\n (char-after (1- (point-max))))))
247 (params (frame-parameters (window-frame window)))
248 (mini (cdr (assq 'minibuffer params)))
249 (edges (window-edges (selected-window))))
250 (if (and (< 1 (save-selected-window
251 (select-window window)
252 (count-windows)))
253 (= (window-width window) (frame-width (window-frame window)))
254 (pos-visible-in-window-p (point-min) window)
255 (not (eq mini 'only))
256 (or (not mini)
257 (< (nth 3 edges)
258 (nth 1 (window-edges mini)))
259 (> (nth 1 edges)
260 (cdr (assq 'menu-bar-lines params)))))
261 (save-selected-window
262 (select-window window)
263 (let (result height)
264 (save-excursion
265 (set-buffer (window-buffer window))
266 (goto-char (point-min))
267 (setq result
268 (compute-motion (point-min) '(0 . 0)
269 (- (point-max)
270 (if ignore-final-newline 1 0))
271 (cons 0 (window-height))
272 (window-width) nil
273 window))
274 ;; Get number of screen lines that the text needs.
275 (setq text-height (+ 1 (nth 2 result)))
276 ;; Shrink down to that, or as far as we can go.
277 (if (> (window-height) (1+ text-height))
278 (shrink-window (- (window-height)
279 (max (1+ text-height) window-min-height))))))))))
b691df0c
RS
280
281(defun kill-buffer-and-window ()
282 "Kill the current buffer and delete the selected window."
283 (interactive)
284 (if (yes-or-no-p (format "Kill buffer `%s'? " (buffer-name)))
285 (let ((buffer (current-buffer)))
286 (delete-window (selected-window))
287 (kill-buffer buffer))
288 (error "Aborted")))
289
a2535589 290(define-key ctl-x-map "2" 'split-window-vertically)
492878e4 291(define-key ctl-x-map "3" 'split-window-horizontally)
a2535589
JA
292(define-key ctl-x-map "}" 'enlarge-window-horizontally)
293(define-key ctl-x-map "{" 'shrink-window-horizontally)
a0900d9f
ER
294(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
295(define-key ctl-x-map "+" 'balance-windows)
b691df0c 296(define-key ctl-x-4-map "0" 'kill-buffer-and-window)
76d7458e
ER
297
298;;; windows.el ends here