Fix event race
[bpt/emacs.git] / lisp / window.el
CommitLineData
3c448ab6
MR
1;;; window.el --- GNU Emacs window commands aside from those written in C
2
ba318903
PE
3;; Copyright (C) 1985, 1989, 1992-1994, 2000-2014 Free Software
4;; Foundation, Inc.
3c448ab6 5
34dc21db 6;; Maintainer: emacs-devel@gnu.org
3c448ab6 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
662a9d0e
SM
31(defun internal--before-save-selected-window ()
32 (cons (selected-window)
33 ;; We save and restore all frames' selected windows, because
34 ;; `select-window' can change the frame-selected-window of
35 ;; whatever frame that window is in. Each text terminal's
36 ;; top-frame is preserved by putting it last in the list.
37 (apply #'append
38 (mapcar (lambda (terminal)
39 (let ((frames (frames-on-display-list terminal))
40 (top-frame (tty-top-frame terminal))
41 alist)
42 (if top-frame
43 (setq frames
44 (cons top-frame
45 (delq top-frame frames))))
46 (dolist (f frames)
47 (push (cons f (frame-selected-window f))
48 alist))
49 alist))
50 (terminal-list)))))
51
52(defun internal--after-save-selected-window (state)
53 (dolist (elt (cdr state))
54 (and (frame-live-p (car elt))
55 (window-live-p (cdr elt))
56 (set-frame-selected-window (car elt) (cdr elt) 'norecord)))
57 (when (window-live-p (car state))
58 (select-window (car state) 'norecord)))
59
3c448ab6
MR
60(defmacro save-selected-window (&rest body)
61 "Execute BODY, then select the previously selected window.
62The value returned is the value of the last form in BODY.
63
64This macro saves and restores the selected window, as well as the
65selected window in each frame. If the previously selected window
66is no longer live, then whatever window is selected at the end of
67BODY remains selected. If the previously selected window of some
68frame is no longer live at the end of BODY, that frame's selected
69window is left alone.
70
71This macro saves and restores the current buffer, since otherwise
72its normal operation could make a different buffer current. The
73order of recently selected windows and the buffer list ordering
74are not altered by this macro (unless they are altered in BODY)."
f291fe60 75 (declare (indent 0) (debug t))
662a9d0e 76 `(let ((save-selected-window--state (internal--before-save-selected-window)))
3c448ab6
MR
77 (save-current-buffer
78 (unwind-protect
79 (progn ,@body)
662a9d0e 80 (internal--after-save-selected-window save-selected-window--state)))))
3c448ab6 81
c5e28e39
MR
82(defvar temp-buffer-window-setup-hook nil
83 "Normal hook run by `with-temp-buffer-window' before buffer display.
84This hook is run by `with-temp-buffer-window' with the buffer to be
85displayed current.")
86
87(defvar temp-buffer-window-show-hook nil
88 "Normal hook run by `with-temp-buffer-window' after buffer display.
89This hook is run by `with-temp-buffer-window' with the buffer
90displayed and current and its window selected.")
91
92(defun temp-buffer-window-setup (buffer-or-name)
42019c2e 93 "Set up temporary buffer specified by BUFFER-OR-NAME.
c5e28e39
MR
94Return the buffer."
95 (let ((old-dir default-directory)
96 (buffer (get-buffer-create buffer-or-name)))
97 (with-current-buffer buffer
98 (kill-all-local-variables)
99 (setq default-directory old-dir)
100 (delete-all-overlays)
101 (setq buffer-read-only nil)
102 (setq buffer-file-name nil)
103 (setq buffer-undo-list t)
104 (let ((inhibit-read-only t)
105 (inhibit-modification-hooks t))
106 (erase-buffer)
107 (run-hooks 'temp-buffer-window-setup-hook))
108 ;; Return the buffer.
109 buffer)))
110
111(defun temp-buffer-window-show (&optional buffer action)
112 "Show temporary buffer BUFFER in a window.
113Return the window showing BUFFER. Pass ACTION as action argument
114to `display-buffer'."
115 (let (window frame)
116 (with-current-buffer buffer
117 (set-buffer-modified-p nil)
118 (setq buffer-read-only t)
119 (goto-char (point-min))
8e17c9ba
MR
120 (when (let ((window-combination-limit
121 ;; When `window-combination-limit' equals
122 ;; `temp-buffer' or `temp-buffer-resize' and
123 ;; `temp-buffer-resize-mode' is enabled in this
124 ;; buffer bind it to t so resizing steals space
125 ;; preferably from the window that was split.
126 (if (or (eq window-combination-limit 'temp-buffer)
127 (and (eq window-combination-limit
128 'temp-buffer-resize)
129 temp-buffer-resize-mode))
130 t
131 window-combination-limit)))
132 (setq window (display-buffer buffer action)))
c5e28e39
MR
133 (setq frame (window-frame window))
134 (unless (eq frame (selected-frame))
135 (raise-frame frame))
136 (setq minibuffer-scroll-window window)
137 (set-window-hscroll window 0)
138 (with-selected-window window
139 (run-hooks 'temp-buffer-window-show-hook)
140 (when temp-buffer-resize-mode
141 (resize-temp-buffer-window window)))
142 ;; Return the window.
143 window))))
144
95f0501e 145;; Doc is very similar to with-output-to-temp-buffer.
c5e28e39 146(defmacro with-temp-buffer-window (buffer-or-name action quit-function &rest body)
95f0501e 147 "Bind `standard-output' to BUFFER-OR-NAME, eval BODY, show the buffer.
38785e75
GM
148BUFFER-OR-NAME must specify either a live buffer, or the name of a
149buffer (if it does not exist, this macro creates it).
c5e28e39 150
95f0501e
GM
151This construct makes buffer BUFFER-OR-NAME empty before running BODY.
152It does not make the buffer current for BODY.
153Instead it binds `standard-output' to that buffer, so that output
154generated with `prin1' and similar functions in BODY goes into
155the buffer.
c5e28e39 156
95f0501e
GM
157At the end of BODY, this marks the specified buffer unmodified and
158read-only, and displays it in a window (but does not select it, or make
159the buffer current). The display happens by calling `display-buffer'
160with the ACTION argument. If `temp-buffer-resize-mode' is enabled,
161the relevant window shrinks automatically.
c5e28e39 162
95f0501e
GM
163This returns the value returned by BODY, unless QUIT-FUNCTION specifies
164a function. In that case, it runs the function with two arguments -
c5e28e39 165the window showing the specified buffer and the value returned by
38785e75 166BODY - and returns the value returned by that function.
c5e28e39
MR
167
168If the buffer is displayed on a new frame, the window manager may
169decide to select that frame. In that case, it's usually a good
65463c40
GM
170strategy if QUIT-FUNCTION selects the window showing the buffer
171before reading any value from the minibuffer; for example, when
172asking a `yes-or-no-p' question.
38785e75 173
95f0501e
GM
174This runs the hook `temp-buffer-window-setup-hook' before BODY,
175with the specified buffer temporarily current. It runs the
176hook `temp-buffer-window-show-hook' after displaying the buffer,
177with that buffer temporarily current, and the window that was used to
178display it temporarily selected.
179
180This construct is similar to `with-output-to-temp-buffer', but
181runs different hooks. In particular, it does not run
182`temp-buffer-setup-hook', which usually puts the buffer in Help mode.
183Also, it does not call `temp-buffer-show-function' (the ACTION
184argument replaces this)."
c5e28e39
MR
185 (declare (debug t))
186 (let ((buffer (make-symbol "buffer"))
187 (window (make-symbol "window"))
188 (value (make-symbol "value")))
189 `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name))
190 (standard-output ,buffer)
191 ,window ,value)
2ed94e04 192 (setq ,value (progn ,@body))
c5e28e39 193 (with-current-buffer ,buffer
c5e28e39
MR
194 (setq ,window (temp-buffer-window-show ,buffer ,action)))
195
196 (if (functionp ,quit-function)
197 (funcall ,quit-function ,window ,value)
198 ,value))))
199
d68443dc
MR
200;; The following two functions are like `window-next-sibling' and
201;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so
202;; they don't substitute the selected window for nil), and they return
203;; nil when WINDOW doesn't have a parent (like a frame's root window or
204;; a minibuffer window).
4b0d61e3 205(defun window-right (window)
85cc1f11
MR
206 "Return WINDOW's right sibling.
207Return nil if WINDOW is the root window of its frame. WINDOW can
208be any window."
d68443dc 209 (and window (window-parent window) (window-next-sibling window)))
85cc1f11 210
4b0d61e3 211(defun window-left (window)
85cc1f11
MR
212 "Return WINDOW's left sibling.
213Return nil if WINDOW is the root window of its frame. WINDOW can
214be any window."
d68443dc 215 (and window (window-parent window) (window-prev-sibling window)))
85cc1f11 216
4b0d61e3 217(defun window-child (window)
85c2386b
MR
218 "Return WINDOW's first child window.
219WINDOW can be any window."
d68443dc 220 (or (window-top-child window) (window-left-child window)))
85cc1f11
MR
221
222(defun window-child-count (window)
85c2386b
MR
223 "Return number of WINDOW's child windows.
224WINDOW can be any window."
85cc1f11
MR
225 (let ((count 0))
226 (when (and (windowp window) (setq window (window-child window)))
227 (while window
228 (setq count (1+ count))
d68443dc 229 (setq window (window-next-sibling window))))
85cc1f11
MR
230 count))
231
232(defun window-last-child (window)
85c2386b
MR
233 "Return last child window of WINDOW.
234WINDOW can be any window."
85cc1f11 235 (when (and (windowp window) (setq window (window-child window)))
d68443dc
MR
236 (while (window-next-sibling window)
237 (setq window (window-next-sibling window))))
85cc1f11
MR
238 window)
239
4b0d61e3 240(defun window-normalize-buffer (buffer-or-name)
85cc1f11
MR
241 "Return buffer specified by BUFFER-OR-NAME.
242BUFFER-OR-NAME must be either a buffer or a string naming a live
243buffer and defaults to the current buffer."
244 (cond
245 ((not buffer-or-name)
246 (current-buffer))
247 ((bufferp buffer-or-name)
248 (if (buffer-live-p buffer-or-name)
249 buffer-or-name
250 (error "Buffer %s is not a live buffer" buffer-or-name)))
251 ((get-buffer buffer-or-name))
252 (t
253 (error "No such buffer %s" buffer-or-name))))
254
4b0d61e3 255(defun window-normalize-frame (frame)
85cc1f11
MR
256 "Return frame specified by FRAME.
257FRAME must be a live frame and defaults to the selected frame."
258 (if frame
259 (if (frame-live-p frame)
260 frame
261 (error "%s is not a live frame" frame))
262 (selected-frame)))
263
4b0d61e3 264(defun window-normalize-window (window &optional live-only)
85c2386b
MR
265 "Return the window specified by WINDOW.
266If WINDOW is nil, return the selected window. Otherwise, if
267WINDOW is a live or an internal window, return WINDOW; if
268LIVE-ONLY is non-nil, return WINDOW for a live window only.
447f16b8 269Otherwise, signal an error."
85c2386b
MR
270 (cond
271 ((null window)
272 (selected-window))
273 (live-only
274 (if (window-live-p window)
275 window
276 (error "%s is not a live window" window)))
277 ((window-valid-p window)
278 window)
279 (t
280 (error "%s is not a valid window" window))))
85cc1f11 281
880e6158
MR
282;; Maybe this should go to frame.el.
283(defun frame-char-size (&optional window-or-frame horizontal)
284 "Return the value of `frame-char-height' for WINDOW-OR-FRAME.
285If WINDOW-OR-FRAME is a live frame, return the value of
286`frame-char-height' for that frame. If WINDOW-OR-FRAME is a
287valid window, return the value of `frame-char-height' for that
288window's frame. In any other case, return the value of
289`frame-char-height' for the selected frame.
290
291Optional argument HORIZONTAL non-nil means to return the value of
292`frame-char-width' for WINDOW-OR-FRAME."
293 (let ((frame
294 (cond
295 ((window-valid-p window-or-frame)
296 (window-frame window-or-frame))
297 ((frame-live-p window-or-frame)
298 window-or-frame)
299 (t (selected-frame)))))
300 (if horizontal
301 (frame-char-width frame)
302 (frame-char-height frame))))
303
85cc1f11
MR
304(defvar ignore-window-parameters nil
305 "If non-nil, standard functions ignore window parameters.
306The functions currently affected by this are `split-window',
307`delete-window', `delete-other-windows' and `other-window'.
308
309An application may bind this to a non-nil value around calls to
310these functions to inhibit processing of window parameters.")
311
880e6158 312;; This must go to C, finally (or get removed).
a1511caf 313(defconst window-safe-min-height 1
880e6158 314 "The absolute minimum number of lines of any window.
a1511caf
MR
315Anything less might crash Emacs.")
316
880e6158
MR
317(defun window-safe-min-pixel-height (&optional window)
318 "Return the absolute minimum pixel height of WINDOW."
319 (* window-safe-min-height
320 (frame-char-size (window-normalize-window window))))
321
562dd5e9
MR
322(defcustom window-min-height 4
323 "The minimum number of lines of any window.
9173deec
JB
324The value has to accommodate a mode- or header-line if present.
325A value less than `window-safe-min-height' is ignored. The value
562dd5e9
MR
326of this variable is honored when windows are resized or split.
327
328Applications should never rebind this variable. To resize a
329window to a height less than the one specified here, an
d615d6d2 330application should instead call `window-resize' with a non-nil
562dd5e9 331IGNORE argument. In order to have `split-window' make a window
e4769531 332shorter, explicitly specify the SIZE argument of that function."
562dd5e9
MR
333 :type 'integer
334 :version "24.1"
335 :group 'windows)
336
880e6158
MR
337(defun window-min-pixel-height (&optional window)
338 "Return the minimum pixel height of window WINDOW."
339 (* (max window-min-height window-safe-min-height)
340 (frame-char-size window)))
341
342;; This must go to C, finally (or get removed).
a1511caf 343(defconst window-safe-min-width 2
8da11505 344 "The absolute minimum number of columns of a window.
a1511caf
MR
345Anything less might crash Emacs.")
346
880e6158
MR
347(defun window-safe-min-pixel-width (&optional window)
348 "Return the absolute minimum pixel width of WINDOW."
349 (* window-safe-min-width
350 (frame-char-size (window-normalize-window window) t)))
351
562dd5e9
MR
352(defcustom window-min-width 10
353 "The minimum number of columns of any window.
a91adc7e 354The value has to accommodate margins, fringes, or scrollbars if
562dd5e9
MR
355present. A value less than `window-safe-min-width' is ignored.
356The value of this variable is honored when windows are resized or
357split.
358
359Applications should never rebind this variable. To resize a
360window to a width less than the one specified here, an
d615d6d2 361application should instead call `window-resize' with a non-nil
562dd5e9 362IGNORE argument. In order to have `split-window' make a window
e4769531 363narrower, explicitly specify the SIZE argument of that function."
562dd5e9
MR
364 :type 'integer
365 :version "24.1"
366 :group 'windows)
367
880e6158
MR
368(defun window-min-pixel-width (&optional window)
369 "Return the minimum pixel width of window WINDOW."
370 (* (max window-min-width window-safe-min-width)
371 (frame-char-size window t)))
372
373(defun window-safe-min-pixel-size (&optional window horizontal)
374 "Return the absolute minimum pixel height of WINDOW.
375Optional argument HORIZONTAL non-nil means return the absolute
376minimum pixel width of WINDOW."
377 (if horizontal
378 (window-safe-min-pixel-width window)
379 (window-safe-min-pixel-height window)))
380
4b0d61e3 381(defun window-combined-p (&optional window horizontal)
49745b39 382 "Return non-nil if WINDOW has siblings in a given direction.
85c2386b 383WINDOW must be a valid window and defaults to the selected one.
49745b39 384
880e6158
MR
385HORIZONTAL determines a direction for the window combination. If
386HORIZONTAL is omitted or nil, return non-nil if WINDOW is part of
387a vertical window combination. If HORIZONTAL is non-nil, return
388non-nil if WINDOW is part of a horizontal window combination."
447f16b8 389 (setq window (window-normalize-window window))
85cc1f11 390 (let ((parent (window-parent window)))
49745b39
CY
391 (and parent
392 (if horizontal
393 (window-left-child parent)
394 (window-top-child parent)))))
85cc1f11 395
880e6158
MR
396(defun window-combination-p (&optional window horizontal)
397 "Return WINDOW's first child if WINDOW is a vertical combination.
398WINDOW can be any window and defaults to the selected one.
399Optional argument HORIZONTAL non-nil means return WINDOW's first
400child if WINDOW is a horizontal combination."
401 (setq window (window-normalize-window window))
402 (if horizontal
403 (window-left-child window)
404 (window-top-child window)))
405
be7f5545
MR
406(defun window-combinations (window &optional horizontal)
407 "Return largest number of windows vertically arranged within WINDOW.
85c2386b 408WINDOW must be a valid window and defaults to the selected one.
49745b39 409If HORIZONTAL is non-nil, return the largest number of
be7f5545 410windows horizontally arranged within WINDOW."
447f16b8 411 (setq window (window-normalize-window window))
85cc1f11
MR
412 (cond
413 ((window-live-p window)
414 ;; If WINDOW is live, return 1.
415 1)
49745b39
CY
416 ((if horizontal
417 (window-left-child window)
418 (window-top-child window))
85cc1f11 419 ;; If WINDOW is iso-combined, return the sum of the values for all
be7f5545 420 ;; child windows of WINDOW.
85cc1f11
MR
421 (let ((child (window-child window))
422 (count 0))
423 (while child
424 (setq count
3d8daefe 425 (+ (window-combinations child horizontal)
85cc1f11
MR
426 count))
427 (setq child (window-right child)))
428 count))
429 (t
430 ;; If WINDOW is not iso-combined, return the maximum value of any
be7f5545 431 ;; child window of WINDOW.
85cc1f11
MR
432 (let ((child (window-child window))
433 (count 1))
434 (while child
435 (setq count
3d8daefe 436 (max (window-combinations child horizontal)
85cc1f11
MR
437 count))
438 (setq child (window-right child)))
439 count))))
440
c7635a97 441(defun walk-window-tree-1 (fun walk-window-tree-window any &optional sub-only)
85cc1f11
MR
442 "Helper function for `walk-window-tree' and `walk-window-subtree'."
443 (let (walk-window-tree-buffer)
444 (while walk-window-tree-window
445 (setq walk-window-tree-buffer
446 (window-buffer walk-window-tree-window))
447 (when (or walk-window-tree-buffer any)
c7635a97 448 (funcall fun walk-window-tree-window))
85cc1f11
MR
449 (unless walk-window-tree-buffer
450 (walk-window-tree-1
c7635a97 451 fun (window-left-child walk-window-tree-window) any)
85cc1f11 452 (walk-window-tree-1
c7635a97 453 fun (window-top-child walk-window-tree-window) any))
85cc1f11
MR
454 (if sub-only
455 (setq walk-window-tree-window nil)
456 (setq walk-window-tree-window
457 (window-right walk-window-tree-window))))))
458
ea95074e 459(defun walk-window-tree (fun &optional frame any minibuf)
c7635a97
CY
460 "Run function FUN on each live window of FRAME.
461FUN must be a function with one argument - a window. FRAME must
85cc1f11 462be a live frame and defaults to the selected one. ANY, if
ea95074e 463non-nil, means to run FUN on all live and internal windows of
85cc1f11
MR
464FRAME.
465
ea95074e
MR
466Optional argument MINIBUF t means run FUN on FRAME's minibuffer
467window even if it isn't active. MINIBUF nil or omitted means run
468FUN on FRAME's minibuffer window only if it's active. In both
469cases the minibuffer window must be part of FRAME. MINIBUF
470neither nil nor t means never run FUN on the minibuffer window.
471
85cc1f11 472This function performs a pre-order, depth-first traversal of the
c7635a97 473window tree. If FUN changes the window tree, the result is
85cc1f11 474unpredictable."
ea95074e
MR
475 (setq frame (window-normalize-frame frame))
476 (walk-window-tree-1 fun (frame-root-window frame) any)
477 (when (memq minibuf '(nil t))
478 ;; Run FUN on FRAME's minibuffer window if requested.
479 (let ((minibuffer-window (minibuffer-window frame)))
480 (when (and (window-live-p minibuffer-window)
481 (eq (window-frame minibuffer-window) frame)
482 (or (eq minibuf t)
483 (minibuffer-window-active-p minibuffer-window)))
484 (funcall fun minibuffer-window)))))
85cc1f11 485
c7635a97
CY
486(defun walk-window-subtree (fun &optional window any)
487 "Run function FUN on the subtree of windows rooted at WINDOW.
488WINDOW defaults to the selected window. FUN must be a function
489with one argument - a window. By default, run FUN only on live
be7f5545 490windows of the subtree. If the optional argument ANY is non-nil,
c7635a97
CY
491run FUN on all live and internal windows of the subtree. If
492WINDOW is live, run FUN on WINDOW only.
85cc1f11
MR
493
494This function performs a pre-order, depth-first traversal of the
c7635a97 495subtree rooted at WINDOW. If FUN changes that tree, the result
be7f5545 496is unpredictable."
447f16b8 497 (setq window (window-normalize-window window))
c7635a97 498 (walk-window-tree-1 fun window any t))
85cc1f11 499
ea95074e 500(defun window-with-parameter (parameter &optional value frame any minibuf)
85cc1f11
MR
501 "Return first window on FRAME with PARAMETER non-nil.
502FRAME defaults to the selected frame. Optional argument VALUE
503non-nil means only return a window whose window-parameter value
382c953b 504for PARAMETER equals VALUE (comparison is done with `equal').
85cc1f11 505Optional argument ANY non-nil means consider internal windows
ea95074e
MR
506too.
507
508Optional argument MINIBUF t means consider FRAME's minibuffer
509window even if it isn't active. MINIBUF nil or omitted means
510consider FRAME's minibuffer window only if it's active. In both
511cases the minibuffer window must be part of FRAME. MINIBUF
512neither nil nor t means never consider the minibuffer window."
cb882333 513 (let (this-value)
85cc1f11
MR
514 (catch 'found
515 (walk-window-tree
516 (lambda (window)
517 (when (and (setq this-value (window-parameter window parameter))
518 (or (not value) (equal value this-value)))
519 (throw 'found window)))
ea95074e 520 frame any minibuf))))
85cc1f11
MR
521
522;;; Atomic windows.
523(defun window-atom-root (&optional window)
524 "Return root of atomic window WINDOW is a part of.
85c2386b 525WINDOW must be a valid window and defaults to the selected one.
382c953b 526Return nil if WINDOW is not part of an atomic window."
447f16b8 527 (setq window (window-normalize-window window))
85cc1f11
MR
528 (let (root)
529 (while (and window (window-parameter window 'window-atom))
530 (setq root window)
531 (setq window (window-parent window)))
532 root))
533
5386012d 534(defun window-make-atom (window)
85cc1f11
MR
535 "Make WINDOW an atomic window.
536WINDOW must be an internal window. Return WINDOW."
537 (if (not (window-child window))
538 (error "Window %s is not an internal window" window)
539 (walk-window-subtree
540 (lambda (window)
c660a885
MR
541 (unless (window-parameter window 'window-atom)
542 (set-window-parameter window 'window-atom t)))
85cc1f11
MR
543 window t)
544 window))
545
caceae25
MR
546(defun display-buffer-in-atom-window (buffer alist)
547 "Display BUFFER in an atomic window.
548This function displays BUFFER in a new window that will be
549combined with an existing window to form an atomic window. If
550the existing window is already part of an atomic window, add the
551new window to that atomic window. Operations like `split-window'
552or `delete-window', when applied to a constituent of an atomic
553window, are applied atomically to the root of that atomic window.
554
555ALIST is an association list of symbols and values. The
556following symbols can be used.
557
558`window' specifies the existing window the new window shall be
559 combined with. Use `window-atom-root' to make the new window a
560 sibling of an atomic window's root. If an internal window is
561 specified here, all children of that window become part of the
562 atomic window too. If no window is specified, the new window
c660a885
MR
563 becomes a sibling of the selected window. By default, the
564 `window-atom' parameter of the existing window is set to `main'
565 provided it is live and was not set before.
caceae25
MR
566
567`side' denotes the side of the existing window where the new
568 window shall be located. Valid values are `below', `right',
c660a885
MR
569 `above' and `left'. The default is `below'. By default, the
570 `window-atom' parameter of the new window is set to this value.
caceae25
MR
571
572The return value is the new window, nil when creating that window
573failed."
c660a885
MR
574 (let* ((ignore-window-parameters t)
575 (window-combination-limit t)
576 (window-combination-resize 'atom)
577 (window (cdr (assq 'window alist)))
578 (side (cdr (assq 'side alist)))
579 (atom (when window (window-parameter window 'window-atom)))
580 root new)
caceae25 581 (setq window (window-normalize-window window))
c660a885
MR
582 (setq root (window-atom-root window))
583 ;; Split off new window.
caceae25 584 (when (setq new (split-window window nil side))
c660a885
MR
585 (window-make-atom
586 (if (and root (not (eq root window)))
587 ;; When WINDOW was part of an atomic window and we did not
588 ;; split its root, root atomic window at old root.
589 root
590 ;; Otherwise, root atomic window at WINDOW's new parent.
591 (window-parent window)))
592 ;; Assign `window-atom' parameters, if needed.
593 (when (and (not atom) (window-live-p window))
594 (set-window-parameter window 'window-atom 'main))
595 (set-window-parameter new 'window-atom side)
caceae25
MR
596 ;; Display BUFFER in NEW and return NEW.
597 (window--display-buffer
5938d519 598 buffer new 'window alist display-buffer-mark-dedicated))))
caceae25 599
54f9154c
MR
600(defun window--atom-check-1 (window)
601 "Subroutine of `window--atom-check'."
85cc1f11
MR
602 (when window
603 (if (window-parameter window 'window-atom)
604 (let ((count 0))
605 (when (or (catch 'reset
606 (walk-window-subtree
607 (lambda (window)
608 (if (window-parameter window 'window-atom)
609 (setq count (1+ count))
610 (throw 'reset t)))
611 window t))
612 ;; count >= 1 must hold here. If there's no other
613 ;; window around dissolve this atomic window.
614 (= count 1))
615 ;; Dissolve atomic window.
616 (walk-window-subtree
617 (lambda (window)
618 (set-window-parameter window 'window-atom nil))
619 window t)))
620 ;; Check children.
621 (unless (window-buffer window)
54f9154c
MR
622 (window--atom-check-1 (window-left-child window))
623 (window--atom-check-1 (window-top-child window))))
85cc1f11 624 ;; Check right sibling
54f9154c 625 (window--atom-check-1 (window-right window))))
85cc1f11 626
54f9154c 627(defun window--atom-check (&optional frame)
85cc1f11
MR
628 "Check atomicity of all windows on FRAME.
629FRAME defaults to the selected frame. If an atomic window is
be7f5545
MR
630wrongly configured, reset the atomicity of all its windows on
631FRAME to nil. An atomic window is wrongly configured if it has
632no child windows or one of its child windows is not atomic."
54f9154c 633 (window--atom-check-1 (frame-root-window frame)))
85cc1f11
MR
634
635;; Side windows.
636(defvar window-sides '(left top right bottom)
637 "Window sides.")
638
639(defcustom window-sides-vertical nil
640 "If non-nil, left and right side windows are full height.
641Otherwise, top and bottom side windows are full width."
642 :type 'boolean
643 :group 'windows
644 :version "24.1")
645
646(defcustom window-sides-slots '(nil nil nil nil)
647 "Maximum number of side window slots.
648The value is a list of four elements specifying the number of
382c953b 649side window slots on (in this order) the left, top, right and
85cc1f11
MR
650bottom side of each frame. If an element is a number, this means
651to display at most that many side windows on the corresponding
652side. If an element is nil, this means there's no bound on the
653number of slots on that side."
2bed3f04 654 :version "24.1"
85cc1f11
MR
655 :risky t
656 :type
657 '(list
658 :value (nil nil nil nil)
659 (choice
660 :tag "Left"
661 :help-echo "Maximum slots of left side window."
662 :value nil
663 :format "%[Left%] %v\n"
664 (const :tag "Unlimited" :format "%t" nil)
665 (integer :tag "Number" :value 2 :size 5))
666 (choice
667 :tag "Top"
668 :help-echo "Maximum slots of top side window."
669 :value nil
670 :format "%[Top%] %v\n"
671 (const :tag "Unlimited" :format "%t" nil)
672 (integer :tag "Number" :value 3 :size 5))
673 (choice
674 :tag "Right"
675 :help-echo "Maximum slots of right side window."
676 :value nil
677 :format "%[Right%] %v\n"
678 (const :tag "Unlimited" :format "%t" nil)
679 (integer :tag "Number" :value 2 :size 5))
680 (choice
681 :tag "Bottom"
682 :help-echo "Maximum slots of bottom side window."
683 :value nil
684 :format "%[Bottom%] %v\n"
685 (const :tag "Unlimited" :format "%t" nil)
686 (integer :tag "Number" :value 3 :size 5)))
687 :group 'windows)
688
caceae25
MR
689(defun window--major-non-side-window (&optional frame)
690 "Return the major non-side window of frame FRAME.
691The optional argument FRAME must be a live frame and defaults to
692the selected one.
693
694If FRAME has at least one side window, the major non-side window
695is either an internal non-side window such that all other
696non-side windows on FRAME descend from it, or the single live
697non-side window of FRAME. If FRAME has no side windows, return
698its root window."
699 (let ((frame (window-normalize-frame frame))
700 major sibling)
701 ;; Set major to the _last_ window found by `walk-window-tree' that
702 ;; is not a side window but has a side window as its sibling.
703 (walk-window-tree
704 (lambda (window)
705 (and (not (window-parameter window 'window-side))
706 (or (and (setq sibling (window-prev-sibling window))
707 (window-parameter sibling 'window-side))
708 (and (setq sibling (window-next-sibling window))
709 (window-parameter sibling 'window-side)))
710 (setq major window)))
c660a885 711 frame t 'nomini)
caceae25
MR
712 (or major (frame-root-window frame))))
713
714(defun window--major-side-window (side)
715 "Return major side window on SIDE.
716SIDE must be one of the symbols `left', `top', `right' or
717`bottom'. Return nil if no such window exists."
718 (let ((root (frame-root-window))
719 window)
720 ;; (1) If a window on the opposite side exists, return that window's
721 ;; sibling.
722 ;; (2) If the new window shall span the entire side, return the
723 ;; frame's root window.
724 ;; (3) If a window on an orthogonal side exists, return that
725 ;; window's sibling.
726 ;; (4) Otherwise return the frame's root window.
727 (cond
728 ((or (and (eq side 'left)
729 (setq window (window-with-parameter 'window-side 'right nil t)))
730 (and (eq side 'top)
731 (setq window (window-with-parameter 'window-side 'bottom nil t))))
732 (window-prev-sibling window))
733 ((or (and (eq side 'right)
734 (setq window (window-with-parameter 'window-side 'left nil t)))
735 (and (eq side 'bottom)
736 (setq window (window-with-parameter 'window-side 'top nil t))))
737 (window-next-sibling window))
738 ((memq side '(left right))
739 (cond
740 (window-sides-vertical
741 root)
742 ((setq window (window-with-parameter 'window-side 'top nil t))
743 (window-next-sibling window))
744 ((setq window (window-with-parameter 'window-side 'bottom nil t))
745 (window-prev-sibling window))
746 (t root)))
747 ((memq side '(top bottom))
748 (cond
749 ((not window-sides-vertical)
750 root)
751 ((setq window (window-with-parameter 'window-side 'left nil t))
752 (window-next-sibling window))
753 ((setq window (window-with-parameter 'window-side 'right nil t))
754 (window-prev-sibling window))
755 (t root))))))
756
757(defun display-buffer-in-major-side-window (buffer side slot &optional alist)
758 "Display BUFFER in a new window on SIDE of the selected frame.
759SIDE must be one of `left', `top', `right' or `bottom'. SLOT
760specifies the slot to use. ALIST is an association list of
761symbols and values as passed to `display-buffer-in-side-window'.
762This function may be called only if no window on SIDE exists yet.
763The new window automatically becomes the \"major\" side window on
764SIDE. Return the new window, nil if its creation window failed."
9d3aa82c 765 (let* ((left-or-right (memq side '(left right)))
caceae25 766 (major (window--major-side-window side))
caceae25
MR
767 (on-side (cond
768 ((eq side 'top) 'above)
769 ((eq side 'bottom) 'below)
770 (t side)))
771 ;; The following two bindings will tell `split-window' to take
772 ;; the space for the new window from `major' and not make a new
773 ;; parent window unless needed.
774 (window-combination-resize 'side)
775 (window-combination-limit nil)
9d3aa82c 776 (new (split-window major nil on-side)))
caceae25
MR
777 (when new
778 ;; Initialize `window-side' parameter of new window to SIDE.
779 (set-window-parameter new 'window-side side)
780 ;; Install `window-slot' parameter of new window.
781 (set-window-parameter new 'window-slot slot)
782 ;; Install `delete-window' parameter thus making sure that when
783 ;; the new window is deleted, a side window on the opposite side
784 ;; does not get resized.
785 (set-window-parameter new 'delete-window 'delete-side-window)
5938d519
MR
786 ;; Auto-adjust height/width of new window unless a size has been
787 ;; explicitly requested.
735135f9 788 (unless (if left-or-right
5938d519
MR
789 (cdr (assq 'window-width alist))
790 (cdr (assq 'window-height alist)))
791 (setq alist
792 (cons
793 (cons
794 (if left-or-right 'window-width 'window-height)
795 (/ (window-total-size (frame-root-window) left-or-right)
880e6158
MR
796 ;; By default use a fourth of the size of the frame's
797 ;; root window.
5938d519
MR
798 4))
799 alist)))
caceae25 800 ;; Install BUFFER in new window and return NEW.
5938d519 801 (window--display-buffer buffer new 'window alist 'side))))
caceae25
MR
802
803(defun delete-side-window (window)
804 "Delete side window WINDOW."
805 (let ((window-combination-resize
806 (window-parameter (window-parent window) 'window-side))
807 (ignore-window-parameters t))
808 (delete-window window)))
809
810(defun display-buffer-in-side-window (buffer alist)
3c29190f 811 "Display BUFFER in a side window of the selected frame.
caceae25 812ALIST is an association list of symbols and values. The
3c29190f 813following special symbols can be used in ALIST.
caceae25 814
3c29190f
MR
815`side' denotes the side of the frame where the new window shall
816 be located. Valid values are `bottom', `right', `top' and
817 `left'. The default is `bottom'.
caceae25
MR
818
819`slot' if non-nil, specifies the window slot where to display
820 BUFFER. A value of zero or nil means use the middle slot on
821 the specified side. A negative value means use a slot
822 preceding (that is, above or on the left of) the middle slot.
823 A positive value means use a slot following (that is, below or
824 on the right of) the middle slot. The default is zero."
825 (let ((side (or (cdr (assq 'side alist)) 'bottom))
9d3aa82c 826 (slot (or (cdr (assq 'slot alist)) 0)))
caceae25
MR
827 (cond
828 ((not (memq side '(top bottom left right)))
829 (error "Invalid side %s specified" side))
830 ((not (numberp slot))
831 (error "Invalid slot %s specified" slot)))
832
833 (let* ((major (window-with-parameter 'window-side side nil t))
834 ;; `major' is the major window on SIDE, `windows' the list of
835 ;; life windows on SIDE.
836 (windows
837 (when major
838 (let (windows)
839 (walk-window-tree
840 (lambda (window)
841 (when (eq (window-parameter window 'window-side) side)
c660a885
MR
842 (setq windows (cons window windows))))
843 nil nil 'nomini)
caceae25
MR
844 (nreverse windows))))
845 (slots (when major (max 1 (window-child-count major))))
846 (max-slots
847 (nth (cond
848 ((eq side 'left) 0)
849 ((eq side 'top) 1)
850 ((eq side 'right) 2)
851 ((eq side 'bottom) 3))
852 window-sides-slots))
caceae25 853 window this-window this-slot prev-window next-window
9d3aa82c 854 best-window best-slot abs-slot)
caceae25
MR
855
856 (cond
857 ((and (numberp max-slots) (<= max-slots 0))
858 ;; No side-slots available on this side. Don't create an error,
859 ;; just return nil.
860 nil)
861 ((not windows)
862 ;; No major window exists on this side, make one.
863 (display-buffer-in-major-side-window buffer side slot alist))
864 (t
865 ;; Scan windows on SIDE.
866 (catch 'found
867 (dolist (window windows)
868 (setq this-slot (window-parameter window 'window-slot))
869 (cond
870 ;; The following should not happen and probably be checked
871 ;; by window--side-check.
872 ((not (numberp this-slot)))
873 ((= this-slot slot)
874 ;; A window with a matching slot has been found.
875 (setq this-window window)
876 (throw 'found t))
877 (t
878 ;; Check if this window has a better slot value wrt the
879 ;; slot of the window we want.
880 (setq abs-slot
881 (if (or (and (> this-slot 0) (> slot 0))
882 (and (< this-slot 0) (< slot 0)))
883 (abs (- slot this-slot))
884 (+ (abs slot) (abs this-slot))))
885 (unless (and best-slot (<= best-slot abs-slot))
886 (setq best-window window)
887 (setq best-slot abs-slot))
888 (cond
889 ((<= this-slot slot)
890 (setq prev-window window))
891 ((not next-window)
892 (setq next-window window)))))))
893
894 ;; `this-window' is the first window with the same SLOT.
895 ;; `prev-window' is the window with the largest slot < SLOT. A new
896 ;; window will be created after it.
897 ;; `next-window' is the window with the smallest slot > SLOT. A new
898 ;; window will be created before it.
899 ;; `best-window' is the window with the smallest absolute difference
900 ;; of its slot and SLOT.
901
902 ;; Note: We dedicate the window used softly to its buffer to
903 ;; avoid that "other" (non-side) buffer display functions steal
904 ;; it from us. This must eventually become customizable via
905 ;; ALIST (or, better, avoided in the "other" functions).
906 (or (and this-window
907 ;; Reuse `this-window'.
5938d519 908 (window--display-buffer buffer this-window 'reuse alist 'side))
caceae25
MR
909 (and (or (not max-slots) (< slots max-slots))
910 (or (and next-window
911 ;; Make new window before `next-window'.
912 (let ((next-side
913 (if (memq side '(left right)) 'above 'left))
914 (window-combination-resize 'side))
915 (setq window (split-window next-window nil next-side))
916 ;; When the new window is deleted, its space
917 ;; is returned to other side windows.
918 (set-window-parameter
919 window 'delete-window 'delete-side-window)
920 window))
921 (and prev-window
922 ;; Make new window after `prev-window'.
923 (let ((prev-side
924 (if (memq side '(left right)) 'below 'right))
925 (window-combination-resize 'side))
926 (setq window (split-window prev-window nil prev-side))
927 ;; When the new window is deleted, its space
928 ;; is returned to other side windows.
929 (set-window-parameter
930 window 'delete-window 'delete-side-window)
931 window)))
932 (set-window-parameter window 'window-slot slot)
5938d519 933 (window--display-buffer buffer window 'window alist 'side))
caceae25
MR
934 (and best-window
935 ;; Reuse `best-window'.
936 (progn
937 ;; Give best-window the new slot value.
938 (set-window-parameter best-window 'window-slot slot)
5938d519
MR
939 (window--display-buffer
940 buffer best-window 'reuse alist 'side)))))))))
caceae25 941
54f9154c 942(defun window--side-check (&optional frame)
caceae25
MR
943 "Check the side window configuration of FRAME.
944FRAME defaults to the selected frame.
945
946A valid side window configuration preserves the following two
947invariants:
948
949- If there exists a window whose window-side parameter is
950 non-nil, there must exist at least one live window whose
951 window-side parameter is nil.
952
953- If a window W has a non-nil window-side parameter (i) it must
954 have a parent window and that parent's window-side parameter
955 must be either nil or the same as for W, and (ii) any child
956 window of W must have the same window-side parameter as W.
957
958If the configuration is invalid, reset the window-side parameters
959of all windows on FRAME to nil."
960 (let (left top right bottom none side parent parent-side)
85cc1f11
MR
961 (when (or (catch 'reset
962 (walk-window-tree
963 (lambda (window)
964 (setq side (window-parameter window 'window-side))
965 (setq parent (window-parent window))
966 (setq parent-side
967 (and parent (window-parameter parent 'window-side)))
968 ;; The following `cond' seems a bit tedious, but I'd
969 ;; rather stick to using just the stack.
970 (cond
971 (parent-side
972 (when (not (eq parent-side side))
973 ;; A parent whose window-side is non-nil must
974 ;; have a child with the same window-side.
975 (throw 'reset t)))
caceae25
MR
976 ((not side)
977 (when (window-buffer window)
978 ;; Record that we have at least one non-side,
979 ;; live window.
85cc1f11 980 (setq none t)))
caceae25
MR
981 ((if (memq side '(left top))
982 (window-prev-sibling window)
983 (window-next-sibling window))
984 ;; Left and top major side windows must not have a
985 ;; previous sibling, right and bottom major side
986 ;; windows must not have a next sibling.
987 (throw 'reset t))
988 ;; Now check that there's no more than one major
989 ;; window for any of left, top, right and bottom.
85cc1f11 990 ((eq side 'left)
caceae25 991 (if left (throw 'reset t) (setq left t)))
85cc1f11 992 ((eq side 'top)
caceae25 993 (if top (throw 'reset t) (setq top t)))
85cc1f11 994 ((eq side 'right)
caceae25 995 (if right (throw 'reset t) (setq right t)))
85cc1f11 996 ((eq side 'bottom)
caceae25 997 (if bottom (throw 'reset t) (setq bottom t)))
42019c2e 998 (t
caceae25 999 (throw 'reset t))))
c660a885 1000 frame t 'nomini))
caceae25
MR
1001 ;; If there's a side window, there must be at least one
1002 ;; non-side window.
1003 (and (or left top right bottom) (not none)))
85cc1f11
MR
1004 (walk-window-tree
1005 (lambda (window)
1006 (set-window-parameter window 'window-side nil))
c660a885 1007 frame t 'nomini))))
85cc1f11 1008
54f9154c 1009(defun window--check (&optional frame)
85cc1f11
MR
1010 "Check atomic and side windows on FRAME.
1011FRAME defaults to the selected frame."
54f9154c
MR
1012 (window--side-check frame)
1013 (window--atom-check frame))
85cc1f11 1014
8dd3e94f
MR
1015;; Dumping frame/window contents.
1016(defun window--dump-window (&optional window erase)
1017 "Dump WINDOW to buffer *window-frame-dump*.
1018WINDOW must be a valid window and defaults to the selected one.
1019Optional argument ERASE non-nil means erase *window-frame-dump*
1020before writing to it."
1021 (setq window (window-normalize-window window))
1022 (with-current-buffer (get-buffer-create "*window-frame-dump*")
1023 (when erase (erase-buffer))
1024 (insert
1025 (format "%s parent: %s\n" window (window-parent window))
1026 (format "pixel left: %s top: %s size: %s x %s new: %s\n"
1027 (window-pixel-left window) (window-pixel-top window)
1028 (window-size window t t) (window-size window nil t)
1029 (window-new-pixel window))
1030 (format "char left: %s top: %s size: %s x %s new: %s\n"
1031 (window-left-column window) (window-top-line window)
1032 (window-total-size window t) (window-total-size window)
1033 (window-new-total window))
1034 (format "normal: %s x %s new: %s\n"
1035 (window-normal-size window t) (window-normal-size window)
1036 (window-new-normal window)))
1037 (when (window-live-p window)
1038 (let ((fringes (window-fringes window))
1039 (margins (window-margins window)))
1040 (insert
1041 (format "body pixel: %s x %s char: %s x %s\n"
1042 (window-body-width window t) (window-body-height window t)
1043 (window-body-width window) (window-body-height window))
1044 (format "width left fringe: %s left margin: %s right margin: %s\n"
1045 (car fringes) (or (car margins) 0) (or (cdr margins) 0))
1046 (format "width right fringe: %s scroll-bar: %s divider: %s\n"
1047 (cadr fringes)
1048 (window-scroll-bar-width window)
1049 (window-right-divider-width window))
1050 (format "height header-line: %s mode-line: %s divider: %s\n"
1051 (window-header-line-height window)
1052 (window-mode-line-height window)
1053 (window-bottom-divider-width window)))))
1054 (insert "\n")))
1055
1056(defun window--dump-frame (&optional window-or-frame)
1057 "Dump WINDOW-OR-FRAME to buffer *window-frame-dump*.
1058WINDOW-OR-FRAME can be a frame or a window and defaults to the
1059selected frame. When WINDOW-OR-FRAME is a window, dump that
1060window's frame. The buffer *window-frame-dump* is erased before
1061dumping to it."
1062 (interactive)
1063 (let* ((window
1064 (cond
1065 ((or (not window-or-frame)
1066 (frame-live-p window-or-frame))
1067 (frame-root-window window-or-frame))
1068 ((or (window-live-p window-or-frame)
1069 (window-child window-or-frame))
1070 window-or-frame)
1071 (t
1072 (frame-root-window))))
1073 (frame (window-frame window)))
1074 (with-current-buffer (get-buffer-create "*window-frame-dump*")
1075 (erase-buffer)
1076 (insert
1077 (format "frame pixel: %s x %s cols/lines: %s x %s units: %s x %s\n"
1078 (frame-pixel-width frame) (frame-pixel-height frame)
1079 (frame-total-cols frame) (frame-text-lines frame) ; (frame-total-lines frame)
1080 (frame-char-width frame) (frame-char-height frame))
1081 (format "frame text pixel: %s x %s cols/lines: %s x %s\n"
1082 (frame-text-width frame) (frame-text-height frame)
1083 (frame-text-cols frame) (frame-text-lines frame))
1084 (format "tool: %s scroll: %s fringe: %s border: %s right: %s bottom: %s\n\n"
1085 (tool-bar-height frame t)
1086 (frame-scroll-bar-width frame)
1087 (frame-fringe-width frame)
1088 (frame-border-width frame)
1089 (frame-right-divider-width frame)
1090 (frame-bottom-divider-width frame)))
1091 (walk-window-tree 'window--dump-window frame t t))))
1092
85cc1f11 1093;;; Window sizes.
6cb4da45 1094(defun window-total-size (&optional window horizontal round)
880e6158
MR
1095 "Return the total height or width of WINDOW.
1096WINDOW must be a valid window and defaults to the selected one.
1097
1098If HORIZONTAL is omitted or nil, return the total height of
1099WINDOW, in lines, like `window-total-height'. Otherwise return
6cb4da45
MR
1100the total width, in columns, like `window-total-width'.
1101
1102Optional argument ROUND is handled as for `window-total-height'
1103and `window-total-width'."
880e6158 1104 (if horizontal
6cb4da45
MR
1105 (window-total-width window round)
1106 (window-total-height window round)))
880e6158 1107
6cb4da45 1108(defun window-size (&optional window horizontal pixelwise round)
880e6158
MR
1109 "Return the height or width of WINDOW.
1110WINDOW must be a valid window and defaults to the selected one.
1111
1112If HORIZONTAL is omitted or nil, return the total height of
1113WINDOW, in lines, like `window-total-height'. Otherwise return
1114the total width, in columns, like `window-total-width'.
1115
1116Optional argument PIXELWISE means return the pixel size of WINDOW
6cb4da45
MR
1117like `window-pixel-height' and `window-pixel-width'.
1118
1119Optional argument ROUND is ignored if PIXELWISE is non-nil and
1120handled as for `window-total-height' and `window-total-width'
1121otherwise."
880e6158
MR
1122 (if horizontal
1123 (if pixelwise
1124 (window-pixel-width window)
6cb4da45 1125 (window-total-width window round))
880e6158
MR
1126 (if pixelwise
1127 (window-pixel-height window)
6cb4da45 1128 (window-total-height window round))))
880e6158 1129
85cc1f11
MR
1130(defvar window-size-fixed nil
1131 "Non-nil in a buffer means windows displaying the buffer are fixed-size.
1132If the value is `height', then only the window's height is fixed.
1133If the value is `width', then only the window's width is fixed.
1134Any other non-nil value fixes both the width and the height.
1135
1136Emacs won't change the size of any window displaying that buffer,
382c953b 1137unless it has no other choice (like when deleting a neighboring
85cc1f11
MR
1138window).")
1139(make-variable-buffer-local 'window-size-fixed)
1140
842e3a93 1141(defun window--size-ignore-p (window ignore)
a1511caf 1142 "Return non-nil if IGNORE says to ignore size restrictions for WINDOW."
24300f5f 1143 (if (window-valid-p ignore) (eq window ignore) ignore))
a1511caf 1144
880e6158
MR
1145(defun window-safe-min-size (&optional window horizontal pixelwise)
1146 "Return safe minimum size of WINDOW.
1147WINDOW must be a valid window and defaults to the selected one.
1148Optional argument HORIZONTAL non-nil means return the minimum
1149number of columns of WINDOW; otherwise return the minimum number
1150of WINDOW's lines.
1151
1152Optional argument PIXELWISE non-nil means return the minimum pixel-size
1153of WINDOW."
1154 (setq window (window-normalize-window window))
1155 (if pixelwise
1156 (if horizontal
1157 (* window-safe-min-width
1158 (frame-char-width (window-frame window)))
1159 (* window-safe-min-height
1160 (frame-char-height (window-frame window))))
1161 (if horizontal window-safe-min-width window-safe-min-height)))
1162
1163(defun window-min-size (&optional window horizontal ignore pixelwise)
2116e93c 1164 "Return the minimum size of WINDOW.
85c2386b
MR
1165WINDOW must be a valid window and defaults to the selected one.
1166Optional argument HORIZONTAL non-nil means return the minimum
1167number of columns of WINDOW; otherwise return the minimum number
1168of WINDOW's lines.
a1511caf 1169
2116e93c 1170Optional argument IGNORE, if non-nil, means ignore restrictions
a1511caf 1171imposed by fixed size windows, `window-min-height' or
2116e93c 1172`window-min-width' settings. If IGNORE equals `safe', live
a1511caf 1173windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
1174`window-safe-min-width' columns. If IGNORE is a window, ignore
1175restrictions for that window only. Any other non-nil value
880e6158
MR
1176means ignore all of the above restrictions for all windows.
1177
1178Optional argument PIXELWISE non-nil means return the minimum pixel-size
1179of WINDOW."
c56cad4a 1180 (window--min-size-1
880e6158 1181 (window-normalize-window window) horizontal ignore pixelwise))
a1511caf 1182
880e6158 1183(defun window--min-size-1 (window horizontal ignore pixelwise)
a1511caf
MR
1184 "Internal function of `window-min-size'."
1185 (let ((sub (window-child window)))
1186 (if sub
1187 (let ((value 0))
1188 ;; WINDOW is an internal window.
3d8daefe 1189 (if (window-combined-p sub horizontal)
a1511caf 1190 ;; The minimum size of an iso-combination is the sum of
be7f5545 1191 ;; the minimum sizes of its child windows.
a1511caf
MR
1192 (while sub
1193 (setq value (+ value
880e6158
MR
1194 (window--min-size-1
1195 sub horizontal ignore pixelwise)))
a1511caf 1196 (setq sub (window-right sub)))
c660a885
MR
1197 ;; The minimum size of an ortho-combination is the maximum
1198 ;; of the minimum sizes of its child windows.
a1511caf
MR
1199 (while sub
1200 (setq value (max value
880e6158
MR
1201 (window--min-size-1
1202 sub horizontal ignore pixelwise)))
a1511caf
MR
1203 (setq sub (window-right sub))))
1204 value)
1205 (with-current-buffer (window-buffer window)
1206 (cond
842e3a93 1207 ((and (not (window--size-ignore-p window ignore))
a1511caf
MR
1208 (window-size-fixed-p window horizontal))
1209 ;; The minimum size of a fixed size window is its size.
880e6158 1210 (window-size window horizontal pixelwise))
a1511caf
MR
1211 ((or (eq ignore 'safe) (eq ignore window))
1212 ;; If IGNORE equals `safe' or WINDOW return the safe values.
880e6158 1213 (window-safe-min-size window horizontal pixelwise))
a1511caf
MR
1214 (horizontal
1215 ;; For the minimum width of a window take fringes and
1216 ;; scroll-bars into account. This is questionable and should
1217 ;; be removed as soon as we are able to split (and resize)
1218 ;; windows such that the new (or resized) windows can get a
1219 ;; size less than the user-specified `window-min-height' and
1220 ;; `window-min-width'.
8dd3e94f
MR
1221 (let* ((char-size (frame-char-size window t))
1222 (fringes (window-fringes window))
1223 (pixel-width
1224 (+ (window-safe-min-size window t t)
1225 (car fringes) (cadr fringes)
1226 (window-scroll-bar-width window)
1227 (window-right-divider-width window))))
880e6158
MR
1228 (if pixelwise
1229 (max
8dd3e94f
MR
1230 (if window-resize-pixelwise
1231 pixel-width
1232 ;; Round up to next integral of columns.
1233 (* (ceiling pixel-width char-size) char-size))
880e6158
MR
1234 (if (window--size-ignore-p window ignore)
1235 0
1236 (window-min-pixel-width)))
1237 (max
8dd3e94f 1238 (ceiling pixel-width char-size)
880e6158
MR
1239 (if (window--size-ignore-p window ignore)
1240 0
1241 window-min-width)))))
8dd3e94f
MR
1242 ((let ((char-size (frame-char-size window))
1243 (pixel-height
1244 (+ (window-safe-min-size window nil t)
1245 (window-header-line-height window)
1246 (window-mode-line-height window)
1247 (window-bottom-divider-width window))))
1248 (if pixelwise
1249 (max
1250 (if window-resize-pixelwise
1251 pixel-height
1252 ;; Round up to next integral of lines.
1253 (* (ceiling pixel-height char-size) char-size))
1254 (if (window--size-ignore-p window ignore)
1255 0
1256 (window-min-pixel-height)))
1257 (max (ceiling pixel-height char-size)
1258 (if (window--size-ignore-p window ignore)
1259 0
1260 window-min-height))))))))))
a1511caf 1261
880e6158 1262(defun window-sizable (window delta &optional horizontal ignore pixelwise)
a1511caf 1263 "Return DELTA if DELTA lines can be added to WINDOW.
85c2386b 1264WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
1265Optional argument HORIZONTAL non-nil means return DELTA if DELTA
1266columns can be added to WINDOW. A return value of zero means
1267that no lines (or columns) can be added to WINDOW.
1268
be7f5545
MR
1269This function looks only at WINDOW and, recursively, its child
1270windows. The function `window-resizable' looks at other windows
1271as well.
a1511caf
MR
1272
1273DELTA positive means WINDOW shall be enlarged by DELTA lines or
1274columns. If WINDOW cannot be enlarged by DELTA lines or columns
1275return the maximum value in the range 0..DELTA by which WINDOW
1276can be enlarged.
1277
1278DELTA negative means WINDOW shall be shrunk by -DELTA lines or
1279columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
1280return the minimum value in the range DELTA..0 by which WINDOW
1281can be shrunk.
1282
2116e93c 1283Optional argument IGNORE non-nil means ignore restrictions
a1511caf 1284imposed by fixed size windows, `window-min-height' or
2116e93c 1285`window-min-width' settings. If IGNORE equals `safe', live
a1511caf 1286windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
1287`window-safe-min-width' columns. If IGNORE is a window, ignore
1288restrictions for that window only. Any other non-nil value means
880e6158
MR
1289ignore all of the above restrictions for all windows.
1290
1291Optional argument PIXELWISE non-nil means interpret DELTA as
1292pixels."
447f16b8 1293 (setq window (window-normalize-window window))
a1511caf
MR
1294 (cond
1295 ((< delta 0)
880e6158
MR
1296 (max (- (window-min-size window horizontal ignore pixelwise)
1297 (window-size window horizontal pixelwise))
a1511caf 1298 delta))
842e3a93 1299 ((window--size-ignore-p window ignore)
a1511caf
MR
1300 delta)
1301 ((> delta 0)
1302 (if (window-size-fixed-p window horizontal)
1303 0
1304 delta))
1305 (t 0)))
1306
880e6158 1307(defun window-sizable-p (window delta &optional horizontal ignore pixelwise)
a1511caf 1308 "Return t if WINDOW can be resized by DELTA lines.
85c2386b 1309WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
1310For the meaning of the arguments of this function see the
1311doc-string of `window-sizable'."
447f16b8 1312 (setq window (window-normalize-window window))
a1511caf 1313 (if (> delta 0)
880e6158
MR
1314 (>= (window-sizable window delta horizontal ignore pixelwise)
1315 delta)
1316 (<= (window-sizable window delta horizontal ignore pixelwise)
1317 delta)))
a1511caf 1318
5e92ca23 1319(defun window--size-fixed-1 (window horizontal)
a1511caf
MR
1320 "Internal function for `window-size-fixed-p'."
1321 (let ((sub (window-child window)))
1322 (catch 'fixed
1323 (if sub
1324 ;; WINDOW is an internal window.
3d8daefe 1325 (if (window-combined-p sub horizontal)
be7f5545
MR
1326 ;; An iso-combination is fixed size if all its child
1327 ;; windows are fixed-size.
a1511caf
MR
1328 (progn
1329 (while sub
5e92ca23 1330 (unless (window--size-fixed-1 sub horizontal)
be7f5545
MR
1331 ;; We found a non-fixed-size child window, so
1332 ;; WINDOW's size is not fixed.
a1511caf
MR
1333 (throw 'fixed nil))
1334 (setq sub (window-right sub)))
be7f5545 1335 ;; All child windows are fixed-size, so WINDOW's size is
a1511caf
MR
1336 ;; fixed.
1337 (throw 'fixed t))
1338 ;; An ortho-combination is fixed-size if at least one of its
be7f5545 1339 ;; child windows is fixed-size.
a1511caf 1340 (while sub
5e92ca23 1341 (when (window--size-fixed-1 sub horizontal)
be7f5545
MR
1342 ;; We found a fixed-size child window, so WINDOW's size
1343 ;; is fixed.
a1511caf
MR
1344 (throw 'fixed t))
1345 (setq sub (window-right sub))))
1346 ;; WINDOW is a live window.
1347 (with-current-buffer (window-buffer window)
1348 (if horizontal
1349 (memq window-size-fixed '(width t))
1350 (memq window-size-fixed '(height t))))))))
1351
1352(defun window-size-fixed-p (&optional window horizontal)
1353 "Return non-nil if WINDOW's height is fixed.
85c2386b
MR
1354WINDOW must be a valid window and defaults to the selected one.
1355Optional argument HORIZONTAL non-nil means return non-nil if
1356WINDOW's width is fixed.
a1511caf
MR
1357
1358If this function returns nil, this does not necessarily mean that
2cffd681
MR
1359WINDOW can be resized in the desired direction. The function
1360`window-resizable' can tell that."
5e92ca23 1361 (window--size-fixed-1
447f16b8 1362 (window-normalize-window window) horizontal))
a1511caf 1363
880e6158 1364(defun window--min-delta-1 (window delta &optional horizontal ignore trail noup pixelwise)
a1511caf
MR
1365 "Internal function for `window-min-delta'."
1366 (if (not (window-parent window))
1367 ;; If we can't go up, return zero.
1368 0
1369 ;; Else try to find a non-fixed-size sibling of WINDOW.
1370 (let* ((parent (window-parent window))
1371 (sub (window-child parent)))
1372 (catch 'done
3d8daefe 1373 (if (window-combined-p sub horizontal)
a1511caf 1374 ;; In an iso-combination throw DELTA if we find at least one
be7f5545
MR
1375 ;; child window and that window is either not fixed-size or
1376 ;; we can ignore fixed-sizeness.
a1511caf
MR
1377 (let ((skip (eq trail 'after)))
1378 (while sub
1379 (cond
1380 ((eq sub window)
1381 (setq skip (eq trail 'before)))
1382 (skip)
842e3a93 1383 ((and (not (window--size-ignore-p window ignore))
a1511caf
MR
1384 (window-size-fixed-p sub horizontal)))
1385 (t
be7f5545 1386 ;; We found a non-fixed-size child window.
a1511caf
MR
1387 (throw 'done delta)))
1388 (setq sub (window-right sub))))
1389 ;; In an ortho-combination set DELTA to the minimum value by
be7f5545 1390 ;; which other child windows can shrink.
a1511caf
MR
1391 (while sub
1392 (unless (eq sub window)
1393 (setq delta
1394 (min delta
8dd3e94f
MR
1395 (max (- (window-size sub horizontal pixelwise 'ceiling)
1396 (window-min-size
1397 sub horizontal ignore pixelwise))
1398 0))))
a1511caf
MR
1399 (setq sub (window-right sub))))
1400 (if noup
1401 delta
880e6158
MR
1402 (window--min-delta-1
1403 parent delta horizontal ignore trail nil pixelwise))))))
a1511caf 1404
880e6158 1405(defun window-min-delta (&optional window horizontal ignore trail noup nodown pixelwise)
a1511caf 1406 "Return number of lines by which WINDOW can be shrunk.
85c2386b
MR
1407WINDOW must be a valid window and defaults to the selected one.
1408Return zero if WINDOW cannot be shrunk.
a1511caf
MR
1409
1410Optional argument HORIZONTAL non-nil means return number of
1411columns by which WINDOW can be shrunk.
1412
2116e93c 1413Optional argument IGNORE non-nil means ignore restrictions
a1511caf 1414imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
1415`window-min-width' settings. If IGNORE is a window, ignore
1416restrictions for that window only. If IGNORE equals `safe',
a1511caf 1417live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
1418and `window-safe-min-width' columns. Any other non-nil value
1419means ignore all of the above restrictions for all windows.
a1511caf 1420
2116e93c
EZ
1421Optional argument TRAIL restricts the windows that can be enlarged.
1422If its value is `before', only windows to the left of or above WINDOW
1423can be enlarged. If it is `after', only windows to the right of or
1424below WINDOW can be enlarged.
a1511caf
MR
1425
1426Optional argument NOUP non-nil means don't go up in the window
2116e93c 1427tree, but try to enlarge windows within WINDOW's combination only.
a1511caf
MR
1428
1429Optional argument NODOWN non-nil means don't check whether WINDOW
382c953b 1430itself (and its child windows) can be shrunk; check only whether
880e6158
MR
1431at least one other window can be enlarged appropriately.
1432
1433Optional argument PIXELWISE non-nil means return number of pixels
1434by which WINDOW can be shrunk."
447f16b8 1435 (setq window (window-normalize-window window))
6cb4da45 1436 (let ((size (window-size window horizontal pixelwise 'floor))
880e6158 1437 (minimum (window-min-size window horizontal ignore pixelwise)))
a1511caf
MR
1438 (cond
1439 (nodown
1440 ;; If NODOWN is t, try to recover the entire size of WINDOW.
880e6158
MR
1441 (window--min-delta-1
1442 window size horizontal ignore trail noup pixelwise))
1443 ((<= size minimum)
a1511caf
MR
1444 ;; If NODOWN is nil and WINDOW's size is already at its minimum,
1445 ;; there's nothing to recover.
1446 0)
1447 (t
1448 ;; Otherwise, try to recover whatever WINDOW is larger than its
1449 ;; minimum size.
c56cad4a 1450 (window--min-delta-1
880e6158 1451 window (- size minimum) horizontal ignore trail noup pixelwise)))))
a1511caf 1452
880e6158 1453(defun window--max-delta-1 (window delta &optional horizontal ignore trail noup pixelwise)
a1511caf
MR
1454 "Internal function of `window-max-delta'."
1455 (if (not (window-parent window))
1456 ;; Can't go up. Return DELTA.
1457 delta
1458 (let* ((parent (window-parent window))
1459 (sub (window-child parent)))
1460 (catch 'fixed
3d8daefe 1461 (if (window-combined-p sub horizontal)
a1511caf 1462 ;; For an iso-combination calculate how much we can get from
be7f5545 1463 ;; other child windows.
a1511caf
MR
1464 (let ((skip (eq trail 'after)))
1465 (while sub
1466 (cond
1467 ((eq sub window)
1468 (setq skip (eq trail 'before)))
1469 (skip)
1470 (t
1471 (setq delta
1472 (+ delta
8dd3e94f
MR
1473 (max
1474 (- (window-size sub horizontal pixelwise 'ceiling)
1475 (window-min-size
1476 sub horizontal ignore pixelwise))
1477 0)))))
a1511caf
MR
1478 (setq sub (window-right sub))))
1479 ;; For an ortho-combination throw DELTA when at least one
be7f5545 1480 ;; child window is fixed-size.
a1511caf
MR
1481 (while sub
1482 (when (and (not (eq sub window))
842e3a93 1483 (not (window--size-ignore-p sub ignore))
a1511caf
MR
1484 (window-size-fixed-p sub horizontal))
1485 (throw 'fixed delta))
1486 (setq sub (window-right sub))))
1487 (if noup
1488 ;; When NOUP is nil, DELTA is all we can get.
1489 delta
1490 ;; Else try with parent of WINDOW, passing the DELTA we
1491 ;; recovered so far.
880e6158
MR
1492 (window--max-delta-1
1493 parent delta horizontal ignore trail nil pixelwise))))))
a1511caf 1494
880e6158 1495(defun window-max-delta (&optional window horizontal ignore trail noup nodown pixelwise)
2116e93c 1496 "Return maximum number of lines by which WINDOW can be enlarged.
85c2386b
MR
1497WINDOW must be a valid window and defaults to the selected one.
1498The return value is zero if WINDOW cannot be enlarged.
a1511caf
MR
1499
1500Optional argument HORIZONTAL non-nil means return maximum number
1501of columns by which WINDOW can be enlarged.
1502
2116e93c 1503Optional argument IGNORE non-nil means ignore restrictions
a1511caf 1504imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
1505`window-min-width' settings. If IGNORE is a window, ignore
1506restrictions for that window only. If IGNORE equals `safe',
a1511caf 1507live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
1508and `window-safe-min-width' columns. Any other non-nil value means
1509ignore all of the above restrictions for all windows.
a1511caf 1510
2116e93c
EZ
1511Optional argument TRAIL restricts the windows that can be enlarged.
1512If its value is `before', only windows to the left of or above WINDOW
1513can be enlarged. If it is `after', only windows to the right of or
1514below WINDOW can be enlarged.
a1511caf
MR
1515
1516Optional argument NOUP non-nil means don't go up in the window
1517tree but try to obtain the entire space from windows within
1518WINDOW's combination.
1519
1520Optional argument NODOWN non-nil means do not check whether
382c953b 1521WINDOW itself (and its child windows) can be enlarged; check
880e6158
MR
1522only whether other windows can be shrunk appropriately.
1523
1524Optional argument PIXELWISE non-nil means return number of
1525pixels by which WINDOW can be enlarged."
447f16b8 1526 (setq window (window-normalize-window window))
842e3a93 1527 (if (and (not (window--size-ignore-p window ignore))
a1511caf
MR
1528 (not nodown) (window-size-fixed-p window horizontal))
1529 ;; With IGNORE and NOWDON nil return zero if WINDOW has fixed
1530 ;; size.
1531 0
1532 ;; WINDOW has no fixed size.
880e6158 1533 (window--max-delta-1 window 0 horizontal ignore trail noup pixelwise)))
a1511caf
MR
1534
1535;; Make NOUP also inhibit the min-size check.
880e6158 1536(defun window--resizable (window delta &optional horizontal ignore trail noup nodown pixelwise)
a1511caf 1537 "Return DELTA if WINDOW can be resized vertically by DELTA lines.
85c2386b 1538WINDOW must be a valid window and defaults to the selected one.
a1511caf
MR
1539Optional argument HORIZONTAL non-nil means return DELTA if WINDOW
1540can be resized horizontally by DELTA columns. A return value of
1541zero means that WINDOW is not resizable.
1542
1543DELTA positive means WINDOW shall be enlarged by DELTA lines or
2cffd681 1544columns. If WINDOW cannot be enlarged by DELTA lines or columns,
a1511caf
MR
1545return the maximum value in the range 0..DELTA by which WINDOW
1546can be enlarged.
1547
1548DELTA negative means WINDOW shall be shrunk by -DELTA lines or
1549columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
1550return the minimum value in the range DELTA..0 that can be used
1551for shrinking WINDOW.
1552
2116e93c 1553Optional argument IGNORE non-nil means ignore restrictions
a1511caf 1554imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
1555`window-min-width' settings. If IGNORE is a window, ignore
1556restrictions for that window only. If IGNORE equals `safe',
a1511caf 1557live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
1558and `window-safe-min-width' columns. Any other non-nil value
1559means ignore all of the above restrictions for all windows.
a1511caf
MR
1560
1561Optional argument TRAIL `before' means only windows to the left
1562of or below WINDOW can be shrunk. Optional argument TRAIL
1563`after' means only windows to the right of or above WINDOW can be
1564shrunk.
1565
1566Optional argument NOUP non-nil means don't go up in the window
2cffd681
MR
1567tree but check only whether space can be obtained from (or given
1568to) WINDOW's siblings.
a1511caf 1569
2cffd681
MR
1570Optional argument NODOWN non-nil means don't go down in the
1571window tree. This means do not check whether resizing would
880e6158
MR
1572violate size restrictions of WINDOW or its child windows.
1573
1574Optional argument PIXELWISE non-nil means interpret DELTA as
1575number of pixels."
447f16b8 1576 (setq window (window-normalize-window window))
a1511caf
MR
1577 (cond
1578 ((< delta 0)
880e6158
MR
1579 (max (- (window-min-delta
1580 window horizontal ignore trail noup nodown pixelwise))
a1511caf
MR
1581 delta))
1582 ((> delta 0)
880e6158
MR
1583 (min (window-max-delta
1584 window horizontal ignore trail noup nodown pixelwise)
a1511caf
MR
1585 delta))
1586 (t 0)))
1587
880e6158 1588(defun window--resizable-p (window delta &optional horizontal ignore trail noup nodown pixelwise)
a1511caf 1589 "Return t if WINDOW can be resized vertically by DELTA lines.
85c2386b 1590WINDOW must be a valid window and defaults to the selected one.
a1511caf 1591For the meaning of the arguments of this function see the
880e6158
MR
1592doc-string of `window--resizable'.
1593
1594Optional argument PIXELWISE non-nil means interpret DELTA as
1595pixels."
447f16b8 1596 (setq window (window-normalize-window window))
a1511caf 1597 (if (> delta 0)
880e6158
MR
1598 (>= (window--resizable
1599 window delta horizontal ignore trail noup nodown pixelwise)
a1511caf 1600 delta)
880e6158
MR
1601 (<= (window--resizable
1602 window delta horizontal ignore trail noup nodown pixelwise)
a1511caf
MR
1603 delta)))
1604
880e6158 1605(defun window-resizable (window delta &optional horizontal ignore pixelwise)
2cffd681 1606 "Return DELTA if WINDOW can be resized vertically by DELTA lines.
85c2386b 1607WINDOW must be a valid window and defaults to the selected one.
2cffd681
MR
1608Optional argument HORIZONTAL non-nil means return DELTA if WINDOW
1609can be resized horizontally by DELTA columns. A return value of
1610zero means that WINDOW is not resizable.
1611
1612DELTA positive means WINDOW shall be enlarged by DELTA lines or
1613columns. If WINDOW cannot be enlarged by DELTA lines or columns
1614return the maximum value in the range 0..DELTA by which WINDOW
1615can be enlarged.
1616
1617DELTA negative means WINDOW shall be shrunk by -DELTA lines or
1618columns. If WINDOW cannot be shrunk by -DELTA lines or columns,
1619return the minimum value in the range DELTA..0 that can be used
1620for shrinking WINDOW.
1621
2116e93c 1622Optional argument IGNORE non-nil means ignore restrictions
2cffd681 1623imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
1624`window-min-width' settings. If IGNORE is a window, ignore
1625restrictions for that window only. If IGNORE equals `safe',
2cffd681 1626live windows may get as small as `window-safe-min-height' lines
2116e93c 1627and `window-safe-min-width' columns. Any other non-nil value
880e6158
MR
1628means ignore all of the above restrictions for all windows.
1629
1630Optional argument PIXELWISE non-nil means interpret DELTA as
1631pixels."
2cffd681 1632 (setq window (window-normalize-window window))
880e6158 1633 (window--resizable window delta horizontal ignore nil nil nil pixelwise))
2cffd681 1634
880e6158
MR
1635(defun window-resizable-p (window delta &optional horizontal ignore pixelwise)
1636 "Return t if WINDOW can be resized vertically by DELTA lines.
85c2386b 1637WINDOW must be a valid window and defaults to the selected one.
880e6158
MR
1638For the meaning of the arguments of this function see the
1639doc-string of `window-resizable'."
1640 (setq window (window-normalize-window window))
1641 (if (> delta 0)
1642 (>= (window--resizable
1643 window delta horizontal ignore nil nil nil pixelwise)
1644 delta)
1645 (<= (window--resizable
1646 window delta horizontal ignore nil nil nil pixelwise)
1647 delta)))
105216ed 1648
880e6158 1649;; Aliases of functions defined in window.c.
f3d1777e 1650(defalias 'window-height 'window-total-height)
880e6158
MR
1651(defalias 'window-width 'window-body-width)
1652
1653;; Eventually the following two should work pixelwise.
f3d1777e 1654
ccafbf06 1655;; See discussion in bug#4543.
4b0d61e3 1656(defun window-full-height-p (&optional window)
2116e93c 1657 "Return t if WINDOW is as high as its containing frame.
a1511caf
MR
1658More precisely, return t if and only if the total height of
1659WINDOW equals the total height of the root window of WINDOW's
85c2386b
MR
1660frame. WINDOW must be a valid window and defaults to the
1661selected one."
447f16b8 1662 (setq window (window-normalize-window window))
880e6158
MR
1663 (= (window-pixel-height window)
1664 (window-pixel-height (frame-root-window window))))
a1511caf 1665
4b0d61e3 1666(defun window-full-width-p (&optional window)
2116e93c 1667 "Return t if WINDOW is as wide as its containing frame.
a1511caf
MR
1668More precisely, return t if and only if the total width of WINDOW
1669equals the total width of the root window of WINDOW's frame.
85c2386b 1670WINDOW must be a valid window and defaults to the selected one."
447f16b8 1671 (setq window (window-normalize-window window))
880e6158
MR
1672 (= (window-pixel-width window)
1673 (window-pixel-width (frame-root-window window))))
a1511caf 1674
105216ed
CY
1675(defun window-body-size (&optional window horizontal)
1676 "Return the height or width of WINDOW's text area.
85c2386b 1677WINDOW must be a live window and defaults to the selected one.
105216ed
CY
1678
1679If HORIZONTAL is omitted or nil, return the height of the text
1680area, like `window-body-height'. Otherwise, return the width of
1681the text area, like `window-body-width'."
1682 (if horizontal
1683 (window-body-width window)
1684 (window-body-height window)))
02c6f098 1685
3c448ab6
MR
1686(defun window-current-scroll-bars (&optional window)
1687 "Return the current scroll bar settings for WINDOW.
387522b2 1688WINDOW must be a live window and defaults to the selected one.
3c448ab6
MR
1689
1690The return value is a cons cell (VERTICAL . HORIZONTAL) where
1691VERTICAL specifies the current location of the vertical scroll
1692bars (`left', `right', or nil), and HORIZONTAL specifies the
1693current location of the horizontal scroll bars (`top', `bottom',
1694or nil).
1695
1696Unlike `window-scroll-bars', this function reports the scroll bar
1697type actually used, once frame defaults and `scroll-bar-mode' are
1698taken into account."
447f16b8 1699 (setq window (window-normalize-window window t))
3c448ab6
MR
1700 (let ((vert (nth 2 (window-scroll-bars window)))
1701 (hor nil))
1702 (when (or (eq vert t) (eq hor t))
387522b2 1703 (let ((fcsb (frame-current-scroll-bars (window-frame window))))
3c448ab6
MR
1704 (if (eq vert t)
1705 (setq vert (car fcsb)))
1706 (if (eq hor t)
1707 (setq hor (cdr fcsb)))))
1708 (cons vert hor)))
1709
c7635a97
CY
1710(defun walk-windows (fun &optional minibuf all-frames)
1711 "Cycle through all live windows, calling FUN for each one.
1712FUN must specify a function with a window as its sole argument.
3c448ab6 1713The optional arguments MINIBUF and ALL-FRAMES specify the set of
387522b2 1714windows to include in the walk.
3c448ab6
MR
1715
1716MINIBUF t means include the minibuffer window even if the
1717minibuffer is not active. MINIBUF nil or omitted means include
1718the minibuffer window only if the minibuffer is active. Any
1719other value means do not include the minibuffer window even if
1720the minibuffer is active.
1721
387522b2
MR
1722ALL-FRAMES nil or omitted means consider all windows on the
1723selected frame, plus the minibuffer window if specified by the
1724MINIBUF argument. If the minibuffer counts, consider all windows
1725on all frames that share that minibuffer too. The following
1726non-nil values of ALL-FRAMES have special meanings:
1727
1728- t means consider all windows on all existing frames.
1729
1730- `visible' means consider all windows on all visible frames on
1731 the current terminal.
1732
1733- 0 (the number zero) means consider all windows on all visible
1734 and iconified frames on the current terminal.
1735
1736- A frame means consider all windows on that frame only.
1737
1738Anything else means consider all windows on the selected frame
1739and no others.
3c448ab6
MR
1740
1741This function changes neither the order of recently selected
1742windows nor the buffer list."
1743 ;; If we start from the minibuffer window, don't fail to come
1744 ;; back to it.
290d5b58 1745 (when (window-minibuffer-p)
3c448ab6
MR
1746 (setq minibuf t))
1747 ;; Make sure to not mess up the order of recently selected
1748 ;; windows. Use `save-selected-window' and `select-window'
1749 ;; with second argument non-nil for this purpose.
1750 (save-selected-window
1751 (when (framep all-frames)
1752 (select-window (frame-first-window all-frames) 'norecord))
387522b2 1753 (dolist (walk-windows-window (window-list-1 nil minibuf all-frames))
c7635a97 1754 (funcall fun walk-windows-window))))
387522b2 1755
e07b9a6d
MR
1756(defun window-at-side-p (&optional window side)
1757 "Return t if WINDOW is at SIDE of its containing frame.
85c2386b
MR
1758WINDOW must be a valid window and defaults to the selected one.
1759SIDE can be any of the symbols `left', `top', `right' or
1760`bottom'. The default value nil is handled like `bottom'."
447f16b8 1761 (setq window (window-normalize-window window))
e07b9a6d
MR
1762 (let ((edge
1763 (cond
1764 ((eq side 'left) 0)
1765 ((eq side 'top) 1)
1766 ((eq side 'right) 2)
1767 ((memq side '(bottom nil)) 3))))
880e6158
MR
1768 (= (nth edge (window-pixel-edges window))
1769 (nth edge (window-pixel-edges (frame-root-window window))))))
e07b9a6d 1770
54f9154c 1771(defun window-at-side-list (&optional frame side)
e07b9a6d
MR
1772 "Return list of all windows on SIDE of FRAME.
1773FRAME must be a live frame and defaults to the selected frame.
1774SIDE can be any of the symbols `left', `top', `right' or
1775`bottom'. The default value nil is handled like `bottom'."
1776 (setq frame (window-normalize-frame frame))
1777 (let (windows)
1778 (walk-window-tree
1779 (lambda (window)
1780 (when (window-at-side-p window side)
1781 (setq windows (cons window windows))))
ea95074e 1782 frame nil 'nomini)
e07b9a6d
MR
1783 (nreverse windows)))
1784
5e92ca23 1785(defun window--in-direction-2 (window posn &optional horizontal)
387522b2
MR
1786 "Support function for `window-in-direction'."
1787 (if horizontal
880e6158 1788 (let ((top (window-pixel-top window)))
387522b2
MR
1789 (if (> top posn)
1790 (- top posn)
880e6158
MR
1791 (- posn top (window-pixel-height window))))
1792 (let ((left (window-pixel-left window)))
387522b2
MR
1793 (if (> left posn)
1794 (- left posn)
880e6158 1795 (- posn left (window-pixel-width window))))))
387522b2 1796
ea95074e
MR
1797;; Predecessors to the below have been devised by Julian Assange in
1798;; change-windows-intuitively.el and Hovav Shacham in windmove.el.
1799;; Neither of these allow to selectively ignore specific windows
1800;; (windows whose `no-other-window' parameter is non-nil) as targets of
1801;; the movement.
71e6691e 1802(defun window-in-direction (direction &optional window ignore sign wrap mini)
387522b2 1803 "Return window in DIRECTION as seen from WINDOW.
ea95074e
MR
1804More precisely, return the nearest window in direction DIRECTION
1805as seen from the position of `window-point' in window WINDOW.
387522b2
MR
1806DIRECTION must be one of `above', `below', `left' or `right'.
1807WINDOW must be a live window and defaults to the selected one.
ea95074e
MR
1808
1809Do not return a window whose `no-other-window' parameter is
1810non-nil. If the nearest window's `no-other-window' parameter is
1811non-nil, try to find another window in the indicated direction.
1812If, however, the optional argument IGNORE is non-nil, return that
1813window even if its `no-other-window' parameter is non-nil.
1814
71e6691e
MR
1815Optional argument SIGN a negative number means to use the right
1816or bottom edge of WINDOW as reference position instead of
1817`window-point'. SIGN a positive number means to use the left or
1818top edge of WINDOW as reference position.
1819
1820Optional argument WRAP non-nil means to wrap DIRECTION around
1821frame borders. This means to return for a WINDOW a the top of
1822the frame and DIRECTION `above' to return the minibuffer window
1823if the frame has one, and a window at the bottom of the frame
1824otherwise.
1825
1826Optional argument MINI nil means to return the minibuffer window
1827if and only if it is currently active. MINI non-nil means to
1828return the minibuffer window even when it's not active. However,
1829if WRAP non-nil, always act as if MINI were nil.
1830
ea95074e 1831Return nil if no suitable window can be found."
447f16b8 1832 (setq window (window-normalize-window window t))
387522b2
MR
1833 (unless (memq direction '(above below left right))
1834 (error "Wrong direction %s" direction))
1835 (let* ((frame (window-frame window))
1836 (hor (memq direction '(left right)))
1837 (first (if hor
880e6158
MR
1838 (window-pixel-left window)
1839 (window-pixel-top window)))
1840 (last (+ first (window-size window hor t)))
387522b2
MR
1841 ;; The column / row value of `posn-at-point' can be nil for the
1842 ;; mini-window, guard against that.
71e6691e
MR
1843 (posn
1844 (cond
1845 ((and (numberp sign) (< sign 0))
1846 (if hor
1847 (1- (+ (window-pixel-top window) (window-pixel-height window)))
1848 (1- (+ (window-pixel-left window) (window-pixel-width window)))))
1849 ((and (numberp sign) (> sign 0))
1850 (if hor
1851 (window-pixel-top window)
1852 (window-pixel-left window)))
1853 ((let ((posn-cons (nth 2 (posn-at-point (window-point window) window))))
1854 (if hor
1855 (+ (or (cdr posn-cons) 1) (window-pixel-top window))
1856 (+ (or (car posn-cons) 1) (window-pixel-left window)))))))
387522b2
MR
1857 (best-edge
1858 (cond
880e6158
MR
1859 ((eq direction 'below) (frame-pixel-height frame))
1860 ((eq direction 'right) (frame-pixel-width frame))
387522b2
MR
1861 (t -1)))
1862 (best-edge-2 best-edge)
880e6158 1863 (best-diff-2 (if hor (frame-pixel-height frame) (frame-pixel-width frame)))
387522b2
MR
1864 best best-2 best-diff-2-new)
1865 (walk-window-tree
1866 (lambda (w)
880e6158
MR
1867 (let* ((w-top (window-pixel-top w))
1868 (w-left (window-pixel-left w)))
387522b2
MR
1869 (cond
1870 ((or (eq window w)
1871 ;; Ignore ourselves.
1872 (and (window-parameter w 'no-other-window)
1873 ;; Ignore W unless IGNORE is non-nil.
1874 (not ignore))))
1875 (hor
1876 (cond
1877 ((and (<= w-top posn)
880e6158 1878 (< posn (+ w-top (window-pixel-height w))))
387522b2
MR
1879 ;; W is to the left or right of WINDOW and covers POSN.
1880 (when (or (and (eq direction 'left)
71e6691e
MR
1881 (or (and (<= w-left first) (> w-left best-edge))
1882 (and wrap
1883 (window-at-side-p window 'left)
1884 (window-at-side-p w 'right))))
387522b2 1885 (and (eq direction 'right)
71e6691e
MR
1886 (or (and (>= w-left last) (< w-left best-edge))
1887 (and wrap
1888 (window-at-side-p window 'right)
1889 (window-at-side-p w 'left)))))
387522b2
MR
1890 (setq best-edge w-left)
1891 (setq best w)))
1892 ((and (or (and (eq direction 'left)
880e6158 1893 (<= (+ w-left (window-pixel-width w)) first))
387522b2
MR
1894 (and (eq direction 'right) (<= last w-left)))
1895 ;; W is to the left or right of WINDOW but does not
1896 ;; cover POSN.
1897 (setq best-diff-2-new
5e92ca23 1898 (window--in-direction-2 w posn hor))
387522b2
MR
1899 (or (< best-diff-2-new best-diff-2)
1900 (and (= best-diff-2-new best-diff-2)
1901 (if (eq direction 'left)
1902 (> w-left best-edge-2)
1903 (< w-left best-edge-2)))))
1904 (setq best-edge-2 w-left)
1905 (setq best-diff-2 best-diff-2-new)
1906 (setq best-2 w))))
71e6691e
MR
1907 ((and (<= w-left posn)
1908 (< posn (+ w-left (window-pixel-width w))))
1909 ;; W is above or below WINDOW and covers POSN.
1910 (when (or (and (eq direction 'above)
1911 (or (and (<= w-top first) (> w-top best-edge))
1912 (and wrap
1913 (window-at-side-p window 'top)
1914 (if (active-minibuffer-window)
1915 (minibuffer-window-active-p w)
1916 (window-at-side-p w 'bottom)))))
1917 (and (eq direction 'below)
1918 (or (and (>= w-top first) (< w-top best-edge))
1919 (and wrap
1920 (if (active-minibuffer-window)
1921 (minibuffer-window-active-p window)
1922 (window-at-side-p window 'bottom))
1923 (window-at-side-p w 'top)))))
1924 (setq best-edge w-top)
1925 (setq best w)))
1926 ((and (or (and (eq direction 'above)
1927 (<= (+ w-top (window-pixel-height w)) first))
1928 (and (eq direction 'below) (<= last w-top)))
1929 ;; W is above or below WINDOW but does not cover POSN.
1930 (setq best-diff-2-new
1931 (window--in-direction-2 w posn hor))
1932 (or (< best-diff-2-new best-diff-2)
1933 (and (= best-diff-2-new best-diff-2)
1934 (if (eq direction 'above)
1935 (> w-top best-edge-2)
1936 (< w-top best-edge-2)))))
1937 (setq best-edge-2 w-top)
1938 (setq best-diff-2 best-diff-2-new)
1939 (setq best-2 w)))))
1940 frame nil (and mini t))
387522b2 1941 (or best best-2)))
3c448ab6 1942
4c43d97b 1943(defun get-window-with-predicate (predicate &optional minibuf all-frames default)
387522b2
MR
1944 "Return a live window satisfying PREDICATE.
1945More precisely, cycle through all windows calling the function
1946PREDICATE on each one of them with the window as its sole
1947argument. Return the first window for which PREDICATE returns
4c43d97b 1948non-nil. Windows are scanned starting with the window following
c80e3b4a 1949the selected window. If no window satisfies PREDICATE, return
4c43d97b
MR
1950DEFAULT.
1951
1952MINIBUF t means include the minibuffer window even if the
1953minibuffer is not active. MINIBUF nil or omitted means include
1954the minibuffer window only if the minibuffer is active. Any
1955other value means do not include the minibuffer window even if
1956the minibuffer is active.
387522b2
MR
1957
1958ALL-FRAMES nil or omitted means consider all windows on the selected
1959frame, plus the minibuffer window if specified by the MINIBUF
1960argument. If the minibuffer counts, consider all windows on all
1961frames that share that minibuffer too. The following non-nil
1962values of ALL-FRAMES have special meanings:
3c448ab6 1963
387522b2
MR
1964- t means consider all windows on all existing frames.
1965
1966- `visible' means consider all windows on all visible frames on
1967 the current terminal.
1968
1969- 0 (the number zero) means consider all windows on all visible
1970 and iconified frames on the current terminal.
1971
1972- A frame means consider all windows on that frame only.
1973
1974Anything else means consider all windows on the selected frame
1975and no others."
3c448ab6 1976 (catch 'found
4c43d97b
MR
1977 (dolist (window (window-list-1
1978 (next-window nil minibuf all-frames)
1979 minibuf all-frames))
387522b2
MR
1980 (when (funcall predicate window)
1981 (throw 'found window)))
3c448ab6
MR
1982 default))
1983
1984(defalias 'some-window 'get-window-with-predicate)
1985
51a5f9d8 1986(defun get-lru-window (&optional all-frames dedicated not-selected)
190b47e6
MR
1987 "Return the least recently used window on frames specified by ALL-FRAMES.
1988Return a full-width window if possible. A minibuffer window is
1989never a candidate. A dedicated window is never a candidate
1990unless DEDICATED is non-nil, so if all windows are dedicated, the
1991value is nil. Avoid returning the selected window if possible.
51a5f9d8
MR
1992Optional argument NOT-SELECTED non-nil means never return the
1993selected window.
190b47e6
MR
1994
1995The following non-nil values of the optional argument ALL-FRAMES
1996have special meanings:
1997
1998- t means consider all windows on all existing frames.
1999
2000- `visible' means consider all windows on all visible frames on
2001 the current terminal.
2002
2003- 0 (the number zero) means consider all windows on all visible
2004 and iconified frames on the current terminal.
2005
2006- A frame means consider all windows on that frame only.
2007
2008Any other value of ALL-FRAMES means consider all windows on the
2009selected frame and no others."
2010 (let (best-window best-time second-best-window second-best-time time)
02cfc6d6 2011 (dolist (window (window-list-1 nil 'nomini all-frames))
51a5f9d8
MR
2012 (when (and (or dedicated (not (window-dedicated-p window)))
2013 (or (not not-selected) (not (eq window (selected-window)))))
190b47e6
MR
2014 (setq time (window-use-time window))
2015 (if (or (eq window (selected-window))
2016 (not (window-full-width-p window)))
2017 (when (or (not second-best-time) (< time second-best-time))
2018 (setq second-best-time time)
2019 (setq second-best-window window))
2020 (when (or (not best-time) (< time best-time))
2021 (setq best-time time)
2022 (setq best-window window)))))
2023 (or best-window second-best-window)))
2024
51a5f9d8 2025(defun get-mru-window (&optional all-frames dedicated not-selected)
387522b2 2026 "Return the most recently used window on frames specified by ALL-FRAMES.
51a5f9d8
MR
2027A minibuffer window is never a candidate. A dedicated window is
2028never a candidate unless DEDICATED is non-nil, so if all windows
2029are dedicated, the value is nil. Optional argument NOT-SELECTED
2030non-nil means never return the selected window.
387522b2
MR
2031
2032The following non-nil values of the optional argument ALL-FRAMES
2033have special meanings:
2034
2035- t means consider all windows on all existing frames.
2036
2037- `visible' means consider all windows on all visible frames on
2038 the current terminal.
2039
2040- 0 (the number zero) means consider all windows on all visible
2041 and iconified frames on the current terminal.
2042
2043- A frame means consider all windows on that frame only.
2044
2045Any other value of ALL-FRAMES means consider all windows on the
2046selected frame and no others."
2047 (let (best-window best-time time)
02cfc6d6 2048 (dolist (window (window-list-1 nil 'nomini all-frames))
387522b2 2049 (setq time (window-use-time window))
51a5f9d8
MR
2050 (when (and (or dedicated (not (window-dedicated-p window)))
2051 (or (not not-selected) (not (eq window (selected-window))))
2052 (or (not best-time) (> time best-time)))
387522b2
MR
2053 (setq best-time time)
2054 (setq best-window window)))
2055 best-window))
2056
51a5f9d8 2057(defun get-largest-window (&optional all-frames dedicated not-selected)
190b47e6
MR
2058 "Return the largest window on frames specified by ALL-FRAMES.
2059A minibuffer window is never a candidate. A dedicated window is
2060never a candidate unless DEDICATED is non-nil, so if all windows
51a5f9d8
MR
2061are dedicated, the value is nil. Optional argument NOT-SELECTED
2062non-nil means never return the selected window.
190b47e6
MR
2063
2064The following non-nil values of the optional argument ALL-FRAMES
2065have special meanings:
2066
2067- t means consider all windows on all existing frames.
2068
2069- `visible' means consider all windows on all visible frames on
2070 the current terminal.
2071
2072- 0 (the number zero) means consider all windows on all visible
2073 and iconified frames on the current terminal.
2074
2075- A frame means consider all windows on that frame only.
2076
2077Any other value of ALL-FRAMES means consider all windows on the
2078selected frame and no others."
2079 (let ((best-size 0)
2080 best-window size)
02cfc6d6 2081 (dolist (window (window-list-1 nil 'nomini all-frames))
51a5f9d8
MR
2082 (when (and (or dedicated (not (window-dedicated-p window)))
2083 (or (not not-selected) (not (eq window (selected-window)))))
880e6158
MR
2084 (setq size (* (window-pixel-height window)
2085 (window-pixel-width window)))
190b47e6
MR
2086 (when (> size best-size)
2087 (setq best-size size)
2088 (setq best-window window))))
2089 best-window))
2090
3c448ab6
MR
2091(defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames)
2092 "Return list of all windows displaying BUFFER-OR-NAME, or nil if none.
2093BUFFER-OR-NAME may be a buffer or the name of an existing buffer
4c43d97b
MR
2094and defaults to the current buffer. Windows are scanned starting
2095with the selected window.
190b47e6
MR
2096
2097MINIBUF t means include the minibuffer window even if the
2098minibuffer is not active. MINIBUF nil or omitted means include
2099the minibuffer window only if the minibuffer is active. Any
2100other value means do not include the minibuffer window even if
2101the minibuffer is active.
2102
2103ALL-FRAMES nil or omitted means consider all windows on the
2104selected frame, plus the minibuffer window if specified by the
2105MINIBUF argument. If the minibuffer counts, consider all windows
2106on all frames that share that minibuffer too. The following
2107non-nil values of ALL-FRAMES have special meanings:
2108
2109- t means consider all windows on all existing frames.
2110
2111- `visible' means consider all windows on all visible frames on
2112 the current terminal.
2113
2114- 0 (the number zero) means consider all windows on all visible
2115 and iconified frames on the current terminal.
2116
2117- A frame means consider all windows on that frame only.
2118
2119Anything else means consider all windows on the selected frame
2120and no others."
5386012d 2121 (let ((buffer (window-normalize-buffer buffer-or-name))
3c448ab6 2122 windows)
4c43d97b 2123 (dolist (window (window-list-1 (selected-window) minibuf all-frames))
190b47e6
MR
2124 (when (eq (window-buffer window) buffer)
2125 (setq windows (cons window windows))))
2126 (nreverse windows)))
3c448ab6
MR
2127
2128(defun minibuffer-window-active-p (window)
2129 "Return t if WINDOW is the currently active minibuffer window."
2130 (eq window (active-minibuffer-window)))
387522b2 2131
3c448ab6 2132(defun count-windows (&optional minibuf)
387522b2 2133 "Return the number of live windows on the selected frame.
3c448ab6
MR
2134The optional argument MINIBUF specifies whether the minibuffer
2135window shall be counted. See `walk-windows' for the precise
2136meaning of this argument."
387522b2 2137 (length (window-list-1 nil minibuf)))
9aab8e0d
MR
2138\f
2139;;; Resizing windows.
880e6158
MR
2140(defun window--size-to-pixel (window size &optional horizontal pixelwise round-maybe)
2141 "For WINDOW convert SIZE lines to pixels.
2142SIZE is supposed to specify a height of WINDOW in terms of text
2143lines. The return value is the number of pixels specifying that
2144height.
2145
2146WINDOW must be a valid window. Optional argument HORIZONTAL
2147non-nil means convert SIZE columns to pixels.
2148
2149Optional argument PIXELWISE non-nil means SIZE already specifies
2150pixels but may have to be adjusted to a multiple of the character
2151size of WINDOW's frame. Optional argument ROUND-MAYBE non-nil
2152means round to the nearest multiple of the character size of
2153WINDOW's frame if the option `window-resize-pixelwise' is nil."
2154 (setq window (window-normalize-window window))
2155 (let ((char-size (frame-char-size window horizontal)))
2156 (if pixelwise
2157 (if (and round-maybe (not window-resize-pixelwise))
2158 (* (round size char-size) char-size)
2159 size)
2160 (* size char-size))))
2161
880e6158
MR
2162(defun window--pixel-to-total-1 (window horizontal char-size)
2163 "Subroutine of `window--pixel-to-total'."
2164 (let ((child (window-child window)))
2165 (if (window-combination-p window horizontal)
2166 ;; In an iso-combination distribute sizes proportionally.
2167 (let ((remainder (window-new-total window))
c44de18d 2168 size best-child rem best-rem)
880e6158
MR
2169 ;; Initialize total sizes to each child's floor.
2170 (while child
c44de18d 2171 (setq size (max (/ (window-size child horizontal t) char-size) 1))
880e6158
MR
2172 (set-window-new-total child size)
2173 (setq remainder (- remainder size))
2174 (setq child (window-next-sibling child)))
2175 ;; Distribute remainder.
2176 (while (> remainder 0)
2177 (setq child (window-last-child window))
2178 (setq best-child nil)
c44de18d 2179 (setq best-rem 0)
880e6158 2180 (while child
c44de18d
MR
2181 (when (and (<= (window-new-total child)
2182 (/ (window-size child horizontal t) char-size))
2183 (> (setq rem (% (window-size child horizontal t)
2184 char-size))
2185 best-rem))
2186 (setq best-child child)
2187 (setq best-rem rem))
880e6158
MR
2188 (setq child (window-prev-sibling child)))
2189 ;; We MUST have a best-child here.
2190 (set-window-new-total best-child 1 t)
2191 (setq remainder (1- remainder)))
2192 ;; Recurse.
2193 (setq child (window-child window))
2194 (while child
2195 (window--pixel-to-total-1 child horizontal char-size)
2196 (setq child (window-next-sibling child))))
2197 ;; In an ortho-combination assign new sizes directly.
2198 (let ((size (window-new-total window)))
2199 (while child
2200 (set-window-new-total child size)
2201 (window--pixel-to-total-1 child horizontal char-size)
2202 (setq child (window-next-sibling child)))))))
2203
2204(defun window--pixel-to-total (&optional frame horizontal)
2205 "On FRAME assign new total window heights from pixel heights.
2206FRAME must be a live frame and defaults to the selected frame.
2207
2208Optional argument HORIZONTAL non-nil means assign new total
2209window widths from pixel widths."
2210 (setq frame (window-normalize-frame frame))
c44de18d
MR
2211 (let* ((char-size (frame-char-size frame horizontal))
2212 (root (frame-root-window))
2213 (root-size (window-size root horizontal t))
2214 ;; We have to care about the minibuffer window only if it
2215 ;; appears together with the root window on this frame.
2216 (mini (let ((mini (minibuffer-window frame)))
2217 (and (eq (window-frame mini) frame)
2218 (not (eq mini root)) mini)))
2219 (mini-size (and mini (window-size mini horizontal t))))
2220 ;; We round the line/column sizes of windows here to the nearest
2221 ;; integer. In some cases this can make windows appear _larger_
2222 ;; than the containing frame (line/column-wise) because the latter's
2223 ;; sizes are not (yet) rounded. We might eventually fix that.
2224 (if (and mini (not horizontal))
2225 (let (lines)
2226 (set-window-new-total root (max (/ root-size char-size) 1))
2227 (set-window-new-total mini (max (/ mini-size char-size) 1))
2228 (setq lines (- (round (+ root-size mini-size) char-size)
2229 (+ (window-new-total root) (window-new-total mini))))
2230 (while (> lines 0)
2231 (if (>= (% root-size (window-new-total root))
2232 (% mini-size (window-new-total mini)))
2233 (set-window-new-total root 1 t)
2234 (set-window-new-total mini 1 t))
2235 (setq lines (1- lines))))
2236 (set-window-new-total root (round root-size char-size))
2237 (when mini
2238 ;; This is taken in the horizontal case only.
2239 (set-window-new-total mini (round mini-size char-size))))
880e6158 2240 (unless (window-buffer root)
c44de18d
MR
2241 (window--pixel-to-total-1 root horizontal char-size))
2242 ;; Apply the new sizes.
2243 (window-resize-apply-total frame horizontal)))
880e6158 2244
5386012d 2245(defun window--resize-reset (&optional frame horizontal)
9aab8e0d
MR
2246 "Reset resize values for all windows on FRAME.
2247FRAME defaults to the selected frame.
2248
880e6158 2249This function stores the current value of `window-size' applied
9aab8e0d
MR
2250with argument HORIZONTAL in the new total size of all windows on
2251FRAME. It also resets the new normal size of each of these
2252windows."
5386012d
MR
2253 (window--resize-reset-1
2254 (frame-root-window (window-normalize-frame frame)) horizontal))
9aab8e0d 2255
5386012d
MR
2256(defun window--resize-reset-1 (window horizontal)
2257 "Internal function of `window--resize-reset'."
9aab8e0d 2258 ;; Register old size in the new total size.
880e6158
MR
2259 (set-window-new-pixel window (window-size window horizontal t))
2260 (set-window-new-total window (window-size window horizontal))
9aab8e0d
MR
2261 ;; Reset new normal size.
2262 (set-window-new-normal window)
2263 (when (window-child window)
5386012d 2264 (window--resize-reset-1 (window-child window) horizontal))
9aab8e0d 2265 (when (window-right window)
5386012d 2266 (window--resize-reset-1 (window-right window) horizontal)))
9aab8e0d 2267
562dd5e9
MR
2268;; The following routine is used to manually resize the minibuffer
2269;; window and is currently used, for example, by ispell.el.
5386012d 2270(defun window--resize-mini-window (window delta)
880e6158
MR
2271 "Resize minibuffer window WINDOW by DELTA pixels.
2272If WINDOW cannot be resized by DELTA pixels make it as large (or
2116e93c 2273as small) as possible, but don't signal an error."
562dd5e9
MR
2274 (when (window-minibuffer-p window)
2275 (let* ((frame (window-frame window))
2276 (root (frame-root-window frame))
880e6158 2277 (height (window-pixel-height window))
562dd5e9 2278 (min-delta
880e6158
MR
2279 (- (window-pixel-height root)
2280 (window-min-size root nil nil t))))
562dd5e9
MR
2281 ;; Sanitize DELTA.
2282 (cond
2283 ((<= (+ height delta) 0)
880e6158 2284 (setq delta (- (frame-char-height (window-frame window)) height)))
562dd5e9
MR
2285 ((> delta min-delta)
2286 (setq delta min-delta)))
2287
880e6158
MR
2288 (unless (zerop delta)
2289 ;; Resize now.
2290 (window--resize-reset frame)
2291 ;; Ideally we should be able to resize just the last child of root
2292 ;; here. See the comment in `resize-root-window-vertically' for
2293 ;; why we do not do that.
2294 (window--resize-this-window root (- delta) nil nil t)
2295 (set-window-new-pixel window (+ height delta))
2296 ;; The following routine catches the case where we want to resize
2297 ;; a minibuffer-only frame.
2298 (when (resize-mini-window-internal window)
2299 (window--pixel-to-total frame)
2300 (run-window-configuration-change-hook frame))))))
2301
2302(defun window--resize-apply-p (frame &optional horizontal)
2303 "Return t when a window on FRAME shall be resized vertically.
2304Optional argument HORIZONTAL non-nil means return t when a window
2305shall be resized horizontally."
2306(catch 'apply
2307 (walk-window-tree
2308 (lambda (window)
2309 (unless (= (window-new-pixel window)
2310 (window-size window horizontal t))
2311 (throw 'apply t)))
2312 frame t)
2313 nil))
2314
2315(defun window-resize (window delta &optional horizontal ignore pixelwise)
562dd5e9
MR
2316 "Resize WINDOW vertically by DELTA lines.
2317WINDOW can be an arbitrary window and defaults to the selected
2318one. An attempt to resize the root window of a frame will raise
2319an error though.
2320
2321DELTA a positive number means WINDOW shall be enlarged by DELTA
2322lines. DELTA negative means WINDOW shall be shrunk by -DELTA
2323lines.
2324
2325Optional argument HORIZONTAL non-nil means resize WINDOW
2326horizontally by DELTA columns. In this case a positive DELTA
2327means enlarge WINDOW by DELTA columns. DELTA negative means
2328WINDOW shall be shrunk by -DELTA columns.
2329
2116e93c 2330Optional argument IGNORE non-nil means ignore restrictions
562dd5e9 2331imposed by fixed size windows, `window-min-height' or
2116e93c
EZ
2332`window-min-width' settings. If IGNORE is a window, ignore
2333restrictions for that window only. If IGNORE equals `safe',
562dd5e9 2334live windows may get as small as `window-safe-min-height' lines
2116e93c
EZ
2335and `window-safe-min-width' columns. Any other non-nil value
2336means ignore all of the above restrictions for all windows.
562dd5e9 2337
880e6158
MR
2338Optional argument PIXELWISE non-nil means resize WINDOW by DELTA
2339pixels.
2340
562dd5e9
MR
2341This function resizes other windows proportionally and never
2342deletes any windows. If you want to move only the low (right)
2343edge of WINDOW consider using `adjust-window-trailing-edge'
2344instead."
447f16b8 2345 (setq window (window-normalize-window window))
562dd5e9 2346 (let* ((frame (window-frame window))
feeb6f53 2347 (minibuffer-window (minibuffer-window frame))
562dd5e9 2348 sibling)
880e6158
MR
2349 (setq delta (window--size-to-pixel
2350 window delta horizontal pixelwise t))
562dd5e9
MR
2351 (cond
2352 ((eq window (frame-root-window frame))
2353 (error "Cannot resize the root window of a frame"))
2354 ((window-minibuffer-p window)
41cfe0cb
MR
2355 (if horizontal
2356 (error "Cannot resize minibuffer window horizontally")
2357 (window--resize-mini-window window delta)))
feeb6f53
MR
2358 ((and (not horizontal)
2359 (window-full-height-p window)
2360 (eq (window-frame minibuffer-window) frame)
2361 (or (not resize-mini-windows)
2362 (eq minibuffer-window (active-minibuffer-window))))
2363 ;; If WINDOW is full height and either `resize-mini-windows' is
2364 ;; nil or the minibuffer window is active, resize the minibuffer
2365 ;; window.
2366 (window--resize-mini-window minibuffer-window (- delta)))
880e6158
MR
2367 ((window--resizable-p
2368 window delta horizontal ignore nil nil nil t)
5386012d
MR
2369 (window--resize-reset frame horizontal)
2370 (window--resize-this-window window delta horizontal ignore t)
a0c2d0ae 2371 (if (and (not window-combination-resize)
3d8daefe 2372 (window-combined-p window horizontal)
562dd5e9 2373 (setq sibling (or (window-right window) (window-left window)))
880e6158
MR
2374 (window-sizable-p
2375 sibling (- delta) horizontal ignore t))
a0c2d0ae 2376 ;; If window-combination-resize is nil, WINDOW is part of an
89d61221 2377 ;; iso-combination, and WINDOW's neighboring right or left
562dd5e9
MR
2378 ;; sibling can be resized as requested, resize that sibling.
2379 (let ((normal-delta
2380 (/ (float delta)
880e6158 2381 (window-size (window-parent window) horizontal t))))
5386012d 2382 (window--resize-this-window sibling (- delta) horizontal nil t)
562dd5e9
MR
2383 (set-window-new-normal
2384 window (+ (window-normal-size window horizontal)
2385 normal-delta))
2386 (set-window-new-normal
2387 sibling (- (window-normal-size sibling horizontal)
2388 normal-delta)))
2389 ;; Otherwise, resize all other windows in the same combination.
5386012d 2390 (window--resize-siblings window delta horizontal ignore))
880e6158 2391 (when (window--resize-apply-p frame horizontal)
8dd3e94f
MR
2392 (if (window-resize-apply frame horizontal)
2393 (progn
2394 (window--pixel-to-total frame horizontal)
2395 (run-window-configuration-change-hook frame))
2396 (error "Failed to apply resizing %s" window))))
562dd5e9
MR
2397 (t
2398 (error "Cannot resize window %s" window)))))
2399
880e6158 2400(defun window-resize-no-error (window delta &optional horizontal ignore pixelwise)
27fcfe31
MR
2401 "Resize WINDOW vertically if it is resizable by DELTA lines.
2402This function is like `window-resize' but does not signal an
2403error when WINDOW cannot be resized. For the meaning of the
880e6158
MR
2404optional arguments see the documentation of `window-resize'.
2405
2406Optional argument PIXELWISE non-nil means interpret DELTA as
2407pixels."
2408 (when (window--resizable-p
2409 window delta horizontal ignore nil nil nil pixelwise)
2410 (window-resize window delta horizontal ignore pixelwise)))
27fcfe31 2411
4b0d61e3 2412(defun window--resize-child-windows-skip-p (window)
9aab8e0d
MR
2413 "Return non-nil if WINDOW shall be skipped by resizing routines."
2414 (memq (window-new-normal window) '(ignore stuck skip)))
2415
be7f5545
MR
2416(defun window--resize-child-windows-normal (parent horizontal window this-delta &optional trail other-delta)
2417 "Recursively set new normal height of child windows of window PARENT.
9aab8e0d 2418HORIZONTAL non-nil means set the new normal width of these
be7f5545 2419windows. WINDOW specifies a child window of PARENT that has been
382c953b 2420resized by THIS-DELTA lines (columns).
9aab8e0d 2421
2116e93c
EZ
2422Optional argument TRAIL either `before' or `after' means set values
2423only for windows before or after WINDOW. Optional argument
2424OTHER-DELTA, a number, specifies that this many lines (columns)
382c953b 2425have been obtained from (or returned to) an ancestor window of
9aab8e0d
MR
2426PARENT in order to resize WINDOW."
2427 (let* ((delta-normal
880e6158
MR
2428 (if (and (= (- this-delta)
2429 (window-size window horizontal t))
9aab8e0d
MR
2430 (zerop other-delta))
2431 ;; When WINDOW gets deleted and we can return its entire
2432 ;; space to its siblings, use WINDOW's normal size as the
2433 ;; normal delta.
2434 (- (window-normal-size window horizontal))
2435 ;; In any other case calculate the normal delta from the
2436 ;; relation of THIS-DELTA to the total size of PARENT.
880e6158
MR
2437 (/ (float this-delta)
2438 (window-size parent horizontal t))))
9aab8e0d
MR
2439 (sub (window-child parent))
2440 (parent-normal 0.0)
2441 (skip (eq trail 'after)))
2442
be7f5545
MR
2443 ;; Set parent-normal to the sum of the normal sizes of all child
2444 ;; windows of PARENT that shall be resized, excluding only WINDOW
9aab8e0d
MR
2445 ;; and any windows specified by the optional TRAIL argument.
2446 (while sub
2447 (cond
2448 ((eq sub window)
2449 (setq skip (eq trail 'before)))
2450 (skip)
2451 (t
2452 (setq parent-normal
2453 (+ parent-normal (window-normal-size sub horizontal)))))
2454 (setq sub (window-right sub)))
2455
be7f5545 2456 ;; Set the new normal size of all child windows of PARENT from what
9aab8e0d
MR
2457 ;; they should have contributed for recovering THIS-DELTA lines
2458 ;; (columns).
2459 (setq sub (window-child parent))
2460 (setq skip (eq trail 'after))
2461 (while sub
2462 (cond
2463 ((eq sub window)
2464 (setq skip (eq trail 'before)))
2465 (skip)
2466 (t
2467 (let ((old-normal (window-normal-size sub horizontal)))
2468 (set-window-new-normal
2469 sub (min 1.0 ; Don't get larger than 1.
2470 (max (- old-normal
2471 (* (/ old-normal parent-normal)
2472 delta-normal))
2473 ;; Don't drop below 0.
2474 0.0))))))
2475 (setq sub (window-right sub)))
2476
2477 (when (numberp other-delta)
2478 ;; Set the new normal size of windows from what they should have
2479 ;; contributed for recovering OTHER-DELTA lines (columns).
880e6158
MR
2480 (setq delta-normal (/ (float (window-size parent horizontal t))
2481 (+ (window-size parent horizontal t)
9aab8e0d
MR
2482 other-delta)))
2483 (setq sub (window-child parent))
2484 (setq skip (eq trail 'after))
2485 (while sub
2486 (cond
2487 ((eq sub window)
2488 (setq skip (eq trail 'before)))
2489 (skip)
2490 (t
2491 (set-window-new-normal
2492 sub (min 1.0 ; Don't get larger than 1.
2493 (max (* (window-new-normal sub) delta-normal)
2494 ;; Don't drop below 0.
2495 0.0)))))
2496 (setq sub (window-right sub))))
2497
2498 ;; Set the new normal size of WINDOW to what is left by the sum of
2499 ;; the normal sizes of its siblings.
2500 (set-window-new-normal
2501 window
2502 (let ((sum 0))
2503 (setq sub (window-child parent))
2504 (while sub
2505 (cond
2506 ((eq sub window))
2507 ((not (numberp (window-new-normal sub)))
2508 (setq sum (+ sum (window-normal-size sub horizontal))))
2509 (t
2510 (setq sum (+ sum (window-new-normal sub)))))
2511 (setq sub (window-right sub)))
2512 ;; Don't get larger than 1 or smaller than 0.
2513 (min 1.0 (max (- 1.0 sum) 0.0))))))
2514
880e6158
MR
2515(defun window--resize-child-windows (parent delta &optional horizontal window ignore trail edge char-size)
2516 "Resize child windows of window PARENT vertically by DELTA pixels.
9aab8e0d
MR
2517PARENT must be a vertically combined internal window.
2518
880e6158
MR
2519Optional argument HORIZONTAL non-nil means resize child windows
2520of PARENT horizontally by DELTA pixels. In this case PARENT must
9aab8e0d
MR
2521be a horizontally combined internal window.
2522
2523WINDOW, if specified, must denote a child window of PARENT that
880e6158 2524is resized by DELTA pixels.
9aab8e0d 2525
2116e93c 2526Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 2527imposed by fixed size windows, `window-min-height' or
2116e93c 2528`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 2529windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
2530`window-safe-min-width' columns. If IGNORE is a window, ignore
2531restrictions for that window only. Any other non-nil value means
2532ignore all of the above restrictions for all windows.
9aab8e0d
MR
2533
2534Optional arguments TRAIL and EDGE, when non-nil, restrict the set
2535of windows that shall be resized. If TRAIL equals `before',
2536resize only windows on the left or above EDGE. If TRAIL equals
2537`after', resize only windows on the right or below EDGE. Also,
2538preferably only resize windows adjacent to EDGE.
2539
880e6158
MR
2540If the optional argument CHAR-SIZE is a positive integer, it specifies
2541the number of pixels by which windows are incrementally resized.
2542If CHAR-SIZE is nil, this means to use the value of
2543`frame-char-height' or `frame-char-width' of WINDOW's frame.
2544
9aab8e0d
MR
2545Return the symbol `normalized' if new normal sizes have been
2546already set by this routine."
2547 (let* ((first (window-child parent))
9c52dd5a 2548 (last (window-last-child parent))
880e6158
MR
2549 (parent-total (+ (window-size parent horizontal t)
2550 delta))
2551 (char-size (or char-size
2552 (and window-resize-pixelwise 1)
2553 (frame-char-size window horizontal)))
2554 sub best-window best-value best-delta)
9aab8e0d
MR
2555
2556 (if (and edge (memq trail '(before after))
2557 (progn
2558 (setq sub first)
2559 (while (and (window-right sub)
2560 (or (and (eq trail 'before)
be7f5545 2561 (not (window--resize-child-windows-skip-p
9aab8e0d
MR
2562 (window-right sub))))
2563 (and (eq trail 'after)
be7f5545 2564 (window--resize-child-windows-skip-p sub))))
9aab8e0d
MR
2565 (setq sub (window-right sub)))
2566 sub)
2567 (if horizontal
2568 (if (eq trail 'before)
880e6158 2569 (= (+ (window-pixel-left sub) (window-pixel-width sub))
9aab8e0d 2570 edge)
880e6158 2571 (= (window-pixel-left sub) edge))
9aab8e0d 2572 (if (eq trail 'before)
880e6158 2573 (= (+ (window-pixel-top sub) (window-pixel-height sub))
9aab8e0d 2574 edge)
880e6158
MR
2575 (= (window-pixel-top sub) edge)))
2576 (window-sizable-p sub delta horizontal ignore t))
9aab8e0d
MR
2577 ;; Resize only windows adjacent to EDGE.
2578 (progn
5386012d
MR
2579 (window--resize-this-window
2580 sub delta horizontal ignore t trail edge)
9aab8e0d
MR
2581 (if (and window (eq (window-parent sub) parent))
2582 (progn
2583 ;; Assign new normal sizes.
2584 (set-window-new-normal
880e6158 2585 sub (/ (float (window-new-pixel sub)) parent-total))
9aab8e0d
MR
2586 (set-window-new-normal
2587 window (- (window-normal-size window horizontal)
2588 (- (window-new-normal sub)
2589 (window-normal-size sub horizontal)))))
be7f5545 2590 (window--resize-child-windows-normal
5386012d
MR
2591 parent horizontal sub 0 trail delta))
2592 ;; Return 'normalized to notify `window--resize-siblings' that
9aab8e0d
MR
2593 ;; normal sizes have been already set.
2594 'normalized)
2595 ;; Resize all windows proportionally.
9c52dd5a 2596 (setq sub last)
9aab8e0d
MR
2597 (while sub
2598 (cond
be7f5545
MR
2599 ((or (window--resize-child-windows-skip-p sub)
2600 ;; Ignore windows to skip and fixed-size child windows -
2601 ;; in the latter case make it a window to skip.
9aab8e0d
MR
2602 (and (not ignore)
2603 (window-size-fixed-p sub horizontal)
2604 (set-window-new-normal sub 'ignore))))
2605 ((< delta 0)
2606 ;; When shrinking store the number of lines/cols we can get
2607 ;; from this window here together with the total/normal size
2608 ;; factor.
2609 (set-window-new-normal
2610 sub
2611 (cons
2612 ;; We used to call this with NODOWN t, "fixed" 2011-05-11.
880e6158
MR
2613 (window-min-delta sub horizontal ignore trail t nil t)
2614 (- (/ (float (window-size sub horizontal t))
9aab8e0d
MR
2615 parent-total)
2616 (window-normal-size sub horizontal)))))
2617 ((> delta 0)
2618 ;; When enlarging store the total/normal size factor only
2619 (set-window-new-normal
2620 sub
880e6158 2621 (- (/ (float (window-size sub horizontal t))
9aab8e0d
MR
2622 parent-total)
2623 (window-normal-size sub horizontal)))))
2624
9c52dd5a 2625 (setq sub (window-left sub)))
9aab8e0d
MR
2626
2627 (cond
2628 ((< delta 0)
2629 ;; Shrink windows by delta.
2630 (setq best-window t)
2631 (while (and best-window (not (zerop delta)))
9c52dd5a 2632 (setq sub last)
9aab8e0d
MR
2633 (setq best-window nil)
2634 (setq best-value most-negative-fixnum)
2635 (while sub
2636 (when (and (consp (window-new-normal sub))
8dd3e94f 2637 (not (<= (car (window-new-normal sub)) 0))
9aab8e0d
MR
2638 (> (cdr (window-new-normal sub)) best-value))
2639 (setq best-window sub)
2640 (setq best-value (cdr (window-new-normal sub))))
2641
9c52dd5a 2642 (setq sub (window-left sub)))
9aab8e0d
MR
2643
2644 (when best-window
880e6158
MR
2645 (setq best-delta (min (car (window-new-normal best-window))
2646 char-size (- delta)))
2647 (setq delta (+ delta best-delta))
2648 (set-window-new-pixel best-window (- best-delta) t)
2649 (set-window-new-normal
2650 best-window
2651 (if (= (car (window-new-normal best-window)) best-delta)
2652 'skip ; We can't shrink best-window any further.
8dd3e94f 2653 (cons (- (car (window-new-normal best-window)) best-delta)
880e6158
MR
2654 (- (/ (float (window-new-pixel best-window))
2655 parent-total)
2656 (window-normal-size best-window horizontal))))))))
9aab8e0d
MR
2657 ((> delta 0)
2658 ;; Enlarge windows by delta.
2659 (setq best-window t)
2660 (while (and best-window (not (zerop delta)))
9c52dd5a 2661 (setq sub last)
9aab8e0d
MR
2662 (setq best-window nil)
2663 (setq best-value most-positive-fixnum)
2664 (while sub
2665 (when (and (numberp (window-new-normal sub))
2666 (< (window-new-normal sub) best-value))
2667 (setq best-window sub)
2668 (setq best-value (window-new-normal sub)))
2669
9c52dd5a 2670 (setq sub (window-left sub)))
9aab8e0d
MR
2671
2672 (when best-window
880e6158
MR
2673 (setq best-delta (min delta char-size))
2674 (setq delta (- delta best-delta))
2675 (set-window-new-pixel best-window best-delta t)
2676 (set-window-new-normal
2677 best-window
2678 (- (/ (float (window-new-pixel best-window))
2679 parent-total)
2680 (window-normal-size best-window horizontal)))))))
9aab8e0d
MR
2681
2682 (when best-window
9c52dd5a 2683 (setq sub last)
9aab8e0d
MR
2684 (while sub
2685 (when (or (consp (window-new-normal sub))
2686 (numberp (window-new-normal sub)))
d615d6d2 2687 ;; Reset new normal size fields so `window-resize-apply'
9aab8e0d
MR
2688 ;; won't use them to apply new sizes.
2689 (set-window-new-normal sub))
2690
2691 (unless (eq (window-new-normal sub) 'ignore)
be7f5545 2692 ;; Resize this window's child windows (back-engineering
9aab8e0d 2693 ;; delta from sub's old and new total sizes).
880e6158
MR
2694 (let ((delta (- (window-new-pixel sub)
2695 (window-size sub horizontal t))))
9aab8e0d
MR
2696 (unless (and (zerop delta) (not trail))
2697 ;; For the TRAIL non-nil case we have to resize SUB
2698 ;; recursively even if it's size does not change.
5386012d 2699 (window--resize-this-window
9aab8e0d 2700 sub delta horizontal ignore nil trail edge))))
9c52dd5a 2701 (setq sub (window-left sub)))))))
9aab8e0d 2702
880e6158
MR
2703(defun window--resize-siblings (window delta &optional horizontal ignore trail edge char-size)
2704 "Resize other windows when WINDOW is resized vertically by DELTA pixels.
9aab8e0d 2705Optional argument HORIZONTAL non-nil means resize other windows
880e6158 2706when WINDOW is resized horizontally by DELTA pixels. WINDOW
9aab8e0d
MR
2707itself is not resized by this function.
2708
2116e93c 2709Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 2710imposed by fixed size windows, `window-min-height' or
2116e93c 2711`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 2712windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
2713`window-safe-min-width' columns. If IGNORE is a window, ignore
2714restrictions for that window only. Any other non-nil value means
2715ignore all of the above restrictions for all windows.
9aab8e0d
MR
2716
2717Optional arguments TRAIL and EDGE, when non-nil, refine the set
2718of windows that shall be resized. If TRAIL equals `before',
2719resize only windows on the left or above EDGE. If TRAIL equals
2720`after', resize only windows on the right or below EDGE. Also,
2721preferably only resize windows adjacent to EDGE."
2722 (when (window-parent window)
2723 (let* ((parent (window-parent window))
2724 (sub (window-child parent)))
3d8daefe 2725 (if (window-combined-p sub horizontal)
9aab8e0d
MR
2726 ;; In an iso-combination try to extract DELTA from WINDOW's
2727 ;; siblings.
cb882333 2728 (let ((skip (eq trail 'after))
9aab8e0d
MR
2729 this-delta other-delta)
2730 ;; Decide which windows shall be left alone.
2731 (while sub
2732 (cond
2733 ((eq sub window)
2734 ;; Make sure WINDOW is left alone when
2735 ;; resizing its siblings.
2736 (set-window-new-normal sub 'ignore)
2737 (setq skip (eq trail 'before)))
2738 (skip
2739 ;; Make sure this sibling is left alone when
2740 ;; resizing its siblings.
2741 (set-window-new-normal sub 'ignore))
842e3a93 2742 ((or (window--size-ignore-p sub ignore)
9aab8e0d
MR
2743 (not (window-size-fixed-p sub horizontal)))
2744 ;; Set this-delta to t to signal that we found a sibling
2745 ;; of WINDOW whose size is not fixed.
2746 (setq this-delta t)))
2747
2748 (setq sub (window-right sub)))
2749
2750 ;; Set this-delta to what we can get from WINDOW's siblings.
880e6158 2751 (if (= (- delta) (window-size window horizontal t))
9aab8e0d 2752 ;; A deletion, presumably. We must handle this case
2cffd681 2753 ;; specially since `window--resizable' can't be used.
9aab8e0d
MR
2754 (if this-delta
2755 ;; There's at least one resizable sibling we can
2756 ;; give WINDOW's size to.
2757 (setq this-delta delta)
2758 ;; No resizable sibling exists.
2759 (setq this-delta 0))
2760 ;; Any other form of resizing.
2761 (setq this-delta
880e6158
MR
2762 (window--resizable
2763 window delta horizontal ignore trail t nil t)))
9aab8e0d
MR
2764
2765 ;; Set other-delta to what we still have to get from
2766 ;; ancestor windows of parent.
2767 (setq other-delta (- delta this-delta))
2768 (unless (zerop other-delta)
2769 ;; Unless we got everything from WINDOW's siblings, PARENT
2770 ;; must be resized by other-delta lines or columns.
880e6158 2771 (set-window-new-pixel parent other-delta 'add))
9aab8e0d
MR
2772
2773 (if (zerop this-delta)
2774 ;; We haven't got anything from WINDOW's siblings but we
2775 ;; must update the normal sizes to respect other-delta.
be7f5545 2776 (window--resize-child-windows-normal
9aab8e0d
MR
2777 parent horizontal window this-delta trail other-delta)
2778 ;; We did get something from WINDOW's siblings which means
be7f5545
MR
2779 ;; we have to resize their child windows.
2780 (unless (eq (window--resize-child-windows
5386012d 2781 parent (- this-delta) horizontal
880e6158 2782 window ignore trail edge char-size)
be7f5545 2783 ;; If `window--resize-child-windows' returns
5386012d
MR
2784 ;; 'normalized, this means it has set the
2785 ;; normal sizes already.
9aab8e0d
MR
2786 'normalized)
2787 ;; Set the normal sizes.
be7f5545 2788 (window--resize-child-windows-normal
9aab8e0d
MR
2789 parent horizontal window this-delta trail other-delta))
2790 ;; Set DELTA to what we still have to get from ancestor
2791 ;; windows.
2792 (setq delta other-delta)))
2793
2794 ;; In an ortho-combination all siblings of WINDOW must be
2795 ;; resized by DELTA.
880e6158 2796 (set-window-new-pixel parent delta 'add)
9aab8e0d
MR
2797 (while sub
2798 (unless (eq sub window)
880e6158
MR
2799 (window--resize-this-window
2800 sub delta horizontal ignore t))
9aab8e0d
MR
2801 (setq sub (window-right sub))))
2802
2803 (unless (zerop delta)
2804 ;; "Go up."
5386012d 2805 (window--resize-siblings
880e6158 2806 parent delta horizontal ignore trail edge char-size)))))
9aab8e0d 2807
880e6158
MR
2808(defun window--resize-this-window (window delta &optional horizontal ignore add trail edge char-size)
2809 "Resize WINDOW vertically by DELTA pixels.
9aab8e0d 2810Optional argument HORIZONTAL non-nil means resize WINDOW
880e6158 2811horizontally by DELTA pixels.
9aab8e0d 2812
2116e93c 2813Optional argument IGNORE non-nil means ignore restrictions
9aab8e0d 2814imposed by fixed size windows, `window-min-height' or
2116e93c 2815`window-min-width' settings. If IGNORE equals `safe', live
9aab8e0d 2816windows may get as small as `window-safe-min-height' lines and
2116e93c
EZ
2817`window-safe-min-width' columns. If IGNORE is a window, ignore
2818restrictions for that window only. Any other non-nil value
2819means ignore all of the above restrictions for all windows.
9aab8e0d
MR
2820
2821Optional argument ADD non-nil means add DELTA to the new total
2822size of WINDOW.
2823
2824Optional arguments TRAIL and EDGE, when non-nil, refine the set
2825of windows that shall be resized. If TRAIL equals `before',
2826resize only windows on the left or above EDGE. If TRAIL equals
2827`after', resize only windows on the right or below EDGE. Also,
2828preferably only resize windows adjacent to EDGE.
2829
880e6158
MR
2830If the optional argument CHAR-SIZE is a positive integer, it specifies
2831the number of pixels by which windows are incrementally resized.
2832If CHAR-SIZE is nil, this means to use the value of
2833`frame-char-height' or `frame-char-width' of WINDOW's frame.
2834
be7f5545 2835This function recursively resizes WINDOW's child windows to fit the
2cffd681 2836new size. Make sure that WINDOW is `window--resizable' before
9aab8e0d
MR
2837calling this function. Note that this function does not resize
2838siblings of WINDOW or WINDOW's parent window. You have to
d615d6d2 2839eventually call `window-resize-apply' in order to make resizing
9aab8e0d
MR
2840actually take effect."
2841 (when add
2842 ;; Add DELTA to the new total size of WINDOW.
880e6158 2843 (set-window-new-pixel window delta t))
387522b2 2844
9aab8e0d
MR
2845 (let ((sub (window-child window)))
2846 (cond
2847 ((not sub))
3d8daefe 2848 ((window-combined-p sub horizontal)
be7f5545 2849 ;; In an iso-combination resize child windows according to their
9aab8e0d 2850 ;; normal sizes.
be7f5545 2851 (window--resize-child-windows
880e6158 2852 window delta horizontal nil ignore trail edge char-size))
be7f5545 2853 ;; In an ortho-combination resize each child window by DELTA.
9aab8e0d
MR
2854 (t
2855 (while sub
5386012d 2856 (window--resize-this-window
880e6158 2857 sub delta horizontal ignore t trail edge char-size)
9aab8e0d
MR
2858 (setq sub (window-right sub)))))))
2859
880e6158 2860(defun window--resize-root-window (window delta horizontal ignore pixelwise)
9aab8e0d
MR
2861 "Resize root window WINDOW vertically by DELTA lines.
2862HORIZONTAL non-nil means resize root window WINDOW horizontally
2863by DELTA columns.
2864
2865IGNORE non-nil means ignore any restrictions imposed by fixed
2866size windows, `window-min-height' or `window-min-width' settings.
2867
2868This function is only called by the frame resizing routines. It
2869resizes windows proportionally and never deletes any windows."
880e6158
MR
2870 (when (and (windowp window) (numberp delta))
2871 (let ((pixel-delta
2872 (if pixelwise
2873 delta
2874 (window--size-to-pixel window delta horizontal))))
2875 (when (window-sizable-p window pixel-delta horizontal ignore t)
2876 (window--resize-reset (window-frame window) horizontal)
2877 (window--resize-this-window
2878 window pixel-delta horizontal ignore t)))))
9aab8e0d 2879
880e6158 2880(defun window--resize-root-window-vertically (window delta pixelwise)
9aab8e0d
MR
2881 "Resize root window WINDOW vertically by DELTA lines.
2882If DELTA is less than zero and we can't shrink WINDOW by DELTA
2883lines, shrink it as much as possible. If DELTA is greater than
be7f5545 2884zero, this function can resize fixed-size windows in order to
880e6158
MR
2885recover the necessary lines. Return the number of lines that
2886were recovered.
9aab8e0d 2887
f224e500 2888Third argument PIXELWISE non-nil means to interpret DELTA as
880e6158 2889pixels and return the number of pixels that were recovered.
9aab8e0d 2890
880e6158
MR
2891This function is called by the minibuffer window resizing
2892routines."
2893 (let* ((frame (window-frame window))
2894 (pixel-delta
2895 (cond
2896 (pixelwise
2897 delta)
2898 ((numberp delta)
2899 (* (frame-char-height frame) delta))
2900 (t 0)))
2901 ignore)
9c52dd5a 2902 (cond
880e6158
MR
2903 ((zerop pixel-delta))
2904 ((< pixel-delta 0)
2905 (setq pixel-delta (window-sizable window pixel-delta nil nil pixelwise))
9c52dd5a
MR
2906 (window--resize-reset frame)
2907 ;; When shrinking the root window, emulate an edge drag in order
2908 ;; to not resize other windows if we can avoid it (Bug#12419).
2909 (window--resize-this-window
880e6158
MR
2910 window pixel-delta nil ignore t 'before
2911 (+ (window-pixel-top window) (window-pixel-height window)))
9c52dd5a
MR
2912 ;; Don't record new normal sizes to make sure that shrinking back
2913 ;; proportionally works as intended.
2914 (walk-window-tree
2915 (lambda (window) (set-window-new-normal window 'ignore)) frame t))
880e6158 2916 ((> pixel-delta 0)
9c52dd5a 2917 (window--resize-reset frame)
880e6158 2918 (unless (window-sizable window pixel-delta nil nil pixelwise)
9c52dd5a
MR
2919 (setq ignore t))
2920 ;; When growing the root window, resize proportionally. This
2921 ;; should give windows back their original sizes (hopefully).
880e6158
MR
2922 (window--resize-this-window
2923 window pixel-delta nil ignore t)))
9c52dd5a 2924 ;; Return the possibly adjusted DELTA.
880e6158
MR
2925 (if pixelwise
2926 pixel-delta
2927 (/ pixel-delta (frame-char-height frame)))))
9aab8e0d 2928
880e6158 2929(defun adjust-window-trailing-edge (window delta &optional horizontal pixelwise)
562dd5e9
MR
2930 "Move WINDOW's bottom edge by DELTA lines.
2931Optional argument HORIZONTAL non-nil means move WINDOW's right
85c2386b
MR
2932edge by DELTA columns. WINDOW must be a valid window and
2933defaults to the selected one.
562dd5e9 2934
880e6158
MR
2935Optional argument PIXELWISE non-nil means interpret DELTA as
2936number of pixels.
2937
2116e93c 2938If DELTA is greater than zero, move the edge downwards or to the
562dd5e9
MR
2939right. If DELTA is less than zero, move the edge upwards or to
2940the left. If the edge can't be moved by DELTA lines or columns,
2941move it as far as possible in the desired direction."
447f16b8 2942 (setq window (window-normalize-window window))
41cfe0cb
MR
2943 (let* ((frame (window-frame window))
2944 (minibuffer-window (minibuffer-window frame))
2945 (right window)
2946 left this-delta min-delta max-delta)
880e6158
MR
2947
2948 (unless pixelwise
2949 (setq pixelwise t)
2950 (setq delta (* delta (frame-char-size window horizontal))))
2951
562dd5e9 2952 ;; Find the edge we want to move.
3d8daefe 2953 (while (and (or (not (window-combined-p right horizontal))
562dd5e9
MR
2954 (not (window-right right)))
2955 (setq right (window-parent right))))
2956 (cond
41cfe0cb
MR
2957 ((and (not right) (not horizontal)
2958 ;; Resize the minibuffer window if it's on the same frame as
2959 ;; and immediately below WINDOW and it's either active or
2960 ;; `resize-mini-windows' is nil.
2961 (eq (window-frame minibuffer-window) frame)
880e6158
MR
2962 (= (nth 1 (window-pixel-edges minibuffer-window))
2963 (nth 3 (window-pixel-edges window)))
41cfe0cb
MR
2964 (or (not resize-mini-windows)
2965 (eq minibuffer-window (active-minibuffer-window))))
2966 (window--resize-mini-window minibuffer-window (- delta)))
562dd5e9
MR
2967 ((or (not (setq left right)) (not (setq right (window-right right))))
2968 (if horizontal
2969 (error "No window on the right of this one")
2970 (error "No window below this one")))
2971 (t
2972 ;; Set LEFT to the first resizable window on the left. This step is
2973 ;; needed to handle fixed-size windows.
2974 (while (and left (window-size-fixed-p left horizontal))
2975 (setq left
2976 (or (window-left left)
2977 (progn
2978 (while (and (setq left (window-parent left))
3d8daefe 2979 (not (window-combined-p left horizontal))))
562dd5e9
MR
2980 (window-left left)))))
2981 (unless left
2982 (if horizontal
2983 (error "No resizable window on the left of this one")
2984 (error "No resizable window above this one")))
2985
2986 ;; Set RIGHT to the first resizable window on the right. This step
2987 ;; is needed to handle fixed-size windows.
2988 (while (and right (window-size-fixed-p right horizontal))
2989 (setq right
2990 (or (window-right right)
2991 (progn
2992 (while (and (setq right (window-parent right))
3d8daefe 2993 (not (window-combined-p right horizontal))))
562dd5e9
MR
2994 (window-right right)))))
2995 (unless right
2996 (if horizontal
2997 (error "No resizable window on the right of this one")
2998 (error "No resizable window below this one")))
2999
3000 ;; LEFT and RIGHT (which might be both internal windows) are now the
3001 ;; two windows we want to resize.
3002 (cond
3003 ((> delta 0)
880e6158
MR
3004 (setq max-delta
3005 (window--max-delta-1
3006 left 0 horizontal nil 'after nil pixelwise))
3007 (setq min-delta
3008 (window--min-delta-1
3009 right (- delta) horizontal nil 'before nil pixelwise))
562dd5e9
MR
3010 (when (or (< max-delta delta) (> min-delta (- delta)))
3011 ;; We can't get the whole DELTA - move as far as possible.
3012 (setq delta (min max-delta (- min-delta))))
3013 (unless (zerop delta)
3014 ;; Start resizing.
5386012d 3015 (window--resize-reset frame horizontal)
562dd5e9 3016 ;; Try to enlarge LEFT first.
880e6158 3017 (setq this-delta (window--resizable
8dd3e94f 3018 left delta horizontal nil 'after nil nil pixelwise))
562dd5e9 3019 (unless (zerop this-delta)
5386012d 3020 (window--resize-this-window
562dd5e9
MR
3021 left this-delta horizontal nil t 'before
3022 (if horizontal
880e6158
MR
3023 (+ (window-pixel-left left) (window-pixel-width left))
3024 (+ (window-pixel-top left) (window-pixel-height left)))))
562dd5e9 3025 ;; Shrink windows on right of LEFT.
5386012d 3026 (window--resize-siblings
562dd5e9
MR
3027 left delta horizontal nil 'after
3028 (if horizontal
880e6158
MR
3029 (window-pixel-left right)
3030 (window-pixel-top right)))))
562dd5e9 3031 ((< delta 0)
880e6158
MR
3032 (setq max-delta
3033 (window--max-delta-1
3034 right 0 horizontal nil 'before nil pixelwise))
3035 (setq min-delta
3036 (window--min-delta-1
3037 left delta horizontal nil 'after nil pixelwise))
562dd5e9
MR
3038 (when (or (< max-delta (- delta)) (> min-delta delta))
3039 ;; We can't get the whole DELTA - move as far as possible.
3040 (setq delta (max (- max-delta) min-delta)))
3041 (unless (zerop delta)
3042 ;; Start resizing.
5386012d 3043 (window--resize-reset frame horizontal)
562dd5e9 3044 ;; Try to enlarge RIGHT.
880e6158
MR
3045 (setq this-delta
3046 (window--resizable
8dd3e94f 3047 right (- delta) horizontal nil 'before nil nil pixelwise))
562dd5e9 3048 (unless (zerop this-delta)
5386012d 3049 (window--resize-this-window
562dd5e9
MR
3050 right this-delta horizontal nil t 'after
3051 (if horizontal
880e6158
MR
3052 (window-pixel-left right)
3053 (window-pixel-top right))))
562dd5e9 3054 ;; Shrink windows on left of RIGHT.
5386012d 3055 (window--resize-siblings
562dd5e9
MR
3056 right (- delta) horizontal nil 'before
3057 (if horizontal
880e6158
MR
3058 (+ (window-pixel-left left) (window-pixel-width left))
3059 (+ (window-pixel-top left) (window-pixel-height left)))))))
562dd5e9
MR
3060 (unless (zerop delta)
3061 ;; Don't report an error in the standard case.
880e6158
MR
3062 (when (window--resize-apply-p frame horizontal)
3063 (if (window-resize-apply frame horizontal)
3064 (progn
3065 (window--pixel-to-total frame horizontal)
3066 (run-window-configuration-change-hook frame))
3067 ;; But do report an error if applying the changes fails.
3068 (error "Failed adjusting window %s" window))))))))
562dd5e9
MR
3069
3070(defun enlarge-window (delta &optional horizontal)
2116e93c 3071 "Make the selected window DELTA lines taller.
562dd5e9
MR
3072Interactively, if no argument is given, make the selected window
3073one line taller. If optional argument HORIZONTAL is non-nil,
3074make selected window wider by DELTA columns. If DELTA is
0ff7851c 3075negative, shrink selected window by -DELTA lines or columns."
562dd5e9 3076 (interactive "p")
feeb6f53
MR
3077 (let ((minibuffer-window (minibuffer-window)))
3078 (cond
3079 ((zerop delta))
3080 ((window-size-fixed-p nil horizontal)
3081 (error "Selected window has fixed size"))
3082 ((window-minibuffer-p)
3083 (if horizontal
3084 (error "Cannot resize minibuffer window horizontally")
3085 (window--resize-mini-window (selected-window) delta)))
3086 ((and (not horizontal)
3087 (window-full-height-p)
3088 (eq (window-frame minibuffer-window) (selected-frame))
3089 (not resize-mini-windows))
3090 ;; If the selected window is full height and `resize-mini-windows'
3091 ;; is nil, resize the minibuffer window.
3092 (window--resize-mini-window minibuffer-window (- delta)))
880e6158 3093 ((window--resizable-p nil delta horizontal)
feeb6f53
MR
3094 (window-resize nil delta horizontal))
3095 (t
3096 (window-resize
3097 nil (if (> delta 0)
3098 (window-max-delta nil horizontal)
3099 (- (window-min-delta nil horizontal)))
3100 horizontal)))))
562dd5e9
MR
3101
3102(defun shrink-window (delta &optional horizontal)
2116e93c 3103 "Make the selected window DELTA lines smaller.
562dd5e9
MR
3104Interactively, if no argument is given, make the selected window
3105one line smaller. If optional argument HORIZONTAL is non-nil,
3106make selected window narrower by DELTA columns. If DELTA is
3107negative, enlarge selected window by -DELTA lines or columns.
0ff7851c 3108Also see the `window-min-height' variable."
562dd5e9 3109 (interactive "p")
feeb6f53
MR
3110 (let ((minibuffer-window (minibuffer-window)))
3111 (cond
3112 ((zerop delta))
3113 ((window-size-fixed-p nil horizontal)
3114 (error "Selected window has fixed size"))
3115 ((window-minibuffer-p)
3116 (if horizontal
3117 (error "Cannot resize minibuffer window horizontally")
3118 (window--resize-mini-window (selected-window) (- delta))))
3119 ((and (not horizontal)
3120 (window-full-height-p)
3121 (eq (window-frame minibuffer-window) (selected-frame))
3122 (not resize-mini-windows))
3123 ;; If the selected window is full height and `resize-mini-windows'
3124 ;; is nil, resize the minibuffer window.
3125 (window--resize-mini-window minibuffer-window delta))
880e6158 3126 ((window--resizable-p nil (- delta) horizontal)
feeb6f53
MR
3127 (window-resize nil (- delta) horizontal))
3128 (t
3129 (window-resize
3130 nil (if (> delta 0)
3131 (- (window-min-delta nil horizontal))
3132 (window-max-delta nil horizontal))
3133 horizontal)))))
562dd5e9 3134
2d6b6005 3135(defun maximize-window (&optional window)
562dd5e9
MR
3136 "Maximize WINDOW.
3137Make WINDOW as large as possible without deleting any windows.
880e6158
MR
3138WINDOW must be a valid window and defaults to the selected one.
3139
3140If the option `window-resize-pixelwise' is non-nil maximize
3141WINDOW pixelwise."
562dd5e9 3142 (interactive)
447f16b8 3143 (setq window (window-normalize-window window))
880e6158
MR
3144 (window-resize
3145 window (window-max-delta window nil nil nil nil nil window-resize-pixelwise)
3146 nil nil window-resize-pixelwise)
3147 (window-resize
3148 window (window-max-delta window t nil nil nil nil window-resize-pixelwise)
3149 t nil window-resize-pixelwise))
3150
2d6b6005 3151(defun minimize-window (&optional window)
562dd5e9
MR
3152 "Minimize WINDOW.
3153Make WINDOW as small as possible without deleting any windows.
880e6158
MR
3154WINDOW must be a valid window and defaults to the selected one.
3155
3156If the option `window-resize-pixelwise' is non-nil minimize
3157WINDOW pixelwise."
562dd5e9 3158 (interactive)
447f16b8 3159 (setq window (window-normalize-window window))
880e6158
MR
3160 (window-resize
3161 window
3162 (- (window-min-delta window nil nil nil nil nil window-resize-pixelwise))
3163 nil nil window-resize-pixelwise)
3164 (window-resize
3165 window
3166 (- (window-min-delta window t nil nil nil nil window-resize-pixelwise))
3167 t nil window-resize-pixelwise))
562dd5e9 3168\f
4b0d61e3 3169(defun frame-root-window-p (window)
9aab8e0d
MR
3170 "Return non-nil if WINDOW is the root window of its frame."
3171 (eq window (frame-root-window window)))
6198ccd0 3172
5e92ca23
MR
3173(defun window--subtree (window &optional next)
3174 "Return window subtree rooted at WINDOW.
3175Optional argument NEXT non-nil means include WINDOW's right
6198ccd0
MR
3176siblings in the return value.
3177
3178See the documentation of `window-tree' for a description of the
3179return value."
3180 (let (list)
3181 (while window
3182 (setq list
3183 (cons
3184 (cond
d68443dc 3185 ((window-top-child window)
6198ccd0 3186 (cons t (cons (window-edges window)
5e92ca23 3187 (window--subtree (window-top-child window) t))))
d68443dc 3188 ((window-left-child window)
6198ccd0 3189 (cons nil (cons (window-edges window)
5e92ca23 3190 (window--subtree (window-left-child window) t))))
6198ccd0
MR
3191 (t window))
3192 list))
d68443dc 3193 (setq window (when next (window-next-sibling window))))
6198ccd0
MR
3194 (nreverse list)))
3195
3196(defun window-tree (&optional frame)
3197 "Return the window tree of frame FRAME.
3198FRAME must be a live frame and defaults to the selected frame.
3199The return value is a list of the form (ROOT MINI), where ROOT
3200represents the window tree of the frame's root window, and MINI
3201is the frame's minibuffer window.
3202
3203If the root window is not split, ROOT is the root window itself.
3204Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil
3205for a horizontal split, and t for a vertical split. EDGES gives
be7f5545
MR
3206the combined size and position of the child windows in the split,
3207and the rest of the elements are the child windows in the split.
3208Each of the child windows may again be a window or a list
382c953b 3209representing a window split, and so on. EDGES is a list (LEFT
6198ccd0 3210TOP RIGHT BOTTOM) as returned by `window-edges'."
5386012d 3211 (setq frame (window-normalize-frame frame))
5e92ca23 3212 (window--subtree (frame-root-window frame) t))
9aab8e0d 3213\f
9397e56f
MR
3214(defun other-window (count &optional all-frames)
3215 "Select another window in cyclic ordering of windows.
3216COUNT specifies the number of windows to skip, starting with the
3217selected window, before making the selection. If COUNT is
3218positive, skip COUNT windows forwards. If COUNT is negative,
3219skip -COUNT windows backwards. COUNT zero means do not skip any
3220window, so select the selected window. In an interactive call,
3221COUNT is the numeric prefix argument. Return nil.
3222
9a9e9ef0
MR
3223If the `other-window' parameter of the selected window is a
3224function and `ignore-window-parameters' is nil, call that
3225function with the arguments COUNT and ALL-FRAMES.
9397e56f
MR
3226
3227This function does not select a window whose `no-other-window'
3228window parameter is non-nil.
3229
3230This function uses `next-window' for finding the window to
3231select. The argument ALL-FRAMES has the same meaning as in
3232`next-window', but the MINIBUF argument of `next-window' is
3233always effectively nil."
3234 (interactive "p")
3235 (let* ((window (selected-window))
3236 (function (and (not ignore-window-parameters)
3237 (window-parameter window 'other-window)))
3238 old-window old-count)
3239 (if (functionp function)
3240 (funcall function count all-frames)
3241 ;; `next-window' and `previous-window' may return a window we are
3242 ;; not allowed to select. Hence we need an exit strategy in case
3243 ;; all windows are non-selectable.
3244 (catch 'exit
3245 (while (> count 0)
3246 (setq window (next-window window nil all-frames))
3247 (cond
3248 ((eq window old-window)
3249 (when (= count old-count)
3250 ;; Keep out of infinite loops. When COUNT has not changed
3251 ;; since we last looked at `window' we're probably in one.
3252 (throw 'exit nil)))
3253 ((window-parameter window 'no-other-window)
3254 (unless old-window
3255 ;; The first non-selectable window `next-window' got us:
3256 ;; Remember it and the current value of COUNT.
3257 (setq old-window window)
3258 (setq old-count count)))
3259 (t
3260 (setq count (1- count)))))
3261 (while (< count 0)
3262 (setq window (previous-window window nil all-frames))
3263 (cond
3264 ((eq window old-window)
3265 (when (= count old-count)
3266 ;; Keep out of infinite loops. When COUNT has not changed
3267 ;; since we last looked at `window' we're probably in one.
3268 (throw 'exit nil)))
3269 ((window-parameter window 'no-other-window)
3270 (unless old-window
3271 ;; The first non-selectable window `previous-window' got
3272 ;; us: Remember it and the current value of COUNT.
3273 (setq old-window window)
3274 (setq old-count count)))
3275 (t
3276 (setq count (1+ count)))))
3277
3278 (select-window window)
3279 ;; Always return nil.
3280 nil))))
3281
387522b2
MR
3282;; This should probably return non-nil when the selected window is part
3283;; of an atomic window whose root is the frame's root window.
3284(defun one-window-p (&optional nomini all-frames)
3285 "Return non-nil if the selected window is the only window.
3286Optional arg NOMINI non-nil means don't count the minibuffer
3287even if it is active. Otherwise, the minibuffer is counted
3288when it is active.
3289
3290Optional argument ALL-FRAMES specifies the set of frames to
3291consider, see also `next-window'. ALL-FRAMES nil or omitted
3292means consider windows on the selected frame only, plus the
3293minibuffer window if specified by the NOMINI argument. If the
3294minibuffer counts, consider all windows on all frames that share
3295that minibuffer too. The remaining non-nil values of ALL-FRAMES
3296with a special meaning are:
3297
3298- t means consider all windows on all existing frames.
3299
3300- `visible' means consider all windows on all visible frames on
3301 the current terminal.
3302
3303- 0 (the number zero) means consider all windows on all visible
3304 and iconified frames on the current terminal.
3305
3306- A frame means consider all windows on that frame only.
3307
3308Anything else means consider all windows on the selected frame
3309and no others."
3310 (let ((base-window (selected-window)))
3311 (if (and nomini (eq base-window (minibuffer-window)))
3312 (setq base-window (next-window base-window)))
3313 (eq base-window
3314 (next-window base-window (if nomini 'arg) all-frames))))
3c448ab6 3315\f
9aab8e0d 3316;;; Deleting windows.
1b36ed6a 3317(defun window-deletable-p (&optional window)
9aab8e0d 3318 "Return t if WINDOW can be safely deleted from its frame.
85c2386b 3319WINDOW must be a valid window and defaults to the selected one.
c660a885 3320Return 'frame if deleting WINDOW should also delete its frame."
447f16b8 3321 (setq window (window-normalize-window window))
8b0874b5 3322
c660a885 3323 (unless (or ignore-window-parameters
f224e500 3324 (eq (window-parameter window 'delete-window) t))
9aab8e0d
MR
3325 ;; Handle atomicity.
3326 (when (window-parameter window 'window-atom)
3327 (setq window (window-atom-root window))))
8b0874b5 3328
caceae25 3329 (let ((frame (window-frame window)))
9aab8e0d
MR
3330 (cond
3331 ((frame-root-window-p window)
85e9c04b 3332 ;; WINDOW's frame can be deleted only if there are other frames
46b7967e
TN
3333 ;; on the same terminal, and it does not contain the active
3334 ;; minibuffer.
3335 (unless (or (eq frame (next-frame frame 0))
c660a885
MR
3336 ;; We can delete our frame only if no other frame
3337 ;; currently uses our minibuffer window.
3338 (catch 'other
3339 (dolist (other (frame-list))
3340 (when (and (not (eq other frame))
3341 (eq (window-frame (minibuffer-window other))
3342 frame))
3343 (throw 'other t))))
46b7967e
TN
3344 (let ((minibuf (active-minibuffer-window)))
3345 (and minibuf (eq frame (window-frame minibuf)))))
85e9c04b 3346 'frame))
1b36ed6a 3347 ((or ignore-window-parameters
caceae25
MR
3348 (not (eq window (window--major-non-side-window frame))))
3349 ;; WINDOW can be deleted unless it is the major non-side window of
3350 ;; its frame.
1f3c99ca 3351 t))))
9aab8e0d 3352
be7f5545
MR
3353(defun window--in-subtree-p (window root)
3354 "Return t if WINDOW is either ROOT or a member of ROOT's subtree."
3355 (or (eq window root)
3356 (let ((parent (window-parent window)))
9aab8e0d
MR
3357 (catch 'done
3358 (while parent
be7f5545 3359 (if (eq parent root)
9aab8e0d
MR
3360 (throw 'done t)
3361 (setq parent (window-parent parent))))))))
3362
562dd5e9
MR
3363(defun delete-window (&optional window)
3364 "Delete WINDOW.
85c2386b
MR
3365WINDOW must be a valid window and defaults to the selected one.
3366Return nil.
562dd5e9
MR
3367
3368If the variable `ignore-window-parameters' is non-nil or the
3369`delete-window' parameter of WINDOW equals t, do not process any
3370parameters of WINDOW. Otherwise, if the `delete-window'
3371parameter of WINDOW specifies a function, call that function with
3372WINDOW as its sole argument and return the value returned by that
3373function.
3374
3375Otherwise, if WINDOW is part of an atomic window, call
3376`delete-window' with the root of the atomic window as its
85c2386b
MR
3377argument. Signal an error if WINDOW is either the only window on
3378its frame, the last non-side window, or part of an atomic window
3379that is its frame's root window."
562dd5e9 3380 (interactive)
447f16b8 3381 (setq window (window-normalize-window window))
562dd5e9
MR
3382 (let* ((frame (window-frame window))
3383 (function (window-parameter window 'delete-window))
3384 (parent (window-parent window))
3385 atom-root)
54f9154c 3386 (window--check frame)
562dd5e9
MR
3387 (catch 'done
3388 ;; Handle window parameters.
3389 (cond
3390 ;; Ignore window parameters if `ignore-window-parameters' tells
3391 ;; us so or `delete-window' equals t.
3392 ((or ignore-window-parameters (eq function t)))
3393 ((functionp function)
3394 ;; The `delete-window' parameter specifies the function to call.
3395 ;; If that function is `ignore' nothing is done. It's up to the
3396 ;; function called here to avoid infinite recursion.
3397 (throw 'done (funcall function window)))
3398 ((and (window-parameter window 'window-atom)
3399 (setq atom-root (window-atom-root window))
3400 (not (eq atom-root window)))
caceae25
MR
3401 (if (eq atom-root (frame-root-window frame))
3402 (error "Root of atomic window is root window of its frame")
3403 (throw 'done (delete-window atom-root))))
562dd5e9 3404 ((not parent)
caceae25
MR
3405 (error "Attempt to delete minibuffer or sole ordinary window"))
3406 ((eq window (window--major-non-side-window frame))
3407 (error "Attempt to delete last non-side window")))
562dd5e9 3408
d68443dc 3409 (let* ((horizontal (window-left-child parent))
880e6158 3410 (size (window-size window horizontal t))
562dd5e9 3411 (frame-selected
be7f5545 3412 (window--in-subtree-p (frame-selected-window frame) window))
562dd5e9
MR
3413 ;; Emacs 23 preferably gives WINDOW's space to its left
3414 ;; sibling.
3415 (sibling (or (window-left window) (window-right window))))
5386012d 3416 (window--resize-reset frame horizontal)
562dd5e9 3417 (cond
a0c2d0ae 3418 ((and (not window-combination-resize)
880e6158 3419 sibling (window-sizable-p sibling size horizontal nil t))
562dd5e9 3420 ;; Resize WINDOW's sibling.
5386012d 3421 (window--resize-this-window sibling size horizontal nil t)
562dd5e9
MR
3422 (set-window-new-normal
3423 sibling (+ (window-normal-size sibling horizontal)
3424 (window-normal-size window horizontal))))
880e6158 3425 ((window--resizable-p window (- size) horizontal nil nil nil t t)
562dd5e9 3426 ;; Can do without resizing fixed-size windows.
5386012d 3427 (window--resize-siblings window (- size) horizontal))
562dd5e9
MR
3428 (t
3429 ;; Can't do without resizing fixed-size windows.
5386012d 3430 (window--resize-siblings window (- size) horizontal t)))
562dd5e9
MR
3431 ;; Actually delete WINDOW.
3432 (delete-window-internal window)
880e6158 3433 (window--pixel-to-total frame horizontal)
562dd5e9
MR
3434 (when (and frame-selected
3435 (window-parameter
3436 (frame-selected-window frame) 'no-other-window))
3437 ;; `delete-window-internal' has selected a window that should
3438 ;; not be selected, fix this here.
3439 (other-window -1 frame))
3440 (run-window-configuration-change-hook frame)
54f9154c 3441 (window--check frame)
562dd5e9
MR
3442 ;; Always return nil.
3443 nil))))
3444
3445(defun delete-other-windows (&optional window)
3446 "Make WINDOW fill its frame.
85c2386b 3447WINDOW must be a valid window and defaults to the selected one.
562dd5e9
MR
3448Return nil.
3449
3450If the variable `ignore-window-parameters' is non-nil or the
3451`delete-other-windows' parameter of WINDOW equals t, do not
3452process any parameters of WINDOW. Otherwise, if the
3453`delete-other-windows' parameter of WINDOW specifies a function,
3454call that function with WINDOW as its sole argument and return
3455the value returned by that function.
3456
3457Otherwise, if WINDOW is part of an atomic window, call this
3458function with the root of the atomic window as its argument. If
3459WINDOW is a non-side window, make WINDOW the only non-side window
382c953b 3460on the frame. Side windows are not deleted. If WINDOW is a side
562dd5e9
MR
3461window signal an error."
3462 (interactive)
447f16b8 3463 (setq window (window-normalize-window window))
562dd5e9
MR
3464 (let* ((frame (window-frame window))
3465 (function (window-parameter window 'delete-other-windows))
3466 (window-side (window-parameter window 'window-side))
3467 atom-root side-main)
54f9154c 3468 (window--check frame)
562dd5e9
MR
3469 (catch 'done
3470 (cond
3471 ;; Ignore window parameters if `ignore-window-parameters' is t or
3472 ;; `delete-other-windows' is t.
3473 ((or ignore-window-parameters (eq function t)))
3474 ((functionp function)
3475 ;; The `delete-other-windows' parameter specifies the function
3476 ;; to call. If the function is `ignore' no windows are deleted.
3477 ;; It's up to the function called to avoid infinite recursion.
3478 (throw 'done (funcall function window)))
3479 ((and (window-parameter window 'window-atom)
3480 (setq atom-root (window-atom-root window))
3481 (not (eq atom-root window)))
caceae25
MR
3482 (if (eq atom-root (frame-root-window frame))
3483 (error "Root of atomic window is root window of its frame")
3484 (throw 'done (delete-other-windows atom-root))))
562dd5e9 3485 ((memq window-side window-sides)
caceae25
MR
3486 (error "Cannot make side window the only window"))
3487 ((and (window-minibuffer-p window)
3488 (not (eq window (frame-root-window window))))
3489 (error "Can't expand minibuffer to full frame")))
3490
3491 ;; If WINDOW is the major non-side window, do nothing.
3492 (if (window-with-parameter 'window-side)
3493 (setq side-main (window--major-non-side-window frame))
3494 (setq side-main (frame-root-window frame)))
562dd5e9
MR
3495 (unless (eq window side-main)
3496 (delete-other-windows-internal window side-main)
3497 (run-window-configuration-change-hook frame)
54f9154c 3498 (window--check frame))
562dd5e9
MR
3499 ;; Always return nil.
3500 nil)))
9397e56f
MR
3501
3502(defun delete-other-windows-vertically (&optional window)
3503 "Delete the windows in the same column with WINDOW, but not WINDOW itself.
3504This may be a useful alternative binding for \\[delete-other-windows]
3505 if you often split windows horizontally."
3506 (interactive)
3507 (let* ((window (or window (selected-window)))
3508 (edges (window-edges window))
3509 (w window) delenda)
3510 (while (not (eq (setq w (next-window w 1)) window))
3511 (let ((e (window-edges w)))
3512 (when (and (= (car e) (car edges))
36cec983 3513 (= (nth 2 e) (nth 2 edges)))
9397e56f
MR
3514 (push w delenda))))
3515 (mapc 'delete-window delenda)))
3516
3517;;; Windows and buffers.
3518
3519;; `prev-buffers' and `next-buffers' are two reserved window slots used
3520;; for (1) determining which buffer to show in the window when its
3521;; buffer shall be buried or killed and (2) which buffer to show for
3522;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
3523
3524;; `prev-buffers' consists of <buffer, window-start, window-point>
3525;; triples. The entries on this list are ordered by the time their
3526;; buffer has been removed from the window, the most recently removed
3527;; buffer's entry being first. The window-start and window-point
3528;; components are `window-start' and `window-point' at the time the
3529;; buffer was removed from the window which implies that the entry must
3530;; be added when `set-window-buffer' removes the buffer from the window.
3531
3532;; `next-buffers' is the list of buffers that have been replaced
3533;; recently by `switch-to-prev-buffer'. These buffers are the least
3534;; preferred candidates of `switch-to-prev-buffer' and the preferred
3535;; candidates of `switch-to-next-buffer' to switch to. This list is
3536;; reset to nil by any action changing the window's buffer with the
3537;; exception of `switch-to-prev-buffer' and `switch-to-next-buffer'.
3538;; `switch-to-prev-buffer' pushes the buffer it just replaced on it,
3539;; `switch-to-next-buffer' pops the last pushed buffer from it.
3540
3541;; Both `prev-buffers' and `next-buffers' may reference killed buffers
3542;; if such a buffer was killed while the window was hidden within a
3543;; window configuration. Such killed buffers get removed whenever
3544;; `switch-to-prev-buffer' or `switch-to-next-buffer' encounter them.
3545
3546;; The following function is called by `set-window-buffer' _before_ it
3547;; replaces the buffer of the argument window with the new buffer.
3548(defun record-window-buffer (&optional window)
3549 "Record WINDOW's buffer.
3550WINDOW must be a live window and defaults to the selected one."
447f16b8 3551 (let* ((window (window-normalize-window window t))
9397e56f
MR
3552 (buffer (window-buffer window))
3553 (entry (assq buffer (window-prev-buffers window))))
3554 ;; Reset WINDOW's next buffers. If needed, they are resurrected by
3555 ;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
3556 (set-window-next-buffers window nil)
3557
3558 (when entry
3559 ;; Remove all entries for BUFFER from WINDOW's previous buffers.
3560 (set-window-prev-buffers
3561 window (assq-delete-all buffer (window-prev-buffers window))))
3562
3563 ;; Don't record insignificant buffers.
3564 (unless (eq (aref (buffer-name buffer) 0) ?\s)
3565 ;; Add an entry for buffer to WINDOW's previous buffers.
3566 (with-current-buffer buffer
3567 (let ((start (window-start window))
5481664a 3568 (point (window-point window)))
9397e56f
MR
3569 (setq entry
3570 (cons buffer
3571 (if entry
3572 ;; We have an entry, update marker positions.
3573 (list (set-marker (nth 1 entry) start)
3574 (set-marker (nth 2 entry) point))
3575 ;; Make new markers.
3576 (list (copy-marker start)
92346275
MR
3577 (copy-marker
3578 ;; Preserve window-point-insertion-type
3579 ;; (Bug#12588).
3580 point window-point-insertion-type)))))
9397e56f 3581 (set-window-prev-buffers
c660a885
MR
3582 window (cons entry (window-prev-buffers window)))))
3583
3584 (run-hooks 'buffer-list-update-hook))))
9397e56f
MR
3585
3586(defun unrecord-window-buffer (&optional window buffer)
3587 "Unrecord BUFFER in WINDOW.
3588WINDOW must be a live window and defaults to the selected one.
3589BUFFER must be a live buffer and defaults to the buffer of
3590WINDOW."
447f16b8 3591 (let* ((window (window-normalize-window window t))
9397e56f
MR
3592 (buffer (or buffer (window-buffer window))))
3593 (set-window-prev-buffers
3594 window (assq-delete-all buffer (window-prev-buffers window)))
3595 (set-window-next-buffers
3596 window (delq buffer (window-next-buffers window)))))
3597
3598(defun set-window-buffer-start-and-point (window buffer &optional start point)
3599 "Set WINDOW's buffer to BUFFER.
85c2386b 3600WINDOW must be a live window and defaults to the selected one.
9397e56f
MR
3601Optional argument START non-nil means set WINDOW's start position
3602to START. Optional argument POINT non-nil means set WINDOW's
3603point to POINT. If WINDOW is selected this also sets BUFFER's
3604`point' to POINT. If WINDOW is selected and the buffer it showed
3605before was current this also makes BUFFER the current buffer."
85c2386b 3606 (setq window (window-normalize-window window t))
9397e56f
MR
3607 (let ((selected (eq window (selected-window)))
3608 (current (eq (window-buffer window) (current-buffer))))
3609 (set-window-buffer window buffer)
3610 (when (and selected current)
3611 (set-buffer buffer))
3612 (when start
cf4eacfd
MR
3613 ;; Don't force window-start here (even if POINT is nil).
3614 (set-window-start window start t))
9397e56f 3615 (when point
5481664a 3616 (set-window-point window point))))
9397e56f 3617
dcb6e7b3
MR
3618(defcustom switch-to-visible-buffer t
3619 "If non-nil, allow switching to an already visible buffer.
3620If this variable is non-nil, `switch-to-prev-buffer' and
3621`switch-to-next-buffer' may switch to an already visible buffer
43bcfda6
MR
3622provided the buffer was shown before in the window specified as
3623argument to those functions. If this variable is nil,
3624`switch-to-prev-buffer' and `switch-to-next-buffer' always try to
3625avoid switching to a buffer that is already visible in another
3626window on the same frame."
dcb6e7b3
MR
3627 :type 'boolean
3628 :version "24.1"
3629 :group 'windows)
3630
9397e56f
MR
3631(defun switch-to-prev-buffer (&optional window bury-or-kill)
3632 "In WINDOW switch to previous buffer.
3633WINDOW must be a live window and defaults to the selected one.
502e3f89
MR
3634Return the buffer switched to, nil if no suitable buffer could be
3635found.
9397e56f
MR
3636
3637Optional argument BURY-OR-KILL non-nil means the buffer currently
3638shown in WINDOW is about to be buried or killed and consequently
78dd6ab1
MR
3639shall not be switched to in future invocations of this command.
3640
3641As a special case, if BURY-OR-KILL equals `append', this means to
3642move the buffer to the end of WINDOW's previous buffers list so a
3643future invocation of `switch-to-prev-buffer' less likely switches
3644to it."
9397e56f 3645 (interactive)
447f16b8 3646 (let* ((window (window-normalize-window window t))
dcb6e7b3 3647 (frame (window-frame window))
9397e56f
MR
3648 (old-buffer (window-buffer window))
3649 ;; Save this since it's destroyed by `set-window-buffer'.
3650 (next-buffers (window-next-buffers window))
862382df 3651 (pred (frame-parameter frame 'buffer-predicate))
78dd6ab1
MR
3652 entry new-buffer killed-buffers visible)
3653 (when (window-minibuffer-p window)
3654 ;; Don't switch in minibuffer window.
3655 (unless (setq window (minibuffer-selected-window))
3656 (error "Window %s is a minibuffer window" window)))
3657
1b36ed6a 3658 (when (window-dedicated-p window)
78dd6ab1 3659 ;; Don't switch in dedicated window.
1b36ed6a
MR
3660 (error "Window %s is dedicated to buffer %s" window old-buffer))
3661
3662 (catch 'found
3663 ;; Scan WINDOW's previous buffers first, skipping entries of next
3664 ;; buffers.
3665 (dolist (entry (window-prev-buffers window))
78dd6ab1
MR
3666 (when (and (setq new-buffer (car entry))
3667 (or (buffer-live-p new-buffer)
1b36ed6a 3668 (not (setq killed-buffers
78dd6ab1
MR
3669 (cons new-buffer killed-buffers))))
3670 (not (eq new-buffer old-buffer))
3671 (or (null pred) (funcall pred new-buffer))
3672 ;; When BURY-OR-KILL is nil, avoid switching to a
3673 ;; buffer in WINDOW's next buffers list.
3674 (or bury-or-kill (not (memq new-buffer next-buffers))))
dcb6e7b3 3675 (if (and (not switch-to-visible-buffer)
78dd6ab1
MR
3676 (get-buffer-window new-buffer frame))
3677 ;; Try to avoid showing a buffer visible in some other
3678 ;; window.
3679 (setq visible new-buffer)
502e3f89
MR
3680 (set-window-buffer-start-and-point
3681 window new-buffer (nth 1 entry) (nth 2 entry))
3682 (throw 'found t))))
1b36ed6a
MR
3683 ;; Scan reverted buffer list of WINDOW's frame next, skipping
3684 ;; entries of next buffers. Note that when we bury or kill a
3685 ;; buffer we don't reverse the global buffer list to avoid showing
3686 ;; a buried buffer instead. Otherwise, we must reverse the global
3687 ;; buffer list in order to make sure that switching to the
3688 ;; previous/next buffer traverse it in opposite directions.
3689 (dolist (buffer (if bury-or-kill
dcb6e7b3
MR
3690 (buffer-list frame)
3691 (nreverse (buffer-list frame))))
1b36ed6a
MR
3692 (when (and (buffer-live-p buffer)
3693 (not (eq buffer old-buffer))
862382df 3694 (or (null pred) (funcall pred buffer))
78dd6ab1 3695 (not (eq (aref (buffer-name buffer) 0) ?\s))
1b36ed6a 3696 (or bury-or-kill (not (memq buffer next-buffers))))
dcb6e7b3 3697 (if (get-buffer-window buffer frame)
1b36ed6a 3698 ;; Try to avoid showing a buffer visible in some other window.
dcb6e7b3
MR
3699 (unless visible
3700 (setq visible buffer))
1b36ed6a
MR
3701 (setq new-buffer buffer)
3702 (set-window-buffer-start-and-point window new-buffer)
3703 (throw 'found t))))
3704 (unless bury-or-kill
3705 ;; Scan reverted next buffers last (must not use nreverse
3706 ;; here!).
3707 (dolist (buffer (reverse next-buffers))
3708 ;; Actually, buffer _must_ be live here since otherwise it
3709 ;; would have been caught in the scan of previous buffers.
3710 (when (and (or (buffer-live-p buffer)
9397e56f 3711 (not (setq killed-buffers
1b36ed6a 3712 (cons buffer killed-buffers))))
9397e56f 3713 (not (eq buffer old-buffer))
862382df 3714 (or (null pred) (funcall pred buffer))
1b36ed6a 3715 (setq entry (assq buffer (window-prev-buffers window))))
9397e56f 3716 (setq new-buffer buffer)
1b36ed6a
MR
3717 (set-window-buffer-start-and-point
3718 window new-buffer (nth 1 entry) (nth 2 entry))
9397e56f 3719 (throw 'found t))))
1b36ed6a
MR
3720
3721 ;; Show a buffer visible in another window.
3722 (when visible
3723 (setq new-buffer visible)
3724 (set-window-buffer-start-and-point window new-buffer)))
3725
3726 (if bury-or-kill
78dd6ab1
MR
3727 (let ((entry (and (eq bury-or-kill 'append)
3728 (assq old-buffer (window-prev-buffers window)))))
3729 ;; Remove `old-buffer' from WINDOW's previous and (restored list
3730 ;; of) next buffers.
1b36ed6a
MR
3731 (set-window-prev-buffers
3732 window (assq-delete-all old-buffer (window-prev-buffers window)))
78dd6ab1
MR
3733 (set-window-next-buffers window (delq old-buffer next-buffers))
3734 (when entry
3735 ;; Append old-buffer's entry to list of WINDOW's previous
3736 ;; buffers so it's less likely to get switched to soon but
3737 ;; `display-buffer-in-previous-window' can nevertheless find
3738 ;; it.
3739 (set-window-prev-buffers
3740 window (append (window-prev-buffers window) (list entry)))))
1b36ed6a
MR
3741 ;; Move `old-buffer' to head of WINDOW's restored list of next
3742 ;; buffers.
3743 (set-window-next-buffers
3744 window (cons old-buffer (delq old-buffer next-buffers))))
9397e56f
MR
3745
3746 ;; Remove killed buffers from WINDOW's previous and next buffers.
3747 (when killed-buffers
3748 (dolist (buffer killed-buffers)
3749 (set-window-prev-buffers
3750 window (assq-delete-all buffer (window-prev-buffers window)))
3751 (set-window-next-buffers
3752 window (delq buffer (window-next-buffers window)))))
3753
3754 ;; Return new-buffer.
3755 new-buffer))
3756
3757(defun switch-to-next-buffer (&optional window)
3758 "In WINDOW switch to next buffer.
502e3f89
MR
3759WINDOW must be a live window and defaults to the selected one.
3760Return the buffer switched to, nil if no suitable buffer could be
3761found."
9397e56f 3762 (interactive)
447f16b8 3763 (let* ((window (window-normalize-window window t))
dcb6e7b3 3764 (frame (window-frame window))
9397e56f
MR
3765 (old-buffer (window-buffer window))
3766 (next-buffers (window-next-buffers window))
862382df 3767 (pred (frame-parameter frame 'buffer-predicate))
78dd6ab1
MR
3768 new-buffer entry killed-buffers visible)
3769 (when (window-minibuffer-p window)
3770 ;; Don't switch in minibuffer window.
3771 (unless (setq window (minibuffer-selected-window))
3772 (error "Window %s is a minibuffer window" window)))
3773
9397e56f 3774 (when (window-dedicated-p window)
78dd6ab1 3775 ;; Don't switch in dedicated window.
9397e56f
MR
3776 (error "Window %s is dedicated to buffer %s" window old-buffer))
3777
3778 (catch 'found
3779 ;; Scan WINDOW's next buffers first.
3780 (dolist (buffer next-buffers)
3781 (when (and (or (buffer-live-p buffer)
3782 (not (setq killed-buffers
3783 (cons buffer killed-buffers))))
3784 (not (eq buffer old-buffer))
862382df 3785 (or (null pred) (funcall pred buffer))
9397e56f
MR
3786 (setq entry (assq buffer (window-prev-buffers window))))
3787 (setq new-buffer buffer)
3788 (set-window-buffer-start-and-point
3789 window new-buffer (nth 1 entry) (nth 2 entry))
3790 (throw 'found t)))
3791 ;; Scan the buffer list of WINDOW's frame next, skipping previous
3792 ;; buffers entries.
dcb6e7b3 3793 (dolist (buffer (buffer-list frame))
78dd6ab1
MR
3794 (when (and (buffer-live-p buffer)
3795 (not (eq buffer old-buffer))
862382df 3796 (or (null pred) (funcall pred buffer))
78dd6ab1 3797 (not (eq (aref (buffer-name buffer) 0) ?\s))
9397e56f 3798 (not (assq buffer (window-prev-buffers window))))
dcb6e7b3 3799 (if (get-buffer-window buffer frame)
9397e56f
MR
3800 ;; Try to avoid showing a buffer visible in some other window.
3801 (setq visible buffer)
3802 (setq new-buffer buffer)
3803 (set-window-buffer-start-and-point window new-buffer)
3804 (throw 'found t))))
3805 ;; Scan WINDOW's reverted previous buffers last (must not use
3806 ;; nreverse here!)
3807 (dolist (entry (reverse (window-prev-buffers window)))
78dd6ab1
MR
3808 (when (and (setq new-buffer (car entry))
3809 (or (buffer-live-p new-buffer)
9397e56f 3810 (not (setq killed-buffers
78dd6ab1
MR
3811 (cons new-buffer killed-buffers))))
3812 (not (eq new-buffer old-buffer))
3813 (or (null pred) (funcall pred new-buffer)))
dcb6e7b3 3814 (if (and (not switch-to-visible-buffer)
78dd6ab1 3815 (get-buffer-window new-buffer frame))
dcb6e7b3
MR
3816 ;; Try to avoid showing a buffer visible in some other window.
3817 (unless visible
78dd6ab1 3818 (setq visible new-buffer))
dcb6e7b3
MR
3819 (set-window-buffer-start-and-point
3820 window new-buffer (nth 1 entry) (nth 2 entry))
3821 (throw 'found t))))
9397e56f
MR
3822
3823 ;; Show a buffer visible in another window.
3824 (when visible
3825 (setq new-buffer visible)
3826 (set-window-buffer-start-and-point window new-buffer)))
3827
3828 ;; Remove `new-buffer' from and restore WINDOW's next buffers.
3829 (set-window-next-buffers window (delq new-buffer next-buffers))
3830
3831 ;; Remove killed buffers from WINDOW's previous and next buffers.
3832 (when killed-buffers
3833 (dolist (buffer killed-buffers)
3834 (set-window-prev-buffers
3835 window (assq-delete-all buffer (window-prev-buffers window)))
3836 (set-window-next-buffers
3837 window (delq buffer (window-next-buffers window)))))
3838
3839 ;; Return new-buffer.
3840 new-buffer))
3841
3842(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
3843 "Search LIST for a valid buffer to display in FRAME.
3844Return nil when all buffers in LIST are undesirable for display,
3845otherwise return the first suitable buffer in LIST.
3846
3847Buffers not visible in windows are preferred to visible buffers,
3848unless VISIBLE-OK is non-nil.
3849If the optional argument FRAME is nil, it defaults to the selected frame.
3850If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
3851 ;; This logic is more or less copied from other-buffer.
3852 (setq frame (or frame (selected-frame)))
3853 (let ((pred (frame-parameter frame 'buffer-predicate))
3854 found buf)
3855 (while (and (not found) list)
3856 (setq buf (car list))
3857 (if (and (not (eq buffer buf))
3858 (buffer-live-p buf)
3859 (or (null pred) (funcall pred buf))
3860 (not (eq (aref (buffer-name buf) 0) ?\s))
3861 (or visible-ok (null (get-buffer-window buf 'visible))))
3862 (setq found buf)
3863 (setq list (cdr list))))
3864 (car list)))
3865
3866(defun last-buffer (&optional buffer visible-ok frame)
3867 "Return the last buffer in FRAME's buffer list.
3868If BUFFER is the last buffer, return the preceding buffer
3869instead. Buffers not visible in windows are preferred to visible
3870buffers, unless optional argument VISIBLE-OK is non-nil.
3871Optional third argument FRAME nil or omitted means use the
3872selected frame's buffer list. If no such buffer exists, return
3873the buffer `*scratch*', creating it if necessary."
3874 (setq frame (or frame (selected-frame)))
3875 (or (get-next-valid-buffer (nreverse (buffer-list frame))
3876 buffer visible-ok frame)
3877 (get-buffer "*scratch*")
3878 (let ((scratch (get-buffer-create "*scratch*")))
3879 (set-buffer-major-mode scratch)
3880 scratch)))
3881
5a4cf282
MR
3882(defcustom frame-auto-hide-function #'iconify-frame
3883 "Function called to automatically hide frames.
3884The function is called with one argument - a frame.
3885
3886Functions affected by this option are those that bury a buffer
3887shown in a separate frame like `quit-window' and `bury-buffer'."
3888 :type '(choice (const :tag "Iconify" iconify-frame)
3889 (const :tag "Delete" delete-frame)
3890 (const :tag "Do nothing" ignore)
3891 function)
3892 :group 'windows
49677495
MR
3893 :group 'frames
3894 :version "24.1")
0e2070b5
MR
3895
3896(defun window--delete (&optional window dedicated-only kill)
3897 "Delete WINDOW if possible.
3898WINDOW must be a live window and defaults to the selected one.
3899Optional argument DEDICATED-ONLY non-nil means to delete WINDOW
3900only if it's dedicated to its buffer. Optional argument KILL
3901means the buffer shown in window will be killed. Return non-nil
c557cd6b 3902if WINDOW gets deleted or its frame is auto-hidden."
447f16b8 3903 (setq window (window-normalize-window window t))
0e2070b5 3904 (unless (and dedicated-only (not (window-dedicated-p window)))
cb882333 3905 (let ((deletable (window-deletable-p window)))
0e2070b5
MR
3906 (cond
3907 ((eq deletable 'frame)
3908 (let ((frame (window-frame window)))
c557cd6b
MR
3909 (cond
3910 (kill
3911 (delete-frame frame))
3912 ((functionp frame-auto-hide-function)
3913 (funcall frame-auto-hide-function frame))))
0e2070b5
MR
3914 'frame)
3915 (deletable
3916 (delete-window window)
3917 t)))))
3918
9397e56f
MR
3919(defun bury-buffer (&optional buffer-or-name)
3920 "Put BUFFER-OR-NAME at the end of the list of all buffers.
3921There it is the least likely candidate for `other-buffer' to
3922return; thus, the least likely buffer for \\[switch-to-buffer] to
3923select by default.
3924
3925You can specify a buffer name as BUFFER-OR-NAME, or an actual
3926buffer object. If BUFFER-OR-NAME is nil or omitted, bury the
3927current buffer. Also, if BUFFER-OR-NAME is nil or omitted,
3928remove the current buffer from the selected window if it is
3929displayed there."
3930 (interactive)
5386012d 3931 (let* ((buffer (window-normalize-buffer buffer-or-name)))
9397e56f
MR
3932 ;; If `buffer-or-name' is not on the selected frame we unrecord it
3933 ;; although it's not "here" (call it a feature).
e4ed06f1 3934 (bury-buffer-internal buffer)
9397e56f
MR
3935 ;; Handle case where `buffer-or-name' is nil and the current buffer
3936 ;; is shown in the selected window.
3937 (cond
3938 ((or buffer-or-name (not (eq buffer (window-buffer)))))
0e2070b5
MR
3939 ((window--delete nil t))
3940 (t
3941 ;; Switch to another buffer in window.
3942 (set-window-dedicated-p nil nil)
1885e5b8 3943 (switch-to-prev-buffer nil 'bury)))
1b36ed6a 3944
9397e56f
MR
3945 ;; Always return nil.
3946 nil))
3947
3948(defun unbury-buffer ()
3949 "Switch to the last buffer in the buffer list."
3950 (interactive)
3951 (switch-to-buffer (last-buffer)))
3952
3953(defun next-buffer ()
3954 "In selected window switch to next buffer."
3955 (interactive)
85c2386b
MR
3956 (cond
3957 ((window-minibuffer-p)
3958 (error "Cannot switch buffers in minibuffer window"))
3959 ((eq (window-dedicated-p) t)
3960 (error "Window is strongly dedicated to its buffer"))
3961 (t
3962 (switch-to-next-buffer))))
9397e56f
MR
3963
3964(defun previous-buffer ()
3965 "In selected window switch to previous buffer."
3966 (interactive)
85c2386b
MR
3967 (cond
3968 ((window-minibuffer-p)
3969 (error "Cannot switch buffers in minibuffer window"))
3970 ((eq (window-dedicated-p) t)
3971 (error "Window is strongly dedicated to its buffer"))
3972 (t
3973 (switch-to-prev-buffer))))
9397e56f
MR
3974
3975(defun delete-windows-on (&optional buffer-or-name frame)
3976 "Delete all windows showing BUFFER-OR-NAME.
3977BUFFER-OR-NAME may be a buffer or the name of an existing buffer
3978and defaults to the current buffer.
3979
3980The following non-nil values of the optional argument FRAME
3981have special meanings:
3982
3983- t means consider all windows on the selected frame only.
3984
3985- `visible' means consider all windows on all visible frames on
3986 the current terminal.
3987
3988- 0 (the number zero) means consider all windows on all visible
3989 and iconified frames on the current terminal.
3990
3991- A frame means consider all windows on that frame only.
3992
3993Any other value of FRAME means consider all windows on all
3994frames.
3995
3996When a window showing BUFFER-OR-NAME is dedicated and the only
3997window of its frame, that frame is deleted when there are other
3998frames left."
3999 (interactive "BDelete windows on (buffer):\nP")
5386012d 4000 (let ((buffer (window-normalize-buffer buffer-or-name))
9397e56f
MR
4001 ;; Handle the "inverted" meaning of the FRAME argument wrt other
4002 ;; `window-list-1' based function.
4003 (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
4004 (dolist (window (window-list-1 nil nil all-frames))
4005 (if (eq (window-buffer window) buffer)
1b36ed6a 4006 (let ((deletable (window-deletable-p window)))
9397e56f 4007 (cond
1b36ed6a
MR
4008 ((and (eq deletable 'frame) (window-dedicated-p window))
4009 ;; Delete frame if and only if window is dedicated.
9397e56f 4010 (delete-frame (window-frame window)))
1b36ed6a
MR
4011 ((eq deletable t)
4012 ;; Delete window.
9397e56f
MR
4013 (delete-window window))
4014 (t
4015 ;; In window switch to previous buffer.
4016 (set-window-dedicated-p window nil)
4017 (switch-to-prev-buffer window 'bury))))
4018 ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
4019 (unrecord-window-buffer window buffer)))))
4020
4021(defun replace-buffer-in-windows (&optional buffer-or-name)
4022 "Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
4023BUFFER-OR-NAME may be a buffer or the name of an existing buffer
4024and defaults to the current buffer.
4025
0e2070b5
MR
4026When a window showing BUFFER-OR-NAME is dedicated, that window is
4027deleted. If that window is the only window on its frame, the
4028frame is deleted too when there are other frames left. If there
4029are no other frames left, some other buffer is displayed in that
4030window.
9397e56f
MR
4031
4032This function removes the buffer denoted by BUFFER-OR-NAME from
4033all window-local buffer lists."
24901d61 4034 (interactive "bBuffer to replace: ")
5386012d 4035 (let ((buffer (window-normalize-buffer buffer-or-name)))
9397e56f
MR
4036 (dolist (window (window-list-1 nil nil t))
4037 (if (eq (window-buffer window) buffer)
0e2070b5
MR
4038 (unless (window--delete window t t)
4039 ;; Switch to another buffer in window.
4040 (set-window-dedicated-p window nil)
4041 (switch-to-prev-buffer window 'kill))
9397e56f
MR
4042 ;; Unrecord BUFFER in WINDOW.
4043 (unrecord-window-buffer window buffer)))))
4044
78dd6ab1
MR
4045(defun quit-restore-window (&optional window bury-or-kill)
4046 "Quit WINDOW and deal with its buffer.
cf4eacfd 4047WINDOW must be a live window and defaults to the selected one.
9397e56f
MR
4048
4049According to information stored in WINDOW's `quit-restore' window
382c953b
JB
4050parameter either (1) delete WINDOW and its frame, (2) delete
4051WINDOW, (3) restore the buffer previously displayed in WINDOW,
4052or (4) make WINDOW display some other buffer than the present
78dd6ab1
MR
4053one. If non-nil, reset `quit-restore' parameter to nil.
4054
4055Optional second argument BURY-OR-KILL tells how to proceed with
4056the buffer of WINDOW. The following values are handled:
4057
4058`nil' means to not handle the buffer in a particular way. This
4059 means that if WINDOW is not deleted by this function, invoking
4060 `switch-to-prev-buffer' will usually show the buffer again.
4061
4062`append' means that if WINDOW is not deleted, move its buffer to
4063 the end of WINDOW's previous buffers so it's less likely that a
4064 future invocation of `switch-to-prev-buffer' will switch to it.
4065 Also, move the buffer to the end of the frame's buffer list.
4066
4067`bury' means that if WINDOW is not deleted, remove its buffer
4068 from WINDOW'S list of previous buffers. Also, move the buffer
4069 to the end of the frame's buffer list. This value provides the
4070 most reliable remedy to not have `switch-to-prev-buffer' switch
4071 to this buffer again without killing the buffer.
4072
4073`kill' means to kill WINDOW's buffer."
447f16b8 4074 (setq window (window-normalize-window window t))
cf4eacfd
MR
4075 (let* ((buffer (window-buffer window))
4076 (quit-restore (window-parameter window 'quit-restore))
4077 (prev-buffer
4078 (let* ((prev-buffers (window-prev-buffers window))
4079 (prev-buffer (caar prev-buffers)))
4080 (and (or (not (eq prev-buffer buffer))
4081 (and (cdr prev-buffers)
4082 (not (eq (setq prev-buffer (cadr prev-buffers))
4083 buffer))))
4084 prev-buffer)))
78dd6ab1 4085 quad entry)
9397e56f 4086 (cond
cf4eacfd 4087 ((and (not prev-buffer)
218e997a
MR
4088 (or (eq (nth 1 quit-restore) 'frame)
4089 (and (eq (nth 1 quit-restore) 'window)
4090 ;; If the window has been created on an existing
4091 ;; frame and ended up as the sole window on that
4092 ;; frame, do not delete it (Bug#12764).
4093 (not (eq window (frame-root-window window)))))
0e2070b5
MR
4094 (eq (nth 3 quit-restore) buffer)
4095 ;; Delete WINDOW if possible.
78dd6ab1 4096 (window--delete window nil (eq bury-or-kill 'kill)))
9397e56f
MR
4097 ;; If the previously selected window is still alive, select it.
4098 (when (window-live-p (nth 2 quit-restore))
4099 (select-window (nth 2 quit-restore))))
cf4eacfd
MR
4100 ((and (listp (setq quad (nth 1 quit-restore)))
4101 (buffer-live-p (car quad))
4102 (eq (nth 3 quit-restore) buffer))
4103 ;; Show another buffer stored in quit-restore parameter.
78dd6ab1 4104 (when (and (integerp (nth 3 quad))
880e6158 4105 (/= (nth 3 quad) (window-total-height window)))
cf4eacfd
MR
4106 ;; Try to resize WINDOW to its old height but don't signal an
4107 ;; error.
4108 (condition-case nil
880e6158 4109 (window-resize window (- (nth 3 quad) (window-total-height window)))
cf4eacfd 4110 (error nil)))
78dd6ab1 4111 (set-window-dedicated-p window nil)
1885e5b8 4112 ;; Restore WINDOW's previous buffer, start and point position.
cf4eacfd
MR
4113 (set-window-buffer-start-and-point
4114 window (nth 0 quad) (nth 1 quad) (nth 2 quad))
78dd6ab1
MR
4115 ;; Deal with the buffer we just removed from WINDOW.
4116 (setq entry (and (eq bury-or-kill 'append)
4117 (assq buffer (window-prev-buffers window))))
4118 (when bury-or-kill
4119 ;; Remove buffer from WINDOW's previous and next buffers.
4120 (set-window-prev-buffers
4121 window (assq-delete-all buffer (window-prev-buffers window)))
4122 (set-window-next-buffers
4123 window (delq buffer (window-next-buffers window))))
4124 (when entry
4125 ;; Append old buffer's entry to list of WINDOW's previous
4126 ;; buffers so it's less likely to get switched to soon but
4127 ;; `display-buffer-in-previous-window' can nevertheless find it.
4128 (set-window-prev-buffers
4129 window (append (window-prev-buffers window) (list entry))))
9397e56f
MR
4130 ;; Reset the quit-restore parameter.
4131 (set-window-parameter window 'quit-restore nil)
cf4eacfd
MR
4132 ;; Select old window.
4133 (when (window-live-p (nth 2 quit-restore))
4134 (select-window (nth 2 quit-restore))))
9397e56f 4135 (t
cf4eacfd
MR
4136 ;; Show some other buffer in WINDOW and reset the quit-restore
4137 ;; parameter.
9397e56f 4138 (set-window-parameter window 'quit-restore nil)
b4d72fcf
MR
4139 ;; Make sure that WINDOW is no more dedicated.
4140 (set-window-dedicated-p window nil)
78dd6ab1
MR
4141 (switch-to-prev-buffer window bury-or-kill)))
4142
4143 ;; Deal with the buffer.
4144 (cond
4145 ((not (buffer-live-p buffer)))
4146 ((eq bury-or-kill 'kill)
4147 (kill-buffer buffer))
4148 (bury-or-kill
4149 (bury-buffer-internal buffer)))))
9397e56f 4150
78dd6ab1
MR
4151(defun quit-window (&optional kill window)
4152 "Quit WINDOW and bury its buffer.
4153WINDOW must be a live window and defaults to the selected one.
4154With prefix argument KILL non-nil, kill the buffer instead of
4155burying it.
4156
4157According to information stored in WINDOW's `quit-restore' window
4158parameter either (1) delete WINDOW and its frame, (2) delete
4159WINDOW, (3) restore the buffer previously displayed in WINDOW,
4160or (4) make WINDOW display some other buffer than the present
4161one. If non-nil, reset `quit-restore' parameter to nil."
4162 (interactive "P")
4163 (quit-restore-window window (if kill 'kill 'bury)))
366ca7f3
MR
4164
4165(defun quit-windows-on (&optional buffer-or-name kill frame)
4166 "Quit all windows showing BUFFER-OR-NAME.
4167BUFFER-OR-NAME may be a buffer or the name of an existing buffer
4168and defaults to the current buffer. Optional argument KILL
4169non-nil means to kill BUFFER-OR-NAME. KILL nil means to bury
4170BUFFER-OR-NAME. Optional argument FRAME is handled as by
4171`delete-windows-on'.
4172
4173This function calls `quit-window' on all candidate windows
4174showing BUFFER-OR-NAME."
4175 (interactive "BQuit windows on (buffer):\nP")
4176 (let ((buffer (window-normalize-buffer buffer-or-name))
4177 ;; Handle the "inverted" meaning of the FRAME argument wrt other
4178 ;; `window-list-1' based function.
4179 (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
4180 (dolist (window (window-list-1 nil nil all-frames))
4181 (if (eq (window-buffer window) buffer)
4182 (quit-window kill window)
4183 ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
4184 (unrecord-window-buffer window buffer)))))
562dd5e9
MR
4185\f
4186;;; Splitting windows.
880e6158 4187(defun window-split-min-size (&optional horizontal pixelwise)
562dd5e9
MR
4188 "Return minimum height of any window when splitting windows.
4189Optional argument HORIZONTAL non-nil means return minimum width."
880e6158
MR
4190 (cond
4191 (pixelwise
4192 (if horizontal
4193 (window-min-pixel-width)
4194 (window-min-pixel-height)))
4195 (horizontal
4196 (max window-min-width window-safe-min-width))
4197 (t
4198 (max window-min-height window-safe-min-height))))
562dd5e9 4199
880e6158 4200(defun split-window (&optional window size side pixelwise)
562dd5e9 4201 "Make a new window adjacent to WINDOW.
85c2386b 4202WINDOW must be a valid window and defaults to the selected one.
562dd5e9
MR
4203Return the new window which is always a live window.
4204
4205Optional argument SIZE a positive number means make WINDOW SIZE
4206lines or columns tall. If SIZE is negative, make the new window
4207-SIZE lines or columns tall. If and only if SIZE is non-nil, its
4208absolute value can be less than `window-min-height' or
4209`window-min-width'; so this command can make a new window as
4210small as one line or two columns. SIZE defaults to half of
0aa3616e 4211WINDOW's size.
562dd5e9
MR
4212
4213Optional third argument SIDE nil (or `below') specifies that the
4214new window shall be located below WINDOW. SIDE `above' means the
4215new window shall be located above WINDOW. In both cases SIZE
382c953b 4216specifies the new number of lines for WINDOW (or the new window
562dd5e9
MR
4217if SIZE is negative) including space reserved for the mode and/or
4218header line.
4219
4220SIDE t (or `right') specifies that the new window shall be
4221located on the right side of WINDOW. SIDE `left' means the new
4222window shall be located on the left of WINDOW. In both cases
382c953b 4223SIZE specifies the new number of columns for WINDOW (or the new
562dd5e9
MR
4224window provided SIZE is negative) including space reserved for
4225fringes and the scrollbar or a divider column. Any other non-nil
4226value for SIDE is currently handled like t (or `right').
4227
f224e500 4228PIXELWISE, if non-nil, means to interpret SIZE pixelwise.
880e6158 4229
562dd5e9
MR
4230If the variable `ignore-window-parameters' is non-nil or the
4231`split-window' parameter of WINDOW equals t, do not process any
4232parameters of WINDOW. Otherwise, if the `split-window' parameter
4233of WINDOW specifies a function, call that function with all three
4234arguments and return the value returned by that function.
4235
4236Otherwise, if WINDOW is part of an atomic window, \"split\" the
4237root of that atomic window. The new window does not become a
4238member of that atomic window.
4239
4240If WINDOW is live, properties of the new window like margins and
4241scrollbars are inherited from WINDOW. If WINDOW is an internal
4242window, these properties as well as the buffer displayed in the
4243new window are inherited from the window selected on WINDOW's
4244frame. The selected window is not changed by this function."
447f16b8 4245 (setq window (window-normalize-window window))
130e3e11
MR
4246 (let* ((side (cond
4247 ((not side) 'below)
4248 ((memq side '(below above right left)) side)
4249 (t 'right)))
caceae25 4250 (horizontal (not (memq side '(below above))))
562dd5e9
MR
4251 (frame (window-frame window))
4252 (parent (window-parent window))
4253 (function (window-parameter window 'split-window))
4254 (window-side (window-parameter window 'window-side))
8e17c9ba
MR
4255 ;; Rebind the following two variables since in some cases we
4256 ;; have to override their value.
b6f67890 4257 (window-combination-limit window-combination-limit)
caceae25 4258 (window-combination-resize window-combination-resize)
880e6158
MR
4259 (char-size (frame-char-size window horizontal))
4260 (pixel-size
4261 (when (numberp size)
4262 (window--size-to-pixel window size horizontal pixelwise t)))
562dd5e9 4263 atom-root)
54f9154c 4264 (window--check frame)
562dd5e9
MR
4265 (catch 'done
4266 (cond
4267 ;; Ignore window parameters if either `ignore-window-parameters'
4268 ;; is t or the `split-window' parameter equals t.
4269 ((or ignore-window-parameters (eq function t)))
4270 ((functionp function)
4271 ;; The `split-window' parameter specifies the function to call.
4272 ;; If that function is `ignore', do nothing.
4273 (throw 'done (funcall function window size side)))
be7f5545
MR
4274 ;; If WINDOW is part of an atomic window, split the root window
4275 ;; of that atomic window instead.
562dd5e9
MR
4276 ((and (window-parameter window 'window-atom)
4277 (setq atom-root (window-atom-root window))
4278 (not (eq atom-root window)))
880e6158 4279 (throw 'done (split-window atom-root size side pixelwise)))
caceae25
MR
4280 ;; If WINDOW is a side window or its first or last child is a
4281 ;; side window, throw an error unless `window-combination-resize'
4282 ;; equals 'side.
4283 ((and (not (eq window-combination-resize 'side))
4284 (or (window-parameter window 'window-side)
4285 (and (window-child window)
4286 (or (window-parameter
4287 (window-child window) 'window-side)
4288 (window-parameter
4289 (window-last-child window) 'window-side)))))
4290 (error "Cannot split side window or parent of side window"))
4291 ;; If `window-combination-resize' is 'side and window has a side
4292 ;; window sibling, bind `window-combination-limit' to t.
4293 ((and (not (eq window-combination-resize 'side))
4294 (or (and (window-prev-sibling window)
4295 (window-parameter
4296 (window-prev-sibling window) 'window-side))
4297 (and (window-next-sibling window)
4298 (window-parameter
4299 (window-next-sibling window) 'window-side))))
4300 (setq window-combination-limit t)))
4301
4302 ;; If `window-combination-resize' is t and SIZE is non-negative,
4303 ;; bind `window-combination-limit' to t.
880e6158
MR
4304 (when (and (eq window-combination-resize t)
4305 pixel-size (> pixel-size 0))
b6f67890 4306 (setq window-combination-limit t))
562dd5e9 4307
880e6158
MR
4308 (let* ((parent-pixel-size
4309 ;; `parent-pixel-size' is the pixel size of WINDOW's
4310 ;; parent, provided it has one.
4311 (when parent (window-size parent horizontal t)))
562dd5e9
MR
4312 ;; `resize' non-nil means we are supposed to resize other
4313 ;; windows in WINDOW's combination.
4314 (resize
caceae25
MR
4315 (and window-combination-resize
4316 (or (window-parameter window 'window-side)
4317 (not (eq window-combination-resize 'side)))
8e17c9ba 4318 (not (eq window-combination-limit t))
562dd5e9 4319 ;; Resize makes sense in iso-combinations only.
3d8daefe 4320 (window-combined-p window horizontal)))
880e6158
MR
4321 ;; `old-pixel-size' is the current pixel size of WINDOW.
4322 (old-pixel-size (window-size window horizontal t))
562dd5e9
MR
4323 ;; `new-size' is the specified or calculated size of the
4324 ;; new window.
2d6b6005 4325 new-pixel-size new-parent new-normal)
880e6158
MR
4326 (cond
4327 ((not pixel-size)
4328 (setq new-pixel-size
4329 (if resize
4330 ;; When resizing try to give the new window the
4331 ;; average size of a window in its combination.
4332 (min (- parent-pixel-size
4333 (window-min-size parent horizontal nil t))
4334 (/ parent-pixel-size
4335 (1+ (window-combinations parent horizontal))))
4336 ;; Else try to give the new window half the size
4337 ;; of WINDOW (plus an eventual odd pixel).
4338 (/ old-pixel-size 2)))
4339 (unless window-resize-pixelwise
4340 ;; Round to nearest char-size multiple.
4341 (setq new-pixel-size
4342 (* char-size (round new-pixel-size char-size)))))
4343 ((>= pixel-size 0)
4344 ;; SIZE non-negative specifies the new size of WINDOW.
4345
4346 ;; Note: Specifying a non-negative SIZE is practically
4347 ;; always done as workaround for making the new window
4348 ;; appear above or on the left of the new window (the
4349 ;; ispell window is a typical example of that). In all
4350 ;; these cases the SIDE argument should be set to 'above
4351 ;; or 'left in order to support the 'resize option.
4352 ;; Here we have to nest the windows instead, see above.
4353 (setq new-pixel-size (- old-pixel-size pixel-size)))
4354 (t
4355 ;; SIZE negative specifies the size of the new window.
4356 (setq new-pixel-size (- pixel-size))))
562dd5e9
MR
4357
4358 ;; Check SIZE.
4359 (cond
880e6158 4360 ((not pixel-size)
562dd5e9
MR
4361 (cond
4362 (resize
4363 ;; SIZE unspecified, resizing.
880e6158
MR
4364 (when (and (not (window-sizable-p
4365 parent (- new-pixel-size) horizontal nil t))
562dd5e9 4366 ;; Try again with minimum split size.
880e6158
MR
4367 (setq new-pixel-size
4368 (max new-pixel-size
4369 (window-split-min-size horizontal t)))
4370 (not (window-sizable-p
4371 parent (- new-pixel-size) horizontal nil t)))
4372 (error "Window %s too small for splitting 1" parent)))
4373 ((> (+ new-pixel-size (window-min-size window horizontal nil t))
4374 old-pixel-size)
562dd5e9 4375 ;; SIZE unspecified, no resizing.
880e6158
MR
4376 (error "Window %s too small for splitting 2" window))))
4377 ((and (>= pixel-size 0)
4378 (or (>= pixel-size old-pixel-size)
4379 (< new-pixel-size
4380 (window-safe-min-pixel-size window horizontal))))
562dd5e9
MR
4381 ;; SIZE specified as new size of old window. If the new size
4382 ;; is larger than the old size or the size of the new window
4383 ;; would be less than the safe minimum, signal an error.
880e6158 4384 (error "Window %s too small for splitting 3" window))
562dd5e9
MR
4385 (resize
4386 ;; SIZE specified, resizing.
880e6158
MR
4387 (unless (window-sizable-p
4388 parent (- new-pixel-size) horizontal nil t)
562dd5e9 4389 ;; If we cannot resize the parent give up.
880e6158
MR
4390 (error "Window %s too small for splitting 4" parent)))
4391 ((or (< new-pixel-size
4392 (window-safe-min-pixel-size window horizontal))
4393 (< (- old-pixel-size new-pixel-size)
4394 (window-safe-min-pixel-size window horizontal)))
562dd5e9 4395 ;; SIZE specification violates minimum size restrictions.
880e6158 4396 (error "Window %s too small for splitting 5" window)))
562dd5e9 4397
5386012d 4398 (window--resize-reset frame horizontal)
562dd5e9
MR
4399
4400 (setq new-parent
4401 ;; Make new-parent non-nil if we need a new parent window;
4402 ;; either because we want to nest or because WINDOW is not
4403 ;; iso-combined.
8e17c9ba 4404 (or (eq window-combination-limit t)
b6f67890 4405 (not (window-combined-p window horizontal))))
562dd5e9
MR
4406 (setq new-normal
4407 ;; Make new-normal the normal size of the new window.
4408 (cond
880e6158
MR
4409 (pixel-size (/ (float new-pixel-size)
4410 (if new-parent old-pixel-size parent-pixel-size)))
562dd5e9 4411 (new-parent 0.5)
3d8daefe 4412 (resize (/ 1.0 (1+ (window-combinations parent horizontal))))
562dd5e9
MR
4413 (t (/ (window-normal-size window horizontal) 2.0))))
4414
4415 (if resize
4416 ;; Try to get space from OLD's siblings. We could go "up" and
4417 ;; try getting additional space from surrounding windows but
4418 ;; we won't be able to return space to those windows when we
4419 ;; delete the one we create here. Hence we do not go up.
4420 (progn
880e6158
MR
4421 (window--resize-child-windows
4422 parent (- new-pixel-size) horizontal)
562dd5e9
MR
4423 (let* ((normal (- 1.0 new-normal))
4424 (sub (window-child parent)))
4425 (while sub
4426 (set-window-new-normal
4427 sub (* (window-normal-size sub horizontal) normal))
4428 (setq sub (window-right sub)))))
4429 ;; Get entire space from WINDOW.
880e6158
MR
4430 (set-window-new-pixel
4431 window (- old-pixel-size new-pixel-size))
4432;; (set-window-new-pixel window (- old-pixel-size new-pixel-size))
4433;; (set-window-new-total
4434;; window (- old-size new-size))
4435 (window--resize-this-window window (- new-pixel-size) horizontal)
562dd5e9
MR
4436 (set-window-new-normal
4437 window (- (if new-parent 1.0 (window-normal-size window horizontal))
4438 new-normal)))
4439
880e6158
MR
4440 (let* ((new (split-window-internal window new-pixel-size side new-normal)))
4441 (window--pixel-to-total frame horizontal)
caceae25 4442 ;; Assign window-side parameters, if any.
c660a885
MR
4443 (cond
4444 ((eq window-combination-resize 'side)
caceae25
MR
4445 (let ((window-side
4446 (cond
4447 (window-side window-side)
4448 ((eq side 'above) 'top)
4449 ((eq side 'below) 'bottom)
4450 (t side))))
4451 ;; We made a new side window.
4452 (set-window-parameter new 'window-side window-side)
4453 (when (and new-parent (window-parameter window 'window-side))
4454 ;; We've been splitting a side root window. Give the
4455 ;; new parent the same window-side parameter.
4456 (set-window-parameter
4457 (window-parent new) 'window-side window-side))))
c660a885
MR
4458 ((eq window-combination-resize 'atom)
4459 ;; Make sure `window--check-frame' won't destroy an existing
4460 ;; atomic window in case the new window gets nested inside.
4461 (unless (window-parameter window 'window-atom)
4462 (set-window-parameter window 'window-atom t))
4463 (when new-parent
4464 (set-window-parameter (window-parent new) 'window-atom t))
4465 (set-window-parameter new 'window-atom t)))
562dd5e9
MR
4466
4467 (run-window-configuration-change-hook frame)
880e6158 4468 (run-window-scroll-functions new)
54f9154c 4469 (window--check frame)
562dd5e9
MR
4470 ;; Always return the new window.
4471 new)))))
4472
4473;; I think this should be the default; I think people will prefer it--rms.
4474(defcustom split-window-keep-point t
2d197ffb
CY
4475 "If non-nil, \\[split-window-below] preserves point in the new window.
4476If nil, adjust point in the two windows to minimize redisplay.
4477This option applies only to `split-window-below' and functions
4478that call it. The low-level `split-window' function always keeps
4479the original point in both windows."
562dd5e9
MR
4480 :type 'boolean
4481 :group 'windows)
4482
2d197ffb
CY
4483(defun split-window-below (&optional size)
4484 "Split the selected window into two windows, one above the other.
4485The selected window is above. The newly split-off window is
4486below, and displays the same buffer. Return the new window.
4487
4488If optional argument SIZE is omitted or nil, both windows get the
4489same height, or close to it. If SIZE is positive, the upper
4490\(selected) window gets SIZE lines. If SIZE is negative, the
4491lower (new) window gets -SIZE lines.
4492
4493If the variable `split-window-keep-point' is non-nil, both
4494windows get the same value of point as the selected window.
4495Otherwise, the window starts are chosen so as to minimize the
4496amount of redisplay; this is convenient on slow terminals."
562dd5e9
MR
4497 (interactive "P")
4498 (let ((old-window (selected-window))
5481664a 4499 (old-point (window-point))
562dd5e9
MR
4500 (size (and size (prefix-numeric-value size)))
4501 moved-by-window-height moved new-window bottom)
4502 (when (and size (< size 0) (< (- size) window-min-height))
4503 ;; `split-window' would not signal an error here.
4504 (error "Size of new window too small"))
4505 (setq new-window (split-window nil size))
4506 (unless split-window-keep-point
4507 (with-current-buffer (window-buffer)
c491fa41
MR
4508 ;; Use `save-excursion' around vertical movements below
4509 ;; (Bug#10971). Note: When the selected window's buffer has a
4510 ;; header line, up to two lines of the buffer may not show up
4511 ;; in the resulting configuration.
4512 (save-excursion
4513 (goto-char (window-start))
4514 (setq moved (vertical-motion (window-height)))
4515 (set-window-start new-window (point))
4516 (when (> (point) (window-point new-window))
4517 (set-window-point new-window (point)))
4518 (when (= moved (window-height))
4519 (setq moved-by-window-height t)
4520 (vertical-motion -1))
4521 (setq bottom (point)))
4522 (and moved-by-window-height
4523 (<= bottom (point))
5481664a 4524 (set-window-point old-window (1- bottom)))
c491fa41
MR
4525 (and moved-by-window-height
4526 (<= (window-start new-window) old-point)
4527 (set-window-point new-window old-point)
4528 (select-window new-window))))
9397e56f
MR
4529 ;; Always copy quit-restore parameter in interactive use.
4530 (let ((quit-restore (window-parameter old-window 'quit-restore)))
4531 (when quit-restore
4532 (set-window-parameter new-window 'quit-restore quit-restore)))
4533 new-window))
562dd5e9 4534
2d197ffb 4535(defalias 'split-window-vertically 'split-window-below)
562dd5e9 4536
2d197ffb
CY
4537(defun split-window-right (&optional size)
4538 "Split the selected window into two side-by-side windows.
4539The selected window is on the left. The newly split-off window
4540is on the right, and displays the same buffer. Return the new
4541window.
562dd5e9 4542
2d197ffb
CY
4543If optional argument SIZE is omitted or nil, both windows get the
4544same width, or close to it. If SIZE is positive, the left-hand
4545\(selected) window gets SIZE columns. If SIZE is negative, the
4546right-hand (new) window gets -SIZE columns. Here, SIZE includes
4547the width of the window's scroll bar; if there are no scroll
4548bars, it includes the width of the divider column to the window's
4549right, if any."
562dd5e9
MR
4550 (interactive "P")
4551 (let ((old-window (selected-window))
4552 (size (and size (prefix-numeric-value size)))
4553 new-window)
4554 (when (and size (< size 0) (< (- size) window-min-width))
4555 ;; `split-window' would not signal an error here.
4556 (error "Size of new window too small"))
9397e56f
MR
4557 (setq new-window (split-window nil size t))
4558 ;; Always copy quit-restore parameter in interactive use.
4559 (let ((quit-restore (window-parameter old-window 'quit-restore)))
4560 (when quit-restore
4561 (set-window-parameter new-window 'quit-restore quit-restore)))
4562 new-window))
562dd5e9 4563
2d197ffb 4564(defalias 'split-window-horizontally 'split-window-right)
562dd5e9 4565\f
6198ccd0
MR
4566;;; Balancing windows.
4567
4568;; The following routine uses the recycled code from an old version of
be7f5545
MR
4569;; `window--resize-child-windows'. It's not very pretty, but coding it the way the
4570;; new `window--resize-child-windows' code does would hardly make it any shorter or
6198ccd0
MR
4571;; more readable (FWIW we'd need three loops - one to calculate the
4572;; minimum sizes per window, one to enlarge or shrink windows until the
4573;; new parent-size matches, and one where we shrink the largest/enlarge
4574;; the smallest window).
4575(defun balance-windows-2 (window horizontal)
4576 "Subroutine of `balance-windows-1'.
3d8daefe 4577WINDOW must be a vertical combination (horizontal if HORIZONTAL
85c2386b 4578is non-nil)."
880e6158
MR
4579 (let* ((char-size (if window-resize-pixelwise
4580 1
4581 (frame-char-size window horizontal)))
4582 (first (window-child window))
6198ccd0
MR
4583 (sub first)
4584 (number-of-children 0)
880e6158 4585 (parent-size (window-new-pixel window))
6198ccd0 4586 (total-sum parent-size)
cb882333 4587 failed size sub-total sub-delta sub-amount rest)
6198ccd0
MR
4588 (while sub
4589 (setq number-of-children (1+ number-of-children))
4590 (when (window-size-fixed-p sub horizontal)
4591 (setq total-sum
880e6158 4592 (- total-sum (window-size sub horizontal t)))
6198ccd0
MR
4593 (set-window-new-normal sub 'ignore))
4594 (setq sub (window-right sub)))
3c448ab6 4595
6198ccd0
MR
4596 (setq failed t)
4597 (while (and failed (> number-of-children 0))
4598 (setq size (/ total-sum number-of-children))
4599 (setq failed nil)
4600 (setq sub first)
4601 (while (and sub (not failed))
be7f5545
MR
4602 ;; Ignore child windows that should be ignored or are stuck.
4603 (unless (window--resize-child-windows-skip-p sub)
880e6158 4604 (setq sub-total (window-size sub horizontal t))
6198ccd0
MR
4605 (setq sub-delta (- size sub-total))
4606 (setq sub-amount
880e6158 4607 (window-sizable sub sub-delta horizontal nil t))
be7f5545 4608 ;; Register the new total size for this child window.
880e6158 4609 (set-window-new-pixel sub (+ sub-total sub-amount))
6198ccd0
MR
4610 (unless (= sub-amount sub-delta)
4611 (setq total-sum (- total-sum sub-total sub-amount))
4612 (setq number-of-children (1- number-of-children))
4613 ;; We failed and need a new round.
4614 (setq failed t)
4615 (set-window-new-normal sub 'skip)))
4616 (setq sub (window-right sub))))
3c448ab6 4617
880e6158 4618 ;; How can we be sure that `number-of-children' is NOT zero here ?
6198ccd0
MR
4619 (setq rest (% total-sum number-of-children))
4620 ;; Fix rounding by trying to enlarge non-stuck windows by one line
4621 ;; (column) until `rest' is zero.
4622 (setq sub first)
4623 (while (and sub (> rest 0))
be7f5545 4624 (unless (window--resize-child-windows-skip-p window)
7e1899d7 4625 (set-window-new-pixel sub (min rest char-size) t)
880e6158 4626 (setq rest (- rest char-size)))
6198ccd0 4627 (setq sub (window-right sub)))
3c448ab6 4628
6198ccd0
MR
4629 ;; Fix rounding by trying to enlarge stuck windows by one line
4630 ;; (column) until `rest' equals zero.
4631 (setq sub first)
4632 (while (and sub (> rest 0))
4633 (unless (eq (window-new-normal sub) 'ignore)
7e1899d7 4634 (set-window-new-pixel sub (min rest char-size) t)
880e6158 4635 (setq rest (- rest char-size)))
6198ccd0
MR
4636 (setq sub (window-right sub)))
4637
4638 (setq sub first)
4639 (while sub
4640 ;; Record new normal sizes.
4641 (set-window-new-normal
4642 sub (/ (if (eq (window-new-normal sub) 'ignore)
880e6158
MR
4643 (window-size sub horizontal t)
4644 (window-new-pixel sub))
6198ccd0 4645 (float parent-size)))
be7f5545 4646 ;; Recursively balance each window's child windows.
6198ccd0
MR
4647 (balance-windows-1 sub horizontal)
4648 (setq sub (window-right sub)))))
4649
4650(defun balance-windows-1 (window &optional horizontal)
4651 "Subroutine of `balance-windows'."
4652 (if (window-child window)
4653 (let ((sub (window-child window)))
3d8daefe 4654 (if (window-combined-p sub horizontal)
6198ccd0 4655 (balance-windows-2 window horizontal)
880e6158 4656 (let ((size (window-new-pixel window)))
6198ccd0 4657 (while sub
880e6158 4658 (set-window-new-pixel sub size)
6198ccd0
MR
4659 (balance-windows-1 sub horizontal)
4660 (setq sub (window-right sub))))))))
4661
4662(defun balance-windows (&optional window-or-frame)
be7f5545 4663 "Balance the sizes of windows of WINDOW-OR-FRAME.
6198ccd0
MR
4664WINDOW-OR-FRAME is optional and defaults to the selected frame.
4665If WINDOW-OR-FRAME denotes a frame, balance the sizes of all
4c36be58 4666windows of that frame. If WINDOW-OR-FRAME denotes a window,
be7f5545 4667recursively balance the sizes of all child windows of that
6198ccd0
MR
4668window."
4669 (interactive)
4670 (let* ((window
4671 (cond
4672 ((or (not window-or-frame)
4673 (frame-live-p window-or-frame))
4674 (frame-root-window window-or-frame))
4675 ((or (window-live-p window-or-frame)
4676 (window-child window-or-frame))
4677 window-or-frame)
4678 (t
4679 (error "Not a window or frame %s" window-or-frame))))
4680 (frame (window-frame window)))
4681 ;; Balance vertically.
5386012d 4682 (window--resize-reset (window-frame window))
6198ccd0 4683 (balance-windows-1 window)
880e6158
MR
4684 (when (window--resize-apply-p frame)
4685 (window-resize-apply frame)
4686 (window--pixel-to-total frame)
4687 (run-window-configuration-change-hook frame))
6198ccd0 4688 ;; Balance horizontally.
5386012d 4689 (window--resize-reset (window-frame window) t)
6198ccd0 4690 (balance-windows-1 window t)
880e6158 4691 (when (window--resize-apply-p frame t)
3669b636 4692 (window-resize-apply frame t)
880e6158
MR
4693 (window--pixel-to-total frame t)
4694 (run-window-configuration-change-hook frame))))
3c448ab6
MR
4695
4696(defun window-fixed-size-p (&optional window direction)
4697 "Return t if WINDOW cannot be resized in DIRECTION.
4698WINDOW defaults to the selected window. DIRECTION can be
4699nil (i.e. any), `height' or `width'."
4700 (with-current-buffer (window-buffer window)
4701 (when (and (boundp 'window-size-fixed) window-size-fixed)
4702 (not (and direction
4703 (member (cons direction window-size-fixed)
4704 '((height . width) (width . height))))))))
4705
4706;;; A different solution to balance-windows.
3c448ab6
MR
4707(defvar window-area-factor 1
4708 "Factor by which the window area should be over-estimated.
4709This is used by `balance-windows-area'.
4710Changing this globally has no effect.")
4711(make-variable-buffer-local 'window-area-factor)
4712
880e6158 4713(defun balance-windows-area-adjust (window delta horizontal pixelwise)
d615d6d2 4714 "Wrapper around `window-resize' with error checking.
6198ccd0 4715Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function."
d615d6d2 4716 ;; `window-resize' may fail if delta is too large.
6198ccd0
MR
4717 (while (>= (abs delta) 1)
4718 (condition-case nil
4719 (progn
880e6158
MR
4720 ;; It was wrong to use `window-resize' here. Somehow
4721 ;; `balance-windows-area' depends on resizing windows
4722 ;; asymmetrically.
4723 (adjust-window-trailing-edge window delta horizontal pixelwise)
6198ccd0
MR
4724 (setq delta 0))
4725 (error
4726 ;;(message "adjust: %s" (error-message-string err))
4727 (setq delta (/ delta 2))))))
4728
3c448ab6
MR
4729(defun balance-windows-area ()
4730 "Make all visible windows the same area (approximately).
4731See also `window-area-factor' to change the relative size of
4732specific buffers."
4733 (interactive)
4734 (let* ((unchanged 0) (carry 0) (round 0)
4735 ;; Remove fixed-size windows.
4736 (wins (delq nil (mapcar (lambda (win)
4737 (if (not (window-fixed-size-p win)) win))
4738 (window-list nil 'nomini))))
4739 (changelog nil)
880e6158
MR
4740 (pixelwise window-resize-pixelwise)
4741 next)
3c448ab6
MR
4742 ;; Resizing a window changes the size of surrounding windows in complex
4743 ;; ways, so it's difficult to balance them all. The introduction of
4744 ;; `adjust-window-trailing-edge' made it a bit easier, but it is still
4745 ;; very difficult to do. `balance-window' above takes an off-line
4746 ;; approach: get the whole window tree, then balance it, then try to
4747 ;; adjust the windows so they fit the result.
4748 ;; Here, instead, we take a "local optimization" approach, where we just
4749 ;; go through all the windows several times until nothing needs to be
4750 ;; changed. The main problem with this approach is that it's difficult
4751 ;; to make sure it terminates, so we use some heuristic to try and break
4752 ;; off infinite loops.
4753 ;; After a round without any change, we allow a second, to give a chance
4754 ;; to the carry to propagate a minor imbalance from the end back to
4755 ;; the beginning.
4756 (while (< unchanged 2)
4757 ;; (message "New round")
4758 (setq unchanged (1+ unchanged) round (1+ round))
4759 (dolist (win wins)
4760 (setq next win)
4761 (while (progn (setq next (next-window next))
4762 (window-fixed-size-p next)))
4763 ;; (assert (eq next (or (cadr (member win wins)) (car wins))))
4764 (let* ((horiz
880e6158 4765 (< (car (window-pixel-edges win)) (car (window-pixel-edges next))))
18cee9ec
MR
4766 (areadiff (/ (- (* (window-size next nil pixelwise)
4767 (window-size next t pixelwise)
3c448ab6
MR
4768 (buffer-local-value 'window-area-factor
4769 (window-buffer next)))
18cee9ec
MR
4770 (* (window-size win nil pixelwise)
4771 (window-size win t pixelwise)
3c448ab6
MR
4772 (buffer-local-value 'window-area-factor
4773 (window-buffer win))))
4774 (max (buffer-local-value 'window-area-factor
4775 (window-buffer win))
4776 (buffer-local-value 'window-area-factor
4777 (window-buffer next)))))
4778 (edgesize (if horiz
18cee9ec
MR
4779 (+ (window-size win nil pixelwise)
4780 (window-size next nil pixelwise))
4781 (+ (window-size win t pixelwise)
4782 (window-size next t pixelwise))))
3c448ab6
MR
4783 (diff (/ areadiff edgesize)))
4784 (when (zerop diff)
4785 ;; Maybe diff is actually closer to 1 than to 0.
4786 (setq diff (/ (* 3 areadiff) (* 2 edgesize))))
4787 (when (and (zerop diff) (not (zerop areadiff)))
4788 (setq diff (/ (+ areadiff carry) edgesize))
4789 ;; Change things smoothly.
4790 (if (or (> diff 1) (< diff -1)) (setq diff (/ diff 2))))
4791 (if (zerop diff)
4792 ;; Make sure negligible differences don't accumulate to
4793 ;; become significant.
4794 (setq carry (+ carry areadiff))
6198ccd0 4795 ;; This used `adjust-window-trailing-edge' before and uses
d615d6d2 4796 ;; `window-resize' now. Error wrapping is still needed.
880e6158 4797 (balance-windows-area-adjust win diff horiz pixelwise)
3c448ab6 4798 ;; (sit-for 0.5)
880e6158 4799 (let ((change (cons win (window-pixel-edges win))))
3c448ab6
MR
4800 ;; If the same change has been seen already for this window,
4801 ;; we're most likely in an endless loop, so don't count it as
4802 ;; a change.
4803 (unless (member change changelog)
4804 (push change changelog)
4805 (setq unchanged 0 carry 0)))))))
4806 ;; We've now basically balanced all the windows.
4807 ;; But there may be some minor off-by-one imbalance left over,
4808 ;; so let's do some fine tuning.
4809 ;; (bw-finetune wins)
4810 ;; (message "Done in %d rounds" round)
4811 ))
9d89fec7
MR
4812
4813;;; Window states, how to get them and how to put them in a window.
34a02f46 4814(defun window--state-get-1 (window &optional writable)
9d89fec7
MR
4815 "Helper function for `window-state-get'."
4816 (let* ((type
4817 (cond
d68443dc
MR
4818 ((window-top-child window) 'vc)
4819 ((window-left-child window) 'hc)
9d89fec7
MR
4820 (t 'leaf)))
4821 (buffer (window-buffer window))
4822 (selected (eq window (selected-window)))
4823 (head
4b0d61e3
SM
4824 `(,type
4825 ,@(unless (window-next-sibling window) `((last . t)))
880e6158
MR
4826 (pixel-width . ,(window-pixel-width window))
4827 (pixel-height . ,(window-pixel-height window))
4828 (total-width . ,(window-total-width window))
4829 (total-height . ,(window-total-height window))
4b0d61e3
SM
4830 (normal-height . ,(window-normal-size window))
4831 (normal-width . ,(window-normal-size window t))
8bbdea0f 4832 ,@(unless (window-live-p window)
ab5340fe 4833 `((combination-limit . ,(window-combination-limit window))))
34a02f46
MR
4834 ,@(let ((parameters (window-parameters window))
4835 list)
4836 ;; Make copies of those window parameters whose
4837 ;; persistence property is `writable' if WRITABLE is
4838 ;; non-nil and non-nil if WRITABLE is nil.
4839 (dolist (par parameters)
4840 (let ((pers (cdr (assq (car par)
4841 window-persistent-parameters))))
4842 (when (and pers (or (not writable) (eq pers 'writable)))
4843 (setq list (cons (cons (car par) (cdr par)) list)))))
4844 ;; Add `clone-of' parameter if necessary.
4845 (let ((pers (cdr (assq 'clone-of
4846 window-persistent-parameters))))
4847 (when (and pers (or (not writable) (eq pers 'writable))
4848 (not (assq 'clone-of list)))
4849 (setq list (cons (cons 'clone-of window) list))))
4b0d61e3
SM
4850 (when list
4851 `((parameters . ,list))))
4852 ,@(when buffer
1edf595d 4853 ;; All buffer related things go in here.
5481664a 4854 (let ((point (window-point window))
1edf595d
MR
4855 (start (window-start window)))
4856 `((buffer
4857 ,(buffer-name buffer)
4858 (selected . ,selected)
4859 (hscroll . ,(window-hscroll window))
4860 (fringes . ,(window-fringes window))
4861 (margins . ,(window-margins window))
4862 (scroll-bars . ,(window-scroll-bars window))
4863 (vscroll . ,(window-vscroll window))
4864 (dedicated . ,(window-dedicated-p window))
de8c03dc
SM
4865 (point . ,(if writable point
4866 (copy-marker point
4867 (buffer-local-value
4868 'window-point-insertion-type
4869 buffer))))
1edf595d 4870 (start . ,(if writable start (copy-marker start)))))))))
9d89fec7
MR
4871 (tail
4872 (when (memq type '(vc hc))
4873 (let (list)
4874 (setq window (window-child window))
4875 (while window
34a02f46 4876 (setq list (cons (window--state-get-1 window writable) list))
9d89fec7
MR
4877 (setq window (window-right window)))
4878 (nreverse list)))))
4879 (append head tail)))
4880
34a02f46 4881(defun window-state-get (&optional window writable)
9d89fec7
MR
4882 "Return state of WINDOW as a Lisp object.
4883WINDOW can be any window and defaults to the root window of the
4884selected frame.
4885
34a02f46
MR
4886Optional argument WRITABLE non-nil means do not use markers for
4887sampling `window-point' and `window-start'. Together, WRITABLE
4888and the variable `window-persistent-parameters' specify which
4889window parameters are saved by this function. WRITABLE should be
4890non-nil when the return value shall be written to a file and read
4891back in another session. Otherwise, an application may run into
4892an `invalid-read-syntax' error while attempting to read back the
4893value from file.
9d89fec7
MR
4894
4895The return value can be used as argument for `window-state-put'
4896to put the state recorded here into an arbitrary window. The
4897value can be also stored on disk and read back in a new session."
4898 (setq window
4899 (if window
24300f5f 4900 (if (window-valid-p window)
9d89fec7
MR
4901 window
4902 (error "%s is not a live or internal window" window))
4903 (frame-root-window)))
4904 ;; The return value is a cons whose car specifies some constraints on
be7f5545
MR
4905 ;; the size of WINDOW. The cdr lists the states of the child windows
4906 ;; of WINDOW.
9d89fec7
MR
4907 (cons
4908 ;; Frame related things would go into a function, say `frame-state',
4909 ;; calling `window-state-get' to insert the frame's root window.
4b0d61e3
SM
4910 `((min-height . ,(window-min-size window))
4911 (min-width . ,(window-min-size window t))
4912 (min-height-ignore . ,(window-min-size window nil t))
4913 (min-width-ignore . ,(window-min-size window t t))
4914 (min-height-safe . ,(window-min-size window nil 'safe))
880e6158
MR
4915 (min-width-safe . ,(window-min-size window t 'safe))
4916 (min-pixel-height . ,(window-min-size window nil nil t))
4917 (min-pixel-width . ,(window-min-size window t nil t))
4918 (min-pixel-height-ignore . ,(window-min-size window nil t t))
4919 (min-pixel-width-ignore . ,(window-min-size window t t t))
4920 (min-pixel-height-safe . ,(window-min-size window nil 'safe t))
4921 (min-pixel-width-safe . ,(window-min-size window t 'safe t)))
34a02f46 4922 (window--state-get-1 window writable)))
9d89fec7
MR
4923
4924(defvar window-state-put-list nil
4925 "Helper variable for `window-state-put'.")
4926
34ada5f4
MR
4927(defvar window-state-put-stale-windows nil
4928 "Helper variable for `window-state-put'.")
4929
880e6158 4930(defun window--state-put-1 (state &optional window ignore totals pixelwise)
9d89fec7
MR
4931 "Helper function for `window-state-put'."
4932 (let ((type (car state)))
4933 (setq state (cdr state))
4934 (cond
4935 ((eq type 'leaf)
4936 ;; For a leaf window just add unprocessed entries to
4937 ;; `window-state-put-list'.
c7635a97 4938 (push (cons window state) window-state-put-list))
9d89fec7
MR
4939 ((memq type '(vc hc))
4940 (let* ((horizontal (eq type 'hc))
880e6158 4941 (total (window-size window horizontal pixelwise))
9d89fec7
MR
4942 (first t)
4943 size new)
4944 (dolist (item state)
4945 ;; Find the next child window. WINDOW always points to the
4946 ;; real window that we want to fill with what we find here.
4947 (when (memq (car item) '(leaf vc hc))
4948 (if (assq 'last item)
c56cad4a 4949 ;; The last child window. Below `window--state-put-1'
9d89fec7
MR
4950 ;; will put into it whatever ITEM has in store.
4951 (setq new nil)
4952 ;; Not the last child window, prepare for splitting
4953 ;; WINDOW. SIZE is the new (and final) size of the old
4954 ;; window.
4955 (setq size
4956 (if totals
4957 ;; Use total size.
880e6158
MR
4958 (if pixelwise
4959 (cdr (assq (if horizontal
4960 'pixel-width
4961 'pixel-height)
4962 item))
4963 (cdr (assq (if horizontal
4964 'total-width
4965 'total-height)
4966 item)))
9d89fec7 4967 ;; Use normalized size and round.
880e6158
MR
4968 (round
4969 (* total
4970 (cdr (assq (if horizontal 'normal-width 'normal-height)
4971 item))))))
9d89fec7
MR
4972
4973 ;; Use safe sizes, we try to resize later.
880e6158
MR
4974 (setq size (max size
4975 (if horizontal
4976 (* window-safe-min-width
4977 (if pixelwise
4978 (frame-char-width (window-frame window))
4979 1))
4980 (* window-safe-min-height
4981 (if pixelwise
4982 (frame-char-height (window-frame window))
4983 1)))))
4984 (if (window-sizable-p window (- size) horizontal 'safe pixelwise)
b6f67890
MR
4985 (let* ((window-combination-limit
4986 (assq 'combination-limit item)))
301b181a 4987 ;; We must inherit the combination limit, otherwise
b6f67890
MR
4988 ;; we might mess up handling of atomic and side
4989 ;; window.
880e6158 4990 (setq new (split-window window size horizontal pixelwise)))
9d89fec7
MR
4991 ;; Give up if we can't resize window down to safe sizes.
4992 (error "Cannot resize window %s" window))
4993
4994 (when first
4995 (setq first nil)
4996 ;; When creating the first child window add for parent
4997 ;; unprocessed entries to `window-state-put-list'.
4998 (setq window-state-put-list
4999 (cons (cons (window-parent window) state)
5000 window-state-put-list))))
5001
5002 ;; Now process the current window (either the one we've just
5003 ;; split or the last child of its parent).
c56cad4a 5004 (window--state-put-1 item window ignore totals)
9d89fec7
MR
5005 ;; Continue with the last window split off.
5006 (setq window new))))))))
5007
880e6158 5008(defun window--state-put-2 (ignore pixelwise)
9d89fec7
MR
5009 "Helper function for `window-state-put'."
5010 (dolist (item window-state-put-list)
5011 (let ((window (car item))
b6f67890 5012 (combination-limit (cdr (assq 'combination-limit item)))
9d89fec7
MR
5013 (parameters (cdr (assq 'parameters item)))
5014 (state (cdr (assq 'buffer item))))
b6f67890
MR
5015 (when combination-limit
5016 (set-window-combination-limit window combination-limit))
34a02f46
MR
5017 ;; Reset window's parameters and assign saved ones (we might want
5018 ;; a `remove-window-parameters' function here).
5019 (dolist (parameter (window-parameters window))
5020 (set-window-parameter window (car parameter) nil))
9d89fec7
MR
5021 (when parameters
5022 (dolist (parameter parameters)
34a02f46 5023 (set-window-parameter window (car parameter) (cdr parameter))))
9d89fec7
MR
5024 ;; Process buffer related state.
5025 (when state
34ada5f4
MR
5026 (let ((buffer (get-buffer (car state))))
5027 (if buffer
c089653d
MR
5028 (with-current-buffer buffer
5029 (set-window-buffer window buffer)
5030 (set-window-hscroll window (cdr (assq 'hscroll state)))
5031 (apply 'set-window-fringes
5032 (cons window (cdr (assq 'fringes state))))
5033 (let ((margins (cdr (assq 'margins state))))
5034 (set-window-margins window (car margins) (cdr margins)))
5035 (let ((scroll-bars (cdr (assq 'scroll-bars state))))
5036 (set-window-scroll-bars
5037 window (car scroll-bars) (nth 2 scroll-bars)
5038 (nth 3 scroll-bars)))
5039 (set-window-vscroll window (cdr (assq 'vscroll state)))
5040 ;; Adjust vertically.
5041 (if (memq window-size-fixed '(t height))
5042 ;; A fixed height window, try to restore the
5043 ;; original size.
880e6158
MR
5044 (let ((delta
5045 (- (cdr (assq
5046 (if pixelwise 'pixel-height 'total-height)
5047 item))
5048 (window-size window nil pixelwise)))
c089653d 5049 window-size-fixed)
880e6158
MR
5050 (when (window--resizable-p
5051 window delta nil nil nil nil nil pixelwise)
5052 (window-resize window delta nil nil pixelwise)))
c089653d 5053 ;; Else check whether the window is not high enough.
880e6158
MR
5054 (let* ((min-size
5055 (window-min-size window nil ignore pixelwise))
5056 (delta
5057 (- min-size (window-size window nil pixelwise))))
c089653d 5058 (when (and (> delta 0)
880e6158
MR
5059 (window--resizable-p
5060 window delta nil ignore nil nil nil pixelwise))
5061 (window-resize window delta nil ignore pixelwise))))
c089653d
MR
5062 ;; Adjust horizontally.
5063 (if (memq window-size-fixed '(t width))
5064 ;; A fixed width window, try to restore the original
5065 ;; size.
880e6158
MR
5066 (let ((delta
5067 (- (cdr (assq
5068 (if pixelwise 'pixel-width 'total-width)
5069 item))
5070 (window-size window t pixelwise)))
c089653d 5071 window-size-fixed)
880e6158
MR
5072 (when (window--resizable-p
5073 window delta nil nil nil nil nil pixelwise)
5074 (window-resize window delta nil nil pixelwise)))
c089653d 5075 ;; Else check whether the window is not wide enough.
880e6158
MR
5076 (let* ((min-size (window-min-size window t ignore pixelwise))
5077 (delta (- min-size (window-size window t pixelwise))))
c089653d 5078 (when (and (> delta 0)
880e6158
MR
5079 (window--resizable-p
5080 window delta t ignore nil nil nil pixelwise))
5081 (window-resize window delta t ignore pixelwise))))
c089653d
MR
5082 ;; Set dedicated status.
5083 (set-window-dedicated-p window (cdr (assq 'dedicated state)))
5084 ;; Install positions (maybe we should do this after all
5085 ;; windows have been created and sized).
5086 (ignore-errors
5087 (set-window-start window (cdr (assq 'start state)))
5088 (set-window-point window (cdr (assq 'point state))))
5089 ;; Select window if it's the selected one.
5090 (when (cdr (assq 'selected state))
5091 (select-window window)))
5092 ;; We don't want to raise an error in case the buffer does
5093 ;; not exist anymore, so we switch to a previous one and
5094 ;; save the window with the intention of deleting it later
5095 ;; if possible.
34ada5f4 5096 (switch-to-prev-buffer window)
c089653d 5097 (push window window-state-put-stale-windows)))))))
9d89fec7
MR
5098
5099(defun window-state-put (state &optional window ignore)
5100 "Put window state STATE into WINDOW.
5101STATE should be the state of a window returned by an earlier
5102invocation of `window-state-get'. Optional argument WINDOW must
8e009b78
MR
5103specify a valid window and defaults to the selected one. If
5104WINDOW is not live, replace WINDOW by a live one before putting
5105STATE into it.
9d89fec7
MR
5106
5107Optional argument IGNORE non-nil means ignore minimum window
5108sizes and fixed size restrictions. IGNORE equal `safe' means
be7f5545 5109windows can get as small as `window-safe-min-height' and
9d89fec7 5110`window-safe-min-width'."
34ada5f4 5111 (setq window-state-put-stale-windows nil)
8e009b78
MR
5112 (setq window (window-normalize-window window))
5113
5114 ;; When WINDOW is internal, reduce it to a live one to put STATE into,
5115 ;; see Bug#16793.
5116 (unless (window-live-p window)
5117 (let ((root (frame-root-window window)))
5118 (if (eq window root)
5119 (setq window (frame-first-window root))
5120 (setq root window)
5121 (setq window (catch 'live
5122 (walk-window-subtree
5123 (lambda (window)
5124 (when (window-live-p window)
5125 (throw 'live window)))
5126 root))))
5127 (delete-other-windows-internal window root)))
5128
9d89fec7
MR
5129 (let* ((frame (window-frame window))
5130 (head (car state))
5131 ;; We check here (1) whether the total sizes of root window of
5132 ;; STATE and that of WINDOW are equal so we can avoid
5133 ;; calculating new sizes, and (2) if we do have to resize
5134 ;; whether we can do so without violating size restrictions.
880e6158
MR
5135 (pixelwise (and (cdr (assq 'pixel-width state))
5136 (cdr (assq 'pixel-height state))))
5137 (totals (or (and pixelwise
5138 (= (window-pixel-width window)
5139 (cdr (assq 'pixel-width state)))
5140 (= (window-pixel-height window)
5141 (cdr (assq 'pixel-height state))))
5142 (and (= (window-total-width window)
5143 (cdr (assq 'total-width state)))
5144 (= (window-total-height window)
5145 (cdr (assq 'total-height state))))))
5146 (min-height (cdr (assq
5147 (if pixelwise 'min-pixel-height 'min-height)
5148 head)))
5149 (min-width (cdr (assq
5150 (if pixelwise 'min-pixel-width 'min-weight)
5151 head))))
9d89fec7 5152 (if (and (not totals)
880e6158
MR
5153 (or (> min-height (window-size window nil pixelwise))
5154 (> min-width (window-size window t pixelwise)))
9d89fec7
MR
5155 (or (not ignore)
5156 (and (setq min-height
880e6158
MR
5157 (cdr (assq
5158 (if pixelwise
5159 'min-pixel-height-ignore
5160 'min-height-ignore)
5161 head)))
9d89fec7 5162 (setq min-width
880e6158
MR
5163 (cdr (assq
5164 (if pixelwise
5165 'min-pixel-width-ignore
5166 'min-width-ignore)
5167 head)))
5168 (or (> min-height
5169 (window-size window nil pixelwise))
5170 (> min-width
5171 (window-size window t pixelwise)))
9d89fec7
MR
5172 (or (not (eq ignore 'safe))
5173 (and (setq min-height
880e6158
MR
5174 (cdr (assq
5175 (if pixelwise
5176 'min-pixel-height-safe
5177 'min-height-safe)
5178 head)))
9d89fec7 5179 (setq min-width
880e6158
MR
5180 (cdr (assq
5181 (if pixelwise
5182 'min-pixel-width-safe
5183 'min-width-safe)
5184 head)))
9d89fec7 5185 (or (> min-height
880e6158 5186 (window-size window nil pixelwise))
9d89fec7 5187 (> min-width
880e6158 5188 (window-size window t pixelwise))))))))
9d89fec7
MR
5189 ;; The check above might not catch all errors due to rounding
5190 ;; issues - so IGNORE equal 'safe might not always produce the
5191 ;; minimum possible state. But such configurations hardly make
5192 ;; sense anyway.
a91adc7e 5193 (error "Window %s too small to accommodate state" window)
9d89fec7
MR
5194 (setq state (cdr state))
5195 (setq window-state-put-list nil)
5196 ;; Work on the windows of a temporary buffer to make sure that
5197 ;; splitting proceeds regardless of any buffer local values of
5198 ;; `window-size-fixed'. Release that buffer after the buffers of
c56cad4a 5199 ;; all live windows have been set by `window--state-put-2'.
9d89fec7
MR
5200 (with-temp-buffer
5201 (set-window-buffer window (current-buffer))
880e6158
MR
5202 (window--state-put-1 state window nil totals pixelwise)
5203 (window--state-put-2 ignore pixelwise))
34ada5f4
MR
5204 (while window-state-put-stale-windows
5205 (let ((window (pop window-state-put-stale-windows)))
5206 (when (eq (window-deletable-p window) t)
5207 (delete-window window))))
54f9154c 5208 (window--check frame))))
9481c002 5209\f
f818cd2a
MR
5210(defun display-buffer-record-window (type window buffer)
5211 "Record information for window used by `display-buffer'.
cf4eacfd 5212TYPE specifies the type of the calling operation and must be one
382c953b
JB
5213of the symbols 'reuse (when WINDOW existed already and was
5214reused for displaying BUFFER), 'window (when WINDOW was created
5215on an already existing frame), or 'frame (when WINDOW was
5216created on a new frame). WINDOW is the window used for or created
cf4eacfd
MR
5217by the `display-buffer' routines. BUFFER is the buffer that
5218shall be displayed.
5219
5220This function installs or updates the quit-restore parameter of
5221WINDOW. The quit-restore parameter is a list of four elements:
5222The first element is one of the symbols 'window, 'frame, 'same or
5223'other. The second element is either one of the symbols 'window
5224or 'frame or a list whose elements are the buffer previously
5225shown in the window, that buffer's window start and window point,
5226and the window's height. The third element is the window
5227selected at the time the parameter was created. The fourth
5228element is BUFFER."
f818cd2a 5229 (cond
cf4eacfd
MR
5230 ((eq type 'reuse)
5231 (if (eq (window-buffer window) buffer)
5232 ;; WINDOW shows BUFFER already.
5233 (when (consp (window-parameter window 'quit-restore))
5234 ;; If WINDOW has a quit-restore parameter, reset its car.
5235 (setcar (window-parameter window 'quit-restore) 'same))
5236 ;; WINDOW shows another buffer.
92346275
MR
5237 (with-current-buffer (window-buffer window)
5238 (set-window-parameter
5239 window 'quit-restore
5240 (list 'other
5241 ;; A quadruple of WINDOW's buffer, start, point and height.
5242 (list (current-buffer) (window-start window)
5243 ;; Preserve window-point-insertion-type (Bug#12588).
5244 (copy-marker
5245 (window-point window) window-point-insertion-type)
880e6158 5246 (window-total-height window))
92346275 5247 (selected-window) buffer)))))
cf4eacfd
MR
5248 ((eq type 'window)
5249 ;; WINDOW has been created on an existing frame.
f818cd2a 5250 (set-window-parameter
cf4eacfd
MR
5251 window 'quit-restore
5252 (list 'window 'window (selected-window) buffer)))
5253 ((eq type 'frame)
5254 ;; WINDOW has been created on a new frame.
f818cd2a 5255 (set-window-parameter
cf4eacfd
MR
5256 window 'quit-restore
5257 (list 'frame 'frame (selected-window) buffer)))))
9481c002 5258
f818cd2a
MR
5259(defcustom display-buffer-function nil
5260 "If non-nil, function to call to handle `display-buffer'.
5261It will receive two args, the buffer and a flag which if non-nil
5262means that the currently selected window is not acceptable. It
5263should choose or create a window, display the specified buffer in
5264it, and return the window.
5265
e1c2c6f2
MR
5266The specified function should call `display-buffer-record-window'
5267with corresponding arguments to set up the quit-restore parameter
5268of the window used."
f818cd2a
MR
5269 :type '(choice
5270 (const nil)
5271 (function :tag "function"))
3c448ab6 5272 :group 'windows)
9481c002 5273
71ce58e7
CY
5274(make-obsolete-variable 'display-buffer-function
5275 'display-buffer-alist "24.3")
5276
d97af5a0
CY
5277;; Eventually, we want to turn this into a defvar; instead of
5278;; customizing this, the user should use a `pop-up-frame-parameters'
5279;; alist entry in `display-buffer-base-action'.
f818cd2a
MR
5280(defcustom pop-up-frame-alist nil
5281 "Alist of parameters for automatically generated new frames.
f818cd2a
MR
5282If non-nil, the value you specify here is used by the default
5283`pop-up-frame-function' for the creation of new frames.
9481c002 5284
f818cd2a
MR
5285Since `pop-up-frame-function' is used by `display-buffer' for
5286making new frames, any value specified here by default affects
5287the automatic generation of new frames via `display-buffer' and
5288all functions based on it. The behavior of `make-frame' is not
5289affected by this variable."
9481c002 5290 :type '(repeat (cons :format "%v"
f818cd2a
MR
5291 (symbol :tag "Parameter")
5292 (sexp :tag "Value")))
9481c002 5293 :group 'frames)
9481c002 5294
f818cd2a
MR
5295(defcustom pop-up-frame-function
5296 (lambda () (make-frame pop-up-frame-alist))
5297 "Function used by `display-buffer' for creating a new frame.
5298This function is called with no arguments and should return a new
5299frame. The default value calls `make-frame' with the argument
5300`pop-up-frame-alist'."
9481c002 5301 :type 'function
9481c002 5302 :group 'frames)
3c448ab6 5303
56f31926
MR
5304(defcustom special-display-buffer-names nil
5305 "List of names of buffers that should be displayed specially.
5306Displaying a buffer with `display-buffer' or `pop-to-buffer', if
5307its name is in this list, displays the buffer in a way specified
5308by `special-display-function'. `special-display-popup-frame'
5309\(the default for `special-display-function') usually displays
5310the buffer in a separate frame made with the parameters specified
5311by `special-display-frame-alist'. If `special-display-function'
5312has been set to some other function, that function is called with
5313the buffer as first, and nil as second argument.
5314
5315Alternatively, an element of this list can be specified as
5316\(BUFFER-NAME FRAME-PARAMETERS), where BUFFER-NAME is a buffer
382c953b 5317name and FRAME-PARAMETERS an alist of (PARAMETER . VALUE) pairs.
56f31926
MR
5318`special-display-popup-frame' will interpret such pairs as frame
5319parameters when it creates a special frame, overriding the
5320corresponding values from `special-display-frame-alist'.
5321
5322As a special case, if FRAME-PARAMETERS contains (same-window . t)
5323`special-display-popup-frame' displays that buffer in the
5324selected window. If FRAME-PARAMETERS contains (same-frame . t),
5325it displays that buffer in a window on the selected frame.
5326
5327If `special-display-function' specifies some other function than
5328`special-display-popup-frame', that function is called with the
5329buffer named BUFFER-NAME as first, and FRAME-PARAMETERS as second
5330argument.
5331
5332Finally, an element of this list can be also specified as
5333\(BUFFER-NAME FUNCTION OTHER-ARGS). In that case,
5334`special-display-popup-frame' will call FUNCTION with the buffer
5335named BUFFER-NAME as first argument, and OTHER-ARGS as the
0563dae9
MR
5336second.
5337
5338Any alternative function specified here is responsible for
5339setting up the quit-restore parameter of the window used.
56f31926
MR
5340
5341If this variable appears \"not to work\", because you added a
5342name to it but the corresponding buffer is displayed in the
5343selected window, look at the values of `same-window-buffer-names'
5344and `same-window-regexps'. Those variables take precedence over
5345this one.
5346
5347See also `special-display-regexps'."
5348 :type '(repeat
5349 (choice :tag "Buffer"
5350 :value ""
5351 (string :format "%v")
5352 (cons :tag "With parameters"
5353 :format "%v"
5354 :value ("" . nil)
5355 (string :format "%v")
5356 (repeat :tag "Parameters"
5357 (cons :format "%v"
5358 (symbol :tag "Parameter")
5359 (sexp :tag "Value"))))
5360 (list :tag "With function"
5361 :format "%v"
5362 :value ("" . nil)
5363 (string :format "%v")
5364 (function :tag "Function")
5365 (repeat :tag "Arguments" (sexp)))))
5366 :group 'windows
5367 :group 'frames)
77f1f99c 5368(make-obsolete-variable 'special-display-buffer-names 'display-buffer-alist "24.3")
ac549fa5
GM
5369(put 'special-display-buffer-names 'risky-local-variable t)
5370
56f31926
MR
5371(defcustom special-display-regexps nil
5372 "List of regexps saying which buffers should be displayed specially.
5373Displaying a buffer with `display-buffer' or `pop-to-buffer', if
5374any regexp in this list matches its name, displays it specially
5375using `special-display-function'. `special-display-popup-frame'
5376\(the default for `special-display-function') usually displays
5377the buffer in a separate frame made with the parameters specified
5378by `special-display-frame-alist'. If `special-display-function'
5379has been set to some other function, that function is called with
5380the buffer as first, and nil as second argument.
5381
5382Alternatively, an element of this list can be specified as
5383\(REGEXP FRAME-PARAMETERS), where REGEXP is a regexp as above and
5384FRAME-PARAMETERS an alist of (PARAMETER . VALUE) pairs.
5385`special-display-popup-frame' will then interpret these pairs as
5386frame parameters when creating a special frame for a buffer whose
5387name matches REGEXP, overriding the corresponding values from
5388`special-display-frame-alist'.
5389
5390As a special case, if FRAME-PARAMETERS contains (same-window . t)
5391`special-display-popup-frame' displays buffers matching REGEXP in
382c953b 5392the selected window. (same-frame . t) in FRAME-PARAMETERS means
56f31926
MR
5393to display such buffers in a window on the selected frame.
5394
5395If `special-display-function' specifies some other function than
5396`special-display-popup-frame', that function is called with the
5397buffer whose name matched REGEXP as first, and FRAME-PARAMETERS
5398as second argument.
5399
5400Finally, an element of this list can be also specified as
5401\(REGEXP FUNCTION OTHER-ARGS). `special-display-popup-frame'
5402will then call FUNCTION with the buffer whose name matched
0563dae9
MR
5403REGEXP as first, and OTHER-ARGS as second argument.
5404
5405Any alternative function specified here is responsible for
5406setting up the quit-restore parameter of the window used.
56f31926
MR
5407
5408If this variable appears \"not to work\", because you added a
5409name to it but the corresponding buffer is displayed in the
5410selected window, look at the values of `same-window-buffer-names'
5411and `same-window-regexps'. Those variables take precedence over
5412this one.
5413
5414See also `special-display-buffer-names'."
5415 :type '(repeat
5416 (choice :tag "Buffer"
5417 :value ""
5418 (regexp :format "%v")
5419 (cons :tag "With parameters"
5420 :format "%v"
5421 :value ("" . nil)
5422 (regexp :format "%v")
5423 (repeat :tag "Parameters"
5424 (cons :format "%v"
5425 (symbol :tag "Parameter")
5426 (sexp :tag "Value"))))
5427 (list :tag "With function"
5428 :format "%v"
5429 :value ("" . nil)
5430 (regexp :format "%v")
5431 (function :tag "Function")
5432 (repeat :tag "Arguments" (sexp)))))
5433 :group 'windows
5434 :group 'frames)
77f1f99c
CY
5435(make-obsolete-variable 'special-display-regexps 'display-buffer-alist "24.3")
5436(put 'special-display-regexps 'risky-local-variable t)
56f31926 5437
3c448ab6
MR
5438(defun special-display-p (buffer-name)
5439 "Return non-nil if a buffer named BUFFER-NAME gets a special frame.
56f31926
MR
5440More precisely, return t if `special-display-buffer-names' or
5441`special-display-regexps' contain a string entry equaling or
5442matching BUFFER-NAME. If `special-display-buffer-names' or
5443`special-display-regexps' contain a list entry whose car equals
5444or matches BUFFER-NAME, the return value is the cdr of that
5445entry."
f818cd2a 5446 (let (tmp)
98722073 5447 (cond
f818cd2a 5448 ((member buffer-name special-display-buffer-names)
98722073 5449 t)
f818cd2a 5450 ((setq tmp (assoc buffer-name special-display-buffer-names))
98722073
MR
5451 (cdr tmp))
5452 ((catch 'found
f818cd2a 5453 (dolist (regexp special-display-regexps)
98722073
MR
5454 (cond
5455 ((stringp regexp)
5456 (when (string-match-p regexp buffer-name)
5457 (throw 'found t)))
5458 ((and (consp regexp) (stringp (car regexp))
5459 (string-match-p (car regexp) buffer-name))
5460 (throw 'found (cdr regexp))))))))))
9481c002 5461
f818cd2a
MR
5462(defcustom special-display-frame-alist
5463 '((height . 14) (width . 80) (unsplittable . t))
5464 "Alist of parameters for special frames.
5465Special frames are used for buffers whose names are listed in
5466`special-display-buffer-names' and for buffers whose names match
5467one of the regular expressions in `special-display-regexps'.
9481c002 5468
f818cd2a 5469This variable can be set in your init file, like this:
9481c002 5470
f818cd2a
MR
5471 (setq special-display-frame-alist '((width . 80) (height . 20)))
5472
5473These supersede the values given in `default-frame-alist'."
5474 :type '(repeat (cons :format "%v"
5475 (symbol :tag "Parameter")
5476 (sexp :tag "Value")))
5477 :group 'frames)
77f1f99c 5478(make-obsolete-variable 'special-display-frame-alist 'display-buffer-alist "24.3")
f818cd2a
MR
5479
5480(defun special-display-popup-frame (buffer &optional args)
31cd32c9 5481 "Pop up a frame displaying BUFFER and return its window.
f818cd2a
MR
5482If BUFFER is already displayed in a visible or iconified frame,
5483raise that frame. Otherwise, display BUFFER in a new frame.
5484
5485Optional argument ARGS is a list specifying additional
5486information.
5487
5488If ARGS is an alist, use it as a list of frame parameters. If
382c953b
JB
5489these parameters contain (same-window . t), display BUFFER in
5490the selected window. If they contain (same-frame . t), display
f818cd2a
MR
5491BUFFER in a window of the selected frame.
5492
5493If ARGS is a list whose car is a symbol, use (car ARGS) as a
fdc2806d
CY
5494function to do the work. Pass it BUFFER as first argument, and
5495pass the elements of (cdr ARGS) as the remaining arguments."
f818cd2a
MR
5496 (if (and args (symbolp (car args)))
5497 (apply (car args) buffer (cdr args))
5498 (let ((window (get-buffer-window buffer 0)))
5499 (or
5500 ;; If we have a window already, make it visible.
5501 (when window
5502 (let ((frame (window-frame window)))
5503 (make-frame-visible frame)
5504 (raise-frame frame)
cf4eacfd 5505 (display-buffer-record-window 'reuse window buffer)
f818cd2a
MR
5506 window))
5507 ;; Reuse the current window if the user requested it.
5508 (when (cdr (assq 'same-window args))
5509 (condition-case nil
5510 (progn (switch-to-buffer buffer nil t) (selected-window))
5511 (error nil)))
5512 ;; Stay on the same frame if requested.
5513 (when (or (cdr (assq 'same-frame args)) (cdr (assq 'same-window args)))
5514 (let* ((pop-up-windows t)
5515 pop-up-frames
5516 special-display-buffer-names special-display-regexps)
5517 (display-buffer buffer)))
5518 ;; If no window yet, make one in a new frame.
e75852fd
MR
5519 (let* ((frame
5520 (with-current-buffer buffer
5521 (make-frame (append args special-display-frame-alist))))
5522 (window (frame-selected-window frame)))
5523 (display-buffer-record-window 'frame window buffer)
c5e28e39
MR
5524 (unless (eq buffer (window-buffer window))
5525 (set-window-buffer window buffer)
5526 (set-window-prev-buffers window nil))
e75852fd
MR
5527 (set-window-dedicated-p window t)
5528 window)))))
f818cd2a
MR
5529
5530(defcustom special-display-function 'special-display-popup-frame
5531 "Function to call for displaying special buffers.
5532This function is called with two arguments - the buffer and,
5533optionally, a list - and should return a window displaying that
5534buffer. The default value usually makes a separate frame for the
5535buffer using `special-display-frame-alist' to specify the frame
5536parameters. See the definition of `special-display-popup-frame'
5537for how to specify such a function.
5538
5539A buffer is special when its name is either listed in
5540`special-display-buffer-names' or matches a regexp in
5541`special-display-regexps'.
5542
e1c2c6f2
MR
5543The specified function should call `display-buffer-record-window'
5544with corresponding arguments to set up the quit-restore parameter
5545of the window used."
f818cd2a
MR
5546 :type 'function
5547 :group 'frames)
77f1f99c 5548(make-obsolete-variable 'special-display-function 'display-buffer-alist "24.3")
f818cd2a
MR
5549
5550(defcustom same-window-buffer-names nil
5551 "List of names of buffers that should appear in the \"same\" window.
5552`display-buffer' and `pop-to-buffer' show a buffer whose name is
5553on this list in the selected rather than some other window.
5554
5555An element of this list can be a cons cell instead of just a
5556string. In that case, the cell's car must be a string specifying
5557the buffer name. This is for compatibility with
5558`special-display-buffer-names'; the cdr of the cons cell is
5559ignored.
5560
5561See also `same-window-regexps'."
5562 :type '(repeat (string :format "%v"))
5563 :group 'windows)
5564
5565(defcustom same-window-regexps nil
5566 "List of regexps saying which buffers should appear in the \"same\" window.
5567`display-buffer' and `pop-to-buffer' show a buffer whose name
5568matches a regexp on this list in the selected rather than some
5569other window.
5570
5571An element of this list can be a cons cell instead of just a
5572string. In that case, the cell's car must be a regexp matching
5573the buffer name. This is for compatibility with
5574`special-display-regexps'; the cdr of the cons cell is ignored.
9481c002 5575
f818cd2a
MR
5576See also `same-window-buffer-names'."
5577 :type '(repeat (regexp :format "%v"))
5578 :group 'windows)
9481c002 5579
f818cd2a
MR
5580(defun same-window-p (buffer-name)
5581 "Return non-nil if a buffer named BUFFER-NAME would be shown in the \"same\" window.
5582This function returns non-nil if `display-buffer' or
5583`pop-to-buffer' would show a buffer named BUFFER-NAME in the
382c953b 5584selected rather than (as usual) some other window. See
f818cd2a
MR
5585`same-window-buffer-names' and `same-window-regexps'."
5586 (cond
5587 ((not (stringp buffer-name)))
5588 ;; The elements of `same-window-buffer-names' can be buffer
5589 ;; names or cons cells whose cars are buffer names.
5590 ((member buffer-name same-window-buffer-names))
5591 ((assoc buffer-name same-window-buffer-names))
5592 ((catch 'found
5593 (dolist (regexp same-window-regexps)
5594 ;; The elements of `same-window-regexps' can be regexps
5595 ;; or cons cells whose cars are regexps.
5596 (when (or (and (stringp regexp)
cb882333 5597 (string-match-p regexp buffer-name))
f818cd2a
MR
5598 (and (consp regexp) (stringp (car regexp))
5599 (string-match-p (car regexp) buffer-name)))
5600 (throw 'found t)))))))
3c448ab6 5601
d1067961 5602(defcustom pop-up-frames nil
3c448ab6 5603 "Whether `display-buffer' should make a separate frame.
d1f18ec0 5604If nil, never make a separate frame.
3c448ab6
MR
5605If the value is `graphic-only', make a separate frame
5606on graphic displays only.
5607Any other non-nil value means always make a separate frame."
5608 :type '(choice
5609 (const :tag "Never" nil)
5610 (const :tag "On graphic displays only" graphic-only)
5611 (const :tag "Always" t))
f818cd2a 5612 :group 'windows)
3c448ab6 5613
d1067961 5614(defcustom display-buffer-reuse-frames nil
f818cd2a 5615 "Non-nil means `display-buffer' should reuse frames.
3c448ab6
MR
5616If the buffer in question is already displayed in a frame, raise
5617that frame."
5618 :type 'boolean
d1067961 5619 :version "21.1"
f818cd2a 5620 :group 'windows)
24777832
CY
5621
5622(make-obsolete-variable
5623 'display-buffer-reuse-frames
5624 "use a `reusable-frames' alist entry in `display-buffer-alist'."
5625 "24.3")
3c448ab6 5626
4dc2a129
MR
5627(defcustom pop-up-windows t
5628 "Non-nil means `display-buffer' should make a new window."
3c448ab6
MR
5629 :type 'boolean
5630 :group 'windows)
5631
8b10a2d1 5632(defcustom split-window-preferred-function 'split-window-sensibly
f818cd2a 5633 "Function called by `display-buffer' routines to split a window.
8b10a2d1
MR
5634This function is called with a window as single argument and is
5635supposed to split that window and return the new window. If the
5636window can (or shall) not be split, it is supposed to return nil.
5637The default is to call the function `split-window-sensibly' which
5638tries to split the window in a way which seems most suitable.
5639You can customize the options `split-height-threshold' and/or
5640`split-width-threshold' in order to have `split-window-sensibly'
5641prefer either vertical or horizontal splitting.
5642
f818cd2a
MR
5643If you set this to any other function, bear in mind that the
5644`display-buffer' routines may call this function two times. The
5645argument of the first call is the largest window on its frame.
5646If that call fails to return a live window, the function is
5647called again with the least recently used window as argument. If
5648that call fails too, `display-buffer' will use an existing window
5649to display its buffer.
8b10a2d1
MR
5650
5651The window selected at the time `display-buffer' was invoked is
5652still selected when this function is called. Hence you can
5653compare the window argument with the value of `selected-window'
5654if you intend to split the selected window instead or if you do
5655not want to split the selected window."
5656 :type 'function
3c448ab6
MR
5657 :version "23.1"
5658 :group 'windows)
5659
8b10a2d1 5660(defcustom split-height-threshold 80
f818cd2a
MR
5661 "Minimum height for splitting windows sensibly.
5662If this is an integer, `split-window-sensibly' may split a window
8b10a2d1 5663vertically only if it has at least this many lines. If this is
f818cd2a
MR
5664nil, `split-window-sensibly' is not allowed to split a window
5665vertically. If, however, a window is the only window on its
5666frame, `split-window-sensibly' may split it vertically
5667disregarding the value of this variable."
8b10a2d1 5668 :type '(choice (const nil) (integer :tag "lines"))
3c448ab6
MR
5669 :version "23.1"
5670 :group 'windows)
5671
8b10a2d1 5672(defcustom split-width-threshold 160
f818cd2a
MR
5673 "Minimum width for splitting windows sensibly.
5674If this is an integer, `split-window-sensibly' may split a window
8b10a2d1 5675horizontally only if it has at least this many columns. If this
f818cd2a
MR
5676is nil, `split-window-sensibly' is not allowed to split a window
5677horizontally."
8b10a2d1 5678 :type '(choice (const nil) (integer :tag "columns"))
3c448ab6
MR
5679 :version "23.1"
5680 :group 'windows)
9481c002 5681
8b10a2d1
MR
5682(defun window-splittable-p (window &optional horizontal)
5683 "Return non-nil if `split-window-sensibly' may split WINDOW.
5684Optional argument HORIZONTAL nil or omitted means check whether
5685`split-window-sensibly' may split WINDOW vertically. HORIZONTAL
5686non-nil means check whether WINDOW may be split horizontally.
3c448ab6 5687
8b10a2d1 5688WINDOW may be split vertically when the following conditions
3c448ab6 5689hold:
3c448ab6
MR
5690- `window-size-fixed' is either nil or equals `width' for the
5691 buffer of WINDOW.
8b10a2d1 5692- `split-height-threshold' is an integer and WINDOW is at least as
3c448ab6 5693 high as `split-height-threshold'.
3c448ab6
MR
5694- When WINDOW is split evenly, the emanating windows are at least
5695 `window-min-height' lines tall and can accommodate at least one
5696 line plus - if WINDOW has one - a mode line.
5697
8b10a2d1 5698WINDOW may be split horizontally when the following conditions
3c448ab6 5699hold:
3c448ab6
MR
5700- `window-size-fixed' is either nil or equals `height' for the
5701 buffer of WINDOW.
8b10a2d1 5702- `split-width-threshold' is an integer and WINDOW is at least as
3c448ab6 5703 wide as `split-width-threshold'.
3c448ab6
MR
5704- When WINDOW is split evenly, the emanating windows are at least
5705 `window-min-width' or two (whichever is larger) columns wide."
5706 (when (window-live-p window)
5707 (with-current-buffer (window-buffer window)
5708 (if horizontal
5709 ;; A window can be split horizontally when its width is not
5710 ;; fixed, it is at least `split-width-threshold' columns wide
5711 ;; and at least twice as wide as `window-min-width' and 2 (the
5712 ;; latter value is hardcoded).
5713 (and (memq window-size-fixed '(nil height))
5714 ;; Testing `window-full-width-p' here hardly makes any
5715 ;; sense nowadays. This can be done more intuitively by
5716 ;; setting up `split-width-threshold' appropriately.
5717 (numberp split-width-threshold)
5718 (>= (window-width window)
5719 (max split-width-threshold
5720 (* 2 (max window-min-width 2)))))
5721 ;; A window can be split vertically when its height is not
5722 ;; fixed, it is at least `split-height-threshold' lines high,
5723 ;; and it is at least twice as high as `window-min-height' and 2
37269466 5724 ;; if it has a mode line or 1.
3c448ab6
MR
5725 (and (memq window-size-fixed '(nil width))
5726 (numberp split-height-threshold)
5727 (>= (window-height window)
5728 (max split-height-threshold
5729 (* 2 (max window-min-height
5730 (if mode-line-format 2 1))))))))))
5731
2dc2a609 5732(defun split-window-sensibly (&optional window)
8b10a2d1 5733 "Split WINDOW in a way suitable for `display-buffer'.
2dc2a609 5734WINDOW defaults to the currently selected window.
8b10a2d1
MR
5735If `split-height-threshold' specifies an integer, WINDOW is at
5736least `split-height-threshold' lines tall and can be split
5737vertically, split WINDOW into two windows one above the other and
5738return the lower window. Otherwise, if `split-width-threshold'
5739specifies an integer, WINDOW is at least `split-width-threshold'
5740columns wide and can be split horizontally, split WINDOW into two
5741windows side by side and return the window on the right. If this
5742can't be done either and WINDOW is the only window on its frame,
5743try to split WINDOW vertically disregarding any value specified
5744by `split-height-threshold'. If that succeeds, return the lower
5745window. Return nil otherwise.
5746
5747By default `display-buffer' routines call this function to split
5748the largest or least recently used window. To change the default
5749customize the option `split-window-preferred-function'.
5750
5751You can enforce this function to not split WINDOW horizontally,
382c953b 5752by setting (or binding) the variable `split-width-threshold' to
8b10a2d1
MR
5753nil. If, in addition, you set `split-height-threshold' to zero,
5754chances increase that this function does split WINDOW vertically.
5755
382c953b 5756In order to not split WINDOW vertically, set (or bind) the
8b10a2d1
MR
5757variable `split-height-threshold' to nil. Additionally, you can
5758set `split-width-threshold' to zero to make a horizontal split
5759more likely to occur.
5760
5761Have a look at the function `window-splittable-p' if you want to
5762know how `split-window-sensibly' determines whether WINDOW can be
5763split."
2dc2a609
TH
5764 (let ((window (or window (selected-window))))
5765 (or (and (window-splittable-p window)
5766 ;; Split window vertically.
5767 (with-selected-window window
5768 (split-window-below)))
5769 (and (window-splittable-p window t)
5770 ;; Split window horizontally.
5771 (with-selected-window window
5772 (split-window-right)))
5773 (and (eq window (frame-root-window (window-frame window)))
5774 (not (window-minibuffer-p window))
5775 ;; If WINDOW is the only window on its frame and is not the
5776 ;; minibuffer window, try to split it vertically disregarding
5777 ;; the value of `split-height-threshold'.
5778 (let ((split-height-threshold 0))
5779 (when (window-splittable-p window)
5780 (with-selected-window window
5781 (split-window-below))))))))
9481c002 5782
5938d519 5783(defun window--try-to-split-window (window &optional alist)
f818cd2a
MR
5784 "Try to split WINDOW.
5785Return value returned by `split-window-preferred-function' if it
5786represents a live window, nil otherwise."
5787 (and (window-live-p window)
5788 (not (frame-parameter (window-frame window) 'unsplittable))
8e17c9ba
MR
5789 (let* ((window-combination-limit
5790 ;; When `window-combination-limit' equals
5938d519
MR
5791 ;; `display-buffer' or equals `resize-window' and a
5792 ;; `window-height' or `window-width' alist entry are
5793 ;; present, bind it to t so resizing steals space
5794 ;; preferably from the window that was split.
5795 (if (or (eq window-combination-limit 'display-buffer)
5796 (and (eq window-combination-limit 'window-size)
5797 (or (cdr (assq 'window-height alist))
5798 (cdr (assq 'window-width alist)))))
8e17c9ba
MR
5799 t
5800 window-combination-limit))
5801 (new-window
5802 ;; Since `split-window-preferred-function' might
5803 ;; throw an error use `condition-case'.
5804 (condition-case nil
5805 (funcall split-window-preferred-function window)
5806 (error nil))))
f818cd2a
MR
5807 (and (window-live-p new-window) new-window))))
5808
5809(defun window--frame-usable-p (frame)
5810 "Return FRAME if it can be used to display a buffer."
5811 (when (frame-live-p frame)
5812 (let ((window (frame-root-window frame)))
5813 ;; `frame-root-window' may be an internal window which is considered
5814 ;; "dead" by `window-live-p'. Hence if `window' is not live we
5815 ;; implicitly know that `frame' has a visible window we can use.
5816 (unless (and (window-live-p window)
5817 (or (window-minibuffer-p window)
5818 ;; If the window is soft-dedicated, the frame is usable.
5819 ;; Actually, even if the window is really dedicated,
5820 ;; the frame is still usable by splitting it.
5821 ;; At least Emacs-22 allowed it, and it is desirable
5822 ;; when displaying same-frame windows.
5823 nil ; (eq t (window-dedicated-p window))
5824 ))
5825 frame))))
5826
5827(defcustom even-window-heights t
5828 "If non-nil `display-buffer' will try to even window heights.
5829Otherwise `display-buffer' will leave the window configuration
5830alone. Heights are evened only when `display-buffer' chooses a
5831window that appears above or below the selected window."
5832 :type 'boolean
5833 :group 'windows)
5834
5835(defun window--even-window-heights (window)
5836 "Even heights of WINDOW and selected window.
5837Do this only if these windows are vertically adjacent to each
5838other, `even-window-heights' is non-nil, and the selected window
5839is higher than WINDOW."
5840 (when (and even-window-heights
9aba119d
MR
5841 ;; Even iff WINDOW forms a vertical combination with the
5842 ;; selected window, and WINDOW's height exceeds that of the
5843 ;; selected window, see also bug#11880.
5844 (window-combined-p window)
5845 (= (window-child-count (window-parent window)) 2)
5846 (eq (window-parent) (window-parent window))
5847 (> (window-total-height) (window-total-height window)))
5848 ;; Don't throw an error if we can't even window heights for
5849 ;; whatever reason.
5850 (condition-case nil
5851 (enlarge-window
5852 (/ (- (window-total-height window) (window-total-height)) 2))
5853 (error nil))))
f818cd2a 5854
5938d519 5855(defun window--display-buffer (buffer window type &optional alist dedicated)
0ff7851c 5856 "Display BUFFER in WINDOW.
51a5f9d8 5857TYPE must be one of the symbols `reuse', `window' or `frame' and
0ff7851c
MR
5858is passed unaltered to `display-buffer-record-window'. ALIST is
5859the alist argument of `display-buffer'. Set `window-dedicated-p'
5860to DEDICATED if non-nil. Return WINDOW if BUFFER and WINDOW are
5861live."
f818cd2a 5862 (when (and (buffer-live-p buffer) (window-live-p window))
caceae25 5863 (display-buffer-record-window type window buffer)
90749b53
CY
5864 (unless (eq buffer (window-buffer window))
5865 (set-window-dedicated-p window nil)
90749b53
CY
5866 (set-window-buffer window buffer)
5867 (when dedicated
5868 (set-window-dedicated-p window dedicated))
5869 (when (memq type '(window frame))
5870 (set-window-prev-buffers window nil)))
2d6b6005 5871 (let ((parameter (window-parameter window 'quit-restore))
5938d519 5872 (height (cdr (assq 'window-height alist)))
880e6158
MR
5873 (width (cdr (assq 'window-width alist)))
5874 (size (cdr (assq 'window-size alist))))
5875 (cond
5876 ((or (eq type 'frame)
5877 (and (eq (car parameter) 'same)
5878 (eq (nth 1 parameter) 'frame)))
5879 ;; Adjust size of frame if asked for.
5880 (cond
5881 ((not size))
5882 ((consp size)
5883 (let ((width (car size))
5884 (height (cdr size))
2d6b6005 5885 (frame (window-frame window)))
880e6158
MR
5886 (when (and (numberp width) (numberp height))
5887 (set-frame-height
5888 frame (+ (frame-height frame)
5889 (- height (window-total-height window))))
5890 (set-frame-width
5891 frame (+ (frame-width frame)
5892 (- width (window-total-width window)))))))
5893 ((functionp size)
5894 (ignore-errors (funcall size window)))))
5895 ((or (eq type 'window)
5896 (and (eq (car parameter) 'same)
5897 (eq (nth 1 parameter) 'window)))
0ff7851c 5898 ;; Adjust height of window if asked for.
5938d519
MR
5899 (cond
5900 ((not height))
5901 ((numberp height)
5902 (let* ((new-height
5903 (if (integerp height)
5904 height
5905 (round
880e6158 5906 (* (window-total-height (frame-root-window window))
5938d519 5907 height))))
880e6158
MR
5908 (delta (- new-height (window-total-height window))))
5909 (when (and (window--resizable-p window delta nil 'safe)
0ff7851c
MR
5910 (window-combined-p window))
5911 (window-resize window delta nil 'safe))))
5938d519
MR
5912 ((functionp height)
5913 (ignore-errors (funcall height window))))
0ff7851c 5914 ;; Adjust width of window if asked for.
5938d519
MR
5915 (cond
5916 ((not width))
5917 ((numberp width)
5918 (let* ((new-width
5919 (if (integerp width)
5920 width
5921 (round
880e6158 5922 (* (window-total-width (frame-root-window window))
5938d519 5923 width))))
880e6158
MR
5924 (delta (- new-width (window-total-width window))))
5925 (when (and (window--resizable-p window delta t 'safe)
0ff7851c
MR
5926 (window-combined-p window t))
5927 (window-resize window delta t 'safe))))
5938d519 5928 ((functionp width)
880e6158 5929 (ignore-errors (funcall width window)))))))
0ff7851c 5930
90749b53
CY
5931 window))
5932
5933(defun window--maybe-raise-frame (frame)
5934 (let ((visible (frame-visible-p frame)))
5935 (unless (or (not visible)
5936 ;; Assume the selected frame is already visible enough.
5937 (eq frame (selected-frame))
5938 ;; Assume the frame from which we invoked the
5939 ;; minibuffer is visible.
5940 (and (minibuffer-window-active-p (selected-window))
5941 (eq frame (window-frame (minibuffer-selected-window)))))
5942 (raise-frame frame))))
f818cd2a 5943
24510c22
SM
5944;; FIXME: Not implemented.
5945;; FIXME: By the way, there could be more levels of dedication:
5946;; - `barely' dedicated doesn't prevent reuse of the window, only records that
5947;; the window hasn't been used for something else yet.
5948;; - `softly' dedicated only allows reuse when asked explicitly.
5949;; - `strongly' never allows reuse.
f818cd2a
MR
5950(defvar display-buffer-mark-dedicated nil
5951 "If non-nil, `display-buffer' marks the windows it creates as dedicated.
5952The actual non-nil value of this variable will be copied to the
5953`window-dedicated-p' flag.")
5954
fa5660f9
CY
5955(defconst display-buffer--action-function-custom-type
5956 '(choice :tag "Function"
5957 (const :tag "--" ignore) ; default for insertion
fa5660f9 5958 (const display-buffer-reuse-window)
d9558cad 5959 (const display-buffer-pop-up-window)
fa5660f9
CY
5960 (const display-buffer-same-window)
5961 (const display-buffer-pop-up-frame)
880e6158 5962 (const display-buffer-in-previous-window)
fa5660f9
CY
5963 (const display-buffer-use-some-window)
5964 (function :tag "Other function"))
5965 "Custom type for `display-buffer' action functions.")
5966
5967(defconst display-buffer--action-custom-type
5968 `(cons :tag "Action"
5969 (choice :tag "Action functions"
5970 ,display-buffer--action-function-custom-type
5971 (repeat
5972 :tag "List of functions"
5973 ,display-buffer--action-function-custom-type))
5974 (alist :tag "Action arguments"
5975 :key-type symbol
5976 :value-type (sexp :tag "Value")))
5977 "Custom type for `display-buffer' actions.")
5978
cbb0f9ab
CY
5979(defvar display-buffer-overriding-action '(nil . nil)
5980 "Overriding action to perform to display a buffer.
5981It should be a cons cell (FUNCTION . ALIST), where FUNCTION is a
382c953b 5982function or a list of functions. Each function should accept two
cbb0f9ab
CY
5983arguments: a buffer to display and an alist similar to ALIST.
5984See `display-buffer' for details.")
5985(put 'display-buffer-overriding-action 'risky-local-variable t)
5986
fa5660f9 5987(defcustom display-buffer-alist nil
89894cd8
CY
5988 "Alist of conditional actions for `display-buffer'.
5989This is a list of elements (CONDITION . ACTION), where:
5990
0ff7851c
MR
5991 CONDITION is either a regexp matching buffer names, or a
5992 function that takes two arguments - a buffer name and the
5993 ACTION argument of `display-buffer' - and returns a boolean.
89894cd8 5994
8319e0bf
CY
5995 ACTION is a cons cell (FUNCTION . ALIST), where FUNCTION is a
5996 function or a list of functions. Each such function should
382c953b 5997 accept two arguments: a buffer to display and an alist of the
f0cfa5fe 5998 same form as ALIST. See `display-buffer' for details.
0ff7851c
MR
5999
6000`display-buffer' scans this alist until it either finds a
6001matching regular expression or the function specified by a
9139632a
JL
6002condition returns non-nil. In any of these cases, it adds the
6003associated action to the list of actions it will try."
fa5660f9
CY
6004 :type `(alist :key-type
6005 (choice :tag "Condition"
6006 regexp
6007 (function :tag "Matcher function"))
6008 :value-type ,display-buffer--action-custom-type)
6009 :risky t
6010 :version "24.1"
6011 :group 'windows)
89894cd8 6012
cbb0f9ab
CY
6013(defcustom display-buffer-base-action '(nil . nil)
6014 "User-specified default action for `display-buffer'.
8319e0bf 6015It should be a cons cell (FUNCTION . ALIST), where FUNCTION is a
382c953b 6016function or a list of functions. Each function should accept two
fa5660f9
CY
6017arguments: a buffer to display and an alist similar to ALIST.
6018See `display-buffer' for details."
6019 :type display-buffer--action-custom-type
6020 :risky t
6021 :version "24.1"
6022 :group 'windows)
89894cd8 6023
cbb0f9ab 6024(defconst display-buffer-fallback-action
0a9f9ab5 6025 '((display-buffer--maybe-same-window ;FIXME: why isn't this redundant?
cbb0f9ab 6026 display-buffer-reuse-window
cbb0f9ab 6027 display-buffer--maybe-pop-up-frame-or-window
880e6158 6028 display-buffer-in-previous-window
cbb0f9ab
CY
6029 display-buffer-use-some-window
6030 ;; If all else fails, pop up a new frame.
6031 display-buffer-pop-up-frame))
6032 "Default fallback action for `display-buffer'.
6033This is the action used by `display-buffer' if no other actions
6034specified, e.g. by the user options `display-buffer-alist' or
6035`display-buffer-base-action'. See `display-buffer'.")
6036(put 'display-buffer-fallback-action 'risky-local-variable t)
f818cd2a 6037
0ff7851c
MR
6038(defun display-buffer-assq-regexp (buffer-name alist action)
6039 "Retrieve ALIST entry corresponding to BUFFER-NAME.
6040ACTION is the action argument passed to `display-buffer'."
f818cd2a
MR
6041 (catch 'match
6042 (dolist (entry alist)
cb882333 6043 (let ((key (car entry)))
f818cd2a
MR
6044 (when (or (and (stringp key)
6045 (string-match-p key buffer-name))
0ff7851c
MR
6046 (and (functionp key)
6047 (funcall key buffer-name action)))
f818cd2a
MR
6048 (throw 'match (cdr entry)))))))
6049
8319e0bf
CY
6050(defvar display-buffer--same-window-action
6051 '(display-buffer-same-window
6052 (inhibit-same-window . nil))
6053 "A `display-buffer' action for displaying in the same window.")
6054(put 'display-buffer--same-window-action 'risky-local-variable t)
6055
6056(defvar display-buffer--other-frame-action
6057 '((display-buffer-reuse-window
8319e0bf
CY
6058 display-buffer-pop-up-frame)
6059 (reusable-frames . 0)
6060 (inhibit-same-window . t))
6061 "A `display-buffer' action for displaying in another frame.")
6062(put 'display-buffer--other-frame-action 'risky-local-variable t)
6063
d45ba96b 6064(defun display-buffer (buffer-or-name &optional action frame)
3199b96f 6065 "Display BUFFER-OR-NAME in some window, without selecting it.
89894cd8
CY
6066BUFFER-OR-NAME must be a buffer or the name of an existing
6067buffer. Return the window chosen for displaying BUFFER-OR-NAME,
6068or nil if no such window is found.
6069
7b9abf24
EZ
6070Optional argument ACTION, if non-nil, should specify a display
6071action. Its form is described below.
6072
6073Optional argument FRAME, if non-nil, acts like an additional
6074ALIST entry (reusable-frames . FRAME) to the action list of ACTION,
6075specifying the frame(s) to search for a window that is already
6076displaying the buffer. See `display-buffer-reuse-window'
6077
6078If ACTION is non-nil, it should have the form (FUNCTION . ALIST),
6079where FUNCTION is either a function or a list of functions, and
d4bd55e7
CY
6080ALIST is an arbitrary association list (alist).
6081
6082Each such FUNCTION should accept two arguments: the buffer to
f130cb76
LL
6083display and an alist. Based on those arguments, it should
6084display the buffer and return the window. If the caller is
9139632a
JL
6085prepared to handle the case of not displaying the buffer
6086and returning nil from `display-buffer' it should pass
6087\(allow-no-window . t) as an element of the ALIST.
89894cd8 6088
cbb0f9ab 6089The `display-buffer' function builds a function list and an alist
d4bd55e7
CY
6090by combining the functions and alists specified in
6091`display-buffer-overriding-action', `display-buffer-alist', the
6092ACTION argument, `display-buffer-base-action', and
6093`display-buffer-fallback-action' (in order). Then it calls each
6094function in the combined function list in turn, passing the
cbb0f9ab
CY
6095buffer as the first argument and the combined alist as the second
6096argument, until one of the functions returns non-nil.
8319e0bf 6097
7b9abf24
EZ
6098If ACTION is nil, the function list and the alist are built using
6099only the other variables mentioned above.
6100
8319e0bf
CY
6101Available action functions include:
6102 `display-buffer-same-window'
8319e0bf
CY
6103 `display-buffer-reuse-window'
6104 `display-buffer-pop-up-frame'
6105 `display-buffer-pop-up-window'
880e6158 6106 `display-buffer-in-previous-window'
8319e0bf
CY
6107 `display-buffer-use-some-window'
6108
6109Recognized alist entries include:
6110
6111 `inhibit-same-window' -- A non-nil value prevents the same
6112 window from being used for display.
6113
90749b53
CY
6114 `inhibit-switch-frame' -- A non-nil value prevents any other
6115 frame from being raised or selected,
6116 even if the window is displayed there.
6117
8319e0bf
CY
6118 `reusable-frames' -- Value specifies frame(s) to search for a
6119 window that already displays the buffer.
6120 See `display-buffer-reuse-window'.
2a7bdc1a 6121
d97af5a0
CY
6122 `pop-up-frame-parameters' -- Value specifies an alist of frame
6123 parameters to give a new frame, if
6124 one is created.
6125
df171c23
MR
6126 `window-height' -- Value specifies either an integer (the number
6127 of lines of a new window), a floating point number (the
6128 fraction of a new window with respect to the height of the
6129 frame's root window) or a function to be called with one
6130 argument - a new window. The function is supposed to adjust
6131 the height of the window; its return value is ignored.
6132 Suitable functions are `shrink-window-if-larger-than-buffer'
6133 and `fit-window-to-buffer'.
6134
6135 `window-width' -- Value specifies either an integer (the number
6136 of columns of a new window), a floating point number (the
6137 fraction of a new window with respect to the width of the
6138 frame's root window) or a function to be called with one
6139 argument - a new window. The function is supposed to adjust
6140 the width of the window; its return value is ignored.
6141
9139632a
JL
6142 `allow-no-window' -- A non-nil value indicates readiness for the case
6143 of not displaying the buffer and FUNCTION can safely return
6144 a non-window value to suppress displaying.
6145
2a7bdc1a
CY
6146The ACTION argument to `display-buffer' can also have a non-nil
6147and non-list value. This means to display the buffer in a window
6148other than the selected one, even if it is already displayed in
6149the selected window. If called interactively with a prefix
7b9abf24 6150argument, ACTION is t."
c3313451
CY
6151 (interactive (list (read-buffer "Display buffer: " (other-buffer))
6152 (if current-prefix-arg t)))
d45ba96b
MR
6153 (let ((buffer (if (bufferp buffer-or-name)
6154 buffer-or-name
6155 (get-buffer buffer-or-name)))
f47ad11b
MR
6156 ;; Make sure that when we split windows the old window keeps
6157 ;; point, bug#14829.
6158 (split-window-keep-point t)
89894cd8
CY
6159 ;; Handle the old form of the first argument.
6160 (inhibit-same-window (and action (not (listp action)))))
6161 (unless (listp action) (setq action nil))
6162 (if display-buffer-function
6163 ;; If `display-buffer-function' is defined, let it do the job.
6164 (funcall display-buffer-function buffer inhibit-same-window)
6165 ;; Otherwise, use the defined actions.
6166 (let* ((user-action
0ff7851c
MR
6167 (display-buffer-assq-regexp
6168 (buffer-name buffer) display-buffer-alist action))
0a9f9ab5 6169 (special-action (display-buffer--special-action buffer))
89894cd8
CY
6170 ;; Extra actions from the arguments to this function:
6171 (extra-action
6172 (cons nil (append (if inhibit-same-window
6173 '((inhibit-same-window . t)))
6174 (if frame
8319e0bf 6175 `((reusable-frames . ,frame))))))
89894cd8
CY
6176 ;; Construct action function list and action alist.
6177 (actions (list display-buffer-overriding-action
0a9f9ab5 6178 user-action special-action action extra-action
cbb0f9ab
CY
6179 display-buffer-base-action
6180 display-buffer-fallback-action))
89894cd8
CY
6181 (functions (apply 'append
6182 (mapcar (lambda (x)
6183 (setq x (car x))
c3313451 6184 (if (functionp x) (list x) x))
89894cd8
CY
6185 actions)))
6186 (alist (apply 'append (mapcar 'cdr actions)))
6187 window)
6188 (unless (buffer-live-p buffer)
6189 (error "Invalid buffer"))
6190 (while (and functions (not window))
6191 (setq window (funcall (car functions) buffer alist)
6192 functions (cdr functions)))
f130cb76 6193 (and (windowp window) window)))))
f818cd2a
MR
6194
6195(defun display-buffer-other-frame (buffer)
e6f759f9 6196 "Display buffer BUFFER preferably in another frame.
f818cd2a
MR
6197This uses the function `display-buffer' as a subroutine; see
6198its documentation for additional customization information."
6199 (interactive "BDisplay buffer in other frame: ")
8319e0bf 6200 (display-buffer buffer display-buffer--other-frame-action t))
f818cd2a 6201
89894cd8 6202;;; `display-buffer' action functions:
437014c8 6203
89894cd8 6204(defun display-buffer-same-window (buffer alist)
8319e0bf
CY
6205 "Display BUFFER in the selected window.
6206This fails if ALIST has a non-nil `inhibit-same-window' entry, or
6207if the selected window is a minibuffer window or is dedicated to
6208another buffer; in that case, return nil. Otherwise, return the
6209selected window."
89894cd8
CY
6210 (unless (or (cdr (assq 'inhibit-same-window alist))
6211 (window-minibuffer-p)
6212 (window-dedicated-p))
5938d519 6213 (window--display-buffer buffer (selected-window) 'reuse alist)))
89894cd8 6214
0d3ff375 6215(defun display-buffer--maybe-same-window (buffer alist)
8319e0bf
CY
6216 "Conditionally display BUFFER in the selected window.
6217If `same-window-p' returns non-nil for BUFFER's name, call
6218`display-buffer-same-window' and return its value. Otherwise,
6219return nil."
89894cd8
CY
6220 (and (same-window-p (buffer-name buffer))
6221 (display-buffer-same-window buffer alist)))
6222
6223(defun display-buffer-reuse-window (buffer alist)
6224 "Return a window that is already displaying BUFFER.
8319e0bf
CY
6225Return nil if no usable window is found.
6226
6227If ALIST has a non-nil `inhibit-same-window' entry, the selected
6228window is not eligible for reuse.
6229
6230If ALIST contains a `reusable-frames' entry, its value determines
6231which frames to search for a reusable window:
6232 nil -- the selected frame (actually the last non-minibuffer frame)
6233 A frame -- just that frame
6234 `visible' -- all visible frames
6235 0 -- all frames on the current terminal
6236 t -- all frames.
6237
6238If ALIST contains no `reusable-frames' entry, search just the
6239selected frame if `display-buffer-reuse-frames' and
6240`pop-up-frames' are both nil; search all frames on the current
90749b53
CY
6241terminal if either of those variables is non-nil.
6242
6243If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
6244event that a window on another frame is chosen, avoid raising
6245that frame."
8319e0bf
CY
6246 (let* ((alist-entry (assq 'reusable-frames alist))
6247 (frames (cond (alist-entry (cdr alist-entry))
6248 ((if (eq pop-up-frames 'graphic-only)
6249 (display-graphic-p)
6250 pop-up-frames)
6251 0)
6252 (display-buffer-reuse-frames 0)
6253 (t (last-nonminibuffer-frame))))
6254 (window (if (and (eq buffer (window-buffer))
6255 (not (cdr (assq 'inhibit-same-window alist))))
6256 (selected-window)
6257 (car (delq (selected-window)
6258 (get-buffer-window-list buffer 'nomini
6259 frames))))))
90749b53 6260 (when (window-live-p window)
5938d519 6261 (prog1 (window--display-buffer buffer window 'reuse alist)
90749b53
CY
6262 (unless (cdr (assq 'inhibit-switch-frame alist))
6263 (window--maybe-raise-frame (window-frame window)))))))
89894cd8 6264
0a9f9ab5 6265(defun display-buffer--special-action (buffer)
4ad3bc2a
CY
6266 "Return special display action for BUFFER, if any.
6267If `special-display-p' returns non-nil for BUFFER, return an
6268appropriate display action involving `special-display-function'.
6269See `display-buffer' for the format of display actions."
8319e0bf
CY
6270 (and special-display-function
6271 ;; `special-display-p' returns either t or a list of frame
6272 ;; parameters to pass to `special-display-function'.
6273 (let ((pars (special-display-p (buffer-name buffer))))
6274 (when pars
0a9f9ab5
SM
6275 (list (list #'display-buffer-reuse-window
6276 `(lambda (buffer _alist)
6277 (funcall special-display-function
6278 buffer ',(if (listp pars) pars)))))))))
8319e0bf 6279
90749b53 6280(defun display-buffer-pop-up-frame (buffer alist)
89894cd8 6281 "Display BUFFER in a new frame.
8319e0bf 6282This works by calling `pop-up-frame-function'. If successful,
90749b53
CY
6283return the window used; otherwise return nil.
6284
6285If ALIST has a non-nil `inhibit-switch-frame' entry, avoid
d97af5a0
CY
6286raising the new frame.
6287
6288If ALIST has a non-nil `pop-up-frame-parameters' entry, the
6289corresponding value is an alist of frame parameters to give the
6290new frame."
6291 (let* ((params (cdr (assq 'pop-up-frame-parameters alist)))
6292 (pop-up-frame-alist (append params pop-up-frame-alist))
6293 (fun pop-up-frame-function)
6294 frame window)
89894cd8 6295 (when (and fun
7fd5f65e
MR
6296 ;; Make BUFFER current so `make-frame' will use it as the
6297 ;; new frame's buffer (Bug#15133).
6298 (with-current-buffer buffer
6299 (setq frame (funcall fun)))
89894cd8 6300 (setq window (frame-selected-window frame)))
5938d519
MR
6301 (prog1 (window--display-buffer
6302 buffer window 'frame alist display-buffer-mark-dedicated)
90749b53
CY
6303 (unless (cdr (assq 'inhibit-switch-frame alist))
6304 (window--maybe-raise-frame frame))))))
89894cd8 6305
90749b53 6306(defun display-buffer-pop-up-window (buffer alist)
89894cd8
CY
6307 "Display BUFFER by popping up a new window.
6308The new window is created on the selected frame, or in
6309`last-nonminibuffer-frame' if no windows can be created there.
90749b53
CY
6310If successful, return the new window; otherwise return nil.
6311
6312If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
6313event that the new window is created on another frame, avoid
6314raising the frame."
89894cd8
CY
6315 (let ((frame (or (window--frame-usable-p (selected-frame))
6316 (window--frame-usable-p (last-nonminibuffer-frame))))
6317 window)
6318 (when (and (or (not (frame-parameter frame 'unsplittable))
6319 ;; If the selected frame cannot be split, look at
6320 ;; `last-nonminibuffer-frame'.
6321 (and (eq frame (selected-frame))
6322 (setq frame (last-nonminibuffer-frame))
6323 (window--frame-usable-p frame)
6324 (not (frame-parameter frame 'unsplittable))))
6325 ;; Attempt to split largest or least recently used window.
6326 (setq window (or (window--try-to-split-window
5938d519 6327 (get-largest-window frame t) alist)
89894cd8 6328 (window--try-to-split-window
5938d519
MR
6329 (get-lru-window frame t) alist))))
6330 (prog1 (window--display-buffer
6331 buffer window 'window alist display-buffer-mark-dedicated)
90749b53
CY
6332 (unless (cdr (assq 'inhibit-switch-frame alist))
6333 (window--maybe-raise-frame (window-frame window)))))))
89894cd8 6334
8319e0bf
CY
6335(defun display-buffer--maybe-pop-up-frame-or-window (buffer alist)
6336 "Try displaying BUFFER based on `pop-up-frames' or `pop-up-windows'.
6337
6338If `pop-up-frames' is non-nil (and not `graphic-only' on a
6339text-only terminal), try with `display-buffer-pop-up-frame'.
6340
6341If that cannot be done, and `pop-up-windows' is non-nil, try
6342again with `display-buffer-pop-up-window'."
6343 (or (and (if (eq pop-up-frames 'graphic-only)
6344 (display-graphic-p)
6345 pop-up-frames)
6346 (display-buffer-pop-up-frame buffer alist))
6347 (and pop-up-windows
6348 (display-buffer-pop-up-window buffer alist))))
89894cd8 6349
5938d519 6350(defun display-buffer-below-selected (buffer alist)
78dd6ab1
MR
6351 "Try displaying BUFFER in a window below the selected window.
6352This either splits the selected window or reuses the window below
6353the selected one."
6354 (let (window)
6355 (or (and (not (frame-parameter nil 'unsplittable))
d144ef06
MR
6356 (let ((split-height-threshold 0)
6357 split-width-threshold)
f93cc74f 6358 (setq window (window--try-to-split-window (selected-window) alist)))
78dd6ab1 6359 (window--display-buffer
5938d519 6360 buffer window 'window alist display-buffer-mark-dedicated))
78dd6ab1
MR
6361 (and (setq window (window-in-direction 'below))
6362 (not (window-dedicated-p window))
6363 (window--display-buffer
5938d519 6364 buffer window 'reuse alist display-buffer-mark-dedicated)))))
8e17c9ba 6365
5938d519 6366(defun display-buffer-at-bottom (buffer alist)
735135f9 6367 "Try displaying BUFFER in a window at the bottom of the selected frame.
8e17c9ba
MR
6368This either splits the window at the bottom of the frame or the
6369frame's root window, or reuses an existing window at the bottom
6370of the selected frame."
6371 (let (bottom-window window)
c660a885
MR
6372 (walk-window-tree
6373 (lambda (window) (setq bottom-window window)) nil nil 'nomini)
8e17c9ba 6374 (or (and (not (frame-parameter nil 'unsplittable))
00139435
MR
6375 (let (split-width-threshold)
6376 (setq window (window--try-to-split-window bottom-window alist)))
8e17c9ba 6377 (window--display-buffer
5938d519 6378 buffer window 'window alist display-buffer-mark-dedicated))
8e17c9ba
MR
6379 (and (not (frame-parameter nil 'unsplittable))
6380 (setq window
6381 (condition-case nil
c660a885 6382 (split-window (window--major-non-side-window))
8e17c9ba
MR
6383 (error nil)))
6384 (window--display-buffer
5938d519 6385 buffer window 'window alist display-buffer-mark-dedicated))
8e17c9ba
MR
6386 (and (setq window bottom-window)
6387 (not (window-dedicated-p window))
6388 (window--display-buffer
5938d519 6389 buffer window 'reuse alist display-buffer-mark-dedicated)))))
78dd6ab1 6390
fa2bcf43
MR
6391(defun display-buffer-in-previous-window (buffer alist)
6392 "Display BUFFER in a window previously showing it.
6393If ALIST has a non-nil `inhibit-same-window' entry, the selected
6394window is not eligible for reuse.
6395
6396If ALIST contains a `reusable-frames' entry, its value determines
6397which frames to search for a reusable window:
6398 nil -- the selected frame (actually the last non-minibuffer frame)
6399 A frame -- just that frame
6400 `visible' -- all visible frames
6401 0 -- all frames on the current terminal
6402 t -- all frames.
6403
6404If ALIST contains no `reusable-frames' entry, search just the
6405selected frame if `display-buffer-reuse-frames' and
6406`pop-up-frames' are both nil; search all frames on the current
6407terminal if either of those variables is non-nil.
6408
6409If ALIST has a `previous-window' entry, the window specified by
6410that entry will override any other window found by the methods
6411above, even if that window never showed BUFFER before."
6412 (let* ((alist-entry (assq 'reusable-frames alist))
6413 (inhibit-same-window
6414 (cdr (assq 'inhibit-same-window alist)))
6415 (frames (cond
6416 (alist-entry (cdr alist-entry))
6417 ((if (eq pop-up-frames 'graphic-only)
6418 (display-graphic-p)
6419 pop-up-frames)
6420 0)
6421 (display-buffer-reuse-frames 0)
6422 (t (last-nonminibuffer-frame))))
9d3aa82c 6423 best-window second-best-window window)
fa2bcf43
MR
6424 ;; Scan windows whether they have shown the buffer recently.
6425 (catch 'best
6426 (dolist (window (window-list-1 (frame-first-window) 'nomini frames))
6427 (when (and (assq buffer (window-prev-buffers window))
6428 (not (window-dedicated-p window)))
6429 (if (eq window (selected-window))
6430 (unless inhibit-same-window
6431 (setq second-best-window window))
6432 (setq best-window window)
6433 (throw 'best t)))))
6434 ;; When ALIST has a `previous-window' entry, that entry may override
6435 ;; anything we found so far.
6436 (when (and (setq window (cdr (assq 'previous-window alist)))
6437 (window-live-p window)
6438 (not (window-dedicated-p window)))
6439 (if (eq window (selected-window))
6440 (unless inhibit-same-window
6441 (setq second-best-window window))
6442 (setq best-window window)))
6443 ;; Return best or second best window found.
6444 (when (setq window (or best-window second-best-window))
5938d519 6445 (window--display-buffer buffer window 'reuse alist))))
fa2bcf43 6446
89894cd8
CY
6447(defun display-buffer-use-some-window (buffer alist)
6448 "Display BUFFER in an existing window.
6449Search for a usable window, set that window to the buffer, and
90749b53
CY
6450return the window. If no suitable window is found, return nil.
6451
6452If ALIST has a non-nil `inhibit-switch-frame' entry, then in the
6453event that a window in another frame is chosen, avoid raising
6454that frame."
89894cd8 6455 (let* ((not-this-window (cdr (assq 'inhibit-same-window alist)))
89894cd8
CY
6456 (frame (or (window--frame-usable-p (selected-frame))
6457 (window--frame-usable-p (last-nonminibuffer-frame))))
51a5f9d8
MR
6458 (window
6459 ;; Reuse an existing window.
6460 (or (get-lru-window frame nil not-this-window)
6461 (let ((window (get-buffer-window buffer 'visible)))
6462 (unless (and not-this-window
6463 (eq window (selected-window)))
6464 window))
6465 (get-largest-window 'visible nil not-this-window)
6466 (let ((window (get-buffer-window buffer 0)))
6467 (unless (and not-this-window
6468 (eq window (selected-window)))
6469 window))
880e6158
MR
6470 (get-largest-window 0 nil not-this-window)))
6471 (quit-restore (and (window-live-p window)
6472 (window-parameter window 'quit-restore)))
6473 (quad (nth 1 quit-restore)))
90749b53 6474 (when (window-live-p window)
880e6158
MR
6475 ;; If the window was used by `display-buffer' before, try to
6476 ;; resize it to its old height but don't signal an error.
6477 (when (and (listp quad)
6478 (integerp (nth 3 quad))
6479 (/= (nth 3 quad) (window-total-height window)))
6480 (condition-case nil
6481 (window-resize window (- (nth 3 quad) (window-total-height window)))
6482 (error nil)))
6483
9aba119d 6484 (prog1
5938d519 6485 (window--display-buffer buffer window 'reuse alist)
9aba119d 6486 (window--even-window-heights window)
90749b53
CY
6487 (unless (cdr (assq 'inhibit-switch-frame alist))
6488 (window--maybe-raise-frame (window-frame window)))))))
437014c8 6489
2d6b6005 6490(defun display-buffer-no-window (_buffer alist)
9139632a
JL
6491 "Display BUFFER in no window.
6492If ALIST has a non-nil `allow-no-window' entry, then don't display
6493a window at all. This makes possible to override the default action
6494and avoid displaying the buffer. It is assumed that when the caller
6495specifies a non-nil `allow-no-window' then it can handle a nil value
6496returned from `display-buffer' in this case."
6497 (when (cdr (assq 'allow-no-window alist))
6498 'fail))
6499
437014c8 6500;;; Display + selection commands:
c3313451
CY
6501(defun pop-to-buffer (buffer &optional action norecord)
6502 "Select buffer BUFFER in some window, preferably a different one.
6503BUFFER may be a buffer, a string (a buffer name), or nil. If it
6504is a string not naming an existent buffer, create a buffer with
6505that name. If BUFFER is nil, choose some other buffer. Return
6506the buffer.
6507
6508This uses `display-buffer' as a subroutine. The optional ACTION
6509argument is passed to `display-buffer' as its ACTION argument.
6510See `display-buffer' for more information. ACTION is t if called
6511interactively with a prefix argument, which means to pop to a
6512window other than the selected one even if the buffer is already
6513displayed in the selected window.
6514
6515If the window to show BUFFER is not on the selected
f818cd2a
MR
6516frame, raise that window's frame and give it input focus.
6517
f818cd2a
MR
6518Optional third arg NORECORD non-nil means do not put this buffer
6519at the front of the list of recently selected ones."
c3313451
CY
6520 (interactive (list (read-buffer "Pop to buffer: " (other-buffer))
6521 (if current-prefix-arg t)))
8319e0bf 6522 (setq buffer (window-normalize-buffer-to-switch-to buffer))
c660a885
MR
6523 ;; This should be done by `select-window' below.
6524 ;; (set-buffer buffer)
cb882333 6525 (let* ((old-frame (selected-frame))
8319e0bf 6526 (window (display-buffer buffer action))
c3313451 6527 (frame (window-frame window)))
97adfb97
CY
6528 ;; If we chose another frame, make sure it gets input focus.
6529 (unless (eq frame old-frame)
c3313451 6530 (select-frame-set-input-focus frame norecord))
97adfb97
CY
6531 ;; Make sure new window is selected (Bug#8615), (Bug#6954).
6532 (select-window window norecord)
c3313451 6533 buffer))
f818cd2a 6534
72258fe5
CY
6535(defun pop-to-buffer-same-window (buffer &optional norecord)
6536 "Select buffer BUFFER in some window, preferably the same one.
72258fe5
CY
6537BUFFER may be a buffer, a string (a buffer name), or nil. If it
6538is a string not naming an existent buffer, create a buffer with
6539that name. If BUFFER is nil, choose some other buffer. Return
6540the buffer.
6541
6c8413fc
MR
6542Optional argument NORECORD, if non-nil means do not put this
6543buffer at the front of the list of recently selected ones.
6544
6545Unlike `pop-to-buffer', this function prefers using the selected
6546window over popping up a new window or frame."
24510c22 6547 (pop-to-buffer buffer display-buffer--same-window-action norecord))
72258fe5 6548
f818cd2a
MR
6549(defun read-buffer-to-switch (prompt)
6550 "Read the name of a buffer to switch to, prompting with PROMPT.
e1dbe924 6551Return the name of the buffer as a string.
f818cd2a
MR
6552
6553This function is intended for the `switch-to-buffer' family of
6554commands since these need to omit the name of the current buffer
6555from the list of completions and default values."
6556 (let ((rbts-completion-table (internal-complete-buffer-except)))
6557 (minibuffer-with-setup-hook
6558 (lambda ()
6559 (setq minibuffer-completion-table rbts-completion-table)
6560 ;; Since rbts-completion-table is built dynamically, we
6561 ;; can't just add it to the default value of
6562 ;; icomplete-with-completion-tables, so we add it
6563 ;; here manually.
6564 (if (and (boundp 'icomplete-with-completion-tables)
6565 (listp icomplete-with-completion-tables))
6566 (set (make-local-variable 'icomplete-with-completion-tables)
6567 (cons rbts-completion-table
6568 icomplete-with-completion-tables))))
6569 (read-buffer prompt (other-buffer (current-buffer))
6570 (confirm-nonexistent-file-or-buffer)))))
6571
6572(defun window-normalize-buffer-to-switch-to (buffer-or-name)
6573 "Normalize BUFFER-OR-NAME argument of buffer switching functions.
6574If BUFFER-OR-NAME is nil, return the buffer returned by
6575`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
6576exists, return that buffer. If no such buffer exists, create a
6577buffer with the name BUFFER-OR-NAME and return that buffer."
6578 (if buffer-or-name
6579 (or (get-buffer buffer-or-name)
6580 (let ((buffer (get-buffer-create buffer-or-name)))
6581 (set-buffer-major-mode buffer)
6582 buffer))
6583 (other-buffer)))
6584
9d7f027b
MR
6585(defcustom switch-to-buffer-preserve-window-point nil
6586 "If non-nil, `switch-to-buffer' tries to preserve `window-point'.
6587If this is nil, `switch-to-buffer' displays the buffer at that
6588buffer's `point'. If this is `already-displayed', it tries to
791ef5f8 6589display the buffer at its previous position in the selected
9d7f027b
MR
6590window, provided the buffer is currently displayed in some other
6591window on any visible or iconified frame. If this is t, it
6592unconditionally tries to display the buffer at its previous
6593position in the selected window.
6594
43bcfda6
MR
6595This variable is ignored if the buffer is already displayed in
6596the selected window or never appeared in it before, or if
9d7f027b
MR
6597`switch-to-buffer' calls `pop-to-buffer' to display the buffer."
6598 :type '(choice
6599 (const :tag "Never" nil)
6600 (const :tag "If already displayed elsewhere" already-displayed)
6601 (const :tag "Always" t))
6602 :group 'windows
6603 :version "24.3")
6604
f818cd2a 6605(defun switch-to-buffer (buffer-or-name &optional norecord force-same-window)
d1c0cddf
SM
6606 "Display buffer BUFFER-OR-NAME in the selected window.
6607
6608WARNING: This is NOT the way to work on another buffer temporarily
6609within a Lisp program! Use `set-buffer' instead. That avoids
6610messing with the window-buffer correspondences.
6611
cee2e90d
CY
6612If the selected window cannot display the specified
6613buffer (e.g. if it is a minibuffer window or strongly dedicated
6614to another buffer), call `pop-to-buffer' to select the buffer in
6615another window.
6616
6617If called interactively, read the buffer name using the
f818cd2a
MR
6618minibuffer. The variable `confirm-nonexistent-file-or-buffer'
6619determines whether to request confirmation before creating a new
6620buffer.
6621
cee2e90d
CY
6622BUFFER-OR-NAME may be a buffer, a string (a buffer name), or nil.
6623If BUFFER-OR-NAME is a string that does not identify an existing
6624buffer, create a buffer with that name. If BUFFER-OR-NAME is
6625nil, switch to the buffer returned by `other-buffer'.
6626
6627If optional argument NORECORD is non-nil, do not put the buffer
6628at the front of the buffer list, and do not make the window
6629displaying it the most recently selected one.
6630
6631If optional argument FORCE-SAME-WINDOW is non-nil, the buffer
6632must be displayed in the selected window; if that is impossible,
6633signal an error rather than calling `pop-to-buffer'.
f818cd2a 6634
9d7f027b
MR
6635The option `switch-to-buffer-preserve-window-point' can be used
6636to make the buffer appear at its last position in the selected
6637window.
6638
f818cd2a
MR
6639Return the buffer switched to."
6640 (interactive
acc825c5 6641 (list (read-buffer-to-switch "Switch to buffer: ") nil 'force-same-window))
f818cd2a 6642 (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
24510c22
SM
6643 (cond
6644 ;; Don't call set-window-buffer if it's not needed since it
6645 ;; might signal an error (e.g. if the window is dedicated).
6646 ((eq buffer (window-buffer)))
6647 ((window-minibuffer-p)
6648 (if force-same-window
71873e2b 6649 (user-error "Cannot switch buffers in minibuffer window")
24510c22
SM
6650 (pop-to-buffer buffer norecord)))
6651 ((eq (window-dedicated-p) t)
6652 (if force-same-window
71873e2b 6653 (user-error "Cannot switch buffers in a dedicated window")
24510c22 6654 (pop-to-buffer buffer norecord)))
9d7f027b
MR
6655 (t
6656 (let* ((entry (assq buffer (window-prev-buffers)))
6657 (displayed (and (eq switch-to-buffer-preserve-window-point
6658 'already-displayed)
6659 (get-buffer-window buffer 0))))
6660 (set-window-buffer nil buffer)
6661 (when (and entry
6662 (or (eq switch-to-buffer-preserve-window-point t)
6663 displayed))
6664 ;; Try to restore start and point of buffer in the selected
6665 ;; window (Bug#4041).
6666 (set-window-start (selected-window) (nth 1 entry) t)
6667 (set-window-point nil (nth 2 entry))))))
24510c22
SM
6668
6669 (unless norecord
6670 (select-window (selected-window)))
6671 (set-buffer buffer)))
f818cd2a
MR
6672
6673(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
6674 "Select the buffer specified by BUFFER-OR-NAME in another window.
382c953b 6675BUFFER-OR-NAME may be a buffer, a string (a buffer name), or
f818cd2a
MR
6676nil. Return the buffer switched to.
6677
6678If called interactively, prompt for the buffer name using the
6679minibuffer. The variable `confirm-nonexistent-file-or-buffer'
6680determines whether to request confirmation before creating a new
6681buffer.
6682
6683If BUFFER-OR-NAME is a string and does not identify an existing
6684buffer, create a new buffer with that name. If BUFFER-OR-NAME is
6685nil, switch to the buffer returned by `other-buffer'.
6686
6687Optional second argument NORECORD non-nil means do not put this
6688buffer at the front of the list of recently selected ones.
6689
6690This uses the function `display-buffer' as a subroutine; see its
6691documentation for additional customization information."
6692 (interactive
6693 (list (read-buffer-to-switch "Switch to buffer in other window: ")))
8319e0bf
CY
6694 (let ((pop-up-windows t))
6695 (pop-to-buffer buffer-or-name t norecord)))
f818cd2a
MR
6696
6697(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
6698 "Switch to buffer BUFFER-OR-NAME in another frame.
382c953b 6699BUFFER-OR-NAME may be a buffer, a string (a buffer name), or
f818cd2a
MR
6700nil. Return the buffer switched to.
6701
6702If called interactively, prompt for the buffer name using the
6703minibuffer. The variable `confirm-nonexistent-file-or-buffer'
6704determines whether to request confirmation before creating a new
6705buffer.
6706
6707If BUFFER-OR-NAME is a string and does not identify an existing
6708buffer, create a new buffer with that name. If BUFFER-OR-NAME is
6709nil, switch to the buffer returned by `other-buffer'.
6710
6711Optional second arg NORECORD non-nil means do not put this
6712buffer at the front of the list of recently selected ones.
6713
6714This uses the function `display-buffer' as a subroutine; see its
6715documentation for additional customization information."
6716 (interactive
6717 (list (read-buffer-to-switch "Switch to buffer in other frame: ")))
8319e0bf 6718 (pop-to-buffer buffer-or-name display-buffer--other-frame-action norecord))
3c448ab6
MR
6719\f
6720(defun set-window-text-height (window height)
9992ea0c 6721 "Set the height in lines of the text display area of WINDOW to HEIGHT.
85c2386b
MR
6722WINDOW must be a live window and defaults to the selected one.
6723HEIGHT doesn't include the mode line or header line, if any, or
6724any partial-height lines in the text display area.
3c448ab6
MR
6725
6726Note that the current implementation of this function cannot
6727always set the height exactly, but attempts to be conservative,
6728by allocating more lines than are actually needed in the case
6729where some error may be present."
447f16b8 6730 (setq window (window-normalize-window window t))
3c448ab6
MR
6731 (let ((delta (- height (window-text-height window))))
6732 (unless (zerop delta)
6733 ;; Setting window-min-height to a value like 1 can lead to very
6734 ;; bizarre displays because it also allows Emacs to make *other*
37269466
CY
6735 ;; windows one line tall, which means that there's no more space
6736 ;; for the mode line.
6737 (let ((window-min-height (min 2 height)))
d615d6d2 6738 (window-resize window delta)))))
3c448ab6 6739
6198ccd0
MR
6740(defun enlarge-window-horizontally (delta)
6741 "Make selected window DELTA columns wider.
3c448ab6
MR
6742Interactively, if no argument is given, make selected window one
6743column wider."
6744 (interactive "p")
6198ccd0 6745 (enlarge-window delta t))
3c448ab6 6746
6198ccd0
MR
6747(defun shrink-window-horizontally (delta)
6748 "Make selected window DELTA columns narrower.
3c448ab6
MR
6749Interactively, if no argument is given, make selected window one
6750column narrower."
6751 (interactive "p")
6198ccd0 6752 (shrink-window delta t))
3c448ab6
MR
6753
6754(defun count-screen-lines (&optional beg end count-final-newline window)
6755 "Return the number of screen lines in the region.
6756The number of screen lines may be different from the number of actual lines,
6757due to line breaking, display table, etc.
6758
6759Optional arguments BEG and END default to `point-min' and `point-max'
6760respectively.
6761
6762If region ends with a newline, ignore it unless optional third argument
6763COUNT-FINAL-NEWLINE is non-nil.
6764
6765The optional fourth argument WINDOW specifies the window used for obtaining
6766parameters such as width, horizontal scrolling, and so on. The default is
6767to use the selected window's parameters.
6768
6769Like `vertical-motion', `count-screen-lines' always uses the current buffer,
6770regardless of which buffer is displayed in WINDOW. This makes possible to use
6771`count-screen-lines' in any buffer, whether or not it is currently displayed
6772in some window."
6773 (unless beg
6774 (setq beg (point-min)))
6775 (unless end
6776 (setq end (point-max)))
6777 (if (= beg end)
6778 0
6779 (save-excursion
6780 (save-restriction
6781 (widen)
6782 (narrow-to-region (min beg end)
6783 (if (and (not count-final-newline)
6784 (= ?\n (char-before (max beg end))))
6785 (1- (max beg end))
6786 (max beg end)))
6787 (goto-char (point-min))
6788 (1+ (vertical-motion (buffer-size) window))))))
6789
6198ccd0 6790(defun window-buffer-height (window)
85c2386b
MR
6791 "Return the height (in screen lines) of the buffer that WINDOW is displaying.
6792WINDOW must be a live window and defaults to the selected one."
6793 (setq window (window-normalize-window window t))
6198ccd0
MR
6794 (with-current-buffer (window-buffer window)
6795 (max 1
6796 (count-screen-lines (point-min) (point-max)
6797 ;; If buffer ends with a newline, ignore it when
6798 ;; counting height unless point is after it.
6799 (eobp)
6800 window))))
6801
880e6158
MR
6802;;; Resizing windows and frames to fit their contents exactly.
6803(defcustom fit-window-to-buffer-horizontally nil
6804 "Non-nil means `fit-window-to-buffer' can resize windows horizontally.
6805If this is nil, `fit-window-to-buffer' never resizes windows
6806horizontally. If this is `only', it can resize windows
6807horizontally only. Any other value means `fit-window-to-buffer'
6808can resize windows in both dimensions."
6809 :type 'boolean
6810 :version "24.4"
6811 :group 'help)
6812
6813;; `fit-frame-to-buffer' eventually wants to know the real frame sizes
6814;; counting title bar and outer borders.
5938d519 6815(defcustom fit-frame-to-buffer nil
880e6158
MR
6816 "Non-nil means `fit-frame-to-buffer' can fit a frame to its buffer.
6817A frame is fit if and only if its root window is a live window
6818and this option is non-nil. If this is `horizontally', frames
6819are resized horizontally only. If this is `vertically', frames
6820are resized vertically only. Any other non-nil value means
6821frames can be resized in both dimensions. See also
6822`fit-frame-to-buffer-margins' and `fit-frame-to-buffer-sizes'.
6823
6824If this is non-nil and a window is the only window of its frame,
6825`fit-window-to-buffer' will invoke `fit-frame-to-buffer' to fit
6826the frame to its buffer."
5938d519 6827 :type 'boolean
880e6158 6828 :version "24.4"
5938d519
MR
6829 :group 'help)
6830
880e6158
MR
6831(defcustom fit-frame-to-buffer-margins '(nil nil nil nil)
6832 "Margins around frame for `fit-frame-to-buffer'.
6833This list specifies the numbers of pixels to be left free on the
6834left, above, the right, and below a frame that shall be fit to
6835its buffer. The value specified here can be overridden for a
6836specific frame by that frame's `fit-frame-to-buffer-margins'
6837parameter, if present.
6838
6839This variable controls how fitting a frame to the size of its
6840buffer coordinates with the size of your display. If you don't
6841specify a value here, the size of the display's workarea is used.
6842
6843See also `fit-frame-to-buffer-sizes'."
6844 :version "24.4"
6845 :type '(list
6846 (choice
6847 :tag "Left"
6848 :value nil
6849 :format "%[LeftMargin%] %v "
6850 (const :tag "None" :format "%t" nil)
6851 (integer :tag "Pixels" :size 5))
6852 (choice
6853 :tag "Top"
6854 :value nil
6855 :format "%[TopMargin%] %v "
6856 (const :tag "None" :format "%t" nil)
6857 (integer :tag "Pixels" :size 5))
6858 (choice
6859 :tag "Right"
6860 :value nil
6861 :format "%[RightMargin%] %v "
6862 (const :tag "None" :format "%t" nil)
6863 (integer :tag "Pixels" :size 5))
6864 (choice
6865 :tag "Bottom"
6866 :value nil
6867 :format "%[BottomMargin%] %v "
6868 (const :tag "None" :format "%t" nil)
6869 (integer :tag "Pixels" :size 5)))
6870 :group 'help)
6871
6872(defcustom fit-frame-to-buffer-sizes '(nil nil nil nil)
6873 "Size boundaries of frame for `fit-frame-to-buffer'.
6874This list specifies the total maximum and minimum lines and
6875maximum and minimum columns of the root window of any frame that
6876shall be fit to its buffer. If any of these values is non-nil,
6877it overrides the corresponding argument of `fit-frame-to-buffer'.
6878
6879On window systems where the menubar can wrap, fitting a frame to
6880its buffer may swallow the last line(s). Specifying an
6881appropriate minimum width value here can avoid such wrapping.
6882
6883See also `fit-frame-to-buffer-margins'."
6884 :version "24.4"
6885 :type '(list
6886 (choice
6887 :tag "Maximum Height"
6888 :value nil
6889 :format "%[MaxHeight%] %v "
6890 (const :tag "None" :format "%t" nil)
6891 (integer :tag "Lines" :size 5))
6892 (choice
6893 :tag "Minimum Height"
6894 :value nil
6895 :format "%[MinHeight%] %v "
6896 (const :tag "None" :format "%t" nil)
6897 (integer :tag "Lines" :size 5))
6898 (choice
6899 :tag "Maximum Width"
6900 :value nil
6901 :format "%[MaxWidth%] %v "
6902 (const :tag "None" :format "%t" nil)
6903 (integer :tag "Columns" :size 5))
6904 (choice
6905 :tag "Minimum Width"
6906 :value nil
6907 :format "%[MinWidth%] %v\n"
6908 (const :tag "None" :format "%t" nil)
6909 (integer :tag "Columns" :size 5)))
6910 :group 'help)
5938d519 6911
e740f9d2 6912(declare-function x-display-pixel-height "xfns.c" (&optional terminal))
e740f9d2 6913
880e6158
MR
6914(defun window--sanitize-margin (margin left right)
6915 "Return MARGIN if it's a number between LEFT and RIGHT."
6916 (when (and (numberp margin)
6917 (<= left (- right margin)) (<= margin right))
6918 margin))
5938d519 6919
880e6158
MR
6920(defun fit-frame-to-buffer (&optional frame max-height min-height max-width min-width)
6921 "Adjust size of FRAME to display the contents of its buffer exactly.
6922FRAME can be any live frame and defaults to the selected one.
6923Fit only if FRAME's root window is live. MAX-HEIGHT, MIN-HEIGHT,
6924MAX-WIDTH and MIN-WIDTH specify bounds on the new total size of
25a700d0
MR
6925FRAME's root window. MIN-HEIGHT and MIN-WIDTH default to the values of
6926`window-min-height' and `window-min-width' respectively.
880e6158
MR
6927
6928The option `fit-frame-to-buffer' controls whether this function
6929has any effect. New position and size of FRAME are additionally
6930determined by the options `fit-frame-to-buffer-sizes' and
6931`fit-frame-to-buffer-margins' or the corresponding parameters of
6932FRAME."
5938d519 6933 (interactive)
25a700d0
MR
6934 (unless (and (fboundp 'x-display-pixel-height)
6935 ;; We need the respective sizes now.
6936 (fboundp 'display-monitor-attributes-list))
6937 (user-error "Cannot resize frame in non-graphic Emacs"))
5938d519 6938 (setq frame (window-normalize-frame frame))
880e6158
MR
6939 (when (and (window-live-p (frame-root-window frame))
6940 fit-frame-to-buffer
6941 (or (not window-size-fixed)
6942 (and (eq window-size-fixed 'height)
6943 (not (eq fit-frame-to-buffer 'vertically)))
6944 (and (eq window-size-fixed 'width)
6945 (not (eq fit-frame-to-buffer 'horizontally)))))
6946 (with-selected-window (frame-root-window frame)
6947 (let* ((window (frame-root-window frame))
6948 (char-width (frame-char-width))
6949 (char-height (frame-char-height))
6950 (monitor-attributes (car (display-monitor-attributes-list
6951 (frame-parameter frame 'display))))
6952 (geometry (cdr (assq 'geometry monitor-attributes)))
6953 (display-width (- (nth 2 geometry) (nth 0 geometry)))
6954 (display-height (- (nth 3 geometry) (nth 1 geometry)))
6955 (workarea (cdr (assq 'workarea monitor-attributes)))
6956 ;; Handle margins.
6957 (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins)
6958 fit-frame-to-buffer-margins))
1dcb169c
MR
6959 (left-margin (if (nth 0 margins)
6960 (or (window--sanitize-margin
6961 (nth 0 margins) 0 display-width)
6962 0)
6963 (nth 0 workarea)))
6964 (top-margin (if (nth 1 margins)
6965 (or (window--sanitize-margin
6966 (nth 1 margins) 0 display-height)
6967 0)
6968 (nth 1 workarea)))
880e6158 6969 (workarea-width (nth 2 workarea))
1dcb169c
MR
6970 (right-margin (if (nth 2 margins)
6971 (- display-width
6972 (or (window--sanitize-margin
6973 (nth 2 margins) left-margin display-width)
6974 0))
6975 (nth 2 workarea)))
880e6158 6976 (workarea-height (nth 3 workarea))
1dcb169c
MR
6977 (bottom-margin (if (nth 3 margins)
6978 (- display-height
6979 (or (window--sanitize-margin
6980 (nth 3 margins) top-margin display-height)
6981 0))
6982 (nth 3 workarea)))
880e6158
MR
6983 ;; The pixel width of FRAME (which does not include the
6984 ;; window manager's decorations).
6985 (frame-width (frame-pixel-width))
6986 ;; The pixel width of the body of FRAME's root window.
6987 (window-body-width (window-body-width nil t))
6988 ;; The difference in pixels between total and body width of
6989 ;; FRAME's window.
6990 (window-extra-width (- (window-pixel-width) window-body-width))
6991 ;; The difference in pixels between the frame's pixel width
6992 ;; and the window's body width. This is the space we can't
6993 ;; use for fitting.
6994 (extra-width (- frame-width window-body-width))
6995 ;; The maximum width we can use for fitting.
6996 (fit-width (- workarea-width extra-width))
6997 ;; The pixel position of FRAME's left border. We usually
6998 ;; try to leave this alone.
6999 (left
7000 (let ((left (frame-parameter nil 'left)))
7001 (if (consp left)
7002 (funcall (car left) (cadr left))
7003 left)))
7004 ;; The pixel height of FRAME (which does not include title
7005 ;; line, decorations, and sometimes neither the menu nor
7006 ;; the toolbar).
7007 (frame-height (frame-pixel-height))
7008 ;; The pixel height of FRAME's root window (we don't care
7009 ;; about the window's body height since the return value of
7010 ;; `window-text-pixel-size' includes header and mode line).
7011 (window-height (window-pixel-height))
7012 ;; The difference in pixels between the frame's pixel
7013 ;; height and the window's height.
7014 (extra-height (- frame-height window-height))
7015 ;; When tool-bar-mode is enabled and we just created a new
7016 ;; frame, reserve lines for toolbar resizing. Needed
7017 ;; because for reasons unknown to me Emacs (1) reserves one
7018 ;; line for the toolbar when making the initial frame and
7019 ;; toolbars are enabled, and (2) later adds the remaining
7020 ;; lines needed. Our code runs IN BETWEEN (1) and (2).
7021 ;; YMMV when you're on a system that behaves differently.
7022 (toolbar-extra-height
7023 (let ((quit-restore (window-parameter window 'quit-restore))
7024 ;; This may have to change when we allow arbitrary
7025 ;; pixel height toolbars.
7026 (lines (tool-bar-height)))
7027 (* char-height
7028 (if (and quit-restore (eq (car quit-restore) 'frame)
7029 (not (zerop lines)))
7030 (1- lines)
7031 0))))
1dcb169c 7032 ;; The pixel position of FRAME's top border.
880e6158
MR
7033 (top
7034 (let ((top (frame-parameter nil 'top)))
7035 (if (consp top)
7036 (funcall (car top) (cadr top))
7037 top)))
7038 ;; Sanitize minimum and maximum sizes.
7039 (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes)
7040 fit-frame-to-buffer-sizes))
7041 (max-height
7042 (cond
7043 ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height))
1dcb169c
MR
7044 ((numberp max-height) (* max-height char-height))
7045 (t display-height)))
880e6158
MR
7046 (min-height
7047 (cond
7048 ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height))
25a700d0
MR
7049 ((numberp min-height) (* min-height char-height))
7050 (t (* window-min-height char-height))))
880e6158
MR
7051 (max-width
7052 (cond
7053 ((numberp (nth 2 sizes))
7054 (- (* (nth 2 sizes) char-width) window-extra-width))
7055 ((numberp max-width)
1dcb169c
MR
7056 (- (* max-width char-width) window-extra-width))
7057 (t display-height)))
880e6158
MR
7058 (min-width
7059 (cond
7060 ((numberp (nth 3 sizes))
7061 (- (* (nth 3 sizes) char-width) window-extra-width))
7062 ((numberp min-width)
25a700d0
MR
7063 (- (* min-width char-width) window-extra-width))
7064 (t (* window-min-width char-width))))
880e6158
MR
7065 ;; Note: Currently, for a new frame the sizes of the header
7066 ;; and mode line may be estimated incorrectly
7067 (value (window-text-pixel-size
7068 nil t t workarea-width workarea-height t))
7069 (width (+ (car value) (window-right-divider-width)))
1dcb169c 7070 (height (+ (cdr value) (window-bottom-divider-width))))
880e6158
MR
7071 ;; Don't change height or width when the window's size is fixed
7072 ;; in either direction.
5938d519 7073 (cond
880e6158 7074 ((eq window-size-fixed 'width)
1dcb169c
MR
7075 (setq width nil))
7076 ((eq window-size-fixed 'height)
880e6158 7077 (setq height nil)))
1dcb169c 7078 ;; Fit width to constraints.
880e6158 7079 (when width
1dcb169c
MR
7080 (unless frame-resize-pixelwise
7081 ;; Round to character sizes.
7082 (setq width (* (/ (+ width char-width -1) char-width)
7083 char-width)))
880e6158 7084 ;; Fit to maximum and minimum widths.
1dcb169c 7085 (setq width (max (min width max-width) min-width))
880e6158
MR
7086 ;; Add extra width.
7087 (setq width (+ width extra-width))
1dcb169c
MR
7088 ;; Preserve margins.
7089 (let ((right (+ left width)))
880e6158 7090 (cond
25a700d0
MR
7091 ((> right right-margin)
7092 ;; Move frame to left (we don't know its real width).
1dcb169c 7093 (setq left (max left-margin (- left (- right right-margin)))))
880e6158
MR
7094 ((< left left-margin)
7095 ;; Move frame to right.
7096 (setq left left-margin)))))
1dcb169c 7097 ;; Fit height to constraints.
880e6158 7098 (when height
1dcb169c
MR
7099 (unless frame-resize-pixelwise
7100 (setq height (* (/ (+ height char-height -1) char-height)
7101 char-height)))
880e6158 7102 ;; Fit to maximum and minimum heights.
1dcb169c 7103 (setq height (max (min height max-height) min-height))
880e6158
MR
7104 ;; Add extra height.
7105 (setq height (+ height extra-height))
1dcb169c
MR
7106 ;; Preserve margins.
7107 (let ((bottom (+ top height)))
880e6158 7108 (cond
25a700d0
MR
7109 ((> bottom bottom-margin)
7110 ;; Move frame up (we don't know its real height).
1dcb169c 7111 (setq top (max top-margin (- top (- bottom bottom-margin)))))
880e6158
MR
7112 ((< top top-margin)
7113 ;; Move frame down.
7114 (setq top top-margin)))))
7115 ;; Apply changes.
7116 (set-frame-position frame left top)
7117 ;; Clumsily try to translate our calculations to what
7118 ;; `set-frame-size' wants.
7119 (when width
7120 (setq width (- (+ (frame-text-width) width)
7121 extra-width window-body-width)))
7122 (when height
7123 (setq height (- (+ (frame-text-height) height)
7124 extra-height window-height)))
7125 (set-frame-size
7126 frame
7127 (if width
25a700d0 7128 (if frame-resize-pixelwise
880e6158
MR
7129 width
7130 (/ width char-width))
7131 (frame-text-width))
7132 (if height
25a700d0 7133 (if frame-resize-pixelwise
880e6158
MR
7134 height
7135 (/ height char-height))
7136 (frame-text-height))
25a700d0 7137 frame-resize-pixelwise)))))
880e6158
MR
7138
7139(defun fit-window-to-buffer (&optional window max-height min-height max-width min-width)
7140 "Adjust size of WINDOW to display its buffer's contents exactly.
85c2386b 7141WINDOW must be a live window and defaults to the selected one.
6198ccd0 7142
880e6158
MR
7143If WINDOW is part of a vertical combination, adjust WINDOW's
7144height. The new height is calculated from the number of lines of
7145the accessible portion of its buffer. The optional argument
7146MAX-HEIGHT specifies a maximum height and defaults to the height
7147of WINDOW's frame. The optional argument MIN-HEIGHT specifies a
7148minimum height and defaults to `window-min-height'. Both
7149MAX-HEIGHT and MIN-HEIGHT are specified in lines and include the
7150mode line and header line, if any.
7151
7152If WINDOW is part of a horizontal combination and the value of
7153the option `fit-window-to-buffer-horizontally' is non-nil, adjust
7154WINDOW's height. The new width of WINDOW is calculated from the
7155maximum length of its buffer's lines that follow the current
7156start position of WINDOW. The optional argument MAX-WIDTH
7157specifies a maximum width and defaults to the width of WINDOW's
7158frame. The optional argument MIN-WIDTH specifies a minimum width
7159and defaults to `window-min-width'. Both MAX-WIDTH and MIN-WIDTH
7160are specified in columns and include fringes, margins and
7161scrollbars, if any.
7162
7163Fit pixelwise if the option `window-resize-pixelwise' is non-nil.
7164If WINDOW is its frame's root window, then if the option
7165`fit-frame-to-buffer' is non-nil, call `fit-frame-to-buffer' to
7166adjust the frame's size.
6198ccd0
MR
7167
7168Note that even if this function makes WINDOW large enough to show
880e6158
MR
7169_all_ parts of its buffer you might not see the first part when
7170WINDOW was scrolled. If WINDOW is resized horizontally, you will
7171not see the top of its buffer unless WINDOW starts at its minimum
7172accessible position."
f7baca20 7173 (interactive)
447f16b8 7174 (setq window (window-normalize-window window t))
880e6158
MR
7175 (if (eq window (frame-root-window window))
7176 (when fit-frame-to-buffer
7177 ;; Fit WINDOW's frame to buffer.
7178 (fit-frame-to-buffer
7179 (window-frame window)
7180 max-height min-height max-width min-width))
6198ccd0 7181 (with-selected-window window
880e6158 7182 (let* ((pixelwise window-resize-pixelwise)
880e6158
MR
7183 (char-height (frame-char-height))
7184 (char-width (frame-char-width))
880e6158
MR
7185 (total-height (window-size window nil pixelwise))
7186 (body-height (window-body-height window pixelwise))
7187 (body-width (window-body-width window pixelwise))
6198ccd0 7188 (min-height
880e6158 7189 ;; Sanitize MIN-HEIGHT.
c5e28e39
MR
7190 (if (numberp min-height)
7191 ;; Can't get smaller than `window-safe-min-height'.
880e6158
MR
7192 (max (if pixelwise
7193 (* char-height min-height)
7194 min-height)
7195 (if pixelwise
7196 (window-safe-min-pixel-height window)
7197 window-safe-min-height))
c5e28e39 7198 ;; Preserve header and mode line if present.
25a700d0
MR
7199 (max (if pixelwise
7200 (* char-height window-min-height)
7201 window-min-height)
7202 (window-min-size nil nil t pixelwise))))
6198ccd0 7203 (max-height
880e6158 7204 ;; Sanitize MAX-HEIGHT.
c5e28e39 7205 (if (numberp max-height)
880e6158
MR
7206 (min
7207 (+ total-height
7208 (window-max-delta
7209 window nil nil nil nil nil pixelwise))
7210 (if pixelwise
7211 (* char-height max-height)
7212 max-height))
7213 (+ total-height (window-max-delta
7214 window nil nil nil nil nil pixelwise))))
7215 height)
7216 (cond
7217 ;; If WINDOW is vertically combined, try to resize it
7218 ;; vertically.
7219 ((and (not (eq fit-window-to-buffer-horizontally 'only))
7220 (not (window-size-fixed-p window))
7221 (window-combined-p))
7222 ;; Vertically we always want to fit the entire buffer.
7223 ;; WINDOW'S height can't get larger than its frame's pixel
7224 ;; height. Its width remains fixed.
7225 (setq height (+ (cdr (window-text-pixel-size
7226 nil nil t nil (frame-pixel-height) t))
7227 (window-bottom-divider-width)))
7228 ;; Round height.
7229 (unless pixelwise
6cb4da45 7230 (setq height (/ (+ height char-height -1) char-height)))
880e6158
MR
7231 (unless (= height total-height)
7232 (window-resize-no-error
7233 window
7234 (- (max min-height (min max-height height)) total-height)
7235 nil window pixelwise)))
7236 ;; If WINDOW is horizontally combined, try to resize it
7237 ;; horizontally.
7238 ((and fit-window-to-buffer-horizontally
7239 (not (window-size-fixed-p window t))
7240 (window-combined-p nil t))
2d6b6005 7241 (let* ((total-width (window-size window nil pixelwise))
880e6158
MR
7242 (min-width
7243 ;; Sanitize MIN-WIDTH.
7244 (if (numberp min-width)
7245 ;; Can't get smaller than `window-safe-min-width'.
7246 (max (if pixelwise
7247 (* char-width min-width)
7248 min-width)
7249 (if pixelwise
7250 (window-safe-min-pixel-width)
7251 window-safe-min-width))
f224e500 7252 ;; Preserve fringes, margins, scrollbars if present.
25a700d0
MR
7253 (max (if pixelwise
7254 (* char-width window-min-width)
7255 window-min-width)
7256 (window-min-size nil nil t pixelwise))))
880e6158
MR
7257 (max-width
7258 ;; Sanitize MAX-WIDTH.
7259 (if (numberp max-width)
7260 (min (+ total-width
7261 (window-max-delta
7262 nil t nil nil nil nil pixelwise))
7263 (if pixelwise
7264 (* char-width max-width)
7265 max-width))
7266 (+ total-width (window-max-delta
7267 nil t nil nil nil nil pixelwise))))
7268 ;; When fitting vertically, assume that WINDOW's start
7269 ;; position remains unaltered. WINDOW can't get wider
7270 ;; than its frame's pixel width, its height remains
7271 ;; unaltered.
7272 (width (+ (car (window-text-pixel-size
7273 nil (window-start) (point-max)
7274 (frame-pixel-width)
7275 ;; Add one char-height to assure that
7276 ;; we're on the safe side. This
7277 ;; overshoots when the first line below
7278 ;; the bottom is wider than the window.
7279 (* body-height
7280 (if pixelwise char-height 1))))
7281 (window-right-divider-width))))
7282 (unless pixelwise
6cb4da45 7283 (setq width (/ (+ width char-width -1) char-width)))
880e6158
MR
7284 (unless (= width body-width)
7285 (window-resize-no-error
7286 window
7287 (- (max min-width
7288 (min max-width
7289 (+ total-width (- width body-width))))
7290 total-width)
7291 t window pixelwise)))))))))
ef654460 7292
39cffb44
MR
7293(defun window-safely-shrinkable-p (&optional window)
7294 "Return t if WINDOW can be shrunk without shrinking other windows.
7295WINDOW defaults to the selected window."
7296 (with-selected-window (or window (selected-window))
7297 (let ((edges (window-edges)))
39cffb44
MR
7298 (or (= (nth 2 edges) (nth 2 (window-edges (previous-window))))
7299 (= (nth 0 edges) (nth 0 (window-edges (next-window))))))))
39cffb44 7300
3c448ab6
MR
7301(defun shrink-window-if-larger-than-buffer (&optional window)
7302 "Shrink height of WINDOW if its buffer doesn't need so many lines.
7303More precisely, shrink WINDOW vertically to be as small as
7304possible, while still showing the full contents of its buffer.
85c2386b 7305WINDOW must be a live window and defaults to the selected one.
3c448ab6 7306
6198ccd0
MR
7307Do not shrink WINDOW to less than `window-min-height' lines. Do
7308nothing if the buffer contains more lines than the present window
7309height, or if some of the window's contents are scrolled out of
7310view, or if shrinking this window would also shrink another
7311window, or if the window is the only window of its frame.
3c448ab6
MR
7312
7313Return non-nil if the window was shrunk, nil otherwise."
7314 (interactive)
447f16b8 7315 (setq window (window-normalize-window window t))
6198ccd0
MR
7316 ;; Make sure that WINDOW is vertically combined and `point-min' is
7317 ;; visible (for whatever reason that's needed). The remaining issues
7318 ;; should be taken care of by `fit-window-to-buffer'.
3d8daefe 7319 (when (and (window-combined-p window)
6198ccd0 7320 (pos-visible-in-window-p (point-min) window))
880e6158 7321 (fit-window-to-buffer window (window-total-height window))))
6198ccd0 7322\f
3c448ab6
MR
7323(defun kill-buffer-and-window ()
7324 "Kill the current buffer and delete the selected window."
7325 (interactive)
7326 (let ((window-to-delete (selected-window))
7327 (buffer-to-kill (current-buffer))
6198ccd0 7328 (delete-window-hook (lambda () (ignore-errors (delete-window)))))
3c448ab6
MR
7329 (unwind-protect
7330 (progn
7331 (add-hook 'kill-buffer-hook delete-window-hook t t)
7332 (if (kill-buffer (current-buffer))
7333 ;; If `delete-window' failed before, we rerun it to regenerate
7334 ;; the error so it can be seen in the echo area.
7335 (when (eq (selected-window) window-to-delete)
7336 (delete-window))))
7337 ;; If the buffer is not dead for some reason (probably because
7338 ;; of a `quit' signal), remove the hook again.
6198ccd0
MR
7339 (ignore-errors
7340 (with-current-buffer buffer-to-kill
7341 (remove-hook 'kill-buffer-hook delete-window-hook t))))))
3c448ab6 7342
74f806a1 7343\f
3c448ab6
MR
7344(defvar recenter-last-op nil
7345 "Indicates the last recenter operation performed.
0116abbd
JL
7346Possible values: `top', `middle', `bottom', integer or float numbers.")
7347
7348(defcustom recenter-positions '(middle top bottom)
7349 "Cycling order for `recenter-top-bottom'.
7350A list of elements with possible values `top', `middle', `bottom',
7351integer or float numbers that define the cycling order for
7352the command `recenter-top-bottom'.
7353
382c953b 7354Top and bottom destinations are `scroll-margin' lines from the true
0116abbd
JL
7355window top and bottom. Middle redraws the frame and centers point
7356vertically within the window. Integer number moves current line to
7357the specified absolute window-line. Float number between 0.0 and 1.0
7358means the percentage of the screen space from the top. The default
7359cycling order is middle -> top -> bottom."
7360 :type '(repeat (choice
7361 (const :tag "Top" top)
7362 (const :tag "Middle" middle)
7363 (const :tag "Bottom" bottom)
7364 (integer :tag "Line number")
7365 (float :tag "Percentage")))
7366 :version "23.2"
7367 :group 'windows)
3c448ab6
MR
7368
7369(defun recenter-top-bottom (&optional arg)
0116abbd
JL
7370 "Move current buffer line to the specified window line.
7371With no prefix argument, successive calls place point according
7372to the cycling order defined by `recenter-positions'.
3c448ab6
MR
7373
7374A prefix argument is handled like `recenter':
7375 With numeric prefix ARG, move current line to window-line ARG.
0116abbd 7376 With plain `C-u', move current line to window center."
3c448ab6
MR
7377 (interactive "P")
7378 (cond
0116abbd 7379 (arg (recenter arg)) ; Always respect ARG.
3c448ab6 7380 (t
0116abbd
JL
7381 (setq recenter-last-op
7382 (if (eq this-command last-command)
7383 (car (or (cdr (member recenter-last-op recenter-positions))
7384 recenter-positions))
7385 (car recenter-positions)))
3c448ab6
MR
7386 (let ((this-scroll-margin
7387 (min (max 0 scroll-margin)
7388 (truncate (/ (window-body-height) 4.0)))))
7389 (cond ((eq recenter-last-op 'middle)
0116abbd 7390 (recenter))
3c448ab6 7391 ((eq recenter-last-op 'top)
0116abbd
JL
7392 (recenter this-scroll-margin))
7393 ((eq recenter-last-op 'bottom)
7394 (recenter (- -1 this-scroll-margin)))
7395 ((integerp recenter-last-op)
7396 (recenter recenter-last-op))
7397 ((floatp recenter-last-op)
7398 (recenter (round (* recenter-last-op (window-height))))))))))
3c448ab6
MR
7399
7400(define-key global-map [?\C-l] 'recenter-top-bottom)
216349f8 7401
216349f8
SM
7402(defun move-to-window-line-top-bottom (&optional arg)
7403 "Position point relative to window.
7404
0f202d5d 7405With a prefix argument ARG, acts like `move-to-window-line'.
216349f8
SM
7406
7407With no argument, positions point at center of window.
0116abbd
JL
7408Successive calls position point at positions defined
7409by `recenter-positions'."
216349f8
SM
7410 (interactive "P")
7411 (cond
0116abbd 7412 (arg (move-to-window-line arg)) ; Always respect ARG.
216349f8 7413 (t
0116abbd
JL
7414 (setq recenter-last-op
7415 (if (eq this-command last-command)
7416 (car (or (cdr (member recenter-last-op recenter-positions))
7417 recenter-positions))
7418 (car recenter-positions)))
216349f8
SM
7419 (let ((this-scroll-margin
7420 (min (max 0 scroll-margin)
7421 (truncate (/ (window-body-height) 4.0)))))
0f202d5d 7422 (cond ((eq recenter-last-op 'middle)
0116abbd 7423 (call-interactively 'move-to-window-line))
0f202d5d 7424 ((eq recenter-last-op 'top)
0116abbd
JL
7425 (move-to-window-line this-scroll-margin))
7426 ((eq recenter-last-op 'bottom)
7427 (move-to-window-line (- -1 this-scroll-margin)))
7428 ((integerp recenter-last-op)
7429 (move-to-window-line recenter-last-op))
7430 ((floatp recenter-last-op)
7431 (move-to-window-line (round (* recenter-last-op (window-height))))))))))
216349f8
SM
7432
7433(define-key global-map [?\M-r] 'move-to-window-line-top-bottom)
3c448ab6 7434\f
74f806a1
JL
7435;;; Scrolling commands.
7436
0a9f9ab5
SM
7437;;; Scrolling commands which do not signal errors at top/bottom
7438;;; of buffer at first key-press (instead move to top/bottom
74f806a1
JL
7439;;; of buffer).
7440
7441(defcustom scroll-error-top-bottom nil
8350f087 7442 "Move point to top/bottom of buffer before signaling a scrolling error.
74f806a1
JL
7443A value of nil means just signal an error if no more scrolling possible.
7444A value of t means point moves to the beginning or the end of the buffer
7445\(depending on scrolling direction) when no more scrolling possible.
7446When point is already on that position, then signal an error."
7447 :type 'boolean
60efac0f 7448 :group 'windows
74f806a1
JL
7449 :version "24.1")
7450
7451(defun scroll-up-command (&optional arg)
7452 "Scroll text of selected window upward ARG lines; or near full screen if no ARG.
7453If `scroll-error-top-bottom' is non-nil and `scroll-up' cannot
7454scroll window further, move cursor to the bottom line.
7455When point is already on that position, then signal an error.
7456A near full screen is `next-screen-context-lines' less than a full screen.
7457Negative ARG means scroll downward.
7458If ARG is the atom `-', scroll downward by nearly full screen."
7459 (interactive "^P")
7460 (cond
7461 ((null scroll-error-top-bottom)
7462 (scroll-up arg))
7463 ((eq arg '-)
7464 (scroll-down-command nil))
7465 ((< (prefix-numeric-value arg) 0)
7466 (scroll-down-command (- (prefix-numeric-value arg))))
7467 ((eobp)
7468 (scroll-up arg)) ; signal error
7469 (t
7470 (condition-case nil
7471 (scroll-up arg)
7472 (end-of-buffer
7473 (if arg
7474 ;; When scrolling by ARG lines can't be done,
7475 ;; move by ARG lines instead.
7476 (forward-line arg)
7477 ;; When ARG is nil for full-screen scrolling,
7478 ;; move to the bottom of the buffer.
7479 (goto-char (point-max))))))))
7480
7481(put 'scroll-up-command 'scroll-command t)
7482
7483(defun scroll-down-command (&optional arg)
7484 "Scroll text of selected window down ARG lines; or near full screen if no ARG.
7485If `scroll-error-top-bottom' is non-nil and `scroll-down' cannot
7486scroll window further, move cursor to the top line.
7487When point is already on that position, then signal an error.
7488A near full screen is `next-screen-context-lines' less than a full screen.
7489Negative ARG means scroll upward.
7490If ARG is the atom `-', scroll upward by nearly full screen."
7491 (interactive "^P")
7492 (cond
7493 ((null scroll-error-top-bottom)
7494 (scroll-down arg))
7495 ((eq arg '-)
7496 (scroll-up-command nil))
7497 ((< (prefix-numeric-value arg) 0)
7498 (scroll-up-command (- (prefix-numeric-value arg))))
7499 ((bobp)
7500 (scroll-down arg)) ; signal error
7501 (t
7502 (condition-case nil
7503 (scroll-down arg)
7504 (beginning-of-buffer
7505 (if arg
7506 ;; When scrolling by ARG lines can't be done,
7507 ;; move by ARG lines instead.
7508 (forward-line (- arg))
7509 ;; When ARG is nil for full-screen scrolling,
7510 ;; move to the top of the buffer.
7511 (goto-char (point-min))))))))
7512
7513(put 'scroll-down-command 'scroll-command t)
7514
7515;;; Scrolling commands which scroll a line instead of full screen.
7516
7517(defun scroll-up-line (&optional arg)
7518 "Scroll text of selected window upward ARG lines; or one line if no ARG.
7519If ARG is omitted or nil, scroll upward by one line.
7520This is different from `scroll-up-command' that scrolls a full screen."
7521 (interactive "p")
7522 (scroll-up (or arg 1)))
7523
7524(put 'scroll-up-line 'scroll-command t)
7525
7526(defun scroll-down-line (&optional arg)
7527 "Scroll text of selected window down ARG lines; or one line if no ARG.
7528If ARG is omitted or nil, scroll down by one line.
7529This is different from `scroll-down-command' that scrolls a full screen."
7530 (interactive "p")
7531 (scroll-down (or arg 1)))
7532
7533(put 'scroll-down-line 'scroll-command t)
7534
7535\f
011474aa 7536(defun scroll-other-window-down (&optional lines)
74f806a1
JL
7537 "Scroll the \"other window\" down.
7538For more details, see the documentation for `scroll-other-window'."
7539 (interactive "P")
7540 (scroll-other-window
7541 ;; Just invert the argument's meaning.
7542 ;; We can do that without knowing which window it will be.
7543 (if (eq lines '-) nil
7544 (if (null lines) '-
7545 (- (prefix-numeric-value lines))))))
7546
7547(defun beginning-of-buffer-other-window (arg)
7548 "Move point to the beginning of the buffer in the other window.
7549Leave mark at previous position.
7550With arg N, put point N/10 of the way from the true beginning."
7551 (interactive "P")
7552 (let ((orig-window (selected-window))
7553 (window (other-window-for-scrolling)))
7554 ;; We use unwind-protect rather than save-window-excursion
7555 ;; because the latter would preserve the things we want to change.
7556 (unwind-protect
7557 (progn
7558 (select-window window)
7559 ;; Set point and mark in that window's buffer.
7560 (with-no-warnings
7561 (beginning-of-buffer arg))
7562 ;; Set point accordingly.
7563 (recenter '(t)))
7564 (select-window orig-window))))
7565
7566(defun end-of-buffer-other-window (arg)
7567 "Move point to the end of the buffer in the other window.
7568Leave mark at previous position.
7569With arg N, put point N/10 of the way from the true end."
7570 (interactive "P")
7571 ;; See beginning-of-buffer-other-window for comments.
7572 (let ((orig-window (selected-window))
7573 (window (other-window-for-scrolling)))
7574 (unwind-protect
7575 (progn
7576 (select-window window)
7577 (with-no-warnings
7578 (end-of-buffer arg))
7579 (recenter '(t)))
7580 (select-window orig-window))))
74f806a1 7581\f
3c448ab6
MR
7582(defvar mouse-autoselect-window-timer nil
7583 "Timer used by delayed window autoselection.")
7584
7585(defvar mouse-autoselect-window-position nil
7586 "Last mouse position recorded by delayed window autoselection.")
7587
7588(defvar mouse-autoselect-window-window nil
7589 "Last window recorded by delayed window autoselection.")
7590
7591(defvar mouse-autoselect-window-state nil
7592 "When non-nil, special state of delayed window autoselection.
382c953b
JB
7593Possible values are `suspend' (suspend autoselection after a menu or
7594scrollbar interaction) and `select' (the next invocation of
7595`handle-select-window' shall select the window immediately).")
3c448ab6
MR
7596
7597(defun mouse-autoselect-window-cancel (&optional force)
7598 "Cancel delayed window autoselection.
7599Optional argument FORCE means cancel unconditionally."
7600 (unless (and (not force)
7601 ;; Don't cancel for select-window or select-frame events
7602 ;; or when the user drags a scroll bar.
7603 (or (memq this-command
7604 '(handle-select-window handle-switch-frame))
7605 (and (eq this-command 'scroll-bar-toolkit-scroll)
7606 (memq (nth 4 (event-end last-input-event))
7607 '(handle end-scroll)))))
7608 (setq mouse-autoselect-window-state nil)
7609 (when (timerp mouse-autoselect-window-timer)
7610 (cancel-timer mouse-autoselect-window-timer))
7611 (remove-hook 'pre-command-hook 'mouse-autoselect-window-cancel)))
7612
7613(defun mouse-autoselect-window-start (mouse-position &optional window suspend)
7614 "Start delayed window autoselection.
7615MOUSE-POSITION is the last position where the mouse was seen as returned
7616by `mouse-position'. Optional argument WINDOW non-nil denotes the
7617window where the mouse was seen. Optional argument SUSPEND non-nil
7618means suspend autoselection."
7619 ;; Record values for MOUSE-POSITION, WINDOW, and SUSPEND.
7620 (setq mouse-autoselect-window-position mouse-position)
7621 (when window (setq mouse-autoselect-window-window window))
7622 (setq mouse-autoselect-window-state (when suspend 'suspend))
7623 ;; Install timer which runs `mouse-autoselect-window-select' after
7624 ;; `mouse-autoselect-window' seconds.
7625 (setq mouse-autoselect-window-timer
7626 (run-at-time
7627 (abs mouse-autoselect-window) nil 'mouse-autoselect-window-select)))
7628
7629(defun mouse-autoselect-window-select ()
7630 "Select window with delayed window autoselection.
7631If the mouse position has stabilized in a non-selected window, select
382c953b
JB
7632that window. The minibuffer window is selected only if the minibuffer
7633is active. This function is run by `mouse-autoselect-window-timer'."
6198ccd0
MR
7634 (ignore-errors
7635 (let* ((mouse-position (mouse-position))
7636 (window
7637 (ignore-errors
7638 (window-at (cadr mouse-position) (cddr mouse-position)
7639 (car mouse-position)))))
7640 (cond
e740f9d2 7641 ((or (and (fboundp 'menu-or-popup-active-p) (menu-or-popup-active-p))
6198ccd0 7642 (and window
3dfc5cd6
MR
7643 (let ((coords (coordinates-in-window-p
7644 (cdr mouse-position) window)))
7645 (and (not (consp coords))
7646 (not (memq coords '(left-margin right-margin)))))))
c660a885
MR
7647 ;; A menu / popup dialog is active or the mouse is not on the
7648 ;; text region of WINDOW: Suspend autoselection temporarily.
6198ccd0
MR
7649 (mouse-autoselect-window-start mouse-position nil t))
7650 ((eq mouse-autoselect-window-state 'suspend)
7651 ;; Delayed autoselection was temporarily suspended, reenable it.
7652 (mouse-autoselect-window-start mouse-position))
7653 ((and window (not (eq window (selected-window)))
7654 (or (not (numberp mouse-autoselect-window))
7655 (and (> mouse-autoselect-window 0)
7656 ;; If `mouse-autoselect-window' is positive, select
7657 ;; window if the window is the same as before.
7658 (eq window mouse-autoselect-window-window))
7659 ;; Otherwise select window if the mouse is at the same
7660 ;; position as before. Observe that the first test after
7661 ;; starting autoselection usually fails since the value of
7662 ;; `mouse-autoselect-window-position' recorded there is the
7663 ;; position where the mouse has entered the new window and
7664 ;; not necessarily where the mouse has stopped moving.
7665 (equal mouse-position mouse-autoselect-window-position))
7666 ;; The minibuffer is a candidate window if it's active.
7667 (or (not (window-minibuffer-p window))
7668 (eq window (active-minibuffer-window))))
7669 ;; Mouse position has stabilized in non-selected window: Cancel
7670 ;; delayed autoselection and try to select that window.
7671 (mouse-autoselect-window-cancel t)
7672 ;; Select window where mouse appears unless the selected window is the
7673 ;; minibuffer. Use `unread-command-events' in order to execute pre-
7674 ;; and post-command hooks and trigger idle timers. To avoid delaying
7675 ;; autoselection again, set `mouse-autoselect-window-state'."
290d5b58 7676 (unless (window-minibuffer-p)
6198ccd0
MR
7677 (setq mouse-autoselect-window-state 'select)
7678 (setq unread-command-events
7679 (cons (list 'select-window (list window))
7680 unread-command-events))))
7681 ((or (and window (eq window (selected-window)))
7682 (not (numberp mouse-autoselect-window))
7683 (equal mouse-position mouse-autoselect-window-position))
7684 ;; Mouse position has either stabilized in the selected window or at
7685 ;; `mouse-autoselect-window-position': Cancel delayed autoselection.
7686 (mouse-autoselect-window-cancel t))
7687 (t
7688 ;; Mouse position has not stabilized yet, resume delayed
7689 ;; autoselection.
7690 (mouse-autoselect-window-start mouse-position window))))))
3c448ab6
MR
7691
7692(defun handle-select-window (event)
7693 "Handle select-window events."
7694 (interactive "e")
7695 (let ((window (posn-window (event-start event))))
7696 (unless (or (not (window-live-p window))
7697 ;; Don't switch if we're currently in the minibuffer.
7698 ;; This tries to work around problems where the
7699 ;; minibuffer gets unselected unexpectedly, and where
7700 ;; you then have to move your mouse all the way down to
7701 ;; the minibuffer to select it.
290d5b58 7702 (window-minibuffer-p)
3c448ab6
MR
7703 ;; Don't switch to minibuffer window unless it's active.
7704 (and (window-minibuffer-p window)
7705 (not (minibuffer-window-active-p window)))
7706 ;; Don't switch when autoselection shall be delayed.
7707 (and (numberp mouse-autoselect-window)
7708 (not (zerop mouse-autoselect-window))
7709 (not (eq mouse-autoselect-window-state 'select))
7710 (progn
7711 ;; Cancel any delayed autoselection.
7712 (mouse-autoselect-window-cancel t)
7713 ;; Start delayed autoselection from current mouse
7714 ;; position and window.
7715 (mouse-autoselect-window-start (mouse-position) window)
7716 ;; Executing a command cancels delayed autoselection.
7717 (add-hook
7718 'pre-command-hook 'mouse-autoselect-window-cancel))))
7719 (when mouse-autoselect-window
7720 ;; Reset state of delayed autoselection.
7721 (setq mouse-autoselect-window-state nil)
7722 ;; Run `mouse-leave-buffer-hook' when autoselecting window.
7723 (run-hooks 'mouse-leave-buffer-hook))
b1bac16e
MR
7724 ;; Clear echo area.
7725 (message nil)
3c448ab6
MR
7726 (select-window window))))
7727
3c448ab6
MR
7728(defun truncated-partial-width-window-p (&optional window)
7729 "Return non-nil if lines in WINDOW are specifically truncated due to its width.
85c2386b 7730WINDOW must be a live window and defaults to the selected one.
3c448ab6
MR
7731Return nil if WINDOW is not a partial-width window
7732 (regardless of the value of `truncate-lines').
7733Otherwise, consult the value of `truncate-partial-width-windows'
7734 for the buffer shown in WINDOW."
85c2386b 7735 (setq window (window-normalize-window window t))
3c448ab6
MR
7736 (unless (window-full-width-p window)
7737 (let ((t-p-w-w (buffer-local-value 'truncate-partial-width-windows
7738 (window-buffer window))))
7739 (if (integerp t-p-w-w)
7740 (< (window-width window) t-p-w-w)
7741 t-p-w-w))))
562dd5e9 7742\f
59ee0542
GM
7743;; Some of these are in tutorial--default-keys, so update that if you
7744;; change these.
562dd5e9
MR
7745(define-key ctl-x-map "0" 'delete-window)
7746(define-key ctl-x-map "1" 'delete-other-windows)
2d197ffb
CY
7747(define-key ctl-x-map "2" 'split-window-below)
7748(define-key ctl-x-map "3" 'split-window-right)
9397e56f 7749(define-key ctl-x-map "o" 'other-window)
562dd5e9 7750(define-key ctl-x-map "^" 'enlarge-window)
3c448ab6
MR
7751(define-key ctl-x-map "}" 'enlarge-window-horizontally)
7752(define-key ctl-x-map "{" 'shrink-window-horizontally)
7753(define-key ctl-x-map "-" 'shrink-window-if-larger-than-buffer)
7754(define-key ctl-x-map "+" 'balance-windows)
7755(define-key ctl-x-4-map "0" 'kill-buffer-and-window)
7756
3c448ab6 7757;;; window.el ends here