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