The actual non-nil value of this variable will be copied to the
`window-dedicated-p' flag.")
-(defun display-buffer-default (buffer-or-name &optional not-this-window frame)
- "Make buffer BUFFER-OR-NAME appear in some window but don't select it.
-BUFFER-OR-NAME must be a buffer or the name of an existing
-buffer. Return the window chosen to display BUFFER-OR-NAME or
-nil if no such window is found.
-
-Optional argument NOT-THIS-WINDOW non-nil means display the
-buffer in a window other than the selected one, even if it is
-already displayed in the selected window.
-
-Optional argument FRAME specifies which frames to investigate
-when the specified buffer is already displayed. If the buffer is
-already displayed in some window on one of these frames simply
-return that window. Possible values of FRAME are:
-
-`visible' - consider windows on all visible frames on the current
-terminal.
-
-0 - consider windows on all visible or iconified frames on the
-current terminal.
-
-t - consider windows on all frames.
-
-A specific frame - consider windows on that frame only.
-
-nil - consider windows on the selected frame \(actually the
-last non-minibuffer frame\) only. If, however, either
-`display-buffer-reuse-frames' or `pop-up-frames' is non-nil
-\(non-nil and not graphic-only on a text-only terminal),
-consider all visible or iconified frames on the current terminal."
- (interactive "BDisplay buffer:\nP")
- (let* ((can-use-selected-window
- ;; The selected window is usable unless either NOT-THIS-WINDOW
- ;; is non-nil, it is dedicated to its buffer, or it is the
- ;; `minibuffer-window'.
- (not (or not-this-window
- (window-dedicated-p (selected-window))
- (window-minibuffer-p))))
- (buffer (if (bufferp buffer-or-name)
- buffer-or-name
- (get-buffer buffer-or-name)))
- (name-of-buffer (buffer-name buffer))
- ;; On text-only terminals do not pop up a new frame when
- ;; `pop-up-frames' equals graphic-only.
- (use-pop-up-frames (if (eq pop-up-frames 'graphic-only)
- (display-graphic-p)
- pop-up-frames))
- ;; `frame-to-use' is the frame where to show `buffer' - either
- ;; the selected frame or the last nonminibuffer frame.
- (frame-to-use
- (or (window--frame-usable-p (selected-frame))
- (window--frame-usable-p (last-nonminibuffer-frame))))
- ;; `window-to-use' is the window we use for showing `buffer'.
- window-to-use popped-up-frame)
- (cond
- ((not (buffer-live-p buffer))
- (error "No such buffer %s" buffer))
- (display-buffer-function
- ;; Let `display-buffer-function' do the job.
- (funcall display-buffer-function buffer not-this-window))
- ((and (not not-this-window)
- (eq (window-buffer (selected-window)) buffer))
- ;; The selected window already displays BUFFER and
- ;; `not-this-window' is nil, so use it.
- (display-buffer-record-window 'reuse-window (selected-window) buffer)
- (window--display-buffer-1 (selected-window)))
- ((and can-use-selected-window (same-window-p name-of-buffer))
- ;; If the buffer's name tells us to use the selected window do so.
- (display-buffer-record-window 'reuse-window (selected-window) buffer)
- (window--display-buffer-2 buffer (selected-window)))
- ((let ((frames (or frame
- (and (or use-pop-up-frames
- display-buffer-reuse-frames
- (not (last-nonminibuffer-frame)))
- 0)
- (last-nonminibuffer-frame))))
- (setq window-to-use
- (catch 'found
- ;; Search frames for a window displaying BUFFER. Return
- ;; the selected window only if we are allowed to do so.
- (dolist (window (get-buffer-window-list buffer 'nomini frames))
- (when (or can-use-selected-window
- (not (eq (selected-window) window)))
- (throw 'found window))))))
- ;; The buffer is already displayed in some window; use that.
- (display-buffer-record-window 'reuse-window window-to-use buffer)
- (window--display-buffer-1 window-to-use))
- ((and special-display-function
- ;; `special-display-p' returns either t or a list of frame
- ;; parameters to pass to `special-display-function'.
- (let ((pars (special-display-p name-of-buffer)))
- (when pars
- (funcall special-display-function
- buffer (if (listp pars) pars))))))
- ((or use-pop-up-frames (not frame-to-use))
- ;; We want or need a new frame.
- (setq window-to-use
- (frame-selected-window (funcall pop-up-frame-function)))
- (display-buffer-record-window 'pop-up-frame window-to-use buffer)
- (window--display-buffer-2 buffer window-to-use))
- ((and pop-up-windows
- ;; Make a new window.
- (or (not (frame-parameter frame-to-use 'unsplittable))
- ;; If the selected frame cannot be split look at
- ;; `last-nonminibuffer-frame'.
- (and (eq frame-to-use (selected-frame))
- (setq frame-to-use (last-nonminibuffer-frame))
- (window--frame-usable-p frame-to-use)
- (not (frame-parameter frame-to-use 'unsplittable))))
- ;; Attempt to split largest or least recently used window.
- (setq window-to-use
- (or (window--try-to-split-window
- (get-largest-window frame-to-use t))
- (window--try-to-split-window
- (get-lru-window frame-to-use t))))
- (display-buffer-record-window 'pop-up-window window-to-use buffer)
- (window--display-buffer-2 buffer window-to-use)))
- ((let ((window-to-undedicate
- ;; When NOT-THIS-WINDOW is non-nil, temporarily dedicate
- ;; the selected window to its buffer, to avoid that some of
- ;; the `get-' routines below choose it. (Bug#1415)
- (and not-this-window (not (window-dedicated-p))
- (set-window-dedicated-p (selected-window) t)
- (selected-window))))
- (unwind-protect
- (setq window-to-use
- ;; Reuse an existing window.
- (or (get-lru-window frame-to-use)
- (let ((window (get-buffer-window buffer 'visible)))
- (unless (and not-this-window
- (eq window (selected-window)))
- window))
- (get-largest-window 'visible)
- (let ((window (get-buffer-window buffer 0)))
- (unless (and not-this-window
- (eq window (selected-window)))
- window))
- (get-largest-window 0)
- (prog1
- (frame-selected-window (funcall pop-up-frame-function))
- (setq popped-up-frame t))))
- (when (window-live-p window-to-undedicate)
- ;; Restore dedicated status of selected window.
- (set-window-dedicated-p window-to-undedicate nil))))
- (display-buffer-record-window
- (if popped-up-frame 'pop-up-frame 'reuse-window) window-to-use buffer)
- (window--even-window-heights window-to-use)
- (window--display-buffer-2 buffer window-to-use)))))
-
(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
(current-buffer)))
(defvar display-buffer-alist nil
- "Specifications of user preferences for `display-buffer'.
-This is a list of elements of the form (CONDITION . ACTION) where
-CONDITION is either a regexp matching buffer names, or a function
-that takes a buffer and returns a boolean. ACTION is a list of
-the form (FUNCTION . ALIST) where FUNCTION can be either a
-function or a list of functions. Those functions will be called
-with 2 arguments: the buffer to display and an ALIST built from
-the various alists specified in the various ACTIONs. It should
-either return the window used, or nil to fallback to the next
-function.")
-
-(defvar display-buffer-default-action (list #'display-buffer-default)
- "Default action to perform to display a buffer.
-This is an ACTION just like in `display-buffer-alist'.")
-
-(defvar display-buffer-overriding-action '(nil)
+ "Alist of conditional actions for `display-buffer'.
+This is a list of elements (CONDITION . ACTION), where:
+
+ CONDITION is either a regexp matching buffer names, or a function
+ that takes a buffer and returns a boolean.
+
+ ACTION is a cons cell (FUNCTION . ALIST), where FUNCTION is
+ either a function or a list of functions. Each such function
+ should accept 2 arguments: a buffer to display and an alist of
+ the same form as ALIST. It should return the window used, or
+ nil if it fails to display the window. See `display-buffer'
+ for more details.
+
+Usable action functions include:
+ `display-buffer-reuse-selected-window'
+ `display-buffer-same-window'
+ `display-buffer-maybe-same-window'
+ `display-buffer-reuse-window'
+ `display-buffer-pop-up-frame'
+ `display-buffer-pop-up-window'
+ `display-buffer-reuse-or-pop-window'
+ `display-buffer-use-some-window'
+
+The above functions recognize the following alist entries:
+ - `inhibit-same-window', if non-nil, prevents the same window
+ from being used for display.
+ - `reuse-frame' specifies the frames that can be searched for a
+ window displaying the buffer. Its values have the same
+ meaning as the ALL-FRAMES arg to `get-buffer-window-list'.")
+
+(defvar display-buffer-default-action
+ '((display-buffer-reuse-selected-window
+ display-buffer-maybe-same-window
+ display-buffer-reuse-or-pop-window
+ display-buffer-use-some-window
+ ;; If all else fails, pop up a new frame regardless of
+ ;; restrictions.
+ display-buffer-pop-up-frame))
+ "List of default actions for `display-buffer'.
+It should be a cons cell of the form (FUNCTION . ALIST), which
+has the same meaning as in `display-buffer-alist'.")
+
+(defvar display-buffer-overriding-action nil
"Overriding action to perform to display a buffer.
-This is an ACTION just like in `display-buffer-alist'.")
+If non-nil, it should be a cons cell (FUNCTION . ALIST), which
+has the same meaning as in `display-buffer-alist'.")
(defun display-buffer-assq-regexp (buffer-name alist)
"Retrieve ALIST entry corresponding to BUFFER-NAME."
(throw 'match (cdr entry)))))))
(defun display-buffer (&optional buffer-or-name action frame)
- "Display BUFFER in some window."
+ "Display BUFFER-OR-NAME in some window.
+BUFFER-OR-NAME must be a buffer or the name of an existing
+buffer. Return the window chosen for displaying BUFFER-OR-NAME,
+or nil if no such window is found.
+
+Optional argument ACTION should have the form (FUNCTION . ALIST).
+FUNCTION is either a function or a list of functions. Each such
+function is called with 2 arguments: the buffer to display and an
+alist. It should either display the buffer and return the
+window, or return nil if it is unable to display the buffer.
+
+`display-buffer' constructs a list of action functions and an
+action alist from `display-buffer-overriding-action',
+`user-action', ACTION, and `display-buffer-default-action' (in
+order). It calls each action function in turn, passing the
+consolidated action alist as the second argument, until one of
+the functions returns non-nil.
+
+ACTION can also have a non-nil and non-list value. This means to
+display the buffer in a window other than the selected one, even
+if it is already displayed in the selected window. If called
+interactively with a prefix argument, ACTION is t.
+
+Optional argument FRAME specifies where to look for a window that
+already displays the buffer. If nil, check only the selected
+frame (actually the last non-minibuffer frame), except if
+`display-buffer-reuse-frames' or `pop-up-frames' is non-nil
+\(non-nil and not graphic-only on a text-only terminal), in which
+case check all visible or iconified frames. Otherwise, FRAME can
+be a specific frame, `visible' (all visible frames), 0 (all
+frames on the current terminal), or t (all frames)."
(interactive "BDisplay buffer:\nP")
- (let* ((buffer (window-normalize-buffer-to-display buffer-or-name))
- (buffer-name (buffer-name buffer))
- (user-action
- (display-buffer-assq-regexp buffer-name display-buffer-alist))
- (functions
- (append
- (list (car display-buffer-overriding-action))
- (list (car user-action))
- (and (listp action) (list (car action)))
- (list (car display-buffer-default-action))))
- (specifiers (append (cdr display-buffer-overriding-action)
- (cdr user-action)
- (and (listp action) (cdr action))
- (cdr display-buffer-default-action)))
- function window)
- (while (and functions (not window))
- (setq function (car functions))
- (cond
- ((listp function)
- (while (and function (not window))
- (cond
- ((eq (car function) 'display-buffer-default)
- (setq window
- (display-buffer-default
- buffer (memq action '(t other-window)) frame)))
- ((functionp (car function))
- (setq window (funcall (car function) buffer specifiers))))
- (setq function (cdr function))))
- ((eq function 'display-buffer-default)
- (setq window
- (display-buffer-default
- buffer (memq action '(t other-window)) frame)))
- ((functionp function)
- (setq window
- (funcall function buffer specifiers))))
- (setq functions (cdr functions)))
-
- window))
+ (let ((buffer (window-normalize-buffer-to-display buffer-or-name))
+ ;; Handle the old form of the first argument.
+ (inhibit-same-window (and action (not (listp action)))))
+ (unless (listp action) (setq action nil))
+ (if display-buffer-function
+ ;; If `display-buffer-function' is defined, let it do the job.
+ (funcall display-buffer-function buffer inhibit-same-window)
+ ;; Otherwise, use the defined actions.
+ (let* ((user-action
+ (display-buffer-assq-regexp (buffer-name buffer)
+ display-buffer-alist))
+ ;; Extra actions from the arguments to this function:
+ (extra-action
+ (cons nil (append (if inhibit-same-window
+ '((inhibit-same-window . t)))
+ (if frame
+ `((reuse-frame . ,frame))))))
+ ;; Construct action function list and action alist.
+ (actions (list display-buffer-overriding-action
+ user-action action extra-action
+ display-buffer-default-action))
+ (functions (apply 'append
+ (mapcar (lambda (x)
+ (setq x (car x))
+ (if (listp x) x (list x)))
+ actions)))
+ (alist (apply 'append (mapcar 'cdr actions)))
+ window)
+ (unless (buffer-live-p buffer)
+ (error "Invalid buffer"))
+ (while (and functions (not window))
+ (setq window (funcall (car functions) buffer alist)
+ functions (cdr functions)))
+ window))))
(defun display-buffer-other-frame (buffer)
"Display buffer BUFFER in another frame.
;;(make-frame-visible (window-frame old-window))
))
-;;; Functions for use via `display-buffer-alist'.
+;;; `display-buffer' action functions:
-(defun display-buffer-same-window (buffer alist)
- "Display BUFFER in the selected window, and return the window.
-If BUFFER cannot be displayed in the selected window (usually
-because it is dedicated to another buffer), return nil."
- (let ((norecord (cadr (assq 'norecord alist))))
- (cond
- ((eq buffer (window-buffer))
- (selected-window))
- ((not (or (window-minibuffer-p) (window-dedicated-p)))
- (set-window-buffer nil buffer)
- (selected-window)))))
+(defun display-buffer-reuse-selected-window (buffer alist)
+ "Try to display BUFFER in the selected window if it is already there.
+If this succeeds, return the selected window.
-(defun display-buffer-other-window (buffer alist)
- "Display BUFFER in another window, and return BUFFER.
-If BUFFER cannot be displayed in another window, just return nil."
- (display-buffer-default buffer t))
+This fails if BUFFER is not displayed in the selected window, or
+if ALIST has a non-nil `inhibit-same-window' entry. In that
+case, return nil."
+ (when (and (not (cdr (assq 'inhibit-same-window alist)))
+ (eq buffer (window-buffer)))
+ (display-buffer-record-window 'reuse-window (selected-window) buffer)
+ (window--display-buffer-1 (selected-window))))
+
+(defun display-buffer-same-window (buffer alist)
+ "Try to display BUFFER in the selected window.
+If this succeeds, return the selected window.
+
+This fails if the selected window is a minibuffer window or is
+dedicated to another buffer, or if ALIST has a non-nil
+`inhibit-same-window' entry. In that case, return nil."
+ (unless (or (cdr (assq 'inhibit-same-window alist))
+ (window-minibuffer-p)
+ (window-dedicated-p))
+ (display-buffer-record-window 'reuse-window (selected-window) buffer)
+ (window--display-buffer-2 buffer (selected-window))))
+
+(defun display-buffer-maybe-same-window (buffer alist)
+ "Try to display BUFFER in the selected window.
+This acts like `display-buffer-same-window', except that it also
+fails if `same-window-p' returns nil for this buffer."
+ (and (same-window-p (buffer-name buffer))
+ (display-buffer-same-window buffer alist)))
+
+(defun display-buffer-reuse-window (buffer alist)
+ "Return a window that is already displaying BUFFER.
+If no usable window is found, return nil.
+
+If ALIST has a non-nil `inhibit-same-window' entry, the same
+window cannot be reused.
+
+If ALIST contains a `reuse-frame' entry, that determines the
+frames to check for a window displaying the buffer. If the entry
+is omitted or the value is nil, check only this frame. The value
+can also be a specific frame, `visible' (all visible frames),
+0 (all frames on the current terminal), or t (all frames)."
+ (let* ((can-use-selected-window
+ (not (cdr (assq 'inhibit-same-window alist))))
+ (frames (or (cdr (assq 'reuse-frame alist))
+ (last-nonminibuffer-frame)))
+ (window (catch 'found
+ (dolist (window (get-buffer-window-list
+ buffer 'nomini frames))
+ (when (or can-use-selected-window
+ (not (eq (selected-window) window)))
+ (throw 'found window))))))
+ (when window
+ (display-buffer-record-window 'reuse-window window buffer)
+ (window--display-buffer-1 window))))
+
+(defun display-buffer-pop-up-frame (buffer alist)
+ "Display BUFFER in a new frame.
+This works by calling `pop-up-frame-function'. If sucessful,
+return the window on the new frame; otherwise return nil."
+ (let ((fun pop-up-frame-function)
+ frame window)
+ (when (and fun
+ (setq frame (funcall fun))
+ (setq window (frame-selected-window frame)))
+ (display-buffer-record-window 'pop-up-frame window buffer)
+ (window--display-buffer-2 buffer window))))
+
+(defun display-buffer-pop-up-window (buffer alist)
+ "Display BUFFER by popping up a new window.
+The new window is created on the selected frame, or in
+`last-nonminibuffer-frame' if no windows can be created there.
+If sucessful, return the new window; otherwise return nil."
+ (let ((frame (or (window--frame-usable-p (selected-frame))
+ (window--frame-usable-p (last-nonminibuffer-frame))))
+ window)
+ (when (and (or (not (frame-parameter frame 'unsplittable))
+ ;; If the selected frame cannot be split, look at
+ ;; `last-nonminibuffer-frame'.
+ (and (eq frame (selected-frame))
+ (setq frame (last-nonminibuffer-frame))
+ (window--frame-usable-p frame)
+ (not (frame-parameter frame 'unsplittable))))
+ ;; Attempt to split largest or least recently used window.
+ (setq window (or (window--try-to-split-window
+ (get-largest-window frame t))
+ (window--try-to-split-window
+ (get-lru-window frame t)))))
+ (display-buffer-record-window 'pop-up-window window buffer)
+ (window--display-buffer-2 buffer window))))
+
+;; This display action function groups together some lower-level ones:
+(defun display-buffer-reuse-or-pop-window (buffer alist)
+ "Display BUFFER in some window other than the selected one.
+This attempts to call the following functions (in order):
+ - `display-buffer-reuse-window', ensuring that it checks all
+ frames on this terminal if `display-buffer-reuse-frames' or
+ `pop-up-frames' is non-nil.
+ - `special-display-function', if it is available.
+ - `display-buffer-pop-up-frame', if specified by `pop-up-frames'.
+ - `display-buffer-pop-up-window', if specified by `pop-up-windows'.
+
+If BUFFER is sucessfully display, return its window; otherwise
+return nil."
+ (let ((use-pop-up-frames (if (eq pop-up-frames 'graphic-only)
+ (display-graphic-p)
+ pop-up-frames)))
+ (or (display-buffer-reuse-window
+ buffer
+ ;; If `display-buffer-reuse-frames' or `pop-up-frames' is
+ ;; non-nil, check all frames on this terminal.
+ (if (and (null (cdr (assq 'reuse-frame alist)))
+ (or use-pop-up-frames display-buffer-reuse-frames))
+ (cons '(reuse-frame . 0) alist)
+ alist))
+ ;; Try with `special-display-function':
+ (and special-display-function
+ ;; `special-display-p' returns either t or a list of frame
+ ;; parameters to pass to `special-display-function'.
+ (let ((pars (special-display-p (buffer-name buffer))))
+ (when pars
+ (funcall special-display-function
+ buffer (if (listp pars) pars)))))
+ (and use-pop-up-frames
+ (display-buffer-pop-up-frame buffer alist))
+ (and pop-up-windows
+ (display-buffer-pop-up-window buffer alist)))))
+
+(defun display-buffer-use-some-window (buffer alist)
+ "Display BUFFER in an existing window.
+Search for a usable window, set that window to the buffer, and
+return the window. If no suitable window is found, return nil."
+ (let* ((not-this-window (cdr (assq 'inhibit-same-window alist)))
+ (window-to-undedicate
+ ;; When NOT-THIS-WINDOW is non-nil, temporarily dedicate the
+ ;; selected window to its buffer, to prevent any of the
+ ;; `get-' routines below from choosing it. (Bug#1415)
+ (and not-this-window (not (window-dedicated-p))
+ (set-window-dedicated-p (selected-window) t)
+ (selected-window)))
+ (frame (or (window--frame-usable-p (selected-frame))
+ (window--frame-usable-p (last-nonminibuffer-frame))))
+ (use-pop-up-frames (if (eq pop-up-frames 'graphic-only)
+ (display-graphic-p)
+ pop-up-frames))
+ window popped-up-frame)
+ (unwind-protect
+ (setq window
+ ;; Reuse an existing window.
+ (or (get-lru-window frame)
+ (let ((window (get-buffer-window buffer 'visible)))
+ (unless (and not-this-window
+ (eq window (selected-window)))
+ window))
+ (get-largest-window 'visible)
+ (let ((window (get-buffer-window buffer 0)))
+ (unless (and not-this-window
+ (eq window (selected-window)))
+ window))
+ (get-largest-window 0)
+ (and use-pop-up-frames
+ (prog1
+ (frame-selected-window (funcall pop-up-frame-function))
+ (setq popped-up-frame t)))))
+ (when (window-live-p window-to-undedicate)
+ ;; Restore dedicated status of selected window.
+ (set-window-dedicated-p window-to-undedicate nil)))
+ (when window
+ (display-buffer-record-window
+ (if popped-up-frame 'pop-up-frame 'reuse-window) window buffer)
+ (window--even-window-heights window)
+ (window--display-buffer-2 buffer window))))
;;; Display + selection commands:
;; Based on the WINDOW-CHOICE argument, choose an action
;; argument to pass to `display-buffer'.
(cond
- ((null window-choice)
- '((display-buffer-other-window display-buffer-same-window)))
((eq window-choice 'same-window)
- '((display-buffer-same-window display-buffer-other-window)))
- (t
- '((display-buffer-other-window)))))
+ '((display-buffer-reuse-selected-window
+ display-buffer-same-window)))
+ (window-choice
+ '(nil (inhibit-same-window . t)))))
(window (display-buffer (current-buffer) action))
(frame (window-frame window)))
(if (eq frame old-frame)