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