+;;; Window states, how to get them and how to put them in a window.
+(defsubst window-list-no-nils (&rest args)
+ "Like LIST but do not add nil elements of ARGS."
+ (delq nil (apply 'list args)))
+
+(defvar window-state-ignored-parameters '(quit-restore)
+ "List of window parameters ignored by `window-state-get'.")
+
+(defun window-state-get-1 (window &optional markers)
+ "Helper function for `window-state-get'."
+ (let* ((type
+ (cond
+ ((window-top-child window) 'vc)
+ ((window-left-child window) 'hc)
+ (t 'leaf)))
+ (buffer (window-buffer window))
+ (selected (eq window (selected-window)))
+ (head
+ (window-list-no-nils
+ type
+ (unless (window-next-sibling window) (cons 'last t))
+ (cons 'total-height (window-total-size window))
+ (cons 'total-width (window-total-size window t))
+ (cons 'normal-height (window-normal-size window))
+ (cons 'normal-width (window-normal-size window t))
+ (cons 'splits (window-splits window))
+ (cons 'nest (window-nest window))
+ (let (list)
+ (dolist (parameter (window-parameters window))
+ (unless (memq (car parameter)
+ window-state-ignored-parameters)
+ (setq list (cons parameter list))))
+ (unless (window-parameter window 'clone-of)
+ ;; Make a clone-of parameter.
+ (setq list (cons (cons 'clone-of window) list)))
+ (when list
+ (cons 'parameters list)))
+ (when buffer
+ ;; All buffer related things go in here - make the buffer
+ ;; current when retrieving `point' and `mark'.
+ (with-current-buffer (window-buffer window)
+ (let ((point (if selected (point) (window-point window)))
+ (start (window-start window))
+ (mark (mark)))
+ (window-list-no-nils
+ 'buffer (buffer-name buffer)
+ (cons 'selected selected)
+ (when window-size-fixed (cons 'size-fixed window-size-fixed))
+ (cons 'hscroll (window-hscroll window))
+ (cons 'fringes (window-fringes window))
+ (cons 'margins (window-margins window))
+ (cons 'scroll-bars (window-scroll-bars window))
+ (cons 'vscroll (window-vscroll window))
+ (cons 'dedicated (window-dedicated-p window))
+ (cons 'point (if markers (copy-marker point) point))
+ (cons 'start (if markers (copy-marker start) start))
+ (when mark
+ (cons 'mark (if markers (copy-marker mark) mark)))))))))
+ (tail
+ (when (memq type '(vc hc))
+ (let (list)
+ (setq window (window-child window))
+ (while window
+ (setq list (cons (window-state-get-1 window markers) list))
+ (setq window (window-right window)))
+ (nreverse list)))))
+ (append head tail)))
+
+(defun window-state-get (&optional window markers)
+ "Return state of WINDOW as a Lisp object.
+WINDOW can be any window and defaults to the root window of the
+selected frame.
+
+Optional argument MARKERS non-nil means use markers for sampling
+positions like `window-point' or `window-start'. MARKERS should
+be non-nil only if the value is used for putting the state back
+in the same session (note that markers slow down processing).
+
+The return value can be used as argument for `window-state-put'
+to put the state recorded here into an arbitrary window. The
+value can be also stored on disk and read back in a new session."
+ (setq window
+ (if window
+ (if (window-any-p window)
+ window
+ (error "%s is not a live or internal window" window))
+ (frame-root-window)))
+ ;; The return value is a cons whose car specifies some constraints on
+ ;; the size of WINDOW. The cdr lists the states of the subwindows of
+ ;; WINDOW.
+ (cons
+ ;; Frame related things would go into a function, say `frame-state',
+ ;; calling `window-state-get' to insert the frame's root window.
+ (window-list-no-nils
+ (cons 'min-height (window-min-size window))
+ (cons 'min-width (window-min-size window t))
+ (cons 'min-height-ignore (window-min-size window nil t))
+ (cons 'min-width-ignore (window-min-size window t t))
+ (cons 'min-height-safe (window-min-size window nil 'safe))
+ (cons 'min-width-safe (window-min-size window t 'safe))
+ ;; These are probably not needed.
+ (when (window-size-fixed-p window) (cons 'fixed-height t))
+ (when (window-size-fixed-p window t) (cons 'fixed-width t)))
+ (window-state-get-1 window markers)))
+
+(defvar window-state-put-list nil
+ "Helper variable for `window-state-put'.")
+
+(defun window-state-put-1 (state &optional window ignore totals)
+ "Helper function for `window-state-put'."
+ (let ((type (car state)))
+ (setq state (cdr state))
+ (cond
+ ((eq type 'leaf)
+ ;; For a leaf window just add unprocessed entries to
+ ;; `window-state-put-list'.
+ (setq window-state-put-list
+ (cons (cons window state) window-state-put-list)))
+ ((memq type '(vc hc))
+ (let* ((horizontal (eq type 'hc))
+ (total (window-total-size window horizontal))
+ (first t)
+ size new)
+ (dolist (item state)
+ ;; Find the next child window. WINDOW always points to the
+ ;; real window that we want to fill with what we find here.
+ (when (memq (car item) '(leaf vc hc))
+ (if (assq 'last item)
+ ;; The last child window. Below `window-state-put-1'
+ ;; will put into it whatever ITEM has in store.
+ (setq new nil)
+ ;; Not the last child window, prepare for splitting
+ ;; WINDOW. SIZE is the new (and final) size of the old
+ ;; window.
+ (setq size
+ (if totals
+ ;; Use total size.
+ (cdr (assq (if horizontal 'total-width 'total-height) item))
+ ;; Use normalized size and round.
+ (round (* total
+ (cdr (assq
+ (if horizontal 'normal-width 'normal-height)
+ item))))))
+
+ ;; Use safe sizes, we try to resize later.
+ (setq size (max size (if horizontal
+ window-safe-min-height
+ window-safe-min-width)))
+
+ (if (window-sizable-p window (- size) horizontal 'safe)
+ (let* ((window-nest (assq 'nest item)))
+ ;; We must inherit the nesting, otherwise we might mess
+ ;; up handling of atomic and side window.
+ (setq new (split-window window size horizontal)))
+ ;; Give up if we can't resize window down to safe sizes.
+ (error "Cannot resize window %s" window))
+
+ (when first
+ (setq first nil)
+ ;; When creating the first child window add for parent
+ ;; unprocessed entries to `window-state-put-list'.
+ (setq window-state-put-list
+ (cons (cons (window-parent window) state)
+ window-state-put-list))))
+
+ ;; Now process the current window (either the one we've just
+ ;; split or the last child of its parent).
+ (window-state-put-1 item window ignore totals)
+ ;; Continue with the last window split off.
+ (setq window new))))))))
+
+(defun window-state-put-2 (ignore)
+ "Helper function for `window-state-put'."
+ (dolist (item window-state-put-list)
+ (let ((window (car item))
+ (splits (cdr (assq 'splits item)))
+ (nest (cdr (assq 'nest item)))
+ (parameters (cdr (assq 'parameters item)))
+ (state (cdr (assq 'buffer item))))
+ (when splits (set-window-splits window splits))
+ (when nest (set-window-nest window nest))
+ ;; Process parameters.
+ (when parameters
+ (dolist (parameter parameters)
+ (set-window-parameter window (car parameter) (cdr parameter))))
+ ;; Process buffer related state.
+ (when state
+ ;; We don't want to raise an error here so we create a buffer if
+ ;; there's none.
+ (set-window-buffer window (get-buffer-create (car state)))
+ (with-current-buffer (window-buffer window)
+ (set-window-hscroll window (cdr (assq 'hscroll state)))
+ (apply 'set-window-fringes
+ (cons window (cdr (assq 'fringes state))))
+ (let ((margins (cdr (assq 'margins state))))
+ (set-window-margins window (car margins) (cdr margins)))
+ (let ((scroll-bars (cdr (assq 'scroll-bars state))))
+ (set-window-scroll-bars
+ window (car scroll-bars) (nth 2 scroll-bars) (nth 3 scroll-bars)))
+ (set-window-vscroll window (cdr (assq 'vscroll state)))
+ ;; Adjust vertically.
+ (if (memq window-size-fixed '(t height))
+ ;; A fixed height window, try to restore the original size.
+ (let ((delta (- (cdr (assq 'total-height item))
+ (window-total-height window)))
+ window-size-fixed)
+ (when (window-resizable-p window delta)
+ (window-resize window delta)))
+ ;; Else check whether the window is not high enough.
+ (let* ((min-size (window-min-size window nil ignore))
+ (delta (- min-size (window-total-size window))))
+ (when (and (> delta 0)
+ (window-resizable-p window delta nil ignore))
+ (window-resize window delta nil ignore))))
+ ;; Adjust horizontally.
+ (if (memq window-size-fixed '(t width))
+ ;; A fixed width window, try to restore the original size.
+ (let ((delta (- (cdr (assq 'total-width item))
+ (window-total-width window)))
+ window-size-fixed)
+ (when (window-resizable-p window delta)
+ (window-resize window delta)))
+ ;; Else check whether the window is not wide enough.
+ (let* ((min-size (window-min-size window t ignore))
+ (delta (- min-size (window-total-size window t))))
+ (when (and (> delta 0)
+ (window-resizable-p window delta t ignore))
+ (window-resize window delta t ignore))))
+ ;; Set dedicated status.
+ (set-window-dedicated-p window (cdr (assq 'dedicated state)))
+ ;; Install positions (maybe we should do this after all windows
+ ;; have been created and sized).
+ (ignore-errors
+ (set-window-start window (cdr (assq 'start state)))
+ (set-window-point window (cdr (assq 'point state)))
+ ;; I'm not sure whether we should set the mark here, but maybe
+ ;; it can be used.
+ (let ((mark (cdr (assq 'mark state))))
+ (when mark (set-mark mark))))
+ ;; Select window if it's the selected one.
+ (when (cdr (assq 'selected state))
+ (select-window window)))))))
+
+(defun window-state-put (state &optional window ignore)
+ "Put window state STATE into WINDOW.
+STATE should be the state of a window returned by an earlier
+invocation of `window-state-get'. Optional argument WINDOW must
+specify a live window and defaults to the selected one.
+
+Optional argument IGNORE non-nil means ignore minimum window
+sizes and fixed size restrictions. IGNORE equal `safe' means
+subwindows can get as small as `window-safe-min-height' and
+`window-safe-min-width'."
+ (setq window (window-normalize-live-window window))
+ (let* ((frame (window-frame window))
+ (head (car state))
+ ;; We check here (1) whether the total sizes of root window of
+ ;; STATE and that of WINDOW are equal so we can avoid
+ ;; calculating new sizes, and (2) if we do have to resize
+ ;; whether we can do so without violating size restrictions.
+ (totals
+ (and (= (window-total-size window)
+ (cdr (assq 'total-height state)))
+ (= (window-total-size window t)
+ (cdr (assq 'total-width state)))))
+ (min-height (cdr (assq 'min-height head)))
+ (min-width (cdr (assq 'min-width head)))
+ window-splits selected)
+ (if (and (not totals)
+ (or (> min-height (window-total-size window))
+ (> min-width (window-total-size window t)))
+ (or (not ignore)
+ (and (setq min-height
+ (cdr (assq 'min-height-ignore head)))
+ (setq min-width
+ (cdr (assq 'min-width-ignore head)))
+ (or (> min-height (window-total-size window))
+ (> min-width (window-total-size window t)))
+ (or (not (eq ignore 'safe))
+ (and (setq min-height
+ (cdr (assq 'min-height-safe head)))
+ (setq min-width
+ (cdr (assq 'min-width-safe head)))
+ (or (> min-height
+ (window-total-size window))
+ (> min-width
+ (window-total-size window t))))))))
+ ;; The check above might not catch all errors due to rounding
+ ;; issues - so IGNORE equal 'safe might not always produce the
+ ;; minimum possible state. But such configurations hardly make
+ ;; sense anyway.
+ (error "Window %s too small to accomodate state" window)
+ (setq state (cdr state))
+ (setq window-state-put-list nil)
+ ;; Work on the windows of a temporary buffer to make sure that
+ ;; splitting proceeds regardless of any buffer local values of
+ ;; `window-size-fixed'. Release that buffer after the buffers of
+ ;; all live windows have been set by `window-state-put-2'.
+ (with-temp-buffer
+ (set-window-buffer window (current-buffer))
+ (window-state-put-1 state window nil totals)
+ (window-state-put-2 ignore))
+ (window-check frame))))
+\f
+(defconst display-buffer-macro-specifiers
+ '((same-window
+ ;; Use the same window.
+ (reuse-window same nil nil))
+ (same-frame
+ ;; Avoid other frames.
+ (reuse-window nil same nil)
+ (pop-up-window (largest . nil) (lru . nil))
+ (reuse-window nil other nil))
+ (same-frame-other-window
+ ;; Avoid other frames and selected window.
+ (reuse-window other same nil)
+ (pop-up-window (largest . nil) (lru . nil))
+ (reuse-window other other nil))
+ (other-frame
+ ;; Avoid selected frame.
+ (reuse-window nil same other)
+ (pop-up-frame)
+ (reuse-window nil other other)))
+ "Buffer display macro specifiers.")
+
+(defcustom display-buffer-alist nil
+ "List associating buffer identifiers with display specifiers.
+The car of each element of this list is built from a set of cons
+cells called buffer identifiers. `display-buffer' shows a buffer
+according to the display specifiers in the element's cdr
+\(elements are true lists) if at least one of the identifiers
+matches the first or third argument of `display-buffer'. Such a
+match occurs in one of the following three cases:
+
+- The car of the buffer identifier is the symbol `name' and its
+ cdr is a string equalling the name of the buffer specified by
+ the first \(BUFFER-OR-NAME) argument of `display-buffer'.
+
+- The car is the symbol `regexp' and the cdr is a regular
+ expression matching the name of the buffer specified by the
+ first \(BUFFER-OR-NAME) argument of `display-buffer'.
+
+- The car is the symbol `label' and the cdr is a symbol equalling
+ the third \(LABEL) argument of `display-buffer'.
+
+Display specifiers are either symbols, cons cells, or lists.
+Five specifiers have been reserved to indicate the basic method
+for displaying the buffer: `reuse-window', `pop-up-window',
+`pop-up-frame', `use-side-window', and `function'.
+
+A list whose car is the symbol `reuse-window' indicates that an
+existing window shall be reused for displaying the buffer. The
+second element of this list specifies the window to use and can
+be one of the following symbols:
+
+ nil stands for any window.
+
+ `same' stands for the selected window.
+
+ `other' stands for any but the selected window.
+
+The third element specifies whether the buffer shown in a window
+that shall be reused must be the same buffer that shall be
+displayed or another buffer and can be one of the following:
+
+ nil means to not care about the window's buffer.
+
+ `same' means the window must show the buffer already.
+
+ `other' means the window must not show the buffer yet.
+
+The fourth element specifies the set of frames to search for a
+suitable window and can be one of the following:
+
+ nil to reuse a window on the selected frame.
+
+ `visible' to search visible frames on the current terminal.
+
+ `other' stands for any visible frame but the selected one.
+
+ 0 \(the number zero) to search visible and iconified frames on
+ the current terminal.
+
+ t to search arbitrary frames including invisible ones.
+
+If more than one window fits the constraints imposed by these
+elements, the least recently used candidate is chosen. A side
+window is never reused unless it already shows the buffer.
+
+The following two specifiers are useful when the method equals
+`reuse-window':
+
+- A cons cell whose car is the symbol `reuse-window-even-sizes'
+ and whose cdr is non-nil means to even out the sizes of a
+ reused window and the selected window provided they (1) appear
+ adjacent to each other and (2) the selected window is larger
+ than the window chosen. If the cdr is nil, this means that the
+ window sizes are left alone.
+
+- A cons cell whose car is the symbol `reuse-window-dedicated'
+ and whose cdr is non-nil means that a window can be reused even
+ if it's weakly dedicated to its buffer. If the cdr is t, a
+ strongly dedicated window can be reused to show the buffer.
+ Any other non-nil value means only weakly dedicated windows can
+ be reused. If the cdr is nil, dedicated windows are not
+ reused.
+
+ This specifier should be used in emergency cases only since
+ windows are usually made dedicated in order to prevent
+ `display-buffer' from reusing them.
+
+A list whose car is the symbol `pop-up-window' and whose cdr is
+built from cons cells representing window/side tuples indicates
+that a new window shall be made for displaying the buffer on the
+selected frame.
+
+Window/side tuples are cons cells. The car of such a tuple
+identifies the window that shall be split. Possible values are
+`largest', `lru', `selected', and `root' to split the largest,
+least recently used, selected or root window of the selected
+frame.
+
+If the frame has side windows, these values do allow to split
+only the selected frame's main window or one of its subwindows.
+Setting the car to one of `left', `top', `right' and `bottom'
+splits the corresponding side window, provided such a window
+exists.
+
+The cdr of each pair specifies on which side of the window to
+split the new window shall appear and can be one of `below',
+`right', `above', or `left' with the obvious meanings. If the
+cdr is nil, the window is split in a fashion suitable for its
+current dimensions. If the cdr specifies a function, that
+function is called with one argument - the window to split. The
+function is supposed to split that window and return the new
+window.
+
+`display-buffer' scans these tuples until it can either produce a
+suitable window or fails. The default value for
+`display-buffer-alist' contains the tuples \(largest . nil) and
+\(lru . nil) in order to split the largest window first and, if
+that fails, the least recently used one.
+
+The following specifiers are useful if the method specifier is
+`pop-up-window'.
+
+- A cons cell whose car is the symbol `pop-up-window-min-height'
+ specifiies the minimum height of the new window. If the cdr is
+ an integer number, it specifies the minimum number of lines of
+ the window. A floating point number gives the minimum fraction
+ of the window height with respect to the height of the frame's
+ root window. A new window is created only if it can be made at
+ least as high as specified by the number. If the cdr is nil,
+ this means to use the value of `window-min-height'.
+
+- A cons cell whose car is the symbol `pop-up-window-min-width'
+ specifies the minimum width of the new window. If the cdr is
+ an integer number, it specifies the minimum number of columns
+ of the window. A floating point number gives the minimum
+ fraction of the window width with respect to the width of the
+ frame's root window. A new window is created only if it can be
+ made at least as wide as specified by the number. If the cdr
+ is nil, this means to use the value of `window-min-width'.
+
+- A cons cell whose car is `pop-up-window-set-height' with
+ the following interpretations for the cdr:
+
+ - nil means leave the height of the new window alone.
+
+ - A number specifies the desired height of the new window. An
+ integer number specifies the number of lines of the window.
+ A floating point number gives the fraction of the window
+ height with respect to the height of the frame's root window.
+
+ - If the cdr specifies a function, that function is called with
+ one argument - the new window. The function is supposed to
+ adjust the height of the window; its return value is ignored.
+ Suitable functions are `shrink-window-if-larger-than-buffer'
+ and `fit-window-to-buffer'.
+
+- A cons cell whose car equals `pop-up-window-set-width' with
+ the following interpretations for the cdr:
+
+ - nil means leave the width of the new window alone.
+
+ - A number specifies the desired width of the new window. An
+ integer number specifies the number of columns of the window.
+ A floating point number gives the fraction of the window
+ width with respect to the width of the frame's root window.
+
+ - If the cdr specifies a function, that function is called with
+ one argument - the new window. The function is supposed to
+ adjust the width of the window; its return value is ignored.
+
+ Observe that specifying `pop-up-window-set-height' or
+ `pop-up-window-set-width' may override restrictions given by
+ the `pop-up-window-min-height' and `pop-up-window-min-width'
+ specifiers.
+
+- A cons cell whose car is `pop-up-window-split-unsplittable' and
+ whose cdr is non-nil allows to make a new window on an
+ unsplittable frame. If the cdr is nil, unsplittable frames are
+ not split. This specifier should be used in special cases only
+ since frames are usually made unsplittable in order to prevent
+ `display-buffer' from splitting them.
+
+A list whose car is the symbol `pop-up-frame' specifies that a
+new frame shall be made for displaying the buffer. The second
+element, if non-nil, allows popping up a new frame on graphic
+displays only.
+
+The following specifiers are useful if the method specifier is
+`pop-up-frame'.
+
+- A list whose car is the symbol `pop-up-frame-function' together
+ with a valid function as cdr specifies the function for
+ creating a new frame. If the cdr is nil, the default function
+ `make-frame' is called. The function is called with the
+ parameters and values provided by the specifier described next.
+
+- A list whose car is the symbol `pop-up-frame-alist' followed by
+ an arbitrary number of frame parameter/value tuples, each given
+ as a cons cell, specifies the parameters passed to the pop-up
+ frame function.
+
+A list of three elements whose car is the symbol
+`use-side-window' specifies that the buffer shall be displayed in
+a side window of the selected frame. The second element denotes
+the side of the frame where the window appears or shall be made.
+The third element denotes the slot used by the window. If a side
+window with the specified slot exists already, that window is
+reused. If no such window exists it is created.
+
+The following specifiers are useful in connection with the
+`use-side-window' method specifier: `reuse-window-dedicated',
+`pop-up-window-min-height', `pop-up-window-min-width',
+`pop-up-window-set-height' and `pop-up-window-set-width'.
+
+A list whose car is the symbol `function' specifies that the
+function specified in the second element of the list is
+responsible for displaying the buffer. `display-buffer' calls
+this function with the buffer as first argument and the remaining
+elements of the list as the second.
+
+The function should choose or create a window, display the buffer
+in it, and return the window. It is also responsible for giving
+the variable `display-buffer-window' and the `quit-restore'
+parameter of the window used a meaningful value.
+
+Within the body of this function avoid calling `display-buffer'
+with the same buffer as argument since this may lead to endless
+recursion.
+
+Instead of supplying basic method specifiers, it's sometimes more
+convenient to use macro specifiers. They provide some commonly
+used display methods but do not support the fine control provided
+by the basic method specifiers. Macro specifiers are symbols.
+The following macro specifiers are provided:
+
+ `same-window' to display the buffer in the selected window.
+
+ `same-frame' to display the buffer on the selected frame.
+
+ `other-window' to display the buffer in any window but the
+ selected one.
+
+ `same-frame-other-window' as `other-window' but stay on the
+ selected frame.
+
+ `other-frame' to display the buffer on another visible
+ frame.
+
+ `default' to use the default value of `display-buffer-alist'.
+
+One specifier is useful with any method specifier: A list whose
+car is the symbol `dedicate' and whose cdr is non-nil will
+dedicate the window to its buffer. The following values are
+supported:
+
+- nil to not dedicate the window to the buffer.
+
+- `weak' to weakly dedicate the window to the buffer.
+
+- t to strongly dedicate the window to the buffer.
+
+A cons cell whose car is `other-window-means-other-frame' and
+whose cdr is non-nil means that you want calls of
+`display-buffer' with the second argument t or the symbol
+`other-window' to display the buffer in another frame. This
+means, for example, that you prefer functions like
+`find-file-other-window' or `switch-to-buffer-other-window' to
+make a new frame instead of a new window on the selected frame.
+
+Usually, applications are free to override the specifiers of
+`display-buffer-alist' by passing their own specifiers as second
+argument of `display-buffer'. For every `display-buffer-alist'
+entry you can, however, add a cons cell whose car is the symbol
+`override' and whose cdr is non-nil, to explicitly override any
+value supplied by the application.
+
+Overriding specifiers supplied by the calling application is, in
+general, not advisable. It permits, for example, to change the
+semantics of a function like `display-buffer-other-window' by
+using the location specifiers `same-window' or `other-frame'."
+ :risky t
+ :type
+ '(repeat
+ :offset 9
+ ;; Associations of buffer identifiers and display specifiers.
+ (list
+ :format "%v"
+ ;; Buffer identifiers.
+ (repeat
+ :tag "Buffer identifiers"
+ (choice
+ :tag "Identifier"
+ :format "%[%t%] %v" :size 15
+ (cons
+ :tag "Name"
+ :format "%v"
+ :help-echo "A buffer name."
+ (const :format "" name)
+ (string :format "Name: %v\n" :size 32))
+ (cons
+ :tag "Regexp"
+ :format "%v"
+ :help-echo "A regular expression matching buffer names."
+ (const :format "" regexp)
+ (string :format "Regexp: %v\n" :size 32))
+ (cons
+ :tag "Label"
+ :format "%v"
+ :help-echo "A symbol equalling the buffer display label."
+ (const :format "" label)
+ (symbol :format "Label: %v\n" :size 32))))
+
+ ;; Display specifiers.
+ (repeat
+ :offset 9
+ :tag "Display specifiers"
+ :inline t
+ (list
+ :inline t
+ :format "%v"
+ (choice
+ :tag "Method"
+ :value (reuse-window
+ (reuse-window nil same nil)
+ (reuse-window-even-sizes . t))
+ :inline t
+ :help-echo "Method for displaying the buffer."
+ :format "%[Method%] %v" :size 15
+
+ ;; Reuse window specifiers.
+ (list
+ :tag "Reuse window"
+ :value (reuse-window
+ (reuse-window nil same nil)
+ (reuse-window-even-sizes . t))
+ :format "%t\n%v"
+ :inline t
+ ;; For customization purposes only.
+ (const :format "" reuse-window)
+ (set
+ :format "%v"
+ :inline t
+ ;; The window to reuse.
+ (list
+ :format "%v\n"
+ (const :format "" reuse-window)
+ ;; The window type.
+ (choice
+ :tag "Window"
+ :help-echo "Window to reuse."
+ :value nil
+ :format "%[Window%] %v" :size 15
+ (const :tag "Any window" :format "%t" nil)
+ (const :tag "Same window" :format "%t" same)
+ (const :tag "Other window" :format "%t" other))
+ ;; The window's buffer.
+ (choice
+ :tag "Buffer"
+ :help-echo "Buffer shown by reused window."
+ :value t
+ :format " %[Buffer%] %v" :size 15
+ (const :tag "Any buffer" :format "%t" nil)
+ (const :tag "Same buffer" :format "%t" same)
+ (const :tag "Other buffer" :format "%t" other))
+ ;; The window's frame.
+ (choice
+ :help-echo "Frames to search for a window to reuse."
+ :tag "Frame"
+ :value nil
+ :format " %[Frame%] %v" :size 15
+ (const :tag "Same frame only" :format "%t" nil)
+ (const :tag "Visible frames" :format "%t" visible)
+ (const :tag "Any other visible frame" :format "%t" other)
+ (const :tag "Visible and iconified frames" :format "%t" 0)
+ (const :tag "All frames" :format "%t" t)))
+ ;; Whether window sizes should be evened out.
+ (cons
+ :format "%v\n"
+ :tag "Even window sizes"
+ (const :format "" reuse-window-even-sizes)
+ (choice
+ :tag "Even window sizes"
+ :help-echo "Whether to even sizes of selected and reused window."
+ :value t
+ :format "%[Even window sizes%] %v" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Even window sizes" :format "%t" t)))
+ ;; Whether to reuse a dedicated window
+ (cons
+ :format "%v\n"
+ (const :format "" reuse-window-dedicated)
+ (choice
+ :tag "Reuse dedicated window" :value nil
+ :help-echo "Reuse a window even if it is dedicated to its buffer."
+ :format "%[Reuse dedicated window%] %v" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Reuse weakly dedicated windows" :format "%t" weak)
+ (const :tag "Reuse any dedicated window" :format "%t" t)))))
+
+ ;; Pop-up window specifiers.
+ (list
+ :tag "Pop-up window"
+ :value (pop-up-window (pop-up-window (largest . nil) (lru . nil)))
+ :format "%t\n%v"
+ :inline t
+ (const :format "" pop-up-window)
+ (set
+ :format "%v"
+ :inline t
+ ;; Pop-up window list.
+ (list
+ :format "%v"
+ :value (pop-up-window (largest . nil) (lru . nil))
+ (const :format "" pop-up-window)
+ (repeat
+ :tag "Window / Side tuples"
+ :inline t
+ (cons
+ :format "%v\n"
+ (choice
+ :tag "Window"
+ :help-echo "The window to split."
+ :value largest
+ :format "%[Window%] %v"
+ (const :tag "Largest" :format "%t" largest)
+ (const :tag "Least recently used" :format "%t" lru)
+ (const :tag "Selected" :format "%t" selected)
+ (const :tag "Root" :format "%t" root)
+ (const :tag "Left" :format "%t" left)
+ (const :tag "Top" :format "%t" top)
+ (const :tag "Right" :format "%t" right)
+ (const :tag "Bottom" :format "%t" bottom))
+ (choice
+ :tag "Side"
+ :help-echo "The position of the new window with respect to the window to split."
+ :value nil
+ :format " %[Side%] %v"
+ (const :tag "Dynamic" :format "%t" nil)
+ (const :tag "Below" :format "%t" below)
+ (const :tag "Right" :format "%t" right)
+ (const :tag "Above" :format "%t" above)
+ (const :tag "Left" :format "%t" left)
+ (function
+ :tag "Function" :format "%v" :size 25)))))
+ ;; Minimum height of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-min-height)
+ (choice
+ :help-echo "Minimum height of popped-up window."
+ :format "%[Minimum height%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of lines" :value 12 :size 5)
+ (float :tag "Fraction of frame height" :value .25 :size 5)))
+ ;; Minimum width of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-min-width)
+ (choice
+ :help-echo "Minimum width of popped-up window."
+ :format "%[Minimum width%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of columns" :value 12 :size 5)
+ (float :tag "Fraction of frame width" :value .25 :size 5)))
+ ;; Desired height of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-set-height)
+ (choice
+ :help-echo "Desired height of popped-up window."
+ :format "%[Desired height%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of lines" :value 12 :size 5)
+ (float :tag "Fraction of frame height" :value .25 :size 5)
+ (function :tag "Function" :size 25)))
+ ;; Desired width of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-set-width)
+ (choice
+ :help-echo "Desired width of popped-up window."
+ :format "%[Desired width%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of column" :value 12 :size 5)
+ (float :tag "Fraction of frame width" :value .25 :size 5)
+ (function :tag "Function" :size 25)))
+ ;; Split unsplittable frames.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-unsplittable)
+ (choice
+ :help-echo "Allow popping up a window on \"unsplittable\" frames."
+ :format "%[Split unsplittable frame%] %v"
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Allow" :format "%t" t)))))
+
+ ;; Pop-up frame specifiers.
+ (list
+ :tag "Pop-up frame"
+ :value (pop-up-frame
+ (pop-up-frame))
+ :format "%t\n%v"
+ :inline t
+ (const :format "" pop-up-frame)
+ (set
+ :format "%v"
+ :inline t
+ ;; Pop-up frame.
+ (list
+ :tag "Pop-up a new frame"
+ :value (pop-up-frame)
+ :format "%v"
+ (const :format "" pop-up-frame)
+ (choice
+ :tag "Pop-up a new frame"
+ :help-echo "Whether to pop-up a new frame on a display."
+ :format "%[Display%] %v\n" :size 15
+ (const :tag "On any display" :format "%t" nil)
+ (const :tag "On graphic displays only" :format "%t" t)))
+ ;; Pop-up frame function.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-frame-function)
+ (choice
+ :tag "Pop-up frame function"
+ :value nil
+ :help-echo "Function to use to pop-up a new frame."
+ :format "%[Function%] %v" :size 15
+ (const :tag "Default" :format "%t" nil)
+ (function
+ :value make-frame
+ :format "%t: %v"
+ :size 25)))
+ ;; Pop-up frame alist.
+ (list
+ :format "%v"
+ (const :format "" pop-up-frame-alist)
+ (repeat
+ :tag "Parameter / Value tuples"
+ :inline t
+ (cons
+ :format "%v\n"
+ (symbol
+ :tag "Parameter"
+ :format "Parameter: %v"
+ :size 16)
+ (sexp
+ :tag "Value"
+ :format " Value: %v"
+ :size 8))))))
+
+ ;; Use side-window specifiers.
+ (list
+ :tag "Use side-window"
+ :value (use-side-window (use-side-window bottom 0))
+ :format "%t\n%v"
+ :inline t
+ ;; For customization purposes only.
+ (const :format "" use-side-window)
+ (set
+ :format "%v"
+ :inline t
+ ;; Side and slot.
+ (list
+ :format "%v\n"
+ :value (use-side-window bottom 0)
+ (const :format "" use-side-window)
+ ;; The side.
+ (choice
+ :tag "Side"
+ :help-echo "Side of frame."
+ :value bottom
+ :format "%[Side%] %v" :size 15
+ (const :tag "Left" :format "%t" left)
+ (const :tag "Top" :format "%t" top)
+ (const :tag "Right" :format "%t" right)
+ (const :tag "Bottom" :format "%t" bottom))
+ ;; The slot
+ (number
+ :tag "Slot"
+ :help-echo "The slot (an arbitrary number, where 0 stands for the center slot)."
+ :value 0
+ :format " Slot: %v" :size 8))
+ ;; Whether to reuse a dedicated side window
+ (cons
+ :format "%v\n"
+ (const :format "" reuse-window-dedicated)
+ (choice
+ :tag "Reuse dedicated side window" :value nil
+ :help-echo "Reuse a side window even if it is dedicated to its buffer."
+ :format "%[Reuse dedicated side window%] %v" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Reuse weakly dedicated side windows" :format "%t" weak)
+ (const :tag "Reuse any dedicated side window" :format "%t" t)))
+ ;; Minimum height of pop-up side windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-min-height)
+ (choice
+ :help-echo "Minimum height of popped-up side window."
+ :format "%[Minimum height%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of lines" :value 12 :size 5)
+ (float :tag "Fraction of frame height" :value .25 :size 5)))
+ ;; Minimum width of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-min-width)
+ (choice
+ :help-echo "Minimum width of popped-up side window."
+ :format "%[Minimum width%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of columns" :value 12 :size 5)
+ (float :tag "Fraction of frame width" :value .25 :size 5)))
+ ;; Desired height of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-set-height)
+ (choice
+ :help-echo "Desired height of popped-up side window."
+ :format "%[Desired height%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of lines" :value 12 :size 5)
+ (float :tag "Fraction of frame height" :value .25 :size 5)
+ (function :tag "Function" :size 25)))
+ ;; Desired width of pop-up windows.
+ (cons
+ :format "%v\n"
+ (const :format "" pop-up-window-set-width)
+ (choice
+ :help-echo "Desired width of popped-up side window."
+ :format "%[Desired width%] %v"
+ (const :tag "Default" :format "%t" :value nil)
+ (integer :tag "Number of column" :value 12 :size 5)
+ (float :tag "Fraction of frame width" :value .25 :size 5)
+ (function :tag "Function" :size 25)))))
+
+ ;; Function with argument specifiers.
+ (list
+ :tag "Function with arguments"
+ :value (function (function 'ignore))
+ :format "%t\n%v"
+ :inline t
+ ;; For customization purposes only.
+ (const :format "" function)
+ (set
+ :format "%v"
+ :inline t
+ (list
+ :format "%v"
+ :value (function 'ignore)
+ (const :format "" function)
+ (function :tag "Function" :format "%t: %v\n" :size 25)
+ (list
+ :format "%v"
+ (repeat
+ :tag "Arguments"
+ :inline t
+ (sexp
+ :format "%v\n"
+ :size 16))))))
+
+ ;; Macro specifiers.
+ (list
+ :tag "Same window"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" same-window))
+ (list
+ :tag "Same frame"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" same-frame))
+ (list
+ :tag "Other window"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" other-window))
+ (list
+ :tag "Same frame other window"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" same-frame-other-window))
+ (list
+ :tag "Other frame"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" other-frame))
+ (list
+ :tag "Default"
+ :format "%t%v"
+ :inline t
+ (const :format "\n" default)))))
+
+ (set
+ :format "%v"
+ :inline t
+ ;; Dedicate window to buffer.
+ (cons
+ :format "%v"
+ (const :format "" dedicate)
+ (choice
+ :help-echo "Mark window as dedicated to its buffer."
+ :format "%[Dedicate window to buffer%] %v\n" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Weak" :format "%t" weak)
+ (const :tag "Strong" :format "%t" t)))
+ ;; No other window.
+ (cons
+ :format "%v"
+ (const :format "" no-other-window)
+ (choice
+ :help-echo "Whether `other-window' shall ignore the window."
+ :format "%[No other window%] %v\n" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Ignore" :format "%t" t)))
+ ;; Other window means other frame.
+ (cons
+ :format "%v"
+ (const :format "" other-window-means-other-frame)
+ (choice
+ :help-echo "Whether other window means same or other frame."
+ :format "%[Other window means other frame%] %v\n" :size 15
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "On" :format "%t" t)))
+ ;; Overriding.
+ (cons
+ :format "%v\n"
+ (const :format "" override)
+ (choice
+ :help-echo "Override application supplied specifiers."
+ :format "%[Override%] %v"
+ (const :tag "Off" :format "%t" nil)
+ (const :tag "Override" :format "%t" t))))))
+ :group 'windows
+ :group 'frames)
+
+(defcustom display-buffer-function nil
+ "If non-nil, function to call to display a buffer.
+`display-buffer' calls this function with two arguments, the
+buffer to display and a list of buffer display specifiers, see
+`display-buffer-alist'.
+
+The function is supposed to choose or create a window, display
+the specified buffer in it, and return the window. It is also
+responsible for giving the variable `display-buffer-window' and
+the `quit-restore' parameter of the window used a meaningful
+value.
+
+The function specified here overrides all specifiers of the
+variable `display-buffer-alist' any specifiers passed to
+`display-buffer'.
+
+If you call `display-buffer' within the body of the function,
+bind the value of `display-buffer-function' to nil around that
+call to avoid that the function recursively calls itself."
+ :type '(choice
+ (const nil)
+ (function :tag "Function"))
+ :group 'windows)
+
+;; The following is a global variable which is used externally (by
+;; help.el) to (1) know which window was used for displaying a buffer
+;; and (2) whether the window was new or reused.
+(defvar display-buffer-window nil
+ "Window used by `display-buffer' and related information.
+After `display-buffer' displays a buffer in some window this
+variable is a cons cell whose car denotes the window used to
+display the buffer. The cdr is supposed to be one of the symbols
+`reuse-buffer-window', `reuse-other-window', `new-window' or
+`new-frame'.
+
+If the buffer display location specifier is one of 'same-window,
+'same-frame, or 'other-frame, the `display-buffer' routines
+assign the value of this variable. If the location specifier is
+a function, that function becomes responsible for assigning a
+meaningful value to this variable. See the functions
+`display-buffer-reuse-window', `display-buffer-pop-up-window' and
+`display-buffer-pop-up-frame' for how this can be done.")
+
+(defun display-buffer-even-window-sizes (window specifiers)
+ "Even sizes of WINDOW and selected window according to SPECIFIERS.
+SPECIFIERS must be a list of buffer display specifiers, see the
+documentation of `display-buffer-alist' for a description.
+
+Sizes are evened out if and only if WINDOW and the selected
+window appear next to each other and the selected window is
+larger than WINDOW."
+ (cond
+ ((or (not (cdr (assq 'reuse-window-even-sizes specifiers)))
+ ;; Don't resize minibuffer windows.
+ (window-minibuffer-p)
+ ;; WINDOW must be adjacent to the selected one.
+ (not (or (eq window (window-prev-sibling))
+ (eq window (window-next-sibling))))))
+ ((and (window-iso-combined-p window)
+ ;; Resize iff the selected window is higher than WINDOW.
+ (> (window-total-height) (window-total-height window)))
+ ;; Don't throw an error if we can't even window heights for
+ ;; whatever reason. In any case, enlarging the selected window
+ ;; might fail anyway if there are other windows above or below
+ ;; WINDOW and the selected one. But for a simple two windows
+ ;; configuration the present behavior is good enough so why care?
+ (ignore-errors
+ (window-resize
+ window (/ (- (window-total-height) (window-total-height window))
+ 2))))
+ ((and (window-iso-combined-p window t)
+ ;; Resize iff the selected window is wider than WINDOW.
+ (> (window-total-width) (window-total-width window)))
+ ;; Don't throw an error if we can't even window widths, see
+ ;; comment above.
+ (ignore-errors
+ (window-resize
+ window (/ (- (window-total-width) (window-total-width window))
+ 2) t)))))
+
+(defun display-buffer-set-height (window specifiers)
+ "Adjust height of WINDOW according to SPECIFIERS.
+SPECIFIERS must be a list of buffer display specifiers, see the
+documentation of `display-buffer-alist' for a description."
+ (let ((set-height (cdr (assq 'pop-up-window-set-height specifiers))))
+ (cond
+ ((numberp set-height)
+ (let* ((height (if (integerp set-height)
+ set-height
+ (round
+ (* (window-total-size (frame-root-window window))
+ set-height))))
+ (delta (- height (window-total-size window))))
+ (when (and (window-resizable-p window delta nil 'safe)
+ (window-iso-combined-p window))
+ (window-resize window delta nil 'safe))))
+ ((functionp set-height)
+ (ignore-errors (funcall set-height window))))))
+
+(defun display-buffer-set-width (window specifiers)
+ "Adjust width of WINDOW according to SPECIFIERS.
+SPECIFIERS must be a list of buffer display specifiers, see the
+documentation of `display-buffer-alist' for a description."
+ (let ((set-width (cdr (assq 'pop-up-window-set-width specifiers))))
+ (cond
+ ((numberp set-width)
+ (let* ((width (if (integerp set-width)
+ set-width
+ (round
+ (* (window-total-size (frame-root-window window) t)
+ set-width))))
+ (delta (- width (window-total-size window t))))
+ (when (and (window-resizable-p window delta t 'safe)
+ (window-iso-combined-p window t))
+ (window-resize window delta t 'safe))))
+ ((functionp set-width)
+ (ignore-errors (funcall set-width window))))))
+
+(defun display-buffer-in-window (buffer window specifiers)
+ "Display BUFFER in WINDOW and raise its frame if needed.
+WINDOW must be a live window and defaults to the selected one.
+Return WINDOW.
+
+SPECIFIERS must be a list of buffer display specifiers, see the
+documentation of `display-buffer-alist' for a description."
+ (setq buffer (window-normalize-buffer buffer))
+ (setq window (window-normalize-live-window window))
+ (let* ((old-frame (selected-frame))
+ (new-frame (window-frame window))
+ (no-other-window (cdr (assq 'no-other-window specifiers))))
+ ;; Show BUFFER in WINDOW.
+ (unless (eq buffer (window-buffer window))
+ ;; If we show another buffer in WINDOW, undedicate it first.
+ (set-window-dedicated-p window nil))
+ (set-window-buffer window buffer)
+ (when no-other-window
+ (set-window-parameter window 'no-other-window t))
+ (unless (or (eq old-frame new-frame)
+ (not (frame-visible-p new-frame))
+ ;; Assume the selected frame is already visible enough.
+ (eq new-frame (selected-frame))
+ ;; Assume the frame from which we invoked the minibuffer
+ ;; is visible.
+ (and (minibuffer-window-active-p (selected-window))
+ (eq new-frame
+ (window-frame (minibuffer-selected-window)))))
+ (raise-frame new-frame))
+ ;; Return window.
+ window))
+
+(defun display-buffer-reuse-window (buffer method &optional specifiers other-window)
+ "Display BUFFER in an existing window.
+METHOD must be a list in the form of the cdr of a `reuse-window'
+buffer display specifier, see `display-buffer-alist' for an
+explanation. The first element must specifiy the window to use,
+and can be either nil, `same', `other', or a live window. The
+second element must specify the window's buffer and can be either
+nil, `same', `other', or a live buffer. The third element is the
+frame to use - either nil, 0, `visible', `other', t, or a live
+frame.
+
+Optional argument SPECIFIERS must be a list of valid display
+specifiers. Optional argument OTHER-WINDOW, if non-nil, means do
+not use the selected window. Return the window chosen to display
+BUFFER, nil if none was found."
+ (let* ((method-window (nth 0 method))
+ (method-buffer (nth 1 method))
+ (method-frame (nth 2 method))
+ (reuse-dedicated (cdr (assq 'reuse-window-dedicated specifiers)))
+ windows other-frame dedicated time best-window best-time)
+ (when (eq method-frame 'other)
+ ;; `other' is not handled by `window-list-1'.
+ (setq other-frame t)
+ (setq method-frame t))
+ (dolist (window (window-list-1 nil 'nomini method-frame))
+ (let ((window-buffer (window-buffer window)))
+ (when (and (not (window-minibuffer-p window))
+ ;; Don't reuse a side window.
+ (or (not (eq (window-parameter window 'window-side) 'side))
+ (eq window-buffer buffer))
+ (or (not method-window)
+ (and (eq method-window 'same)
+ (not other-window)
+ (eq window (selected-window)))
+ (and (eq method-window 'other)
+ (not (eq window (selected-window))))
+ ;; Special case for applications that specifiy
+ ;; the window explicitly.
+ (eq method-window window))
+ (or (not method-buffer)
+ (and (eq method-buffer 'same)
+ (eq window-buffer buffer))
+ (and (eq method-buffer 'other)
+ (not (eq window-buffer buffer)))
+ ;; Special case for applications that specifiy
+ ;; the window's buffer explicitly.
+ (eq method-buffer window-buffer))
+ (or (not other-frame)
+ (not (eq (window-frame window) (selected-frame))))
+ ;; Handle dedicatedness.
+ (or (eq window-buffer buffer)
+ ;; The window does not show the same buffer.
+ (not (setq dedicated (window-dedicated-p window)))
+ ;; If the window is weakly dedicated to its
+ ;; buffer, reuse-dedicated must be non-nil.
+ (and (not (eq dedicated t)) reuse-dedicated)
+ ;; If the window is strongly dedicated to its
+ ;; buffer, reuse-dedicated must be t.
+ (eq reuse-dedicated t)))
+ (setq windows (cons window windows)))))
+
+ (if (eq method-buffer 'same)
+ ;; When reusing a window on the same buffer use the lru one.
+ (dolist (window windows)
+ (setq time (window-use-time window))
+ (when (or (not best-window) (< time best-time))
+ (setq best-window window)
+ (setq best-time time)))
+ ;; Otherwise, sort windows according to their use-time.
+ (setq windows
+ (sort windows
+ #'(lambda (window-1 window-2)
+ (<= (window-use-time window-1)
+ (window-use-time window-2)))))
+ (setq best-window
+ ;; Try to get a full-width window (this is silly and can
+ ;; get us to another frame but let's ignore these issues
+ ;; for the moment).
+ (catch 'found
+ (dolist (window windows)
+ (when (window-full-width-p window)
+ (throw 'found window)))
+ ;; If there's no full-width window return the lru window.
+ (car windows))))
+
+ (when best-window
+ (display-buffer-even-window-sizes best-window specifiers)
+ ;; Never change the quit-restore parameter of a window here.
+ (if (eq (window-buffer best-window) buffer)
+ (setq display-buffer-window
+ (cons best-window 'reuse-buffer-window))
+ (setq display-buffer-window
+ (cons best-window 'reuse-other-window))
+ (unless (window-parameter best-window 'quit-restore)
+ ;; Don't overwrite an existing quit-restore entry.
+ (set-window-parameter
+ best-window 'quit-restore
+ (list (window-buffer best-window) (window-start best-window)
+ (window-point best-window) buffer
+ (window-total-size best-window) (selected-window)))))
+
+ (display-buffer-in-window buffer best-window specifiers))))
+
+(defconst display-buffer-split-specifiers '(largest lru selected root left top right bottom)
+ "List of symbols identifying window that shall be split.")
+
+(defconst display-buffer-side-specifiers '(below right above left nil)
+ "List of symbols identifying side of split-off window.")
+
+(defun display-buffer-split-window-1 (window side min-size)
+ "Subroutine of `display-buffer-split-window'."
+ (let* ((horizontal (memq side '(left right)))
+ (parent (window-parent window))
+ (resize (and window-splits (window-iso-combined-p window horizontal)))
+ (old-size
+ ;; We either resize WINDOW or its parent.
+ (window-total-size (if resize parent window) horizontal))
+ new-size)
+ ;; We don't call split-window-vertically/-horizontally any more
+ ;; here. If for some reason it's needed we can always do so
+ ;; (provided we give it an optional SIDE argument).
+ (cond
+ (resize
+ ;; When we resize a combination, the new window must be at least
+ ;; MIN-SIZE large after the split.
+ (setq new-size
+ (max min-size
+ (min (- old-size (window-min-size parent horizontal))
+ (/ old-size
+ ;; Try to make the size of the new window
+ ;; proportional to the number of iso-arranged
+ ;; windows in the combination.
+ (1+ (window-iso-combinations parent horizontal))))))
+ (when (window-sizable-p parent (- new-size) horizontal)
+ (split-window window (- new-size) side)))
+ ((window-live-p window)
+ (setq new-size (/ old-size 2))
+ ;; When WINDOW is live, the old _and_ the new window must be at
+ ;; least MIN-SIZE large after the split.
+ (when (and (>= new-size min-size)
+ (window-sizable-p window (- new-size) horizontal))
+ ;; Do an even split to make Stepan happy.
+ (split-window window nil side)))
+ (t
+ ;; When WINDOW is internal, the new window must be at least
+ ;; MIN-SIZE large after the split.
+ (setq new-size
+ (max min-size
+ (/ old-size
+ ;; Try to make the size of the new window
+ ;; proportional to the number of iso-arranged
+ ;; subwindows of WINDOW.
+ (1+ (window-iso-combinations window horizontal)))))
+ (when (window-sizable-p window (- new-size) horizontal)
+ (split-window window (- new-size) side))))))
+
+(defun display-buffer-split-window (window &optional side specifiers)
+ "Split WINDOW in a way suitable for `display-buffer'.
+Optional argument SIDE must be a side specifier \(one of the
+symbols below, right, above, left, or nil). SPECIFIERS must be a
+list of buffer display specifiers, see the documentation of
+`display-buffer-alist' for a description.
+
+Return the new window, nil if it could not be created."
+ (let ((min-height (cdr (assq 'pop-up-window-min-height specifiers)))
+ (min-width (cdr (assq 'pop-up-window-min-width specifiers)))
+ size)
+ ;; Normalize min-height and min-width, we might need both.
+ (setq min-height
+ ;; If min-height is specified, it can be as small as
+ ;; `window-safe-min-height'.
+ (cond
+ ((and (integerp min-height)
+ (>= min-height window-safe-min-height))
+ min-height)
+ ((and (floatp min-height)
+ (<= min-height 1)
+ (let* ((root-height (window-total-height
+ (frame-root-window
+ (window-frame window))))
+ (height (round (* min-height root-height))))
+ (when (>= height window-safe-min-height)
+ height))))
+ (t window-min-height)))
+ (setq min-width
+ ;; If min-width is specified, it can be as small as
+ ;; `window-safe-min-width'.
+ (cond
+ ((and (integerp min-width)
+ (>= min-width window-safe-min-width))
+ min-width)
+ ((and (floatp min-width)
+ (<= min-width 1)
+ (let* ((root-width (window-total-width
+ (frame-root-window
+ (window-frame window))))
+ (width (round (* min-width root-width))))
+ (when (>= width window-safe-min-width)
+ width))))
+ (t window-min-width)))
+
+ (or (and (memq side '(nil above below))
+ (display-buffer-split-window-1
+ window (or side 'below) min-height))
+ ;; If SIDE is nil and vertical splitting failed, we try again
+ ;; splitting horizontally this time.
+ (and (memq side '(nil left right))
+ (display-buffer-split-window-1
+ window (or side 'right) min-width))
+ ;; If WINDOW is live and the root window of its frame, try once
+ ;; more splitting vertically, disregarding the min-height
+ ;; specifier this time and using `window-min-height' instead.
+ (and (memq side '(nil above below))
+ (<= window-min-height min-height)
+ (window-live-p window)
+ (eq window (frame-root-window window))
+ (display-buffer-split-window-1
+ window (or side 'below) window-min-height)))))
+
+(defun display-buffer-split-atom-window (window &optional side nest specifiers)
+ "Make WINDOW part of an atomic window."
+ (let ((ignore-window-parameters t)
+ (window-nest t)
+ (selected-window (selected-window))
+ root new new-parent)
+
+ ;; We are in an atomic window.
+ (when (and (window-parameter window 'window-atom) (not nest))
+ ;; Split the root window.
+ (setq window (window-atom-root window)))
+
+ (when (setq new (display-buffer-split-window window side specifiers))
+ (setq new-parent (window-parent window))
+ ;; WINDOW is or becomes atomic.
+ (unless (window-parameter window 'window-atom)
+ (walk-window-subtree
+ (lambda (window)
+ (set-window-parameter window 'window-atom t))
+ window t))
+ ;; New window and any new parent get their window-atom parameter
+ ;; set too.
+ (set-window-parameter new 'window-atom t)
+ (set-window-parameter new-parent 'window-atom t)
+ new)))
+
+(defun display-buffer-pop-up-window (buffer methods &optional specifiers)
+ "Display BUFFER in a new window.
+Return the window displaying BUFFER, nil if popping up the window
+failed. METHODS must be a list of window/side tuples like those
+forming the cdr of the `pop-up-window' buffer display specifier.
+As a special case, the car of such a tuple can be also a live
+window.
+
+Optional argument SPECIFIERS must be a list of buffer display
+specifiers, see the doc-string of `display-buffer-alist' for a
+description."
+ (let* ((frame (display-buffer-frame))
+ (selected-window (frame-selected-window frame))
+ cand window side atomic)
+ (unless (and (cdr (assq 'unsplittable (frame-parameters frame)))
+ ;; Don't split an unsplittable frame unless
+ ;; SPECIFIERS allow it.
+ (not (cdr (assq 'split-unsplittable-frame specifiers))))
+ (catch 'done
+ (dolist (method methods)
+ (setq cand (car method))
+ (setq side (cdr method))
+ (setq window
+ (cond
+ ((eq cand 'largest)
+ ;; The largest window.
+ (get-largest-window frame t))
+ ((eq cand 'lru)
+ ;; The least recently used window.
+ (get-lru-window frame t))
+ ((eq cand 'selected)
+ ;; The selected window.
+ (frame-selected-window frame))
+ ((eq cand 'root)
+ ;; If there are side windows, split the main window
+ ;; else the frame's root window.
+ (or (window-with-parameter 'window-side 'none nil t)
+ (frame-root-window frame)))
+ ((memq cand window-sides)
+ ;; This should gets us the "root" side window if there
+ ;; exists more than one window on that side.
+ (window-with-parameter 'window-side cand nil t))
+ ((windowp cand)
+ ;; A window, directly specified.
+ cand)))
+
+ (when (and (window-any-p window)
+ ;; The window must be on the correct frame,
+ (eq (window-frame window) frame)
+ ;; and must be neither a minibuffer window
+ (not (window-minibuffer-p window))
+ ;; nor a side window.
+ (not (eq (window-parameter window 'window-side) 'side)))
+ (setq window
+ (cond
+ ((memq side display-buffer-side-specifiers)
+ (if (and (window-buffer window)
+ (setq atomic (cdr (assq 'atomic specifiers))))
+ (display-buffer-split-atom-window
+ window side (eq atomic 'nest) specifiers)
+ (display-buffer-split-window window side specifiers)))
+ ((functionp side)
+ (ignore-errors
+ ;; Don't pass any specifiers to this function.
+ (funcall side window)))))
+
+ (when (window-live-p window)
+ ;; In `quit-restore' parameter record that we popped up
+ ;; this window, its buffer and which window was selected.
+ (set-window-parameter
+ window 'quit-restore (list 'new-window buffer selected-window))
+ ;; For `display-buffer-window' mark window as new.
+ (setq display-buffer-window (cons window 'new-window))
+ ;; Install BUFFER in the new window.
+ (display-buffer-in-window buffer window specifiers)
+ (let ((dedicate (cdr (assq 'dedicate specifiers))))
+ (when dedicate
+ ;; Dedicate window to buffer.
+ (set-window-dedicated-p window dedicate)))
+ ;; Adjust sizes if asked for (for `fit-window-to-buffer'
+ ;; and friends BUFFER must be already shown in the new
+ ;; window).
+ (display-buffer-set-height window specifiers)
+ (display-buffer-set-width window specifiers)
+ ;; Reset list of window's previous buffers to nil.
+ (set-window-prev-buffers window nil)
+ ;; Return the new window.
+ (throw 'done window))))))))
+
+(defun display-buffer-pop-up-frame (buffer &optional graphic-only specifiers)
+ "Make a new frame for displaying BUFFER.
+Return the window displaying BUFFER if creating the new frame was
+successful, nil otherwise. Optional argument GRAPHIC-ONLY
+non-nil means to make a new frame on graphic displays only.
+
+SPECIFIERS must be a list of buffer display specifiers, see the
+documentation of `display-buffer-alist' for a description."
+ (unless (or (and graphic-only (not (display-graphic-p)))
+ noninteractive)
+ (let* ((selected-window (selected-window))
+ (function (or (cdr (assq 'pop-up-frame-function specifiers))
+ 'make-frame))
+ (parameters
+ (when (symbolp function)
+ (cdr (assq 'pop-up-frame-alist specifiers))))
+ (frame
+ (if (symbolp function)
+ (funcall function parameters)
+ (funcall function))))
+ (when frame
+ (let ((window (frame-selected-window frame)))
+ (set-window-parameter
+ window 'quit-restore (list 'new-frame buffer selected-window))
+ (setq display-buffer-window (cons window 'new-frame))
+ (display-buffer-in-window buffer window specifiers)
+ (let ((dedicate (cdr (assq 'dedicate specifiers))))
+ (when dedicate
+ ;; Dedicate window to buffer.
+ (set-window-dedicated-p window dedicate)))
+ window)))))
+
+(defun display-buffer-pop-up-side-window (buffer side slot &optional specifiers)
+ "Display BUFFER in a new window on SIDE of the selected frame.
+SLOT specifies the slot to use. SPECIFIERS must be a list of
+buffer display specifiers.
+
+Return the window displaying BUFFER, nil if popping up the window
+failed."
+ (let* ((root (frame-root-window))
+ (main (window-with-parameter 'window-side 'none nil t))
+ (left-or-right (memq side '(left right)))
+ (main-or-root
+ (if (and main
+ (or (and left-or-right (not window-sides-vertical))
+ (and (not left-or-right) window-sides-vertical)))
+ main
+ root))
+ (selected-window (selected-window))
+ (on-side (cond
+ ((eq side 'top) 'above)
+ ((eq side 'bottom) 'below)
+ (t side)))
+ (window
+ (display-buffer-split-window main-or-root on-side specifiers))
+ fun)
+ (when window
+ ;; We were able to split off a new window.
+ (unless main
+ (walk-window-subtree
+ (lambda (window)
+ ;; Make all main-or-root subwindows main windows.
+ (set-window-parameter window 'window-side 'none))
+ main-or-root t))
+ ;; Reset window-side parameter of new window's parent to nil.
+ (set-window-parameter (window-parent window) 'window-side nil)
+ ;; Initialize window-side parameter of new window to SIDE.
+ (set-window-parameter window 'window-side side)
+ ;; Install window-slot parameter of new window.
+ (set-window-parameter window 'window-slot slot)
+ ;; In `quit-restore' parameter record that we popped up a new
+ ;; window.
+ (set-window-parameter
+ window 'quit-restore (list 'new-window buffer selected-window))
+ ;; For `display-buffer-window' mark window as new.
+ (setq display-buffer-window (cons window 'new-window))
+ ;; Install BUFFER in new window.
+ (display-buffer-in-window buffer window specifiers)
+ (let ((dedicate (cdr (assq 'dedicate specifiers))))
+ (when dedicate
+ ;; Dedicate window to buffer.
+ (set-window-dedicated-p window dedicate)))
+ ;; Adjust sizes of new window if asked for.
+ (display-buffer-set-height window specifiers)
+ (display-buffer-set-width window specifiers)
+ ;; Reset list of new window's previous buffers to nil.
+ (set-window-prev-buffers window nil)
+ ;; Return the new window.
+ window)))
+
+(defun display-buffer-in-side-window (buffer side &optional slot specifiers)
+ "Display BUFFER in a window on SIDE of the selected frame.
+SLOT, if non-nil, specifies the window slot where to display the
+BUFFER. SLOT zero or nil means use the central slot on SIDE.
+SLOT negative means use a slot preceding the central window.
+SLOT positive means use a slot following the central window.
+
+SPECIFIERS must be a list of buffer display specifiers."
+ (unless (memq side window-sides)
+ (error "Invalid side %s specified" side))
+ (let* ((major (window-with-parameter 'window-side side nil t))
+ ;; `major' is the major window on SIDE, `windows' the life
+ ;; windows on SIDE.
+ (windows (when major (windows-with-parameter 'window-side side)))
+ (reuse-dedicated (cdr (assq 'reuse-window-dedicated specifiers)))
+ (slots (when major (window-child-count major)))
+ (max-slots
+ (nth (cond
+ ((eq side 'left) 0)
+ ((eq side 'top) 1)
+ ((eq side 'right) 2)
+ ((eq side 'bottom) 3))
+ window-sides-slots))
+ (selected-window (selected-window))
+ window this-window this-slot prev-window next-window
+ best-window best-slot abs-slot dedicated new-window)
+
+ (unless (numberp slot)
+ (setq slot 0))
+ (if (not windows)
+ ;; No suitable side window exists, make one.
+ (display-buffer-pop-up-side-window buffer side slot specifiers)
+ ;; Scan windows on SIDE.
+ (catch 'found
+ (dolist (window windows)
+ (setq this-slot (window-parameter window 'window-slot))
+ (cond
+ ((not (numberp this-slot)))
+ ((and (= this-slot slot)
+ ;; Dedicatedness check.
+ (or (not (setq dedicated (window-dedicated-p window)))
+ ;; If the window is weakly dedicated to its
+ ;; buffer, reuse-dedicated must be non-nil.
+ (and (not (eq dedicated t)) reuse-dedicated)
+ ;; If the window is strongly dedicated to its
+ ;; buffer, reuse-dedicated must be t.
+ (eq reuse-dedicated t)))
+ ;; Window with matching SLOT, use it.
+ (setq this-window window)
+ (throw 'found t))
+ (t
+ (setq abs-slot (abs (- (abs slot) (abs this-slot))))
+ (unless (and best-slot (<= best-slot abs-slot))
+ (setq best-window window)
+ (setq best-slot abs-slot))
+ (cond
+ ((<= this-slot slot)
+ (setq prev-window window))
+ ((not next-window)
+ (setq next-window window)))))))
+
+ ;; `this-window' is the first window with the same SLOT.
+ ;; `prev-window' is the window with the largest slot < SLOT. A new
+ ;; window will be created after it.
+ ;; `next-window' is the window with the smallest slot > SLOT. A new
+ ;; window will be created before it.
+ ;; `best-window' is the window with the smallest absolute difference
+ ;; of its slot and SLOT.
+ (or (and this-window
+ ;; Reuse this window.
+ (prog1
+ (setq window this-window)
+ (if (eq (window-buffer window) buffer)
+ (setq display-buffer-window
+ (cons window 'reuse-buffer-window))
+ (setq display-buffer-window
+ (cons window 'reuse-other-window))
+ (unless (window-parameter window 'quit-restore)
+ ;; Don't overwrite an existing quit-restore entry.
+ (set-window-parameter
+ window 'quit-restore
+ (list (window-buffer window) (window-start window)
+ (window-point window) buffer
+ (window-total-size window) (selected-window)))))))
+ (and (or (not max-slots) (< slots max-slots))
+ (or (and next-window
+ ;; Make new window before next-window.
+ (let ((next-side
+ (if (memq side '(left right)) 'above 'left)))
+ (setq window (display-buffer-split-window
+ next-window next-side specifiers))))
+ (and prev-window
+ ;; Make new window after prev-window.
+ (let ((prev-side
+ (if (memq side '(left right)) 'below 'right)))
+ (setq window (display-buffer-split-window
+ prev-window prev-side specifiers)))))
+ (progn
+ ;; In `quit-restore' parameter record that we popped up
+ ;; this window, its buffer and the old selected window.
+ (set-window-parameter
+ window 'quit-restore
+ (list 'new-window buffer selected-window))
+ ;; For `display-buffer-window' mark window as new.
+ (setq display-buffer-window (cons window 'new-window))
+ ;; Record that window is new, we need this for
+ ;; adjusting sizes below.
+ (setq new-window window)))
+ (and best-window
+ (setq window best-window)
+ ;; Reuse best window (the window nearest to SLOT).
+ (if (eq (window-buffer window) buffer)
+ (setq display-buffer-window
+ (cons window 'reuse-buffer-window))
+ (setq display-buffer-window
+ (cons window 'reuse-other-window))
+
+ (unless (window-parameter window 'quit-restore)
+ ;; Don't overwrite an existing quit-restore entry.
+ (set-window-parameter
+ window 'quit-restore
+ (list (window-buffer window) (window-start window)
+ (window-point window) buffer
+ (window-total-size window) (selected-window)))))
+ window))
+
+ (when window
+ (unless (window-parameter window 'window-slot)
+ ;; Don't change exisiting slot value.
+ (set-window-parameter window 'window-slot slot))
+ ;; Install BUFFER in the window.
+ (display-buffer-in-window buffer window specifiers)
+ (let ((dedicate (cdr (assq 'dedicate specifiers))))
+ (when dedicate
+ ;; Dedicate window to buffer.
+ (set-window-dedicated-p window dedicate)))
+ (when new-window
+ ;; Adjust sizes if asked for (for `fit-window-to-buffer' and
+ ;; friends BUFFER must be already shown in the new window).
+ (display-buffer-set-height window specifiers)
+ (display-buffer-set-width window specifiers)
+ ;; Reset list of new window's previous buffers to nil.
+ (set-window-prev-buffers window nil))
+ ;; Return the window used.
+ window))))
+
+(defun window-normalize-buffer-to-display (buffer-or-name)
+ "Normalize BUFFER-OR-NAME argument for buffer display functions.
+If BUFFER-OR-NAME is nil, return the curent buffer. Else, if a
+buffer specified by BUFFER-OR-NAME exists, return that buffer.
+If no such buffer exists, create a buffer with the name
+BUFFER-OR-NAME and return that buffer."
+ (if buffer-or-name
+ (or (get-buffer buffer-or-name)
+ (let ((buffer (get-buffer-create buffer-or-name)))
+ (set-buffer-major-mode buffer)
+ buffer))
+ (current-buffer)))
+
+(defun display-buffer-other-window-means-other-frame (buffer-or-name &optional label)
+ "Return non-nil if BUFFER shall be preferably displayed in another frame.
+BUFFER must be a live buffer or the name of a live buffer.
+
+Return nil if BUFFER shall be preferably displayed in another
+window on the selected frame. Return non-nil if BUFFER shall be
+preferably displayed in a window on any but the selected frame.
+
+Optional argument LABEL is like the same argument of
+`display-buffer'.
+
+The calculation of the return value is exclusively based on the
+user preferences expressed in `display-buffer-alist'."
+ (let* ((buffer-name
+ (buffer-name (window-normalize-buffer buffer-or-name)))
+ (default (display-buffer-normalize-default buffer-name))
+ (alist (display-buffer-normalize-alist buffer-name label)))
+ (or (cdr (assq 'other-window-means-other-frame default))
+ (cdr (assq 'other-window-means-other-frame (cdr alist))))))
+
+(defun display-buffer-normalize-special (&optional args)
+ "Return buffer display specifiers for `special-display-frame-alist'."
+ (progn ;; <-- reserved for with-no-warnings
+ (if (and (listp args) (symbolp (car args)))
+ ;; Note: `display-buffer' funcalls this so take "(nth 1 args)"
+ ;; where `special-display-popup-frame' (which uses apply) takes
+ ;; "(cdr args)".
+ `((function ,(car args) ,(nth 1 args)))
+ (append
+ '((reuse-window nil same 0))
+ (when (and (listp args) (cdr (assq 'same-window args)))
+ '((reuse-window same nil nil) (reuse-dedicated . weak)))
+ (when (and (listp args)
+ (or (cdr (assq 'same-frame args))
+ (cdr (assq 'same-window args))))
+ '((pop-up-window (largest . nil) (lru . nil))
+ (reuse-window nil nil nil)))
+ (unless display-buffer-mark-dedicated
+ ;; Don't make anything created above dedicated unless requested.
+ ;; Otherwise the dedication request below gets in our way.
+ '((dedicate . nil)))
+ `((pop-up-frame t)
+ ,(append '(pop-up-frame-alist)
+ (when (listp args) args)
+ special-display-frame-alist)
+ (dedicate . t))))))
+
+(defun display-buffer-normalize-default (buffer-or-name)
+ "Subroutine of `display-buffer-normalize-specifiers'.
+BUFFER-OR-NAME is the buffer to display.
+
+This routine provides a compatibility layer for the obsolete
+Emacs 23 buffer display options to set up the corresponding
+buffer display specifiers."
+ (progn ;; <-- reserved for with-no-warnings
+ (let* ((buffer (window-normalize-buffer buffer-or-name))
+ (buffer-name (buffer-name buffer))
+ (pop-up-frames
+ (and (boundp 'pop-up-frames)
+ (or (and (eq pop-up-frames 'graphic-only)
+ (display-graphic-p))
+ pop-up-frames)))
+ specifiers args)
+ ;; `other-window-means-other-frame'
+ (when pop-up-frames
+ (setq specifiers
+ (cons (cons 'other-window-means-other-frame t) specifiers)))
+
+ ;; `even-window-heights'
+ (unless (and (boundp 'even-window-heights)
+ (not even-window-heights))
+ (setq specifiers
+ (cons (cons 'reuse-window-even-sizes t) specifiers)))
+
+ ;; `display-buffer-mark-dedicated'
+ (when (and (boundp 'display-buffer-mark-dedicated)
+ display-buffer-mark-dedicated)
+ (setq specifiers
+ (cons (cons 'dedicate display-buffer-mark-dedicated)
+ specifiers)))
+
+ ;; `pop-up-window-min-height'
+ (let ((min-height
+ (if (boundp 'split-height-threshold)
+ (if (numberp split-height-threshold)
+ (/ split-height-threshold 2)
+ 1.0)
+ 40)))
+ (setq specifiers
+ (cons (cons 'pop-up-window-min-height min-height)
+ specifiers)))
+
+ ;; `pop-up-window-min-width'
+ (let ((min-width
+ (if (boundp 'split-width-threshold)
+ (if (numberp split-width-threshold)
+ (/ split-width-threshold 2)
+ 1.0)
+ 80)))
+ (setq specifiers
+ (cons (cons 'pop-up-window-min-width min-width)
+ specifiers)))
+
+ ;; `pop-up-window'
+ (unless (and (boundp 'pop-up-windows) (not pop-up-windows))
+ (let ((fun (when (and (boundp 'split-window-preferred-function)
+ (not (eq split-window-preferred-function
+ 'split-window-sensibly)))
+ split-window-preferred-function)))
+ ;; `pop-up-window'
+ (setq specifiers
+ (cons
+ (list 'pop-up-window (cons 'largest fun) (cons 'lru fun))
+ specifiers))))
+
+ ;; `pop-up-frame-function'
+ (when (and (boundp 'pop-up-frame-function)
+ (not (equal pop-up-frame-function
+ '(lambda nil
+ (make-frame pop-up-frame-alist)))))
+ (setq specifiers
+ (cons (cons 'pop-up-frame-function pop-up-frame-function)
+ specifiers)))
+
+ ;; `pop-up-frame-alist'
+ (when pop-up-frame-alist
+ (setq specifiers
+ (cons (cons 'pop-up-frame-alist pop-up-frame-alist)
+ specifiers)))
+
+ ;; `pop-up-frame'
+ (when pop-up-frames
+ ;; `pop-up-frame-function'. If `pop-up-frame-function' uses the
+ ;; now obsolete `pop-up-frame-alist' it will continue to do so.
+ ;; `pop-up-frame'
+ (setq specifiers
+ ;; Maybe we should merge graphic-only into the following?
+ (cons (list 'pop-up-frame t) specifiers)))
+
+ ;; `special-display'
+ (when (and (boundp 'special-display-function)
+ special-display-function
+ (fboundp 'special-display-p)
+ (setq args (special-display-p buffer-name)))
+ ;; `special-display-p' returns either t or a list of arguments
+ ;; to pass to `special-display-function'.
+ (if (eq special-display-function 'special-display-popup-frame)
+ (setq specifiers
+ (append (display-buffer-normalize-special args)
+ specifiers))
+ (setq specifiers
+ (cons
+ `(function ,special-display-function ,(when (listp args) args))
+ specifiers))))
+
+ ;; Reuse window showing same buffer on visible or iconified frame.
+ ;; `pop-up-frames', `display-buffer-reuse-frames' means search for
+ ;; a window showing the buffer on some visible or iconfied frame.
+ ;; `last-nonminibuffer-frame' non-nil means search that frame.
+ (let ((frames (or (and (or pop-up-frames
+ (and (boundp 'display-buffer-reuse-frames)
+ display-buffer-reuse-frames)
+ (not (last-nonminibuffer-frame)))
+ ;; All visible or iconfied frames.
+ 0)
+ ;; The following usually returns the same frame
+ ;; so we implicitly search for a window showing
+ ;; the buffer on the same frame already.
+ (last-nonminibuffer-frame))))
+ (when frames
+ (setq specifiers
+ (cons (list 'reuse-window 'other 'same frames)
+ specifiers))))
+
+ ;; `same-window'
+ (when (and (fboundp 'same-window-p) (same-window-p buffer-name))
+ ;; Try to reuse the same (selected) window.
+ (setq specifiers
+ (cons (list 'reuse-window 'same nil nil) specifiers)))
+
+ ;; Same window if showing this buffer already. Can be overridden
+ ;; by `other-window' argument if the buffer is already shown in
+ ;; the same window.
+ (setq specifiers
+ (cons (list 'reuse-window 'same 'same nil) specifiers))
+
+ specifiers)))
+
+(defun display-buffer-normalize-argument (buffer-name specifiers other-window-means-other-frame)
+ "Normalize second argument of `display-buffer'.
+BUFFER-NAME is the name of the buffer that shall be displayed,
+SPECIFIERS is the second argument of `display-buffer'.
+OTHER-WINDOW-MEANS-OTHER-FRAME non-nil means use other-frame for
+other-window."
+ (progn ;; <-- reserved for with-no-warnings
+ (let (normalized entry specifier pars)
+ (cond
+ ((not specifiers)
+ nil)
+ ((listp specifiers)
+ ;; If SPECIFIERS is a list, we assume it is a list of valid
+ ;; specifiers.
+ (dolist (specifier specifiers)
+ (cond
+ ((consp specifier)
+ (setq normalized (cons specifier normalized)))
+ ((eq specifier 'other-window)
+ ;; `other-window' must be treated separately.
+ (let ((entry (assq (if other-window-means-other-frame
+ 'other-frame
+ 'same-frame-other-window)
+ display-buffer-macro-specifiers)))
+ (dolist (item (cdr entry))
+ (setq normalized (cons item normalized)))))
+ ((symbolp specifier)
+ ;; Might be a macro specifier, try to expand it (the cdr is a
+ ;; list and we have to reverse it later, so do it one at a
+ ;; time).
+ (let ((entry (assq specifier display-buffer-macro-specifiers)))
+ (dolist (item (cdr entry))
+ (setq normalized (cons item normalized)))))))
+ ;; Reverse list.
+ (nreverse normalized))
+ ((setq entry (assq specifiers display-buffer-macro-specifiers))
+ ;; A macro specifier.
+ (cdr entry))
+ (t
+ ;; Anything else means use another window according to the
+ ;; non-overriding specifiers of `display-buffer-alist' and the
+ ;; specifiers produced by `display-buffer-normalize-default'.
+ '((other-window . t)))))))
+
+(defun display-buffer-normalize-alist-1 (specifiers label)
+ "Subroutine of `display-buffer-normalize-alist'.
+SPECIFIERS is a list of buffer display specfiers. LABEL is the
+same argument of `display-buffer'."
+ (let (normalized entry)
+ (cond
+ ((not specifiers)
+ nil)
+ ((listp specifiers)
+ ;; If SPECIFIERS is a list, we assume it is a list of specifiers.
+ (dolist (specifier specifiers)
+ (cond
+ ((consp specifier)
+ (setq normalized (cons specifier normalized)))
+ ((symbolp specifier)
+ ;; Might be a macro specifier, try to expand it (the cdr is a
+ ;; list and we have to reverse it later, so do it one at a
+ ;; time).
+ (let ((entry (assq specifier display-buffer-macro-specifiers)))
+ (dolist (item (cdr entry))
+ (setq normalized (cons item normalized)))))))
+ ;; Reverse list.
+ (nreverse normalized))
+ ((setq entry (assq specifiers display-buffer-macro-specifiers))
+ ;; A macro specifier.
+ (cdr entry)))))
+
+(defun display-buffer-normalize-alist (buffer-name label)
+ "Normalize `display-buffer-alist'.
+BUFFER-NAME must be the name of the buffer that shall be displayed.
+LABEL the corresponding argument of `display-buffer'."
+ (let (list-1 list-2)
+ (dolist (entry display-buffer-alist)
+ (when (and (listp entry)
+ (catch 'match
+ (dolist (id (car entry))
+ (when (consp id)
+ (let ((type (car id))
+ (value (cdr id)))
+ (when (or (and (eq type 'name) (stringp value)
+ (equal value buffer-name))
+ (and (eq type 'regexp) (stringp value)
+ (string-match-p value buffer-name))
+ (and (eq type 'label) (eq value label)))
+ (throw 'match t)))))))
+ (let* ((specifiers (cdr entry))
+ (normalized
+ (display-buffer-normalize-alist-1 specifiers label)))
+ (if (cdr (assq 'override specifiers))
+ (setq list-1
+ (if list-1
+ (append list-1 normalized)
+ normalized))
+ (setq list-2
+ (if list-2
+ (append list-2 normalized)
+ normalized))))))
+
+ (cons list-1 list-2)))
+
+(defun display-buffer-normalize-specifiers (buffer-name specifiers label)
+ "Return normalized specifiers for a buffer matching BUFFER-NAME or LABEL.
+BUFFER-NAME must be a string specifying a valid buffer name.
+SPECIFIERS and LABEL are the homonymous arguments of
+`display-buffer'.
+
+The method for displaying the buffer specified by BUFFER-NAME or
+LABEL is established by appending the following four lists of
+specifiers:
+
+- The specifiers in `display-buffer-alist' whose buffer
+ identifier matches BUFFER-NAME or LABEL and whose 'override
+ component is set.
+
+- SPECIFIERS.
+
+- The specifiers in `display-buffer-alist' whose buffer
+ identifier matches BUFFER-NAME or LABEL and whose 'override
+ component is not set."
+ (let* ((default (display-buffer-normalize-default buffer-name))
+ (alist (display-buffer-normalize-alist buffer-name label))
+ (other-window-means-other-frame
+ (or (cdr (assq 'other-window-means-other-frame default))
+ (cdr (assq 'other-window-means-other-frame (cdr alist)))))
+ (arg2 (display-buffer-normalize-argument
+ buffer-name specifiers other-window-means-other-frame))
+ (arg3
+ ;; Handle special meaning of the LABEL argument of
+ ;; `display-buffer'.
+ (when (or (memq label '(visible 0 t)) (frame-live-p label))
+ ;; LABEL must be one of visible (any visible frame), 0 (any
+ ;; visible or iconfied frame), t (any frame), or a live
+ ;; frame.
+ `((reuse-window nil same ,label)))))
+ (append
+ ;; Overriding user specifiers.
+ (car alist)
+ ;; Special value of third argument of display-buffer.
+ arg3
+ ;; Second argument of display-buffer.
+ arg2
+ ;; Non-overriding user specifiers.
+ (cdr alist)
+ ;; Default specifiers.
+ default)))
+
+;; Minibuffer-only frames should be documented better. They really
+;; deserve a separate section in the manual. Also
+;; `last-nonminibuffer-frame' is nowhere documented in the manual.
+(defun display-buffer-frame (&optional frame)
+ "Return FRAME if it is live and not a minibuffer-only frame.
+Return the value of `last-nonminibuffer-frame' otherwise."
+ (setq frame (window-normalize-frame frame))
+ (if (and (frame-live-p frame)
+ ;; A not very nice way to get that information.
+ (not (window-minibuffer-p (frame-root-window frame))))
+ frame
+ (last-nonminibuffer-frame)))
+
+(defun display-buffer (&optional buffer-or-name specifiers label)
+ "Make the buffer specified by BUFFER-OR-NAME appear in some window.
+Optional argument BUFFER-OR-NAME may be a buffer, a string \(a
+buffer name), or nil. If BUFFER-OR-NAME is a string not naming
+an existent buffer, create a buffer with that name. If
+BUFFER-OR-NAME is nil or omitted, display the current buffer.
+Interactively, prompt for the buffer name using the minibuffer.
+
+Return the window chosen to display the buffer or nil if no such
+window is found. Do not change the selected window unless the
+buffer is shown on a different frame than the selected one.
+
+Optional argument SPECIFIERS must be a list of buffer display
+specifiers, see the documentation of `display-buffer-alist' for a
+description.
+
+For convenience, SPECIFIERS may also consist of a single buffer
+display location specifier or t, where the latter means to
+display the buffer in any but the selected window. If SPECIFIERS
+is nil or omitted, this means to exclusively use the specifiers
+provided by the variable `display-buffer-alist' and the function
+`display-buffer-normalize-default'.
+
+As a special case, the `reuse-window' specifier allows to specify
+as second element an arbitrary window, as third element an
+arbitrary buffer, and as fourth element an arbitrary frame. As
+first element of a window/side pair of the `pop-up-window'
+specifier you can specifiy an arbitrary window.
+
+The optional third argument LABEL, if non-nil, must be a symbol
+specifiying the buffer display label. Applications should set
+this when the buffer shall be displayed in some special way but
+BUFFER-OR-NAME does not identify the buffer as special. Typical
+buffers that fit into this category are those whose names are
+derived from the name of the file they are visiting. A user can
+override SPECIFIERS by adding an entry to `display-buffer-alist'
+whose car contains LABEL and whose cdr specifies the preferred
+alternative display method.
+
+The following values of LABEL have a special meaning and allow to
+specify the set of frames to investigate when the buffer already
+appears in a window:
+
+`visible' - the set of visible frames.
+
+0 - the set of visible or iconified frames.
+
+t - the set of all frames.
+
+A live frame - the set containing that frame as its only element.
+
+If the buffer is already displayed in a window on a frame in the
+specified set, return that window.
+
+The method to display the buffer is derived by combining the
+values of `display-buffer-alist' and SPECIFIERS. Highest
+priority is given to overriding elements of
+`display-buffer-alist'. Next come the elements specified by
+SPECIFIERS, followed by the non-overriding elements of
+`display-buffer-alist'.
+
+The result must be a list of valid buffer display specifiers. If
+`display-buffer-function' is non-nil, call it with the buffer and
+this list as arguments."
+ (interactive "BDisplay buffer:\nP")
+ (let* ((buffer (window-normalize-buffer-to-display buffer-or-name))
+ (buffer-name (buffer-name buffer))
+ (normalized
+ ;; Normalize specifiers.
+ (display-buffer-normalize-specifiers buffer-name specifiers label))
+ ;; Don't use a minibuffer frame.
+ (frame (display-buffer-frame))
+ ;; `window' is the window we use for showing `buffer'.
+ window specifier method other-window)
+ ;; Reset this.
+ (setq display-buffer-window nil)
+ (if display-buffer-function
+ ;; Let `display-buffer-function' do the job.
+ (funcall display-buffer-function buffer specifiers)
+ ;; Retrieve the next location specifier while there a specifiers
+ ;; left and we don't have a valid window.
+ (while (and normalized (not (window-live-p window)))
+ (setq specifier (car normalized))
+ (setq normalized (cdr normalized))
+ (setq method (car specifier))
+ (setq window
+ (cond
+ ((eq method 'reuse-window)
+ (display-buffer-reuse-window
+ buffer (cdr specifier) normalized other-window))
+ ((eq method 'pop-up-window)
+ (display-buffer-pop-up-window
+ buffer (cdr specifier) normalized))
+ ((eq method 'pop-up-frame)
+ (display-buffer-pop-up-frame
+ buffer (cdr specifier) normalized))
+ ((eq method 'use-side-window)
+ (display-buffer-in-side-window
+ buffer (nth 1 specifier) (nth 2 specifier) normalized))
+ ((eq method 'function)
+ (funcall (nth 1 specifier) buffer (nth 2 specifier)))
+ ((eq method 'other-window)
+ (setq other-window t)))))
+
+ ;; If we don't have a window yet, try a fallback method. All
+ ;; specifiers have been used up by now. Try reusing a window
+ (or (and (window-live-p window) window)
+ ;; on the selected frame,
+ (display-buffer-reuse-window
+ buffer '(nil nil nil) nil other-window)
+ ;; showing BUFFER on any visible frame,
+ (display-buffer-reuse-window
+ buffer '(nil same visible) nil other-window)
+ ;; not showing BUFFER on any visible frame,
+ (display-buffer-reuse-window
+ buffer '(nil other visible) nil other-window)
+ ;; showing BUFFER on any visible or iconified frame,
+ (display-buffer-reuse-window
+ buffer '(nil same 0) nil other-window)
+ ;; not showing BUFFER on any visible or iconified frame.
+ (display-buffer-reuse-window
+ buffer '(nil other 0) nil other-window)
+ ;; If everything failed so far, try popping up a new frame
+ ;; regardless of graphic-only restrictions.
+ (display-buffer-pop-up-frame buffer)))))
+
+(defun display-buffer-same-window (&optional buffer-or-name label)
+ "Display buffer specified by BUFFER-OR-NAME in the selected window.
+Another window will be used only if the buffer can't be shown in
+the selected window, usually because it is dedicated to another
+buffer. Optional argument BUFFER-OR-NAME and LABEL are as for
+`display-buffer'."
+ (interactive "BDisplay buffer in same window:\nP")
+ (display-buffer buffer-or-name 'same-window label))
+
+(defun display-buffer-same-frame (&optional buffer-or-name label)
+ "Display buffer specified by BUFFER-OR-NAME in a window on the same frame.
+Another frame will be used only if there is no other choice.
+Optional argument BUFFER-OR-NAME and LABEL are as for
+`display-buffer'."
+ (interactive "BDisplay buffer on same frame:\nP")
+ (display-buffer buffer-or-name 'same-frame label))
+
+(defun display-buffer-other-window (&optional buffer-or-name label)
+ "Display buffer specified by BUFFER-OR-NAME in another window.
+The selected window will be used only if there is no other
+choice. Windows on the selected frame are preferred to windows
+on other frames. Optional argument BUFFER-OR-NAME and LABEL are as
+for `display-buffer'."
+ (interactive "BDisplay buffer in another window:\nP")
+ (display-buffer buffer-or-name 'other-window label))
+
+(defun display-buffer-same-frame-other-window (&optional buffer-or-name label)
+ "Display buffer specified by BUFFER-OR-NAME in another window on the same frame.
+The selected window or another frame will be used only if there
+is no other choice. Optional argument BUFFER-OR-NAME and LABEL are
+as for `display-buffer'."
+ (interactive "BDisplay buffer in another window on same frame:\nP")
+ (display-buffer buffer-or-name 'same-frame-other-window label))
+
+(defun display-buffer-other-frame (&optional buffer-or-name label)
+ "Display buffer specified by BUFFER-OR-NAME on another frame.
+The selected frame will be used only if there is no other choice.
+Optional argument BUFFER-OR-NAME and LABEL are as for
+`display-buffer'.
+
+If this command uses another frame, it will also select that frame."
+ (interactive "BDisplay buffer in other frame: ")
+ (display-buffer buffer-or-name 'other-frame label))
+
+(defun pop-to-buffer (&optional buffer-or-name specifiers norecord label)
+ "Display buffer specified by BUFFER-OR-NAME and select the window used.
+Optional argument BUFFER-OR-NAME may be a buffer, a string \(a
+buffer name), or nil. If BUFFER-OR-NAME is a string naming a buffer
+that does not exist, create a buffer with that name. If
+BUFFER-OR-NAME is nil or omitted, display the current buffer.
+Interactively, prompt for the buffer name using the minibuffer.
+
+Optional second argument SPECIFIERS can be: a list of buffer
+display specifiers (see `display-buffer-alist'); a single
+location specifier; t, which means to display the buffer in any
+but the selected window; or nil, which means to exclusively apply
+the specifiers customized by the user. See `display-buffer' for
+more details.
+
+Optional argument NORECORD non-nil means do not put the displayed
+buffer at the front of the buffer list, and do not make the window
+displaying it the most recently selected one.
+
+The optional argument LABEL, if non-nil, is a symbol specifying the
+display purpose. Applications should set this when the buffer
+should be displayed in a special way but BUFFER-OR-NAME does not
+identify the buffer as special. Buffers that typically fit into
+this category are those whose names have been derived from the
+name of the file they are visiting.
+
+Returns the displayed buffer, or nil if displaying the buffer failed.
+
+This uses the function `display-buffer' as a subroutine; see the
+documentations of `display-buffer' and `display-buffer-alist' for
+additional information."
+ (interactive "BPop to buffer:\nP")
+ (let ((buffer (window-normalize-buffer-to-display buffer-or-name))
+ (old-window (selected-window))
+ (old-frame (selected-frame))
+ new-window new-frame)
+ (set-buffer buffer)
+ (setq new-window (display-buffer buffer specifiers label))
+ (setq new-frame (window-frame new-window))
+ (if (eq old-frame new-frame)
+ ;; Make sure new-window gets selected (Bug#8615), (Bug#6954).
+ (select-window new-window norecord)
+ ;; `display-buffer' has chosen another frame, make sure it gets
+ ;; input focus and is risen.
+ (select-frame-set-input-focus new-frame norecord))
+ buffer))
+
+(defun pop-to-buffer-same-window (&optional buffer-or-name norecord label)
+ "Pop to buffer specified by BUFFER-OR-NAME in the selected window.
+Another window will be used only if the buffer can't be shown in
+the selected window, usually because it is dedicated to another
+buffer. Optional arguments BUFFER-OR-NAME, NORECORD and LABEL are
+as for `pop-to-buffer'."
+ (interactive "BPop to buffer in selected window:\nP")
+ (pop-to-buffer buffer-or-name 'same-window norecord label))
+
+(defun pop-to-buffer-same-frame (&optional buffer-or-name norecord label)
+ "Pop to buffer specified by BUFFER-OR-NAME in a window on the selected frame.
+Another frame will be used only if there is no other choice.
+Optional arguments BUFFER-OR-NAME, NORECORD and LABEL are as for
+`pop-to-buffer'."
+ (interactive "BPop to buffer on same frame:\nP")
+ (pop-to-buffer buffer-or-name 'same-frame norecord label))
+
+(defun pop-to-buffer-other-window (&optional buffer-or-name norecord label)
+ "Pop to buffer specified by BUFFER-OR-NAME in another window.
+The selected window will be used only if there is no other
+choice. Windows on the selected frame are preferred to windows
+on other frames. Optional arguments BUFFER-OR-NAME, NORECORD and
+LABEL are as for `pop-to-buffer'."
+ (interactive "BPop to buffer in another window:\nP")
+ (pop-to-buffer buffer-or-name 'other-window norecord))
+
+(defun pop-to-buffer-same-frame-other-window (&optional buffer-or-name norecord label)
+ "Pop to buffer specified by BUFFER-OR-NAME in another window on the selected frame.
+The selected window or another frame will be used only if there
+is no other choice. Optional arguments BUFFER-OR-NAME, NORECORD
+and LABEL are as for `pop-to-buffer'."
+ (interactive "BPop to buffer in another window on same frame:\nP")
+ (pop-to-buffer buffer-or-name 'same-frame-other-window norecord label))
+
+(defun pop-to-buffer-other-frame (&optional buffer-or-name norecord label)
+ "Pop to buffer specified by BUFFER-OR-NAME on another frame.
+The selected frame will be used only if there's no other choice.
+Optional arguments BUFFER-OR-NAME, NORECORD and LABEL are as for
+`pop-to-buffer'."
+ (interactive "BPop to buffer on another frame:\nP")
+ (pop-to-buffer buffer-or-name 'other-frame norecord label))
+
+(defun read-buffer-to-switch (prompt)
+ "Read the name of a buffer to switch to, prompting with PROMPT.
+Return the neame of the buffer as a string.
+
+This function is intended for the `switch-to-buffer' family of
+commands since these need to omit the name of the current buffer
+from the list of completions and default values."
+ (let ((rbts-completion-table (internal-complete-buffer-except)))
+ (minibuffer-with-setup-hook
+ (lambda ()
+ (setq minibuffer-completion-table rbts-completion-table)
+ ;; Since rbts-completion-table is built dynamically, we
+ ;; can't just add it to the default value of
+ ;; icomplete-with-completion-tables, so we add it
+ ;; here manually.
+ (if (and (boundp 'icomplete-with-completion-tables)
+ (listp icomplete-with-completion-tables))
+ (set (make-local-variable 'icomplete-with-completion-tables)
+ (cons rbts-completion-table
+ icomplete-with-completion-tables))))
+ (read-buffer prompt (other-buffer (current-buffer))
+ (confirm-nonexistent-file-or-buffer)))))
+
+(defun window-normalize-buffer-to-switch-to (buffer-or-name)
+ "Normalize BUFFER-OR-NAME argument of buffer switching functions.
+If BUFFER-OR-NAME is nil, return the buffer returned by
+`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
+exists, return that buffer. If no such buffer exists, create a
+buffer with the name BUFFER-OR-NAME and return that buffer."
+ (if buffer-or-name
+ (or (get-buffer buffer-or-name)
+ (let ((buffer (get-buffer-create buffer-or-name)))
+ (set-buffer-major-mode buffer)
+ buffer))
+ (other-buffer)))
+
+(defun switch-to-buffer (buffer-or-name &optional norecord force-same-window)
+ "Switch to buffer BUFFER-OR-NAME in the selected window.
+If called interactively, prompt for the buffer name using the
+minibuffer. The variable `confirm-nonexistent-file-or-buffer'
+determines whether to request confirmation before creating a new
+buffer.
+
+BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
+nil. If BUFFER-OR-NAME is a string that does not identify an
+existing buffer, create a buffer with that name. If
+BUFFER-OR-NAME is nil, switch to the buffer returned by
+`other-buffer'.
+
+Optional argument NORECORD non-nil means do not put the buffer
+specified by BUFFER-OR-NAME at the front of the buffer list and
+do not make the window displaying it the most recently selected
+one.
+
+If FORCE-SAME-WINDOW is non-nil, BUFFER-OR-NAME must be displayed
+in the currently selected window; signal an error if that is
+impossible (e.g. if the selected window is minibuffer-only).
+If non-nil, BUFFER-OR-NAME may be displayed in another window.
+
+Return the buffer switched to."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer: ") nil nil))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (if (null force-same-window)
+ (pop-to-buffer
+ buffer '(same-window (reuse-window-dedicated . weak)) norecord)
+ (cond
+ ;; Don't call set-window-buffer if it's not needed since it
+ ;; might signal an error (e.g. if the window is dedicated).
+ ((eq buffer (window-buffer)))
+ ((window-minibuffer-p)
+ (error "Cannot switch buffers in minibuffer window"))
+ ((eq (window-dedicated-p) t)
+ (error "Cannot switch buffers in a dedicated window"))
+ (t (set-window-buffer nil buffer)))
+
+ (unless norecord
+ (select-window (selected-window)))
+ (set-buffer buffer))))
+
+(defun switch-to-buffer-same-frame (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME in a window on the selected frame.
+Another frame will be used only if there is no other choice.
+Arguments BUFFER-OR-NAME and NORECORD have the same meaning as
+for `switch-to-buffer'.
+
+This function is intended for interactive use only. Lisp
+functions should call `pop-to-buffer-same-frame' instead."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other window: ")))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (pop-to-buffer buffer 'same-frame norecord)))
+
+(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME in another window.
+The selected window will be used only if there is no other
+choice. Windows on the selected frame are preferred to windows
+on other frames. Arguments BUFFER-OR-NAME and NORECORD have the
+same meaning as for `switch-to-buffer'.
+
+This function is intended for interactive use only. Lisp
+functions should call `pop-to-buffer-other-window' instead."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other window: ")))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (pop-to-buffer buffer 'other-window norecord)))
+
+(defun switch-to-buffer-other-window-same-frame (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME in another window on the selected frame.
+The selected window or another frame will be used only if there
+is no other choice. Arguments BUFFER-OR-NAME and NORECORD have
+the same meaning as for `switch-to-buffer'.
+
+This function is intended for interactive use only. Lisp
+functions should call `pop-to-buffer-other-window-same-frame'
+instead."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other window: ")))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (pop-to-buffer buffer 'same-frame-other-window norecord)))
+
+(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME on another frame.
+The same frame will be used only if there is no other choice.
+Arguments BUFFER-OR-NAME and NORECORD have the same meaning
+as for `switch-to-buffer'.
+
+This function is intended for interactive use only. Lisp
+functions should call `pop-to-buffer-other-frame' instead."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other frame: ")))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (pop-to-buffer buffer 'other-frame norecord)))
+
+;;; Obsolete definitions of `display-buffer' below.
+(defcustom same-window-buffer-names nil
+ "List of names of buffers that should appear in the \"same\" window.
+`display-buffer' and `pop-to-buffer' show a buffer whose name is
+on this list in the selected rather than some other window.
+
+An element of this list can be a cons cell instead of just a
+string. In that case, the cell's car must be a string specifying
+the buffer name. This is for compatibility with
+`special-display-buffer-names'; the cdr of the cons cell is
+ignored.
+
+See also `same-window-regexps'."
+ :type '(repeat (string :format "%v"))
+ :group 'windows)
+;; (make-obsolete-variable
+ ;; 'same-window-buffer-names
+ ;; "use 2nd arg of `display-buffer' instead." "24.1")
+
+(defcustom same-window-regexps nil
+ "List of regexps saying which buffers should appear in the \"same\" window.
+`display-buffer' and `pop-to-buffer' show a buffer whose name
+matches a regexp on this list in the selected rather than some
+other window.
+
+An element of this list can be a cons cell instead of just a
+string. In that case, the cell's car must be a regexp matching
+the buffer name. This is for compatibility with
+`special-display-regexps'; the cdr of the cons cell is ignored.
+
+See also `same-window-buffer-names'."
+ :type '(repeat (regexp :format "%v"))
+ :group 'windows)
+;; (make-obsolete-variable
+ ;; 'same-window-regexps
+ ;; "use 2nd arg of `display-buffer' instead." "24.1")
+
+(defun same-window-p (buffer-name)
+ "Return non-nil if a buffer named BUFFER-NAME would be shown in the \"same\" window.
+This function returns non-nil if `display-buffer' or
+`pop-to-buffer' would show a buffer named BUFFER-NAME in the
+selected rather than \(as usual\) some other window. See
+`same-window-buffer-names' and `same-window-regexps'."
+ (let ((buffer-names (with-no-warnings same-window-buffer-names))
+ (regexps (with-no-warnings same-window-regexps)))
+ (cond
+ ((not (stringp buffer-name)))
+ ;; The elements of `same-window-buffer-names' can be buffer
+ ;; names or cons cells whose cars are buffer names.
+ ((member buffer-name buffer-names))
+ ((assoc buffer-name buffer-names))
+ ((catch 'found
+ (dolist (regexp regexps)
+ ;; The elements of `same-window-regexps' can be regexps
+ ;; or cons cells whose cars are regexps.
+ (when (or (and (stringp regexp)
+ (string-match regexp buffer-name))
+ (and (consp regexp) (stringp (car regexp))
+ (string-match-p (car regexp) buffer-name)))
+ (throw 'found t))))))))
+;; (make-obsolete
+ ;; 'same-window-p "pass argument to buffer display function instead." "24.1")
+
+(defcustom special-display-frame-alist
+ '((height . 14) (width . 80) (unsplittable . t))
+ "Alist of parameters for special frames.
+Special frames are used for buffers whose names are listed in
+`special-display-buffer-names' and for buffers whose names match
+one of the regular expressions in `special-display-regexps'.
+
+This variable can be set in your init file, like this:
+
+ (setq special-display-frame-alist '((width . 80) (height . 20)))
+
+These supersede the values given in `default-frame-alist'."
+ :type '(repeat (cons :format "%v"
+ (symbol :tag "Parameter")
+ (sexp :tag "Value")))
+ :group 'frames)
+;; (make-obsolete-variable
+ ;; 'special-display-frame-alist
+ ;; "use 2nd arg of `display-buffer' instead." "24.1")
+
+(defun special-display-popup-frame (buffer &optional args)
+ "Display BUFFER in a special frame and return the window chosen.
+If BUFFER is already displayed in a visible or iconified frame,
+raise that frame. Otherwise, display BUFFER in a way as
+specified by optional argument ARGS.
+
+If ARGS is an alist, use it as a list of frame parameters. If
+these parameters contain \(same-window . t), display BUFFER in
+the selected window. If they contain \(same-frame . t), display
+BUFFER in a window on the selected frame.
+
+If ARGS is a list whose car is a symbol, use (car ARGS) as a
+function to do the work. Pass it BUFFER as first argument,
+and (cdr ARGS) as the rest of the arguments."
+ (if (and args (symbolp (car args)))
+ (apply (car args) buffer (cdr args))
+ (let ((window (get-buffer-window buffer 0)))
+ (or
+ ;; If we have a window already, make it visible.
+ (when window
+ (let ((frame (window-frame window)))
+ (make-frame-visible frame)
+ (raise-frame frame)
+ window))
+ ;; Reuse the current window if the user requested it.
+ (when (cdr (assq 'same-window args))
+ (display-buffer-reuse-window
+ buffer '(same nil nil) '((reuse-dedicated . weak))))
+ ;; Stay on the same frame if requested.
+ (when (or (cdr (assq 'same-frame args))
+ (cdr (assq 'same-window args)))
+ (or (display-buffer-pop-up-window
+ buffer '((largest . nil) (lru . nil)))
+ (display-buffer-reuse-window
+ buffer '(nil nil nil))))
+ ;; If no window yet, make one in a new frame.
+ (let ((frame
+ (with-current-buffer buffer
+ (make-frame
+ (append args (with-no-warnings
+ special-display-frame-alist))))))
+ (set-window-buffer (frame-selected-window frame) buffer)
+ (set-window-dedicated-p (frame-selected-window frame) t)
+ (frame-selected-window frame))))))
+;; (make-obsolete
+ ;; 'special-display-popup-frame
+ ;; "use 2nd arg of `display-buffer' instead." "24.1")
+
+(defcustom special-display-function 'special-display-popup-frame
+ "Function to call for displaying special buffers.
+This function is called with two arguments - the buffer and,
+optionally, a list - and should return a window displaying that
+buffer. The default value usually makes a separate frame for the
+buffer using `special-display-frame-alist' to specify the frame
+parameters. See the definition of `special-display-popup-frame'
+for how to specify such a function.
+
+A buffer is special when its name is either listed in
+`special-display-buffer-names' or matches a regexp in
+`special-display-regexps'."
+ :type 'function
+ :group 'windows
+ :group 'frames)
+;; (make-obsolete-variable
+ ;; 'special-display-function
+ ;; "use 2nd arg of `display-buffer' instead." "24.1")