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