* fontset.c (FONTSET_ADD): Return void, not Lisp_Object.
[bpt/emacs.git] / lisp / window.el
CommitLineData
3c448ab6
MR
1;;; window.el --- GNU Emacs window commands aside from those written in C
2
acaf905b 3;; Copyright (C) 1985, 1989, 1992-1994, 2000-2012
3689984f 4;; Free Software Foundation, Inc.
3c448ab6
MR
5
6;; Maintainer: FSF
7;; Keywords: internal
bd78fa1d 8;; Package: emacs
3c448ab6
MR
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25;;; Commentary:
26
27;; Window tree functions.
28
29;;; Code:
30
3c448ab6
MR
31(defmacro save-selected-window (&rest body)
32 "Execute BODY, then select the previously selected window.
33The value returned is the value of the last form in BODY.
34
35This macro saves and restores the selected window, as well as the
36selected window in each frame. If the previously selected window
37is no longer live, then whatever window is selected at the end of
38BODY remains selected. If the previously selected window of some
39frame is no longer live at the end of BODY, that frame's selected
40window is left alone.
41
42This macro saves and restores the current buffer, since otherwise
43its normal operation could make a different buffer current. The
44order of recently selected windows and the buffer list ordering
45are not altered by this macro (unless they are altered in BODY)."
f291fe60 46 (declare (indent 0) (debug t))
3c448ab6 47 `(let ((save-selected-window-window (selected-window))
c6bf3022
CY
48 ;; We save and restore all frames' selected windows, because
49 ;; `select-window' can change the frame-selected-window of
50 ;; whatever frame that window is in. Each text terminal's
51 ;; top-frame is preserved by putting it last in the list.
3c448ab6 52 (save-selected-window-alist
c6bf3022
CY
53 (apply 'append
54 (mapcar (lambda (terminal)
55 (let ((frames (frames-on-display-list terminal))
56 (top-frame (tty-top-frame terminal))
57 alist)
58 (if top-frame
59 (setq frames
60 (cons top-frame
61 (delq top-frame frames))))
62 (dolist (f frames)
63 (push (cons f (frame-selected-window f))
64 alist))))
65 (terminal-list)))))
3c448ab6
MR
66 (save-current-buffer
67 (unwind-protect
68 (progn ,@body)
69 (dolist (elt save-selected-window-alist)
70 (and (frame-live-p (car elt))
71 (window-live-p (cdr elt))
72 (set-frame-selected-window (car elt) (cdr elt) 'norecord)))
73 (when (window-live-p save-selected-window-window)
74 (select-window save-selected-window-window 'norecord))))))
75
d68443dc
MR
76;; The following two functions are like `window-next-sibling' and
77;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so
78;; they don't substitute the selected window for nil), and they return
79;; nil when WINDOW doesn't have a parent (like a frame's root window or
80;; a minibuffer window).
4b0d61e3 81(defun window-right (window)
85cc1f11
MR
82 "Return WINDOW's right sibling.
83Return nil if WINDOW is the root window of its frame. WINDOW can
84be any window."
d68443dc 85 (and window (window-parent window) (window-next-sibling window)))
85cc1f11 86
4b0d61e3 87(defun window-left (window)
85cc1f11
MR
88 "Return WINDOW's left sibling.
89Return nil if WINDOW is the root window of its frame. WINDOW can
90be any window."
d68443dc 91 (and window (window-parent window) (window-prev-sibling window)))
85cc1f11 92
4b0d61e3 93(defun window-child (window)
85c2386b
MR
94 "Return WINDOW's first child window.
95WINDOW can be any window."
d68443dc 96 (or (window-top-child window) (window-left-child window)))
85cc1f11
MR
97
98(defun window-child-count (window)
85c2386b
MR
99 "Return number of WINDOW's child windows.
100WINDOW can be any window."
85cc1f11
MR
101 (let ((count 0))
102 (when (and (windowp window) (setq window (window-child window)))
103 (while window
104 (setq count (1+ count))
d68443dc 105 (setq window (window-next-sibling window))))
85cc1f11
MR
106 count))
107
108(defun window-last-child (window)
85c2386b
MR
109 "Return last child window of WINDOW.
110WINDOW can be any window."
85cc1f11 111 (when (and (windowp window) (setq window (window-child window)))
d68443dc
MR
112 (while (window-next-sibling window)
113 (setq window (window-next-sibling window))))
85cc1f11
MR
114 window)
115
4b0d61e3 116(defun window-normalize-buffer (buffer-or-name)
85cc1f11
MR
117 "Return buffer specified by BUFFER-OR-NAME.
118BUFFER-OR-NAME must be either a buffer or a string naming a live
119buffer and defaults to the current buffer."
120 (cond
121 ((not buffer-or-name)
122 (current-buffer))
123 ((bufferp buffer-or-name)
124 (if (buffer-live-p buffer-or-name)
125 buffer-or-name
126 (error "Buffer %s is not a live buffer" buffer-or-name)))
127 ((get-buffer buffer-or-name))
128 (t
129 (error "No such buffer %s" buffer-or-name))))
130
4b0d61e3 131(defun window-normalize-frame (frame)
85cc1f11
MR
132 "Return frame specified by FRAME.
133FRAME must be a live frame and defaults to the selected frame."
134 (if frame
135 (if (frame-live-p frame)
136 frame
137 (error "%s is not a live frame" frame))
138 (selected-frame)))
139
4b0d61e3 140(defun window-normalize-window (window &optional live-only)
85c2386b
MR
141 "Return the window specified by WINDOW.
142If WINDOW is nil, return the selected window. Otherwise, if
143WINDOW is a live or an internal window, return WINDOW; if
144LIVE-ONLY is non-nil, return WINDOW for a live window only.
447f16b8 145Otherwise, signal an error."
85c2386b
MR
146 (cond
147 ((null window)
148 (selected-window))
149 (live-only
150 (if (window-live-p window)
151 window
152 (error "%s is not a live window" window)))
153 ((window-valid-p window)
154 window)
155 (t
156 (error "%s is not a valid window" window))))
85cc1f11
MR
157
158(defvar ignore-window-parameters nil
159 "If non-nil, standard functions ignore window parameters.
160The functions currently affected by this are `split-window',
161`delete-window', `delete-other-windows' and `other-window'.
162
163An application may bind this to a non-nil value around calls to
164these functions to inhibit processing of window parameters.")
165
a1511caf 166(defconst window-safe-min-height 1
8da11505 167 "The absolute minimum number of lines of a window.
a1511caf
MR
168Anything less might crash Emacs.")
169
562dd5e9
MR
170(defcustom window-min-height 4
171 "The minimum number of lines of any window.
9173deec
JB
172The value has to accommodate a mode- or header-line if present.
173A value less than `window-safe-min-height' is ignored. The value
562dd5e9
MR
174of this variable is honored when windows are resized or split.
175
176Applications should never rebind this variable. To resize a
177window to a height less than the one specified here, an
d615d6d2 178application should instead call `window-resize' with a non-nil
562dd5e9 179IGNORE argument. In order to have `split-window' make a window
e4769531 180shorter, explicitly specify the SIZE argument of that function."
562dd5e9
MR
181 :type 'integer
182 :version "24.1"
183 :group 'windows)
184
a1511caf 185(defconst window-safe-min-width 2
8da11505 186 "The absolute minimum number of columns of a window.
a1511caf
MR
187Anything less might crash Emacs.")
188
562dd5e9
MR
189(defcustom window-min-width 10
190 "The minimum number of columns of any window.
a91adc7e 191The value has to accommodate margins, fringes, or scrollbars if
562dd5e9
MR
192present. A value less than `window-safe-min-width' is ignored.
193The value of this variable is honored when windows are resized or
194split.
195
196Applications should never rebind this variable. To resize a
197window to a width less than the one specified here, an
d615d6d2 198application should instead call `window-resize' with a non-nil
562dd5e9 199IGNORE argument. In order to have `split-window' make a window
e4769531 200narrower, explicitly specify the SIZE argument of that function."
562dd5e9
MR
201 :type 'integer
202 :version "24.1"
203 :group 'windows)
204
4b0d61e3 205(defun window-combined-p (&optional window horizontal)
49745b39 206 "Return non-nil if WINDOW has siblings in a given direction.
85c2386b 207WINDOW must be a valid window and defaults to the selected one.
49745b39
CY
208
209HORIZONTAL determines a direction for the window combination.
210If HORIZONTAL is omitted or nil, return non-nil if WINDOW is part
211of a vertical window combination.
212If HORIZONTAL is non-nil, return non-nil if WINDOW is part of a
213horizontal window combination."
447f16b8 214 (setq window (window-normalize-window window))
85cc1f11 215 (let ((parent (window-parent window)))
49745b39
CY
216 (and parent
217 (if horizontal
218 (window-left-child parent)
219 (window-top-child parent)))))
85cc1f11 220
be7f5545
MR
221(defun window-combinations (window &optional horizontal)
222 "Return largest number of windows vertically arranged within WINDOW.
85c2386b 223WINDOW must be a valid window and defaults to the selected one.
49745b39 224If HORIZONTAL is non-nil, return the largest number of
be7f5545 225windows horizontally arranged within WINDOW."
447f16b8 226 (setq window (window-normalize-window window))
85cc1f11
MR
227 (cond
228 ((window-live-p window)
229 ;; If WINDOW is live, return 1.
230 1)
49745b39
CY
231 ((if horizontal
232 (window-left-child window)
233 (window-top-child window))
85cc1f11 234 ;; If WINDOW is iso-combined, return the sum of the values for all
be7f5545 235 ;; child windows of WINDOW.
85cc1f11
MR
236 (let ((child (window-child window))
237 (count 0))
238 (while child
239 (setq count
3d8daefe 240 (+ (window-combinations child horizontal)
85cc1f11
MR
241 count))
242 (setq child (window-right child)))
243 count))
244 (t
245 ;; If WINDOW is not iso-combined, return the maximum value of any
be7f5545 246 ;; child window of WINDOW.
85cc1f11
MR
247 (let ((child (window-child window))
248 (count 1))
249 (while child
250 (setq count
3d8daefe 251 (max (window-combinations child horizontal)
85cc1f11
MR
252 count))
253 (setq child (window-right child)))
254 count))))
255
c7635a97 256(defun walk-window-tree-1 (fun walk-window-tree-window any &optional sub-only)
85cc1f11
MR
257 "Helper function for `walk-window-tree' and `walk-window-subtree'."
258 (let (walk-window-tree-buffer)
259 (while walk-window-tree-window
260 (setq walk-window-tree-buffer
261 (window-buffer walk-window-tree-window))
262 (when (or walk-window-tree-buffer any)
c7635a97 263 (funcall fun walk-window-tree-window))
85cc1f11
MR
264 (unless walk-window-tree-buffer
265 (walk-window-tree-1
c7635a97 266 fun (window-left-child walk-window-tree-window) any)
85cc1f11 267 (walk-window-tree-1
c7635a97 268 fun (window-top-child walk-window-tree-window) any))
85cc1f11
MR
269 (if sub-only
270 (setq walk-window-tree-window nil)
271 (setq walk-window-tree-window
272 (window-right walk-window-tree-window))))))
273
c7635a97
CY
274(defun walk-window-tree (fun &optional frame any)
275 "Run function FUN on each live window of FRAME.
276FUN must be a function with one argument - a window. FRAME must
85cc1f11 277be a live frame and defaults to the selected one. ANY, if
c7635a97 278non-nil means to run FUN on all live and internal windows of
85cc1f11
MR
279FRAME.
280
281This function performs a pre-order, depth-first traversal of the
c7635a97 282window tree. If FUN changes the window tree, the result is
85cc1f11 283unpredictable."
5386012d 284 (let ((walk-window-tree-frame (window-normalize-frame frame)))
85cc1f11 285 (walk-window-tree-1
c7635a97 286 fun (frame-root-window walk-window-tree-frame) any)))
85cc1f11 287
c7635a97
CY
288(defun walk-window-subtree (fun &optional window any)
289 "Run function FUN on the subtree of windows rooted at WINDOW.
290WINDOW defaults to the selected window. FUN must be a function
291with one argument - a window. By default, run FUN only on live
be7f5545 292windows of the subtree. If the optional argument ANY is non-nil,
c7635a97
CY
293run FUN on all live and internal windows of the subtree. If
294WINDOW is live, run FUN on WINDOW only.
85cc1f11
MR
295
296This function performs a pre-order, depth-first traversal of the
c7635a97 297subtree rooted at WINDOW. If FUN changes that tree, the result
be7f5545 298is unpredictable."
447f16b8 299 (setq window (window-normalize-window window))
c7635a97 300 (walk-window-tree-1 fun window any t))
85cc1f11 301
85cc1f11
MR
302(defun window-with-parameter (parameter &optional value frame any)
303 "Return first window on FRAME with PARAMETER non-nil.
304FRAME defaults to the selected frame. Optional argument VALUE
305non-nil means only return a window whose window-parameter value
382c953b 306for PARAMETER equals VALUE (comparison is done with `equal').
85cc1f11
MR
307Optional argument ANY non-nil means consider internal windows
308too."
cb882333 309 (let (this-value)
85cc1f11
MR
310 (catch 'found
311 (walk-window-tree
312 (lambda (window)
313 (when (and (setq this-value (window-parameter window parameter))
314 (or (not value) (equal value this-value)))
315 (throw 'found window)))
316 frame any))))
317
318;;; Atomic windows.
319(defun window-atom-root (&optional window)
320 "Return root of atomic window WINDOW is a part of.
85c2386b 321WINDOW must be a valid window and defaults to the selected one.
382c953b 322Return nil if WINDOW is not part of an atomic window."
447f16b8 323 (setq window (window-normalize-window window))
85cc1f11
MR
324 (let (root)
325 (while (and window (window-parameter window 'window-atom))
326 (setq root window)
327 (setq window (window-parent window)))
328 root))
329
5386012d 330(defun window-make-atom (window)
85cc1f11
MR
331 "Make WINDOW an atomic window.
332WINDOW must be an internal window. Return WINDOW."
333 (if (not (window-child window))
334 (error "Window %s is not an internal window" window)
335 (walk-window-subtree
336 (lambda (window)
337 (set-window-parameter window 'window-atom t))
338 window t)
339 window))
340
54f9154c
MR
341(defun window--atom-check-1 (window)
342 "Subroutine of `window--atom-check'."
85cc1f11
MR
343 (when window
344 (if (window-parameter window 'window-atom)
345 (let ((count 0))
346 (when (or (catch 'reset
347 (walk-window-subtree
348 (lambda (window)
349 (if (window-parameter window 'window-atom)
350 (setq count (1+ count))
351 (throw 'reset t)))
352 window t))
353 ;; count >= 1 must hold here. If there's no other
354 ;; window around dissolve this atomic window.
355 (= count 1))
356 ;; Dissolve atomic window.
357 (walk-window-subtree
358 (lambda (window)
359 (set-window-parameter window 'window-atom nil))
360 window t)))
361 ;; Check children.
362 (unless (window-buffer window)
54f9154c
MR
363 (window--atom-check-1 (window-left-child window))
364 (window--atom-check-1 (window-top-child window))))
85cc1f11 365 ;; Check right sibling
54f9154c 366 (window--atom-check-1 (window-right window))))
85cc1f11 367
54f9154c 368(defun window--atom-check (&optional frame)
85cc1f11
MR
369 "Check atomicity of all windows on FRAME.
370FRAME defaults to the selected frame. If an atomic window is
be7f5545
MR
371wrongly configured, reset the atomicity of all its windows on
372FRAME to nil. An atomic window is wrongly configured if it has
373no child windows or one of its child windows is not atomic."
54f9154c 374 (window--atom-check-1 (frame-root-window frame)))
85cc1f11
MR
375
376;; Side windows.
377(defvar window-sides '(left top right bottom)
378 "Window sides.")
379
380(defcustom window-sides-vertical nil
381 "If non-nil, left and right side windows are full height.
382Otherwise, top and bottom side windows are full width."
383 :type 'boolean
384 :group 'windows
385 :version "24.1")
386
387(defcustom window-sides-slots '(nil nil nil nil)
388 "Maximum number of side window slots.
389The value is a list of four elements specifying the number of
382c953b 390side window slots on (in this order) the left, top, right and
85cc1f11
MR
391bottom side of each frame. If an element is a number, this means
392to display at most that many side windows on the corresponding
393side. If an element is nil, this means there's no bound on the
394number of slots on that side."
2bed3f04 395 :version "24.1"
85cc1f11
MR
396 :risky t
397 :type
398 '(list
399 :value (nil nil nil nil)
400 (choice
401 :tag "Left"
402 :help-echo "Maximum slots of left side window."
403 :value nil
404 :format "%[Left%] %v\n"
405 (const :tag "Unlimited" :format "%t" nil)
406 (integer :tag "Number" :value 2 :size 5))
407 (choice
408 :tag "Top"
409 :help-echo "Maximum slots of top side window."
410 :value nil
411 :format "%[Top%] %v\n"
412 (const :tag "Unlimited" :format "%t" nil)
413 (integer :tag "Number" :value 3 :size 5))
414 (choice
415 :tag "Right"
416 :help-echo "Maximum slots of right side window."
417 :value nil
418 :format "%[Right%] %v\n"
419 (const :tag "Unlimited" :format "%t" nil)
420 (integer :tag "Number" :value 2 :size 5))
421 (choice
422 :tag "Bottom"
423 :help-echo "Maximum slots of bottom side window."
424 :value nil
425 :format "%[Bottom%] %v\n"
426 (const :tag "Unlimited" :format "%t" nil)
427 (integer :tag "Number" :value 3 :size 5)))
428 :group 'windows)
429
54f9154c 430(defun window--side-check (&optional frame)
85cc1f11
MR
431 "Check the window-side parameter of all windows on FRAME.
432FRAME defaults to the selected frame. If the configuration is
433invalid, reset all window-side parameters to nil.
434
435A valid configuration has to preserve the following invariant:
436
437- If a window has a non-nil window-side parameter, it must have a
438 parent window and the parent window's window-side parameter
439 must be either nil or the same as for window.
440
441- If windows with non-nil window-side parameters exist, there
442 must be at most one window of each side and non-side with a
443 parent whose window-side parameter is nil and there must be no
444 leaf window whose window-side parameter is nil."
445 (let (normal none left top right bottom
cb882333 446 side parent parent-side)
85cc1f11
MR
447 (when (or (catch 'reset
448 (walk-window-tree
449 (lambda (window)
450 (setq side (window-parameter window 'window-side))
451 (setq parent (window-parent window))
452 (setq parent-side
453 (and parent (window-parameter parent 'window-side)))
454 ;; The following `cond' seems a bit tedious, but I'd
455 ;; rather stick to using just the stack.
456 (cond
457 (parent-side
458 (when (not (eq parent-side side))
459 ;; A parent whose window-side is non-nil must
460 ;; have a child with the same window-side.
461 (throw 'reset t)))
462 ;; Now check that there's more than one main window
463 ;; for any of none, left, top, right and bottom.
464 ((eq side 'none)
465 (if none
466 (throw 'reset t)
467 (setq none t)))
468 ((eq side 'left)
469 (if left
470 (throw 'reset t)
471 (setq left t)))
472 ((eq side 'top)
473 (if top
474 (throw 'reset t)
475 (setq top t)))
476 ((eq side 'right)
477 (if right
478 (throw 'reset t)
479 (setq right t)))
480 ((eq side 'bottom)
481 (if bottom
482 (throw 'reset t)
483 (setq bottom t)))
484 ((window-buffer window)
485 ;; A leaf window without window-side parameter,
486 ;; record its existence.
487 (setq normal t))))
488 frame t))
489 (if none
490 ;; At least one non-side window exists, so there must
491 ;; be at least one side-window and no normal window.
492 (or (not (or left top right bottom)) normal)
493 ;; No non-side window exists, so there must be no side
494 ;; window either.
495 (or left top right bottom)))
496 (walk-window-tree
497 (lambda (window)
498 (set-window-parameter window 'window-side nil))
499 frame t))))
500
54f9154c 501(defun window--check (&optional frame)
85cc1f11
MR
502 "Check atomic and side windows on FRAME.
503FRAME defaults to the selected frame."
54f9154c
MR
504 (window--side-check frame)
505 (window--atom-check frame))
85cc1f11
MR
506
507;;; Window sizes.
508(defvar window-size-fixed nil
509 "Non-nil in a buffer means windows displaying the buffer are fixed-size.
510If the value is `height', then only the window's height is fixed.
511If the value is `width', then only the window's width is fixed.
512Any other non-nil value fixes both the width and the height.
513
514Emacs won't change the size of any window displaying that buffer,
382c953b 515unless it has no other choice (like when deleting a neighboring
85cc1f11
MR
516window).")
517(make-variable-buffer-local 'window-size-fixed)
518
5e92ca23 519(defun window--size-ignore (window ignore)
a1511caf 520 "Return non-nil if IGNORE says to ignore size restrictions for WINDOW."
24300f5f 521 (if (window-valid-p ignore) (eq window ignore) ignore))
a1511caf
MR
522
523(defun window-min-size (&optional window horizontal ignore)
2116e93c 524 "Return the minimum size of WINDOW.
85c2386b
MR
525WINDOW must be a valid window and defaults to the selected one.
526Optional argument HORIZONTAL non-nil means return the minimum
527number of columns of WINDOW; otherwise return the minimum number
528of WINDOW's lines.
a1511caf 529
2116e93c 530Optional argument IGNORE, if non-nil, means ignore restrictions
a1511caf 531imposed by fixed size windows, `window-min-height' or
2116e93c 532`window-min-width' settings. If IGNORE equals `safe', live
a1511caf 533windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
534`window-safe-min-width' columns. If IGNORE is a window, ignore
535restrictions for that window only. Any other non-nil value
536means ignore all of the above restrictions for all windows."
c56cad4a 537 (window--min-size-1
447f16b8 538 (window-normalize-window window) horizontal ignore))
a1511caf 539
c56cad4a 540(defun window--min-size-1 (window horizontal ignore)
a1511caf
MR
541 "Internal function of `window-min-size'."
542 (let ((sub (window-child window)))
543 (if sub
544 (let ((value 0))
545 ;; WINDOW is an internal window.
3d8daefe 546 (if (window-combined-p sub horizontal)
a1511caf 547 ;; The minimum size of an iso-combination is the sum of
be7f5545 548 ;; the minimum sizes of its child windows.
a1511caf
MR
549 (while sub
550 (setq value (+ value
c56cad4a 551 (window--min-size-1 sub horizontal ignore)))
a1511caf
MR
552 (setq sub (window-right sub)))
553 ;; The minimum size of an ortho-combination is the maximum of
be7f5545 554 ;; the minimum sizes of its child windows.
a1511caf
MR
555 (while sub
556 (setq value (max value
c56cad4a 557 (window--min-size-1 sub horizontal ignore)))
a1511caf
MR
558 (setq sub (window-right sub))))
559 value)
560 (with-current-buffer (window-buffer window)
561 (cond
5e92ca23 562 ((and (not (window--size-ignore window ignore))
a1511caf
MR
563 (window-size-fixed-p window horizontal))
564 ;; The minimum size of a fixed size window is its size.
565 (window-total-size window horizontal))
566 ((or (eq ignore 'safe) (eq ignore window))
567 ;; If IGNORE equals `safe' or WINDOW return the safe values.
568 (if horizontal window-safe-min-width window-safe-min-height))
569 (horizontal
570 ;; For the minimum width of a window take fringes and
571 ;; scroll-bars into account. This is questionable and should
572 ;; be removed as soon as we are able to split (and resize)
573 ;; windows such that the new (or resized) windows can get a
574 ;; size less than the user-specified `window-min-height' and
575 ;; `window-min-width'.
576 (let ((frame (window-frame window))
577 (fringes (window-fringes window))
578 (scroll-bars (window-scroll-bars window)))
579 (max
580 (+ window-safe-min-width
581 (ceiling (car fringes) (frame-char-width frame))
582 (ceiling (cadr fringes) (frame-char-width frame))
583 (cond
584 ((memq (nth 2 scroll-bars) '(left right))
585 (nth 1 scroll-bars))
586 ((memq (frame-parameter frame 'vertical-scroll-bars)
587 '(left right))
588 (ceiling (or (frame-parameter frame 'scroll-bar-width) 14)
589 (frame-char-width)))
590 (t 0)))
5e92ca23 591 (if (and (not (window--size-ignore window ignore))
a1511caf
MR
592 (numberp window-min-width))
593 window-min-width
594 0))))
595 (t
596 ;; For the minimum height of a window take any mode- or
597 ;; header-line into account.
598 (max (+ window-safe-min-height
599 (if header-line-format 1 0)
600 (if mode-line-format 1 0))
5e92ca23 601 (if (and (not (window--size-ignore window ignore))
a1511caf
MR
602 (numberp window-min-height))
603 window-min-height
604 0))))))))
605
606(defun window-sizable (window delta &optional horizontal ignore)
607 "Return DELTA if DELTA lines can be added to WINDOW.
85c2386b 608WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
609Optional argument HORIZONTAL non-nil means return DELTA if DELTA
610columns can be added to WINDOW. A return value of zero means
611that no lines (or columns) can be added to WINDOW.
612
be7f5545
MR
613This function looks only at WINDOW and, recursively, its child
614windows. The function `window-resizable' looks at other windows
615as well.
a1511caf
MR
616
617DELTA positive means WINDOW shall be enlarged by DELTA lines or
618columns. If WINDOW cannot be enlarged by DELTA lines or columns
619return the maximum value in the range 0..DELTA by which WINDOW
620can be enlarged.
621
622DELTA negative means WINDOW shall be shrunk by -DELTA lines or
623columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
624return the minimum value in the range DELTA..0 by which WINDOW
625can be shrunk.
626
2116e93c 627Optional argument IGNORE non-nil means ignore restrictions
a1511caf 628imposed by fixed size windows, `window-min-height' or
2116e93c 629`window-min-width' settings. If IGNORE equals `safe', live
a1511caf 630windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
631`window-safe-min-width' columns. If IGNORE is a window, ignore
632restrictions for that window only. Any other non-nil value means
633ignore all of the above restrictions for all windows."
447f16b8 634 (setq window (window-normalize-window window))
a1511caf
MR
635 (cond
636 ((< delta 0)
637 (max (- (window-min-size window horizontal ignore)
638 (window-total-size window horizontal))
639 delta))
5e92ca23 640 ((window--size-ignore window ignore)
a1511caf
MR
641 delta)
642 ((> delta 0)
643 (if (window-size-fixed-p window horizontal)
644 0
645 delta))
646 (t 0)))
647
4b0d61e3 648(defun window-sizable-p (window delta &optional horizontal ignore)
a1511caf 649 "Return t if WINDOW can be resized by DELTA lines.
85c2386b 650WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
651For the meaning of the arguments of this function see the
652doc-string of `window-sizable'."
447f16b8 653 (setq window (window-normalize-window window))
a1511caf
MR
654 (if (> delta 0)
655 (>= (window-sizable window delta horizontal ignore) delta)
656 (<= (window-sizable window delta horizontal ignore) delta)))
657
5e92ca23 658(defun window--size-fixed-1 (window horizontal)
a1511caf
MR
659 "Internal function for `window-size-fixed-p'."
660 (let ((sub (window-child window)))
661 (catch 'fixed
662 (if sub
663 ;; WINDOW is an internal window.
3d8daefe 664 (if (window-combined-p sub horizontal)
be7f5545
MR
665 ;; An iso-combination is fixed size if all its child
666 ;; windows are fixed-size.
a1511caf
MR
667 (progn
668 (while sub
5e92ca23 669 (unless (window--size-fixed-1 sub horizontal)
be7f5545
MR
670 ;; We found a non-fixed-size child window, so
671 ;; WINDOW's size is not fixed.
a1511caf
MR
672 (throw 'fixed nil))
673 (setq sub (window-right sub)))
be7f5545 674 ;; All child windows are fixed-size, so WINDOW's size is
a1511caf
MR
675 ;; fixed.
676 (throw 'fixed t))
677 ;; An ortho-combination is fixed-size if at least one of its
be7f5545 678 ;; child windows is fixed-size.
a1511caf 679 (while sub
5e92ca23 680 (when (window--size-fixed-1 sub horizontal)
be7f5545
MR
681 ;; We found a fixed-size child window, so WINDOW's size
682 ;; is fixed.
a1511caf
MR
683 (throw 'fixed t))
684 (setq sub (window-right sub))))
685 ;; WINDOW is a live window.
686 (with-current-buffer (window-buffer window)
687 (if horizontal
688 (memq window-size-fixed '(width t))
689 (memq window-size-fixed '(height t))))))))
690
691(defun window-size-fixed-p (&optional window horizontal)
692 "Return non-nil if WINDOW's height is fixed.
85c2386b
MR
693WINDOW must be a valid window and defaults to the selected one.
694Optional argument HORIZONTAL non-nil means return non-nil if
695WINDOW's width is fixed.
a1511caf
MR
696
697If this function returns nil, this does not necessarily mean that
2cffd681
MR
698WINDOW can be resized in the desired direction. The function
699`window-resizable' can tell that."
5e92ca23 700 (window--size-fixed-1
447f16b8 701 (window-normalize-window window) horizontal))
a1511caf 702
c56cad4a 703(defun window--min-delta-1 (window delta &optional horizontal ignore trail noup)
a1511caf
MR
704 "Internal function for `window-min-delta'."
705 (if (not (window-parent window))
706 ;; If we can't go up, return zero.
707 0
708 ;; Else try to find a non-fixed-size sibling of WINDOW.
709 (let* ((parent (window-parent window))
710 (sub (window-child parent)))
711 (catch 'done
3d8daefe 712 (if (window-combined-p sub horizontal)
a1511caf 713 ;; In an iso-combination throw DELTA if we find at least one
be7f5545
MR
714 ;; child window and that window is either not fixed-size or
715 ;; we can ignore fixed-sizeness.
a1511caf
MR
716 (let ((skip (eq trail 'after)))
717 (while sub
718 (cond
719 ((eq sub window)
720 (setq skip (eq trail 'before)))
721 (skip)
5e92ca23 722 ((and (not (window--size-ignore window ignore))
a1511caf
MR
723 (window-size-fixed-p sub horizontal)))
724 (t
be7f5545 725 ;; We found a non-fixed-size child window.
a1511caf
MR
726 (throw 'done delta)))
727 (setq sub (window-right sub))))
728 ;; In an ortho-combination set DELTA to the minimum value by
be7f5545 729 ;; which other child windows can shrink.
a1511caf
MR
730 (while sub
731 (unless (eq sub window)
732 (setq delta
733 (min delta
734 (- (window-total-size sub horizontal)
735 (window-min-size sub horizontal ignore)))))
736 (setq sub (window-right sub))))
737 (if noup
738 delta
c56cad4a 739 (window--min-delta-1 parent delta horizontal ignore trail))))))
a1511caf
MR
740
741(defun window-min-delta (&optional window horizontal ignore trail noup nodown)
742 "Return number of lines by which WINDOW can be shrunk.
85c2386b
MR
743WINDOW must be a valid window and defaults to the selected one.
744Return zero if WINDOW cannot be shrunk.
a1511caf
MR
745
746Optional argument HORIZONTAL non-nil means return number of
747columns by which WINDOW can be shrunk.
748
2116e93c 749Optional argument IGNORE non-nil means ignore restrictions
a1511caf 750imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
751`window-min-width' settings. If IGNORE is a window, ignore
752restrictions for that window only. If IGNORE equals `safe',
a1511caf 753live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
754and `window-safe-min-width' columns. Any other non-nil value
755means ignore all of the above restrictions for all windows.
a1511caf 756
2116e93c
EZ
757Optional argument TRAIL restricts the windows that can be enlarged.
758If its value is `before', only windows to the left of or above WINDOW
759can be enlarged. If it is `after', only windows to the right of or
760below WINDOW can be enlarged.
a1511caf
MR
761
762Optional argument NOUP non-nil means don't go up in the window
2116e93c 763tree, but try to enlarge windows within WINDOW's combination only.
a1511caf
MR
764
765Optional argument NODOWN non-nil means don't check whether WINDOW
382c953b 766itself (and its child windows) can be shrunk; check only whether
b3f4a882 767at least one other window can be enlarged appropriately."
447f16b8 768 (setq window (window-normalize-window window))
a1511caf
MR
769 (let ((size (window-total-size window horizontal))
770 (minimum (window-min-size window horizontal ignore)))
771 (cond
772 (nodown
773 ;; If NODOWN is t, try to recover the entire size of WINDOW.
c56cad4a 774 (window--min-delta-1 window size horizontal ignore trail noup))
a1511caf
MR
775 ((= size minimum)
776 ;; If NODOWN is nil and WINDOW's size is already at its minimum,
777 ;; there's nothing to recover.
778 0)
779 (t
780 ;; Otherwise, try to recover whatever WINDOW is larger than its
781 ;; minimum size.
c56cad4a 782 (window--min-delta-1
a1511caf
MR
783 window (- size minimum) horizontal ignore trail noup)))))
784
c56cad4a 785(defun window--max-delta-1 (window delta &optional horizontal ignore trail noup)
a1511caf
MR
786 "Internal function of `window-max-delta'."
787 (if (not (window-parent window))
788 ;; Can't go up. Return DELTA.
789 delta
790 (let* ((parent (window-parent window))
791 (sub (window-child parent)))
792 (catch 'fixed
3d8daefe 793 (if (window-combined-p sub horizontal)
a1511caf 794 ;; For an iso-combination calculate how much we can get from
be7f5545 795 ;; other child windows.
a1511caf
MR
796 (let ((skip (eq trail 'after)))
797 (while sub
798 (cond
799 ((eq sub window)
800 (setq skip (eq trail 'before)))
801 (skip)
802 (t
803 (setq delta
804 (+ delta
805 (- (window-total-size sub horizontal)
806 (window-min-size sub horizontal ignore))))))
807 (setq sub (window-right sub))))
808 ;; For an ortho-combination throw DELTA when at least one
be7f5545 809 ;; child window is fixed-size.
a1511caf
MR
810 (while sub
811 (when (and (not (eq sub window))
5e92ca23 812 (not (window--size-ignore sub ignore))
a1511caf
MR
813 (window-size-fixed-p sub horizontal))
814 (throw 'fixed delta))
815 (setq sub (window-right sub))))
816 (if noup
817 ;; When NOUP is nil, DELTA is all we can get.
818 delta
819 ;; Else try with parent of WINDOW, passing the DELTA we
820 ;; recovered so far.
c56cad4a 821 (window--max-delta-1 parent delta horizontal ignore trail))))))
a1511caf
MR
822
823(defun window-max-delta (&optional window horizontal ignore trail noup nodown)
2116e93c 824 "Return maximum number of lines by which WINDOW can be enlarged.
85c2386b
MR
825WINDOW must be a valid window and defaults to the selected one.
826The return value is zero if WINDOW cannot be enlarged.
a1511caf
MR
827
828Optional argument HORIZONTAL non-nil means return maximum number
829of columns by which WINDOW can be enlarged.
830
2116e93c 831Optional argument IGNORE non-nil means ignore restrictions
a1511caf 832imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
833`window-min-width' settings. If IGNORE is a window, ignore
834restrictions for that window only. If IGNORE equals `safe',
a1511caf 835live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
836and `window-safe-min-width' columns. Any other non-nil value means
837ignore all of the above restrictions for all windows.
a1511caf 838
2116e93c
EZ
839Optional argument TRAIL restricts the windows that can be enlarged.
840If its value is `before', only windows to the left of or above WINDOW
841can be enlarged. If it is `after', only windows to the right of or
842below WINDOW can be enlarged.
a1511caf
MR
843
844Optional argument NOUP non-nil means don't go up in the window
845tree but try to obtain the entire space from windows within
846WINDOW's combination.
847
848Optional argument NODOWN non-nil means do not check whether
382c953b 849WINDOW itself (and its child windows) can be enlarged; check
be7f5545 850only whether other windows can be shrunk appropriately."
447f16b8 851 (setq window (window-normalize-window window))
5e92ca23 852 (if (and (not (window--size-ignore window ignore))
a1511caf
MR
853 (not nodown) (window-size-fixed-p window horizontal))
854 ;; With IGNORE and NOWDON nil return zero if WINDOW has fixed
855 ;; size.
856 0
857 ;; WINDOW has no fixed size.
c56cad4a 858 (window--max-delta-1 window 0 horizontal ignore trail noup)))
a1511caf
MR
859
860;; Make NOUP also inhibit the min-size check.
2cffd681 861(defun window--resizable (window delta &optional horizontal ignore trail noup nodown)
a1511caf 862 "Return DELTA if WINDOW can be resized vertically by DELTA lines.
85c2386b 863WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
864Optional argument HORIZONTAL non-nil means return DELTA if WINDOW
865can be resized horizontally by DELTA columns. A return value of
866zero means that WINDOW is not resizable.
867
868DELTA positive means WINDOW shall be enlarged by DELTA lines or
2cffd681 869columns. If WINDOW cannot be enlarged by DELTA lines or columns,
a1511caf
MR
870return the maximum value in the range 0..DELTA by which WINDOW
871can be enlarged.
872
873DELTA negative means WINDOW shall be shrunk by -DELTA lines or
874columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
875return the minimum value in the range DELTA..0 that can be used
876for shrinking WINDOW.
877
2116e93c 878Optional argument IGNORE non-nil means ignore restrictions
a1511caf 879imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
880`window-min-width' settings. If IGNORE is a window, ignore
881restrictions for that window only. If IGNORE equals `safe',
a1511caf 882live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
883and `window-safe-min-width' columns. Any other non-nil value
884means ignore all of the above restrictions for all windows.
a1511caf
MR
885
886Optional argument TRAIL `before' means only windows to the left
887of or below WINDOW can be shrunk. Optional argument TRAIL
888`after' means only windows to the right of or above WINDOW can be
889shrunk.
890
891Optional argument NOUP non-nil means don't go up in the window
2cffd681
MR
892tree but check only whether space can be obtained from (or given
893to) WINDOW's siblings.
a1511caf 894
2cffd681
MR
895Optional argument NODOWN non-nil means don't go down in the
896window tree. This means do not check whether resizing would
897violate size restrictions of WINDOW or its child windows."
447f16b8 898 (setq window (window-normalize-window window))
a1511caf
MR
899 (cond
900 ((< delta 0)
901 (max (- (window-min-delta window horizontal ignore trail noup nodown))
902 delta))
903 ((> delta 0)
904 (min (window-max-delta window horizontal ignore trail noup nodown)
905 delta))
906 (t 0)))
907
2cffd681 908(defun window--resizable-p (window delta &optional horizontal ignore trail noup nodown)
a1511caf 909 "Return t if WINDOW can be resized vertically by DELTA lines.
85c2386b 910WINDOW must be a valid window and defaults to the selected one.
a1511caf 911For the meaning of the arguments of this function see the
2cffd681 912doc-string of `window--resizable'."
447f16b8 913 (setq window (window-normalize-window window))
a1511caf 914 (if (> delta 0)
2cffd681 915 (>= (window--resizable window delta horizontal ignore trail noup nodown)
a1511caf 916 delta)
2cffd681 917 (<= (window--resizable window delta horizontal ignore trail noup nodown)
a1511caf
MR
918 delta)))
919
2cffd681
MR
920(defun window-resizable (window delta &optional horizontal ignore)
921 "Return DELTA if WINDOW can be resized vertically by DELTA lines.
85c2386b 922WINDOW must be a valid window and defaults to the selected one.
2cffd681
MR
923Optional argument HORIZONTAL non-nil means return DELTA if WINDOW
924can be resized horizontally by DELTA columns. A return value of
925zero means that WINDOW is not resizable.
926
927DELTA positive means WINDOW shall be enlarged by DELTA lines or
928columns. If WINDOW cannot be enlarged by DELTA lines or columns
929return the maximum value in the range 0..DELTA by which WINDOW
930can be enlarged.
931
932DELTA negative means WINDOW shall be shrunk by -DELTA lines or
933columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
934return the minimum value in the range DELTA..0 that can be used
935for shrinking WINDOW.
936
2116e93c 937Optional argument IGNORE non-nil means ignore restrictions
2cffd681 938imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
939`window-min-width' settings. If IGNORE is a window, ignore
940restrictions for that window only. If IGNORE equals `safe',
2cffd681 941live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
942and `window-safe-min-width' columns. Any other non-nil value
943means ignore all of the above restrictions for all windows."
2cffd681
MR
944 (setq window (window-normalize-window window))
945 (window--resizable window delta horizontal ignore))
946
105216ed 947(defun window-total-size (&optional window horizontal)
2116e93c 948 "Return the total height or width of WINDOW.
85c2386b 949WINDOW must be a valid window and defaults to the selected one.
105216ed
CY
950
951If HORIZONTAL is omitted or nil, return the total height of
952WINDOW, in lines, like `window-total-height'. Otherwise return
953the total width, in columns, like `window-total-width'."
954 (if horizontal
955 (window-total-width window)
956 (window-total-height window)))
3c448ab6 957
f3d1777e
MR
958;; Eventually we should make `window-height' obsolete.
959(defalias 'window-height 'window-total-height)
960
ccafbf06 961;; See discussion in bug#4543.
4b0d61e3 962(defun window-full-height-p (&optional window)
2116e93c 963 "Return t if WINDOW is as high as its containing frame.
a1511caf
MR
964More precisely, return t if and only if the total height of
965WINDOW equals the total height of the root window of WINDOW's
85c2386b
MR
966frame. WINDOW must be a valid window and defaults to the
967selected one."
447f16b8 968 (setq window (window-normalize-window window))
a1511caf
MR
969 (= (window-total-size window)
970 (window-total-size (frame-root-window window))))
971
4b0d61e3 972(defun window-full-width-p (&optional window)
2116e93c 973 "Return t if WINDOW is as wide as its containing frame.
a1511caf
MR
974More precisely, return t if and only if the total width of WINDOW
975equals the total width of the root window of WINDOW's frame.
85c2386b 976WINDOW must be a valid window and defaults to the selected one."
447f16b8 977 (setq window (window-normalize-window window))
a1511caf
MR
978 (= (window-total-size window t)
979 (window-total-size (frame-root-window window) t)))
980
105216ed
CY
981(defun window-body-size (&optional window horizontal)
982 "Return the height or width of WINDOW's text area.
85c2386b 983WINDOW must be a live window and defaults to the selected one.
105216ed
CY
984
985If HORIZONTAL is omitted or nil, return the height of the text
986area, like `window-body-height'. Otherwise, return the width of
987the text area, like `window-body-width'."
988 (if horizontal
989 (window-body-width window)
990 (window-body-height window)))
02c6f098 991
f3d1777e
MR
992;; Eventually we should make `window-height' obsolete.
993(defalias 'window-width 'window-body-width)
994
3c448ab6
MR
995(defun window-current-scroll-bars (&optional window)
996 "Return the current scroll bar settings for WINDOW.
387522b2 997WINDOW must be a live window and defaults to the selected one.
3c448ab6
MR
998
999The return value is a cons cell (VERTICAL . HORIZONTAL) where
1000VERTICAL specifies the current location of the vertical scroll
1001bars (`left', `right', or nil), and HORIZONTAL specifies the
1002current location of the horizontal scroll bars (`top', `bottom',
1003or nil).
1004
1005Unlike `window-scroll-bars', this function reports the scroll bar
1006type actually used, once frame defaults and `scroll-bar-mode' are
1007taken into account."
447f16b8 1008 (setq window (window-normalize-window window t))
3c448ab6
MR
1009 (let ((vert (nth 2 (window-scroll-bars window)))
1010 (hor nil))
1011 (when (or (eq vert t) (eq hor t))
387522b2 1012 (let ((fcsb (frame-current-scroll-bars (window-frame window))))
3c448ab6
MR
1013 (if (eq vert t)
1014 (setq vert (car fcsb)))
1015 (if (eq hor t)
1016 (setq hor (cdr fcsb)))))
1017 (cons vert hor)))
1018
c7635a97
CY
1019(defun walk-windows (fun &optional minibuf all-frames)
1020 "Cycle through all live windows, calling FUN for each one.
1021FUN must specify a function with a window as its sole argument.
3c448ab6 1022The optional arguments MINIBUF and ALL-FRAMES specify the set of
387522b2 1023windows to include in the walk.
3c448ab6
MR
1024
1025MINIBUF t means include the minibuffer window even if the
1026minibuffer is not active. MINIBUF nil or omitted means include
1027the minibuffer window only if the minibuffer is active. Any
1028other value means do not include the minibuffer window even if
1029the minibuffer is active.
1030
387522b2
MR
1031ALL-FRAMES nil or omitted means consider all windows on the
1032selected frame, plus the minibuffer window if specified by the
1033MINIBUF argument. If the minibuffer counts, consider all windows
1034on all frames that share that minibuffer too. The following
1035non-nil values of ALL-FRAMES have special meanings:
1036
1037- t means consider all windows on all existing frames.
1038
1039- `visible' means consider all windows on all visible frames on
1040 the current terminal.
1041
1042- 0 (the number zero) means consider all windows on all visible
1043 and iconified frames on the current terminal.
1044
1045- A frame means consider all windows on that frame only.
1046
1047Anything else means consider all windows on the selected frame
1048and no others.
3c448ab6
MR
1049
1050This function changes neither the order of recently selected
1051windows nor the buffer list."
1052 ;; If we start from the minibuffer window, don't fail to come
1053 ;; back to it.
1054 (when (window-minibuffer-p (selected-window))
1055 (setq minibuf t))
1056 ;; Make sure to not mess up the order of recently selected
1057 ;; windows. Use `save-selected-window' and `select-window'
1058 ;; with second argument non-nil for this purpose.
1059 (save-selected-window
1060 (when (framep all-frames)
1061 (select-window (frame-first-window all-frames) 'norecord))
387522b2 1062 (dolist (walk-windows-window (window-list-1 nil minibuf all-frames))
c7635a97 1063 (funcall fun walk-windows-window))))
387522b2 1064
e07b9a6d
MR
1065(defun window-at-side-p (&optional window side)
1066 "Return t if WINDOW is at SIDE of its containing frame.
85c2386b
MR
1067WINDOW must be a valid window and defaults to the selected one.
1068SIDE can be any of the symbols `left', `top', `right' or
1069`bottom'. The default value nil is handled like `bottom'."
447f16b8 1070 (setq window (window-normalize-window window))
e07b9a6d
MR
1071 (let ((edge
1072 (cond
1073 ((eq side 'left) 0)
1074 ((eq side 'top) 1)
1075 ((eq side 'right) 2)
1076 ((memq side '(bottom nil)) 3))))
1077 (= (nth edge (window-edges window))
1078 (nth edge (window-edges (frame-root-window window))))))
1079
54f9154c 1080(defun window-at-side-list (&optional frame side)
e07b9a6d
MR
1081 "Return list of all windows on SIDE of FRAME.
1082FRAME must be a live frame and defaults to the selected frame.
1083SIDE can be any of the symbols `left', `top', `right' or
1084`bottom'. The default value nil is handled like `bottom'."
1085 (setq frame (window-normalize-frame frame))
1086 (let (windows)
1087 (walk-window-tree
1088 (lambda (window)
1089 (when (window-at-side-p window side)
1090 (setq windows (cons window windows))))
1091 frame)
1092 (nreverse windows)))
1093
5e92ca23 1094(defun window--in-direction-2 (window posn &optional horizontal)
387522b2
MR
1095 "Support function for `window-in-direction'."
1096 (if horizontal
1097 (let ((top (window-top-line window)))
1098 (if (> top posn)
1099 (- top posn)
1100 (- posn top (window-total-height window))))
1101 (let ((left (window-left-column window)))
1102 (if (> left posn)
1103 (- left posn)
1104 (- posn left (window-total-width window))))))
1105
1106(defun window-in-direction (direction &optional window ignore)
1107 "Return window in DIRECTION as seen from WINDOW.
1108DIRECTION must be one of `above', `below', `left' or `right'.
1109WINDOW must be a live window and defaults to the selected one.
2116e93c 1110IGNORE non-nil means a window can be returned even if its
387522b2 1111`no-other-window' parameter is non-nil."
447f16b8 1112 (setq window (window-normalize-window window t))
387522b2
MR
1113 (unless (memq direction '(above below left right))
1114 (error "Wrong direction %s" direction))
1115 (let* ((frame (window-frame window))
1116 (hor (memq direction '(left right)))
1117 (first (if hor
1118 (window-left-column window)
1119 (window-top-line window)))
1120 (last (+ first (if hor
1121 (window-total-width window)
1122 (window-total-height window))))
5481664a 1123 (posn-cons (nth 6 (posn-at-point (window-point window) window)))
387522b2
MR
1124 ;; The column / row value of `posn-at-point' can be nil for the
1125 ;; mini-window, guard against that.
1126 (posn (if hor
1127 (+ (or (cdr posn-cons) 1) (window-top-line window))
1128 (+ (or (car posn-cons) 1) (window-left-column window))))
1129 (best-edge
1130 (cond
1131 ((eq direction 'below) (frame-height frame))
1132 ((eq direction 'right) (frame-width frame))
1133 (t -1)))
1134 (best-edge-2 best-edge)
1135 (best-diff-2 (if hor (frame-height frame) (frame-width frame)))
1136 best best-2 best-diff-2-new)
1137 (walk-window-tree
1138 (lambda (w)
1139 (let* ((w-top (window-top-line w))
1140 (w-left (window-left-column w)))
1141 (cond
1142 ((or (eq window w)
1143 ;; Ignore ourselves.
1144 (and (window-parameter w 'no-other-window)
1145 ;; Ignore W unless IGNORE is non-nil.
1146 (not ignore))))
1147 (hor
1148 (cond
1149 ((and (<= w-top posn)
1150 (< posn (+ w-top (window-total-height w))))
1151 ;; W is to the left or right of WINDOW and covers POSN.
1152 (when (or (and (eq direction 'left)
1153 (<= w-left first) (> w-left best-edge))
1154 (and (eq direction 'right)
1155 (>= w-left last) (< w-left best-edge)))
1156 (setq best-edge w-left)
1157 (setq best w)))
1158 ((and (or (and (eq direction 'left)
1159 (<= (+ w-left (window-total-width w)) first))
1160 (and (eq direction 'right) (<= last w-left)))
1161 ;; W is to the left or right of WINDOW but does not
1162 ;; cover POSN.
1163 (setq best-diff-2-new
5e92ca23 1164 (window--in-direction-2 w posn hor))
387522b2
MR
1165 (or (< best-diff-2-new best-diff-2)
1166 (and (= best-diff-2-new best-diff-2)
1167 (if (eq direction 'left)
1168 (> w-left best-edge-2)
1169 (< w-left best-edge-2)))))
1170 (setq best-edge-2 w-left)
1171 (setq best-diff-2 best-diff-2-new)
1172 (setq best-2 w))))
1173 (t
1174 (cond
1175 ((and (<= w-left posn)
1176 (< posn (+ w-left (window-total-width w))))
1177 ;; W is above or below WINDOW and covers POSN.
1178 (when (or (and (eq direction 'above)
1179 (<= w-top first) (> w-top best-edge))
1180 (and (eq direction 'below)
1181 (>= w-top first) (< w-top best-edge)))
1182 (setq best-edge w-top)
1183 (setq best w)))
1184 ((and (or (and (eq direction 'above)
1185 (<= (+ w-top (window-total-height w)) first))
1186 (and (eq direction 'below) (<= last w-top)))
1187 ;; W is above or below WINDOW but does not cover POSN.
1188 (setq best-diff-2-new
5e92ca23 1189 (window--in-direction-2 w posn hor))
387522b2
MR
1190 (or (< best-diff-2-new best-diff-2)
1191 (and (= best-diff-2-new best-diff-2)
1192 (if (eq direction 'above)
1193 (> w-top best-edge-2)
1194 (< w-top best-edge-2)))))
1195 (setq best-edge-2 w-top)
1196 (setq best-diff-2 best-diff-2-new)
1197 (setq best-2 w)))))))
1198 (window-frame window))
1199 (or best best-2)))
3c448ab6 1200
4c43d97b 1201(defun get-window-with-predicate (predicate &optional minibuf all-frames default)
387522b2
MR
1202 "Return a live window satisfying PREDICATE.
1203More precisely, cycle through all windows calling the function
1204PREDICATE on each one of them with the window as its sole
1205argument. Return the first window for which PREDICATE returns
4c43d97b 1206non-nil. Windows are scanned starting with the window following
c80e3b4a 1207the selected window. If no window satisfies PREDICATE, return
4c43d97b
MR
1208DEFAULT.
1209
1210MINIBUF t means include the minibuffer window even if the
1211minibuffer is not active. MINIBUF nil or omitted means include
1212the minibuffer window only if the minibuffer is active. Any
1213other value means do not include the minibuffer window even if
1214the minibuffer is active.
387522b2
MR
1215
1216ALL-FRAMES nil or omitted means consider all windows on the selected
1217frame, plus the minibuffer window if specified by the MINIBUF
1218argument. If the minibuffer counts, consider all windows on all
1219frames that share that minibuffer too. The following non-nil
1220values of ALL-FRAMES have special meanings:
3c448ab6 1221
387522b2
MR
1222- t means consider all windows on all existing frames.
1223
1224- `visible' means consider all windows on all visible frames on
1225 the current terminal.
1226
1227- 0 (the number zero) means consider all windows on all visible
1228 and iconified frames on the current terminal.
1229
1230- A frame means consider all windows on that frame only.
1231
1232Anything else means consider all windows on the selected frame
1233and no others."
3c448ab6 1234 (catch 'found
4c43d97b
MR
1235 (dolist (window (window-list-1
1236 (next-window nil minibuf all-frames)
1237 minibuf all-frames))
387522b2
MR
1238 (when (funcall predicate window)
1239 (throw 'found window)))
3c448ab6
MR
1240 default))
1241
1242(defalias 'some-window 'get-window-with-predicate)
1243
51a5f9d8 1244(defun get-lru-window (&optional all-frames dedicated not-selected)
190b47e6
MR
1245 "Return the least recently used window on frames specified by ALL-FRAMES.
1246Return a full-width window if possible. A minibuffer window is
1247never a candidate. A dedicated window is never a candidate
1248unless DEDICATED is non-nil, so if all windows are dedicated, the
1249value is nil. Avoid returning the selected window if possible.
51a5f9d8
MR
1250Optional argument NOT-SELECTED non-nil means never return the
1251selected window.
190b47e6
MR
1252
1253The following non-nil values of the optional argument ALL-FRAMES
1254have special meanings:
1255
1256- t means consider all windows on all existing frames.
1257
1258- `visible' means consider all windows on all visible frames on
1259 the current terminal.
1260
1261- 0 (the number zero) means consider all windows on all visible
1262 and iconified frames on the current terminal.
1263
1264- A frame means consider all windows on that frame only.
1265
1266Any other value of ALL-FRAMES means consider all windows on the
1267selected frame and no others."
1268 (let (best-window best-time second-best-window second-best-time time)
02cfc6d6 1269 (dolist (window (window-list-1 nil 'nomini all-frames))
51a5f9d8
MR
1270 (when (and (or dedicated (not (window-dedicated-p window)))
1271 (or (not not-selected) (not (eq window (selected-window)))))
190b47e6
MR
1272 (setq time (window-use-time window))
1273 (if (or (eq window (selected-window))
1274 (not (window-full-width-p window)))
1275 (when (or (not second-best-time) (< time second-best-time))
1276 (setq second-best-time time)
1277 (setq second-best-window window))
1278 (when (or (not best-time) (< time best-time))
1279 (setq best-time time)
1280 (setq best-window window)))))
1281 (or best-window second-best-window)))
1282
51a5f9d8 1283(defun get-mru-window (&optional all-frames dedicated not-selected)
387522b2 1284 "Return the most recently used window on frames specified by ALL-FRAMES.
51a5f9d8
MR
1285A minibuffer window is never a candidate. A dedicated window is
1286never a candidate unless DEDICATED is non-nil, so if all windows
1287are dedicated, the value is nil. Optional argument NOT-SELECTED
1288non-nil means never return the selected window.
387522b2
MR
1289
1290The following non-nil values of the optional argument ALL-FRAMES
1291have special meanings:
1292
1293- t means consider all windows on all existing frames.
1294
1295- `visible' means consider all windows on all visible frames on
1296 the current terminal.
1297
1298- 0 (the number zero) means consider all windows on all visible
1299 and iconified frames on the current terminal.
1300
1301- A frame means consider all windows on that frame only.
1302
1303Any other value of ALL-FRAMES means consider all windows on the
1304selected frame and no others."
1305 (let (best-window best-time time)
02cfc6d6 1306 (dolist (window (window-list-1 nil 'nomini all-frames))
387522b2 1307 (setq time (window-use-time window))
51a5f9d8
MR
1308 (when (and (or dedicated (not (window-dedicated-p window)))
1309 (or (not not-selected) (not (eq window (selected-window))))
1310 (or (not best-time) (> time best-time)))
387522b2
MR
1311 (setq best-time time)
1312 (setq best-window window)))
1313 best-window))
1314
51a5f9d8 1315(defun get-largest-window (&optional all-frames dedicated not-selected)
190b47e6
MR
1316 "Return the largest window on frames specified by ALL-FRAMES.
1317A minibuffer window is never a candidate. A dedicated window is
1318never a candidate unless DEDICATED is non-nil, so if all windows
51a5f9d8
MR
1319are dedicated, the value is nil. Optional argument NOT-SELECTED
1320non-nil means never return the selected window.
190b47e6
MR
1321
1322The following non-nil values of the optional argument ALL-FRAMES
1323have special meanings:
1324
1325- t means consider all windows on all existing frames.
1326
1327- `visible' means consider all windows on all visible frames on
1328 the current terminal.
1329
1330- 0 (the number zero) means consider all windows on all visible
1331 and iconified frames on the current terminal.
1332
1333- A frame means consider all windows on that frame only.
1334
1335Any other value of ALL-FRAMES means consider all windows on the
1336selected frame and no others."
1337 (let ((best-size 0)
1338 best-window size)
02cfc6d6 1339 (dolist (window (window-list-1 nil 'nomini all-frames))
51a5f9d8
MR
1340 (when (and (or dedicated (not (window-dedicated-p window)))
1341 (or (not not-selected) (not (eq window (selected-window)))))
190b47e6
MR
1342 (setq size (* (window-total-size window)
1343 (window-total-size window t)))
1344 (when (> size best-size)
1345 (setq best-size size)
1346 (setq best-window window))))
1347 best-window))
1348
3c448ab6
MR
1349(defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames)
1350 "Return list of all windows displaying BUFFER-OR-NAME, or nil if none.
1351BUFFER-OR-NAME may be a buffer or the name of an existing buffer
4c43d97b
MR
1352and defaults to the current buffer. Windows are scanned starting
1353with the selected window.
190b47e6
MR
1354
1355MINIBUF t means include the minibuffer window even if the
1356minibuffer is not active. MINIBUF nil or omitted means include
1357the minibuffer window only if the minibuffer is active. Any
1358other value means do not include the minibuffer window even if
1359the minibuffer is active.
1360
1361ALL-FRAMES nil or omitted means consider all windows on the
1362selected frame, plus the minibuffer window if specified by the
1363MINIBUF argument. If the minibuffer counts, consider all windows
1364on all frames that share that minibuffer too. The following
1365non-nil values of ALL-FRAMES have special meanings:
1366
1367- t means consider all windows on all existing frames.
1368
1369- `visible' means consider all windows on all visible frames on
1370 the current terminal.
1371
1372- 0 (the number zero) means consider all windows on all visible
1373 and iconified frames on the current terminal.
1374
1375- A frame means consider all windows on that frame only.
1376
1377Anything else means consider all windows on the selected frame
1378and no others."
5386012d 1379 (let ((buffer (window-normalize-buffer buffer-or-name))
3c448ab6 1380 windows)
4c43d97b 1381 (dolist (window (window-list-1 (selected-window) minibuf all-frames))
190b47e6
MR
1382 (when (eq (window-buffer window) buffer)
1383 (setq windows (cons window windows))))
1384 (nreverse windows)))
3c448ab6
MR
1385
1386(defun minibuffer-window-active-p (window)
1387 "Return t if WINDOW is the currently active minibuffer window."
1388 (eq window (active-minibuffer-window)))
387522b2 1389
3c448ab6 1390(defun count-windows (&optional minibuf)
387522b2 1391 "Return the number of live windows on the selected frame.
3c448ab6
MR
1392The optional argument MINIBUF specifies whether the minibuffer
1393window shall be counted. See `walk-windows' for the precise
1394meaning of this argument."
387522b2 1395 (length (window-list-1 nil minibuf)))
9aab8e0d
MR
1396\f
1397;;; Resizing windows.
5386012d 1398(defun window--resize-reset (&optional frame horizontal)
9aab8e0d
MR
1399 "Reset resize values for all windows on FRAME.
1400FRAME defaults to the selected frame.
1401
1402This function stores the current value of `window-total-size' applied
1403with argument HORIZONTAL in the new total size of all windows on
1404FRAME. It also resets the new normal size of each of these
1405windows."
5386012d
MR
1406 (window--resize-reset-1
1407 (frame-root-window (window-normalize-frame frame)) horizontal))
9aab8e0d 1408
5386012d
MR
1409(defun window--resize-reset-1 (window horizontal)
1410 "Internal function of `window--resize-reset'."
9aab8e0d
MR
1411 ;; Register old size in the new total size.
1412 (set-window-new-total window (window-total-size window horizontal))
1413 ;; Reset new normal size.
1414 (set-window-new-normal window)
1415 (when (window-child window)
5386012d 1416 (window--resize-reset-1 (window-child window) horizontal))
9aab8e0d 1417 (when (window-right window)
5386012d 1418 (window--resize-reset-1 (window-right window) horizontal)))
9aab8e0d 1419
562dd5e9
MR
1420;; The following routine is used to manually resize the minibuffer
1421;; window and is currently used, for example, by ispell.el.
5386012d 1422(defun window--resize-mini-window (window delta)
562dd5e9 1423 "Resize minibuffer window WINDOW by DELTA lines.
382c953b 1424If WINDOW cannot be resized by DELTA lines make it as large (or
2116e93c 1425as small) as possible, but don't signal an error."
562dd5e9
MR
1426 (when (window-minibuffer-p window)
1427 (let* ((frame (window-frame window))
1428 (root (frame-root-window frame))
1429 (height (window-total-size window))
1430 (min-delta
1431 (- (window-total-size root)
1432 (window-min-size root))))
1433 ;; Sanitize DELTA.
1434 (cond
1435 ((<= (+ height delta) 0)
1436 (setq delta (- (- height 1))))
1437 ((> delta min-delta)
1438 (setq delta min-delta)))
1439
1440 ;; Resize now.
5386012d 1441 (window--resize-reset frame)
be7f5545
MR
1442 ;; Ideally we should be able to resize just the last child of root
1443 ;; here. See the comment in `resize-root-window-vertically' for
1444 ;; why we do not do that.
5386012d 1445 (window--resize-this-window root (- delta) nil nil t)
562dd5e9
MR
1446 (set-window-new-total window (+ height delta))
1447 ;; The following routine catches the case where we want to resize
1448 ;; a minibuffer-only frame.
1449 (resize-mini-window-internal window))))
1450
d615d6d2 1451(defun window-resize (window delta &optional horizontal ignore)
562dd5e9
MR
1452 "Resize WINDOW vertically by DELTA lines.
1453WINDOW can be an arbitrary window and defaults to the selected
1454one. An attempt to resize the root window of a frame will raise
1455an error though.
1456
1457DELTA a positive number means WINDOW shall be enlarged by DELTA
1458lines. DELTA negative means WINDOW shall be shrunk by -DELTA
1459lines.
1460
1461Optional argument HORIZONTAL non-nil means resize WINDOW
1462horizontally by DELTA columns. In this case a positive DELTA
1463means enlarge WINDOW by DELTA columns. DELTA negative means
1464WINDOW shall be shrunk by -DELTA columns.
1465
2116e93c 1466Optional argument IGNORE non-nil means ignore restrictions
562dd5e9 1467imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
1468`window-min-width' settings. If IGNORE is a window, ignore
1469restrictions for that window only. If IGNORE equals `safe',
562dd5e9 1470live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
1471and `window-safe-min-width' columns. Any other non-nil value
1472means ignore all of the above restrictions for all windows.
562dd5e9
MR
1473
1474This function resizes other windows proportionally and never
1475deletes any windows. If you want to move only the low (right)
1476edge of WINDOW consider using `adjust-window-trailing-edge'
1477instead."
447f16b8 1478 (setq window (window-normalize-window window))
562dd5e9 1479 (let* ((frame (window-frame window))
feeb6f53 1480 (minibuffer-window (minibuffer-window frame))
562dd5e9
MR
1481 sibling)
1482 (cond
1483 ((eq window (frame-root-window frame))
1484 (error "Cannot resize the root window of a frame"))
1485 ((window-minibuffer-p window)
41cfe0cb
MR
1486 (if horizontal
1487 (error "Cannot resize minibuffer window horizontally")
1488 (window--resize-mini-window window delta)))
feeb6f53
MR
1489 ((and (not horizontal)
1490 (window-full-height-p window)
1491 (eq (window-frame minibuffer-window) frame)
1492 (or (not resize-mini-windows)
1493 (eq minibuffer-window (active-minibuffer-window))))
1494 ;; If WINDOW is full height and either `resize-mini-windows' is
1495 ;; nil or the minibuffer window is active, resize the minibuffer
1496 ;; window.
1497 (window--resize-mini-window minibuffer-window (- delta)))
2cffd681 1498 ((window--resizable-p window delta horizontal ignore)
5386012d
MR
1499 (window--resize-reset frame horizontal)
1500 (window--resize-this-window window delta horizontal ignore t)
a0c2d0ae 1501 (if (and (not window-combination-resize)
3d8daefe 1502 (window-combined-p window horizontal)
562dd5e9
MR
1503 (setq sibling (or (window-right window) (window-left window)))
1504 (window-sizable-p sibling (- delta) horizontal ignore))
a0c2d0ae 1505 ;; If window-combination-resize is nil, WINDOW is part of an
89d61221 1506 ;; iso-combination, and WINDOW's neighboring right or left
562dd5e9
MR
1507 ;; sibling can be resized as requested, resize that sibling.
1508 (let ((normal-delta
1509 (/ (float delta)
1510 (window-total-size (window-parent window) horizontal))))
5386012d 1511 (window--resize-this-window sibling (- delta) horizontal nil t)
562dd5e9
MR
1512 (set-window-new-normal
1513 window (+ (window-normal-size window horizontal)
1514 normal-delta))
1515 (set-window-new-normal
1516 sibling (- (window-normal-size sibling horizontal)
1517 normal-delta)))
1518 ;; Otherwise, resize all other windows in the same combination.
5386012d 1519 (window--resize-siblings window delta horizontal ignore))
d615d6d2 1520 (window-resize-apply frame horizontal))
562dd5e9
MR
1521 (t
1522 (error "Cannot resize window %s" window)))))
1523
4b0d61e3 1524(defun window--resize-child-windows-skip-p (window)
9aab8e0d
MR
1525 "Return non-nil if WINDOW shall be skipped by resizing routines."
1526 (memq (window-new-normal window) '(ignore stuck skip)))
1527
be7f5545
MR
1528(defun window--resize-child-windows-normal (parent horizontal window this-delta &optional trail other-delta)
1529 "Recursively set new normal height of child windows of window PARENT.
9aab8e0d 1530HORIZONTAL non-nil means set the new normal width of these
be7f5545 1531windows. WINDOW specifies a child window of PARENT that has been
382c953b 1532resized by THIS-DELTA lines (columns).
9aab8e0d 1533
2116e93c
EZ
1534Optional argument TRAIL either `before' or `after' means set values
1535only for windows before or after WINDOW. Optional argument
1536OTHER-DELTA, a number, specifies that this many lines (columns)
382c953b 1537have been obtained from (or returned to) an ancestor window of
9aab8e0d
MR
1538PARENT in order to resize WINDOW."
1539 (let* ((delta-normal
1540 (if (and (= (- this-delta) (window-total-size window horizontal))
1541 (zerop other-delta))
1542 ;; When WINDOW gets deleted and we can return its entire
1543 ;; space to its siblings, use WINDOW's normal size as the
1544 ;; normal delta.
1545 (- (window-normal-size window horizontal))
1546 ;; In any other case calculate the normal delta from the
1547 ;; relation of THIS-DELTA to the total size of PARENT.
1548 (/ (float this-delta) (window-total-size parent horizontal))))
1549 (sub (window-child parent))
1550 (parent-normal 0.0)
1551 (skip (eq trail 'after)))
1552
be7f5545
MR
1553 ;; Set parent-normal to the sum of the normal sizes of all child
1554 ;; windows of PARENT that shall be resized, excluding only WINDOW
9aab8e0d
MR
1555 ;; and any windows specified by the optional TRAIL argument.
1556 (while sub
1557 (cond
1558 ((eq sub window)
1559 (setq skip (eq trail 'before)))
1560 (skip)
1561 (t
1562 (setq parent-normal
1563 (+ parent-normal (window-normal-size sub horizontal)))))
1564 (setq sub (window-right sub)))
1565
be7f5545 1566 ;; Set the new normal size of all child windows of PARENT from what
9aab8e0d
MR
1567 ;; they should have contributed for recovering THIS-DELTA lines
1568 ;; (columns).
1569 (setq sub (window-child parent))
1570 (setq skip (eq trail 'after))
1571 (while sub
1572 (cond
1573 ((eq sub window)
1574 (setq skip (eq trail 'before)))
1575 (skip)
1576 (t
1577 (let ((old-normal (window-normal-size sub horizontal)))
1578 (set-window-new-normal
1579 sub (min 1.0 ; Don't get larger than 1.
1580 (max (- old-normal
1581 (* (/ old-normal parent-normal)
1582 delta-normal))
1583 ;; Don't drop below 0.
1584 0.0))))))
1585 (setq sub (window-right sub)))
1586
1587 (when (numberp other-delta)
1588 ;; Set the new normal size of windows from what they should have
1589 ;; contributed for recovering OTHER-DELTA lines (columns).
1590 (setq delta-normal (/ (float (window-total-size parent horizontal))
1591 (+ (window-total-size parent horizontal)
1592 other-delta)))
1593 (setq sub (window-child parent))
1594 (setq skip (eq trail 'after))
1595 (while sub
1596 (cond
1597 ((eq sub window)
1598 (setq skip (eq trail 'before)))
1599 (skip)
1600 (t
1601 (set-window-new-normal
1602 sub (min 1.0 ; Don't get larger than 1.
1603 (max (* (window-new-normal sub) delta-normal)
1604 ;; Don't drop below 0.
1605 0.0)))))
1606 (setq sub (window-right sub))))
1607
1608 ;; Set the new normal size of WINDOW to what is left by the sum of
1609 ;; the normal sizes of its siblings.
1610 (set-window-new-normal
1611 window
1612 (let ((sum 0))
1613 (setq sub (window-child parent))
1614 (while sub
1615 (cond
1616 ((eq sub window))
1617 ((not (numberp (window-new-normal sub)))
1618 (setq sum (+ sum (window-normal-size sub horizontal))))
1619 (t
1620 (setq sum (+ sum (window-new-normal sub)))))
1621 (setq sub (window-right sub)))
1622 ;; Don't get larger than 1 or smaller than 0.
1623 (min 1.0 (max (- 1.0 sum) 0.0))))))
1624
be7f5545
MR
1625(defun window--resize-child-windows (parent delta &optional horizontal window ignore trail edge)
1626 "Resize child windows of window PARENT vertically by DELTA lines.
9aab8e0d
MR
1627PARENT must be a vertically combined internal window.
1628
be7f5545 1629Optional argument HORIZONTAL non-nil means resize child windows of
9aab8e0d
MR
1630PARENT horizontally by DELTA columns. In this case PARENT must
1631be a horizontally combined internal window.
1632
1633WINDOW, if specified, must denote a child window of PARENT that
1634is resized by DELTA lines.
1635
2116e93c 1636Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 1637imposed by fixed size windows, `window-min-height' or
2116e93c 1638`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 1639windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
1640`window-safe-min-width' columns. If IGNORE is a window, ignore
1641restrictions for that window only. Any other non-nil value means
1642ignore all of the above restrictions for all windows.
9aab8e0d
MR
1643
1644Optional arguments TRAIL and EDGE, when non-nil, restrict the set
1645of windows that shall be resized. If TRAIL equals `before',
1646resize only windows on the left or above EDGE. If TRAIL equals
1647`after', resize only windows on the right or below EDGE. Also,
1648preferably only resize windows adjacent to EDGE.
1649
1650Return the symbol `normalized' if new normal sizes have been
1651already set by this routine."
1652 (let* ((first (window-child parent))
1653 (sub first)
1654 (parent-total (+ (window-total-size parent horizontal) delta))
1655 best-window best-value)
1656
1657 (if (and edge (memq trail '(before after))
1658 (progn
1659 (setq sub first)
1660 (while (and (window-right sub)
1661 (or (and (eq trail 'before)
be7f5545 1662 (not (window--resize-child-windows-skip-p
9aab8e0d
MR
1663 (window-right sub))))
1664 (and (eq trail 'after)
be7f5545 1665 (window--resize-child-windows-skip-p sub))))
9aab8e0d
MR
1666 (setq sub (window-right sub)))
1667 sub)
1668 (if horizontal
1669 (if (eq trail 'before)
1670 (= (+ (window-left-column sub)
1671 (window-total-size sub t))
1672 edge)
1673 (= (window-left-column sub) edge))
1674 (if (eq trail 'before)
1675 (= (+ (window-top-line sub)
1676 (window-total-size sub))
1677 edge)
1678 (= (window-top-line sub) edge)))
1679 (window-sizable-p sub delta horizontal ignore))
1680 ;; Resize only windows adjacent to EDGE.
1681 (progn
5386012d
MR
1682 (window--resize-this-window
1683 sub delta horizontal ignore t trail edge)
9aab8e0d
MR
1684 (if (and window (eq (window-parent sub) parent))
1685 (progn
1686 ;; Assign new normal sizes.
1687 (set-window-new-normal
1688 sub (/ (float (window-new-total sub)) parent-total))
1689 (set-window-new-normal
1690 window (- (window-normal-size window horizontal)
1691 (- (window-new-normal sub)
1692 (window-normal-size sub horizontal)))))
be7f5545 1693 (window--resize-child-windows-normal
5386012d
MR
1694 parent horizontal sub 0 trail delta))
1695 ;; Return 'normalized to notify `window--resize-siblings' that
9aab8e0d
MR
1696 ;; normal sizes have been already set.
1697 'normalized)
1698 ;; Resize all windows proportionally.
1699 (setq sub first)
1700 (while sub
1701 (cond
be7f5545
MR
1702 ((or (window--resize-child-windows-skip-p sub)
1703 ;; Ignore windows to skip and fixed-size child windows -
1704 ;; in the latter case make it a window to skip.
9aab8e0d
MR
1705 (and (not ignore)
1706 (window-size-fixed-p sub horizontal)
1707 (set-window-new-normal sub 'ignore))))
1708 ((< delta 0)
1709 ;; When shrinking store the number of lines/cols we can get
1710 ;; from this window here together with the total/normal size
1711 ;; factor.
1712 (set-window-new-normal
1713 sub
1714 (cons
1715 ;; We used to call this with NODOWN t, "fixed" 2011-05-11.
1716 (window-min-delta sub horizontal ignore trail t) ; t)
1717 (- (/ (float (window-total-size sub horizontal))
1718 parent-total)
1719 (window-normal-size sub horizontal)))))
1720 ((> delta 0)
1721 ;; When enlarging store the total/normal size factor only
1722 (set-window-new-normal
1723 sub
1724 (- (/ (float (window-total-size sub horizontal))
1725 parent-total)
1726 (window-normal-size sub horizontal)))))
1727
1728 (setq sub (window-right sub)))
1729
1730 (cond
1731 ((< delta 0)
1732 ;; Shrink windows by delta.
1733 (setq best-window t)
1734 (while (and best-window (not (zerop delta)))
1735 (setq sub first)
1736 (setq best-window nil)
1737 (setq best-value most-negative-fixnum)
1738 (while sub
1739 (when (and (consp (window-new-normal sub))
1740 (not (zerop (car (window-new-normal sub))))
1741 (> (cdr (window-new-normal sub)) best-value))
1742 (setq best-window sub)
1743 (setq best-value (cdr (window-new-normal sub))))
1744
1745 (setq sub (window-right sub)))
1746
1747 (when best-window
1748 (setq delta (1+ delta)))
1749 (set-window-new-total best-window -1 t)
1750 (set-window-new-normal
1751 best-window
1752 (if (= (car (window-new-normal best-window)) 1)
1753 'skip ; We can't shrink best-window any further.
1754 (cons (1- (car (window-new-normal best-window)))
1755 (- (/ (float (window-new-total best-window))
1756 parent-total)
1757 (window-normal-size best-window horizontal)))))))
1758 ((> delta 0)
1759 ;; Enlarge windows by delta.
1760 (setq best-window t)
1761 (while (and best-window (not (zerop delta)))
1762 (setq sub first)
1763 (setq best-window nil)
1764 (setq best-value most-positive-fixnum)
1765 (while sub
1766 (when (and (numberp (window-new-normal sub))
1767 (< (window-new-normal sub) best-value))
1768 (setq best-window sub)
1769 (setq best-value (window-new-normal sub)))
1770
1771 (setq sub (window-right sub)))
1772
1773 (when best-window
1774 (setq delta (1- delta)))
1775 (set-window-new-total best-window 1 t)
1776 (set-window-new-normal
1777 best-window
1778 (- (/ (float (window-new-total best-window))
1779 parent-total)
1780 (window-normal-size best-window horizontal))))))
1781
1782 (when best-window
1783 (setq sub first)
1784 (while sub
1785 (when (or (consp (window-new-normal sub))
1786 (numberp (window-new-normal sub)))
d615d6d2 1787 ;; Reset new normal size fields so `window-resize-apply'
9aab8e0d
MR
1788 ;; won't use them to apply new sizes.
1789 (set-window-new-normal sub))
1790
1791 (unless (eq (window-new-normal sub) 'ignore)
be7f5545 1792 ;; Resize this window's child windows (back-engineering
9aab8e0d
MR
1793 ;; delta from sub's old and new total sizes).
1794 (let ((delta (- (window-new-total sub)
1795 (window-total-size sub horizontal))))
1796 (unless (and (zerop delta) (not trail))
1797 ;; For the TRAIL non-nil case we have to resize SUB
1798 ;; recursively even if it's size does not change.
5386012d 1799 (window--resize-this-window
9aab8e0d
MR
1800 sub delta horizontal ignore nil trail edge))))
1801 (setq sub (window-right sub)))))))
1802
5386012d 1803(defun window--resize-siblings (window delta &optional horizontal ignore trail edge)
9aab8e0d
MR
1804 "Resize other windows when WINDOW is resized vertically by DELTA lines.
1805Optional argument HORIZONTAL non-nil means resize other windows
1806when WINDOW is resized horizontally by DELTA columns. WINDOW
1807itself is not resized by this function.
1808
2116e93c 1809Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 1810imposed by fixed size windows, `window-min-height' or
2116e93c 1811`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 1812windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
1813`window-safe-min-width' columns. If IGNORE is a window, ignore
1814restrictions for that window only. Any other non-nil value means
1815ignore all of the above restrictions for all windows.
9aab8e0d
MR
1816
1817Optional arguments TRAIL and EDGE, when non-nil, refine the set
1818of windows that shall be resized. If TRAIL equals `before',
1819resize only windows on the left or above EDGE. If TRAIL equals
1820`after', resize only windows on the right or below EDGE. Also,
1821preferably only resize windows adjacent to EDGE."
1822 (when (window-parent window)
1823 (let* ((parent (window-parent window))
1824 (sub (window-child parent)))
3d8daefe 1825 (if (window-combined-p sub horizontal)
9aab8e0d
MR
1826 ;; In an iso-combination try to extract DELTA from WINDOW's
1827 ;; siblings.
cb882333 1828 (let ((skip (eq trail 'after))
9aab8e0d
MR
1829 this-delta other-delta)
1830 ;; Decide which windows shall be left alone.
1831 (while sub
1832 (cond
1833 ((eq sub window)
1834 ;; Make sure WINDOW is left alone when
1835 ;; resizing its siblings.
1836 (set-window-new-normal sub 'ignore)
1837 (setq skip (eq trail 'before)))
1838 (skip
1839 ;; Make sure this sibling is left alone when
1840 ;; resizing its siblings.
1841 (set-window-new-normal sub 'ignore))
5e92ca23 1842 ((or (window--size-ignore sub ignore)
9aab8e0d
MR
1843 (not (window-size-fixed-p sub horizontal)))
1844 ;; Set this-delta to t to signal that we found a sibling
1845 ;; of WINDOW whose size is not fixed.
1846 (setq this-delta t)))
1847
1848 (setq sub (window-right sub)))
1849
1850 ;; Set this-delta to what we can get from WINDOW's siblings.
1851 (if (= (- delta) (window-total-size window horizontal))
1852 ;; A deletion, presumably. We must handle this case
2cffd681 1853 ;; specially since `window--resizable' can't be used.
9aab8e0d
MR
1854 (if this-delta
1855 ;; There's at least one resizable sibling we can
1856 ;; give WINDOW's size to.
1857 (setq this-delta delta)
1858 ;; No resizable sibling exists.
1859 (setq this-delta 0))
1860 ;; Any other form of resizing.
1861 (setq this-delta
2cffd681 1862 (window--resizable window delta horizontal ignore trail t)))
9aab8e0d
MR
1863
1864 ;; Set other-delta to what we still have to get from
1865 ;; ancestor windows of parent.
1866 (setq other-delta (- delta this-delta))
1867 (unless (zerop other-delta)
1868 ;; Unless we got everything from WINDOW's siblings, PARENT
1869 ;; must be resized by other-delta lines or columns.
1870 (set-window-new-total parent other-delta 'add))
1871
1872 (if (zerop this-delta)
1873 ;; We haven't got anything from WINDOW's siblings but we
1874 ;; must update the normal sizes to respect other-delta.
be7f5545 1875 (window--resize-child-windows-normal
9aab8e0d
MR
1876 parent horizontal window this-delta trail other-delta)
1877 ;; We did get something from WINDOW's siblings which means
be7f5545
MR
1878 ;; we have to resize their child windows.
1879 (unless (eq (window--resize-child-windows
5386012d
MR
1880 parent (- this-delta) horizontal
1881 window ignore trail edge)
be7f5545 1882 ;; If `window--resize-child-windows' returns
5386012d
MR
1883 ;; 'normalized, this means it has set the
1884 ;; normal sizes already.
9aab8e0d
MR
1885 'normalized)
1886 ;; Set the normal sizes.
be7f5545 1887 (window--resize-child-windows-normal
9aab8e0d
MR
1888 parent horizontal window this-delta trail other-delta))
1889 ;; Set DELTA to what we still have to get from ancestor
1890 ;; windows.
1891 (setq delta other-delta)))
1892
1893 ;; In an ortho-combination all siblings of WINDOW must be
1894 ;; resized by DELTA.
1895 (set-window-new-total parent delta 'add)
1896 (while sub
1897 (unless (eq sub window)
5386012d 1898 (window--resize-this-window sub delta horizontal ignore t))
9aab8e0d
MR
1899 (setq sub (window-right sub))))
1900
1901 (unless (zerop delta)
1902 ;; "Go up."
5386012d
MR
1903 (window--resize-siblings
1904 parent delta horizontal ignore trail edge)))))
9aab8e0d 1905
5386012d 1906(defun window--resize-this-window (window delta &optional horizontal ignore add trail edge)
9aab8e0d
MR
1907 "Resize WINDOW vertically by DELTA lines.
1908Optional argument HORIZONTAL non-nil means resize WINDOW
1909horizontally by DELTA columns.
1910
2116e93c 1911Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 1912imposed by fixed size windows, `window-min-height' or
2116e93c 1913`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 1914windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
1915`window-safe-min-width' columns. If IGNORE is a window, ignore
1916restrictions for that window only. Any other non-nil value
1917means ignore all of the above restrictions for all windows.
9aab8e0d
MR
1918
1919Optional argument ADD non-nil means add DELTA to the new total
1920size of WINDOW.
1921
1922Optional arguments TRAIL and EDGE, when non-nil, refine the set
1923of windows that shall be resized. If TRAIL equals `before',
1924resize only windows on the left or above EDGE. If TRAIL equals
1925`after', resize only windows on the right or below EDGE. Also,
1926preferably only resize windows adjacent to EDGE.
1927
be7f5545 1928This function recursively resizes WINDOW's child windows to fit the
2cffd681 1929new size. Make sure that WINDOW is `window--resizable' before
9aab8e0d
MR
1930calling this function. Note that this function does not resize
1931siblings of WINDOW or WINDOW's parent window. You have to
d615d6d2 1932eventually call `window-resize-apply' in order to make resizing
9aab8e0d
MR
1933actually take effect."
1934 (when add
1935 ;; Add DELTA to the new total size of WINDOW.
1936 (set-window-new-total window delta t))
387522b2 1937
9aab8e0d
MR
1938 (let ((sub (window-child window)))
1939 (cond
1940 ((not sub))
3d8daefe 1941 ((window-combined-p sub horizontal)
be7f5545 1942 ;; In an iso-combination resize child windows according to their
9aab8e0d 1943 ;; normal sizes.
be7f5545 1944 (window--resize-child-windows
5386012d 1945 window delta horizontal nil ignore trail edge))
be7f5545 1946 ;; In an ortho-combination resize each child window by DELTA.
9aab8e0d
MR
1947 (t
1948 (while sub
5386012d
MR
1949 (window--resize-this-window
1950 sub delta horizontal ignore t trail edge)
9aab8e0d
MR
1951 (setq sub (window-right sub)))))))
1952
5386012d 1953(defun window--resize-root-window (window delta horizontal ignore)
9aab8e0d
MR
1954 "Resize root window WINDOW vertically by DELTA lines.
1955HORIZONTAL non-nil means resize root window WINDOW horizontally
1956by DELTA columns.
1957
1958IGNORE non-nil means ignore any restrictions imposed by fixed
1959size windows, `window-min-height' or `window-min-width' settings.
1960
1961This function is only called by the frame resizing routines. It
1962resizes windows proportionally and never deletes any windows."
1963 (when (and (windowp window) (numberp delta)
1964 (window-sizable-p window delta horizontal ignore))
5386012d
MR
1965 (window--resize-reset (window-frame window) horizontal)
1966 (window--resize-this-window window delta horizontal ignore t)))
9aab8e0d 1967
5386012d 1968(defun window--resize-root-window-vertically (window delta)
9aab8e0d
MR
1969 "Resize root window WINDOW vertically by DELTA lines.
1970If DELTA is less than zero and we can't shrink WINDOW by DELTA
1971lines, shrink it as much as possible. If DELTA is greater than
be7f5545 1972zero, this function can resize fixed-size windows in order to
9aab8e0d
MR
1973recover the necessary lines.
1974
1975Return the number of lines that were recovered.
1976
1977This function is only called by the minibuffer window resizing
1978routines. It resizes windows proportionally and never deletes
1979any windows."
1980 (when (numberp delta)
1981 (let (ignore)
1982 (cond
1983 ((< delta 0)
1984 (setq delta (window-sizable window delta)))
1985 ((> delta 0)
1986 (unless (window-sizable window delta)
1987 (setq ignore t))))
1988
5386012d 1989 (window--resize-reset (window-frame window))
9aab8e0d
MR
1990 ;; Ideally, we would resize just the last window in a combination
1991 ;; but that's not feasible for the following reason: If we grow
1992 ;; the minibuffer window and the last window cannot be shrunk any
1993 ;; more, we shrink another window instead. But if we then shrink
1994 ;; the minibuffer window again, the last window might get enlarged
1995 ;; and the state after shrinking is not the state before growing.
1996 ;; So, in practice, we'd need a history variable to record how to
1997 ;; proceed. But I'm not sure how such a variable could work with
1998 ;; repeated minibuffer window growing steps.
5386012d 1999 (window--resize-this-window window delta nil ignore t)
9aab8e0d
MR
2000 delta)))
2001
562dd5e9
MR
2002(defun adjust-window-trailing-edge (window delta &optional horizontal)
2003 "Move WINDOW's bottom edge by DELTA lines.
2004Optional argument HORIZONTAL non-nil means move WINDOW's right
85c2386b
MR
2005edge by DELTA columns. WINDOW must be a valid window and
2006defaults to the selected one.
562dd5e9 2007
2116e93c 2008If DELTA is greater than zero, move the edge downwards or to the
562dd5e9
MR
2009right. If DELTA is less than zero, move the edge upwards or to
2010the left. If the edge can't be moved by DELTA lines or columns,
2011move it as far as possible in the desired direction."
447f16b8 2012 (setq window (window-normalize-window window))
41cfe0cb
MR
2013 (let* ((frame (window-frame window))
2014 (minibuffer-window (minibuffer-window frame))
2015 (right window)
2016 left this-delta min-delta max-delta)
562dd5e9 2017 ;; Find the edge we want to move.
3d8daefe 2018 (while (and (or (not (window-combined-p right horizontal))
562dd5e9
MR
2019 (not (window-right right)))
2020 (setq right (window-parent right))))
2021 (cond
41cfe0cb
MR
2022 ((and (not right) (not horizontal)
2023 ;; Resize the minibuffer window if it's on the same frame as
2024 ;; and immediately below WINDOW and it's either active or
2025 ;; `resize-mini-windows' is nil.
2026 (eq (window-frame minibuffer-window) frame)
2027 (= (nth 1 (window-edges minibuffer-window))
2028 (nth 3 (window-edges window)))
2029 (or (not resize-mini-windows)
2030 (eq minibuffer-window (active-minibuffer-window))))
2031 (window--resize-mini-window minibuffer-window (- delta)))
562dd5e9
MR
2032 ((or (not (setq left right)) (not (setq right (window-right right))))
2033 (if horizontal
2034 (error "No window on the right of this one")
2035 (error "No window below this one")))
2036 (t
2037 ;; Set LEFT to the first resizable window on the left. This step is
2038 ;; needed to handle fixed-size windows.
2039 (while (and left (window-size-fixed-p left horizontal))
2040 (setq left
2041 (or (window-left left)
2042 (progn
2043 (while (and (setq left (window-parent left))
3d8daefe 2044 (not (window-combined-p left horizontal))))
562dd5e9
MR
2045 (window-left left)))))
2046 (unless left
2047 (if horizontal
2048 (error "No resizable window on the left of this one")
2049 (error "No resizable window above this one")))
2050
2051 ;; Set RIGHT to the first resizable window on the right. This step
2052 ;; is needed to handle fixed-size windows.
2053 (while (and right (window-size-fixed-p right horizontal))
2054 (setq right
2055 (or (window-right right)
2056 (progn
2057 (while (and (setq right (window-parent right))
3d8daefe 2058 (not (window-combined-p right horizontal))))
562dd5e9
MR
2059 (window-right right)))))
2060 (unless right
2061 (if horizontal
2062 (error "No resizable window on the right of this one")
2063 (error "No resizable window below this one")))
2064
2065 ;; LEFT and RIGHT (which might be both internal windows) are now the
2066 ;; two windows we want to resize.
2067 (cond
2068 ((> delta 0)
c56cad4a
MR
2069 (setq max-delta (window--max-delta-1 left 0 horizontal nil 'after))
2070 (setq min-delta (window--min-delta-1 right (- delta) horizontal nil 'before))
562dd5e9
MR
2071 (when (or (< max-delta delta) (> min-delta (- delta)))
2072 ;; We can't get the whole DELTA - move as far as possible.
2073 (setq delta (min max-delta (- min-delta))))
2074 (unless (zerop delta)
2075 ;; Start resizing.
5386012d 2076 (window--resize-reset frame horizontal)
562dd5e9 2077 ;; Try to enlarge LEFT first.
2cffd681 2078 (setq this-delta (window--resizable left delta horizontal))
562dd5e9 2079 (unless (zerop this-delta)
5386012d 2080 (window--resize-this-window
562dd5e9
MR
2081 left this-delta horizontal nil t 'before
2082 (if horizontal
2083 (+ (window-left-column left) (window-total-size left t))
2084 (+ (window-top-line left) (window-total-size left)))))
2085 ;; Shrink windows on right of LEFT.
5386012d 2086 (window--resize-siblings
562dd5e9
MR
2087 left delta horizontal nil 'after
2088 (if horizontal
2089 (window-left-column right)
2090 (window-top-line right)))))
2091 ((< delta 0)
c56cad4a
MR
2092 (setq max-delta (window--max-delta-1 right 0 horizontal nil 'before))
2093 (setq min-delta (window--min-delta-1 left delta horizontal nil 'after))
562dd5e9
MR
2094 (when (or (< max-delta (- delta)) (> min-delta delta))
2095 ;; We can't get the whole DELTA - move as far as possible.
2096 (setq delta (max (- max-delta) min-delta)))
2097 (unless (zerop delta)
2098 ;; Start resizing.
5386012d 2099 (window--resize-reset frame horizontal)
562dd5e9 2100 ;; Try to enlarge RIGHT.
2cffd681 2101 (setq this-delta (window--resizable right (- delta) horizontal))
562dd5e9 2102 (unless (zerop this-delta)
5386012d 2103 (window--resize-this-window
562dd5e9
MR
2104 right this-delta horizontal nil t 'after
2105 (if horizontal
2106 (window-left-column right)
2107 (window-top-line right))))
2108 ;; Shrink windows on left of RIGHT.
5386012d 2109 (window--resize-siblings
562dd5e9
MR
2110 right (- delta) horizontal nil 'before
2111 (if horizontal
2112 (+ (window-left-column left) (window-total-size left t))
2113 (+ (window-top-line left) (window-total-size left)))))))
2114 (unless (zerop delta)
2115 ;; Don't report an error in the standard case.
d615d6d2 2116 (unless (window-resize-apply frame horizontal)
562dd5e9
MR
2117 ;; But do report an error if applying the changes fails.
2118 (error "Failed adjusting window %s" window)))))))
2119
2120(defun enlarge-window (delta &optional horizontal)
2116e93c 2121 "Make the selected window DELTA lines taller.
562dd5e9
MR
2122Interactively, if no argument is given, make the selected window
2123one line taller. If optional argument HORIZONTAL is non-nil,
2124make selected window wider by DELTA columns. If DELTA is
2125negative, shrink selected window by -DELTA lines or columns.
2126Return nil."
2127 (interactive "p")
feeb6f53
MR
2128 (let ((minibuffer-window (minibuffer-window)))
2129 (cond
2130 ((zerop delta))
2131 ((window-size-fixed-p nil horizontal)
2132 (error "Selected window has fixed size"))
2133 ((window-minibuffer-p)
2134 (if horizontal
2135 (error "Cannot resize minibuffer window horizontally")
2136 (window--resize-mini-window (selected-window) delta)))
2137 ((and (not horizontal)
2138 (window-full-height-p)
2139 (eq (window-frame minibuffer-window) (selected-frame))
2140 (not resize-mini-windows))
2141 ;; If the selected window is full height and `resize-mini-windows'
2142 ;; is nil, resize the minibuffer window.
2143 (window--resize-mini-window minibuffer-window (- delta)))
2144 ((window--resizable-p nil delta horizontal)
2145 (window-resize nil delta horizontal))
2146 (t
2147 (window-resize
2148 nil (if (> delta 0)
2149 (window-max-delta nil horizontal)
2150 (- (window-min-delta nil horizontal)))
2151 horizontal)))))
562dd5e9
MR
2152
2153(defun shrink-window (delta &optional horizontal)
2116e93c 2154 "Make the selected window DELTA lines smaller.
562dd5e9
MR
2155Interactively, if no argument is given, make the selected window
2156one line smaller. If optional argument HORIZONTAL is non-nil,
2157make selected window narrower by DELTA columns. If DELTA is
2158negative, enlarge selected window by -DELTA lines or columns.
f23d2c7d 2159Also see the `window-min-height' variable.
562dd5e9
MR
2160Return nil."
2161 (interactive "p")
feeb6f53
MR
2162 (let ((minibuffer-window (minibuffer-window)))
2163 (cond
2164 ((zerop delta))
2165 ((window-size-fixed-p nil horizontal)
2166 (error "Selected window has fixed size"))
2167 ((window-minibuffer-p)
2168 (if horizontal
2169 (error "Cannot resize minibuffer window horizontally")
2170 (window--resize-mini-window (selected-window) (- delta))))
2171 ((and (not horizontal)
2172 (window-full-height-p)
2173 (eq (window-frame minibuffer-window) (selected-frame))
2174 (not resize-mini-windows))
2175 ;; If the selected window is full height and `resize-mini-windows'
2176 ;; is nil, resize the minibuffer window.
2177 (window--resize-mini-window minibuffer-window delta))
2178 ((window--resizable-p nil (- delta) horizontal)
2179 (window-resize nil (- delta) horizontal))
2180 (t
2181 (window-resize
2182 nil (if (> delta 0)
2183 (- (window-min-delta nil horizontal))
2184 (window-max-delta nil horizontal))
2185 horizontal)))))
562dd5e9
MR
2186
2187(defun maximize-window (&optional window)
2188 "Maximize WINDOW.
2189Make WINDOW as large as possible without deleting any windows.
85c2386b 2190WINDOW must be a valid window and defaults to the selected one."
562dd5e9 2191 (interactive)
447f16b8 2192 (setq window (window-normalize-window window))
d615d6d2
MR
2193 (window-resize window (window-max-delta window))
2194 (window-resize window (window-max-delta window t) t))
562dd5e9
MR
2195
2196(defun minimize-window (&optional window)
2197 "Minimize WINDOW.
2198Make WINDOW as small as possible without deleting any windows.
85c2386b 2199WINDOW must be a valid window and defaults to the selected one."
562dd5e9 2200 (interactive)
447f16b8 2201 (setq window (window-normalize-window window))
d615d6d2
MR
2202 (window-resize window (- (window-min-delta window)))
2203 (window-resize window (- (window-min-delta window t)) t))
562dd5e9 2204\f
4b0d61e3 2205(defun frame-root-window-p (window)
9aab8e0d
MR
2206 "Return non-nil if WINDOW is the root window of its frame."
2207 (eq window (frame-root-window window)))
6198ccd0 2208
5e92ca23
MR
2209(defun window--subtree (window &optional next)
2210 "Return window subtree rooted at WINDOW.
2211Optional argument NEXT non-nil means include WINDOW's right
6198ccd0
MR
2212siblings in the return value.
2213
2214See the documentation of `window-tree' for a description of the
2215return value."
2216 (let (list)
2217 (while window
2218 (setq list
2219 (cons
2220 (cond
d68443dc 2221 ((window-top-child window)
6198ccd0 2222 (cons t (cons (window-edges window)
5e92ca23 2223 (window--subtree (window-top-child window) t))))
d68443dc 2224 ((window-left-child window)
6198ccd0 2225 (cons nil (cons (window-edges window)
5e92ca23 2226 (window--subtree (window-left-child window) t))))
6198ccd0
MR
2227 (t window))
2228 list))
d68443dc 2229 (setq window (when next (window-next-sibling window))))
6198ccd0
MR
2230 (nreverse list)))
2231
2232(defun window-tree (&optional frame)
2233 "Return the window tree of frame FRAME.
2234FRAME must be a live frame and defaults to the selected frame.
2235The return value is a list of the form (ROOT MINI), where ROOT
2236represents the window tree of the frame's root window, and MINI
2237is the frame's minibuffer window.
2238
2239If the root window is not split, ROOT is the root window itself.
2240Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil
2241for a horizontal split, and t for a vertical split. EDGES gives
be7f5545
MR
2242the combined size and position of the child windows in the split,
2243and the rest of the elements are the child windows in the split.
2244Each of the child windows may again be a window or a list
382c953b 2245representing a window split, and so on. EDGES is a list (LEFT
6198ccd0 2246TOP RIGHT BOTTOM) as returned by `window-edges'."
5386012d 2247 (setq frame (window-normalize-frame frame))
5e92ca23 2248 (window--subtree (frame-root-window frame) t))
9aab8e0d 2249\f
9397e56f
MR
2250(defun other-window (count &optional all-frames)
2251 "Select another window in cyclic ordering of windows.
2252COUNT specifies the number of windows to skip, starting with the
2253selected window, before making the selection. If COUNT is
2254positive, skip COUNT windows forwards. If COUNT is negative,
2255skip -COUNT windows backwards. COUNT zero means do not skip any
2256window, so select the selected window. In an interactive call,
2257COUNT is the numeric prefix argument. Return nil.
2258
9a9e9ef0
MR
2259If the `other-window' parameter of the selected window is a
2260function and `ignore-window-parameters' is nil, call that
2261function with the arguments COUNT and ALL-FRAMES.
9397e56f
MR
2262
2263This function does not select a window whose `no-other-window'
2264window parameter is non-nil.
2265
2266This function uses `next-window' for finding the window to
2267select. The argument ALL-FRAMES has the same meaning as in
2268`next-window', but the MINIBUF argument of `next-window' is
2269always effectively nil."
2270 (interactive "p")
2271 (let* ((window (selected-window))
2272 (function (and (not ignore-window-parameters)
2273 (window-parameter window 'other-window)))
2274 old-window old-count)
2275 (if (functionp function)
2276 (funcall function count all-frames)
2277 ;; `next-window' and `previous-window' may return a window we are
2278 ;; not allowed to select. Hence we need an exit strategy in case
2279 ;; all windows are non-selectable.
2280 (catch 'exit
2281 (while (> count 0)
2282 (setq window (next-window window nil all-frames))
2283 (cond
2284 ((eq window old-window)
2285 (when (= count old-count)
2286 ;; Keep out of infinite loops. When COUNT has not changed
2287 ;; since we last looked at `window' we're probably in one.
2288 (throw 'exit nil)))
2289 ((window-parameter window 'no-other-window)
2290 (unless old-window
2291 ;; The first non-selectable window `next-window' got us:
2292 ;; Remember it and the current value of COUNT.
2293 (setq old-window window)
2294 (setq old-count count)))
2295 (t
2296 (setq count (1- count)))))
2297 (while (< count 0)
2298 (setq window (previous-window window nil all-frames))
2299 (cond
2300 ((eq window old-window)
2301 (when (= count old-count)
2302 ;; Keep out of infinite loops. When COUNT has not changed
2303 ;; since we last looked at `window' we're probably in one.
2304 (throw 'exit nil)))
2305 ((window-parameter window 'no-other-window)
2306 (unless old-window
2307 ;; The first non-selectable window `previous-window' got
2308 ;; us: Remember it and the current value of COUNT.
2309 (setq old-window window)
2310 (setq old-count count)))
2311 (t
2312 (setq count (1+ count)))))
2313
2314 (select-window window)
2315 ;; Always return nil.
2316 nil))))
2317
387522b2
MR
2318;; This should probably return non-nil when the selected window is part
2319;; of an atomic window whose root is the frame's root window.
2320(defun one-window-p (&optional nomini all-frames)
2321 "Return non-nil if the selected window is the only window.
2322Optional arg NOMINI non-nil means don't count the minibuffer
2323even if it is active. Otherwise, the minibuffer is counted
2324when it is active.
2325
2326Optional argument ALL-FRAMES specifies the set of frames to
2327consider, see also `next-window'. ALL-FRAMES nil or omitted
2328means consider windows on the selected frame only, plus the
2329minibuffer window if specified by the NOMINI argument. If the
2330minibuffer counts, consider all windows on all frames that share
2331that minibuffer too. The remaining non-nil values of ALL-FRAMES
2332with a special meaning are:
2333
2334- t means consider all windows on all existing frames.
2335
2336- `visible' means consider all windows on all visible frames on
2337 the current terminal.
2338
2339- 0 (the number zero) means consider all windows on all visible
2340 and iconified frames on the current terminal.
2341
2342- A frame means consider all windows on that frame only.
2343
2344Anything else means consider all windows on the selected frame
2345and no others."
2346 (let ((base-window (selected-window)))
2347 (if (and nomini (eq base-window (minibuffer-window)))
2348 (setq base-window (next-window base-window)))
2349 (eq base-window
2350 (next-window base-window (if nomini 'arg) all-frames))))
3c448ab6 2351\f
9aab8e0d 2352;;; Deleting windows.
1b36ed6a 2353(defun window-deletable-p (&optional window)
9aab8e0d 2354 "Return t if WINDOW can be safely deleted from its frame.
85c2386b
MR
2355WINDOW must be a valid window and defaults to the selected one.
2356Return `frame' if deleting WINDOW should also delete its frame."
447f16b8 2357 (setq window (window-normalize-window window))
8b0874b5 2358
9aab8e0d
MR
2359 (unless ignore-window-parameters
2360 ;; Handle atomicity.
2361 (when (window-parameter window 'window-atom)
2362 (setq window (window-atom-root window))))
8b0874b5 2363
cb882333
JB
2364 (let ((parent (window-parent window))
2365 (frame (window-frame window)))
9aab8e0d
MR
2366 (cond
2367 ((frame-root-window-p window)
85e9c04b 2368 ;; WINDOW's frame can be deleted only if there are other frames
46b7967e
TN
2369 ;; on the same terminal, and it does not contain the active
2370 ;; minibuffer.
2371 (unless (or (eq frame (next-frame frame 0))
2372 (let ((minibuf (active-minibuffer-window)))
2373 (and minibuf (eq frame (window-frame minibuf)))))
85e9c04b 2374 'frame))
1b36ed6a
MR
2375 ((or ignore-window-parameters
2376 (not (eq (window-parameter window 'window-side) 'none))
2377 (and parent (eq (window-parameter parent 'window-side) 'none)))
2378 ;; WINDOW can be deleted unless it is the main window of its
2379 ;; frame.
1f3c99ca 2380 t))))
9aab8e0d 2381
be7f5545
MR
2382(defun window--in-subtree-p (window root)
2383 "Return t if WINDOW is either ROOT or a member of ROOT's subtree."
2384 (or (eq window root)
2385 (let ((parent (window-parent window)))
9aab8e0d
MR
2386 (catch 'done
2387 (while parent
be7f5545 2388 (if (eq parent root)
9aab8e0d
MR
2389 (throw 'done t)
2390 (setq parent (window-parent parent))))))))
2391
562dd5e9
MR
2392(defun delete-window (&optional window)
2393 "Delete WINDOW.
85c2386b
MR
2394WINDOW must be a valid window and defaults to the selected one.
2395Return nil.
562dd5e9
MR
2396
2397If the variable `ignore-window-parameters' is non-nil or the
2398`delete-window' parameter of WINDOW equals t, do not process any
2399parameters of WINDOW. Otherwise, if the `delete-window'
2400parameter of WINDOW specifies a function, call that function with
2401WINDOW as its sole argument and return the value returned by that
2402function.
2403
2404Otherwise, if WINDOW is part of an atomic window, call
2405`delete-window' with the root of the atomic window as its
85c2386b
MR
2406argument. Signal an error if WINDOW is either the only window on
2407its frame, the last non-side window, or part of an atomic window
2408that is its frame's root window."
562dd5e9 2409 (interactive)
447f16b8 2410 (setq window (window-normalize-window window))
562dd5e9
MR
2411 (let* ((frame (window-frame window))
2412 (function (window-parameter window 'delete-window))
2413 (parent (window-parent window))
2414 atom-root)
54f9154c 2415 (window--check frame)
562dd5e9
MR
2416 (catch 'done
2417 ;; Handle window parameters.
2418 (cond
2419 ;; Ignore window parameters if `ignore-window-parameters' tells
2420 ;; us so or `delete-window' equals t.
2421 ((or ignore-window-parameters (eq function t)))
2422 ((functionp function)
2423 ;; The `delete-window' parameter specifies the function to call.
2424 ;; If that function is `ignore' nothing is done. It's up to the
2425 ;; function called here to avoid infinite recursion.
2426 (throw 'done (funcall function window)))
2427 ((and (window-parameter window 'window-atom)
2428 (setq atom-root (window-atom-root window))
2429 (not (eq atom-root window)))
2430 (throw 'done (delete-window atom-root)))
2431 ((and (eq (window-parameter window 'window-side) 'none)
2432 (or (not parent)
2433 (not (eq (window-parameter parent 'window-side) 'none))))
2434 (error "Attempt to delete last non-side window"))
2435 ((not parent)
998c4a6a 2436 (error "Attempt to delete minibuffer or sole ordinary window")))
562dd5e9 2437
d68443dc 2438 (let* ((horizontal (window-left-child parent))
562dd5e9
MR
2439 (size (window-total-size window horizontal))
2440 (frame-selected
be7f5545 2441 (window--in-subtree-p (frame-selected-window frame) window))
562dd5e9
MR
2442 ;; Emacs 23 preferably gives WINDOW's space to its left
2443 ;; sibling.
2444 (sibling (or (window-left window) (window-right window))))
5386012d 2445 (window--resize-reset frame horizontal)
562dd5e9 2446 (cond
a0c2d0ae
MR
2447 ((and (not window-combination-resize)
2448 sibling (window-sizable-p sibling size))
562dd5e9 2449 ;; Resize WINDOW's sibling.
5386012d 2450 (window--resize-this-window sibling size horizontal nil t)
562dd5e9
MR
2451 (set-window-new-normal
2452 sibling (+ (window-normal-size sibling horizontal)
2453 (window-normal-size window horizontal))))
2cffd681 2454 ((window--resizable-p window (- size) horizontal nil nil nil t)
562dd5e9 2455 ;; Can do without resizing fixed-size windows.
5386012d 2456 (window--resize-siblings window (- size) horizontal))
562dd5e9
MR
2457 (t
2458 ;; Can't do without resizing fixed-size windows.
5386012d 2459 (window--resize-siblings window (- size) horizontal t)))
562dd5e9
MR
2460 ;; Actually delete WINDOW.
2461 (delete-window-internal window)
2462 (when (and frame-selected
2463 (window-parameter
2464 (frame-selected-window frame) 'no-other-window))
2465 ;; `delete-window-internal' has selected a window that should
2466 ;; not be selected, fix this here.
2467 (other-window -1 frame))
2468 (run-window-configuration-change-hook frame)
54f9154c 2469 (window--check frame)
562dd5e9
MR
2470 ;; Always return nil.
2471 nil))))
2472
2473(defun delete-other-windows (&optional window)
2474 "Make WINDOW fill its frame.
85c2386b 2475WINDOW must be a valid window and defaults to the selected one.
562dd5e9
MR
2476Return nil.
2477
2478If the variable `ignore-window-parameters' is non-nil or the
2479`delete-other-windows' parameter of WINDOW equals t, do not
2480process any parameters of WINDOW. Otherwise, if the
2481`delete-other-windows' parameter of WINDOW specifies a function,
2482call that function with WINDOW as its sole argument and return
2483the value returned by that function.
2484
2485Otherwise, if WINDOW is part of an atomic window, call this
2486function with the root of the atomic window as its argument. If
2487WINDOW is a non-side window, make WINDOW the only non-side window
382c953b 2488on the frame. Side windows are not deleted. If WINDOW is a side
562dd5e9
MR
2489window signal an error."
2490 (interactive)
447f16b8 2491 (setq window (window-normalize-window window))
562dd5e9
MR
2492 (let* ((frame (window-frame window))
2493 (function (window-parameter window 'delete-other-windows))
2494 (window-side (window-parameter window 'window-side))
2495 atom-root side-main)
54f9154c 2496 (window--check frame)
562dd5e9
MR
2497 (catch 'done
2498 (cond
2499 ;; Ignore window parameters if `ignore-window-parameters' is t or
2500 ;; `delete-other-windows' is t.
2501 ((or ignore-window-parameters (eq function t)))
2502 ((functionp function)
2503 ;; The `delete-other-windows' parameter specifies the function
2504 ;; to call. If the function is `ignore' no windows are deleted.
2505 ;; It's up to the function called to avoid infinite recursion.
2506 (throw 'done (funcall function window)))
2507 ((and (window-parameter window 'window-atom)
2508 (setq atom-root (window-atom-root window))
2509 (not (eq atom-root window)))
2510 (throw 'done (delete-other-windows atom-root)))
2511 ((eq window-side 'none)
2512 ;; Set side-main to the major non-side window.
454592a6 2513 (setq side-main (window-with-parameter 'window-side 'none frame t)))
562dd5e9
MR
2514 ((memq window-side window-sides)
2515 (error "Cannot make side window the only window")))
2516 ;; If WINDOW is the main non-side window, do nothing.
2517 (unless (eq window side-main)
2518 (delete-other-windows-internal window side-main)
2519 (run-window-configuration-change-hook frame)
54f9154c 2520 (window--check frame))
562dd5e9
MR
2521 ;; Always return nil.
2522 nil)))
9397e56f
MR
2523
2524(defun delete-other-windows-vertically (&optional window)
2525 "Delete the windows in the same column with WINDOW, but not WINDOW itself.
2526This may be a useful alternative binding for \\[delete-other-windows]
2527 if you often split windows horizontally."
2528 (interactive)
2529 (let* ((window (or window (selected-window)))
2530 (edges (window-edges window))
2531 (w window) delenda)
2532 (while (not (eq (setq w (next-window w 1)) window))
2533 (let ((e (window-edges w)))
2534 (when (and (= (car e) (car edges))
36cec983 2535 (= (nth 2 e) (nth 2 edges)))
9397e56f
MR
2536 (push w delenda))))
2537 (mapc 'delete-window delenda)))
2538
2539;;; Windows and buffers.
2540
2541;; `prev-buffers' and `next-buffers' are two reserved window slots used
2542;; for (1) determining which buffer to show in the window when its
2543;; buffer shall be buried or killed and (2) which buffer to show for
2544;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
2545
2546;; `prev-buffers' consists of <buffer, window-start, window-point>
2547;; triples. The entries on this list are ordered by the time their
2548;; buffer has been removed from the window, the most recently removed
2549;; buffer's entry being first. The window-start and window-point
2550;; components are `window-start' and `window-point' at the time the
2551;; buffer was removed from the window which implies that the entry must
2552;; be added when `set-window-buffer' removes the buffer from the window.
2553
2554;; `next-buffers' is the list of buffers that have been replaced
2555;; recently by `switch-to-prev-buffer'. These buffers are the least
2556;; preferred candidates of `switch-to-prev-buffer' and the preferred
2557;; candidates of `switch-to-next-buffer' to switch to. This list is
2558;; reset to nil by any action changing the window's buffer with the
2559;; exception of `switch-to-prev-buffer' and `switch-to-next-buffer'.
2560;; `switch-to-prev-buffer' pushes the buffer it just replaced on it,
2561;; `switch-to-next-buffer' pops the last pushed buffer from it.
2562
2563;; Both `prev-buffers' and `next-buffers' may reference killed buffers
2564;; if such a buffer was killed while the window was hidden within a
2565;; window configuration. Such killed buffers get removed whenever
2566;; `switch-to-prev-buffer' or `switch-to-next-buffer' encounter them.
2567
2568;; The following function is called by `set-window-buffer' _before_ it
2569;; replaces the buffer of the argument window with the new buffer.
2570(defun record-window-buffer (&optional window)
2571 "Record WINDOW's buffer.
2572WINDOW must be a live window and defaults to the selected one."
447f16b8 2573 (let* ((window (window-normalize-window window t))
9397e56f
MR
2574 (buffer (window-buffer window))
2575 (entry (assq buffer (window-prev-buffers window))))
2576 ;; Reset WINDOW's next buffers. If needed, they are resurrected by
2577 ;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
2578 (set-window-next-buffers window nil)
2579
2580 (when entry
2581 ;; Remove all entries for BUFFER from WINDOW's previous buffers.
2582 (set-window-prev-buffers
2583 window (assq-delete-all buffer (window-prev-buffers window))))
2584
2585 ;; Don't record insignificant buffers.
2586 (unless (eq (aref (buffer-name buffer) 0) ?\s)
2587 ;; Add an entry for buffer to WINDOW's previous buffers.
2588 (with-current-buffer buffer
2589 (let ((start (window-start window))
5481664a 2590 (point (window-point window)))
9397e56f
MR
2591 (setq entry
2592 (cons buffer
2593 (if entry
2594 ;; We have an entry, update marker positions.
2595 (list (set-marker (nth 1 entry) start)
2596 (set-marker (nth 2 entry) point))
2597 ;; Make new markers.
2598 (list (copy-marker start)
2599 (copy-marker point)))))
2600
2601 (set-window-prev-buffers
2602 window (cons entry (window-prev-buffers window))))))))
2603
2604(defun unrecord-window-buffer (&optional window buffer)
2605 "Unrecord BUFFER in WINDOW.
2606WINDOW must be a live window and defaults to the selected one.
2607BUFFER must be a live buffer and defaults to the buffer of
2608WINDOW."
447f16b8 2609 (let* ((window (window-normalize-window window t))
9397e56f
MR
2610 (buffer (or buffer (window-buffer window))))
2611 (set-window-prev-buffers
2612 window (assq-delete-all buffer (window-prev-buffers window)))
2613 (set-window-next-buffers
2614 window (delq buffer (window-next-buffers window)))))
2615
2616(defun set-window-buffer-start-and-point (window buffer &optional start point)
2617 "Set WINDOW's buffer to BUFFER.
85c2386b 2618WINDOW must be a live window and defaults to the selected one.
9397e56f
MR
2619Optional argument START non-nil means set WINDOW's start position
2620to START. Optional argument POINT non-nil means set WINDOW's
2621point to POINT. If WINDOW is selected this also sets BUFFER's
2622`point' to POINT. If WINDOW is selected and the buffer it showed
2623before was current this also makes BUFFER the current buffer."
85c2386b 2624 (setq window (window-normalize-window window t))
9397e56f
MR
2625 (let ((selected (eq window (selected-window)))
2626 (current (eq (window-buffer window) (current-buffer))))
2627 (set-window-buffer window buffer)
2628 (when (and selected current)
2629 (set-buffer buffer))
2630 (when start
cf4eacfd
MR
2631 ;; Don't force window-start here (even if POINT is nil).
2632 (set-window-start window start t))
9397e56f 2633 (when point
5481664a 2634 (set-window-point window point))))
9397e56f 2635
dcb6e7b3
MR
2636(defcustom switch-to-visible-buffer t
2637 "If non-nil, allow switching to an already visible buffer.
2638If this variable is non-nil, `switch-to-prev-buffer' and
2639`switch-to-next-buffer' may switch to an already visible buffer
2640provided the buffer was shown in the argument window before. If
2641this variable is nil, `switch-to-prev-buffer' and
2642`switch-to-next-buffer' always try to avoid switching to a buffer
2643that is already visible in another window on the same frame."
2644 :type 'boolean
2645 :version "24.1"
2646 :group 'windows)
2647
9397e56f
MR
2648(defun switch-to-prev-buffer (&optional window bury-or-kill)
2649 "In WINDOW switch to previous buffer.
2650WINDOW must be a live window and defaults to the selected one.
502e3f89
MR
2651Return the buffer switched to, nil if no suitable buffer could be
2652found.
9397e56f
MR
2653
2654Optional argument BURY-OR-KILL non-nil means the buffer currently
2655shown in WINDOW is about to be buried or killed and consequently
2656shall not be switched to in future invocations of this command."
2657 (interactive)
447f16b8 2658 (let* ((window (window-normalize-window window t))
dcb6e7b3 2659 (frame (window-frame window))
9397e56f
MR
2660 (old-buffer (window-buffer window))
2661 ;; Save this since it's destroyed by `set-window-buffer'.
2662 (next-buffers (window-next-buffers window))
502e3f89 2663 entry buffer new-buffer killed-buffers visible)
1b36ed6a
MR
2664 (when (window-dedicated-p window)
2665 (error "Window %s is dedicated to buffer %s" window old-buffer))
2666
2667 (catch 'found
2668 ;; Scan WINDOW's previous buffers first, skipping entries of next
2669 ;; buffers.
2670 (dolist (entry (window-prev-buffers window))
502e3f89
MR
2671 (when (and (setq buffer (car entry))
2672 (or (buffer-live-p buffer)
1b36ed6a 2673 (not (setq killed-buffers
502e3f89
MR
2674 (cons buffer killed-buffers))))
2675 (not (eq buffer old-buffer))
2676 (or bury-or-kill (not (memq buffer next-buffers))))
dcb6e7b3 2677 (if (and (not switch-to-visible-buffer)
502e3f89 2678 (get-buffer-window buffer frame))
dcb6e7b3 2679 ;; Try to avoid showing a buffer visible in some other window.
502e3f89
MR
2680 (setq visible buffer)
2681 (setq new-buffer buffer)
2682 (set-window-buffer-start-and-point
2683 window new-buffer (nth 1 entry) (nth 2 entry))
2684 (throw 'found t))))
1b36ed6a
MR
2685 ;; Scan reverted buffer list of WINDOW's frame next, skipping
2686 ;; entries of next buffers. Note that when we bury or kill a
2687 ;; buffer we don't reverse the global buffer list to avoid showing
2688 ;; a buried buffer instead. Otherwise, we must reverse the global
2689 ;; buffer list in order to make sure that switching to the
2690 ;; previous/next buffer traverse it in opposite directions.
2691 (dolist (buffer (if bury-or-kill
dcb6e7b3
MR
2692 (buffer-list frame)
2693 (nreverse (buffer-list frame))))
1b36ed6a
MR
2694 (when (and (buffer-live-p buffer)
2695 (not (eq buffer old-buffer))
2696 (not (eq (aref (buffer-name buffer) 0) ?\s))
2697 (or bury-or-kill (not (memq buffer next-buffers))))
dcb6e7b3 2698 (if (get-buffer-window buffer frame)
1b36ed6a 2699 ;; Try to avoid showing a buffer visible in some other window.
dcb6e7b3
MR
2700 (unless visible
2701 (setq visible buffer))
1b36ed6a
MR
2702 (setq new-buffer buffer)
2703 (set-window-buffer-start-and-point window new-buffer)
2704 (throw 'found t))))
2705 (unless bury-or-kill
2706 ;; Scan reverted next buffers last (must not use nreverse
2707 ;; here!).
2708 (dolist (buffer (reverse next-buffers))
2709 ;; Actually, buffer _must_ be live here since otherwise it
2710 ;; would have been caught in the scan of previous buffers.
2711 (when (and (or (buffer-live-p buffer)
9397e56f 2712 (not (setq killed-buffers
1b36ed6a 2713 (cons buffer killed-buffers))))
9397e56f 2714 (not (eq buffer old-buffer))
1b36ed6a 2715 (setq entry (assq buffer (window-prev-buffers window))))
9397e56f 2716 (setq new-buffer buffer)
1b36ed6a
MR
2717 (set-window-buffer-start-and-point
2718 window new-buffer (nth 1 entry) (nth 2 entry))
9397e56f 2719 (throw 'found t))))
1b36ed6a
MR
2720
2721 ;; Show a buffer visible in another window.
2722 (when visible
2723 (setq new-buffer visible)
2724 (set-window-buffer-start-and-point window new-buffer)))
2725
2726 (if bury-or-kill
2727 ;; Remove `old-buffer' from WINDOW's previous and (restored list
2728 ;; of) next buffers.
2729 (progn
2730 (set-window-prev-buffers
2731 window (assq-delete-all old-buffer (window-prev-buffers window)))
2732 (set-window-next-buffers window (delq old-buffer next-buffers)))
2733 ;; Move `old-buffer' to head of WINDOW's restored list of next
2734 ;; buffers.
2735 (set-window-next-buffers
2736 window (cons old-buffer (delq old-buffer next-buffers))))
9397e56f
MR
2737
2738 ;; Remove killed buffers from WINDOW's previous and next buffers.
2739 (when killed-buffers
2740 (dolist (buffer killed-buffers)
2741 (set-window-prev-buffers
2742 window (assq-delete-all buffer (window-prev-buffers window)))
2743 (set-window-next-buffers
2744 window (delq buffer (window-next-buffers window)))))
2745
2746 ;; Return new-buffer.
2747 new-buffer))
2748
2749(defun switch-to-next-buffer (&optional window)
2750 "In WINDOW switch to next buffer.
502e3f89
MR
2751WINDOW must be a live window and defaults to the selected one.
2752Return the buffer switched to, nil if no suitable buffer could be
2753found."
9397e56f 2754 (interactive)
447f16b8 2755 (let* ((window (window-normalize-window window t))
dcb6e7b3 2756 (frame (window-frame window))
9397e56f
MR
2757 (old-buffer (window-buffer window))
2758 (next-buffers (window-next-buffers window))
502e3f89 2759 buffer new-buffer entry killed-buffers visible)
9397e56f
MR
2760 (when (window-dedicated-p window)
2761 (error "Window %s is dedicated to buffer %s" window old-buffer))
2762
2763 (catch 'found
2764 ;; Scan WINDOW's next buffers first.
2765 (dolist (buffer next-buffers)
2766 (when (and (or (buffer-live-p buffer)
2767 (not (setq killed-buffers
2768 (cons buffer killed-buffers))))
2769 (not (eq buffer old-buffer))
2770 (setq entry (assq buffer (window-prev-buffers window))))
2771 (setq new-buffer buffer)
2772 (set-window-buffer-start-and-point
2773 window new-buffer (nth 1 entry) (nth 2 entry))
2774 (throw 'found t)))
2775 ;; Scan the buffer list of WINDOW's frame next, skipping previous
2776 ;; buffers entries.
dcb6e7b3 2777 (dolist (buffer (buffer-list frame))
9397e56f
MR
2778 (when (and (buffer-live-p buffer) (not (eq buffer old-buffer))
2779 (not (eq (aref (buffer-name buffer) 0) ?\s))
2780 (not (assq buffer (window-prev-buffers window))))
dcb6e7b3 2781 (if (get-buffer-window buffer frame)
9397e56f
MR
2782 ;; Try to avoid showing a buffer visible in some other window.
2783 (setq visible buffer)
2784 (setq new-buffer buffer)
2785 (set-window-buffer-start-and-point window new-buffer)
2786 (throw 'found t))))
2787 ;; Scan WINDOW's reverted previous buffers last (must not use
2788 ;; nreverse here!)
2789 (dolist (entry (reverse (window-prev-buffers window)))
502e3f89
MR
2790 (when (and (setq buffer (car entry))
2791 (or (buffer-live-p buffer)
9397e56f 2792 (not (setq killed-buffers
502e3f89
MR
2793 (cons buffer killed-buffers))))
2794 (not (eq buffer old-buffer)))
dcb6e7b3 2795 (if (and (not switch-to-visible-buffer)
502e3f89 2796 (get-buffer-window buffer frame))
dcb6e7b3
MR
2797 ;; Try to avoid showing a buffer visible in some other window.
2798 (unless visible
502e3f89
MR
2799 (setq visible buffer))
2800 (setq new-buffer buffer)
dcb6e7b3
MR
2801 (set-window-buffer-start-and-point
2802 window new-buffer (nth 1 entry) (nth 2 entry))
2803 (throw 'found t))))
9397e56f
MR
2804
2805 ;; Show a buffer visible in another window.
2806 (when visible
2807 (setq new-buffer visible)
2808 (set-window-buffer-start-and-point window new-buffer)))
2809
2810 ;; Remove `new-buffer' from and restore WINDOW's next buffers.
2811 (set-window-next-buffers window (delq new-buffer next-buffers))
2812
2813 ;; Remove killed buffers from WINDOW's previous and next buffers.
2814 (when killed-buffers
2815 (dolist (buffer killed-buffers)
2816 (set-window-prev-buffers
2817 window (assq-delete-all buffer (window-prev-buffers window)))
2818 (set-window-next-buffers
2819 window (delq buffer (window-next-buffers window)))))
2820
2821 ;; Return new-buffer.
2822 new-buffer))
2823
2824(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
2825 "Search LIST for a valid buffer to display in FRAME.
2826Return nil when all buffers in LIST are undesirable for display,
2827otherwise return the first suitable buffer in LIST.
2828
2829Buffers not visible in windows are preferred to visible buffers,
2830unless VISIBLE-OK is non-nil.
2831If the optional argument FRAME is nil, it defaults to the selected frame.
2832If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
2833 ;; This logic is more or less copied from other-buffer.
2834 (setq frame (or frame (selected-frame)))
2835 (let ((pred (frame-parameter frame 'buffer-predicate))
2836 found buf)
2837 (while (and (not found) list)
2838 (setq buf (car list))
2839 (if (and (not (eq buffer buf))
2840 (buffer-live-p buf)
2841 (or (null pred) (funcall pred buf))
2842 (not (eq (aref (buffer-name buf) 0) ?\s))
2843 (or visible-ok (null (get-buffer-window buf 'visible))))
2844 (setq found buf)
2845 (setq list (cdr list))))
2846 (car list)))
2847
2848(defun last-buffer (&optional buffer visible-ok frame)
2849 "Return the last buffer in FRAME's buffer list.
2850If BUFFER is the last buffer, return the preceding buffer
2851instead. Buffers not visible in windows are preferred to visible
2852buffers, unless optional argument VISIBLE-OK is non-nil.
2853Optional third argument FRAME nil or omitted means use the
2854selected frame's buffer list. If no such buffer exists, return
2855the buffer `*scratch*', creating it if necessary."
2856 (setq frame (or frame (selected-frame)))
2857 (or (get-next-valid-buffer (nreverse (buffer-list frame))
2858 buffer visible-ok frame)
2859 (get-buffer "*scratch*")
2860 (let ((scratch (get-buffer-create "*scratch*")))
2861 (set-buffer-major-mode scratch)
2862 scratch)))
2863
5a4cf282
MR
2864(defcustom frame-auto-hide-function #'iconify-frame
2865 "Function called to automatically hide frames.
2866The function is called with one argument - a frame.
2867
2868Functions affected by this option are those that bury a buffer
2869shown in a separate frame like `quit-window' and `bury-buffer'."
2870 :type '(choice (const :tag "Iconify" iconify-frame)
2871 (const :tag "Delete" delete-frame)
2872 (const :tag "Do nothing" ignore)
2873 function)
2874 :group 'windows
49677495
MR
2875 :group 'frames
2876 :version "24.1")
0e2070b5
MR
2877
2878(defun window--delete (&optional window dedicated-only kill)
2879 "Delete WINDOW if possible.
2880WINDOW must be a live window and defaults to the selected one.
2881Optional argument DEDICATED-ONLY non-nil means to delete WINDOW
2882only if it's dedicated to its buffer. Optional argument KILL
2883means the buffer shown in window will be killed. Return non-nil
c557cd6b 2884if WINDOW gets deleted or its frame is auto-hidden."
447f16b8 2885 (setq window (window-normalize-window window t))
0e2070b5 2886 (unless (and dedicated-only (not (window-dedicated-p window)))
cb882333 2887 (let ((deletable (window-deletable-p window)))
0e2070b5
MR
2888 (cond
2889 ((eq deletable 'frame)
2890 (let ((frame (window-frame window)))
c557cd6b
MR
2891 (cond
2892 (kill
2893 (delete-frame frame))
2894 ((functionp frame-auto-hide-function)
2895 (funcall frame-auto-hide-function frame))))
0e2070b5
MR
2896 'frame)
2897 (deletable
2898 (delete-window window)
2899 t)))))
2900
9397e56f
MR
2901(defun bury-buffer (&optional buffer-or-name)
2902 "Put BUFFER-OR-NAME at the end of the list of all buffers.
2903There it is the least likely candidate for `other-buffer' to
2904return; thus, the least likely buffer for \\[switch-to-buffer] to
2905select by default.
2906
2907You can specify a buffer name as BUFFER-OR-NAME, or an actual
2908buffer object. If BUFFER-OR-NAME is nil or omitted, bury the
2909current buffer. Also, if BUFFER-OR-NAME is nil or omitted,
2910remove the current buffer from the selected window if it is
2911displayed there."
2912 (interactive)
5386012d 2913 (let* ((buffer (window-normalize-buffer buffer-or-name)))
9397e56f
MR
2914 ;; If `buffer-or-name' is not on the selected frame we unrecord it
2915 ;; although it's not "here" (call it a feature).
e4ed06f1 2916 (bury-buffer-internal buffer)
9397e56f
MR
2917 ;; Handle case where `buffer-or-name' is nil and the current buffer
2918 ;; is shown in the selected window.
2919 (cond
2920 ((or buffer-or-name (not (eq buffer (window-buffer)))))
0e2070b5
MR
2921 ((window--delete nil t))
2922 (t
2923 ;; Switch to another buffer in window.
2924 (set-window-dedicated-p nil nil)
1885e5b8 2925 (switch-to-prev-buffer nil 'bury)))
1b36ed6a 2926
9397e56f
MR
2927 ;; Always return nil.
2928 nil))
2929
2930(defun unbury-buffer ()
2931 "Switch to the last buffer in the buffer list."
2932 (interactive)
2933 (switch-to-buffer (last-buffer)))
2934
2935(defun next-buffer ()
2936 "In selected window switch to next buffer."
2937 (interactive)
85c2386b
MR
2938 (cond
2939 ((window-minibuffer-p)
2940 (error "Cannot switch buffers in minibuffer window"))
2941 ((eq (window-dedicated-p) t)
2942 (error "Window is strongly dedicated to its buffer"))
2943 (t
2944 (switch-to-next-buffer))))
9397e56f
MR
2945
2946(defun previous-buffer ()
2947 "In selected window switch to previous buffer."
2948 (interactive)
85c2386b
MR
2949 (cond
2950 ((window-minibuffer-p)
2951 (error "Cannot switch buffers in minibuffer window"))
2952 ((eq (window-dedicated-p) t)
2953 (error "Window is strongly dedicated to its buffer"))
2954 (t
2955 (switch-to-prev-buffer))))
9397e56f
MR
2956
2957(defun delete-windows-on (&optional buffer-or-name frame)
2958 "Delete all windows showing BUFFER-OR-NAME.
2959BUFFER-OR-NAME may be a buffer or the name of an existing buffer
2960and defaults to the current buffer.
2961
2962The following non-nil values of the optional argument FRAME
2963have special meanings:
2964
2965- t means consider all windows on the selected frame only.
2966
2967- `visible' means consider all windows on all visible frames on
2968 the current terminal.
2969
2970- 0 (the number zero) means consider all windows on all visible
2971 and iconified frames on the current terminal.
2972
2973- A frame means consider all windows on that frame only.
2974
2975Any other value of FRAME means consider all windows on all
2976frames.
2977
2978When a window showing BUFFER-OR-NAME is dedicated and the only
2979window of its frame, that frame is deleted when there are other
2980frames left."
2981 (interactive "BDelete windows on (buffer):\nP")
5386012d 2982 (let ((buffer (window-normalize-buffer buffer-or-name))
9397e56f
MR
2983 ;; Handle the "inverted" meaning of the FRAME argument wrt other
2984 ;; `window-list-1' based function.
2985 (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
2986 (dolist (window (window-list-1 nil nil all-frames))
2987 (if (eq (window-buffer window) buffer)
1b36ed6a 2988 (let ((deletable (window-deletable-p window)))
9397e56f 2989 (cond
1b36ed6a
MR
2990 ((and (eq deletable 'frame) (window-dedicated-p window))
2991 ;; Delete frame if and only if window is dedicated.
9397e56f 2992 (delete-frame (window-frame window)))
1b36ed6a
MR
2993 ((eq deletable t)
2994 ;; Delete window.
9397e56f
MR
2995 (delete-window window))
2996 (t
2997 ;; In window switch to previous buffer.
2998 (set-window-dedicated-p window nil)
2999 (switch-to-prev-buffer window 'bury))))
3000 ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
3001 (unrecord-window-buffer window buffer)))))
3002
3003(defun replace-buffer-in-windows (&optional buffer-or-name)
3004 "Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
3005BUFFER-OR-NAME may be a buffer or the name of an existing buffer
3006and defaults to the current buffer.
3007
0e2070b5
MR
3008When a window showing BUFFER-OR-NAME is dedicated, that window is
3009deleted. If that window is the only window on its frame, the
3010frame is deleted too when there are other frames left. If there
3011are no other frames left, some other buffer is displayed in that
3012window.
9397e56f
MR
3013
3014This function removes the buffer denoted by BUFFER-OR-NAME from
3015all window-local buffer lists."
24901d61 3016 (interactive "bBuffer to replace: ")
5386012d 3017 (let ((buffer (window-normalize-buffer buffer-or-name)))
9397e56f
MR
3018 (dolist (window (window-list-1 nil nil t))
3019 (if (eq (window-buffer window) buffer)
0e2070b5
MR
3020 (unless (window--delete window t t)
3021 ;; Switch to another buffer in window.
3022 (set-window-dedicated-p window nil)
3023 (switch-to-prev-buffer window 'kill))
9397e56f
MR
3024 ;; Unrecord BUFFER in WINDOW.
3025 (unrecord-window-buffer window buffer)))))
3026
1ed43b09
CY
3027(defun quit-window (&optional kill window)
3028 "Quit WINDOW and bury its buffer.
cf4eacfd
MR
3029WINDOW must be a live window and defaults to the selected one.
3030With prefix argument KILL non-nil, kill the buffer instead of
3031burying it.
9397e56f
MR
3032
3033According to information stored in WINDOW's `quit-restore' window
382c953b
JB
3034parameter either (1) delete WINDOW and its frame, (2) delete
3035WINDOW, (3) restore the buffer previously displayed in WINDOW,
3036or (4) make WINDOW display some other buffer than the present
1ed43b09
CY
3037one. If non-nil, reset `quit-restore' parameter to nil."
3038 (interactive "P")
447f16b8 3039 (setq window (window-normalize-window window t))
cf4eacfd
MR
3040 (let* ((buffer (window-buffer window))
3041 (quit-restore (window-parameter window 'quit-restore))
3042 (prev-buffer
3043 (let* ((prev-buffers (window-prev-buffers window))
3044 (prev-buffer (caar prev-buffers)))
3045 (and (or (not (eq prev-buffer buffer))
3046 (and (cdr prev-buffers)
3047 (not (eq (setq prev-buffer (cadr prev-buffers))
3048 buffer))))
3049 prev-buffer)))
3050 quad resize)
9397e56f 3051 (cond
cf4eacfd 3052 ((and (not prev-buffer)
0e2070b5
MR
3053 (memq (nth 1 quit-restore) '(window frame))
3054 (eq (nth 3 quit-restore) buffer)
3055 ;; Delete WINDOW if possible.
3056 (window--delete window nil kill))
9397e56f
MR
3057 ;; If the previously selected window is still alive, select it.
3058 (when (window-live-p (nth 2 quit-restore))
3059 (select-window (nth 2 quit-restore))))
cf4eacfd
MR
3060 ((and (listp (setq quad (nth 1 quit-restore)))
3061 (buffer-live-p (car quad))
3062 (eq (nth 3 quit-restore) buffer))
3063 ;; Show another buffer stored in quit-restore parameter.
4737eec9
DG
3064 (setq resize (and (integerp (nth 3 quad))
3065 (/= (nth 3 quad) (window-total-size window))))
9397e56f 3066 (set-window-dedicated-p window nil)
cf4eacfd
MR
3067 (when resize
3068 ;; Try to resize WINDOW to its old height but don't signal an
3069 ;; error.
3070 (condition-case nil
3071 (window-resize window (- (nth 3 quad) (window-total-size window)))
3072 (error nil)))
1885e5b8 3073 ;; Restore WINDOW's previous buffer, start and point position.
cf4eacfd
MR
3074 (set-window-buffer-start-and-point
3075 window (nth 0 quad) (nth 1 quad) (nth 2 quad))
1885e5b8
MR
3076 ;; Unrecord WINDOW's buffer here (Bug#9937) to make sure it's not
3077 ;; re-recorded by `set-window-buffer'.
3078 (unrecord-window-buffer window buffer)
9397e56f
MR
3079 ;; Reset the quit-restore parameter.
3080 (set-window-parameter window 'quit-restore nil)
cf4eacfd
MR
3081 ;; Select old window.
3082 (when (window-live-p (nth 2 quit-restore))
3083 (select-window (nth 2 quit-restore))))
9397e56f 3084 (t
cf4eacfd
MR
3085 ;; Show some other buffer in WINDOW and reset the quit-restore
3086 ;; parameter.
9397e56f 3087 (set-window-parameter window 'quit-restore nil)
b4d72fcf
MR
3088 ;; Make sure that WINDOW is no more dedicated.
3089 (set-window-dedicated-p window nil)
9397e56f
MR
3090 (switch-to-prev-buffer window 'bury-or-kill)))
3091
3092 ;; Kill WINDOW's old-buffer if requested
e4ed06f1
CY
3093 (if kill
3094 (kill-buffer buffer)
3095 (bury-buffer-internal buffer))))
366ca7f3
MR
3096
3097(defun quit-windows-on (&optional buffer-or-name kill frame)
3098 "Quit all windows showing BUFFER-OR-NAME.
3099BUFFER-OR-NAME may be a buffer or the name of an existing buffer
3100and defaults to the current buffer. Optional argument KILL
3101non-nil means to kill BUFFER-OR-NAME. KILL nil means to bury
3102BUFFER-OR-NAME. Optional argument FRAME is handled as by
3103`delete-windows-on'.
3104
3105This function calls `quit-window' on all candidate windows
3106showing BUFFER-OR-NAME."
3107 (interactive "BQuit windows on (buffer):\nP")
3108 (let ((buffer (window-normalize-buffer buffer-or-name))
3109 ;; Handle the "inverted" meaning of the FRAME argument wrt other
3110 ;; `window-list-1' based function.
3111 (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
3112 (dolist (window (window-list-1 nil nil all-frames))
3113 (if (eq (window-buffer window) buffer)
3114 (quit-window kill window)
3115 ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
3116 (unrecord-window-buffer window buffer)))))
562dd5e9
MR
3117\f
3118;;; Splitting windows.
4b0d61e3 3119(defun window-split-min-size (&optional horizontal)
562dd5e9
MR
3120 "Return minimum height of any window when splitting windows.
3121Optional argument HORIZONTAL non-nil means return minimum width."
3122 (if horizontal
3123 (max window-min-width window-safe-min-width)
3124 (max window-min-height window-safe-min-height)))
3125
3126(defun split-window (&optional window size side)
3127 "Make a new window adjacent to WINDOW.
85c2386b 3128WINDOW must be a valid window and defaults to the selected one.
562dd5e9
MR
3129Return the new window which is always a live window.
3130
3131Optional argument SIZE a positive number means make WINDOW SIZE
3132lines or columns tall. If SIZE is negative, make the new window
3133-SIZE lines or columns tall. If and only if SIZE is non-nil, its
3134absolute value can be less than `window-min-height' or
3135`window-min-width'; so this command can make a new window as
3136small as one line or two columns. SIZE defaults to half of
3137WINDOW's size. Interactively, SIZE is the prefix argument.
3138
3139Optional third argument SIDE nil (or `below') specifies that the
3140new window shall be located below WINDOW. SIDE `above' means the
3141new window shall be located above WINDOW. In both cases SIZE
382c953b 3142specifies the new number of lines for WINDOW (or the new window
562dd5e9
MR
3143if SIZE is negative) including space reserved for the mode and/or
3144header line.
3145
3146SIDE t (or `right') specifies that the new window shall be
3147located on the right side of WINDOW. SIDE `left' means the new
3148window shall be located on the left of WINDOW. In both cases
382c953b 3149SIZE specifies the new number of columns for WINDOW (or the new
562dd5e9
MR
3150window provided SIZE is negative) including space reserved for
3151fringes and the scrollbar or a divider column. Any other non-nil
3152value for SIDE is currently handled like t (or `right').
3153
3154If the variable `ignore-window-parameters' is non-nil or the
3155`split-window' parameter of WINDOW equals t, do not process any
3156parameters of WINDOW. Otherwise, if the `split-window' parameter
3157of WINDOW specifies a function, call that function with all three
3158arguments and return the value returned by that function.
3159
3160Otherwise, if WINDOW is part of an atomic window, \"split\" the
3161root of that atomic window. The new window does not become a
3162member of that atomic window.
3163
3164If WINDOW is live, properties of the new window like margins and
3165scrollbars are inherited from WINDOW. If WINDOW is an internal
3166window, these properties as well as the buffer displayed in the
3167new window are inherited from the window selected on WINDOW's
3168frame. The selected window is not changed by this function."
3169 (interactive "i")
447f16b8 3170 (setq window (window-normalize-window window))
130e3e11
MR
3171 (let* ((side (cond
3172 ((not side) 'below)
3173 ((memq side '(below above right left)) side)
3174 (t 'right)))
3175 (horizontal (not (memq side '(nil below above))))
562dd5e9
MR
3176 (frame (window-frame window))
3177 (parent (window-parent window))
3178 (function (window-parameter window 'split-window))
3179 (window-side (window-parameter window 'window-side))
b6f67890
MR
3180 ;; Rebind `window-combination-limit' since in some cases we may
3181 ;; have to override its value.
3182 (window-combination-limit window-combination-limit)
562dd5e9
MR
3183 atom-root)
3184
54f9154c 3185 (window--check frame)
562dd5e9
MR
3186 (catch 'done
3187 (cond
3188 ;; Ignore window parameters if either `ignore-window-parameters'
3189 ;; is t or the `split-window' parameter equals t.
3190 ((or ignore-window-parameters (eq function t)))
3191 ((functionp function)
3192 ;; The `split-window' parameter specifies the function to call.
3193 ;; If that function is `ignore', do nothing.
3194 (throw 'done (funcall function window size side)))
be7f5545
MR
3195 ;; If WINDOW is part of an atomic window, split the root window
3196 ;; of that atomic window instead.
562dd5e9
MR
3197 ((and (window-parameter window 'window-atom)
3198 (setq atom-root (window-atom-root window))
3199 (not (eq atom-root window)))
3200 (throw 'done (split-window atom-root size side))))
3201
3202 (when (and window-side
3203 (or (not parent)
3204 (not (window-parameter parent 'window-side))))
3205 ;; WINDOW is a side root window. To make sure that a new parent
b6f67890
MR
3206 ;; window gets created set `window-combination-limit' to t.
3207 (setq window-combination-limit t))
562dd5e9 3208
a0c2d0ae
MR
3209 (when (and window-combination-resize size (> size 0))
3210 ;; If `window-combination-resize' is non-nil and SIZE is a
3211 ;; non-negative integer, we cannot reasonably resize other
3212 ;; windows. Rather bind `window-combination-limit' to t to make
3213 ;; sure that subsequent window deletions are handled correctly.
b6f67890 3214 (setq window-combination-limit t))
562dd5e9
MR
3215
3216 (let* ((parent-size
3217 ;; `parent-size' is the size of WINDOW's parent, provided
3218 ;; it has one.
3219 (when parent (window-total-size parent horizontal)))
3220 ;; `resize' non-nil means we are supposed to resize other
3221 ;; windows in WINDOW's combination.
3222 (resize
a0c2d0ae 3223 (and window-combination-resize (not window-combination-limit)
562dd5e9 3224 ;; Resize makes sense in iso-combinations only.
3d8daefe 3225 (window-combined-p window horizontal)))
562dd5e9
MR
3226 ;; `old-size' is the current size of WINDOW.
3227 (old-size (window-total-size window horizontal))
3228 ;; `new-size' is the specified or calculated size of the
3229 ;; new window.
3230 (new-size
3231 (cond
3232 ((not size)
3233 (max (window-split-min-size horizontal)
3234 (if resize
3235 ;; When resizing try to give the new window the
3236 ;; average size of a window in its combination.
3237 (min (- parent-size
3238 (window-min-size parent horizontal))
3239 (/ parent-size
3d8daefe 3240 (1+ (window-combinations
562dd5e9
MR
3241 parent horizontal))))
3242 ;; Else try to give the new window half the size
3243 ;; of WINDOW (plus an eventual odd line).
3244 (+ (/ old-size 2) (% old-size 2)))))
3245 ((>= size 0)
3246 ;; SIZE non-negative specifies the new size of WINDOW.
3247
3248 ;; Note: Specifying a non-negative SIZE is practically
3249 ;; always done as workaround for making the new window
3250 ;; appear above or on the left of the new window (the
3251 ;; ispell window is a typical example of that). In all
3252 ;; these cases the SIDE argument should be set to 'above
3253 ;; or 'left in order to support the 'resize option.
3254 ;; Here we have to nest the windows instead, see above.
3255 (- old-size size))
3256 (t
3257 ;; SIZE negative specifies the size of the new window.
3258 (- size))))
3259 new-parent new-normal)
3260
3261 ;; Check SIZE.
3262 (cond
3263 ((not size)
3264 (cond
3265 (resize
3266 ;; SIZE unspecified, resizing.
3267 (when (and (not (window-sizable-p parent (- new-size) horizontal))
3268 ;; Try again with minimum split size.
3269 (setq new-size
3270 (max new-size (window-split-min-size horizontal)))
3271 (not (window-sizable-p parent (- new-size) horizontal)))
3272 (error "Window %s too small for splitting" parent)))
3273 ((> (+ new-size (window-min-size window horizontal)) old-size)
3274 ;; SIZE unspecified, no resizing.
3275 (error "Window %s too small for splitting" window))))
3276 ((and (>= size 0)
3277 (or (>= size old-size)
3278 (< new-size (if horizontal
3279 window-safe-min-width
3280 window-safe-min-width))))
3281 ;; SIZE specified as new size of old window. If the new size
3282 ;; is larger than the old size or the size of the new window
3283 ;; would be less than the safe minimum, signal an error.
3284 (error "Window %s too small for splitting" window))
3285 (resize
3286 ;; SIZE specified, resizing.
3287 (unless (window-sizable-p parent (- new-size) horizontal)
3288 ;; If we cannot resize the parent give up.
3289 (error "Window %s too small for splitting" parent)))
3290 ((or (< new-size
3291 (if horizontal window-safe-min-width window-safe-min-height))
3292 (< (- old-size new-size)
3293 (if horizontal window-safe-min-width window-safe-min-height)))
3294 ;; SIZE specification violates minimum size restrictions.
3295 (error "Window %s too small for splitting" window)))
3296
5386012d 3297 (window--resize-reset frame horizontal)
562dd5e9
MR
3298
3299 (setq new-parent
3300 ;; Make new-parent non-nil if we need a new parent window;
3301 ;; either because we want to nest or because WINDOW is not
3302 ;; iso-combined.
b6f67890
MR
3303 (or window-combination-limit
3304 (not (window-combined-p window horizontal))))
562dd5e9
MR
3305 (setq new-normal
3306 ;; Make new-normal the normal size of the new window.
3307 (cond
3308 (size (/ (float new-size) (if new-parent old-size parent-size)))
3309 (new-parent 0.5)
3d8daefe 3310 (resize (/ 1.0 (1+ (window-combinations parent horizontal))))
562dd5e9
MR
3311 (t (/ (window-normal-size window horizontal) 2.0))))
3312
3313 (if resize
3314 ;; Try to get space from OLD's siblings. We could go "up" and
3315 ;; try getting additional space from surrounding windows but
3316 ;; we won't be able to return space to those windows when we
3317 ;; delete the one we create here. Hence we do not go up.
3318 (progn
be7f5545 3319 (window--resize-child-windows parent (- new-size) horizontal)
562dd5e9
MR
3320 (let* ((normal (- 1.0 new-normal))
3321 (sub (window-child parent)))
3322 (while sub
3323 (set-window-new-normal
3324 sub (* (window-normal-size sub horizontal) normal))
3325 (setq sub (window-right sub)))))
3326 ;; Get entire space from WINDOW.
3327 (set-window-new-total window (- old-size new-size))
5386012d 3328 (window--resize-this-window window (- new-size) horizontal)
562dd5e9
MR
3329 (set-window-new-normal
3330 window (- (if new-parent 1.0 (window-normal-size window horizontal))
3331 new-normal)))
3332
3333 (let* ((new (split-window-internal window new-size side new-normal)))
3334 ;; Inherit window-side parameters, if any.
3335 (when (and window-side new-parent)
3336 (set-window-parameter (window-parent new) 'window-side window-side)
3337 (set-window-parameter new 'window-side window-side))
3338
3339 (run-window-configuration-change-hook frame)
54f9154c 3340 (window--check frame)
562dd5e9
MR
3341 ;; Always return the new window.
3342 new)))))
3343
3344;; I think this should be the default; I think people will prefer it--rms.
3345(defcustom split-window-keep-point t
2d197ffb
CY
3346 "If non-nil, \\[split-window-below] preserves point in the new window.
3347If nil, adjust point in the two windows to minimize redisplay.
3348This option applies only to `split-window-below' and functions
3349that call it. The low-level `split-window' function always keeps
3350the original point in both windows."
562dd5e9
MR
3351 :type 'boolean
3352 :group 'windows)
3353
2d197ffb
CY
3354(defun split-window-below (&optional size)
3355 "Split the selected window into two windows, one above the other.
3356The selected window is above. The newly split-off window is
3357below, and displays the same buffer. Return the new window.
3358
3359If optional argument SIZE is omitted or nil, both windows get the
3360same height, or close to it. If SIZE is positive, the upper
3361\(selected) window gets SIZE lines. If SIZE is negative, the
3362lower (new) window gets -SIZE lines.
3363
3364If the variable `split-window-keep-point' is non-nil, both
3365windows get the same value of point as the selected window.
3366Otherwise, the window starts are chosen so as to minimize the
3367amount of redisplay; this is convenient on slow terminals."
562dd5e9
MR
3368 (interactive "P")
3369 (let ((old-window (selected-window))
5481664a 3370 (old-point (window-point))
562dd5e9
MR
3371 (size (and size (prefix-numeric-value size)))
3372 moved-by-window-height moved new-window bottom)
3373 (when (and size (< size 0) (< (- size) window-min-height))
3374 ;; `split-window' would not signal an error here.
3375 (error "Size of new window too small"))
3376 (setq new-window (split-window nil size))
3377 (unless split-window-keep-point
3378 (with-current-buffer (window-buffer)
c491fa41
MR
3379 ;; Use `save-excursion' around vertical movements below
3380 ;; (Bug#10971). Note: When the selected window's buffer has a
3381 ;; header line, up to two lines of the buffer may not show up
3382 ;; in the resulting configuration.
3383 (save-excursion
3384 (goto-char (window-start))
3385 (setq moved (vertical-motion (window-height)))
3386 (set-window-start new-window (point))
3387 (when (> (point) (window-point new-window))
3388 (set-window-point new-window (point)))
3389 (when (= moved (window-height))
3390 (setq moved-by-window-height t)
3391 (vertical-motion -1))
3392 (setq bottom (point)))
3393 (and moved-by-window-height
3394 (<= bottom (point))
5481664a 3395 (set-window-point old-window (1- bottom)))
c491fa41
MR
3396 (and moved-by-window-height
3397 (<= (window-start new-window) old-point)
3398 (set-window-point new-window old-point)
3399 (select-window new-window))))
9397e56f
MR
3400 ;; Always copy quit-restore parameter in interactive use.
3401 (let ((quit-restore (window-parameter old-window 'quit-restore)))
3402 (when quit-restore
3403 (set-window-parameter new-window 'quit-restore quit-restore)))
3404 new-window))
562dd5e9 3405
2d197ffb 3406(defalias 'split-window-vertically 'split-window-below)
562dd5e9 3407
2d197ffb
CY
3408(defun split-window-right (&optional size)
3409 "Split the selected window into two side-by-side windows.
3410The selected window is on the left. The newly split-off window
3411is on the right, and displays the same buffer. Return the new
3412window.
562dd5e9 3413
2d197ffb
CY
3414If optional argument SIZE is omitted or nil, both windows get the
3415same width, or close to it. If SIZE is positive, the left-hand
3416\(selected) window gets SIZE columns. If SIZE is negative, the
3417right-hand (new) window gets -SIZE columns. Here, SIZE includes
3418the width of the window's scroll bar; if there are no scroll
3419bars, it includes the width of the divider column to the window's
3420right, if any."
562dd5e9
MR
3421 (interactive "P")
3422 (let ((old-window (selected-window))
3423 (size (and size (prefix-numeric-value size)))
3424 new-window)
3425 (when (and size (< size 0) (< (- size) window-min-width))
3426 ;; `split-window' would not signal an error here.
3427 (error "Size of new window too small"))
9397e56f
MR
3428 (setq new-window (split-window nil size t))
3429 ;; Always copy quit-restore parameter in interactive use.
3430 (let ((quit-restore (window-parameter old-window 'quit-restore)))
3431 (when quit-restore
3432 (set-window-parameter new-window 'quit-restore quit-restore)))
3433 new-window))
562dd5e9 3434
2d197ffb 3435(defalias 'split-window-horizontally 'split-window-right)
562dd5e9 3436\f
6198ccd0
MR
3437;;; Balancing windows.
3438
3439;; The following routine uses the recycled code from an old version of
be7f5545
MR
3440;; `window--resize-child-windows'. It's not very pretty, but coding it the way the
3441;; new `window--resize-child-windows' code does would hardly make it any shorter or
6198ccd0
MR
3442;; more readable (FWIW we'd need three loops - one to calculate the
3443;; minimum sizes per window, one to enlarge or shrink windows until the
3444;; new parent-size matches, and one where we shrink the largest/enlarge
3445;; the smallest window).
3446(defun balance-windows-2 (window horizontal)
3447 "Subroutine of `balance-windows-1'.
3d8daefe 3448WINDOW must be a vertical combination (horizontal if HORIZONTAL
85c2386b 3449is non-nil)."
6198ccd0
MR
3450 (let* ((first (window-child window))
3451 (sub first)
3452 (number-of-children 0)
3453 (parent-size (window-new-total window))
3454 (total-sum parent-size)
cb882333 3455 failed size sub-total sub-delta sub-amount rest)
6198ccd0
MR
3456 (while sub
3457 (setq number-of-children (1+ number-of-children))
3458 (when (window-size-fixed-p sub horizontal)
3459 (setq total-sum
3460 (- total-sum (window-total-size sub horizontal)))
3461 (set-window-new-normal sub 'ignore))
3462 (setq sub (window-right sub)))
3c448ab6 3463
6198ccd0
MR
3464 (setq failed t)
3465 (while (and failed (> number-of-children 0))
3466 (setq size (/ total-sum number-of-children))
3467 (setq failed nil)
3468 (setq sub first)
3469 (while (and sub (not failed))
be7f5545
MR
3470 ;; Ignore child windows that should be ignored or are stuck.
3471 (unless (window--resize-child-windows-skip-p sub)
6198ccd0
MR
3472 (setq sub-total (window-total-size sub horizontal))
3473 (setq sub-delta (- size sub-total))
3474 (setq sub-amount
3475 (window-sizable sub sub-delta horizontal))
be7f5545 3476 ;; Register the new total size for this child window.
6198ccd0
MR
3477 (set-window-new-total sub (+ sub-total sub-amount))
3478 (unless (= sub-amount sub-delta)
3479 (setq total-sum (- total-sum sub-total sub-amount))
3480 (setq number-of-children (1- number-of-children))
3481 ;; We failed and need a new round.
3482 (setq failed t)
3483 (set-window-new-normal sub 'skip)))
3484 (setq sub (window-right sub))))
3c448ab6 3485
6198ccd0
MR
3486 (setq rest (% total-sum number-of-children))
3487 ;; Fix rounding by trying to enlarge non-stuck windows by one line
3488 ;; (column) until `rest' is zero.
3489 (setq sub first)
3490 (while (and sub (> rest 0))
be7f5545 3491 (unless (window--resize-child-windows-skip-p window)
6198ccd0
MR
3492 (set-window-new-total sub 1 t)
3493 (setq rest (1- rest)))
3494 (setq sub (window-right sub)))
3c448ab6 3495
6198ccd0
MR
3496 ;; Fix rounding by trying to enlarge stuck windows by one line
3497 ;; (column) until `rest' equals zero.
3498 (setq sub first)
3499 (while (and sub (> rest 0))
3500 (unless (eq (window-new-normal sub) 'ignore)
3501 (set-window-new-total sub 1 t)
3502 (setq rest (1- rest)))
3503 (setq sub (window-right sub)))
3504
3505 (setq sub first)
3506 (while sub
3507 ;; Record new normal sizes.
3508 (set-window-new-normal
3509 sub (/ (if (eq (window-new-normal sub) 'ignore)
3510 (window-total-size sub horizontal)
3511 (window-new-total sub))
3512 (float parent-size)))
be7f5545 3513 ;; Recursively balance each window's child windows.
6198ccd0
MR
3514 (balance-windows-1 sub horizontal)
3515 (setq sub (window-right sub)))))
3516
3517(defun balance-windows-1 (window &optional horizontal)
3518 "Subroutine of `balance-windows'."
3519 (if (window-child window)
3520 (let ((sub (window-child window)))
3d8daefe 3521 (if (window-combined-p sub horizontal)
6198ccd0
MR
3522 (balance-windows-2 window horizontal)
3523 (let ((size (window-new-total window)))
3524 (while sub
9173deec 3525 (set-window-new-total sub size)
6198ccd0
MR
3526 (balance-windows-1 sub horizontal)
3527 (setq sub (window-right sub))))))))
3528
3529(defun balance-windows (&optional window-or-frame)
be7f5545 3530 "Balance the sizes of windows of WINDOW-OR-FRAME.
6198ccd0
MR
3531WINDOW-OR-FRAME is optional and defaults to the selected frame.
3532If WINDOW-OR-FRAME denotes a frame, balance the sizes of all
4c36be58 3533windows of that frame. If WINDOW-OR-FRAME denotes a window,
be7f5545 3534recursively balance the sizes of all child windows of that
6198ccd0
MR
3535window."
3536 (interactive)
3537 (let* ((window
3538 (cond
3539 ((or (not window-or-frame)
3540 (frame-live-p window-or-frame))
3541 (frame-root-window window-or-frame))
3542 ((or (window-live-p window-or-frame)
3543 (window-child window-or-frame))
3544 window-or-frame)
3545 (t
3546 (error "Not a window or frame %s" window-or-frame))))
3547 (frame (window-frame window)))
3548 ;; Balance vertically.
5386012d 3549 (window--resize-reset (window-frame window))
6198ccd0 3550 (balance-windows-1 window)
d615d6d2 3551 (window-resize-apply frame)
6198ccd0 3552 ;; Balance horizontally.
5386012d 3553 (window--resize-reset (window-frame window) t)
6198ccd0 3554 (balance-windows-1 window t)
d615d6d2 3555 (window-resize-apply frame t)))
3c448ab6
MR
3556
3557(defun window-fixed-size-p (&optional window direction)
3558 "Return t if WINDOW cannot be resized in DIRECTION.
3559WINDOW defaults to the selected window. DIRECTION can be
3560nil (i.e. any), `height' or `width'."
3561 (with-current-buffer (window-buffer window)
3562 (when (and (boundp 'window-size-fixed) window-size-fixed)
3563 (not (and direction
3564 (member (cons direction window-size-fixed)
3565 '((height . width) (width . height))))))))
3566
3567;;; A different solution to balance-windows.
3c448ab6
MR
3568(defvar window-area-factor 1
3569 "Factor by which the window area should be over-estimated.
3570This is used by `balance-windows-area'.
3571Changing this globally has no effect.")
3572(make-variable-buffer-local 'window-area-factor)
3573
6198ccd0 3574(defun balance-windows-area-adjust (window delta horizontal)
d615d6d2 3575 "Wrapper around `window-resize' with error checking.
6198ccd0 3576Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function."
d615d6d2 3577 ;; `window-resize' may fail if delta is too large.
6198ccd0
MR
3578 (while (>= (abs delta) 1)
3579 (condition-case nil
3580 (progn
d615d6d2 3581 (window-resize window delta horizontal)
6198ccd0
MR
3582 (setq delta 0))
3583 (error
3584 ;;(message "adjust: %s" (error-message-string err))
3585 (setq delta (/ delta 2))))))
3586
3c448ab6
MR
3587(defun balance-windows-area ()
3588 "Make all visible windows the same area (approximately).
3589See also `window-area-factor' to change the relative size of
3590specific buffers."
3591 (interactive)
3592 (let* ((unchanged 0) (carry 0) (round 0)
3593 ;; Remove fixed-size windows.
3594 (wins (delq nil (mapcar (lambda (win)
3595 (if (not (window-fixed-size-p win)) win))
3596 (window-list nil 'nomini))))
3597 (changelog nil)
3598 next)
3599 ;; Resizing a window changes the size of surrounding windows in complex
3600 ;; ways, so it's difficult to balance them all. The introduction of
3601 ;; `adjust-window-trailing-edge' made it a bit easier, but it is still
3602 ;; very difficult to do. `balance-window' above takes an off-line
3603 ;; approach: get the whole window tree, then balance it, then try to
3604 ;; adjust the windows so they fit the result.
3605 ;; Here, instead, we take a "local optimization" approach, where we just
3606 ;; go through all the windows several times until nothing needs to be
3607 ;; changed. The main problem with this approach is that it's difficult
3608 ;; to make sure it terminates, so we use some heuristic to try and break
3609 ;; off infinite loops.
3610 ;; After a round without any change, we allow a second, to give a chance
3611 ;; to the carry to propagate a minor imbalance from the end back to
3612 ;; the beginning.
3613 (while (< unchanged 2)
3614 ;; (message "New round")
3615 (setq unchanged (1+ unchanged) round (1+ round))
3616 (dolist (win wins)
3617 (setq next win)
3618 (while (progn (setq next (next-window next))
3619 (window-fixed-size-p next)))
3620 ;; (assert (eq next (or (cadr (member win wins)) (car wins))))
3621 (let* ((horiz
3622 (< (car (window-edges win)) (car (window-edges next))))
3623 (areadiff (/ (- (* (window-height next) (window-width next)
3624 (buffer-local-value 'window-area-factor
3625 (window-buffer next)))
3626 (* (window-height win) (window-width win)
3627 (buffer-local-value 'window-area-factor
3628 (window-buffer win))))
3629 (max (buffer-local-value 'window-area-factor
3630 (window-buffer win))
3631 (buffer-local-value 'window-area-factor
3632 (window-buffer next)))))
3633 (edgesize (if horiz
3634 (+ (window-height win) (window-height next))
3635 (+ (window-width win) (window-width next))))
3636 (diff (/ areadiff edgesize)))
3637 (when (zerop diff)
3638 ;; Maybe diff is actually closer to 1 than to 0.
3639 (setq diff (/ (* 3 areadiff) (* 2 edgesize))))
3640 (when (and (zerop diff) (not (zerop areadiff)))
3641 (setq diff (/ (+ areadiff carry) edgesize))
3642 ;; Change things smoothly.
3643 (if (or (> diff 1) (< diff -1)) (setq diff (/ diff 2))))
3644 (if (zerop diff)
3645 ;; Make sure negligible differences don't accumulate to
3646 ;; become significant.
3647 (setq carry (+ carry areadiff))
6198ccd0 3648 ;; This used `adjust-window-trailing-edge' before and uses
d615d6d2 3649 ;; `window-resize' now. Error wrapping is still needed.
6198ccd0 3650 (balance-windows-area-adjust win diff horiz)
3c448ab6
MR
3651 ;; (sit-for 0.5)
3652 (let ((change (cons win (window-edges win))))
3653 ;; If the same change has been seen already for this window,
3654 ;; we're most likely in an endless loop, so don't count it as
3655 ;; a change.
3656 (unless (member change changelog)
3657 (push change changelog)
3658 (setq unchanged 0 carry 0)))))))
3659 ;; We've now basically balanced all the windows.
3660 ;; But there may be some minor off-by-one imbalance left over,
3661 ;; so let's do some fine tuning.
3662 ;; (bw-finetune wins)
3663 ;; (message "Done in %d rounds" round)
3664 ))
9d89fec7
MR
3665
3666;;; Window states, how to get them and how to put them in a window.
34a02f46 3667(defun window--state-get-1 (window &optional writable)
9d89fec7
MR
3668 "Helper function for `window-state-get'."
3669 (let* ((type
3670 (cond
d68443dc
MR
3671 ((window-top-child window) 'vc)
3672 ((window-left-child window) 'hc)
9d89fec7
MR
3673 (t 'leaf)))
3674 (buffer (window-buffer window))
3675 (selected (eq window (selected-window)))
3676 (head
4b0d61e3
SM
3677 `(,type
3678 ,@(unless (window-next-sibling window) `((last . t)))
3679 (total-height . ,(window-total-size window))
3680 (total-width . ,(window-total-size window t))
3681 (normal-height . ,(window-normal-size window))
3682 (normal-width . ,(window-normal-size window t))
b6f67890 3683 (combination-limit . ,(window-combination-limit window))
34a02f46
MR
3684 ,@(let ((parameters (window-parameters window))
3685 list)
3686 ;; Make copies of those window parameters whose
3687 ;; persistence property is `writable' if WRITABLE is
3688 ;; non-nil and non-nil if WRITABLE is nil.
3689 (dolist (par parameters)
3690 (let ((pers (cdr (assq (car par)
3691 window-persistent-parameters))))
3692 (when (and pers (or (not writable) (eq pers 'writable)))
3693 (setq list (cons (cons (car par) (cdr par)) list)))))
3694 ;; Add `clone-of' parameter if necessary.
3695 (let ((pers (cdr (assq 'clone-of
3696 window-persistent-parameters))))
3697 (when (and pers (or (not writable) (eq pers 'writable))
3698 (not (assq 'clone-of list)))
3699 (setq list (cons (cons 'clone-of window) list))))
4b0d61e3
SM
3700 (when list
3701 `((parameters . ,list))))
3702 ,@(when buffer
1edf595d 3703 ;; All buffer related things go in here.
5481664a 3704 (let ((point (window-point window))
1edf595d
MR
3705 (start (window-start window)))
3706 `((buffer
3707 ,(buffer-name buffer)
3708 (selected . ,selected)
3709 (hscroll . ,(window-hscroll window))
3710 (fringes . ,(window-fringes window))
3711 (margins . ,(window-margins window))
3712 (scroll-bars . ,(window-scroll-bars window))
3713 (vscroll . ,(window-vscroll window))
3714 (dedicated . ,(window-dedicated-p window))
de8c03dc
SM
3715 (point . ,(if writable point
3716 (copy-marker point
3717 (buffer-local-value
3718 'window-point-insertion-type
3719 buffer))))
1edf595d 3720 (start . ,(if writable start (copy-marker start)))))))))
9d89fec7
MR
3721 (tail
3722 (when (memq type '(vc hc))
3723 (let (list)
3724 (setq window (window-child window))
3725 (while window
34a02f46 3726 (setq list (cons (window--state-get-1 window writable) list))
9d89fec7
MR
3727 (setq window (window-right window)))
3728 (nreverse list)))))
3729 (append head tail)))
3730
34a02f46 3731(defun window-state-get (&optional window writable)
9d89fec7
MR
3732 "Return state of WINDOW as a Lisp object.
3733WINDOW can be any window and defaults to the root window of the
3734selected frame.
3735
34a02f46
MR
3736Optional argument WRITABLE non-nil means do not use markers for
3737sampling `window-point' and `window-start'. Together, WRITABLE
3738and the variable `window-persistent-parameters' specify which
3739window parameters are saved by this function. WRITABLE should be
3740non-nil when the return value shall be written to a file and read
3741back in another session. Otherwise, an application may run into
3742an `invalid-read-syntax' error while attempting to read back the
3743value from file.
9d89fec7
MR
3744
3745The return value can be used as argument for `window-state-put'
3746to put the state recorded here into an arbitrary window. The
3747value can be also stored on disk and read back in a new session."
3748 (setq window
3749 (if window
24300f5f 3750 (if (window-valid-p window)
9d89fec7
MR
3751 window
3752 (error "%s is not a live or internal window" window))
3753 (frame-root-window)))
3754 ;; The return value is a cons whose car specifies some constraints on
be7f5545
MR
3755 ;; the size of WINDOW. The cdr lists the states of the child windows
3756 ;; of WINDOW.
9d89fec7
MR
3757 (cons
3758 ;; Frame related things would go into a function, say `frame-state',
3759 ;; calling `window-state-get' to insert the frame's root window.
4b0d61e3
SM
3760 `((min-height . ,(window-min-size window))
3761 (min-width . ,(window-min-size window t))
3762 (min-height-ignore . ,(window-min-size window nil t))
3763 (min-width-ignore . ,(window-min-size window t t))
3764 (min-height-safe . ,(window-min-size window nil 'safe))
1edf595d 3765 (min-width-safe . ,(window-min-size window t 'safe)))
34a02f46 3766 (window--state-get-1 window writable)))
9d89fec7
MR
3767
3768(defvar window-state-put-list nil
3769 "Helper variable for `window-state-put'.")
3770
c56cad4a 3771(defun window--state-put-1 (state &optional window ignore totals)
9d89fec7
MR
3772 "Helper function for `window-state-put'."
3773 (let ((type (car state)))
3774 (setq state (cdr state))
3775 (cond
3776 ((eq type 'leaf)
3777 ;; For a leaf window just add unprocessed entries to
3778 ;; `window-state-put-list'.
c7635a97 3779 (push (cons window state) window-state-put-list))
9d89fec7
MR
3780 ((memq type '(vc hc))
3781 (let* ((horizontal (eq type 'hc))
3782 (total (window-total-size window horizontal))
3783 (first t)
3784 size new)
3785 (dolist (item state)
3786 ;; Find the next child window. WINDOW always points to the
3787 ;; real window that we want to fill with what we find here.
3788 (when (memq (car item) '(leaf vc hc))
3789 (if (assq 'last item)
c56cad4a 3790 ;; The last child window. Below `window--state-put-1'
9d89fec7
MR
3791 ;; will put into it whatever ITEM has in store.
3792 (setq new nil)
3793 ;; Not the last child window, prepare for splitting
3794 ;; WINDOW. SIZE is the new (and final) size of the old
3795 ;; window.
3796 (setq size
3797 (if totals
3798 ;; Use total size.
3799 (cdr (assq (if horizontal 'total-width 'total-height) item))
3800 ;; Use normalized size and round.
3801 (round (* total
3802 (cdr (assq
3803 (if horizontal 'normal-width 'normal-height)
3804 item))))))
3805
3806 ;; Use safe sizes, we try to resize later.
3807 (setq size (max size (if horizontal
3808 window-safe-min-height
3809 window-safe-min-width)))
3810
3811 (if (window-sizable-p window (- size) horizontal 'safe)
b6f67890
MR
3812 (let* ((window-combination-limit
3813 (assq 'combination-limit item)))
301b181a 3814 ;; We must inherit the combination limit, otherwise
b6f67890
MR
3815 ;; we might mess up handling of atomic and side
3816 ;; window.
9d89fec7
MR
3817 (setq new (split-window window size horizontal)))
3818 ;; Give up if we can't resize window down to safe sizes.
3819 (error "Cannot resize window %s" window))
3820
3821 (when first
3822 (setq first nil)
3823 ;; When creating the first child window add for parent
3824 ;; unprocessed entries to `window-state-put-list'.
3825 (setq window-state-put-list
3826 (cons (cons (window-parent window) state)
3827 window-state-put-list))))
3828
3829 ;; Now process the current window (either the one we've just
3830 ;; split or the last child of its parent).
c56cad4a 3831 (window--state-put-1 item window ignore totals)
9d89fec7
MR
3832 ;; Continue with the last window split off.
3833 (setq window new))))))))
3834
c56cad4a 3835(defun window--state-put-2 (ignore)
9d89fec7
MR
3836 "Helper function for `window-state-put'."
3837 (dolist (item window-state-put-list)
3838 (let ((window (car item))
b6f67890 3839 (combination-limit (cdr (assq 'combination-limit item)))
9d89fec7
MR
3840 (parameters (cdr (assq 'parameters item)))
3841 (state (cdr (assq 'buffer item))))
b6f67890
MR
3842 (when combination-limit
3843 (set-window-combination-limit window combination-limit))
34a02f46
MR
3844 ;; Reset window's parameters and assign saved ones (we might want
3845 ;; a `remove-window-parameters' function here).
3846 (dolist (parameter (window-parameters window))
3847 (set-window-parameter window (car parameter) nil))
9d89fec7
MR
3848 (when parameters
3849 (dolist (parameter parameters)
34a02f46 3850 (set-window-parameter window (car parameter) (cdr parameter))))
9d89fec7
MR
3851 ;; Process buffer related state.
3852 (when state
3853 ;; We don't want to raise an error here so we create a buffer if
3854 ;; there's none.
3855 (set-window-buffer window (get-buffer-create (car state)))
3856 (with-current-buffer (window-buffer window)
3857 (set-window-hscroll window (cdr (assq 'hscroll state)))
3858 (apply 'set-window-fringes
3859 (cons window (cdr (assq 'fringes state))))
3860 (let ((margins (cdr (assq 'margins state))))
3861 (set-window-margins window (car margins) (cdr margins)))
3862 (let ((scroll-bars (cdr (assq 'scroll-bars state))))
3863 (set-window-scroll-bars
3864 window (car scroll-bars) (nth 2 scroll-bars) (nth 3 scroll-bars)))
3865 (set-window-vscroll window (cdr (assq 'vscroll state)))
3866 ;; Adjust vertically.
3867 (if (memq window-size-fixed '(t height))
3868 ;; A fixed height window, try to restore the original size.
3869 (let ((delta (- (cdr (assq 'total-height item))
3870 (window-total-height window)))
3871 window-size-fixed)
2cffd681 3872 (when (window--resizable-p window delta)
d615d6d2 3873 (window-resize window delta)))
9d89fec7
MR
3874 ;; Else check whether the window is not high enough.
3875 (let* ((min-size (window-min-size window nil ignore))
3876 (delta (- min-size (window-total-size window))))
3877 (when (and (> delta 0)
2cffd681 3878 (window--resizable-p window delta nil ignore))
d615d6d2 3879 (window-resize window delta nil ignore))))
9d89fec7
MR
3880 ;; Adjust horizontally.
3881 (if (memq window-size-fixed '(t width))
3882 ;; A fixed width window, try to restore the original size.
3883 (let ((delta (- (cdr (assq 'total-width item))
3884 (window-total-width window)))
3885 window-size-fixed)
2cffd681 3886 (when (window--resizable-p window delta)
d615d6d2 3887 (window-resize window delta)))
9d89fec7
MR
3888 ;; Else check whether the window is not wide enough.
3889 (let* ((min-size (window-min-size window t ignore))
3890 (delta (- min-size (window-total-size window t))))
3891 (when (and (> delta 0)
2cffd681 3892 (window--resizable-p window delta t ignore))
d615d6d2 3893 (window-resize window delta t ignore))))
9d89fec7
MR
3894 ;; Set dedicated status.
3895 (set-window-dedicated-p window (cdr (assq 'dedicated state)))
3896 ;; Install positions (maybe we should do this after all windows
3897 ;; have been created and sized).
3898 (ignore-errors
3899 (set-window-start window (cdr (assq 'start state)))
fa8eafef 3900 (set-window-point window (cdr (assq 'point state))))
9d89fec7
MR
3901 ;; Select window if it's the selected one.
3902 (when (cdr (assq 'selected state))
3903 (select-window window)))))))
3904
3905(defun window-state-put (state &optional window ignore)
3906 "Put window state STATE into WINDOW.
3907STATE should be the state of a window returned by an earlier
3908invocation of `window-state-get'. Optional argument WINDOW must
3909specify a live window and defaults to the selected one.
3910
3911Optional argument IGNORE non-nil means ignore minimum window
3912sizes and fixed size restrictions. IGNORE equal `safe' means
be7f5545 3913windows can get as small as `window-safe-min-height' and
9d89fec7 3914`window-safe-min-width'."
447f16b8 3915 (setq window (window-normalize-window window t))
9d89fec7
MR
3916 (let* ((frame (window-frame window))
3917 (head (car state))
3918 ;; We check here (1) whether the total sizes of root window of
3919 ;; STATE and that of WINDOW are equal so we can avoid
3920 ;; calculating new sizes, and (2) if we do have to resize
3921 ;; whether we can do so without violating size restrictions.
3922 (totals
3923 (and (= (window-total-size window)
3924 (cdr (assq 'total-height state)))
3925 (= (window-total-size window t)
3926 (cdr (assq 'total-width state)))))
3927 (min-height (cdr (assq 'min-height head)))
cb882333 3928 (min-width (cdr (assq 'min-width head))))
9d89fec7
MR
3929 (if (and (not totals)
3930 (or (> min-height (window-total-size window))
3931 (> min-width (window-total-size window t)))
3932 (or (not ignore)
3933 (and (setq min-height
3934 (cdr (assq 'min-height-ignore head)))
3935 (setq min-width
3936 (cdr (assq 'min-width-ignore head)))
3937 (or (> min-height (window-total-size window))
3938 (> min-width (window-total-size window t)))
3939 (or (not (eq ignore 'safe))
3940 (and (setq min-height
3941 (cdr (assq 'min-height-safe head)))
3942 (setq min-width
3943 (cdr (assq 'min-width-safe head)))
3944 (or (> min-height
3945 (window-total-size window))
3946 (> min-width
3947 (window-total-size window t))))))))
3948 ;; The check above might not catch all errors due to rounding
3949 ;; issues - so IGNORE equal 'safe might not always produce the
3950 ;; minimum possible state. But such configurations hardly make
3951 ;; sense anyway.
a91adc7e 3952 (error "Window %s too small to accommodate state" window)
9d89fec7
MR
3953 (setq state (cdr state))
3954 (setq window-state-put-list nil)
3955 ;; Work on the windows of a temporary buffer to make sure that
3956 ;; splitting proceeds regardless of any buffer local values of
3957 ;; `window-size-fixed'. Release that buffer after the buffers of
c56cad4a 3958 ;; all live windows have been set by `window--state-put-2'.
9d89fec7
MR
3959 (with-temp-buffer
3960 (set-window-buffer window (current-buffer))
c56cad4a
MR
3961 (window--state-put-1 state window nil totals)
3962 (window--state-put-2 ignore))
54f9154c 3963 (window--check frame))))
9481c002 3964\f
f818cd2a
MR
3965(defun display-buffer-record-window (type window buffer)
3966 "Record information for window used by `display-buffer'.
cf4eacfd 3967TYPE specifies the type of the calling operation and must be one
382c953b
JB
3968of the symbols 'reuse (when WINDOW existed already and was
3969reused for displaying BUFFER), 'window (when WINDOW was created
3970on an already existing frame), or 'frame (when WINDOW was
3971created on a new frame). WINDOW is the window used for or created
cf4eacfd
MR
3972by the `display-buffer' routines. BUFFER is the buffer that
3973shall be displayed.
3974
3975This function installs or updates the quit-restore parameter of
3976WINDOW. The quit-restore parameter is a list of four elements:
3977The first element is one of the symbols 'window, 'frame, 'same or
3978'other. The second element is either one of the symbols 'window
3979or 'frame or a list whose elements are the buffer previously
3980shown in the window, that buffer's window start and window point,
3981and the window's height. The third element is the window
3982selected at the time the parameter was created. The fourth
3983element is BUFFER."
f818cd2a 3984 (cond
cf4eacfd
MR
3985 ((eq type 'reuse)
3986 (if (eq (window-buffer window) buffer)
3987 ;; WINDOW shows BUFFER already.
3988 (when (consp (window-parameter window 'quit-restore))
3989 ;; If WINDOW has a quit-restore parameter, reset its car.
3990 (setcar (window-parameter window 'quit-restore) 'same))
3991 ;; WINDOW shows another buffer.
9481c002 3992 (set-window-parameter
f818cd2a 3993 window 'quit-restore
cf4eacfd
MR
3994 (list 'other
3995 ;; A quadruple of WINDOW's buffer, start, point and height.
3996 (list (window-buffer window) (window-start window)
5481664a 3997 (window-point window) (window-total-size window))
cf4eacfd
MR
3998 (selected-window) buffer))))
3999 ((eq type 'window)
4000 ;; WINDOW has been created on an existing frame.
f818cd2a 4001 (set-window-parameter
cf4eacfd
MR
4002 window 'quit-restore
4003 (list 'window 'window (selected-window) buffer)))
4004 ((eq type 'frame)
4005 ;; WINDOW has been created on a new frame.
f818cd2a 4006 (set-window-parameter
cf4eacfd
MR
4007 window 'quit-restore
4008 (list 'frame 'frame (selected-window) buffer)))))
9481c002 4009
f818cd2a
MR
4010(defcustom display-buffer-function nil
4011 "If non-nil, function to call to handle `display-buffer'.
4012It will receive two args, the buffer and a flag which if non-nil
4013means that the currently selected window is not acceptable. It
4014should choose or create a window, display the specified buffer in
4015it, and return the window.
4016
e1c2c6f2
MR
4017The specified function should call `display-buffer-record-window'
4018with corresponding arguments to set up the quit-restore parameter
4019of the window used."
f818cd2a
MR
4020 :type '(choice
4021 (const nil)
4022 (function :tag "function"))
3c448ab6 4023 :group 'windows)
9481c002 4024
f818cd2a
MR
4025(defcustom pop-up-frame-alist nil
4026 "Alist of parameters for automatically generated new frames.
4027You can set this in your init file; for example,
9481c002 4028
f818cd2a 4029 (setq pop-up-frame-alist '((width . 80) (height . 20)))
9481c002 4030
f818cd2a
MR
4031If non-nil, the value you specify here is used by the default
4032`pop-up-frame-function' for the creation of new frames.
9481c002 4033
f818cd2a
MR
4034Since `pop-up-frame-function' is used by `display-buffer' for
4035making new frames, any value specified here by default affects
4036the automatic generation of new frames via `display-buffer' and
4037all functions based on it. The behavior of `make-frame' is not
4038affected by this variable."
9481c002 4039 :type '(repeat (cons :format "%v"
f818cd2a
MR
4040 (symbol :tag "Parameter")
4041 (sexp :tag "Value")))
9481c002 4042 :group 'frames)
9481c002 4043
f818cd2a
MR
4044(defcustom pop-up-frame-function
4045 (lambda () (make-frame pop-up-frame-alist))
4046 "Function used by `display-buffer' for creating a new frame.
4047This function is called with no arguments and should return a new
4048frame. The default value calls `make-frame' with the argument
4049`pop-up-frame-alist'."
9481c002 4050 :type 'function
9481c002 4051 :group 'frames)
3c448ab6 4052
56f31926
MR
4053(defcustom special-display-buffer-names nil
4054 "List of names of buffers that should be displayed specially.
4055Displaying a buffer with `display-buffer' or `pop-to-buffer', if
4056its name is in this list, displays the buffer in a way specified
4057by `special-display-function'. `special-display-popup-frame'
4058\(the default for `special-display-function') usually displays
4059the buffer in a separate frame made with the parameters specified
4060by `special-display-frame-alist'. If `special-display-function'
4061has been set to some other function, that function is called with
4062the buffer as first, and nil as second argument.
4063
4064Alternatively, an element of this list can be specified as
4065\(BUFFER-NAME FRAME-PARAMETERS), where BUFFER-NAME is a buffer
382c953b 4066name and FRAME-PARAMETERS an alist of (PARAMETER . VALUE) pairs.
56f31926
MR
4067`special-display-popup-frame' will interpret such pairs as frame
4068parameters when it creates a special frame, overriding the
4069corresponding values from `special-display-frame-alist'.
4070
4071As a special case, if FRAME-PARAMETERS contains (same-window . t)
4072`special-display-popup-frame' displays that buffer in the
4073selected window. If FRAME-PARAMETERS contains (same-frame . t),
4074it displays that buffer in a window on the selected frame.
4075
4076If `special-display-function' specifies some other function than
4077`special-display-popup-frame', that function is called with the
4078buffer named BUFFER-NAME as first, and FRAME-PARAMETERS as second
4079argument.
4080
4081Finally, an element of this list can be also specified as
4082\(BUFFER-NAME FUNCTION OTHER-ARGS). In that case,
4083`special-display-popup-frame' will call FUNCTION with the buffer
4084named BUFFER-NAME as first argument, and OTHER-ARGS as the
0563dae9
MR
4085second.
4086
4087Any alternative function specified here is responsible for
4088setting up the quit-restore parameter of the window used.
56f31926
MR
4089
4090If this variable appears \"not to work\", because you added a
4091name to it but the corresponding buffer is displayed in the
4092selected window, look at the values of `same-window-buffer-names'
4093and `same-window-regexps'. Those variables take precedence over
4094this one.
4095
4096See also `special-display-regexps'."
4097 :type '(repeat
4098 (choice :tag "Buffer"
4099 :value ""
4100 (string :format "%v")
4101 (cons :tag "With parameters"
4102 :format "%v"
4103 :value ("" . nil)
4104 (string :format "%v")
4105 (repeat :tag "Parameters"
4106 (cons :format "%v"
4107 (symbol :tag "Parameter")
4108 (sexp :tag "Value"))))
4109 (list :tag "With function"
4110 :format "%v"
4111 :value ("" . nil)
4112 (string :format "%v")
4113 (function :tag "Function")
4114 (repeat :tag "Arguments" (sexp)))))
4115 :group 'windows
4116 :group 'frames)
4117
ac549fa5
GM
4118;;;###autoload
4119(put 'special-display-buffer-names 'risky-local-variable t)
4120
56f31926
MR
4121(defcustom special-display-regexps nil
4122 "List of regexps saying which buffers should be displayed specially.
4123Displaying a buffer with `display-buffer' or `pop-to-buffer', if
4124any regexp in this list matches its name, displays it specially
4125using `special-display-function'. `special-display-popup-frame'
4126\(the default for `special-display-function') usually displays
4127the buffer in a separate frame made with the parameters specified
4128by `special-display-frame-alist'. If `special-display-function'
4129has been set to some other function, that function is called with
4130the buffer as first, and nil as second argument.
4131
4132Alternatively, an element of this list can be specified as
4133\(REGEXP FRAME-PARAMETERS), where REGEXP is a regexp as above and
4134FRAME-PARAMETERS an alist of (PARAMETER . VALUE) pairs.
4135`special-display-popup-frame' will then interpret these pairs as
4136frame parameters when creating a special frame for a buffer whose
4137name matches REGEXP, overriding the corresponding values from
4138`special-display-frame-alist'.
4139
4140As a special case, if FRAME-PARAMETERS contains (same-window . t)
4141`special-display-popup-frame' displays buffers matching REGEXP in
382c953b 4142the selected window. (same-frame . t) in FRAME-PARAMETERS means
56f31926
MR
4143to display such buffers in a window on the selected frame.
4144
4145If `special-display-function' specifies some other function than
4146`special-display-popup-frame', that function is called with the
4147buffer whose name matched REGEXP as first, and FRAME-PARAMETERS
4148as second argument.
4149
4150Finally, an element of this list can be also specified as
4151\(REGEXP FUNCTION OTHER-ARGS). `special-display-popup-frame'
4152will then call FUNCTION with the buffer whose name matched
0563dae9
MR
4153REGEXP as first, and OTHER-ARGS as second argument.
4154
4155Any alternative function specified here is responsible for
4156setting up the quit-restore parameter of the window used.
56f31926
MR
4157
4158If this variable appears \"not to work\", because you added a
4159name to it but the corresponding buffer is displayed in the
4160selected window, look at the values of `same-window-buffer-names'
4161and `same-window-regexps'. Those variables take precedence over
4162this one.
4163
4164See also `special-display-buffer-names'."
4165 :type '(repeat
4166 (choice :tag "Buffer"
4167 :value ""
4168 (regexp :format "%v")
4169 (cons :tag "With parameters"
4170 :format "%v"
4171 :value ("" . nil)
4172 (regexp :format "%v")
4173 (repeat :tag "Parameters"
4174 (cons :format "%v"
4175 (symbol :tag "Parameter")
4176 (sexp :tag "Value"))))
4177 (list :tag "With function"
4178 :format "%v"
4179 :value ("" . nil)
4180 (regexp :format "%v")
4181 (function :tag "Function")
4182 (repeat :tag "Arguments" (sexp)))))
4183 :group 'windows
4184 :group 'frames)
4185
3c448ab6
MR
4186(defun special-display-p (buffer-name)
4187 "Return non-nil if a buffer named BUFFER-NAME gets a special frame.
56f31926
MR
4188More precisely, return t if `special-display-buffer-names' or
4189`special-display-regexps' contain a string entry equaling or
4190matching BUFFER-NAME. If `special-display-buffer-names' or
4191`special-display-regexps' contain a list entry whose car equals
4192or matches BUFFER-NAME, the return value is the cdr of that
4193entry."
f818cd2a 4194 (let (tmp)
98722073 4195 (cond
f818cd2a 4196 ((member buffer-name special-display-buffer-names)
98722073 4197 t)
f818cd2a 4198 ((setq tmp (assoc buffer-name special-display-buffer-names))
98722073
MR
4199 (cdr tmp))
4200 ((catch 'found
f818cd2a 4201 (dolist (regexp special-display-regexps)
98722073
MR
4202 (cond
4203 ((stringp regexp)
4204 (when (string-match-p regexp buffer-name)
4205 (throw 'found t)))
4206 ((and (consp regexp) (stringp (car regexp))
4207 (string-match-p (car regexp) buffer-name))
4208 (throw 'found (cdr regexp))))))))))
9481c002 4209
f818cd2a
MR
4210(defcustom special-display-frame-alist
4211 '((height . 14) (width . 80) (unsplittable . t))
4212 "Alist of parameters for special frames.
4213Special frames are used for buffers whose names are listed in
4214`special-display-buffer-names' and for buffers whose names match
4215one of the regular expressions in `special-display-regexps'.
9481c002 4216
f818cd2a 4217This variable can be set in your init file, like this:
9481c002 4218
f818cd2a
MR
4219 (setq special-display-frame-alist '((width . 80) (height . 20)))
4220
4221These supersede the values given in `default-frame-alist'."
4222 :type '(repeat (cons :format "%v"
4223 (symbol :tag "Parameter")
4224 (sexp :tag "Value")))
4225 :group 'frames)
4226
4227(defun special-display-popup-frame (buffer &optional args)
31cd32c9 4228 "Pop up a frame displaying BUFFER and return its window.
f818cd2a
MR
4229If BUFFER is already displayed in a visible or iconified frame,
4230raise that frame. Otherwise, display BUFFER in a new frame.
4231
4232Optional argument ARGS is a list specifying additional
4233information.
4234
4235If ARGS is an alist, use it as a list of frame parameters. If
382c953b
JB
4236these parameters contain (same-window . t), display BUFFER in
4237the selected window. If they contain (same-frame . t), display
f818cd2a
MR
4238BUFFER in a window of the selected frame.
4239
4240If ARGS is a list whose car is a symbol, use (car ARGS) as a
4241function to do the work. Pass it BUFFER as first argument,
4242and (cdr ARGS) as second."
4243 (if (and args (symbolp (car args)))
4244 (apply (car args) buffer (cdr args))
4245 (let ((window (get-buffer-window buffer 0)))
4246 (or
4247 ;; If we have a window already, make it visible.
4248 (when window
4249 (let ((frame (window-frame window)))
4250 (make-frame-visible frame)
4251 (raise-frame frame)
cf4eacfd 4252 (display-buffer-record-window 'reuse window buffer)
f818cd2a
MR
4253 window))
4254 ;; Reuse the current window if the user requested it.
4255 (when (cdr (assq 'same-window args))
4256 (condition-case nil
4257 (progn (switch-to-buffer buffer nil t) (selected-window))
4258 (error nil)))
4259 ;; Stay on the same frame if requested.
4260 (when (or (cdr (assq 'same-frame args)) (cdr (assq 'same-window args)))
4261 (let* ((pop-up-windows t)
4262 pop-up-frames
4263 special-display-buffer-names special-display-regexps)
4264 (display-buffer buffer)))
4265 ;; If no window yet, make one in a new frame.
e75852fd
MR
4266 (let* ((frame
4267 (with-current-buffer buffer
4268 (make-frame (append args special-display-frame-alist))))
4269 (window (frame-selected-window frame)))
4270 (display-buffer-record-window 'frame window buffer)
4271 (set-window-dedicated-p window t)
4272 window)))))
f818cd2a
MR
4273
4274(defcustom special-display-function 'special-display-popup-frame
4275 "Function to call for displaying special buffers.
4276This function is called with two arguments - the buffer and,
4277optionally, a list - and should return a window displaying that
4278buffer. The default value usually makes a separate frame for the
4279buffer using `special-display-frame-alist' to specify the frame
4280parameters. See the definition of `special-display-popup-frame'
4281for how to specify such a function.
4282
4283A buffer is special when its name is either listed in
4284`special-display-buffer-names' or matches a regexp in
4285`special-display-regexps'.
4286
e1c2c6f2
MR
4287The specified function should call `display-buffer-record-window'
4288with corresponding arguments to set up the quit-restore parameter
4289of the window used."
f818cd2a
MR
4290 :type 'function
4291 :group 'frames)
4292
4293(defcustom same-window-buffer-names nil
4294 "List of names of buffers that should appear in the \"same\" window.
4295`display-buffer' and `pop-to-buffer' show a buffer whose name is
4296on this list in the selected rather than some other window.
4297
4298An element of this list can be a cons cell instead of just a
4299string. In that case, the cell's car must be a string specifying
4300the buffer name. This is for compatibility with
4301`special-display-buffer-names'; the cdr of the cons cell is
4302ignored.
4303
4304See also `same-window-regexps'."
4305 :type '(repeat (string :format "%v"))
4306 :group 'windows)
4307
4308(defcustom same-window-regexps nil
4309 "List of regexps saying which buffers should appear in the \"same\" window.
4310`display-buffer' and `pop-to-buffer' show a buffer whose name
4311matches a regexp on this list in the selected rather than some
4312other window.
4313
4314An element of this list can be a cons cell instead of just a
4315string. In that case, the cell's car must be a regexp matching
4316the buffer name. This is for compatibility with
4317`special-display-regexps'; the cdr of the cons cell is ignored.
9481c002 4318
f818cd2a
MR
4319See also `same-window-buffer-names'."
4320 :type '(repeat (regexp :format "%v"))
4321 :group 'windows)
9481c002 4322
f818cd2a
MR
4323(defun same-window-p (buffer-name)
4324 "Return non-nil if a buffer named BUFFER-NAME would be shown in the \"same\" window.
4325This function returns non-nil if `display-buffer' or
4326`pop-to-buffer' would show a buffer named BUFFER-NAME in the
382c953b 4327selected rather than (as usual) some other window. See
f818cd2a
MR
4328`same-window-buffer-names' and `same-window-regexps'."
4329 (cond
4330 ((not (stringp buffer-name)))
4331 ;; The elements of `same-window-buffer-names' can be buffer
4332 ;; names or cons cells whose cars are buffer names.
4333 ((member buffer-name same-window-buffer-names))
4334 ((assoc buffer-name same-window-buffer-names))
4335 ((catch 'found
4336 (dolist (regexp same-window-regexps)
4337 ;; The elements of `same-window-regexps' can be regexps
4338 ;; or cons cells whose cars are regexps.
4339 (when (or (and (stringp regexp)
cb882333 4340 (string-match-p regexp buffer-name))
f818cd2a
MR
4341 (and (consp regexp) (stringp (car regexp))
4342 (string-match-p (car regexp) buffer-name)))
4343 (throw 'found t)))))))
3c448ab6 4344
d1067961 4345(defcustom pop-up-frames nil
3c448ab6 4346 "Whether `display-buffer' should make a separate frame.
d1f18ec0 4347If nil, never make a separate frame.
3c448ab6
MR
4348If the value is `graphic-only', make a separate frame
4349on graphic displays only.
4350Any other non-nil value means always make a separate frame."
4351 :type '(choice
4352 (const :tag "Never" nil)
4353 (const :tag "On graphic displays only" graphic-only)
4354 (const :tag "Always" t))
f818cd2a 4355 :group 'windows)
3c448ab6 4356
d1067961 4357(defcustom display-buffer-reuse-frames nil
f818cd2a 4358 "Non-nil means `display-buffer' should reuse frames.
3c448ab6
MR
4359If the buffer in question is already displayed in a frame, raise
4360that frame."
4361 :type 'boolean
d1067961 4362 :version "21.1"
f818cd2a 4363 :group 'windows)
3c448ab6 4364
4dc2a129
MR
4365(defcustom pop-up-windows t
4366 "Non-nil means `display-buffer' should make a new window."
3c448ab6
MR
4367 :type 'boolean
4368 :group 'windows)
4369
8b10a2d1 4370(defcustom split-window-preferred-function 'split-window-sensibly
f818cd2a 4371 "Function called by `display-buffer' routines to split a window.
8b10a2d1
MR
4372This function is called with a window as single argument and is
4373supposed to split that window and return the new window. If the
4374window can (or shall) not be split, it is supposed to return nil.
4375The default is to call the function `split-window-sensibly' which
4376tries to split the window in a way which seems most suitable.
4377You can customize the options `split-height-threshold' and/or
4378`split-width-threshold' in order to have `split-window-sensibly'
4379prefer either vertical or horizontal splitting.
4380
f818cd2a
MR
4381If you set this to any other function, bear in mind that the
4382`display-buffer' routines may call this function two times. The
4383argument of the first call is the largest window on its frame.
4384If that call fails to return a live window, the function is
4385called again with the least recently used window as argument. If
4386that call fails too, `display-buffer' will use an existing window
4387to display its buffer.
8b10a2d1
MR
4388
4389The window selected at the time `display-buffer' was invoked is
4390still selected when this function is called. Hence you can
4391compare the window argument with the value of `selected-window'
4392if you intend to split the selected window instead or if you do
4393not want to split the selected window."
4394 :type 'function
3c448ab6
MR
4395 :version "23.1"
4396 :group 'windows)
4397
8b10a2d1 4398(defcustom split-height-threshold 80
f818cd2a
MR
4399 "Minimum height for splitting windows sensibly.
4400If this is an integer, `split-window-sensibly' may split a window
8b10a2d1 4401vertically only if it has at least this many lines. If this is
f818cd2a
MR
4402nil, `split-window-sensibly' is not allowed to split a window
4403vertically. If, however, a window is the only window on its
4404frame, `split-window-sensibly' may split it vertically
4405disregarding the value of this variable."
8b10a2d1 4406 :type '(choice (const nil) (integer :tag "lines"))
3c448ab6
MR
4407 :version "23.1"
4408 :group 'windows)
4409
8b10a2d1 4410(defcustom split-width-threshold 160
f818cd2a
MR
4411 "Minimum width for splitting windows sensibly.
4412If this is an integer, `split-window-sensibly' may split a window
8b10a2d1 4413horizontally only if it has at least this many columns. If this
f818cd2a
MR
4414is nil, `split-window-sensibly' is not allowed to split a window
4415horizontally."
8b10a2d1 4416 :type '(choice (const nil) (integer :tag "columns"))
3c448ab6
MR
4417 :version "23.1"
4418 :group 'windows)
9481c002 4419
8b10a2d1
MR
4420(defun window-splittable-p (window &optional horizontal)
4421 "Return non-nil if `split-window-sensibly' may split WINDOW.
4422Optional argument HORIZONTAL nil or omitted means check whether
4423`split-window-sensibly' may split WINDOW vertically. HORIZONTAL
4424non-nil means check whether WINDOW may be split horizontally.
3c448ab6 4425
8b10a2d1 4426WINDOW may be split vertically when the following conditions
3c448ab6 4427hold:
3c448ab6
MR
4428- `window-size-fixed' is either nil or equals `width' for the
4429 buffer of WINDOW.
8b10a2d1 4430- `split-height-threshold' is an integer and WINDOW is at least as
3c448ab6 4431 high as `split-height-threshold'.
3c448ab6
MR
4432- When WINDOW is split evenly, the emanating windows are at least
4433 `window-min-height' lines tall and can accommodate at least one
4434 line plus - if WINDOW has one - a mode line.
4435
8b10a2d1 4436WINDOW may be split horizontally when the following conditions
3c448ab6 4437hold:
3c448ab6
MR
4438- `window-size-fixed' is either nil or equals `height' for the
4439 buffer of WINDOW.
8b10a2d1 4440- `split-width-threshold' is an integer and WINDOW is at least as
3c448ab6 4441 wide as `split-width-threshold'.
3c448ab6
MR
4442- When WINDOW is split evenly, the emanating windows are at least
4443 `window-min-width' or two (whichever is larger) columns wide."
4444 (when (window-live-p window)
4445 (with-current-buffer (window-buffer window)
4446 (if horizontal
4447 ;; A window can be split horizontally when its width is not
4448 ;; fixed, it is at least `split-width-threshold' columns wide
4449 ;; and at least twice as wide as `window-min-width' and 2 (the
4450 ;; latter value is hardcoded).
4451 (and (memq window-size-fixed '(nil height))
4452 ;; Testing `window-full-width-p' here hardly makes any
4453 ;; sense nowadays. This can be done more intuitively by
4454 ;; setting up `split-width-threshold' appropriately.
4455 (numberp split-width-threshold)
4456 (>= (window-width window)
4457 (max split-width-threshold
4458 (* 2 (max window-min-width 2)))))
4459 ;; A window can be split vertically when its height is not
4460 ;; fixed, it is at least `split-height-threshold' lines high,
4461 ;; and it is at least twice as high as `window-min-height' and 2
37269466 4462 ;; if it has a mode line or 1.
3c448ab6
MR
4463 (and (memq window-size-fixed '(nil width))
4464 (numberp split-height-threshold)
4465 (>= (window-height window)
4466 (max split-height-threshold
4467 (* 2 (max window-min-height
4468 (if mode-line-format 2 1))))))))))
4469
2dc2a609 4470(defun split-window-sensibly (&optional window)
8b10a2d1 4471 "Split WINDOW in a way suitable for `display-buffer'.
2dc2a609 4472WINDOW defaults to the currently selected window.
8b10a2d1
MR
4473If `split-height-threshold' specifies an integer, WINDOW is at
4474least `split-height-threshold' lines tall and can be split
4475vertically, split WINDOW into two windows one above the other and
4476return the lower window. Otherwise, if `split-width-threshold'
4477specifies an integer, WINDOW is at least `split-width-threshold'
4478columns wide and can be split horizontally, split WINDOW into two
4479windows side by side and return the window on the right. If this
4480can't be done either and WINDOW is the only window on its frame,
4481try to split WINDOW vertically disregarding any value specified
4482by `split-height-threshold'. If that succeeds, return the lower
4483window. Return nil otherwise.
4484
4485By default `display-buffer' routines call this function to split
4486the largest or least recently used window. To change the default
4487customize the option `split-window-preferred-function'.
4488
4489You can enforce this function to not split WINDOW horizontally,
382c953b 4490by setting (or binding) the variable `split-width-threshold' to
8b10a2d1
MR
4491nil. If, in addition, you set `split-height-threshold' to zero,
4492chances increase that this function does split WINDOW vertically.
4493
382c953b 4494In order to not split WINDOW vertically, set (or bind) the
8b10a2d1
MR
4495variable `split-height-threshold' to nil. Additionally, you can
4496set `split-width-threshold' to zero to make a horizontal split
4497more likely to occur.
4498
4499Have a look at the function `window-splittable-p' if you want to
4500know how `split-window-sensibly' determines whether WINDOW can be
4501split."
2dc2a609
TH
4502 (let ((window (or window (selected-window))))
4503 (or (and (window-splittable-p window)
4504 ;; Split window vertically.
4505 (with-selected-window window
4506 (split-window-below)))
4507 (and (window-splittable-p window t)
4508 ;; Split window horizontally.
4509 (with-selected-window window
4510 (split-window-right)))
4511 (and (eq window (frame-root-window (window-frame window)))
4512 (not (window-minibuffer-p window))
4513 ;; If WINDOW is the only window on its frame and is not the
4514 ;; minibuffer window, try to split it vertically disregarding
4515 ;; the value of `split-height-threshold'.
4516 (let ((split-height-threshold 0))
4517 (when (window-splittable-p window)
4518 (with-selected-window window
4519 (split-window-below))))))))
9481c002 4520
f818cd2a
MR
4521(defun window--try-to-split-window (window)
4522 "Try to split WINDOW.
4523Return value returned by `split-window-preferred-function' if it
4524represents a live window, nil otherwise."
4525 (and (window-live-p window)
4526 (not (frame-parameter (window-frame window) 'unsplittable))
4527 (let ((new-window
4528 ;; Since `split-window-preferred-function' might
4529 ;; throw an error use `condition-case'.
4530 (condition-case nil
4531 (funcall split-window-preferred-function window)
4532 (error nil))))
4533 (and (window-live-p new-window) new-window))))
4534
4535(defun window--frame-usable-p (frame)
4536 "Return FRAME if it can be used to display a buffer."
4537 (when (frame-live-p frame)
4538 (let ((window (frame-root-window frame)))
4539 ;; `frame-root-window' may be an internal window which is considered
4540 ;; "dead" by `window-live-p'. Hence if `window' is not live we
4541 ;; implicitly know that `frame' has a visible window we can use.
4542 (unless (and (window-live-p window)
4543 (or (window-minibuffer-p window)
4544 ;; If the window is soft-dedicated, the frame is usable.
4545 ;; Actually, even if the window is really dedicated,
4546 ;; the frame is still usable by splitting it.
4547 ;; At least Emacs-22 allowed it, and it is desirable
4548 ;; when displaying same-frame windows.
4549 nil ; (eq t (window-dedicated-p window))
4550 ))
4551 frame))))
4552
4553(defcustom even-window-heights t
4554 "If non-nil `display-buffer' will try to even window heights.
4555Otherwise `display-buffer' will leave the window configuration
4556alone. Heights are evened only when `display-buffer' chooses a
4557window that appears above or below the selected window."
4558 :type 'boolean
4559 :group 'windows)
4560
4561(defun window--even-window-heights (window)
4562 "Even heights of WINDOW and selected window.
4563Do this only if these windows are vertically adjacent to each
4564other, `even-window-heights' is non-nil, and the selected window
4565is higher than WINDOW."
4566 (when (and even-window-heights
4567 (not (eq window (selected-window)))
4568 ;; Don't resize minibuffer windows.
4569 (not (window-minibuffer-p (selected-window)))
4570 (> (window-height (selected-window)) (window-height window))
4571 (eq (window-frame window) (window-frame (selected-window)))
4572 (let ((sel-edges (window-edges (selected-window)))
4573 (win-edges (window-edges window)))
4574 (and (= (nth 0 sel-edges) (nth 0 win-edges))
4575 (= (nth 2 sel-edges) (nth 2 win-edges))
4576 (or (= (nth 1 sel-edges) (nth 3 win-edges))
4577 (= (nth 3 sel-edges) (nth 1 win-edges))))))
4578 (let ((window-min-height 1))
4579 ;; Don't throw an error if we can't even window heights for
4580 ;; whatever reason.
4581 (condition-case nil
4582 (enlarge-window (/ (- (window-height window) (window-height)) 2))
4583 (error nil)))))
4584
51a5f9d8 4585(defun window--display-buffer (buffer window type &optional dedicated)
f818cd2a 4586 "Display BUFFER in WINDOW and make its frame visible.
51a5f9d8
MR
4587TYPE must be one of the symbols `reuse', `window' or `frame' and
4588is passed unaltered to `display-buffer-record-window'. Set
4589`window-dedicated-p' to DEDICATED if non-nil. Return WINDOW if
4590BUFFER and WINDOW are live."
f818cd2a 4591 (when (and (buffer-live-p buffer) (window-live-p window))
90749b53
CY
4592 (unless (eq buffer (window-buffer window))
4593 (set-window-dedicated-p window nil)
4594 (display-buffer-record-window type window buffer)
4595 (set-window-buffer window buffer)
4596 (when dedicated
4597 (set-window-dedicated-p window dedicated))
4598 (when (memq type '(window frame))
4599 (set-window-prev-buffers window nil)))
4600 window))
4601
4602(defun window--maybe-raise-frame (frame)
4603 (let ((visible (frame-visible-p frame)))
4604 (unless (or (not visible)
4605 ;; Assume the selected frame is already visible enough.
4606 (eq frame (selected-frame))
4607 ;; Assume the frame from which we invoked the
4608 ;; minibuffer is visible.
4609 (and (minibuffer-window-active-p (selected-window))
4610 (eq frame (window-frame (minibuffer-selected-window)))))
4611 (raise-frame frame))))
f818cd2a 4612
24510c22
SM
4613;; FIXME: Not implemented.
4614;; FIXME: By the way, there could be more levels of dedication:
4615;; - `barely' dedicated doesn't prevent reuse of the window, only records that
4616;; the window hasn't been used for something else yet.
4617;; - `softly' dedicated only allows reuse when asked explicitly.
4618;; - `strongly' never allows reuse.
f818cd2a
MR
4619(defvar display-buffer-mark-dedicated nil
4620 "If non-nil, `display-buffer' marks the windows it creates as dedicated.
4621The actual non-nil value of this variable will be copied to the
4622`window-dedicated-p' flag.")
4623
fa5660f9
CY
4624(defconst display-buffer--action-function-custom-type
4625 '(choice :tag "Function"
4626 (const :tag "--" ignore) ; default for insertion
fa5660f9 4627 (const display-buffer-reuse-window)
d9558cad 4628 (const display-buffer-pop-up-window)
fa5660f9
CY
4629 (const display-buffer-same-window)
4630 (const display-buffer-pop-up-frame)
4631 (const display-buffer-use-some-window)
4632 (function :tag "Other function"))
4633 "Custom type for `display-buffer' action functions.")
4634
4635(defconst display-buffer--action-custom-type
4636 `(cons :tag "Action"
4637 (choice :tag "Action functions"
4638 ,display-buffer--action-function-custom-type
4639 (repeat
4640 :tag "List of functions"
4641 ,display-buffer--action-function-custom-type))
4642 (alist :tag "Action arguments"
4643 :key-type symbol
4644 :value-type (sexp :tag "Value")))
4645 "Custom type for `display-buffer' actions.")
4646
cbb0f9ab
CY
4647(defvar display-buffer-overriding-action '(nil . nil)
4648 "Overriding action to perform to display a buffer.
4649It should be a cons cell (FUNCTION . ALIST), where FUNCTION is a
382c953b 4650function or a list of functions. Each function should accept two
cbb0f9ab
CY
4651arguments: a buffer to display and an alist similar to ALIST.
4652See `display-buffer' for details.")
4653(put 'display-buffer-overriding-action 'risky-local-variable t)
4654
fa5660f9 4655(defcustom display-buffer-alist nil
89894cd8
CY
4656 "Alist of conditional actions for `display-buffer'.
4657This is a list of elements (CONDITION . ACTION), where:
4658
4659 CONDITION is either a regexp matching buffer names, or a function
4660 that takes a buffer and returns a boolean.
4661
8319e0bf
CY
4662 ACTION is a cons cell (FUNCTION . ALIST), where FUNCTION is a
4663 function or a list of functions. Each such function should
382c953b 4664 accept two arguments: a buffer to display and an alist of the
fa5660f9
CY
4665 same form as ALIST. See `display-buffer' for details."
4666 :type `(alist :key-type
4667 (choice :tag "Condition"
4668 regexp
4669 (function :tag "Matcher function"))
4670 :value-type ,display-buffer--action-custom-type)
4671 :risky t
4672 :version "24.1"
4673 :group 'windows)
89894cd8 4674
cbb0f9ab
CY
4675(defcustom display-buffer-base-action '(nil . nil)
4676 "User-specified default action for `display-buffer'.
8319e0bf 4677It should be a cons cell (FUNCTION . ALIST), where FUNCTION is a
382c953b 4678function or a list of functions. Each function should accept two
fa5660f9
CY
4679arguments: a buffer to display and an alist similar to ALIST.
4680See `display-buffer' for details."
4681 :type display-buffer--action-custom-type
4682 :risky t
4683 :version "24.1"
4684 :group 'windows)
89894cd8 4685
cbb0f9ab 4686(defconst display-buffer-fallback-action
0a9f9ab5 4687 '((display-buffer--maybe-same-window ;FIXME: why isn't this redundant?
cbb0f9ab 4688 display-buffer-reuse-window
cbb0f9ab
CY
4689 display-buffer--maybe-pop-up-frame-or-window
4690 display-buffer-use-some-window
4691 ;; If all else fails, pop up a new frame.
4692 display-buffer-pop-up-frame))
4693 "Default fallback action for `display-buffer'.
4694This is the action used by `display-buffer' if no other actions
4695specified, e.g. by the user options `display-buffer-alist' or
4696`display-buffer-base-action'. See `display-buffer'.")
4697(put 'display-buffer-fallback-action 'risky-local-variable t)
f818cd2a
MR
4698
4699(defun display-buffer-assq-regexp (buffer-name alist)
4700 "Retrieve ALIST entry corresponding to BUFFER-NAME."
4701 (catch 'match
4702 (dolist (entry alist)
cb882333 4703 (let ((key (car entry)))
f818cd2a
MR
4704 (when (or (and (stringp key)
4705 (string-match-p key buffer-name))
4706 (and (symbolp key) (functionp key)
4707 (funcall key buffer-name alist)))
4708 (throw 'match (cdr entry)))))))
4709
8319e0bf
CY
4710(defvar display-buffer--same-window-action
4711 '(display-buffer-same-window
4712 (inhibit-same-window . nil))
4713 "A `display-buffer' action for displaying in the same window.")
4714(put 'display-buffer--same-window-action 'risky-local-variable t)
4715
4716(defvar display-buffer--other-frame-action
4717 '((display-buffer-reuse-window
8319e0bf
CY
4718 display-buffer-pop-up-frame)
4719 (reusable-frames . 0)
4720 (inhibit-same-window . t))
4721 "A `display-buffer' action for displaying in another frame.")
4722(put 'display-buffer--other-frame-action 'risky-local-variable t)
4723
d45ba96b 4724(defun display-buffer (buffer-or-name &optional action frame)
3199b96f 4725 "Display BUFFER-OR-NAME in some window, without selecting it.
89894cd8
CY
4726BUFFER-OR-NAME must be a buffer or the name of an existing
4727buffer. Return the window chosen for displaying BUFFER-OR-NAME,
4728or nil if no such window is found.
4729
4730Optional argument ACTION should have the form (FUNCTION . ALIST).
d4bd55e7
CY
4731FUNCTION is either a function or a list of functions.
4732ALIST is an arbitrary association list (alist).
4733
4734Each such FUNCTION should accept two arguments: the buffer to
4735display and an alist. Based on those arguments, it should either
4736display the buffer and return the window, or return nil if unable
4737to display the buffer.
89894cd8 4738
cbb0f9ab 4739The `display-buffer' function builds a function list and an alist
d4bd55e7
CY
4740by combining the functions and alists specified in
4741`display-buffer-overriding-action', `display-buffer-alist', the
4742ACTION argument, `display-buffer-base-action', and
4743`display-buffer-fallback-action' (in order). Then it calls each
4744function in the combined function list in turn, passing the
cbb0f9ab
CY
4745buffer as the first argument and the combined alist as the second
4746argument, until one of the functions returns non-nil.
8319e0bf
CY
4747
4748Available action functions include:
4749 `display-buffer-same-window'
8319e0bf
CY
4750 `display-buffer-reuse-window'
4751 `display-buffer-pop-up-frame'
4752 `display-buffer-pop-up-window'
4753 `display-buffer-use-some-window'
4754
4755Recognized alist entries include:
4756
4757 `inhibit-same-window' -- A non-nil value prevents the same
4758 window from being used for display.
4759
90749b53
CY
4760 `inhibit-switch-frame' -- A non-nil value prevents any other
4761 frame from being raised or selected,
4762 even if the window is displayed there.
4763
8319e0bf
CY
4764 `reusable-frames' -- Value specifies frame(s) to search for a
4765 window that already displays the buffer.
4766 See `display-buffer-reuse-window'.
2a7bdc1a
CY
4767
4768The ACTION argument to `display-buffer' can also have a non-nil
4769and non-list value. This means to display the buffer in a window
4770other than the selected one, even if it is already displayed in
4771the selected window. If called interactively with a prefix
4772argument, ACTION is t.
89894cd8 4773
8319e0bf
CY
4774Optional argument FRAME, if non-nil, acts like an additional
4775ALIST entry (reusable-frames . FRAME), specifying the frame(s) to
4776search for a window that is already displaying the buffer. See
4777`display-buffer-reuse-window'."
c3313451
CY
4778 (interactive (list (read-buffer "Display buffer: " (other-buffer))
4779 (if current-prefix-arg t)))
d45ba96b
MR
4780 (let ((buffer (if (bufferp buffer-or-name)
4781 buffer-or-name
4782 (get-buffer buffer-or-name)))
89894cd8
CY
4783 ;; Handle the old form of the first argument.
4784 (inhibit-same-window (and action (not (listp action)))))
4785 (unless (listp action) (setq action nil))
4786 (if display-buffer-function
4787 ;; If `display-buffer-function' is defined, let it do the job.
4788 (funcall display-buffer-function buffer inhibit-same-window)
4789 ;; Otherwise, use the defined actions.
4790 (let* ((user-action
4791 (display-buffer-assq-regexp (buffer-name buffer)
4792 display-buffer-alist))
0a9f9ab5 4793 (special-action (display-buffer--special-action buffer))
89894cd8
CY
4794 ;; Extra actions from the arguments to this function:
4795 (extra-action
4796 (cons nil (append (if inhibit-same-window
4797 '((inhibit-same-window . t)))
4798 (if frame
8319e0bf 4799 `((reusable-frames . ,frame))))))
89894cd8
CY
4800 ;; Construct action function list and action alist.
4801 (actions (list display-buffer-overriding-action
0a9f9ab5 4802 user-action special-action action extra-action
cbb0f9ab
CY
4803 display-buffer-base-action
4804 display-buffer-fallback-action))
89894cd8
CY
4805 (functions (apply 'append
4806 (mapcar (lambda (x)
4807 (setq x (car x))
c3313451 4808 (if (functionp x) (list x) x))
89894cd8
CY
4809 actions)))
4810 (alist (apply 'append (mapcar 'cdr actions)))
4811 window)
4812 (unless (buffer-live-p buffer)
4813 (error "Invalid buffer"))
4814 (while (and functions (not window))
4815 (setq window (funcall (car functions) buffer alist)
4816 functions (cdr functions)))
4817 window))))
f818cd2a
MR
4818
4819(defun display-buffer-other-frame (buffer)
4820 "Display buffer BUFFER in another frame.
4821This uses the function `display-buffer' as a subroutine; see
4822its documentation for additional customization information."
4823 (interactive "BDisplay buffer in other frame: ")
8319e0bf 4824 (display-buffer buffer display-buffer--other-frame-action t))
f818cd2a 4825
89894cd8 4826;;; `display-buffer' action functions:
437014c8 4827
89894cd8 4828(defun display-buffer-same-window (buffer alist)
8319e0bf
CY
4829 "Display BUFFER in the selected window.
4830This fails if ALIST has a non-nil `inhibit-same-window' entry, or
4831if the selected window is a minibuffer window or is dedicated to
4832another buffer; in that case, return nil. Otherwise, return the
4833selected window."
89894cd8
CY
4834 (unless (or (cdr (assq 'inhibit-same-window alist))
4835 (window-minibuffer-p)
4836 (window-dedicated-p))
51a5f9d8 4837 (window--display-buffer buffer (selected-window) 'reuse)))
89894cd8 4838
0d3ff375 4839(defun display-buffer--maybe-same-window (buffer alist)
8319e0bf
CY
4840 "Conditionally display BUFFER in the selected window.
4841If `same-window-p' returns non-nil for BUFFER's name, call
4842`display-buffer-same-window' and return its value. Otherwise,
4843return nil."
89894cd8
CY
4844 (and (same-window-p (buffer-name buffer))
4845 (display-buffer-same-window buffer alist)))
4846
4847(defun display-buffer-reuse-window (buffer alist)
4848 "Return a window that is already displaying BUFFER.
8319e0bf
CY
4849Return nil if no usable window is found.
4850
4851If ALIST has a non-nil `inhibit-same-window' entry, the selected
4852window is not eligible for reuse.
4853
4854If ALIST contains a `reusable-frames' entry, its value determines
4855which frames to search for a reusable window:
4856 nil -- the selected frame (actually the last non-minibuffer frame)
4857 A frame -- just that frame
4858 `visible' -- all visible frames
4859 0 -- all frames on the current terminal
4860 t -- all frames.
4861
4862If ALIST contains no `reusable-frames' entry, search just the
4863selected frame if `display-buffer-reuse-frames' and
4864`pop-up-frames' are both nil; search all frames on the current
90749b53
CY
4865terminal if either of those variables is non-nil.
4866
4867If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
4868event that a window on another frame is chosen, avoid raising
4869that frame."
8319e0bf
CY
4870 (let* ((alist-entry (assq 'reusable-frames alist))
4871 (frames (cond (alist-entry (cdr alist-entry))
4872 ((if (eq pop-up-frames 'graphic-only)
4873 (display-graphic-p)
4874 pop-up-frames)
4875 0)
4876 (display-buffer-reuse-frames 0)
4877 (t (last-nonminibuffer-frame))))
4878 (window (if (and (eq buffer (window-buffer))
4879 (not (cdr (assq 'inhibit-same-window alist))))
4880 (selected-window)
4881 (car (delq (selected-window)
4882 (get-buffer-window-list buffer 'nomini
4883 frames))))))
90749b53
CY
4884 (when (window-live-p window)
4885 (prog1 (window--display-buffer buffer window 'reuse)
4886 (unless (cdr (assq 'inhibit-switch-frame alist))
4887 (window--maybe-raise-frame (window-frame window)))))))
89894cd8 4888
0a9f9ab5 4889(defun display-buffer--special-action (buffer)
4ad3bc2a
CY
4890 "Return special display action for BUFFER, if any.
4891If `special-display-p' returns non-nil for BUFFER, return an
4892appropriate display action involving `special-display-function'.
4893See `display-buffer' for the format of display actions."
8319e0bf
CY
4894 (and special-display-function
4895 ;; `special-display-p' returns either t or a list of frame
4896 ;; parameters to pass to `special-display-function'.
4897 (let ((pars (special-display-p (buffer-name buffer))))
4898 (when pars
0a9f9ab5
SM
4899 (list (list #'display-buffer-reuse-window
4900 `(lambda (buffer _alist)
4901 (funcall special-display-function
4902 buffer ',(if (listp pars) pars)))))))))
8319e0bf 4903
90749b53 4904(defun display-buffer-pop-up-frame (buffer alist)
89894cd8 4905 "Display BUFFER in a new frame.
8319e0bf 4906This works by calling `pop-up-frame-function'. If successful,
90749b53
CY
4907return the window used; otherwise return nil.
4908
4909If ALIST has a non-nil `inhibit-switch-frame' entry, avoid
4910raising the new frame."
89894cd8
CY
4911 (let ((fun pop-up-frame-function)
4912 frame window)
4913 (when (and fun
4914 (setq frame (funcall fun))
4915 (setq window (frame-selected-window frame)))
90749b53
CY
4916 (prog1 (window--display-buffer buffer window
4917 'frame display-buffer-mark-dedicated)
4918 (unless (cdr (assq 'inhibit-switch-frame alist))
4919 (window--maybe-raise-frame frame))))))
89894cd8 4920
90749b53 4921(defun display-buffer-pop-up-window (buffer alist)
89894cd8
CY
4922 "Display BUFFER by popping up a new window.
4923The new window is created on the selected frame, or in
4924`last-nonminibuffer-frame' if no windows can be created there.
90749b53
CY
4925If successful, return the new window; otherwise return nil.
4926
4927If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
4928event that the new window is created on another frame, avoid
4929raising the frame."
89894cd8
CY
4930 (let ((frame (or (window--frame-usable-p (selected-frame))
4931 (window--frame-usable-p (last-nonminibuffer-frame))))
4932 window)
4933 (when (and (or (not (frame-parameter frame 'unsplittable))
4934 ;; If the selected frame cannot be split, look at
4935 ;; `last-nonminibuffer-frame'.
4936 (and (eq frame (selected-frame))
4937 (setq frame (last-nonminibuffer-frame))
4938 (window--frame-usable-p frame)
4939 (not (frame-parameter frame 'unsplittable))))
4940 ;; Attempt to split largest or least recently used window.
4941 (setq window (or (window--try-to-split-window
4942 (get-largest-window frame t))
4943 (window--try-to-split-window
4944 (get-lru-window frame t)))))
90749b53
CY
4945 (prog1 (window--display-buffer buffer window
4946 'window display-buffer-mark-dedicated)
4947 (unless (cdr (assq 'inhibit-switch-frame alist))
4948 (window--maybe-raise-frame (window-frame window)))))))
89894cd8 4949
8319e0bf
CY
4950(defun display-buffer--maybe-pop-up-frame-or-window (buffer alist)
4951 "Try displaying BUFFER based on `pop-up-frames' or `pop-up-windows'.
4952
4953If `pop-up-frames' is non-nil (and not `graphic-only' on a
4954text-only terminal), try with `display-buffer-pop-up-frame'.
4955
4956If that cannot be done, and `pop-up-windows' is non-nil, try
4957again with `display-buffer-pop-up-window'."
4958 (or (and (if (eq pop-up-frames 'graphic-only)
4959 (display-graphic-p)
4960 pop-up-frames)
4961 (display-buffer-pop-up-frame buffer alist))
4962 (and pop-up-windows
4963 (display-buffer-pop-up-window buffer alist))))
89894cd8
CY
4964
4965(defun display-buffer-use-some-window (buffer alist)
4966 "Display BUFFER in an existing window.
4967Search for a usable window, set that window to the buffer, and
90749b53
CY
4968return the window. If no suitable window is found, return nil.
4969
4970If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
4971event that a window in another frame is chosen, avoid raising
4972that frame."
89894cd8 4973 (let* ((not-this-window (cdr (assq 'inhibit-same-window alist)))
89894cd8
CY
4974 (frame (or (window--frame-usable-p (selected-frame))
4975 (window--frame-usable-p (last-nonminibuffer-frame))))
51a5f9d8
MR
4976 (window
4977 ;; Reuse an existing window.
4978 (or (get-lru-window frame nil not-this-window)
4979 (let ((window (get-buffer-window buffer 'visible)))
4980 (unless (and not-this-window
4981 (eq window (selected-window)))
4982 window))
4983 (get-largest-window 'visible nil not-this-window)
4984 (let ((window (get-buffer-window buffer 0)))
4985 (unless (and not-this-window
4986 (eq window (selected-window)))
4987 window))
4988 (get-largest-window 0 not-this-window))))
90749b53 4989 (when (window-live-p window)
89894cd8 4990 (window--even-window-heights window)
90749b53
CY
4991 (prog1 (window--display-buffer buffer window 'reuse)
4992 (unless (cdr (assq 'inhibit-switch-frame alist))
4993 (window--maybe-raise-frame (window-frame window)))))))
437014c8
CY
4994
4995;;; Display + selection commands:
c3313451
CY
4996(defun pop-to-buffer (buffer &optional action norecord)
4997 "Select buffer BUFFER in some window, preferably a different one.
4998BUFFER may be a buffer, a string (a buffer name), or nil. If it
4999is a string not naming an existent buffer, create a buffer with
5000that name. If BUFFER is nil, choose some other buffer. Return
5001the buffer.
5002
5003This uses `display-buffer' as a subroutine. The optional ACTION
5004argument is passed to `display-buffer' as its ACTION argument.
5005See `display-buffer' for more information. ACTION is t if called
5006interactively with a prefix argument, which means to pop to a
5007window other than the selected one even if the buffer is already
5008displayed in the selected window.
5009
5010If the window to show BUFFER is not on the selected
f818cd2a
MR
5011frame, raise that window's frame and give it input focus.
5012
f818cd2a
MR
5013Optional third arg NORECORD non-nil means do not put this buffer
5014at the front of the list of recently selected ones."
c3313451
CY
5015 (interactive (list (read-buffer "Pop to buffer: " (other-buffer))
5016 (if current-prefix-arg t)))
8319e0bf 5017 (setq buffer (window-normalize-buffer-to-switch-to buffer))
c3313451 5018 (set-buffer buffer)
cb882333 5019 (let* ((old-frame (selected-frame))
8319e0bf 5020 (window (display-buffer buffer action))
c3313451 5021 (frame (window-frame window)))
97adfb97
CY
5022 ;; If we chose another frame, make sure it gets input focus.
5023 (unless (eq frame old-frame)
c3313451 5024 (select-frame-set-input-focus frame norecord))
97adfb97
CY
5025 ;; Make sure new window is selected (Bug#8615), (Bug#6954).
5026 (select-window window norecord)
c3313451 5027 buffer))
f818cd2a 5028
72258fe5
CY
5029(defun pop-to-buffer-same-window (buffer &optional norecord)
5030 "Select buffer BUFFER in some window, preferably the same one.
5031This function behaves much like `switch-to-buffer', except it
5032displays with `special-display-function' if BUFFER has a match in
5033`special-display-buffer-names' or `special-display-regexps'.
5034
5035Unlike `pop-to-buffer', this function prefers using the selected
5036window over popping up a new window or frame.
5037
5038BUFFER may be a buffer, a string (a buffer name), or nil. If it
5039is a string not naming an existent buffer, create a buffer with
5040that name. If BUFFER is nil, choose some other buffer. Return
5041the buffer.
5042
5043NORECORD, if non-nil means do not put this buffer at the front of
5044the list of recently selected ones."
24510c22 5045 (pop-to-buffer buffer display-buffer--same-window-action norecord))
72258fe5 5046
f818cd2a
MR
5047(defun read-buffer-to-switch (prompt)
5048 "Read the name of a buffer to switch to, prompting with PROMPT.
e1dbe924 5049Return the name of the buffer as a string.
f818cd2a
MR
5050
5051This function is intended for the `switch-to-buffer' family of
5052commands since these need to omit the name of the current buffer
5053from the list of completions and default values."
5054 (let ((rbts-completion-table (internal-complete-buffer-except)))
5055 (minibuffer-with-setup-hook
5056 (lambda ()
5057 (setq minibuffer-completion-table rbts-completion-table)
5058 ;; Since rbts-completion-table is built dynamically, we
5059 ;; can't just add it to the default value of
5060 ;; icomplete-with-completion-tables, so we add it
5061 ;; here manually.
5062 (if (and (boundp 'icomplete-with-completion-tables)
5063 (listp icomplete-with-completion-tables))
5064 (set (make-local-variable 'icomplete-with-completion-tables)
5065 (cons rbts-completion-table
5066 icomplete-with-completion-tables))))
5067 (read-buffer prompt (other-buffer (current-buffer))
5068 (confirm-nonexistent-file-or-buffer)))))
5069
5070(defun window-normalize-buffer-to-switch-to (buffer-or-name)
5071 "Normalize BUFFER-OR-NAME argument of buffer switching functions.
5072If BUFFER-OR-NAME is nil, return the buffer returned by
5073`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
5074exists, return that buffer. If no such buffer exists, create a
5075buffer with the name BUFFER-OR-NAME and return that buffer."
5076 (if buffer-or-name
5077 (or (get-buffer buffer-or-name)
5078 (let ((buffer (get-buffer-create buffer-or-name)))
5079 (set-buffer-major-mode buffer)
5080 buffer))
5081 (other-buffer)))
5082
5083(defun switch-to-buffer (buffer-or-name &optional norecord force-same-window)
5084 "Switch to buffer BUFFER-OR-NAME in the selected window.
5085If called interactively, prompt for the buffer name using the
5086minibuffer. The variable `confirm-nonexistent-file-or-buffer'
5087determines whether to request confirmation before creating a new
5088buffer.
5089
382c953b 5090BUFFER-OR-NAME may be a buffer, a string (a buffer name), or
f818cd2a
MR
5091nil. If BUFFER-OR-NAME is a string that does not identify an
5092existing buffer, create a buffer with that name. If
5093BUFFER-OR-NAME is nil, switch to the buffer returned by
5094`other-buffer'.
5095
5096Optional argument NORECORD non-nil means do not put the buffer
5097specified by BUFFER-OR-NAME at the front of the buffer list and
5098do not make the window displaying it the most recently selected
5099one.
5100
5101If FORCE-SAME-WINDOW is non-nil, BUFFER-OR-NAME must be displayed
94e0933e
CY
5102in the selected window; signal an error if that is
5103impossible (e.g. if the selected window is minibuffer-only). If
235ce86f 5104nil, BUFFER-OR-NAME may be displayed in another window.
f818cd2a
MR
5105
5106Return the buffer switched to."
5107 (interactive
acc825c5 5108 (list (read-buffer-to-switch "Switch to buffer: ") nil 'force-same-window))
f818cd2a 5109 (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
24510c22
SM
5110 (cond
5111 ;; Don't call set-window-buffer if it's not needed since it
5112 ;; might signal an error (e.g. if the window is dedicated).
5113 ((eq buffer (window-buffer)))
5114 ((window-minibuffer-p)
5115 (if force-same-window
71873e2b 5116 (user-error "Cannot switch buffers in minibuffer window")
24510c22
SM
5117 (pop-to-buffer buffer norecord)))
5118 ((eq (window-dedicated-p) t)
5119 (if force-same-window
71873e2b 5120 (user-error "Cannot switch buffers in a dedicated window")
24510c22
SM
5121 (pop-to-buffer buffer norecord)))
5122 (t (set-window-buffer nil buffer)))
5123
5124 (unless norecord
5125 (select-window (selected-window)))
5126 (set-buffer buffer)))
f818cd2a
MR
5127
5128(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
5129 "Select the buffer specified by BUFFER-OR-NAME in another window.
382c953b 5130BUFFER-OR-NAME may be a buffer, a string (a buffer name), or
f818cd2a
MR
5131nil. Return the buffer switched to.
5132
5133If called interactively, prompt for the buffer name using the
5134minibuffer. The variable `confirm-nonexistent-file-or-buffer'
5135determines whether to request confirmation before creating a new
5136buffer.
5137
5138If BUFFER-OR-NAME is a string and does not identify an existing
5139buffer, create a new buffer with that name. If BUFFER-OR-NAME is
5140nil, switch to the buffer returned by `other-buffer'.
5141
5142Optional second argument NORECORD non-nil means do not put this
5143buffer at the front of the list of recently selected ones.
5144
5145This uses the function `display-buffer' as a subroutine; see its
5146documentation for additional customization information."
5147 (interactive
5148 (list (read-buffer-to-switch "Switch to buffer in other window: ")))
8319e0bf
CY
5149 (let ((pop-up-windows t))
5150 (pop-to-buffer buffer-or-name t norecord)))
f818cd2a
MR
5151
5152(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
5153 "Switch to buffer BUFFER-OR-NAME in another frame.
382c953b 5154BUFFER-OR-NAME may be a buffer, a string (a buffer name), or
f818cd2a
MR
5155nil. Return the buffer switched to.
5156
5157If called interactively, prompt for the buffer name using the
5158minibuffer. The variable `confirm-nonexistent-file-or-buffer'
5159determines whether to request confirmation before creating a new
5160buffer.
5161
5162If BUFFER-OR-NAME is a string and does not identify an existing
5163buffer, create a new buffer with that name. If BUFFER-OR-NAME is
5164nil, switch to the buffer returned by `other-buffer'.
5165
5166Optional second arg NORECORD non-nil means do not put this
5167buffer at the front of the list of recently selected ones.
5168
5169This uses the function `display-buffer' as a subroutine; see its
5170documentation for additional customization information."
5171 (interactive
5172 (list (read-buffer-to-switch "Switch to buffer in other frame: ")))
8319e0bf 5173 (pop-to-buffer buffer-or-name display-buffer--other-frame-action norecord))
3c448ab6
MR
5174\f
5175(defun set-window-text-height (window height)
9992ea0c 5176 "Set the height in lines of the text display area of WINDOW to HEIGHT.
85c2386b
MR
5177WINDOW must be a live window and defaults to the selected one.
5178HEIGHT doesn't include the mode line or header line, if any, or
5179any partial-height lines in the text display area.
3c448ab6
MR
5180
5181Note that the current implementation of this function cannot
5182always set the height exactly, but attempts to be conservative,
5183by allocating more lines than are actually needed in the case
5184where some error may be present."
447f16b8 5185 (setq window (window-normalize-window window t))
3c448ab6
MR
5186 (let ((delta (- height (window-text-height window))))
5187 (unless (zerop delta)
5188 ;; Setting window-min-height to a value like 1 can lead to very
5189 ;; bizarre displays because it also allows Emacs to make *other*
37269466
CY
5190 ;; windows one line tall, which means that there's no more space
5191 ;; for the mode line.
5192 (let ((window-min-height (min 2 height)))
d615d6d2 5193 (window-resize window delta)))))
3c448ab6 5194
6198ccd0
MR
5195(defun enlarge-window-horizontally (delta)
5196 "Make selected window DELTA columns wider.
3c448ab6
MR
5197Interactively, if no argument is given, make selected window one
5198column wider."
5199 (interactive "p")
6198ccd0 5200 (enlarge-window delta t))
3c448ab6 5201
6198ccd0
MR
5202(defun shrink-window-horizontally (delta)
5203 "Make selected window DELTA columns narrower.
3c448ab6
MR
5204Interactively, if no argument is given, make selected window one
5205column narrower."
5206 (interactive "p")
6198ccd0 5207 (shrink-window delta t))
3c448ab6
MR
5208
5209(defun count-screen-lines (&optional beg end count-final-newline window)
5210 "Return the number of screen lines in the region.
5211The number of screen lines may be different from the number of actual lines,
5212due to line breaking, display table, etc.
5213
5214Optional arguments BEG and END default to `point-min' and `point-max'
5215respectively.
5216
5217If region ends with a newline, ignore it unless optional third argument
5218COUNT-FINAL-NEWLINE is non-nil.
5219
5220The optional fourth argument WINDOW specifies the window used for obtaining
5221parameters such as width, horizontal scrolling, and so on. The default is
5222to use the selected window's parameters.
5223
5224Like `vertical-motion', `count-screen-lines' always uses the current buffer,
5225regardless of which buffer is displayed in WINDOW. This makes possible to use
5226`count-screen-lines' in any buffer, whether or not it is currently displayed
5227in some window."
5228 (unless beg
5229 (setq beg (point-min)))
5230 (unless end
5231 (setq end (point-max)))
5232 (if (= beg end)
5233 0
5234 (save-excursion
5235 (save-restriction
5236 (widen)
5237 (narrow-to-region (min beg end)
5238 (if (and (not count-final-newline)
5239 (= ?\n (char-before (max beg end))))
5240 (1- (max beg end))
5241 (max beg end)))
5242 (goto-char (point-min))
5243 (1+ (vertical-motion (buffer-size) window))))))
5244
6198ccd0 5245(defun window-buffer-height (window)
85c2386b
MR
5246 "Return the height (in screen lines) of the buffer that WINDOW is displaying.
5247WINDOW must be a live window and defaults to the selected one."
5248 (setq window (window-normalize-window window t))
6198ccd0
MR
5249 (with-current-buffer (window-buffer window)
5250 (max 1
5251 (count-screen-lines (point-min) (point-max)
5252 ;; If buffer ends with a newline, ignore it when
5253 ;; counting height unless point is after it.
5254 (eobp)
5255 window))))
5256
5257;;; Resizing buffers to fit their contents exactly.
5258(defun fit-window-to-buffer (&optional window max-height min-height override)
3c448ab6 5259 "Adjust height of WINDOW to display its buffer's contents exactly.
85c2386b 5260WINDOW must be a live window and defaults to the selected one.
6198ccd0
MR
5261
5262Optional argument MAX-HEIGHT specifies the maximum height of
5263WINDOW and defaults to the height of WINDOW's frame. Optional
5264argument MIN-HEIGHT specifies the minimum height of WINDOW and
382c953b 5265defaults to `window-min-height'. Both MAX-HEIGHT and MIN-HEIGHT
6198ccd0
MR
5266are specified in lines and include the mode line and header line,
5267if any.
5268
5269Optional argument OVERRIDE non-nil means override restrictions
5270imposed by `window-min-height' and `window-min-width' on the size
5271of WINDOW.
5272
5273Return the number of lines by which WINDOW was enlarged or
5274shrunk. If an error occurs during resizing, return nil but don't
5275signal an error.
5276
5277Note that even if this function makes WINDOW large enough to show
5278_all_ lines of its buffer you might not see the first lines when
5279WINDOW was scrolled."
f7baca20
MR
5280 (interactive)
5281 ;; Do all the work in WINDOW and its buffer and restore the selected
5282 ;; window and the current buffer when we're done.
447f16b8 5283 (setq window (window-normalize-window window t))
6198ccd0 5284 ;; Can't resize a full height or fixed-size window.
9173deec 5285 (unless (or (window-size-fixed-p window)
6198ccd0
MR
5286 (window-full-height-p window))
5287 ;; `with-selected-window' should orderly restore the current buffer.
5288 (with-selected-window window
5289 ;; We are in WINDOW's buffer now.
938b94c8 5290 (let* (;; Adjust MIN-HEIGHT.
6198ccd0
MR
5291 (min-height
5292 (if override
5293 (window-min-size window nil window)
5294 (max (or min-height window-min-height)
5295 window-safe-min-height)))
5296 (max-window-height
5297 (window-total-size (frame-root-window window)))
5298 ;; Adjust MAX-HEIGHT.
5299 (max-height
5300 (if (or override (not max-height))
5301 max-window-height
5302 (min max-height max-window-height)))
5303 ;; Make `desired-height' the height necessary to show
5304 ;; all of WINDOW's buffer, constrained by MIN-HEIGHT
5305 ;; and MAX-HEIGHT.
5306 (desired-height
5307 (max
5308 (min
5309 (+ (count-screen-lines)
5310 ;; For non-minibuffers count the mode line, if any.
5311 (if (and (not (window-minibuffer-p window))
5312 mode-line-format)
5313 1
5314 0)
5315 ;; Count the header line, if any.
5316 (if header-line-format 1 0))
5317 max-height)
5318 min-height))
5319 (desired-delta
5320 (- desired-height (window-total-size window)))
5321 (delta
5322 (if (> desired-delta 0)
5323 (min desired-delta
5324 (window-max-delta window nil window))
5325 (max desired-delta
5326 (- (window-min-delta window nil window))))))
5327 ;; This `condition-case' shouldn't be necessary, but who knows?
5328 (condition-case nil
5329 (if (zerop delta)
c80e3b4a 5330 ;; Return zero if DELTA became zero in the process.
6198ccd0
MR
5331 0
5332 ;; Don't try to redisplay with the cursor at the end on its
5333 ;; own line--that would force a scroll and spoil things.
5334 (when (and (eobp) (bolp) (not (bobp)))
5335 ;; It's silly to put `point' at the end of the previous
5336 ;; line and so maybe force horizontal scrolling.
5337 (set-window-point window (line-beginning-position 0)))
d615d6d2
MR
5338 ;; Call `window-resize' with OVERRIDE argument equal WINDOW.
5339 (window-resize window delta nil window)
f7baca20
MR
5340 ;; Check if the last line is surely fully visible. If
5341 ;; not, enlarge the window.
5342 (let ((end (save-excursion
5343 (goto-char (point-max))
5344 (when (and (bolp) (not (bobp)))
5345 ;; Don't include final newline.
5346 (backward-char 1))
5347 (when truncate-lines
5348 ;; If line-wrapping is turned off, test the
5349 ;; beginning of the last line for
5350 ;; visibility instead of the end, as the
5351 ;; end of the line could be invisible by
5352 ;; virtue of extending past the edge of the
5353 ;; window.
5354 (forward-line 0))
5355 (point))))
5356 (set-window-vscroll window 0)
6198ccd0
MR
5357 ;; This loop might in some rare pathological cases raise
5358 ;; an error - another reason for the `condition-case'.
f7baca20 5359 (while (and (< desired-height max-height)
6198ccd0 5360 (= desired-height (window-total-size))
f7baca20 5361 (not (pos-visible-in-window-p end)))
d615d6d2 5362 (window-resize window 1 nil window)
6198ccd0
MR
5363 (setq desired-height (1+ desired-height)))))
5364 (error (setq delta nil)))
5365 delta))))
3c448ab6 5366
39cffb44
MR
5367(defun window-safely-shrinkable-p (&optional window)
5368 "Return t if WINDOW can be shrunk without shrinking other windows.
5369WINDOW defaults to the selected window."
5370 (with-selected-window (or window (selected-window))
5371 (let ((edges (window-edges)))
39cffb44
MR
5372 (or (= (nth 2 edges) (nth 2 (window-edges (previous-window))))
5373 (= (nth 0 edges) (nth 0 (window-edges (next-window))))))))
39cffb44 5374
3c448ab6
MR
5375(defun shrink-window-if-larger-than-buffer (&optional window)
5376 "Shrink height of WINDOW if its buffer doesn't need so many lines.
5377More precisely, shrink WINDOW vertically to be as small as
5378possible, while still showing the full contents of its buffer.
85c2386b 5379WINDOW must be a live window and defaults to the selected one.
3c448ab6 5380
6198ccd0
MR
5381Do not shrink WINDOW to less than `window-min-height' lines. Do
5382nothing if the buffer contains more lines than the present window
5383height, or if some of the window's contents are scrolled out of
5384view, or if shrinking this window would also shrink another
5385window, or if the window is the only window of its frame.
3c448ab6
MR
5386
5387Return non-nil if the window was shrunk, nil otherwise."
5388 (interactive)
447f16b8 5389 (setq window (window-normalize-window window t))
6198ccd0
MR
5390 ;; Make sure that WINDOW is vertically combined and `point-min' is
5391 ;; visible (for whatever reason that's needed). The remaining issues
5392 ;; should be taken care of by `fit-window-to-buffer'.
3d8daefe 5393 (when (and (window-combined-p window)
6198ccd0
MR
5394 (pos-visible-in-window-p (point-min) window))
5395 (fit-window-to-buffer window (window-total-size window))))
5396\f
3c448ab6
MR
5397(defun kill-buffer-and-window ()
5398 "Kill the current buffer and delete the selected window."
5399 (interactive)
5400 (let ((window-to-delete (selected-window))
5401 (buffer-to-kill (current-buffer))
6198ccd0 5402 (delete-window-hook (lambda () (ignore-errors (delete-window)))))
3c448ab6
MR
5403 (unwind-protect
5404 (progn
5405 (add-hook 'kill-buffer-hook delete-window-hook t t)
5406 (if (kill-buffer (current-buffer))
5407 ;; If `delete-window' failed before, we rerun it to regenerate
5408 ;; the error so it can be seen in the echo area.
5409 (when (eq (selected-window) window-to-delete)
5410 (delete-window))))
5411 ;; If the buffer is not dead for some reason (probably because
5412 ;; of a `quit' signal), remove the hook again.
6198ccd0
MR
5413 (ignore-errors
5414 (with-current-buffer buffer-to-kill
5415 (remove-hook 'kill-buffer-hook delete-window-hook t))))))
3c448ab6 5416
74f806a1 5417\f
3c448ab6
MR
5418(defvar recenter-last-op nil
5419 "Indicates the last recenter operation performed.
0116abbd
JL
5420Possible values: `top', `middle', `bottom', integer or float numbers.")
5421
5422(defcustom recenter-positions '(middle top bottom)
5423 "Cycling order for `recenter-top-bottom'.
5424A list of elements with possible values `top', `middle', `bottom',
5425integer or float numbers that define the cycling order for
5426the command `recenter-top-bottom'.
5427
382c953b 5428Top and bottom destinations are `scroll-margin' lines from the true
0116abbd
JL
5429window top and bottom. Middle redraws the frame and centers point
5430vertically within the window. Integer number moves current line to
5431the specified absolute window-line. Float number between 0.0 and 1.0
5432means the percentage of the screen space from the top. The default
5433cycling order is middle -> top -> bottom."
5434 :type '(repeat (choice
5435 (const :tag "Top" top)
5436 (const :tag "Middle" middle)
5437 (const :tag "Bottom" bottom)
5438 (integer :tag "Line number")
5439 (float :tag "Percentage")))
5440 :version "23.2"
5441 :group 'windows)
3c448ab6
MR
5442
5443(defun recenter-top-bottom (&optional arg)
0116abbd
JL
5444 "Move current buffer line to the specified window line.
5445With no prefix argument, successive calls place point according
5446to the cycling order defined by `recenter-positions'.
3c448ab6
MR
5447
5448A prefix argument is handled like `recenter':
5449 With numeric prefix ARG, move current line to window-line ARG.
0116abbd 5450 With plain `C-u', move current line to window center."
3c448ab6
MR
5451 (interactive "P")
5452 (cond
0116abbd 5453 (arg (recenter arg)) ; Always respect ARG.
3c448ab6 5454 (t
0116abbd
JL
5455 (setq recenter-last-op
5456 (if (eq this-command last-command)
5457 (car (or (cdr (member recenter-last-op recenter-positions))
5458 recenter-positions))
5459 (car recenter-positions)))
3c448ab6
MR
5460 (let ((this-scroll-margin
5461 (min (max 0 scroll-margin)
5462 (truncate (/ (window-body-height) 4.0)))))
5463 (cond ((eq recenter-last-op 'middle)
0116abbd 5464 (recenter))
3c448ab6 5465 ((eq recenter-last-op 'top)
0116abbd
JL
5466 (recenter this-scroll-margin))
5467 ((eq recenter-last-op 'bottom)
5468 (recenter (- -1 this-scroll-margin)))
5469 ((integerp recenter-last-op)
5470 (recenter recenter-last-op))
5471 ((floatp recenter-last-op)
5472 (recenter (round (* recenter-last-op (window-height))))))))))
3c448ab6
MR
5473
5474(define-key global-map [?\C-l] 'recenter-top-bottom)
216349f8 5475
216349f8
SM
5476(defun move-to-window-line-top-bottom (&optional arg)
5477 "Position point relative to window.
5478
0f202d5d 5479With a prefix argument ARG, acts like `move-to-window-line'.
216349f8
SM
5480
5481With no argument, positions point at center of window.
0116abbd
JL
5482Successive calls position point at positions defined
5483by `recenter-positions'."
216349f8
SM
5484 (interactive "P")
5485 (cond
0116abbd 5486 (arg (move-to-window-line arg)) ; Always respect ARG.
216349f8 5487 (t
0116abbd
JL
5488 (setq recenter-last-op
5489 (if (eq this-command last-command)
5490 (car (or (cdr (member recenter-last-op recenter-positions))
5491 recenter-positions))
5492 (car recenter-positions)))
216349f8
SM
5493 (let ((this-scroll-margin
5494 (min (max 0 scroll-margin)
5495 (truncate (/ (window-body-height) 4.0)))))
0f202d5d 5496 (cond ((eq recenter-last-op 'middle)
0116abbd 5497 (call-interactively 'move-to-window-line))
0f202d5d 5498 ((eq recenter-last-op 'top)
0116abbd
JL
5499 (move-to-window-line this-scroll-margin))
5500 ((eq recenter-last-op 'bottom)
5501 (move-to-window-line (- -1 this-scroll-margin)))
5502 ((integerp recenter-last-op)
5503 (move-to-window-line recenter-last-op))
5504 ((floatp recenter-last-op)
5505 (move-to-window-line (round (* recenter-last-op (window-height))))))))))
216349f8
SM
5506
5507(define-key global-map [?\M-r] 'move-to-window-line-top-bottom)
3c448ab6 5508\f
74f806a1
JL
5509;;; Scrolling commands.
5510
0a9f9ab5
SM
5511;;; Scrolling commands which do not signal errors at top/bottom
5512;;; of buffer at first key-press (instead move to top/bottom
74f806a1
JL
5513;;; of buffer).
5514
5515(defcustom scroll-error-top-bottom nil
8350f087 5516 "Move point to top/bottom of buffer before signaling a scrolling error.
74f806a1
JL
5517A value of nil means just signal an error if no more scrolling possible.
5518A value of t means point moves to the beginning or the end of the buffer
5519\(depending on scrolling direction) when no more scrolling possible.
5520When point is already on that position, then signal an error."
5521 :type 'boolean
60efac0f 5522 :group 'windows
74f806a1
JL
5523 :version "24.1")
5524
5525(defun scroll-up-command (&optional arg)
5526 "Scroll text of selected window upward ARG lines; or near full screen if no ARG.
5527If `scroll-error-top-bottom' is non-nil and `scroll-up' cannot
5528scroll window further, move cursor to the bottom line.
5529When point is already on that position, then signal an error.
5530A near full screen is `next-screen-context-lines' less than a full screen.
5531Negative ARG means scroll downward.
5532If ARG is the atom `-', scroll downward by nearly full screen."
5533 (interactive "^P")
5534 (cond
5535 ((null scroll-error-top-bottom)
5536 (scroll-up arg))
5537 ((eq arg '-)
5538 (scroll-down-command nil))
5539 ((< (prefix-numeric-value arg) 0)
5540 (scroll-down-command (- (prefix-numeric-value arg))))
5541 ((eobp)
5542 (scroll-up arg)) ; signal error
5543 (t
5544 (condition-case nil
5545 (scroll-up arg)
5546 (end-of-buffer
5547 (if arg
5548 ;; When scrolling by ARG lines can't be done,
5549 ;; move by ARG lines instead.
5550 (forward-line arg)
5551 ;; When ARG is nil for full-screen scrolling,
5552 ;; move to the bottom of the buffer.
5553 (goto-char (point-max))))))))
5554
5555(put 'scroll-up-command 'scroll-command t)
5556
5557(defun scroll-down-command (&optional arg)
5558 "Scroll text of selected window down ARG lines; or near full screen if no ARG.
5559If `scroll-error-top-bottom' is non-nil and `scroll-down' cannot
5560scroll window further, move cursor to the top line.
5561When point is already on that position, then signal an error.
5562A near full screen is `next-screen-context-lines' less than a full screen.
5563Negative ARG means scroll upward.
5564If ARG is the atom `-', scroll upward by nearly full screen."
5565 (interactive "^P")
5566 (cond
5567 ((null scroll-error-top-bottom)
5568 (scroll-down arg))
5569 ((eq arg '-)
5570 (scroll-up-command nil))
5571 ((< (prefix-numeric-value arg) 0)
5572 (scroll-up-command (- (prefix-numeric-value arg))))
5573 ((bobp)
5574 (scroll-down arg)) ; signal error
5575 (t
5576 (condition-case nil
5577 (scroll-down arg)
5578 (beginning-of-buffer
5579 (if arg
5580 ;; When scrolling by ARG lines can't be done,
5581 ;; move by ARG lines instead.
5582 (forward-line (- arg))
5583 ;; When ARG is nil for full-screen scrolling,
5584 ;; move to the top of the buffer.
5585 (goto-char (point-min))))))))
5586
5587(put 'scroll-down-command 'scroll-command t)
5588
5589;;; Scrolling commands which scroll a line instead of full screen.
5590
5591(defun scroll-up-line (&optional arg)
5592 "Scroll text of selected window upward ARG lines; or one line if no ARG.
5593If ARG is omitted or nil, scroll upward by one line.
5594This is different from `scroll-up-command' that scrolls a full screen."
5595 (interactive "p")
5596 (scroll-up (or arg 1)))
5597
5598(put 'scroll-up-line 'scroll-command t)
5599
5600(defun scroll-down-line (&optional arg)
5601 "Scroll text of selected window down ARG lines; or one line if no ARG.
5602If ARG is omitted or nil, scroll down by one line.
5603This is different from `scroll-down-command' that scrolls a full screen."
5604 (interactive "p")
5605 (scroll-down (or arg 1)))
5606
5607(put 'scroll-down-line 'scroll-command t)
5608
5609\f
5610(defun scroll-other-window-down (lines)
5611 "Scroll the \"other window\" down.
5612For more details, see the documentation for `scroll-other-window'."
5613 (interactive "P")
5614 (scroll-other-window
5615 ;; Just invert the argument's meaning.
5616 ;; We can do that without knowing which window it will be.
5617 (if (eq lines '-) nil
5618 (if (null lines) '-
5619 (- (prefix-numeric-value lines))))))
5620
5621(defun beginning-of-buffer-other-window (arg)
5622 "Move point to the beginning of the buffer in the other window.
5623Leave mark at previous position.
5624With arg N, put point N/10 of the way from the true beginning."
5625 (interactive "P")
5626 (let ((orig-window (selected-window))
5627 (window (other-window-for-scrolling)))
5628 ;; We use unwind-protect rather than save-window-excursion
5629 ;; because the latter would preserve the things we want to change.
5630 (unwind-protect
5631 (progn
5632 (select-window window)
5633 ;; Set point and mark in that window's buffer.
5634 (with-no-warnings
5635 (beginning-of-buffer arg))
5636 ;; Set point accordingly.
5637 (recenter '(t)))
5638 (select-window orig-window))))
5639
5640(defun end-of-buffer-other-window (arg)
5641 "Move point to the end of the buffer in the other window.
5642Leave mark at previous position.
5643With arg N, put point N/10 of the way from the true end."
5644 (interactive "P")
5645 ;; See beginning-of-buffer-other-window for comments.
5646 (let ((orig-window (selected-window))
5647 (window (other-window-for-scrolling)))
5648 (unwind-protect
5649 (progn
5650 (select-window window)
5651 (with-no-warnings
5652 (end-of-buffer arg))
5653 (recenter '(t)))
5654 (select-window orig-window))))
74f806a1 5655\f
3c448ab6
MR
5656(defvar mouse-autoselect-window-timer nil
5657 "Timer used by delayed window autoselection.")
5658
5659(defvar mouse-autoselect-window-position nil
5660 "Last mouse position recorded by delayed window autoselection.")
5661
5662(defvar mouse-autoselect-window-window nil
5663 "Last window recorded by delayed window autoselection.")
5664
5665(defvar mouse-autoselect-window-state nil
5666 "When non-nil, special state of delayed window autoselection.
382c953b
JB
5667Possible values are `suspend' (suspend autoselection after a menu or
5668scrollbar interaction) and `select' (the next invocation of
5669`handle-select-window' shall select the window immediately).")
3c448ab6
MR
5670
5671(defun mouse-autoselect-window-cancel (&optional force)
5672 "Cancel delayed window autoselection.
5673Optional argument FORCE means cancel unconditionally."
5674 (unless (and (not force)
5675 ;; Don't cancel for select-window or select-frame events
5676 ;; or when the user drags a scroll bar.
5677 (or (memq this-command
5678 '(handle-select-window handle-switch-frame))
5679 (and (eq this-command 'scroll-bar-toolkit-scroll)
5680 (memq (nth 4 (event-end last-input-event))
5681 '(handle end-scroll)))))
5682 (setq mouse-autoselect-window-state nil)
5683 (when (timerp mouse-autoselect-window-timer)
5684 (cancel-timer mouse-autoselect-window-timer))
5685 (remove-hook 'pre-command-hook 'mouse-autoselect-window-cancel)))
5686
5687(defun mouse-autoselect-window-start (mouse-position &optional window suspend)
5688 "Start delayed window autoselection.
5689MOUSE-POSITION is the last position where the mouse was seen as returned
5690by `mouse-position'. Optional argument WINDOW non-nil denotes the
5691window where the mouse was seen. Optional argument SUSPEND non-nil
5692means suspend autoselection."
5693 ;; Record values for MOUSE-POSITION, WINDOW, and SUSPEND.
5694 (setq mouse-autoselect-window-position mouse-position)
5695 (when window (setq mouse-autoselect-window-window window))
5696 (setq mouse-autoselect-window-state (when suspend 'suspend))
5697 ;; Install timer which runs `mouse-autoselect-window-select' after
5698 ;; `mouse-autoselect-window' seconds.
5699 (setq mouse-autoselect-window-timer
5700 (run-at-time
5701 (abs mouse-autoselect-window) nil 'mouse-autoselect-window-select)))
5702
5703(defun mouse-autoselect-window-select ()
5704 "Select window with delayed window autoselection.
5705If the mouse position has stabilized in a non-selected window, select
382c953b
JB
5706that window. The minibuffer window is selected only if the minibuffer
5707is active. This function is run by `mouse-autoselect-window-timer'."
6198ccd0
MR
5708 (ignore-errors
5709 (let* ((mouse-position (mouse-position))
5710 (window
5711 (ignore-errors
5712 (window-at (cadr mouse-position) (cddr mouse-position)
5713 (car mouse-position)))))
5714 (cond
5715 ((or (menu-or-popup-active-p)
5716 (and window
5717 (not (coordinates-in-window-p (cdr mouse-position) window))))
5718 ;; A menu / popup dialog is active or the mouse is on the scroll-bar
5719 ;; of WINDOW, temporarily suspend delayed autoselection.
5720 (mouse-autoselect-window-start mouse-position nil t))
5721 ((eq mouse-autoselect-window-state 'suspend)
5722 ;; Delayed autoselection was temporarily suspended, reenable it.
5723 (mouse-autoselect-window-start mouse-position))
5724 ((and window (not (eq window (selected-window)))
5725 (or (not (numberp mouse-autoselect-window))
5726 (and (> mouse-autoselect-window 0)
5727 ;; If `mouse-autoselect-window' is positive, select
5728 ;; window if the window is the same as before.
5729 (eq window mouse-autoselect-window-window))
5730 ;; Otherwise select window if the mouse is at the same
5731 ;; position as before. Observe that the first test after
5732 ;; starting autoselection usually fails since the value of
5733 ;; `mouse-autoselect-window-position' recorded there is the
5734 ;; position where the mouse has entered the new window and
5735 ;; not necessarily where the mouse has stopped moving.
5736 (equal mouse-position mouse-autoselect-window-position))
5737 ;; The minibuffer is a candidate window if it's active.
5738 (or (not (window-minibuffer-p window))
5739 (eq window (active-minibuffer-window))))
5740 ;; Mouse position has stabilized in non-selected window: Cancel
5741 ;; delayed autoselection and try to select that window.
5742 (mouse-autoselect-window-cancel t)
5743 ;; Select window where mouse appears unless the selected window is the
5744 ;; minibuffer. Use `unread-command-events' in order to execute pre-
5745 ;; and post-command hooks and trigger idle timers. To avoid delaying
5746 ;; autoselection again, set `mouse-autoselect-window-state'."
5747 (unless (window-minibuffer-p (selected-window))
5748 (setq mouse-autoselect-window-state 'select)
5749 (setq unread-command-events
5750 (cons (list 'select-window (list window))
5751 unread-command-events))))
5752 ((or (and window (eq window (selected-window)))
5753 (not (numberp mouse-autoselect-window))
5754 (equal mouse-position mouse-autoselect-window-position))
5755 ;; Mouse position has either stabilized in the selected window or at
5756 ;; `mouse-autoselect-window-position': Cancel delayed autoselection.
5757 (mouse-autoselect-window-cancel t))
5758 (t
5759 ;; Mouse position has not stabilized yet, resume delayed
5760 ;; autoselection.
5761 (mouse-autoselect-window-start mouse-position window))))))
3c448ab6
MR
5762
5763(defun handle-select-window (event)
5764 "Handle select-window events."
5765 (interactive "e")
5766 (let ((window (posn-window (event-start event))))
5767 (unless (or (not (window-live-p window))
5768 ;; Don't switch if we're currently in the minibuffer.
5769 ;; This tries to work around problems where the
5770 ;; minibuffer gets unselected unexpectedly, and where
5771 ;; you then have to move your mouse all the way down to
5772 ;; the minibuffer to select it.
5773 (window-minibuffer-p (selected-window))
5774 ;; Don't switch to minibuffer window unless it's active.
5775 (and (window-minibuffer-p window)
5776 (not (minibuffer-window-active-p window)))
5777 ;; Don't switch when autoselection shall be delayed.
5778 (and (numberp mouse-autoselect-window)
5779 (not (zerop mouse-autoselect-window))
5780 (not (eq mouse-autoselect-window-state 'select))
5781 (progn
5782 ;; Cancel any delayed autoselection.
5783 (mouse-autoselect-window-cancel t)
5784 ;; Start delayed autoselection from current mouse
5785 ;; position and window.
5786 (mouse-autoselect-window-start (mouse-position) window)
5787 ;; Executing a command cancels delayed autoselection.
5788 (add-hook
5789 'pre-command-hook 'mouse-autoselect-window-cancel))))
5790 (when mouse-autoselect-window
5791 ;; Reset state of delayed autoselection.
5792 (setq mouse-autoselect-window-state nil)
5793 ;; Run `mouse-leave-buffer-hook' when autoselecting window.
5794 (run-hooks 'mouse-leave-buffer-hook))
b1bac16e
MR
5795 ;; Clear echo area.
5796 (message nil)
3c448ab6
MR
5797 (select-window window))))
5798
3c448ab6
MR
5799(defun truncated-partial-width-window-p (&optional window)
5800 "Return non-nil if lines in WINDOW are specifically truncated due to its width.
85c2386b 5801WINDOW must be a live window and defaults to the selected one.
3c448ab6
MR
5802Return nil if WINDOW is not a partial-width window
5803 (regardless of the value of `truncate-lines').
5804Otherwise, consult the value of `truncate-partial-width-windows'
5805 for the buffer shown in WINDOW."
85c2386b 5806 (setq window (window-normalize-window window t))
3c448ab6
MR
5807 (unless (window-full-width-p window)
5808 (let ((t-p-w-w (buffer-local-value 'truncate-partial-width-windows
5809 (window-buffer window))))
5810 (if (integerp t-p-w-w)
5811 (< (window-width window) t-p-w-w)
5812 t-p-w-w))))
562dd5e9 5813\f
59ee0542
GM
5814;; Some of these are in tutorial--default-keys, so update that if you
5815;; change these.
562dd5e9
MR
5816(define-key ctl-x-map "0" 'delete-window)
5817(define-key ctl-x-map "1" 'delete-other-windows)
2d197ffb
CY
5818(define-key ctl-x-map "2" 'split-window-below)
5819(define-key ctl-x-map "3" 'split-window-right)
9397e56f 5820(define-key ctl-x-map "o" 'other-window)
562dd5e9 5821(define-key ctl-x-map "^" 'enlarge-window)
3c448ab6
MR
5822(define-key ctl-x-map "}" 'enlarge-window-horizontally)
5823(define-key ctl-x-map "{" 'shrink-window-horizontally)
5824(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
5825(define-key ctl-x-map "+" 'balance-windows)
5826(define-key ctl-x-4-map "0" 'kill-buffer-and-window)
5827
3c448ab6 5828;;; window.el ends here