message format spec fixes (commit # 7)
[bpt/emacs.git] / lisp / window.el
CommitLineData
55535639 1;;; window.el --- GNU Emacs window commands aside from those written in C
d46bac56 2
0d30b337
TTN
3;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001, 2002,
4;; 2003, 2004, 2005 Free Software Foundation, Inc.
a2535589 5
58142744 6;; Maintainer: FSF
284b3043 7;; Keywords: internal
58142744 8
a2535589
JA
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
492878e4 13;; the Free Software Foundation; either version 2, or (at your option)
a2535589
JA
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b578f267 22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
a2535589 25
fe7a0e7d
SM
26;;; Commentary:
27
28;; Window tree functions.
29
30;;; Code:
82e6d8cb 31
64da8b20
RS
32(defvar window-size-fixed nil
33 "*Non-nil in a buffer means windows displaying the buffer are fixed-size.
9fa87e0d 34If the value is `height', then only the window's height is fixed.
64da8b20
RS
35If the value is `width', then only the window's width is fixed.
36Any other non-nil value fixes both the width and the height.
37Emacs won't change the size of any window displaying that buffer,
38unless you explicitly change the size, or Emacs has no other choice.")
39(make-variable-buffer-local 'window-size-fixed)
40
471af22c
AS
41(defmacro save-selected-window (&rest body)
42 "Execute BODY, then select the window that was selected before BODY.
7db3c58f
RS
43The value returned is the value of the last form in BODY.
44
45This macro saves and restores the current buffer, since otherwise
46its normal operation could potentially make a different
198081c8 47buffer current. It does not alter the buffer list ordering.
7db3c58f
RS
48
49This macro saves and restores the selected window, as well as
50the selected window in each frame. If the previously selected
51window of some frame is no longer live at the end of BODY, that
52frame's selected window is left alone. If the selected window is
53no longer live, then whatever window is selected at the end of
54BODY remains selected."
991ce473 55 `(let ((save-selected-window-window (selected-window))
1c795a0e
RS
56 ;; It is necessary to save all of these, because calling
57 ;; select-window changes frame-selected-window for whatever
58 ;; frame that window is in.
991ce473
RS
59 (save-selected-window-alist
60 (mapcar (lambda (frame) (list frame (frame-selected-window frame)))
61 (frame-list))))
7db3c58f
RS
62 (save-current-buffer
63 (unwind-protect
64 (progn ,@body)
65 (dolist (elt save-selected-window-alist)
66 (and (frame-live-p (car elt))
67 (window-live-p (cadr elt))
68 (set-frame-selected-window (car elt) (cadr elt))))
69 (if (window-live-p save-selected-window-window)
70 (select-window save-selected-window-window))))))
471af22c 71
e58bff59
RS
72(defun window-body-height (&optional window)
73 "Return number of lines in window WINDOW for actual buffer text.
74This does not include the mode line (if any) or the header line (if any)."
75 (or window (setq window (selected-window)))
9df6e638
RS
76 (if (window-minibuffer-p window)
77 (window-height window)
78 (with-current-buffer (window-buffer window)
79 (max 1 (- (window-height window)
80 (if mode-line-format 1 0)
81 (if header-line-format 1 0))))))
e58bff59 82
82e6d8cb 83(defun one-window-p (&optional nomini all-frames)
90dc1922 84 "Return non-nil if the selected window is the only window.
82e6d8cb 85Optional arg NOMINI non-nil means don't count the minibuffer
90dc1922
LT
86even if it is active. Otherwise, the minibuffer is counted
87when it is active.
82e6d8cb
RS
88
89The optional arg ALL-FRAMES t means count windows on all frames.
90If it is `visible', count windows on all visible frames.
fe7a0e7d 91ALL-FRAMES nil or omitted means count only the selected frame,
82e6d8cb 92plus the minibuffer it uses (which may be on another frame).
90dc1922
LT
93ALL-FRAMES 0 means count all windows in all visible or iconified frames.
94If ALL-FRAMES is anything else, count only the selected frame."
82e6d8cb
RS
95 (let ((base-window (selected-window)))
96 (if (and nomini (eq base-window (minibuffer-window)))
97 (setq base-window (next-window base-window)))
98 (eq base-window
99 (next-window base-window (if nomini 'arg) all-frames))))
100
22f9c48c
KS
101(defun window-current-scroll-bars (&optional window)
102 "Return the current scroll-bar settings in window WINDOW.
c62195fa 103Value is a cons (VERTICAL . HORIZONTAL) where VERTICAL specifies the
22f9c48c 104current location of the vertical scroll-bars (left, right, or nil),
c62195fa 105and HORIZONTAL specifies the current location of the horizontal scroll
22f9c48c
KS
106bars (top, bottom, or nil)."
107 (let ((vert (nth 2 (window-scroll-bars window)))
108 (hor nil))
109 (when (or (eq vert t) (eq hor t))
90dc1922 110 (let ((fcsb (frame-current-scroll-bars
22f9c48c
KS
111 (window-frame (or window (selected-window))))))
112 (if (eq vert t)
113 (setq vert (car fcsb)))
114 (if (eq hor t)
115 (setq hor (cdr fcsb)))))
116 (cons vert hor)))
117
82e6d8cb
RS
118(defun walk-windows (proc &optional minibuf all-frames)
119 "Cycle through all visible windows, calling PROC for each one.
120PROC is called with a window as argument.
121
122Optional second arg MINIBUF t means count the minibuffer window even
123if not active. MINIBUF nil or omitted means count the minibuffer iff
124it is active. MINIBUF neither t nor nil means not to count the
125minibuffer even if it is active.
126
127Several frames may share a single minibuffer; if the minibuffer
128counts, all windows on all frames that share that minibuffer count
5aa29df8
RS
129too. Therefore, if you are using a separate minibuffer frame
130and the minibuffer is active and MINIBUF says it counts,
82e6d8cb 131`walk-windows' includes the windows in the frame from which you
5aa29df8 132entered the minibuffer, as well as the minibuffer window.
82e6d8cb 133
04ea572f
RS
134ALL-FRAMES is the optional third argument.
135ALL-FRAMES nil or omitted means cycle within the frames as specified above.
136ALL-FRAMES = `visible' means include windows on all visible frames.
82e6d8cb 137ALL-FRAMES = 0 means include windows on all visible and iconified frames.
04ea572f 138ALL-FRAMES = t means include windows on all frames including invisible frames.
aeb721fe 139If ALL-FRAMES is a frame, it means include windows on that frame.
c7d031ed 140Anything else means restrict to the selected frame."
82e6d8cb
RS
141 ;; If we start from the minibuffer window, don't fail to come back to it.
142 (if (window-minibuffer-p (selected-window))
143 (setq minibuf t))
aeb721fe
GM
144 (save-selected-window
145 (if (framep all-frames)
146 (select-window (frame-first-window all-frames)))
d4aff7cc
GM
147 (let* (walk-windows-already-seen
148 (walk-windows-current (selected-window)))
aeb721fe
GM
149 (while (progn
150 (setq walk-windows-current
151 (next-window walk-windows-current minibuf all-frames))
d4aff7cc
GM
152 (not (memq walk-windows-current walk-windows-already-seen)))
153 (setq walk-windows-already-seen
154 (cons walk-windows-current walk-windows-already-seen))
155 (funcall proc walk-windows-current)))))
156
d4d986f2
GM
157(defun get-window-with-predicate (predicate &optional minibuf
158 all-frames default)
d4aff7cc
GM
159 "Return a window satisfying PREDICATE.
160
161This function cycles through all visible windows using `walk-windows',
162calling PREDICATE on each one. PREDICATE is called with a window as
163argument. The first window for which PREDICATE returns a non-nil
164value is returned. If no window satisfies PREDICATE, DEFAULT is
165returned.
166
167Optional second arg MINIBUF t means count the minibuffer window even
168if not active. MINIBUF nil or omitted means count the minibuffer iff
169it is active. MINIBUF neither t nor nil means not to count the
170minibuffer even if it is active.
171
172Several frames may share a single minibuffer; if the minibuffer
173counts, all windows on all frames that share that minibuffer count
174too. Therefore, if you are using a separate minibuffer frame
175and the minibuffer is active and MINIBUF says it counts,
176`walk-windows' includes the windows in the frame from which you
177entered the minibuffer, as well as the minibuffer window.
178
179ALL-FRAMES is the optional third argument.
180ALL-FRAMES nil or omitted means cycle within the frames as specified above.
181ALL-FRAMES = `visible' means include windows on all visible frames.
182ALL-FRAMES = 0 means include windows on all visible and iconified frames.
183ALL-FRAMES = t means include windows on all frames including invisible frames.
184If ALL-FRAMES is a frame, it means include windows on that frame.
185Anything else means restrict to the selected frame."
186 (catch 'found
fe7a0e7d 187 (walk-windows #'(lambda (window)
d4aff7cc
GM
188 (when (funcall predicate window)
189 (throw 'found window)))
190 minibuf all-frames)
191 default))
82e6d8cb 192
d4d986f2
GM
193(defalias 'some-window 'get-window-with-predicate)
194
82e6d8cb
RS
195(defun minibuffer-window-active-p (window)
196 "Return t if WINDOW (a minibuffer window) is now active."
0d624ea4 197 (eq window (active-minibuffer-window)))
82e6d8cb 198\f
a2535589 199(defun count-windows (&optional minibuf)
fe7a0e7d 200 "Return the number of visible windows.
b70b2dd2
KH
201This counts the windows in the selected frame and (if the minibuffer is
202to be counted) its minibuffer frame (if that's not the same frame).
203The optional arg MINIBUF non-nil means count the minibuffer
c6897d8e 204even if it is inactive."
a2535589 205 (let ((count 0))
12169754 206 (walk-windows (function (lambda (w)
a2535589
JA
207 (setq count (+ count 1))))
208 minibuf)
209 count))
210
fe7a0e7d 211(defun window-safely-shrinkable-p (&optional window)
119171dd
EZ
212 "Non-nil if the WINDOW can be shrunk without shrinking other windows.
213If WINDOW is nil or omitted, it defaults to the currently selected window."
fc4d69e1
SM
214 (with-selected-window (or window (selected-window))
215 (let ((edges (window-edges)))
216 (or (= (nth 2 edges) (nth 2 (window-edges (previous-window))))
217 (= (nth 0 edges) (nth 0 (window-edges (next-window))))))))
218
fe7a0e7d 219
a2535589 220(defun balance-windows ()
fe7a0e7d 221 "Make all visible windows the same height (approximately)."
a2535589 222 (interactive)
0d6c5d18 223 (let ((count -1) levels newsizes level-size
3ca9dd8d
RS
224 ;; Don't count the lines that are above the uppermost windows.
225 ;; (These are the menu bar lines, if any.)
0d6c5d18
RS
226 (mbl (nth 1 (window-edges (frame-first-window (selected-frame)))))
227 (last-window (previous-window (frame-first-window (selected-frame))))
228 ;; Don't count the lines that are past the lowest main window.
229 total)
230 ;; Bottom edge of last window determines what size we have to work with.
231 (setq total
232 (+ (window-height last-window)
233 (nth 1 (window-edges last-window))))
234
7162c5c4
RS
235 ;; Find all the different vpos's at which windows start,
236 ;; then count them. But ignore levels that differ by only 1.
0d6c5d18
RS
237 (let (tops (prev-top -2))
238 (walk-windows (function (lambda (w)
239 (setq tops (cons (nth 1 (window-edges w))
240 tops))))
241 'nomini)
242 (setq tops (sort tops '<))
243 (while tops
244 (if (> (car tops) (1+ prev-top))
245 (setq prev-top (car tops)
246 count (1+ count)))
247 (setq levels (cons (cons (car tops) count) levels))
248 (setq tops (cdr tops)))
249 (setq count (1+ count)))
250 ;; Subdivide the frame into desired number of vertical levels.
251 (setq level-size (/ (- total mbl) count))
252 (save-selected-window
253 ;; Set up NEWSIZES to map windows to their desired sizes.
254 ;; If a window ends at the bottom level, don't include
255 ;; it in NEWSIZES. Those windows get the right sizes
256 ;; by adjusting the ones above them.
257 (walk-windows (function
258 (lambda (w)
259 (let ((newtop (cdr (assq (nth 1 (window-edges w))
260 levels)))
261 (newbot (cdr (assq (+ (window-height w)
262 (nth 1 (window-edges w)))
263 levels))))
264 (if newbot
265 (setq newsizes
266 (cons (cons w (* level-size (- newbot newtop)))
e1ff49ba 267 newsizes))))))
0d6c5d18
RS
268 'nomini)
269 ;; Make walk-windows start with the topmost window.
270 (select-window (previous-window (frame-first-window (selected-frame))))
271 (let (done (count 0))
272 ;; Give each window its precomputed size, or at least try.
273 ;; Keep trying until they all get the intended sizes,
274 ;; but not more than 3 times (to prevent infinite loop).
275 (while (and (not done) (< count 3))
276 (setq done t)
277 (setq count (1+ count))
278 (walk-windows (function (lambda (w)
279 (select-window w)
280 (let ((newsize (cdr (assq w newsizes))))
281 (when newsize
282 (enlarge-window (- newsize
283 (window-height))
284 nil t)
285 (unless (= (window-height) newsize)
286 (setq done nil))))))
e1ff49ba 287 'nomini))))))
82e6d8cb 288\f
4a4accf7 289;; I think this should be the default; I think people will prefer it--rms.
30e19aee 290(defcustom split-window-keep-point t
90dc1922
LT
291 "*If non-nil, \\[split-window-vertically] keeps the original point \
292in both children.
7162c5c4
RS
293This is often more convenient for editing.
294If nil, adjust point in each of the two windows to minimize redisplay.
90dc1922
LT
295This is convenient on slow terminals, but point can move strangely.
296
297This option applies only to `split-window-vertically' and
298functions that call it. `split-window' always keeps the original
299point in both children,"
30e19aee
RS
300 :type 'boolean
301 :group 'windows)
8e4b71d8 302
a2535589
JA
303(defun split-window-vertically (&optional arg)
304 "Split current window into two windows, one above the other.
c65c1681 305The uppermost window gets ARG lines and the other gets the rest.
90dc1922 306Negative ARG means select the size of the lowermost window instead.
c65c1681
RS
307With no argument, split equally or close to it.
308Both windows display the same buffer now current.
c65c1681 309
3e9890d1 310If the variable `split-window-keep-point' is non-nil, both new windows
8e4b71d8 311will get the same value of point as the current window. This is often
90dc1922 312more convenient for editing. The upper window is the selected window.
8e4b71d8 313
90dc1922 314Otherwise, we choose window starts so as to minimize the amount of
8e4b71d8
JB
315redisplay; this is convenient on slow terminals. The new selected
316window is the one that the current value of point appears in. The
317value of point can change if the text around point is hidden by the
90dc1922
LT
318new mode line.
319
320Regardless of the value of `split-window-keep-point', the upper
321window is the original one and the return value is the new, lower
322window."
a2535589
JA
323 (interactive "P")
324 (let ((old-w (selected-window))
c65c1681 325 (old-point (point))
ab94bf9f 326 (size (and arg (prefix-numeric-value arg)))
4464514e
RS
327 (window-full-p nil)
328 new-w bottom switch moved)
ab94bf9f
KH
329 (and size (< size 0) (setq size (+ (window-height) size)))
330 (setq new-w (split-window nil size))
7d7f1f33 331 (or split-window-keep-point
c65c1681 332 (progn
8e4b71d8
JB
333 (save-excursion
334 (set-buffer (window-buffer))
335 (goto-char (window-start))
4464514e 336 (setq moved (vertical-motion (window-height)))
8e4b71d8
JB
337 (set-window-start new-w (point))
338 (if (> (point) (window-point new-w))
339 (set-window-point new-w (point)))
4464514e
RS
340 (and (= moved (window-height))
341 (progn
342 (setq window-full-p t)
343 (vertical-motion -1)))
344 (setq bottom (point)))
345 (and window-full-p
346 (<= bottom (point))
347 (set-window-point old-w (1- bottom)))
348 (and window-full-p
349 (<= (window-start new-w) old-point)
350 (progn
351 (set-window-point new-w old-point)
352 (select-window new-w)))))
c361280d
RS
353 (split-window-save-restore-data new-w old-w)))
354
3d2f23d9
RS
355;; This is to avoid compiler warnings.
356(defvar view-return-to-alist)
357
c361280d 358(defun split-window-save-restore-data (new-w old-w)
4a4accf7 359 (with-current-buffer (window-buffer)
c361280d
RS
360 (if view-mode
361 (let ((old-info (assq old-w view-return-to-alist)))
6b3b4dbb
RS
362 (if old-info
363 (push (cons new-w (cons (car (cdr old-info)) t))
364 view-return-to-alist))))
2ed3f64c 365 new-w))
a2535589
JA
366
367(defun split-window-horizontally (&optional arg)
368 "Split current window into two windows side by side.
0ef2c2f2 369This window becomes the leftmost of the two, and gets ARG columns.
90dc1922 370Negative ARG means select the size of the rightmost window instead.
dd1455c2
RS
371The argument includes the width of the window's scroll bar; if there
372are no scroll bars, it includes the width of the divider column
90dc1922
LT
373to the window's right, if any. No ARG means split equally.
374
375The original, leftmost window remains selected.
376The return value is the new, rightmost window."
a2535589 377 (interactive "P")
c361280d
RS
378 (let ((old-w (selected-window))
379 (size (and arg (prefix-numeric-value arg))))
0ef2c2f2
KH
380 (and size (< size 0)
381 (setq size (+ (window-width) size)))
c361280d 382 (split-window-save-restore-data (split-window nil size t) old-w)))
361691dc
MB
383
384\f
361691dc
MB
385(defun set-window-text-height (window height)
386 "Sets the height in lines of the text display area of WINDOW to HEIGHT.
387This doesn't include the mode-line (or header-line if any) or any
388partial-height lines in the text display area.
389
390If WINDOW is nil, the selected window is used.
361691dc
MB
391
392Note that the current implementation of this function cannot always set
393the height exactly, but attempts to be conservative, by allocating more
394lines than are actually needed in the case where some error may be present."
395 (let ((delta (- height (window-text-height window))))
396 (unless (zerop delta)
38f99c27
MB
397 (let ((window-min-height 1))
398 (if (and window (not (eq window (selected-window))))
399 (save-selected-window
400 (select-window window)
401 (enlarge-window delta))
402 (enlarge-window delta))))))
361691dc 403
8075a110 404\f
a2535589
JA
405(defun enlarge-window-horizontally (arg)
406 "Make current window ARG columns wider."
407 (interactive "p")
408 (enlarge-window arg t))
409
410(defun shrink-window-horizontally (arg)
411 "Make current window ARG columns narrower."
412 (interactive "p")
413 (shrink-window arg t))
414
3b134005
RS
415(defun window-buffer-height (window)
416 "Return the height (in screen lines) of the buffer that WINDOW is displaying."
ba96f392
SM
417 (with-current-buffer (window-buffer window)
418 (max 1
419 (count-screen-lines (point-min) (point-max)
420 ;; If buffer ends with a newline, ignore it when
421 ;; counting height unless point is after it.
422 (eobp)
423 window))))
3b134005 424
c16c855b
GM
425(defun count-screen-lines (&optional beg end count-final-newline window)
426 "Return the number of screen lines in the region.
427The number of screen lines may be different from the number of actual lines,
428due to line breaking, display table, etc.
429
430Optional arguments BEG and END default to `point-min' and `point-max'
431respectively.
432
fe7a0e7d 433If region ends with a newline, ignore it unless optional third argument
c16c855b
GM
434COUNT-FINAL-NEWLINE is non-nil.
435
436The optional fourth argument WINDOW specifies the window used for obtaining
fe7a0e7d 437parameters such as width, horizontal scrolling, and so on. The default is
c16c855b
GM
438to use the selected window's parameters.
439
440Like `vertical-motion', `count-screen-lines' always uses the current buffer,
fe7a0e7d 441regardless of which buffer is displayed in WINDOW. This makes possible to use
c16c855b
GM
442`count-screen-lines' in any buffer, whether or not it is currently displayed
443in some window."
444 (unless beg
445 (setq beg (point-min)))
446 (unless end
447 (setq end (point-max)))
448 (if (= beg end)
449 0
450 (save-excursion
451 (save-restriction
452 (widen)
453 (narrow-to-region (min beg end)
454 (if (and (not count-final-newline)
455 (= ?\n (char-before (max beg end))))
456 (1- (max beg end))
457 (max beg end)))
458 (goto-char (point-min))
459 (1+ (vertical-motion (buffer-size) window))))))
460
65e742bd
MB
461(defun fit-window-to-buffer (&optional window max-height min-height)
462 "Make WINDOW the right size to display its contents exactly.
119171dd 463If WINDOW is omitted or nil, it defaults to the selected window.
65e742bd
MB
464If the optional argument MAX-HEIGHT is supplied, it is the maximum height
465 the window is allowed to be, defaulting to the frame height.
466If the optional argument MIN-HEIGHT is supplied, it is the minimum
467 height the window is allowed to be, defaulting to `window-min-height'.
468
469The heights in MAX-HEIGHT and MIN-HEIGHT include the mode-line and/or
470header-line."
471 (interactive)
472
473 (when (null window)
474 (setq window (selected-window)))
3511cde8
MB
475 (when (null max-height)
476 (setq max-height (frame-height (window-frame window))))
65e742bd 477
88f0a1eb
MB
478 (let* ((buf
479 ;; Buffer that is displayed in WINDOW
480 (window-buffer window))
481 (window-height
65e742bd
MB
482 ;; The current height of WINDOW
483 (window-height window))
88f0a1eb 484 (desired-height
65e742bd
MB
485 ;; The height necessary to show the buffer displayed by WINDOW
486 ;; (`count-screen-lines' always works on the current buffer).
88f0a1eb
MB
487 (with-current-buffer buf
488 (+ (count-screen-lines)
b1491763
KH
489 ;; If the buffer is empty, (count-screen-lines) is
490 ;; zero. But, even in that case, we need one text line
491 ;; for cursor.
492 (if (= (point-min) (point-max))
493 1 0)
88f0a1eb
MB
494 ;; For non-minibuffers, count the mode-line, if any
495 (if (and (not (window-minibuffer-p window))
496 mode-line-format)
497 1 0)
498 ;; Count the header-line, if any
499 (if header-line-format 1 0))))
65e742bd
MB
500 (delta
501 ;; Calculate how much the window height has to change to show
88f0a1eb
MB
502 ;; desired-height lines, constrained by MIN-HEIGHT and MAX-HEIGHT.
503 (- (max (min desired-height max-height)
65e742bd
MB
504 (or min-height window-min-height))
505 window-height))
506 ;; We do our own height checking, so avoid any restrictions due to
507 ;; window-min-height.
508 (window-min-height 1))
509
510 ;; Don't try to redisplay with the cursor at the end
511 ;; on its own line--that would force a scroll and spoil things.
88f0a1eb
MB
512 (when (with-current-buffer buf
513 (and (eobp) (bolp) (not (bobp))))
514 (set-window-point window (1- (window-point window))))
515
516 (save-selected-window
517 (select-window window)
518
519 ;; Adjust WINDOW to the nominally correct size (which may actually
520 ;; be slightly off because of variable height text, etc).
521 (unless (zerop delta)
522 (enlarge-window delta))
523
524 ;; Check if the last line is surely fully visible. If not,
525 ;; enlarge the window.
526 (let ((end (with-current-buffer buf
527 (save-excursion
528 (goto-char (point-max))
45450dd5
MB
529 (when (and (bolp) (not (bobp)))
530 ;; Don't include final newline
531 (backward-char 1))
532 (when truncate-lines
533 ;; If line-wrapping is turned off, test the
534 ;; beginning of the last line for visibility
535 ;; instead of the end, as the end of the line
536 ;; could be invisible by virtue of extending past
537 ;; the edge of the window.
538 (forward-line 0))
539 (point)))))
88f0a1eb
MB
540 (set-window-vscroll window 0)
541 (while (and (< desired-height max-height)
542 (= desired-height (window-height window))
df0677c3 543 (not (pos-visible-in-window-p end window)))
88f0a1eb 544 (enlarge-window 1)
edb08287 545 (setq desired-height (1+ desired-height)))))))
65e742bd 546
a0900d9f 547(defun shrink-window-if-larger-than-buffer (&optional window)
d0bee390 548 "Shrink the WINDOW to be as small as possible to display its contents.
119171dd 549If WINDOW is omitted or nil, it defaults to the selected window.
30f2e5cc 550Do not shrink to less than `window-min-height' lines.
d0bee390 551Do nothing if the buffer contains more lines than the present window height,
3eb217a0 552or if some of the window's contents are scrolled out of view,
fd8529d0 553or if shrinking this window would also shrink another window,
18fde850 554or if the window is the only window of its frame."
d0bee390 555 (interactive)
65e742bd
MB
556 (when (null window)
557 (setq window (selected-window)))
558 (let* ((frame (window-frame window))
559 (mini (frame-parameter frame 'minibuffer))
560 (edges (window-edges window)))
561 (if (and (not (eq window (frame-root-window frame)))
fe7a0e7d 562 (window-safely-shrinkable-p)
65e742bd
MB
563 (pos-visible-in-window-p (point-min) window)
564 (not (eq mini 'only))
565 (or (not mini)
f92c5e7d
GM
566 (let ((mini-window (minibuffer-window frame)))
567 (or (null mini-window)
568 (not (eq frame (window-frame mini-window)))
569 (< (nth 3 edges)
570 (nth 1 (window-edges mini-window)))
f1180544 571 (> (nth 1 edges)
f92c5e7d 572 (frame-parameter frame 'menu-bar-lines))))))
65e742bd 573 (fit-window-to-buffer window (window-height window)))))
b691df0c
RS
574
575(defun kill-buffer-and-window ()
576 "Kill the current buffer and delete the selected window."
577 (interactive)
0f790c74
RS
578 (let ((window-to-delete (selected-window))
579 (delete-window-hook (lambda ()
580 (condition-case nil
581 (delete-window)
582 (error nil)))))
583 (add-hook 'kill-buffer-hook delete-window-hook t t)
584 (if (kill-buffer (current-buffer))
585 ;; If `delete-window' failed before, we rerun it to regenerate
586 ;; the error so it can be seen in the minibuffer.
587 (when (eq (selected-window) window-to-delete)
588 (delete-window))
589 (remove-hook 'kill-buffer-hook delete-window-hook t))))
b691df0c 590
3d2f23d9
RS
591(defun quit-window (&optional kill window)
592 "Quit the current buffer. Bury it, and maybe delete the selected frame.
18fde850 593\(The frame is deleted if it contains a dedicated window for the buffer.)
3d2f23d9
RS
594With a prefix argument, kill the buffer instead.
595
596Noninteractively, if KILL is non-nil, then kill the current buffer,
597otherwise bury it.
598
599If WINDOW is non-nil, it specifies a window; we delete that window,
600and the buffer that is killed or buried is the one in that window."
601 (interactive "P")
602 (let ((buffer (window-buffer window))
c81845b6 603 (frame (window-frame (or window (selected-window))))
3d2f23d9
RS
604 (window-solitary
605 (save-selected-window
606 (if window
607 (select-window window))
608 (one-window-p t)))
609 window-handled)
610
611 (save-selected-window
612 (if window
613 (select-window window))
eed1360c
RS
614 (or (window-minibuffer-p)
615 (window-dedicated-p (selected-window))
616 (switch-to-buffer (other-buffer))))
3d2f23d9
RS
617
618 ;; Get rid of the frame, if it has just one dedicated window
619 ;; and other visible frames exist.
eed1360c 620 (and (or (window-minibuffer-p) (window-dedicated-p window))
3d2f23d9
RS
621 (delq frame (visible-frame-list))
622 window-solitary
623 (if (and (eq default-minibuffer-frame frame)
624 (= 1 (length (minibuffer-frame-list))))
625 (setq window nil)
626 (delete-frame frame)
627 (setq window-handled t)))
628
629 ;; Deal with the buffer.
630 (if kill
631 (kill-buffer buffer)
632 (bury-buffer buffer))
633
634 ;; Maybe get rid of the window.
635 (and window (not window-handled) (not window-solitary)
636 (delete-window window))))
637
aa8d5134
PJ
638(defun handle-select-window (event)
639 "Handle select-window events."
640 (interactive "e")
641 (let ((window (posn-window (event-start event))))
4a4accf7 642 (if (and (window-live-p window)
66c226bf
SM
643 ;; Don't switch if we're currently in the minibuffer.
644 ;; This tries to work around problems where the minibuffer gets
645 ;; unselected unexpectedly, and where you then have to move
646 ;; your mouse all the way down to the minibuffer to select it.
647 (not (window-minibuffer-p (selected-window)))
648 ;; Don't switch to a minibuffer window unless it's active.
4a4accf7
SM
649 (or (not (window-minibuffer-p window))
650 (minibuffer-window-active-p window)))
aa8d5134
PJ
651 (select-window window))))
652
a2535589 653(define-key ctl-x-map "2" 'split-window-vertically)
492878e4 654(define-key ctl-x-map "3" 'split-window-horizontally)
a2535589
JA
655(define-key ctl-x-map "}" 'enlarge-window-horizontally)
656(define-key ctl-x-map "{" 'shrink-window-horizontally)
a0900d9f
ER
657(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
658(define-key ctl-x-map "+" 'balance-windows)
b691df0c 659(define-key ctl-x-4-map "0" 'kill-buffer-and-window)
76d7458e 660
66c226bf 661;; arch-tag: b508dfcc-c353-4c37-89fa-e773fe10cea9
fe7a0e7d 662;;; window.el ends here