;;; window.el --- GNU Emacs window commands aside from those written in C
-;; Copyright (C) 1985, 1989, 1992-1994, 2000-2012
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1989, 1992-1994, 2000-2013 Free Software
+;; Foundation, Inc.
;; Maintainer: FSF
;; Keywords: internal
;; Return the window.
window))))
+;; Doc is very similar to with-output-to-temp-buffer.
(defmacro with-temp-buffer-window (buffer-or-name action quit-function &rest body)
- "Evaluate BODY and display buffer specified by BUFFER-OR-NAME.
-BUFFER-OR-NAME must specify either a live buffer or the name of a
-buffer. If no buffer with such a name exists, create one.
-
-Make sure the specified buffer is empty before evaluating BODY.
-Do not make that buffer current for BODY. Instead, bind
-`standard-output' to that buffer, so that output generated with
-`prin1' and similar functions in BODY goes into that buffer.
-
-After evaluating BODY, mark the specified buffer unmodified and
-read-only, and display it in a window via `display-buffer'. Pass
-ACTION as action argument to `display-buffer'. Automatically
-shrink the window used if `temp-buffer-resize-mode' is enabled.
-
-Return the value returned by BODY unless QUIT-FUNCTION specifies
-a function. In that case, run the function with two arguments -
+ "Bind `standard-output' to BUFFER-OR-NAME, eval BODY, show the buffer.
+BUFFER-OR-NAME must specify either a live buffer, or the name of a
+buffer (if it does not exist, this macro creates it).
+
+This construct makes buffer BUFFER-OR-NAME empty before running BODY.
+It does not make the buffer current for BODY.
+Instead it binds `standard-output' to that buffer, so that output
+generated with `prin1' and similar functions in BODY goes into
+the buffer.
+
+At the end of BODY, this marks the specified buffer unmodified and
+read-only, and displays it in a window (but does not select it, or make
+the buffer current). The display happens by calling `display-buffer'
+with the ACTION argument. If `temp-buffer-resize-mode' is enabled,
+the relevant window shrinks automatically.
+
+This returns the value returned by BODY, unless QUIT-FUNCTION specifies
+a function. In that case, it runs the function with two arguments -
the window showing the specified buffer and the value returned by
-BODY - and return the value returned by that function.
+BODY - and returns the value returned by that function.
If the buffer is displayed on a new frame, the window manager may
decide to select that frame. In that case, it's usually a good
-strategy if the function specified by QUIT-FUNCTION selects the
-window showing the buffer before reading a value from the
-minibuffer, for example, when asking a `yes-or-no-p' question.
-
-This construct is similar to `with-output-to-temp-buffer' but
-does neither put the buffer in help mode nor does it call
-`temp-buffer-show-function'. It also runs different hooks,
-namely `temp-buffer-window-setup-hook' (with the specified buffer
-current) and `temp-buffer-window-show-hook' (with the specified
-buffer current and the window showing it selected).
-
-Since this macro calls `display-buffer', the window displaying
-the buffer is usually not selected and the specified buffer
-usually not made current. QUIT-FUNCTION can override that."
+strategy if QUIT-FUNCTION selects the window showing the buffer
+before reading any value from the minibuffer; for example, when
+asking a `yes-or-no-p' question.
+
+This runs the hook `temp-buffer-window-setup-hook' before BODY,
+with the specified buffer temporarily current. It runs the
+hook `temp-buffer-window-show-hook' after displaying the buffer,
+with that buffer temporarily current, and the window that was used to
+display it temporarily selected.
+
+This construct is similar to `with-output-to-temp-buffer', but
+runs different hooks. In particular, it does not run
+`temp-buffer-setup-hook', which usually puts the buffer in Help mode.
+Also, it does not call `temp-buffer-show-function' (the ACTION
+argument replaces this)."
(declare (debug t))
(let ((buffer (make-symbol "buffer"))
(window (make-symbol "window"))
delta))
(t 0)))
-(defun window--resizable-p (window delta &optional horizontal ignore trail noup nodown)
+(defun window-resizable-p (window delta &optional horizontal ignore trail noup nodown)
"Return t if WINDOW can be resized vertically by DELTA lines.
WINDOW must be a valid window and defaults to the selected one.
For the meaning of the arguments of this function see the
;; nil or the minibuffer window is active, resize the minibuffer
;; window.
(window--resize-mini-window minibuffer-window (- delta)))
- ((window--resizable-p window delta horizontal ignore)
+ ((window-resizable-p window delta horizontal ignore)
(window--resize-reset frame horizontal)
(window--resize-this-window window delta horizontal ignore t)
(if (and (not window-combination-resize)
(t
(error "Cannot resize window %s" window)))))
+(defun window-resize-no-error (window delta &optional horizontal ignore)
+ "Resize WINDOW vertically if it is resizable by DELTA lines.
+This function is like `window-resize' but does not signal an
+error when WINDOW cannot be resized. For the meaning of the
+optional arguments see the documentation of `window-resize'."
+ (when (window-resizable-p window delta horizontal ignore)
+ (window-resize window delta horizontal ignore)))
+
(defun window--resize-child-windows-skip-p (window)
"Return non-nil if WINDOW shall be skipped by resizing routines."
(memq (window-new-normal window) '(ignore stuck skip)))
Interactively, if no argument is given, make the selected window
one line taller. If optional argument HORIZONTAL is non-nil,
make selected window wider by DELTA columns. If DELTA is
-negative, shrink selected window by -DELTA lines or columns.
-Return nil."
+negative, shrink selected window by -DELTA lines or columns."
(interactive "p")
(let ((minibuffer-window (minibuffer-window)))
(cond
;; If the selected window is full height and `resize-mini-windows'
;; is nil, resize the minibuffer window.
(window--resize-mini-window minibuffer-window (- delta)))
- ((window--resizable-p nil delta horizontal)
+ ((window-resizable-p nil delta horizontal)
(window-resize nil delta horizontal))
(t
(window-resize
one line smaller. If optional argument HORIZONTAL is non-nil,
make selected window narrower by DELTA columns. If DELTA is
negative, enlarge selected window by -DELTA lines or columns.
-Also see the `window-min-height' variable.
-Return nil."
+Also see the `window-min-height' variable."
(interactive "p")
(let ((minibuffer-window (minibuffer-window)))
(cond
;; If the selected window is full height and `resize-mini-windows'
;; is nil, resize the minibuffer window.
(window--resize-mini-window minibuffer-window delta))
- ((window--resizable-p nil (- delta) horizontal)
+ ((window-resizable-p nil (- delta) horizontal)
(window-resize nil (- delta) horizontal))
(t
(window-resize
(set-window-new-normal
sibling (+ (window-normal-size sibling horizontal)
(window-normal-size window horizontal))))
- ((window--resizable-p window (- size) horizontal nil nil nil t)
+ ((window-resizable-p window (- size) horizontal nil nil nil t)
;; Can do without resizing fixed-size windows.
(window--resize-siblings window (- size) horizontal))
(t
(set-marker (nth 2 entry) point))
;; Make new markers.
(list (copy-marker start)
- (copy-marker point)))))
-
+ (copy-marker
+ ;; Preserve window-point-insertion-type
+ ;; (Bug#12588).
+ point window-point-insertion-type)))))
(set-window-prev-buffers
window (cons entry (window-prev-buffers window))))))))
"If non-nil, allow switching to an already visible buffer.
If this variable is non-nil, `switch-to-prev-buffer' and
`switch-to-next-buffer' may switch to an already visible buffer
-provided the buffer was shown in the argument window before. If
-this variable is nil, `switch-to-prev-buffer' and
-`switch-to-next-buffer' always try to avoid switching to a buffer
-that is already visible in another window on the same frame."
+provided the buffer was shown before in the window specified as
+argument to those functions. If this variable is nil,
+`switch-to-prev-buffer' and `switch-to-next-buffer' always try to
+avoid switching to a buffer that is already visible in another
+window on the same frame."
:type 'boolean
:version "24.1"
:group 'windows)
quad entry)
(cond
((and (not prev-buffer)
- (memq (nth 1 quit-restore) '(window frame))
+ (or (eq (nth 1 quit-restore) 'frame)
+ (and (eq (nth 1 quit-restore) 'window)
+ ;; If the window has been created on an existing
+ ;; frame and ended up as the sole window on that
+ ;; frame, do not delete it (Bug#12764).
+ (not (eq window (frame-root-window window)))))
(eq (nth 3 quit-restore) buffer)
;; Delete WINDOW if possible.
(window--delete window nil (eq bury-or-kill 'kill)))
(let ((delta (- (cdr (assq 'total-height item))
(window-total-height window)))
window-size-fixed)
- (when (window--resizable-p window delta)
+ (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-resizable-p window delta nil ignore))
(window-resize window delta nil ignore))))
;; Adjust horizontally.
(if (memq window-size-fixed '(t width))
(let ((delta (- (cdr (assq 'total-width item))
(window-total-width window)))
window-size-fixed)
- (when (window--resizable-p window delta)
+ (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-resizable-p window delta t ignore))
(window-resize window delta t ignore))))
;; Set dedicated status.
(set-window-dedicated-p window (cdr (assq 'dedicated state)))
;; If WINDOW has a quit-restore parameter, reset its car.
(setcar (window-parameter window 'quit-restore) 'same))
;; WINDOW shows another buffer.
- (set-window-parameter
- window 'quit-restore
- (list 'other
- ;; A quadruple of WINDOW's buffer, start, point and height.
- (list (window-buffer window) (window-start window)
- (window-point window) (window-total-size window))
- (selected-window) buffer))))
+ (with-current-buffer (window-buffer window)
+ (set-window-parameter
+ window 'quit-restore
+ (list 'other
+ ;; A quadruple of WINDOW's buffer, start, point and height.
+ (list (current-buffer) (window-start window)
+ ;; Preserve window-point-insertion-type (Bug#12588).
+ (copy-marker
+ (window-point window) window-point-insertion-type)
+ (window-total-size window))
+ (selected-window) buffer)))))
((eq type 'window)
;; WINDOW has been created on an existing frame.
(set-window-parameter
(error nil))))
(defun window--display-buffer (buffer window type &optional alist dedicated)
- "Display BUFFER in WINDOW and make its frame visible.
+ "Display BUFFER in WINDOW.
TYPE must be one of the symbols `reuse', `window' or `frame' and
-is passed unaltered to `display-buffer-record-window'. Set
-`window-dedicated-p' to DEDICATED if non-nil. Return WINDOW if
-BUFFER and WINDOW are live."
+is passed unaltered to `display-buffer-record-window'. ALIST is
+the alist argument of `display-buffer'. Set `window-dedicated-p'
+to DEDICATED if non-nil. Return WINDOW if BUFFER and WINDOW are
+live."
(when (and (buffer-live-p buffer) (window-live-p window))
(display-buffer-record-window type window buffer)
(unless (eq buffer (window-buffer window))
(let ((parameter (window-parameter window 'quit-restore))
(height (cdr (assq 'window-height alist)))
(width (cdr (assq 'window-width alist))))
- (when (or (memq type '(window frame))
+ (when (or (eq type 'window)
(and (eq (car parameter) 'same)
- (memq (nth 1 parameter) '(window frame))))
- ;; Adjust height of new window or frame.
+ (eq (nth 1 parameter) 'window)))
+ ;; Adjust height of window if asked for.
(cond
((not height))
((numberp height)
(* (window-total-size (frame-root-window window))
height))))
(delta (- new-height (window-total-size window))))
- (cond
- ((and (window--resizable-p window delta nil 'safe)
- (window-combined-p window))
- (window-resize window delta nil 'safe))
- ((or (eq type 'frame)
- (and (eq (car parameter) 'same)
- (eq (nth 1 parameter) 'frame)))
- (set-frame-height
- (window-frame window)
- (+ (frame-height (window-frame window)) delta))))))
+ (when (and (window-resizable-p window delta nil 'safe)
+ (window-combined-p window))
+ (window-resize window delta nil 'safe))))
((functionp height)
(ignore-errors (funcall height window))))
- ;; Adjust width of a window or frame.
+ ;; Adjust width of window if asked for.
(cond
((not width))
((numberp width)
(* (window-total-size (frame-root-window window) t)
width))))
(delta (- new-width (window-total-size window t))))
- (cond
- ((and (window--resizable-p window delta t 'safe)
- (window-combined-p window t))
- (window-resize window delta t 'safe))
- ((or (eq type 'frame)
- (and (eq (car parameter) 'same)
- (eq (nth 1 parameter) 'frame)))
- (set-frame-width
- (window-frame window)
- (+ (frame-width (window-frame window)) delta))))))
+ (when (and (window-resizable-p window delta t 'safe)
+ (window-combined-p window t))
+ (window-resize window delta t 'safe))))
((functionp width)
(ignore-errors (funcall width window))))))
+
window))
(defun window--maybe-raise-frame (frame)
"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.
+ CONDITION is either a regexp matching buffer names, or a
+ function that takes two arguments - a buffer name and the
+ ACTION argument of `display-buffer' - and returns a boolean.
ACTION is a cons cell (FUNCTION . ALIST), where FUNCTION is a
function or a list of functions. Each such function should
accept two arguments: a buffer to display and an alist of the
- same form as ALIST. See `display-buffer' for details."
+ same form as ALIST. See `display-buffer' for details.
+
+`display-buffer' scans this alist until it either finds a
+matching regular expression or the function specified by a
+condition returns non-nil. In any of these cases, it adds the
+associated action to the list of actions it will try."
:type `(alist :key-type
(choice :tag "Condition"
regexp
`display-buffer-base-action'. See `display-buffer'.")
(put 'display-buffer-fallback-action 'risky-local-variable t)
-(defun display-buffer-assq-regexp (buffer-name alist)
- "Retrieve ALIST entry corresponding to BUFFER-NAME."
+(defun display-buffer-assq-regexp (buffer-name alist action)
+ "Retrieve ALIST entry corresponding to BUFFER-NAME.
+ACTION is the action argument passed to `display-buffer'."
(catch 'match
(dolist (entry alist)
(let ((key (car entry)))
(when (or (and (stringp key)
(string-match-p key buffer-name))
- (and (symbolp key) (functionp key)
- (funcall key buffer-name alist)))
+ (and (functionp key)
+ (funcall key buffer-name action)))
(throw 'match (cdr entry)))))))
(defvar display-buffer--same-window-action
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.
+Optional argument ACTION, if non-nil, should specify a display
+action. Its form is described below.
+
+Optional argument FRAME, if non-nil, acts like an additional
+ALIST entry (reusable-frames . FRAME) to the action list of ACTION,
+specifying the frame(s) to search for a window that is already
+displaying the buffer. See `display-buffer-reuse-window'
+
+If ACTION is non-nil, it should have the form (FUNCTION . ALIST),
+where FUNCTION is either a function or a list of functions, and
ALIST is an arbitrary association list (alist).
Each such FUNCTION should accept two arguments: the buffer to
buffer as the first argument and the combined alist as the second
argument, until one of the functions returns non-nil.
+If ACTION is nil, the function list and the alist are built using
+only the other variables mentioned above.
+
Available action functions include:
`display-buffer-same-window'
`display-buffer-reuse-window'
parameters to give a new frame, if
one is created.
+ `window-height' -- Value specifies either an integer (the number
+ of lines of a new window), a floating point number (the
+ fraction of a new window with respect to the height of the
+ frame's root window) or a function to be called with one
+ argument - a 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'.
+
+ `window-width' -- Value specifies either an integer (the number
+ of columns of a new window), a floating point number (the
+ fraction of a new window with respect to the width of the
+ frame's root window) or a function to be called with one
+ argument - a new window. The function is supposed to adjust
+ the width of the window; its return value is ignored.
+
The ACTION argument to `display-buffer' 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, if non-nil, acts like an additional
-ALIST entry (reusable-frames . FRAME), specifying the frame(s) to
-search for a window that is already displaying the buffer. See
-`display-buffer-reuse-window'."
+argument, ACTION is t."
(interactive (list (read-buffer "Display buffer: " (other-buffer))
(if current-prefix-arg t)))
(let ((buffer (if (bufferp buffer-or-name)
(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))
+ (display-buffer-assq-regexp
+ (buffer-name buffer) display-buffer-alist action))
(special-action (display-buffer--special-action buffer))
;; Extra actions from the arguments to this function:
(extra-action
buffer))
(other-buffer)))
+(defcustom switch-to-buffer-preserve-window-point nil
+ "If non-nil, `switch-to-buffer' tries to preserve `window-point'.
+If this is nil, `switch-to-buffer' displays the buffer at that
+buffer's `point'. If this is `already-displayed', it tries to
+display the buffer at its previous position in the selected
+window, provided the buffer is currently displayed in some other
+window on any visible or iconified frame. If this is t, it
+unconditionally tries to display the buffer at its previous
+position in the selected window.
+
+This variable is ignored if the buffer is already displayed in
+the selected window or never appeared in it before, or if
+`switch-to-buffer' calls `pop-to-buffer' to display the buffer."
+ :type '(choice
+ (const :tag "Never" nil)
+ (const :tag "If already displayed elsewhere" already-displayed)
+ (const :tag "Always" t))
+ :group 'windows
+ :version "24.3")
+
(defun switch-to-buffer (buffer-or-name &optional norecord force-same-window)
- "Switch to buffer BUFFER-OR-NAME in the selected window.
+ "Display buffer BUFFER-OR-NAME in the selected window.
+
+WARNING: This is NOT the way to work on another buffer temporarily
+within a Lisp program! Use `set-buffer' instead. That avoids
+messing with the window-buffer correspondences.
+
If the selected window cannot display the specified
buffer (e.g. if it is a minibuffer window or strongly dedicated
to another buffer), call `pop-to-buffer' to select the buffer in
must be displayed in the selected window; if that is impossible,
signal an error rather than calling `pop-to-buffer'.
+The option `switch-to-buffer-preserve-window-point' can be used
+to make the buffer appear at its last position in the selected
+window.
+
Return the buffer switched to."
(interactive
(list (read-buffer-to-switch "Switch to buffer: ") nil 'force-same-window))
(if force-same-window
(user-error "Cannot switch buffers in a dedicated window")
(pop-to-buffer buffer norecord)))
- (t (set-window-buffer nil buffer)))
+ (t
+ (let* ((entry (assq buffer (window-prev-buffers)))
+ (displayed (and (eq switch-to-buffer-preserve-window-point
+ 'already-displayed)
+ (get-buffer-window buffer 0))))
+ (set-window-buffer nil buffer)
+ (when (and entry
+ (or (eq switch-to-buffer-preserve-window-point t)
+ displayed))
+ ;; Try to restore start and point of buffer in the selected
+ ;; window (Bug#4041).
+ (set-window-start (selected-window) (nth 1 entry) t)
+ (set-window-point nil (nth 2 entry))))))
(unless norecord
(select-window (selected-window)))
window. The height of the root window is subject to the values
of `fit-frame-to-buffer-max-height' and `window-min-height'."
:type 'boolean
- :version "24.2"
+ :version "24.3"
:group 'help)
(defcustom fit-frame-to-buffer-bottom-margin 4
- "Bottom margin for `fit-frame-to-buffer'.
-This is the number of lines `fit-frame-to-buffer' leaves free at the
-bottom of the display in order to not obscure the system task bar."
+ "Bottom margin for the command `fit-frame-to-buffer'.
+This is the number of lines that function leaves free at the bottom of
+the display, in order to not obscure any system task bar or panel.
+If you do not have one (or if it is vertical) you might want to
+reduce this. If it is thicker, you might want to increase this."
+ ;; If you set this too small, fit-frame-to-buffer can shift the
+ ;; frame up to avoid the panel.
:type 'integer
- :version "24.2"
+ :version "24.3"
:group 'windows)
(defun fit-frame-to-buffer (&optional frame max-height min-height)
- "Adjust height of FRAME to display its buffer's contents exactly.
+ "Adjust height of FRAME to display its buffer contents exactly.
FRAME can be any live frame and defaults to the selected one.
-Optional argument MAX-HEIGHT specifies the maximum height of
-FRAME and defaults to the height of the display below the current
-top line of FRAME minus FIT-FRAME-TO-BUFFER-BOTTOM-MARGIN.
-Optional argument MIN-HEIGHT specifies the minimum height of
-FRAME."
+Optional argument MAX-HEIGHT specifies the maximum height of FRAME.
+It defaults to the height of the display below the current
+top line of FRAME, minus `fit-frame-to-buffer-bottom-margin'.
+Optional argument MIN-HEIGHT specifies the minimum height of FRAME.
+The default corresponds to `window-min-height'."
(interactive)
(setq frame (window-normalize-frame frame))
(let* ((root (frame-root-window frame))
are specified in lines and include the mode line and header line,
if any.
+If WINDOW is a full height window, then if the option
+`fit-frame-to-buffer' is non-nil, this calls the function
+`fit-frame-to-buffer' to adjust the frame height.
+
Return the number of lines by which WINDOW was enlarged or
shrunk. If an error occurs during resizing, return nil but don't
signal an error.