X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c1567cc72d17834f05d2c81d7457b8d249a2a71d..2b4e72e1d5ccecf590125c022a78a88755c779e5:/lisp/window.el diff --git a/lisp/window.el b/lisp/window.el index d338aa20fc..b3ec25e1f6 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -1,7 +1,7 @@ ;;; window.el --- GNU Emacs window commands aside from those written in C ;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001, 2002, -;; 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +;; 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: internal @@ -39,19 +39,20 @@ unless you explicitly change the size, or Emacs has no other choice.") (make-variable-buffer-local 'window-size-fixed) (defmacro save-selected-window (&rest body) - "Execute BODY, then select the window that was selected before BODY. + "Execute BODY, then select the previously selected window. The value returned is the value of the last form in BODY. +This macro saves and restores the selected window, as well as the +selected window in each frame. If the previously selected window +is no longer live, then whatever window is selected at the end of +BODY remains selected. If the previously selected window of some +frame is no longer live at the end of BODY, that frame's selected +window is left alone. + This macro saves and restores the current buffer, since otherwise -its normal operation could potentially make a different -buffer current. It does not alter the buffer list ordering. - -This macro saves and restores the selected window, as well as -the selected window in each frame. If the previously selected -window of some frame is no longer live at the end of BODY, that -frame's selected window is left alone. If the selected window is -no longer live, then whatever window is selected at the end of -BODY remains selected." +its normal operation could make a different buffer current. The +order of recently selected windows and the buffer list ordering +are not altered by this macro (unless they are altered in BODY)." `(let ((save-selected-window-window (selected-window)) ;; It is necessary to save all of these, because calling ;; select-window changes frame-selected-window for whatever @@ -65,13 +66,19 @@ BODY remains selected." (dolist (elt save-selected-window-alist) (and (frame-live-p (car elt)) (window-live-p (cdr elt)) - (set-frame-selected-window (car elt) (cdr elt)))) - (if (window-live-p save-selected-window-window) - (select-window save-selected-window-window)))))) + (set-frame-selected-window (car elt) (cdr elt) 'norecord))) + (when (window-live-p save-selected-window-window) + (select-window save-selected-window-window 'norecord)))))) (defun window-body-height (&optional window) - "Return number of lines in window WINDOW for actual buffer text. -This does not include the mode line (if any) or the header line (if any)." + "Return number of lines in WINDOW available for actual buffer text. +WINDOW defaults to the selected window. + +The return value does not include the mode line or the header +line, if any. If a line at the bottom of the window is only +partially visible, that line is included in the return value. If +you do not want to include a partially visible bottom line in the +return value, use `window-text-height' instead." (or window (setq window (selected-window))) (if (window-minibuffer-p window) (window-height window) @@ -99,11 +106,18 @@ If ALL-FRAMES is anything else, count only the selected frame." (next-window base-window (if nomini 'arg) all-frames)))) (defun window-current-scroll-bars (&optional window) - "Return the current scroll-bar settings in window WINDOW. -Value is a cons (VERTICAL . HORIZONTAL) where VERTICAL specifies the -current location of the vertical scroll-bars (left, right, or nil), -and HORIZONTAL specifies the current location of the horizontal scroll -bars (top, bottom, or nil)." + "Return the current scroll bar settings for WINDOW. +WINDOW defaults to the selected window. + +The return value is a cons cell (VERTICAL . HORIZONTAL) where +VERTICAL specifies the current location of the vertical scroll +bars (`left', `right', or nil), and HORIZONTAL specifies the +current location of the horizontal scroll bars (`top', `bottom', +or nil). + +Unlike `window-scroll-bars', this function reports the scroll bar +type actually used, once frame defaults and `scroll-bar-mode' are +taken into account." (let ((vert (nth 2 (window-scroll-bars window))) (hor nil)) (when (or (eq vert t) (eq hor t)) @@ -116,34 +130,53 @@ bars (top, bottom, or nil)." (cons vert hor))) (defun walk-windows (proc &optional minibuf all-frames) - "Cycle through all visible windows, calling PROC for each one. -PROC is called with a window as argument. + "Cycle through all windows, calling PROC for each one. +PROC must specify a function with a window as its sole argument. +The optional arguments MINIBUF and ALL-FRAMES specify the set of +windows to include in the walk, see also `next-window'. -Optional second arg MINIBUF t means count the minibuffer window even -if not active. MINIBUF nil or omitted means count the minibuffer only if -it is active. MINIBUF neither t nor nil means not to count the -minibuffer even if it is active. +MINIBUF t means include the minibuffer window even if the +minibuffer is not active. MINIBUF nil or omitted means include +the minibuffer window only if the minibuffer is active. Any +other value means do not include the minibuffer window even if +the minibuffer is active. Several frames may share a single minibuffer; if the minibuffer -counts, all windows on all frames that share that minibuffer count -too. Therefore, if you are using a separate minibuffer frame -and the minibuffer is active and MINIBUF says it counts, -`walk-windows' includes the windows in the frame from which you -entered the minibuffer, as well as the minibuffer window. - -ALL-FRAMES is the optional third argument. -ALL-FRAMES nil or omitted means cycle within the frames as specified above. -ALL-FRAMES = `visible' means include windows on all visible frames. -ALL-FRAMES = 0 means include windows on all visible and iconified frames. -ALL-FRAMES = t means include windows on all frames including invisible frames. -If ALL-FRAMES is a frame, it means include windows on that frame. -Anything else means restrict to the selected frame." - ;; If we start from the minibuffer window, don't fail to come back to it. - (if (window-minibuffer-p (selected-window)) - (setq minibuf t)) +is active, all windows on all frames that share that minibuffer +are included too. Therefore, if you are using a separate +minibuffer frame and the minibuffer is active and MINIBUF says it +counts, `walk-windows' includes the windows in the frame from +which you entered the minibuffer, as well as the minibuffer +window. + +ALL-FRAMES nil or omitted means cycle through all windows on + WINDOW's frame, plus the minibuffer window if specified by the + MINIBUF argument, see above. If the minibuffer counts, cycle + through all windows on all frames that share that minibuffer + too. +ALL-FRAMES t means cycle through all windows on all existing + frames. +ALL-FRAMES `visible' means cycle through all windows on all + visible frames. +ALL-FRAMES 0 means cycle through all windows on all visible and + iconified frames. +ALL-FRAMES a frame means cycle through all windows on that frame + only. +Anything else means cycle through all windows on WINDOW's frame + and no others. + +This function changes neither the order of recently selected +windows nor the buffer list." + ;; If we start from the minibuffer window, don't fail to come + ;; back to it. + (when (window-minibuffer-p (selected-window)) + (setq minibuf t)) + ;; Make sure to not mess up the order of recently selected + ;; windows. Use `save-selected-window' and `select-window' + ;; with second argument non-nil for this purpose. (save-selected-window - (if (framep all-frames) - (select-window (frame-first-window all-frames))) + (when (framep all-frames) + (select-window (frame-first-window all-frames) 'norecord)) (let* (walk-windows-already-seen (walk-windows-current (selected-window))) (while (progn @@ -157,32 +190,15 @@ Anything else means restrict to the selected frame." (defun get-window-with-predicate (predicate &optional minibuf all-frames default) "Return a window satisfying PREDICATE. - -This function cycles through all visible windows using `walk-windows', -calling PREDICATE on each one. PREDICATE is called with a window as -argument. The first window for which PREDICATE returns a non-nil -value is returned. If no window satisfies PREDICATE, DEFAULT is -returned. - -Optional second arg MINIBUF t means count the minibuffer window even -if not active. MINIBUF nil or omitted means count the minibuffer only if -it is active. MINIBUF neither t nor nil means not to count the -minibuffer even if it is active. - -Several frames may share a single minibuffer; if the minibuffer -counts, all windows on all frames that share that minibuffer count -too. Therefore, if you are using a separate minibuffer frame -and the minibuffer is active and MINIBUF says it counts, -`walk-windows' includes the windows in the frame from which you -entered the minibuffer, as well as the minibuffer window. - -ALL-FRAMES is the optional third argument. -ALL-FRAMES nil or omitted means cycle within the frames as specified above. -ALL-FRAMES = `visible' means include windows on all visible frames. -ALL-FRAMES = 0 means include windows on all visible and iconified frames. -ALL-FRAMES = t means include windows on all frames including invisible frames. -If ALL-FRAMES is a frame, it means include windows on that frame. -Anything else means restrict to the selected frame." +More precisely, cycle through all windows using `walk-windows', +calling the function PREDICATE on each one of them with the +window as its sole argument. Return the first window for which +PREDICATE returns non-nil. If no window satisfies PREDICATE, +return DEFAULT. + +The optional arguments MINIBUF and ALL-FRAMES specify the set of +windows to include. See `walk-windows' for the meaning of these +arguments." (catch 'found (walk-windows #'(lambda (window) (when (funcall predicate window) @@ -193,11 +209,19 @@ Anything else means restrict to the selected frame." (defalias 'some-window 'get-window-with-predicate) ;; This should probably be written in C (i.e., without using `walk-windows'). -(defun get-buffer-window-list (buffer &optional minibuf all-frames) - "Return list of all windows displaying BUFFER, or nil if none. -BUFFER can be a buffer or a buffer name. -See `walk-windows' for the meaning of MINIBUF and ALL-FRAMES." - (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows) +(defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames) + "Return list of all windows displaying BUFFER-OR-NAME, or nil if none. +BUFFER-OR-NAME may be a buffer or the name of an existing buffer +and defaults to the current buffer. + +The optional arguments MINIBUF and ALL-FRAMES specify the set of +windows to consider. See `walk-windows' for the precise meaning +of these arguments." + (let ((buffer (cond + ((not buffer-or-name) (current-buffer)) + ((bufferp buffer-or-name) buffer-or-name) + (t (get-buffer buffer-or-name)))) + windows) (walk-windows (function (lambda (window) (if (eq (window-buffer window) buffer) (setq windows (cons window windows))))) @@ -205,28 +229,18 @@ See `walk-windows' for the meaning of MINIBUF and ALL-FRAMES." windows)) (defun minibuffer-window-active-p (window) - "Return t if WINDOW (a minibuffer window) is now active." + "Return t if WINDOW is the currently active minibuffer window." (eq window (active-minibuffer-window))) (defun count-windows (&optional minibuf) "Return the number of visible windows. -This counts the windows in the selected frame and (if the minibuffer is -to be counted) its minibuffer frame (if that's not the same frame). -The optional arg MINIBUF non-nil means count the minibuffer -even if it is inactive." +The optional argument MINIBUF specifies whether the minibuffer +window shall be counted. See `walk-windows' for the precise +meaning of this argument." (let ((count 0)) (walk-windows (lambda (w) (setq count (+ count 1))) minibuf) count)) - -(defun window-safely-shrinkable-p (&optional window) - "Non-nil if the WINDOW can be shrunk without shrinking other windows. -If WINDOW is nil or omitted, it defaults to the currently selected window." - (with-selected-window (or window (selected-window)) - (let ((edges (window-edges))) - (or (= (nth 2 edges) (nth 2 (window-edges (previous-window)))) - (= (nth 0 edges) (nth 0 (window-edges (next-window)))))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; `balance-windows' subroutines using `window-tree' @@ -424,17 +438,17 @@ Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function." (dolist (c childs) (bw-balance-sub c cw ch))))) -;;; A different solution to balance-windows - (defun window-fixed-size-p (&optional window direction) - "Non-nil if WINDOW cannot be resized in DIRECTION. -DIRECTION can be nil (i.e. any), `height' or `width'." + "Return t if WINDOW cannot be resized in DIRECTION. +WINDOW defaults to the selected window. DIRECTION can be +nil (i.e. any), `height' or `width'." (with-current-buffer (window-buffer window) - (let ((fixed (and (boundp 'window-size-fixed) window-size-fixed))) - (when fixed - (not (and direction - (member (cons direction window-size-fixed) - '((height . width) (width . height))))))))) + (when (and (boundp 'window-size-fixed) window-size-fixed) + (not (and direction + (member (cons direction window-size-fixed) + '((height . width) (width . height)))))))) + +;;; A different solution to balance-windows. (defvar window-area-factor 1 "Factor by which the window area should be over-estimated. @@ -444,7 +458,8 @@ Changing this globally has no effect.") (defun balance-windows-area () "Make all visible windows the same area (approximately). -See also `window-area-factor' to change the relative size of specific buffers." +See also `window-area-factor' to change the relative size of +specific buffers." (interactive) (let* ((unchanged 0) (carry 0) (round 0) ;; Remove fixed-size windows. @@ -533,159 +548,183 @@ Commands such as `switch-to-buffer-other-window' and (function :tag "function")) :group 'windows) -(defun special-display-p (buffer-name) - "Return non-nil if a buffer named BUFFER-NAME gets a special frame. -If the value is t, `display-buffer' or `pop-to-buffer' would -create a special frame for that buffer using the default frame -parameters. - -If the value is a list, it is a list of frame parameters that -would be used to make a frame for that buffer. The variables -`special-display-buffer-names' and `special-display-regexps' -control this." - (let (tmp) - (cond - ((not (stringp buffer-name))) - ;; Make sure to return t in the following two cases. - ((member buffer-name special-display-buffer-names) t) - ((setq tmp (assoc buffer-name special-display-buffer-names)) (cdr tmp)) - ((catch 'found - (dolist (regexp special-display-regexps) - (cond - ((stringp regexp) - (when (string-match-p regexp buffer-name) - (throw 'found t))) - ((and (consp regexp) (stringp (car regexp)) - (string-match-p (car regexp) buffer-name)) - (throw 'found (cdr regexp)))))))))) - (defcustom special-display-buffer-names nil - "List of buffer names that should have their own special frames. + "List of names of buffers that should be displayed specially. Displaying a buffer with `display-buffer' or `pop-to-buffer', if -its name is in this list, makes a special frame for it using -`special-display-function'. See also `special-display-regexps'. - -An element of the list can be a list instead of just a string. -There are two ways to use a list as an element: - (BUFFER FRAME-PARAMETERS...) (BUFFER FUNCTION OTHER-ARGS...) -In the first case, the FRAME-PARAMETERS are pairs of the form -\(PARAMETER . VALUE); these parameter values are used to create -the frame. In the second case, FUNCTION is called with BUFFER as -the first argument, followed by the OTHER-ARGS--it can display -BUFFER in any way it likes. All this is done by the function -found in `special-display-function'. - -If the specified frame parameters include (same-buffer . t), the -buffer is displayed in the currently selected window. Otherwise, if -they include (same-frame . t), the buffer is displayed in a new window -in the currently selected frame. - -If this variable appears \"not to work\", because you add a name to it -but that buffer still appears in the selected window, look at the -values of `same-window-buffer-names' and `same-window-regexps'. -Those variables take precedence over this one." - :type '(repeat (choice :tag "Buffer" - :value "" - (string :format "%v") - (cons :tag "With attributes" - :format "%v" - :value ("" . nil) - (string :format "%v") - (repeat :tag "Attributes" - (cons :format "%v" - (symbol :tag "Parameter") - (sexp :tag "Value")))))) +its name is in this list, displays the buffer in a way specified +by `special-display-function'. `special-display-popup-frame' +\(the default for `special-display-function') usually displays +the buffer in a separate frame made with the parameters specified +by `special-display-frame-alist'. If `special-display-function' +has been set to some other function, that function is called with +the buffer as first, and nil as second argument. + +Alternatively, an element of this list can be specified as +\(BUFFER-NAME FRAME-PARAMETERS), where BUFFER-NAME is a buffer +name and FRAME-PARAMETERS an alist of \(PARAMETER . VALUE) pairs. +`special-display-popup-frame' will interpret such pairs as frame +parameters when it creates a special frame, overriding the +corresponding values from `special-display-frame-alist'. + +As a special case, if FRAME-PARAMETERS contains (same-window . t) +`special-display-popup-frame' displays that buffer in the +selected window. If FRAME-PARAMETERS contains (same-frame . t), +it displays that buffer in a window on the selected frame. + +If `special-display-function' specifies some other function than +`special-display-popup-frame', that function is called with the +buffer named BUFFER-NAME as first, and FRAME-PARAMETERS as second +argument. + +Finally, an element of this list can be also specified as +\(BUFFER-NAME FUNCTION OTHER-ARGS). In that case, +`special-display-popup-frame' will call FUNCTION with the buffer +named BUFFER-NAME as first argument, and OTHER-ARGS as the +second. If `special-display-function' specifies some other +function, that function is called with the buffer named +BUFFER-NAME as first, and the element's cdr as second argument. + +If this variable appears \"not to work\", because you added a +name to it but the corresponding buffer is displayed in the +selected window, look at the values of `same-window-buffer-names' +and `same-window-regexps'. Those variables take precedence over +this one. + +See also `special-display-regexps'." + :type '(repeat + (choice :tag "Buffer" + :value "" + (string :format "%v") + (cons :tag "With parameters" + :format "%v" + :value ("" . nil) + (string :format "%v") + (repeat :tag "Parameters" + (cons :format "%v" + (symbol :tag "Parameter") + (sexp :tag "Value")))) + (list :tag "With function" + :format "%v" + :value ("" . nil) + (string :format "%v") + (function :tag "Function") + (repeat :tag "Arguments" (sexp))))) + :group 'windows :group 'frames) (defcustom special-display-regexps nil - "List of regexps saying which buffers should have their own special frames. -When displaying a buffer with `display-buffer' or -`pop-to-buffer', if any regexp in this list matches the buffer -name, it makes a special frame for the buffer by calling -`special-display-function'. - -An element of the list can be a list instead of just a string. -There are two ways to use a list as an element: - (REGEXP FRAME-PARAMETERS...) (REGEXP FUNCTION OTHER-ARGS...) -In the first case, the FRAME-PARAMETERS are pairs of the form -\(PARAMETER . VALUE); these parameter values are used to create -the frame. In the second case, FUNCTION is called with BUFFER as -the first argument, followed by the OTHER-ARGS--it can display -the buffer in any way it likes. All this is done by the function -found in `special-display-function'. - -If the specified frame parameters include (same-buffer . t), the -buffer is displayed in the currently selected window. Otherwise, -if they include (same-frame . t), the buffer is displayed in a -new window in the currently selected frame. - -If this variable appears \"not to work\", because you add a -regexp to it but the matching buffers still appear in the + "List of regexps saying which buffers should be displayed specially. +Displaying a buffer with `display-buffer' or `pop-to-buffer', if +any regexp in this list matches its name, displays it specially +using `special-display-function'. `special-display-popup-frame' +\(the default for `special-display-function') usually displays +the buffer in a separate frame made with the parameters specified +by `special-display-frame-alist'. If `special-display-function' +has been set to some other function, that function is called with +the buffer as first, and nil as second argument. + +Alternatively, an element of this list can be specified as +\(REGEXP FRAME-PARAMETERS), where REGEXP is a regexp as above and +FRAME-PARAMETERS an alist of (PARAMETER . VALUE) pairs. +`special-display-popup-frame' will then interpret these pairs as +frame parameters when creating a special frame for a buffer whose +name matches REGEXP, overriding the corresponding values from +`special-display-frame-alist'. + +As a special case, if FRAME-PARAMETERS contains (same-window . t) +`special-display-popup-frame' displays buffers matching REGEXP in +the selected window. \(same-frame . t) in FRAME-PARAMETERS means +to display such buffers in a window on the selected frame. + +If `special-display-function' specifies some other function than +`special-display-popup-frame', that function is called with the +buffer whose name matched REGEXP as first, and FRAME-PARAMETERS +as second argument. + +Finally, an element of this list can be also specified as +\(REGEXP FUNCTION OTHER-ARGS). `special-display-popup-frame' +will then call FUNCTION with the buffer whose name matched +REGEXP as first, and OTHER-ARGS as second argument. If +`special-display-function' specifies some other function, that +function is called with the buffer whose name matched REGEXP +as first, and the element's cdr as second argument. + +If this variable appears \"not to work\", because you added a +name to it but the corresponding buffer is displayed in the selected window, look at the values of `same-window-buffer-names' and `same-window-regexps'. Those variables take precedence over -this one." - :type '(repeat (choice :tag "Buffer" - :value "" - (regexp :format "%v") - (cons :tag "With attributes" - :format "%v" - :value ("" . nil) - (regexp :format "%v") - (repeat :tag "Attributes" - (cons :format "%v" - (symbol :tag "Parameter") - (sexp :tag "Value")))))) +this one. + +See also `special-display-buffer-names'." + :type '(repeat + (choice :tag "Buffer" + :value "" + (regexp :format "%v") + (cons :tag "With parameters" + :format "%v" + :value ("" . nil) + (regexp :format "%v") + (repeat :tag "Parameters" + (cons :format "%v" + (symbol :tag "Parameter") + (sexp :tag "Value")))) + (list :tag "With function" + :format "%v" + :value ("" . nil) + (regexp :format "%v") + (function :tag "Function") + (repeat :tag "Arguments" (sexp))))) + :group 'windows :group 'frames) +(defun special-display-p (buffer-name) + "Return non-nil if a buffer named BUFFER-NAME gets a special frame. +More precisely, return t if `special-display-buffer-names' or +`special-display-regexps' contain a string entry equaling or +matching BUFFER-NAME. If `special-display-buffer-names' or +`special-display-regexps' contain a list entry whose car equals +or matches BUFFER-NAME, the return value is the cdr of that +entry." + (let (tmp) + (cond + ((not (stringp buffer-name))) + ((member buffer-name special-display-buffer-names) + t) + ((setq tmp (assoc buffer-name special-display-buffer-names)) + (cdr tmp)) + ((catch 'found + (dolist (regexp special-display-regexps) + (cond + ((stringp regexp) + (when (string-match-p regexp buffer-name) + (throw 'found t))) + ((and (consp regexp) (stringp (car regexp)) + (string-match-p (car regexp) buffer-name)) + (throw 'found (cdr regexp)))))))))) + (defcustom special-display-function 'special-display-popup-frame - "Function to call to make a new frame for a special buffer. -It is called with two arguments, the buffer and optional buffer -specific data, and should return a window displaying that buffer. -The default value normally makes a separate frame for the buffer, -using `special-display-frame-alist' to specify the frame -parameters. - -But if the buffer specific data includes (same-buffer . t) then -the buffer is displayed in the current selected window. -Otherwise if it includes (same-frame . t) then the buffer is -displayed in a new window in the currently selected frame. - -A buffer is special if it is listed in + "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 'frames) -(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'." - (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 same-window-buffer-names)) - ((assoc buffer-name same-window-buffer-names)) - ((catch 'found - (dolist (regexp same-window-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))))))) - (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 car must be a string specifying the -buffer name. This is for compatibility with +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. @@ -700,18 +739,46 @@ 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 car must be a string, which specifies +string. In that case, the cell's car must be a regexp matching the buffer name. This is for compatibility with -`special-display-buffer-names'; the cdr of the cons cell is -ignored. +`special-display-regexps'; the cdr of the cons cell is ignored. See also `same-window-buffer-names'." :type '(repeat (regexp :format "%v")) :group 'windows) +(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'." + (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 same-window-buffer-names)) + ((assoc buffer-name same-window-buffer-names)) + ((catch 'found + (dolist (regexp same-window-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))))))) + (defcustom pop-up-frames nil - "Non-nil means `display-buffer' should make a separate frame." - :type 'boolean + "Whether `display-buffer' should make a separate frame. +If nil, never make a seperate frame. +If the value is `graphic-only', make a separate frame +on graphic displays only. +Any other non-nil value means always make a separate frame." + :type '(choice + (const :tag "Never" nil) + (const :tag "On graphic displays only" graphic-only) + (const :tag "Always" t)) :group 'windows) (defcustom display-buffer-reuse-frames nil @@ -761,7 +828,7 @@ values of `split-height-threshold' and `split-width-threshold'." :group 'windows) (defun window--splittable-p (window &optional horizontal) - "Return non-nil if window WINDOW can be split evenly. + "Return non-nil if WINDOW can be split evenly. Optional argument HORIZONTAL non-nil means check whether WINDOW can be split horizontally. @@ -776,7 +843,7 @@ hold: - When WINDOW is split evenly, the emanating windows are at least `window-min-height' lines tall and can accommodate at least one - line plus - if WINDOW has one - a modeline. + line plus - if WINDOW has one - a mode line. WINDOW can be split horizontally when the following conditions hold: @@ -816,10 +883,10 @@ hold: (if mode-line-format 2 1)))))))))) (defun window--try-to-split-window (window) - "Split window WINDOW if it is splittable. + "Split WINDOW if it is splittable. See `window--splittable-p' for how to determine whether a window is splittable. If WINDOW can be split, return the value returned -by `split-window' or `split-window-preferred-function'." +by `split-window' (or `split-window-preferred-function')." (when (and (window-live-p window) (not (frame-parameter (window-frame window) 'unsplittable))) (if (functionp split-window-preferred-function) @@ -841,15 +908,21 @@ by `split-window' or `split-window-preferred-function'." (split-window window)))))))) (defun window--frame-usable-p (frame) - "Return frame FRAME if it can be used to display another buffer." - (when (framep frame) + "Return FRAME if it can be used to display a buffer." + (when (frame-live-p frame) (let ((window (frame-root-window frame))) ;; `frame-root-window' may be an internal window which is considered ;; "dead" by `window-live-p'. Hence if `window' is not live we ;; implicitly know that `frame' has a visible window we can use. - (when (or (not (window-live-p window)) - (and (not (window-minibuffer-p window)) - (not (window-dedicated-p window)))) + (unless (and (window-live-p window) + (or (window-minibuffer-p window) + ;; If the window is soft-dedicated, the frame is usable. + ;; Actually, even if the window is really dedicated, + ;; the frame is still usable by splitting it. + ;; At least Emacs-22 allowed it, and it is desirable + ;; when displaying same-frame windows. + nil ; (eq t (window-dedicated-p window)) + )) frame)))) (defcustom even-window-heights t @@ -861,7 +934,7 @@ window that appears above or below the selected window." :group 'windows) (defun window--even-window-heights (window) - "Even heights of window WINDOW and selected window. + "Even heights of WINDOW and selected window. Do this only if these windows are vertically adjacent to each other, `even-window-heights' is non-nil, and the selected window is higher than WINDOW." @@ -885,8 +958,8 @@ is higher than WINDOW." (error nil))))) (defun window--display-buffer-1 (window) - "Deiconify the frame containing the window WINDOW. -Do not deiconify the selected frame. Return WINDOW." + "Raise the frame containing WINDOW. +Do not raise the selected frame. Return WINDOW." (let* ((frame (window-frame window)) (visible (frame-visible-p frame))) (unless (or (not visible) @@ -896,13 +969,11 @@ Do not deiconify the selected frame. Return WINDOW." ;; is visible. (and (minibuffer-window-active-p (selected-window)) (eq frame (window-frame (minibuffer-selected-window))))) - (when (eq visible 'icon) - (make-frame-visible frame)) (raise-frame frame)) window)) (defun window--display-buffer-2 (buffer window) - "Display buffer BUFFER in window WINDOW and make its frame visible. + "Display BUFFER in WINDOW and make its frame visible. Return WINDOW." (when (and (buffer-live-p buffer) (window-live-p window)) (set-window-buffer window buffer) @@ -933,7 +1004,8 @@ 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, +`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." (interactive "BDisplay buffer:\nP") (let* ((can-use-selected-window @@ -947,6 +1019,11 @@ consider all visible or iconified frames." 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 @@ -969,14 +1046,20 @@ consider all visible or iconified frames." ;; If the buffer's name tells us to use the selected window do so. (window--display-buffer-2 buffer (selected-window))) ((let ((frames (or frame - (and (or pop-up-frames display-buffer-reuse-frames + (and (or use-pop-up-frames + display-buffer-reuse-frames (not (last-nonminibuffer-frame))) 0) (last-nonminibuffer-frame)))) - (and (setq window-to-use (get-buffer-window buffer frames)) - (or can-use-selected-window - (not (eq (selected-window) window-to-use))))) - ;; If the buffer is already displayed in some window use that. + (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. (window--display-buffer-1 window-to-use)) ((and special-display-function ;; `special-display-p' returns either t or a list of frame @@ -985,7 +1068,7 @@ consider all visible or iconified frames." (when pars (funcall special-display-function buffer (if (listp pars) pars)))))) - ((or pop-up-frames (not frame-to-use)) + ((or use-pop-up-frames (not frame-to-use)) ;; We want or need a new frame. (window--display-buffer-2 buffer (frame-selected-window (funcall pop-up-frame-function)))) @@ -1005,14 +1088,31 @@ consider all visible or iconified frames." (window--try-to-split-window (get-lru-window frame-to-use t)))) (window--display-buffer-2 buffer window-to-use))) - ((setq window-to-use - ;; Reuse an existing window. - (or (get-lru-window frame-to-use) - (get-buffer-window buffer 'visible) - (get-largest-window 'visible nil) - (get-buffer-window buffer 0) - (get-largest-window 0 nil) - (frame-selected-window (funcall pop-up-frame-function)))) + ((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) + (frame-selected-window (funcall pop-up-frame-function)))) + (when (window-live-p window-to-undedicate) + ;; Restore dedicated status of selected window. + (set-window-dedicated-p window-to-undedicate nil)))) (window--even-window-heights window-to-use) (window--display-buffer-2 buffer window-to-use))))) @@ -1051,10 +1151,10 @@ at the front of the list of recently selected ones." (old-frame (selected-frame)) new-window new-frame) (set-buffer buffer) - (setq new-window (display-buffer buffer other-window) norecord) + (setq new-window (display-buffer buffer other-window)) (unless (eq new-window old-window) ;; `display-buffer' has chosen another window, select it. - (select-window new-window) + (select-window new-window norecord) (setq new-frame (window-frame new-window)) (unless (eq new-frame old-frame) ;; `display-buffer' has chosen another frame, make sure it gets @@ -1076,16 +1176,17 @@ point in both children." :type 'boolean :group 'windows) -(defun split-window-vertically (&optional arg) - "Split current window into two windows, one above the other. -The uppermost window gets ARG lines and the other gets the rest. -Negative ARG means select the size of the lowermost window instead. -With no argument, split equally or close to it. -Both windows display the same buffer now current. +(defun split-window-vertically (&optional size) + "Split selected window into two windows, one above the other. +The upper window gets SIZE lines and the lower one gets the rest. +SIZE negative means the lower window gets -SIZE lines and the +upper one the rest. With no argument, split windows equally or +close to it. Both windows display the same buffer, now current. -If the variable `split-window-keep-point' is non-nil, both new windows -will get the same value of point as the current window. This is often -more convenient for editing. The upper window is the selected window. +If the variable `split-window-keep-point' is non-nil, both new +windows will get the same value of point as the selected window. +This is often more convenient for editing. The upper window is +the selected window. Otherwise, we choose window starts so as to minimize the amount of redisplay; this is convenient on slow terminals. The new selected @@ -1097,100 +1198,103 @@ Regardless of the value of `split-window-keep-point', the upper window is the original one and the return value is the new, lower window." (interactive "P") - (let ((old-w (selected-window)) + (let ((old-window (selected-window)) (old-point (point)) - (size (and arg (prefix-numeric-value arg))) - (window-full-p nil) - new-w bottom moved) - (and size (< size 0) (setq size (+ (window-height) size))) - (setq new-w (split-window nil size)) - (or split-window-keep-point - (progn - (save-excursion - (set-buffer (window-buffer)) - (goto-char (window-start)) - (setq moved (vertical-motion (window-height))) - (set-window-start new-w (point)) - (if (> (point) (window-point new-w)) - (set-window-point new-w (point))) - (and (= moved (window-height)) - (progn - (setq window-full-p t) - (vertical-motion -1))) - (setq bottom (point))) - (and window-full-p - (<= bottom (point)) - (set-window-point old-w (1- bottom))) - (and window-full-p - (<= (window-start new-w) old-point) - (progn - (set-window-point new-w old-point) - (select-window new-w))))) - (split-window-save-restore-data new-w old-w))) + (size (and size (prefix-numeric-value size))) + moved-by-window-height moved new-window bottom) + (and size (< size 0) + ;; Handle negative SIZE value. + (setq size (+ (window-height) size))) + (setq new-window (split-window nil size)) + (unless split-window-keep-point + (save-excursion + (set-buffer (window-buffer)) + (goto-char (window-start)) + (setq moved (vertical-motion (window-height))) + (set-window-start new-window (point)) + (when (> (point) (window-point new-window)) + (set-window-point new-window (point))) + (when (= moved (window-height)) + (setq moved-by-window-height t) + (vertical-motion -1)) + (setq bottom (point))) + (and moved-by-window-height + (<= bottom (point)) + (set-window-point old-window (1- bottom))) + (and moved-by-window-height + (<= (window-start new-window) old-point) + (set-window-point new-window old-point) + (select-window new-window))) + (split-window-save-restore-data new-window old-window))) ;; This is to avoid compiler warnings. (defvar view-return-to-alist) -(defun split-window-save-restore-data (new-w old-w) +(defun split-window-save-restore-data (new-window old-window) (with-current-buffer (window-buffer) - (if view-mode - (let ((old-info (assq old-w view-return-to-alist))) - (if old-info - (push (cons new-w (cons (car (cdr old-info)) t)) - view-return-to-alist)))) - new-w)) - -(defun split-window-horizontally (&optional arg) - "Split current window into two windows side by side. -This window becomes the leftmost of the two, and gets ARG columns. -Negative ARG means select the size of the rightmost window instead. -The argument includes the width of the window's scroll bar; if there -are no scroll bars, it includes the width of the divider column -to the window's right, if any. No ARG means split equally. - -The original, leftmost window remains selected. -The return value is the new, rightmost window." + (when view-mode + (let ((old-info (assq old-window view-return-to-alist))) + (when old-info + (push (cons new-window (cons (car (cdr old-info)) t)) + view-return-to-alist)))) + new-window)) + +(defun split-window-horizontally (&optional size) + "Split selected window into two windows side by side. +The selected window becomes the left one and gets SIZE columns. +SIZE negative means the right window gets -SIZE lines. + +SIZE includes the width of the window's scroll bar; if there are +no scroll bars, it includes the width of the divider column to +the window's right, if any. SIZE omitted or nil means split +window equally. + +The selected window remains selected. Return the new window." (interactive "P") - (let ((old-w (selected-window)) - (size (and arg (prefix-numeric-value arg)))) + (let ((old-window (selected-window)) + (size (and size (prefix-numeric-value size)))) (and size (< size 0) + ;; Handle negative SIZE value. (setq size (+ (window-width) size))) - (split-window-save-restore-data (split-window nil size t) old-w))) + (split-window-save-restore-data (split-window nil size t) old-window))) (defun set-window-text-height (window height) - "Sets the height in lines of the text display area of WINDOW to HEIGHT. -This doesn't include the mode-line (or header-line if any) or any -partial-height lines in the text display area. - -If WINDOW is nil, the selected window is used. - -Note that the current implementation of this function cannot always set -the height exactly, but attempts to be conservative, by allocating more -lines than are actually needed in the case where some error may be present." + "Set the height in lines of the text display area of WINDOW to HEIGHT. +HEIGHT doesn't include the mode line or header line, if any, or +any partial-height lines in the text display area. + +Note that the current implementation of this function cannot +always set the height exactly, but attempts to be conservative, +by allocating more lines than are actually needed in the case +where some error may be present." (let ((delta (- height (window-text-height window)))) (unless (zerop delta) ;; Setting window-min-height to a value like 1 can lead to very ;; bizarre displays because it also allows Emacs to make *other* ;; windows 1-line tall, which means that there's no more space for ;; the modeline. - (let ((window-min-height (min 2 height))) ;One text line plus a modeline. + (let ((window-min-height (min 2 height))) ; One text line plus a modeline. (if (and window (not (eq window (selected-window)))) (save-selected-window - (select-window window) + (select-window window 'norecord) (enlarge-window delta)) (enlarge-window delta)))))) -(defun enlarge-window-horizontally (arg) - "Make current window ARG columns wider." +(defun enlarge-window-horizontally (columns) + "Make selected window COLUMNS wider. +Interactively, if no argument is given, make selected window one +column wider." (interactive "p") - (enlarge-window arg t)) + (enlarge-window columns t)) -(defun shrink-window-horizontally (arg) - "Make current window ARG columns narrower." +(defun shrink-window-horizontally (columns) + "Make selected window COLUMNS narrower. +Interactively, if no argument is given, make selected window one +column narrower." (interactive "p") - (shrink-window arg t)) + (shrink-window columns t)) (defun window-buffer-height (window) "Return the height (in screen lines) of the buffer that WINDOW is displaying." @@ -1239,96 +1343,129 @@ in some window." (1+ (vertical-motion (buffer-size) window)))))) (defun fit-window-to-buffer (&optional window max-height min-height) - "Make WINDOW the right height to display its contents exactly. -If WINDOW is omitted or nil, it defaults to the selected window. -If the optional argument MAX-HEIGHT is supplied, it is the maximum height - the window is allowed to be, defaulting to the frame height. -If the optional argument MIN-HEIGHT is supplied, it is the minimum - height the window is allowed to be, defaulting to `window-min-height'. - -The heights in MAX-HEIGHT and MIN-HEIGHT include the mode-line and/or -header-line." + "Adjust height of WINDOW to display its buffer's contents exactly. +WINDOW defaults to the selected window. +Optional argument MAX-HEIGHT specifies the maximum height of the +window and defaults to the maximum permissible height of a window +on WINDOW's frame. +Optional argument MIN-HEIGHT specifies the minimum height of the +window and defaults to `window-min-height'. +Both, MAX-HEIGHT and MIN-HEIGHT are specified in lines and +include the mode line and header line, if any. + +Return non-nil if height was orderly adjusted, nil otherwise. + +Caution: This function can delete WINDOW and/or other windows +when their height shrinks to less than MIN-HEIGHT." (interactive) + ;; Do all the work in WINDOW and its buffer and restore the selected + ;; window and the current buffer when we're done. + (let ((old-buffer (current-buffer)) + value) + (with-selected-window (or window (setq window (selected-window))) + (set-buffer (window-buffer)) + ;; Use `condition-case' to handle any fixed-size windows and other + ;; pitfalls nearby. + (condition-case nil + (let* (;; MIN-HEIGHT must not be less than 1 and defaults to + ;; `window-min-height'. + (min-height (max (or min-height window-min-height) 1)) + (max-window-height + ;; Maximum height of any window on this frame. + (min (window-height (frame-root-window)) (frame-height))) + ;; MAX-HEIGHT must not be larger than max-window-height and + ;; defaults to max-window-height. + (max-height + (min (or max-height max-window-height) max-window-height)) + (desired-height + ;; The height necessary to show all of WINDOW's buffer, + ;; constrained by MIN-HEIGHT and MAX-HEIGHT. + (max + (min + ;; For an empty buffer `count-screen-lines' returns zero. + ;; Even in that case we need one line for the cursor. + (+ (max (count-screen-lines) 1) + ;; For non-minibuffers count the mode line, if any. + (if (and (not (window-minibuffer-p)) mode-line-format) + 1 0) + ;; Count the header line, if any. + (if header-line-format 1 0)) + max-height) + min-height)) + (delta + ;; How much the window height has to change. + (if (= (window-height) (window-height (frame-root-window))) + ;; Don't try to resize a full-height window. + 0 + (- desired-height (window-height)))) + ;; Do something reasonable so `enlarge-window' can make + ;; windows as small as MIN-HEIGHT. + (window-min-height (min min-height window-min-height))) + ;; Don't try to redisplay with the cursor at the end on its + ;; own line--that would force a scroll and spoil things. + (when (and (eobp) (bolp) (not (bobp))) + (set-window-point window (1- (window-point)))) + ;; Adjust WINDOW's height to the nominally correct one + ;; (which may actually be slightly off because of variable + ;; height text, etc). + (unless (zerop delta) + (enlarge-window delta)) + ;; `enlarge-window' might have deleted WINDOW, so make sure + ;; WINDOW's still alive for the remainder of this. + ;; Note: Deleting WINDOW is clearly counter-intuitive in + ;; this context, but we can't do much about it given the + ;; current semantics of `enlarge-window'. + (when (window-live-p window) + ;; Check if the last line is surely fully visible. If + ;; not, enlarge the window. + (let ((end (save-excursion + (goto-char (point-max)) + (when (and (bolp) (not (bobp))) + ;; Don't include final newline. + (backward-char 1)) + (when truncate-lines + ;; If line-wrapping is turned off, test the + ;; beginning of the last line for + ;; visibility instead of the end, as the + ;; end of the line could be invisible by + ;; virtue of extending past the edge of the + ;; window. + (forward-line 0)) + (point)))) + (set-window-vscroll window 0) + (while (and (< desired-height max-height) + (= desired-height (window-height)) + (not (pos-visible-in-window-p end))) + (enlarge-window 1) + (setq desired-height (1+ desired-height)))) + ;; Return non-nil only if nothing "bad" happened. + (setq value t))) + (error nil))) + (when (buffer-live-p old-buffer) + (set-buffer old-buffer)) + value)) - (when (null window) - (setq window (selected-window))) - (when (null max-height) - (setq max-height (frame-height (window-frame window)))) - - (let* ((buf - ;; Buffer that is displayed in WINDOW - (window-buffer window)) - (window-height - ;; The current height of WINDOW - (window-height window)) - (desired-height - ;; The height necessary to show the buffer displayed by WINDOW - ;; (`count-screen-lines' always works on the current buffer). - (with-current-buffer buf - (+ (count-screen-lines) - ;; If the buffer is empty, (count-screen-lines) is - ;; zero. But, even in that case, we need one text line - ;; for cursor. - (if (= (point-min) (point-max)) - 1 0) - ;; For non-minibuffers, count the mode-line, if any - (if (and (not (window-minibuffer-p window)) - mode-line-format) - 1 0) - ;; Count the header-line, if any - (if header-line-format 1 0)))) - (delta - ;; Calculate how much the window height has to change to show - ;; desired-height lines, constrained by MIN-HEIGHT and MAX-HEIGHT. - (- (max (min desired-height max-height) - (or min-height window-min-height)) - window-height))) - - ;; Don't try to redisplay with the cursor at the end - ;; on its own line--that would force a scroll and spoil things. - (when (with-current-buffer buf - (and (eobp) (bolp) (not (bobp)))) - (set-window-point window (1- (window-point window)))) - - (save-selected-window - (select-window window) - - ;; Adjust WINDOW to the nominally correct size (which may actually - ;; be slightly off because of variable height text, etc). - (unless (zerop delta) - (enlarge-window delta)) - - ;; Check if the last line is surely fully visible. If not, - ;; enlarge the window. - (let ((end (with-current-buffer buf - (save-excursion - (goto-char (point-max)) - (when (and (bolp) (not (bobp))) - ;; Don't include final newline - (backward-char 1)) - (when truncate-lines - ;; If line-wrapping is turned off, test the - ;; beginning of the last line for visibility - ;; instead of the end, as the end of the line - ;; could be invisible by virtue of extending past - ;; the edge of the window. - (forward-line 0)) - (point))))) - (set-window-vscroll window 0) - (while (and (< desired-height max-height) - (= desired-height (window-height window)) - (not (pos-visible-in-window-p end window))) - (enlarge-window 1) - (setq desired-height (1+ desired-height))))))) +(defun window-safely-shrinkable-p (&optional window) + "Return t if WINDOW can be shrunk without shrinking other windows. +WINDOW defaults to the selected window." + (with-selected-window (or window (selected-window)) + (let ((edges (window-edges))) + (or (= (nth 2 edges) (nth 2 (window-edges (previous-window)))) + (= (nth 0 edges) (nth 0 (window-edges (next-window)))))))) (defun shrink-window-if-larger-than-buffer (&optional window) - "Shrink the WINDOW to be as small as possible to display its contents. -If WINDOW is omitted or nil, it defaults to the selected window. -Do not shrink to less than `window-min-height' lines. -Do nothing if the buffer contains more lines than the present window height, -or if some of the window's contents are scrolled out of view, -or if shrinking this window would also shrink another window, -or if the window is the only window of its frame." + "Shrink height of WINDOW if its buffer doesn't need so many lines. +More precisely, shrink WINDOW vertically to be as small as +possible, while still showing the full contents of its buffer. +WINDOW defaults to the selected window. + +Do not shrink to less than `window-min-height' lines. Do nothing +if the buffer contains more lines than the present window height, +or if some of the window's contents are scrolled out of view, or +if shrinking this window would also shrink another window, or if +the window is the only window of its frame. + +Return non-nil if the window was shrunk, nil otherwise." (interactive) (when (null window) (setq window (selected-window))) @@ -1336,7 +1473,7 @@ or if the window is the only window of its frame." (mini (frame-parameter frame 'minibuffer)) (edges (window-edges window))) (if (and (not (eq window (frame-root-window frame))) - (window-safely-shrinkable-p) + (window-safely-shrinkable-p window) (pos-visible-in-window-p (point-min) window) (not (eq mini 'only)) (or (not mini) @@ -1374,51 +1511,39 @@ or if the window is the only window of its frame." (error nil))))) (defun quit-window (&optional kill window) - "Quit the current buffer. Bury it, and maybe delete the selected frame. -\(The frame is deleted if it contains a dedicated window for the buffer.) -With a prefix argument, kill the buffer instead. + "Quit WINDOW and bury its buffer. +With a prefix argument, kill the buffer instead. WINDOW defaults +to the selected window. -Noninteractively, if KILL is non-nil, then kill the current buffer, -otherwise bury it. +If WINDOW is non-nil, dedicated, or a minibuffer window, delete +it and, if it's alone on its frame, its frame too. Otherwise, or +if deleting WINDOW fails in any of the preceding cases, display +another buffer in WINDOW using `switch-to-buffer'. -If WINDOW is non-nil, it specifies a window; we delete that window, -and the buffer that is killed or buried is the one in that window." +Optional argument KILL non-nil means kill WINDOW's buffer. +Otherwise, bury WINDOW's buffer, see `bury-buffer'." (interactive "P") - (let ((buffer (window-buffer window)) - (frame (window-frame (or window (selected-window)))) - (window-solitary - (save-selected-window - (if window - (select-window window)) - (one-window-p t))) - window-handled) - - (save-selected-window - (if window - (select-window window)) - (or (window-minibuffer-p) - (window-dedicated-p (selected-window)) - (switch-to-buffer (other-buffer)))) - - ;; Get rid of the frame, if it has just one dedicated window - ;; and other visible frames exist. - (and (or (window-minibuffer-p) (window-dedicated-p window)) - (delq frame (visible-frame-list)) - window-solitary - (if (and (eq default-minibuffer-frame frame) - (= 1 (length (minibuffer-frame-list)))) - (setq window nil) - (delete-frame frame) - (setq window-handled t))) + (let ((buffer (window-buffer window))) + (if (or window + (window-minibuffer-p window) + (window-dedicated-p window)) + ;; WINDOW is either non-nil, a minibuffer window, or dedicated; + ;; try to delete it. + (let* ((window (or window (selected-window))) + (frame (window-frame window))) + (if (eq window (frame-root-window frame)) + ;; WINDOW is alone on its frame. `delete-windows-on' + ;; knows how to handle that case. + (delete-windows-on buffer frame) + ;; There are other windows on its frame, delete WINDOW. + (delete-window window))) + ;; Otherwise, switch to another buffer in the selected window. + (switch-to-buffer nil)) ;; Deal with the buffer. (if kill (kill-buffer buffer) - (bury-buffer buffer)) - - ;; Maybe get rid of the window. - (and window (not window-handled) (not window-solitary) - (delete-window window)))) + (bury-buffer buffer)))) (defvar recenter-last-op nil "Indicates the last recenter operation performed. @@ -1616,12 +1741,12 @@ This may be a useful alternative binding for \\[delete-other-windows] (mapc 'delete-window delenda))) (defun truncated-partial-width-window-p (&optional window) - "Non-nil if lines in WINDOW are specifically truncated due to its width. -This returns nil if WINDOW is not a partial-width window + "Return non-nil if lines in WINDOW are specifically truncated due to its width. +WINDOW defaults to the selected window. +Return nil if WINDOW is not a partial-width window (regardless of the value of `truncate-lines'). Otherwise, consult the value of `truncate-partial-width-windows' - for the buffer shown in WINDOW. -If WINDOW is nil, use the selected window." + for the buffer shown in WINDOW." (unless window (setq window (selected-window))) (unless (window-full-width-p window)