+2011-06-10 Martin Rudalics <rudalics@gmx.at>
+
+ * loadup.el (top-level): Load window before files for the sake
+ of replace-buffer-in-windows.
+
+ * files.el (read-buffer-to-switch)
+ (switch-to-buffer-other-window)
+ (switch-to-buffer-other-frame, display-buffer-other-frame): Move
+ to window.el.
+
+ * simple.el (get-next-valid-buffer, last-buffer, next-buffer)
+ (previous-buffer): Move to window.el.
+
+ * bindings.el (unbury-buffer): Move to window.el.
+
+ * window.el (delete-other-windows-vertically): Move after
+ definition of delete-other-windows.
+ (other-window, delete-windows-on, replace-buffer-in-windows):
+ Move here from window.c.
+ (record-window-buffer, unrecord-window-buffer)
+ (set-window-buffer-start-and-point, switch-to-prev-buffer)
+ (switch-to-next-buffer): New functions.
+ (get-next-valid-buffer, last-buffer, next-buffer): Move here
+ from simple.el. Call switch-to-next-buffer.
+ (previous-buffer): Move here from simple.el. Call
+ switch-to-prev-buffer.
+ (bury-buffer): Move here from buffer.c. Switch to previous
+ buffer when window cannot be deleted.
+ (unbury-buffer): Move here from bindings.el.
+ (ctl-x-map): Move binding for other-window from window.c to
+ here.
+ (read-buffer-to-switch, switch-to-buffer-other-window)
+ (switch-to-buffer-other-frame): Move here from files.el.
+ (normalize-buffer-to-switch-to): New functions.
+ (switch-to-buffer): Move here from buffer.c. Use
+ read-buffer-to-switch and normalize-buffer-to-switch-to.
+
2011-06-10 Martin Rudalics <rudalics@gmx.at>
* window.el (window-min-height, window-min-width): Move here
(put 'mode-line-buffer-identification 'risky-local-variable t)
(make-variable-buffer-local 'mode-line-buffer-identification)
-(defun unbury-buffer () "\
-Switch to the last buffer in the buffer list."
- (interactive)
- (switch-to-buffer (last-buffer)))
-
(defun mode-line-unbury-buffer (event) "\
Call `unbury-buffer' in this window."
(interactive "e")
'confirm)
(t nil)))
-(defun read-buffer-to-switch (prompt)
- "Read the name of a buffer to switch to and return as a string.
-It is intended for `switch-to-buffer' family of commands since they
-need to omit the name of current buffer from the list of completions
-and default values."
- (let ((rbts-completion-table (internal-complete-buffer-except)))
- (minibuffer-with-setup-hook
- (lambda ()
- (setq minibuffer-completion-table rbts-completion-table)
- ;; Since rbts-completion-table is built dynamically, we
- ;; can't just add it to the default value of
- ;; icomplete-with-completion-tables, so we add it
- ;; here manually.
- (if (and (boundp 'icomplete-with-completion-tables)
- (listp icomplete-with-completion-tables))
- (set (make-local-variable 'icomplete-with-completion-tables)
- (cons rbts-completion-table
- icomplete-with-completion-tables))))
- (read-buffer prompt (other-buffer (current-buffer))
- (confirm-nonexistent-file-or-buffer)))))
-
-(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
- "Select the buffer specified by BUFFER-OR-NAME in another window.
-BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
-nil. Return the buffer switched to.
-
-If called interactively, prompt for the buffer name using the
-minibuffer. The variable `confirm-nonexistent-file-or-buffer'
-determines whether to request confirmation before creating a new
-buffer.
-
-If BUFFER-OR-NAME is a string and does not identify an existing
-buffer, create a new buffer with that name. If BUFFER-OR-NAME is
-nil, switch to the buffer returned by `other-buffer'.
-
-Optional second argument NORECORD non-nil means do not put this
-buffer at the front of the list of recently selected ones.
-
-This uses the function `display-buffer' as a subroutine; see its
-documentation for additional customization information."
- (interactive
- (list (read-buffer-to-switch "Switch to buffer in other window: ")))
- (let ((pop-up-windows t)
- same-window-buffer-names same-window-regexps)
- (pop-to-buffer buffer-or-name t norecord)))
-
-(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
- "Switch to buffer BUFFER-OR-NAME in another frame.
-BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
-nil. Return the buffer switched to.
-
-If called interactively, prompt for the buffer name using the
-minibuffer. The variable `confirm-nonexistent-file-or-buffer'
-determines whether to request confirmation before creating a new
-buffer.
-
-If BUFFER-OR-NAME is a string and does not identify an existing
-buffer, create a new buffer with that name. If BUFFER-OR-NAME is
-nil, switch to the buffer returned by `other-buffer'.
-
-Optional second arg NORECORD non-nil means do not put this
-buffer at the front of the list of recently selected ones.
-
-This uses the function `display-buffer' as a subroutine; see its
-documentation for additional customization information."
- (interactive
- (list (read-buffer-to-switch "Switch to buffer in other frame: ")))
- (let ((pop-up-frames t)
- same-window-buffer-names same-window-regexps)
- (pop-to-buffer buffer-or-name t norecord)))
-
-(defun display-buffer-other-frame (buffer)
- "Display buffer BUFFER in another frame.
-This uses the function `display-buffer' as a subroutine; see
-its documentation for additional customization information."
- (interactive "BDisplay buffer in other frame: ")
- (let ((pop-up-frames t)
- same-window-buffer-names same-window-regexps
- ;;(old-window (selected-window))
- new-window)
- (setq new-window (display-buffer buffer t))
- ;; This may have been here in order to prevent the new frame from hiding
- ;; the old frame. But it does more harm than good.
- ;; Maybe we should call `raise-window' on the old-frame instead? --Stef
- ;;(lower-frame (window-frame new-window))
-
- ;; This may have been here in order to make sure the old-frame gets the
- ;; focus. But not only can it cause an annoying flicker, with some
- ;; window-managers it just makes the window invisible, with no easy
- ;; way to recover it. --Stef
- ;;(make-frame-invisible (window-frame old-window))
- ;;(make-frame-visible (window-frame old-window))
- ))
-
(defmacro minibuffer-with-setup-hook (fun &rest body)
"Temporarily add FUN to `minibuffer-setup-hook' while executing BODY.
BODY should use the minibuffer at most once.
(load "env")
(load "format")
(load "bindings")
+(load "window") ; Needed here for `replace-buffer-in-windows'.
(setq load-source-file-function 'load-with-code-conversion)
(load "files")
(load "language/cham")
(load "indent")
-(load "window")
(load "frame")
(load "term/tty-colors")
(load "font-core")
(defgroup paren-matching nil
"Highlight (un)matching of parens and expressions."
:group 'matching)
-
-(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
- "Search LIST for a valid buffer to display in FRAME.
-Return nil when all buffers in LIST are undesirable for display,
-otherwise return the first suitable buffer in LIST.
-
-Buffers not visible in windows are preferred to visible buffers,
-unless VISIBLE-OK is non-nil.
-If the optional argument FRAME is nil, it defaults to the selected frame.
-If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
- ;; This logic is more or less copied from other-buffer.
- (setq frame (or frame (selected-frame)))
- (let ((pred (frame-parameter frame 'buffer-predicate))
- found buf)
- (while (and (not found) list)
- (setq buf (car list))
- (if (and (not (eq buffer buf))
- (buffer-live-p buf)
- (or (null pred) (funcall pred buf))
- (not (eq (aref (buffer-name buf) 0) ?\s))
- (or visible-ok (null (get-buffer-window buf 'visible))))
- (setq found buf)
- (setq list (cdr list))))
- (car list)))
-
-(defun last-buffer (&optional buffer visible-ok frame)
- "Return the last buffer in FRAME's buffer list.
-If BUFFER is the last buffer, return the preceding buffer instead.
-Buffers not visible in windows are preferred to visible buffers,
-unless optional argument VISIBLE-OK is non-nil.
-Optional third argument FRAME nil or omitted means use the
-selected frame's buffer list.
-If no such buffer exists, return the buffer `*scratch*', creating
-it if necessary."
- (setq frame (or frame (selected-frame)))
- (or (get-next-valid-buffer (nreverse (buffer-list frame))
- buffer visible-ok frame)
- (get-buffer "*scratch*")
- (let ((scratch (get-buffer-create "*scratch*")))
- (set-buffer-major-mode scratch)
- scratch)))
-
-(defun next-buffer ()
- "Switch to the next buffer in cyclic order."
- (interactive)
- (let ((buffer (current-buffer)))
- (switch-to-buffer (other-buffer buffer t))
- (bury-buffer buffer)))
-
-(defun previous-buffer ()
- "Switch to the previous buffer in cyclic order."
- (interactive)
- (switch-to-buffer (last-buffer (current-buffer) t)))
-
\f
;;; next-error support framework
"Return non-nil if WINDOW is the root window of its frame."
(eq window (frame-root-window window)))
\f
+(defun other-window (count &optional all-frames)
+ "Select another window in cyclic ordering of windows.
+COUNT specifies the number of windows to skip, starting with the
+selected window, before making the selection. If COUNT is
+positive, skip COUNT windows forwards. If COUNT is negative,
+skip -COUNT windows backwards. COUNT zero means do not skip any
+window, so select the selected window. In an interactive call,
+COUNT is the numeric prefix argument. Return nil.
+
+If the `other-window' parameter of WINDOW is a function and
+`ignore-window-parameters' is nil, call that function with the
+arguments COUNT and ALL-FRAMES.
+
+This function does not select a window whose `no-other-window'
+window parameter is non-nil.
+
+This function uses `next-window' for finding the window to
+select. The argument ALL-FRAMES has the same meaning as in
+`next-window', but the MINIBUF argument of `next-window' is
+always effectively nil."
+ (interactive "p")
+ (let* ((window (selected-window))
+ (function (and (not ignore-window-parameters)
+ (window-parameter window 'other-window)))
+ old-window old-count)
+ (if (functionp function)
+ (funcall function count all-frames)
+ ;; `next-window' and `previous-window' may return a window we are
+ ;; not allowed to select. Hence we need an exit strategy in case
+ ;; all windows are non-selectable.
+ (catch 'exit
+ (while (> count 0)
+ (setq window (next-window window nil all-frames))
+ (cond
+ ((eq window old-window)
+ (when (= count old-count)
+ ;; Keep out of infinite loops. When COUNT has not changed
+ ;; since we last looked at `window' we're probably in one.
+ (throw 'exit nil)))
+ ((window-parameter window 'no-other-window)
+ (unless old-window
+ ;; The first non-selectable window `next-window' got us:
+ ;; Remember it and the current value of COUNT.
+ (setq old-window window)
+ (setq old-count count)))
+ (t
+ (setq count (1- count)))))
+ (while (< count 0)
+ (setq window (previous-window window nil all-frames))
+ (cond
+ ((eq window old-window)
+ (when (= count old-count)
+ ;; Keep out of infinite loops. When COUNT has not changed
+ ;; since we last looked at `window' we're probably in one.
+ (throw 'exit nil)))
+ ((window-parameter window 'no-other-window)
+ (unless old-window
+ ;; The first non-selectable window `previous-window' got
+ ;; us: Remember it and the current value of COUNT.
+ (setq old-window window)
+ (setq old-count count)))
+ (t
+ (setq count (1+ count)))))
+
+ (select-window window)
+ ;; Always return nil.
+ nil))))
+
;; This should probably return non-nil when the selected window is part
;; of an atomic window whose root is the frame's root window.
(defun one-window-p (&optional nomini all-frames)
(window-check frame))
;; Always return nil.
nil)))
+
+(defun delete-other-windows-vertically (&optional window)
+ "Delete the windows in the same column with WINDOW, but not WINDOW itself.
+This may be a useful alternative binding for \\[delete-other-windows]
+ if you often split windows horizontally."
+ (interactive)
+ (let* ((window (or window (selected-window)))
+ (edges (window-edges window))
+ (w window) delenda)
+ (while (not (eq (setq w (next-window w 1)) window))
+ (let ((e (window-edges w)))
+ (when (and (= (car e) (car edges))
+ (= (caddr e) (caddr edges)))
+ (push w delenda))))
+ (mapc 'delete-window delenda)))
+
+;;; Windows and buffers.
+
+;; `prev-buffers' and `next-buffers' are two reserved window slots used
+;; for (1) determining which buffer to show in the window when its
+;; buffer shall be buried or killed and (2) which buffer to show for
+;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
+
+;; `prev-buffers' consists of <buffer, window-start, window-point>
+;; triples. The entries on this list are ordered by the time their
+;; buffer has been removed from the window, the most recently removed
+;; buffer's entry being first. The window-start and window-point
+;; components are `window-start' and `window-point' at the time the
+;; buffer was removed from the window which implies that the entry must
+;; be added when `set-window-buffer' removes the buffer from the window.
+
+;; `next-buffers' is the list of buffers that have been replaced
+;; recently by `switch-to-prev-buffer'. These buffers are the least
+;; preferred candidates of `switch-to-prev-buffer' and the preferred
+;; candidates of `switch-to-next-buffer' to switch to. This list is
+;; reset to nil by any action changing the window's buffer with the
+;; exception of `switch-to-prev-buffer' and `switch-to-next-buffer'.
+;; `switch-to-prev-buffer' pushes the buffer it just replaced on it,
+;; `switch-to-next-buffer' pops the last pushed buffer from it.
+
+;; Both `prev-buffers' and `next-buffers' may reference killed buffers
+;; if such a buffer was killed while the window was hidden within a
+;; window configuration. Such killed buffers get removed whenever
+;; `switch-to-prev-buffer' or `switch-to-next-buffer' encounter them.
+
+;; The following function is called by `set-window-buffer' _before_ it
+;; replaces the buffer of the argument window with the new buffer.
+(defun record-window-buffer (&optional window)
+ "Record WINDOW's buffer.
+WINDOW must be a live window and defaults to the selected one."
+ (let* ((window (normalize-live-window window))
+ (buffer (window-buffer window))
+ (entry (assq buffer (window-prev-buffers window))))
+ ;; Reset WINDOW's next buffers. If needed, they are resurrected by
+ ;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
+ (set-window-next-buffers window nil)
+
+ (when entry
+ ;; Remove all entries for BUFFER from WINDOW's previous buffers.
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window))))
+
+ ;; Don't record insignificant buffers.
+ (unless (eq (aref (buffer-name buffer) 0) ?\s)
+ ;; Add an entry for buffer to WINDOW's previous buffers.
+ (with-current-buffer buffer
+ (let ((start (window-start window))
+ (point (window-point window)))
+ (setq entry
+ (cons buffer
+ (if entry
+ ;; We have an entry, update marker positions.
+ (list (set-marker (nth 1 entry) start)
+ (set-marker (nth 2 entry) point))
+ ;; Make new markers.
+ (list (copy-marker start)
+ (copy-marker point)))))
+
+ (set-window-prev-buffers
+ window (cons entry (window-prev-buffers window))))))))
+
+(defun unrecord-window-buffer (&optional window buffer)
+ "Unrecord BUFFER in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+BUFFER must be a live buffer and defaults to the buffer of
+WINDOW."
+ (let* ((window (normalize-live-window window))
+ (buffer (or buffer (window-buffer window))))
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+(defun set-window-buffer-start-and-point (window buffer &optional start point)
+ "Set WINDOW's buffer to BUFFER.
+Optional argument START non-nil means set WINDOW's start position
+to START. Optional argument POINT non-nil means set WINDOW's
+point to POINT. If WINDOW is selected this also sets BUFFER's
+`point' to POINT. If WINDOW is selected and the buffer it showed
+before was current this also makes BUFFER the current buffer."
+ (let ((selected (eq window (selected-window)))
+ (current (eq (window-buffer window) (current-buffer))))
+ (set-window-buffer window buffer)
+ (when (and selected current)
+ (set-buffer buffer))
+ (when start
+ (set-window-start window start))
+ (when point
+ (if selected
+ (with-current-buffer buffer
+ (goto-char point))
+ (set-window-point window point)))))
+
+(defun switch-to-prev-buffer (&optional window bury-or-kill)
+ "In WINDOW switch to previous buffer.
+WINDOW must be a live window and defaults to the selected one.
+
+Optional argument BURY-OR-KILL non-nil means the buffer currently
+shown in WINDOW is about to be buried or killed and consequently
+shall not be switched to in future invocations of this command."
+ (interactive)
+ (let* ((window (normalize-live-window window))
+ (old-buffer (window-buffer window))
+ ;; Save this since it's destroyed by `set-window-buffer'.
+ (next-buffers (window-next-buffers window))
+ entry new-buffer killed-buffers deletable visible)
+ (cond
+ ;; When BURY-OR-KILL is non-nil, there's no previous buffer for
+ ;; this window, and we can delete the window (or the frame) do
+ ;; that.
+ ((and bury-or-kill
+ (or (not (window-prev-buffers window))
+ (and (eq (caar (window-prev-buffers window)) old-buffer)
+ (not (cdr (car (window-prev-buffers window))))))
+ (setq deletable (window-deletable-p window)))
+ (if (eq deletable 'frame)
+ (delete-frame (window-frame window))
+ (delete-window window)))
+ ((window-dedicated-p window)
+ (error "Window %s is dedicated to buffer %s" window old-buffer)))
+
+ (unless deletable
+ (catch 'found
+ ;; Scan WINDOW's previous buffers first, skipping entries of next
+ ;; buffers.
+ (dolist (entry (window-prev-buffers window))
+ (when (and (setq new-buffer (car entry))
+ (or (buffer-live-p new-buffer)
+ (not (setq killed-buffers
+ (cons new-buffer killed-buffers))))
+ (not (eq new-buffer old-buffer))
+ (or bury-or-kill
+ (not (memq new-buffer next-buffers))))
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))
+ ;; Scan reverted buffer list of WINDOW's frame next, skipping
+ ;; entries of next buffers. Note that when we bury or kill a
+ ;; buffer we don't reverse the global buffer list to avoid showing
+ ;; a buried buffer instead. Otherwise, we must reverse the global
+ ;; buffer list in order to make sure that switching to the
+ ;; previous/next buffer traverse it in opposite directions.
+ (dolist (buffer (if bury-or-kill
+ (buffer-list (window-frame window))
+ (nreverse (buffer-list (window-frame window)))))
+ (when (and (buffer-live-p buffer)
+ (not (eq buffer old-buffer))
+ (not (eq (aref (buffer-name buffer) 0) ?\s))
+ (or bury-or-kill (not (memq buffer next-buffers))))
+ (if (get-buffer-window buffer)
+ ;; Try to avoid showing a buffer visible in some other window.
+ (setq visible buffer)
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point window new-buffer)
+ (throw 'found t))))
+ (unless bury-or-kill
+ ;; Scan reverted next buffers last (must not use nreverse
+ ;; here!).
+ (dolist (buffer (reverse next-buffers))
+ ;; Actually, buffer _must_ be live here since otherwise it
+ ;; would have been caught in the scan of previous buffers.
+ (when (and (or (buffer-live-p buffer)
+ (not (setq killed-buffers
+ (cons buffer killed-buffers))))
+ (not (eq buffer old-buffer))
+ (setq entry (assq buffer (window-prev-buffers window))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t))))
+
+ ;; Show a buffer visible in another window.
+ (when visible
+ (setq new-buffer visible)
+ (set-window-buffer-start-and-point window new-buffer)))
+
+ (if bury-or-kill
+ ;; Remove `old-buffer' from WINDOW's previous and (restored list
+ ;; of) next buffers.
+ (progn
+ (set-window-prev-buffers
+ window (assq-delete-all old-buffer (window-prev-buffers window)))
+ (set-window-next-buffers window (delq old-buffer next-buffers)))
+ ;; Move `old-buffer' to head of WINDOW's restored list of next
+ ;; buffers.
+ (set-window-next-buffers
+ window (cons old-buffer (delq old-buffer next-buffers)))))
+
+ ;; Remove killed buffers from WINDOW's previous and next buffers.
+ (when killed-buffers
+ (dolist (buffer killed-buffers)
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+ ;; Return new-buffer.
+ new-buffer))
+
+(defun switch-to-next-buffer (&optional window)
+ "In WINDOW switch to next buffer.
+WINDOW must be a live window and defaults to the selected one."
+ (interactive)
+ (let* ((window (normalize-live-window window))
+ (old-buffer (window-buffer window))
+ (next-buffers (window-next-buffers window))
+ new-buffer entry killed-buffers visible)
+ (when (window-dedicated-p window)
+ (error "Window %s is dedicated to buffer %s" window old-buffer))
+
+ (catch 'found
+ ;; Scan WINDOW's next buffers first.
+ (dolist (buffer next-buffers)
+ (when (and (or (buffer-live-p buffer)
+ (not (setq killed-buffers
+ (cons buffer killed-buffers))))
+ (not (eq buffer old-buffer))
+ (setq entry (assq buffer (window-prev-buffers window))))
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))
+ ;; Scan the buffer list of WINDOW's frame next, skipping previous
+ ;; buffers entries.
+ (dolist (buffer (buffer-list (window-frame window)))
+ (when (and (buffer-live-p buffer) (not (eq buffer old-buffer))
+ (not (eq (aref (buffer-name buffer) 0) ?\s))
+ (not (assq buffer (window-prev-buffers window))))
+ (if (get-buffer-window buffer)
+ ;; Try to avoid showing a buffer visible in some other window.
+ (setq visible buffer)
+ (setq new-buffer buffer)
+ (set-window-buffer-start-and-point window new-buffer)
+ (throw 'found t))))
+ ;; Scan WINDOW's reverted previous buffers last (must not use
+ ;; nreverse here!)
+ (dolist (entry (reverse (window-prev-buffers window)))
+ (when (and (setq new-buffer (car entry))
+ (or (buffer-live-p new-buffer)
+ (not (setq killed-buffers
+ (cons new-buffer killed-buffers))))
+ (not (eq new-buffer old-buffer)))
+ (set-window-buffer-start-and-point
+ window new-buffer (nth 1 entry) (nth 2 entry))
+ (throw 'found t)))
+
+ ;; Show a buffer visible in another window.
+ (when visible
+ (setq new-buffer visible)
+ (set-window-buffer-start-and-point window new-buffer)))
+
+ ;; Remove `new-buffer' from and restore WINDOW's next buffers.
+ (set-window-next-buffers window (delq new-buffer next-buffers))
+
+ ;; Remove killed buffers from WINDOW's previous and next buffers.
+ (when killed-buffers
+ (dolist (buffer killed-buffers)
+ (set-window-prev-buffers
+ window (assq-delete-all buffer (window-prev-buffers window)))
+ (set-window-next-buffers
+ window (delq buffer (window-next-buffers window)))))
+
+ ;; Return new-buffer.
+ new-buffer))
+
+(defun get-next-valid-buffer (list &optional buffer visible-ok frame)
+ "Search LIST for a valid buffer to display in FRAME.
+Return nil when all buffers in LIST are undesirable for display,
+otherwise return the first suitable buffer in LIST.
+
+Buffers not visible in windows are preferred to visible buffers,
+unless VISIBLE-OK is non-nil.
+If the optional argument FRAME is nil, it defaults to the selected frame.
+If BUFFER is non-nil, ignore occurrences of that buffer in LIST."
+ ;; This logic is more or less copied from other-buffer.
+ (setq frame (or frame (selected-frame)))
+ (let ((pred (frame-parameter frame 'buffer-predicate))
+ found buf)
+ (while (and (not found) list)
+ (setq buf (car list))
+ (if (and (not (eq buffer buf))
+ (buffer-live-p buf)
+ (or (null pred) (funcall pred buf))
+ (not (eq (aref (buffer-name buf) 0) ?\s))
+ (or visible-ok (null (get-buffer-window buf 'visible))))
+ (setq found buf)
+ (setq list (cdr list))))
+ (car list)))
+
+(defun last-buffer (&optional buffer visible-ok frame)
+ "Return the last buffer in FRAME's buffer list.
+If BUFFER is the last buffer, return the preceding buffer
+instead. Buffers not visible in windows are preferred to visible
+buffers, unless optional argument VISIBLE-OK is non-nil.
+Optional third argument FRAME nil or omitted means use the
+selected frame's buffer list. If no such buffer exists, return
+the buffer `*scratch*', creating it if necessary."
+ (setq frame (or frame (selected-frame)))
+ (or (get-next-valid-buffer (nreverse (buffer-list frame))
+ buffer visible-ok frame)
+ (get-buffer "*scratch*")
+ (let ((scratch (get-buffer-create "*scratch*")))
+ (set-buffer-major-mode scratch)
+ scratch)))
+
+(defun bury-buffer (&optional buffer-or-name)
+ "Put BUFFER-OR-NAME at the end of the list of all buffers.
+There it is the least likely candidate for `other-buffer' to
+return; thus, the least likely buffer for \\[switch-to-buffer] to
+select by default.
+
+You can specify a buffer name as BUFFER-OR-NAME, or an actual
+buffer object. If BUFFER-OR-NAME is nil or omitted, bury the
+current buffer. Also, if BUFFER-OR-NAME is nil or omitted,
+remove the current buffer from the selected window if it is
+displayed there."
+ (interactive)
+ (let* ((buffer (normalize-live-buffer buffer-or-name)))
+ ;; If `buffer-or-name' is not on the selected frame we unrecord it
+ ;; although it's not "here" (call it a feature).
+ (unrecord-buffer buffer)
+ ;; Handle case where `buffer-or-name' is nil and the current buffer
+ ;; is shown in the selected window.
+ (cond
+ ((or buffer-or-name (not (eq buffer (window-buffer)))))
+ ((not (window-dedicated-p))
+ (switch-to-prev-buffer nil 'bury))
+ ((frame-root-window-p (selected-window))
+ (iconify-frame (window-frame (selected-window))))
+ ((window-deletable-p)
+ (delete-window)))
+ ;; Always return nil.
+ nil))
+
+(defun unbury-buffer ()
+ "Switch to the last buffer in the buffer list."
+ (interactive)
+ (switch-to-buffer (last-buffer)))
+
+(defun next-buffer ()
+ "In selected window switch to next buffer."
+ (interactive)
+ (switch-to-next-buffer))
+
+(defun previous-buffer ()
+ "In selected window switch to previous buffer."
+ (interactive)
+ (switch-to-prev-buffer))
+
+(defun delete-windows-on (&optional buffer-or-name frame)
+ "Delete all windows showing BUFFER-OR-NAME.
+BUFFER-OR-NAME may be a buffer or the name of an existing buffer
+and defaults to the current buffer.
+
+The following non-nil values of the optional argument FRAME
+have special meanings:
+
+- t means consider all windows on the selected frame only.
+
+- `visible' means consider all windows on all visible frames on
+ the current terminal.
+
+- 0 (the number zero) means consider all windows on all visible
+ and iconified frames on the current terminal.
+
+- A frame means consider all windows on that frame only.
+
+Any other value of FRAME means consider all windows on all
+frames.
+
+When a window showing BUFFER-OR-NAME is dedicated and the only
+window of its frame, that frame is deleted when there are other
+frames left."
+ (interactive "BDelete windows on (buffer):\nP")
+ (let ((buffer (normalize-live-buffer buffer-or-name))
+ ;; Handle the "inverted" meaning of the FRAME argument wrt other
+ ;; `window-list-1' based function.
+ (all-frames (cond ((not frame) t) ((eq frame t) nil) (t frame))))
+ (dolist (window (window-list-1 nil nil all-frames))
+ (if (eq (window-buffer window) buffer)
+ (let ((deletable (window-deletable-p window)))
+ (cond
+ ((eq deletable 'frame)
+ ;; Delete frame.
+ (delete-frame (window-frame window)))
+ (deletable
+ ;; Delete window only.
+ (delete-window window))
+ (t
+ ;; In window switch to previous buffer.
+ (set-window-dedicated-p window nil)
+ (switch-to-prev-buffer window 'bury))))
+ ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
+ (unrecord-window-buffer window buffer)))))
+
+(defun replace-buffer-in-windows (&optional buffer-or-name)
+ "Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
+BUFFER-OR-NAME may be a buffer or the name of an existing buffer
+and defaults to the current buffer.
+
+When a window showing BUFFER-OR-NAME is either dedicated, or the
+window has no previous buffer, that window is deleted. If that
+window is the only window on its frame, the frame is deleted too
+when there are other frames left. If there are no other frames
+left, some other buffer is displayed in that window.
+
+This function removes the buffer denoted by BUFFER-OR-NAME from
+all window-local buffer lists."
+ (let ((buffer (normalize-live-buffer buffer-or-name)))
+ (dolist (window (window-list-1 nil nil t))
+ (if (eq (window-buffer window) buffer)
+ (let ((deletable (window-deletable-p window)))
+ (cond
+ ((eq deletable 'frame)
+ ;; Delete frame.
+ (delete-frame (window-frame window)))
+ ((and (window-dedicated-p window) deletable)
+ ;; Delete window.
+ (delete-window window))
+ (t
+ ;; Switch to another buffer in window.
+ (set-window-dedicated-p window nil)
+ (switch-to-prev-buffer window 'kill))))
+ ;; Unrecord BUFFER in WINDOW.
+ (unrecord-window-buffer window buffer)))))
+
+(defun quit-restore-window (&optional window kill)
+ "Quit WINDOW in some way.
+WINDOW must be a live window and defaults to the selected window.
+Return nil.
+
+According to information stored in WINDOW's `quit-restore' window
+parameter either \(1) delete WINDOW and its frame, \(2) delete
+WINDOW, \(3) restore the buffer previously displayed in WINDOW,
+or \(4) make WINDOW display some other buffer than the present
+one. If non-nil, reset `quit-restore' parameter to nil.
+
+Optional argument KILL non-nil means in addition kill WINDOW's
+buffer. If KILL is nil, put WINDOW's buffer at the end of the
+buffer list. Interactively, KILL is the prefix argument."
+ (interactive "i\nP")
+ (setq window (normalize-live-window window))
+ (let ((buffer (window-buffer window))
+ (quit-restore (window-parameter window 'quit-restore))
+ deletable resize)
+ (cond
+ ((and (or (and (memq (car-safe quit-restore) '(new-window new-frame))
+ ;; Check that WINDOW's buffer is still the same.
+ (eq (window-buffer window) (nth 1 quit-restore)))
+ (window-dedicated-p window))
+ (setq deletable (window-deletable-p window)))
+ ;; WINDOW can be deleted.
+ (unrecord-buffer buffer)
+ (if (eq deletable 'frame)
+ ;; WINDOW's frame can be deleted.
+ (delete-frame (window-frame window))
+ ;; Just delete WINDOW.
+ (delete-window window))
+ ;; If the previously selected window is still alive, select it.
+ (when (window-live-p (nth 2 quit-restore))
+ (select-window (nth 2 quit-restore))))
+ ((and (buffer-live-p (nth 0 quit-restore))
+ ;; The buffer currently shown in WINDOW must still be the
+ ;; buffer shown when its `quit-restore' parameter was created
+ ;; in the first place.
+ (eq (window-buffer window) (nth 3 quit-restore)))
+ (setq resize (with-current-buffer buffer temp-buffer-resize-mode))
+ ;; Unrecord buffer.
+ (unrecord-buffer buffer)
+ (unrecord-window-buffer window buffer)
+ ;; Display buffer stored in the quit-restore parameter.
+ (set-window-dedicated-p window nil)
+ (set-window-buffer window (nth 0 quit-restore))
+ (set-window-start window (nth 1 quit-restore))
+ (set-window-point window (nth 2 quit-restore))
+ (when (and resize (/= (nth 4 quit-restore) (window-total-size window)))
+ (resize-window
+ window (- (nth 4 quit-restore) (window-total-size window))))
+ ;; Reset the quit-restore parameter.
+ (set-window-parameter window 'quit-restore nil)
+ (when (window-live-p (nth 5 quit-restore))
+ (select-window (nth 5 quit-restore))))
+ (t
+ ;; Otherwise, show another buffer in WINDOW and reset the
+ ;; quit-restore parameter.
+ (set-window-parameter window 'quit-restore nil)
+ (unrecord-buffer buffer)
+ (switch-to-prev-buffer window 'bury-or-kill)))
+
+ ;; Kill WINDOW's old-buffer if requested
+ (when kill (kill-buffer buffer))
+ nil))
\f
;;; Splitting windows.
(defsubst window-split-min-size (&optional horizontal)
(<= (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)))
+ ;; Always copy quit-restore parameter in interactive use.
+ (let ((quit-restore (window-parameter old-window 'quit-restore)))
+ (when quit-restore
+ (set-window-parameter new-window 'quit-restore quit-restore)))
+ new-window))
(defalias 'split-window-vertically 'split-window-above-each-other)
-;; This is to avoid compiler warnings.
-(defvar view-return-to-alist)
-
-(defun split-window-save-restore-data (new-window old-window)
- (with-current-buffer (window-buffer)
- (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-side-by-side (&optional size)
"Split selected window into two windows side by side.
The selected window becomes the left one and gets SIZE columns.
(when (and size (< size 0) (< (- size) window-min-width))
;; `split-window' would not signal an error here.
(error "Size of new window too small"))
- (split-window-save-restore-data (split-window nil size t) old-window)))
+ (setq new-window (split-window nil size t))
+ ;; Always copy quit-restore parameter in interactive use.
+ (let ((quit-restore (window-parameter old-window 'quit-restore)))
+ (when quit-restore
+ (set-window-parameter new-window 'quit-restore quit-restore)))
+ new-window))
(defalias 'split-window-horizontally 'split-window-side-by-side)
\f
(window--even-window-heights window-to-use)
(window--display-buffer-2 buffer window-to-use)))))
+(defun display-buffer-other-frame (buffer)
+ "Display buffer BUFFER in another frame.
+This uses the function `display-buffer' as a subroutine; see
+its documentation for additional customization information."
+ (interactive "BDisplay buffer in other frame: ")
+ (let ((pop-up-frames t)
+ same-window-buffer-names same-window-regexps
+ ;;(old-window (selected-window))
+ new-window)
+ (setq new-window (display-buffer buffer t))
+ ;; This may have been here in order to prevent the new frame from hiding
+ ;; the old frame. But it does more harm than good.
+ ;; Maybe we should call `raise-window' on the old-frame instead? --Stef
+ ;;(lower-frame (window-frame new-window))
+
+ ;; This may have been here in order to make sure the old-frame gets the
+ ;; focus. But not only can it cause an annoying flicker, with some
+ ;; window-managers it just makes the window invisible, with no easy
+ ;; way to recover it. --Stef
+ ;;(make-frame-invisible (window-frame old-window))
+ ;;(make-frame-visible (window-frame old-window))
+ ))
+
(defun pop-to-buffer (buffer-or-name &optional other-window norecord)
"Select buffer BUFFER-OR-NAME in some window, preferably a different one.
BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
;; input focus and is risen.
(select-frame-set-input-focus new-frame))
buffer))
+
+(defun read-buffer-to-switch (prompt)
+ "Read the name of a buffer to switch to, prompting with PROMPT.
+Return the neame of the buffer as a string.
+
+This function is intended for the `switch-to-buffer' family of
+commands since these need to omit the name of the current buffer
+from the list of completions and default values."
+ (let ((rbts-completion-table (internal-complete-buffer-except)))
+ (minibuffer-with-setup-hook
+ (lambda ()
+ (setq minibuffer-completion-table rbts-completion-table)
+ ;; Since rbts-completion-table is built dynamically, we
+ ;; can't just add it to the default value of
+ ;; icomplete-with-completion-tables, so we add it
+ ;; here manually.
+ (if (and (boundp 'icomplete-with-completion-tables)
+ (listp icomplete-with-completion-tables))
+ (set (make-local-variable 'icomplete-with-completion-tables)
+ (cons rbts-completion-table
+ icomplete-with-completion-tables))))
+ (read-buffer prompt (other-buffer (current-buffer))
+ (confirm-nonexistent-file-or-buffer)))))
+
+(defun normalize-buffer-to-switch-to (buffer-or-name)
+ "Normalize BUFFER-OR-NAME argument of buffer switching functions.
+If BUFFER-OR-NAME is nil, return the buffer returned by
+`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
+exists, return that buffer. If no such buffer exists, create a
+buffer with the name BUFFER-OR-NAME and return that buffer."
+ (if buffer-or-name
+ (or (get-buffer buffer-or-name)
+ (let ((buffer (get-buffer-create buffer-or-name)))
+ (set-buffer-major-mode buffer)
+ buffer))
+ (other-buffer)))
+
+(defun switch-to-buffer (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME in the selected window.
+If called interactively, prompt for the buffer name using the
+minibuffer. The variable `confirm-nonexistent-file-or-buffer'
+determines whether to request confirmation before creating a new
+buffer.
+
+BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
+nil. If BUFFER-OR-NAME is a string that does not identify an
+existing buffer, create a buffer with that name. If
+BUFFER-OR-NAME is nil, switch to the buffer returned by
+`other-buffer'.
+
+Optional argument NORECORD non-nil means do not put the buffer
+specified by BUFFER-OR-NAME at the front of the buffer list and
+do not make the window displaying it the most recently selected
+one. Return the buffer switched to.
+
+This function is intended for interactive use only. Lisp
+functions should call `pop-to-buffer-same-window' instead."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer: ")))
+ (let ((buffer (normalize-buffer-to-switch-to buffer-or-name)))
+ (if (and (or (window-minibuffer-p) (eq (window-dedicated-p) t))
+ (not (eq buffer (window-buffer))))
+ ;; Cannot switch to another buffer in a minibuffer or strongly
+ ;; dedicated window that does not show the buffer already. Call
+ ;; `pop-to-buffer' instead.
+ (pop-to-buffer buffer nil norecord)
+ (unless (eq buffer (window-buffer))
+ ;; I'm not sure why we should NOT call `set-window-buffer' here,
+ ;; but let's keep things as they are (otherwise we could always
+ ;; call `pop-to-buffer-same-window' here).
+ (set-window-buffer nil buffer))
+ (unless norecord
+ (select-window (selected-window)))
+ (set-buffer buffer))))
+
+(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
+ "Select the buffer specified by BUFFER-OR-NAME in another window.
+BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
+nil. Return the buffer switched to.
+
+If called interactively, prompt for the buffer name using the
+minibuffer. The variable `confirm-nonexistent-file-or-buffer'
+determines whether to request confirmation before creating a new
+buffer.
+
+If BUFFER-OR-NAME is a string and does not identify an existing
+buffer, create a new buffer with that name. If BUFFER-OR-NAME is
+nil, switch to the buffer returned by `other-buffer'.
+
+Optional second argument NORECORD non-nil means do not put this
+buffer at the front of the list of recently selected ones.
+
+This uses the function `display-buffer' as a subroutine; see its
+documentation for additional customization information."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other window: ")))
+ (let ((pop-up-windows t)
+ same-window-buffer-names same-window-regexps)
+ (pop-to-buffer buffer-or-name t norecord)))
+
+(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
+ "Switch to buffer BUFFER-OR-NAME in another frame.
+BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
+nil. Return the buffer switched to.
+
+If called interactively, prompt for the buffer name using the
+minibuffer. The variable `confirm-nonexistent-file-or-buffer'
+determines whether to request confirmation before creating a new
+buffer.
+
+If BUFFER-OR-NAME is a string and does not identify an existing
+buffer, create a new buffer with that name. If BUFFER-OR-NAME is
+nil, switch to the buffer returned by `other-buffer'.
+
+Optional second arg NORECORD non-nil means do not put this
+buffer at the front of the list of recently selected ones.
+
+This uses the function `display-buffer' as a subroutine; see its
+documentation for additional customization information."
+ (interactive
+ (list (read-buffer-to-switch "Switch to buffer in other frame: ")))
+ (let ((pop-up-frames t)
+ same-window-buffer-names same-window-regexps)
+ (pop-to-buffer buffer-or-name t norecord)))
\f
(defun set-window-text-height (window height)
"Set the height in lines of the text display area of WINDOW to HEIGHT.
(run-hooks 'mouse-leave-buffer-hook))
(select-window window))))
-(defun delete-other-windows-vertically (&optional window)
- "Delete the windows in the same column with WINDOW, but not WINDOW itself.
-This may be a useful alternative binding for \\[delete-other-windows]
- if you often split windows horizontally."
- (interactive)
- (let* ((window (or window (selected-window)))
- (edges (window-edges window))
- (w window) delenda)
- (while (not (eq (setq w (next-window w 1)) window))
- (let ((e (window-edges w)))
- (when (and (= (car e) (car edges))
- (= (caddr e) (caddr edges)))
- (push w delenda))))
- (mapc 'delete-window delenda)))
-
(defun truncated-partial-width-window-p (&optional window)
"Return non-nil if lines in WINDOW are specifically truncated due to its width.
WINDOW defaults to the selected window.
(define-key ctl-x-map "1" 'delete-other-windows)
(define-key ctl-x-map "2" 'split-window-above-each-other)
(define-key ctl-x-map "3" 'split-window-side-by-side)
+(define-key ctl-x-map "o" 'other-window)
(define-key ctl-x-map "^" 'enlarge-window)
(define-key ctl-x-map "}" 'enlarge-window-horizontally)
(define-key ctl-x-map "{" 'shrink-window-horizontally)
+2011-06-11 Martin Rudalics <rudalics@gmx.at>
+
+ * buffer.c: New Lisp objects Qbuffer_list_update_hook and
+ Qclone_number. Remove external declaration of Qdelete_window.
+ (Fbuffer_list): Rewrite doc-string. Minor restructuring of
+ code.
+ (Fget_buffer_create, Fmake_indirect_buffer, Frename_buffer): Run
+ Qbuffer_list_update_hook if allowed.
+ (Fother_buffer): Rewrite doc-string. Major rewrite for new
+ buffer list implementation.
+ (other_buffer_safely): New function.
+ (Fkill_buffer): Replace call to replace_buffer_in_all_windows by
+ calls to replace_buffer_in_windows and
+ replace_buffer_in_windows_safely. Run Qbuffer_list_update_hook
+ if allowed.
+ (record_buffer): Inhibit quitting and rewrite using quittable
+ functions. Run Qbuffer_list_update_hook if allowed.
+ (Frecord_buffer, Funrecord_buffer): New functions.
+ (switch_to_buffer_1, Fswitch_to_buffer): Remove. Move
+ switch-to-buffer to window.el.
+ (bury-buffer): Move to window.el.
+ (Vbuffer_list_update_hook): New variable.
+
+ * lisp.h (other_buffer_safely): Add prototype in buffer.c
+ section.
+
+ * window.h (resize_frame_windows): Move up in code.
+ (Fwindow_frame): Remove EXFUN.
+ (replace_buffer_in_all_windows): Remove prototype.
+ (replace_buffer_in_windows_safely): Add prototype.
+
+ * window.c: Declare Qdelete_window static again. Move down
+ declaration of select_count.
+ (Fnext_window, Fprevious_window): Rewrite doc-strings.
+ (Fother_window): Move to window.el.
+ (window_loop): Remove DELETE_BUFFER_WINDOWS and UNSHOW_BUFFER
+ cases. Add REPLACE_BUFFER_IN_WINDOWS_SAFELY case.
+ (Fdelete_windows_on, Freplace_buffer_in_windows): Move to
+ window.el.
+ (replace_buffer_in_windows): Implement by calling
+ Qreplace_buffer_in_windows.
+ (replace_buffer_in_all_windows): Remove with some functionality
+ moved into replace_buffer_in_windows_safely.
+ (replace_buffer_in_windows_safely): New function.
+ (select_window_norecord, select_frame_norecord): Move in front
+ of run_window_configuration_change_hook. Remove now obsolete
+ declarations.
+ (Fset_window_buffer): Rewrite doc-string. Call
+ Qrecord_window_buffer.
+ (keys_of_window): Move binding for other-window to window.el.
+
2011-06-11 Chong Yidong <cyd@stupidchicken.com>
* dispextern.h (struct image): Replace data member, whose int_val
static Lisp_Object QSFundamental; /* A string "Fundamental" */
static Lisp_Object Qkill_buffer_hook;
+static Lisp_Object Qbuffer_list_update_hook;
static Lisp_Object Qget_file_buffer;
static Lisp_Object Qoverlayp;
Lisp_Object Qpriority, Qbefore_string, Qafter_string;
-static Lisp_Object Qevaporate;
+
+static Lisp_Object Qclone_number, Qevaporate;
Lisp_Object Qmodification_hooks;
Lisp_Object Qinsert_in_front_hooks;
DEFUN ("buffer-list", Fbuffer_list, Sbuffer_list, 0, 1, 0,
doc: /* Return a list of all existing live buffers.
-If the optional arg FRAME is a frame, we return the buffer list
-in the proper order for that frame: the buffers in FRAME's `buffer-list'
-frame parameter come first, followed by the rest of the buffers. */)
+If the optional arg FRAME is a frame, we return the buffer list in the
+proper order for that frame: the buffers show in FRAME come first,
+followed by the rest of the buffers. */)
(Lisp_Object frame)
{
Lisp_Object general;
Lisp_Object args[3];
CHECK_FRAME (frame);
-
framelist = Fcopy_sequence (XFRAME (frame)->buffer_list);
- prevlist = Fnreverse (Fcopy_sequence (XFRAME (frame)->buried_buffer_list));
+ prevlist = Fnreverse (Fcopy_sequence
+ (XFRAME (frame)->buried_buffer_list));
/* Remove from GENERAL any buffer that duplicates one in
FRAMELIST or PREVLIST. */
args[2] = prevlist;
return Fnconc (3, args);
}
-
- return general;
+ else
+ return general;
}
/* Like Fassoc, but use Fstring_equal to compare
/* Put this in the alist of all live buffers. */
XSETBUFFER (buffer, b);
Vbuffer_alist = nconc2 (Vbuffer_alist, Fcons (Fcons (name, buffer), Qnil));
+ /* And run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
/* An error in calling the function here (should someone redefine it)
can lead to infinite regress until you run out of stack. rms
set_buffer_internal_1 (old_b);
}
+ /* Run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
+
return buf;
}
if (NILP (BVAR (current_buffer, filename))
&& !NILP (BVAR (current_buffer, auto_save_file_name)))
call0 (intern ("rename-auto-save-file"));
+
+ /* Run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
+
/* Refetch since that last call may have done GC. */
return BVAR (current_buffer, name);
}
DEFUN ("other-buffer", Fother_buffer, Sother_buffer, 0, 3, 0,
doc: /* Return most recently selected buffer other than BUFFER.
-Buffers not visible in windows are preferred to visible buffers,
-unless optional second argument VISIBLE-OK is non-nil.
-If the optional third argument FRAME is non-nil, use that frame's
-buffer list instead of the selected frame's buffer list.
-If no other buffer exists, the buffer `*scratch*' is returned.
-If BUFFER is omitted or nil, some interesting buffer is returned. */)
+Buffers not visible in windows are preferred to visible buffers, unless
+optional second argument VISIBLE-OK is non-nil. Ignore the argument
+BUFFER unless it denotes a live buffer. If the optional third argument
+FRAME is non-nil, use that frame's buffer list instead of the selected
+frame's buffer list.
+
+The buffer is found by scanning the selected or specified frame's buffer
+list first, followed by the list of all buffers. If no other buffer
+exists, return the buffer `*scratch*' (creating it if necessary). */)
(register Lisp_Object buffer, Lisp_Object visible_ok, Lisp_Object frame)
{
- register Lisp_Object tail, buf, notsogood, tem, pred, add_ons;
- notsogood = Qnil;
+ Lisp_Object Fset_buffer_major_mode (Lisp_Object buffer);
+ Lisp_Object tail, buf, pred;
+ Lisp_Object notsogood = Qnil;
if (NILP (frame))
frame = selected_frame;
CHECK_FRAME (frame);
- tail = Vbuffer_alist;
pred = frame_buffer_predicate (frame);
-
- /* Consider buffers that have been seen in the selected frame
- before other buffers. */
-
- tem = frame_buffer_list (frame);
- add_ons = Qnil;
- while (CONSP (tem))
+ /* Consider buffers that have been seen in the frame first. */
+ tail = XFRAME (frame)->buffer_list;
+ for (; CONSP (tail); tail = XCDR (tail))
{
- if (BUFFERP (XCAR (tem)))
- add_ons = Fcons (Fcons (Qnil, XCAR (tem)), add_ons);
- tem = XCDR (tem);
+ buf = XCAR (tail);
+ if (BUFFERP (buf) && !EQ (buf, buffer)
+ && !NILP (BVAR (XBUFFER (buf), name))
+ && (SREF (BVAR (XBUFFER (buf), name), 0) != ' ')
+ /* If the frame has a buffer_predicate, disregard buffers that
+ don't fit the predicate. */
+ && (NILP (pred) || !NILP (call1 (pred, buf))))
+ {
+ if (!NILP (visible_ok)
+ || NILP (Fget_buffer_window (buf, Qvisible)))
+ return buf;
+ else if (NILP (notsogood))
+ notsogood = buf;
+ }
}
- tail = nconc2 (Fnreverse (add_ons), tail);
+ /* Consider alist of all buffers next. */
+ tail = Vbuffer_alist;
for (; CONSP (tail); tail = XCDR (tail))
{
buf = Fcdr (XCAR (tail));
- if (EQ (buf, buffer))
- continue;
+ if (BUFFERP (buf) && !EQ (buf, buffer)
+ && !NILP (BVAR (XBUFFER (buf), name))
+ && (SREF (BVAR (XBUFFER (buf), name), 0) != ' ')
+ /* If the frame has a buffer_predicate, disregard buffers that
+ don't fit the predicate. */
+ && (NILP (pred) || !NILP (call1 (pred, buf))))
+ {
+ if (!NILP (visible_ok)
+ || NILP (Fget_buffer_window (buf, Qvisible)))
+ return buf;
+ else if (NILP (notsogood))
+ notsogood = buf;
+ }
+ }
+
+ if (!NILP (notsogood))
+ return notsogood;
+ else
+ {
+ buf = Fget_buffer (build_string ("*scratch*"));
if (NILP (buf))
- continue;
- if (NILP (BVAR (XBUFFER (buf), name)))
- continue;
- if (SREF (BVAR (XBUFFER (buf), name), 0) == ' ')
- continue;
- /* If the selected frame has a buffer_predicate,
- disregard buffers that don't fit the predicate. */
- if (!NILP (pred))
{
- tem = call1 (pred, buf);
- if (NILP (tem))
- continue;
+ buf = Fget_buffer_create (build_string ("*scratch*"));
+ Fset_buffer_major_mode (buf);
}
+ return buf;
+ }
+}
- if (NILP (visible_ok))
- tem = Fget_buffer_window (buf, Qvisible);
- else
- tem = Qnil;
- if (NILP (tem))
+/* The following function is a safe variant of Fother_buffer: It doesn't
+ pay attention to any frame-local buffer lists, doesn't care about
+ visibility of buffers, and doesn't evaluate any frame predicates. */
+
+Lisp_Object
+other_buffer_safely (Lisp_Object buffer)
+{
+ Lisp_Object Fset_buffer_major_mode (Lisp_Object buffer);
+ Lisp_Object tail, buf;
+
+ tail = Vbuffer_alist;
+ for (; CONSP (tail); tail = XCDR (tail))
+ {
+ buf = Fcdr (XCAR (tail));
+ if (BUFFERP (buf) && !EQ (buf, buffer)
+ && !NILP (BVAR (XBUFFER (buf), name))
+ && (SREF (BVAR (XBUFFER (buf), name), 0) != ' '))
return buf;
- if (NILP (notsogood))
- notsogood = buf;
}
- if (!NILP (notsogood))
- return notsogood;
+
buf = Fget_buffer (build_string ("*scratch*"));
if (NILP (buf))
{
buf = Fget_buffer_create (build_string ("*scratch*"));
Fset_buffer_major_mode (buf);
}
+
return buf;
}
\f
if (NILP (BVAR (b, name)))
return Qnil;
+ /* These may run Lisp code and into infinite loops (if someone
+ insisted on circular lists) so allow quitting here. */
+ replace_buffer_in_windows (buffer);
+ frames_discard_buffer (buffer);
+
clear_charpos_cache (b);
tem = Vinhibit_quit;
Vinhibit_quit = Qt;
- replace_buffer_in_all_windows (buffer);
+ /* Remove the buffer from the list of all buffers. */
Vbuffer_alist = Fdelq (Frassq (buffer, Vbuffer_alist), Vbuffer_alist);
- frames_discard_buffer (buffer);
+ /* If replace_buffer_in_windows didn't do its job correctly fix that
+ now. */
+ replace_buffer_in_windows_safely (buffer);
Vinhibit_quit = tem;
/* Delete any auto-save file, if we saved it in this session.
UNBLOCK_INPUT;
BVAR (b, undo_list) = Qnil;
+ /* Run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
+
return Qt;
}
\f
-/* Move the assoc for buffer BUF to the front of buffer-alist. Since
- we do this each time BUF is selected visibly, the more recently
- selected buffers are always closer to the front of the list. This
- means that other_buffer is more likely to choose a relevant buffer. */
+/* Move association for BUFFER to the front of buffer (a)lists. Since
+ we do this each time BUFFER is selected visibly, the more recently
+ selected buffers are always closer to the front of those lists. This
+ means that other_buffer is more likely to choose a relevant buffer.
+
+ Note that this moves BUFFER to the front of the buffer lists of the
+ selected frame even if BUFFER is not shown there. If BUFFER is not
+ shown in the selected frame, consider the present behavior a feature.
+ `select-window' gets this right since it shows BUFFER in the selected
+ window when calling us. */
void
-record_buffer (Lisp_Object buf)
+record_buffer (Lisp_Object buffer)
{
- register Lisp_Object list, prev;
- Lisp_Object frame;
- frame = selected_frame;
+ Lisp_Object aelt, link, tem;
+ register struct frame *f = XFRAME (selected_frame);
+ register struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
- prev = Qnil;
- for (list = Vbuffer_alist; CONSP (list); list = XCDR (list))
- {
- if (EQ (XCDR (XCAR (list)), buf))
- break;
- prev = list;
- }
+ CHECK_BUFFER (buffer);
- /* Effectively do Vbuffer_alist = Fdelq (list, Vbuffer_alist);
- we cannot use Fdelq itself here because it allows quitting. */
+ /* Update Vbuffer_alist (we know that it has an entry for BUFFER).
+ Don't allow quitting since this might leave the buffer list in an
+ inconsistent state. */
+ tem = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+ aelt = Frassq (buffer, Vbuffer_alist);
+ link = Fmemq (aelt, Vbuffer_alist);
+ Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
+ XSETCDR (link, Vbuffer_alist);
+ Vbuffer_alist = link;
+ Vinhibit_quit = tem;
- if (NILP (prev))
- Vbuffer_alist = XCDR (Vbuffer_alist);
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
+ /* Update buffer list of selected frame. */
+ f->buffer_list = Fcons (buffer, Fdelq (buffer, f->buffer_list));
+ f->buried_buffer_list = Fdelq (buffer, f->buried_buffer_list);
- XSETCDR (list, Vbuffer_alist);
- Vbuffer_alist = list;
+ /* Run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
+}
- /* Effectively do a delq on buried_buffer_list. */
+DEFUN ("record-buffer", Frecord_buffer, Srecord_buffer, 1, 1, 0,
+ doc: /* Move BUFFER to the front of the buffer list.
+Return BUFFER. */)
+ (Lisp_Object buffer)
+{
+ CHECK_BUFFER (buffer);
- prev = Qnil;
- for (list = XFRAME (frame)->buried_buffer_list; CONSP (list);
- list = XCDR (list))
- {
- if (EQ (XCAR (list), buf))
- {
- if (NILP (prev))
- XFRAME (frame)->buried_buffer_list = XCDR (list);
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
- break;
- }
- prev = list;
- }
+ record_buffer (buffer);
- /* Now move this buffer to the front of frame_buffer_list also. */
+ return buffer;
+}
- prev = Qnil;
- for (list = frame_buffer_list (frame); CONSP (list);
- list = XCDR (list))
- {
- if (EQ (XCAR (list), buf))
- break;
- prev = list;
- }
+ /* Move BUFFER to the end of the buffer (a)lists. Do nothing if the
+ buffer is killed. For the selected frame's buffer list this moves
+ BUFFER to its end even if it was never shown in that frame. If
+ this happens we have a feature, hence `unrecord-buffer' should be
+ called only when BUFFER was shown in the selected frame. */
- /* Effectively do delq. */
+DEFUN ("unrecord-buffer", Funrecord_buffer, Sunrecord_buffer, 1, 1, 0,
+ doc: /* Move BUFFER to the end of the buffer list.
+Return BUFFER. */)
+ (Lisp_Object buffer)
+{
+ Lisp_Object aelt, link, tem;
+ register struct frame *f = XFRAME (selected_frame);
- if (CONSP (list))
- {
- if (NILP (prev))
- set_frame_buffer_list (frame,
- XCDR (frame_buffer_list (frame)));
- else
- XSETCDR (prev, XCDR (XCDR (prev)));
+ CHECK_BUFFER (buffer);
- XSETCDR (list, frame_buffer_list (frame));
- set_frame_buffer_list (frame, list);
- }
- else
- set_frame_buffer_list (frame, Fcons (buf, frame_buffer_list (frame)));
+ /* Update Vbuffer_alist (we know that it has an entry for BUFFER).
+ Don't allow quitting since this might leave the buffer list in an
+ inconsistent state. */
+ tem = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+ aelt = Frassq (buffer, Vbuffer_alist);
+ link = Fmemq (aelt, Vbuffer_alist);
+ Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
+ XSETCDR (link, Qnil);
+ Vbuffer_alist = nconc2 (Vbuffer_alist, link);
+ Vinhibit_quit = tem;
+
+ /* Update buffer lists of selected frame. */
+ f->buffer_list = Fdelq (buffer, f->buffer_list);
+ f->buried_buffer_list = Fcons (buffer, Fdelq (buffer, f->buried_buffer_list));
+
+ /* Run buffer-list-update-hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qbuffer_list_update_hook);
+
+ return buffer;
}
DEFUN ("set-buffer-major-mode", Fset_buffer_major_mode, Sset_buffer_major_mode, 1, 1, 0,
return unbind_to (count, Qnil);
}
-/* Switch to buffer BUFFER in the selected window.
- If NORECORD is non-nil, don't call record_buffer. */
-
-static Lisp_Object
-switch_to_buffer_1 (Lisp_Object buffer_or_name, Lisp_Object norecord)
-{
- register Lisp_Object buffer;
-
- if (NILP (buffer_or_name))
- buffer = Fother_buffer (Fcurrent_buffer (), Qnil, Qnil);
- else
- {
- buffer = Fget_buffer (buffer_or_name);
- if (NILP (buffer))
- {
- buffer = Fget_buffer_create (buffer_or_name);
- Fset_buffer_major_mode (buffer);
- }
- }
- Fset_buffer (buffer);
- if (NILP (norecord))
- record_buffer (buffer);
-
- Fset_window_buffer (EQ (selected_window, minibuf_window)
- ? Fnext_window (minibuf_window, Qnil, Qnil)
- : selected_window,
- buffer, Qnil);
-
- return buffer;
-}
-
-DEFUN ("switch-to-buffer", Fswitch_to_buffer, Sswitch_to_buffer, 1, 2,
- "(list (read-buffer-to-switch \"Switch to buffer: \"))",
- doc: /* Make BUFFER-OR-NAME current and display it in selected window.
-BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
-nil. Return the buffer switched to.
-
-If BUFFER-OR-NAME is a string and does not identify an existing
-buffer, create a new buffer with that name. Interactively, if
-`confirm-nonexistent-file-or-buffer' is non-nil, request
-confirmation before creating a new buffer. If BUFFER-OR-NAME is
-nil, switch to buffer returned by `other-buffer'.
-
-Optional second arg NORECORD non-nil means do not put this buffer
-at the front of the list of recently selected ones. This
-function returns the buffer it switched to as a Lisp object.
-
-If the selected window is the minibuffer window or dedicated to
-its buffer, use `pop-to-buffer' for displaying the buffer.
-
-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. */)
- (Lisp_Object buffer_or_name, Lisp_Object norecord)
-{
- if (EQ (buffer_or_name, Fwindow_buffer (selected_window)))
- {
- /* Basically a NOP. Avoid signalling an error in the case where
- the selected window is dedicated, or a minibuffer. */
-
- /* But do put this buffer at the front of the buffer list, unless
- that has been inhibited. Note that even if BUFFER-OR-NAME is
- at the front of the main buffer-list already, we still want to
- move it to the front of the frame's buffer list. */
- if (NILP (norecord))
- record_buffer (buffer_or_name);
- return Fset_buffer (buffer_or_name);
- }
- else if (EQ (minibuf_window, selected_window)
- /* If `dedicated' is neither nil nor t, it means it's
- dedicatedness can be overridden by an explicit request
- such as a call to switch-to-buffer. */
- || EQ (Fwindow_dedicated_p (selected_window), Qt))
- /* We can't use the selected window so let `pop-to-buffer' try some
- other window. */
- return call3 (intern ("pop-to-buffer"), buffer_or_name, Qnil, norecord);
- else
- return switch_to_buffer_1 (buffer_or_name, norecord);
-}
-
DEFUN ("current-buffer", Fcurrent_buffer, Scurrent_buffer, 0, 0, 0,
doc: /* Return the current buffer as a Lisp object. */)
(void)
xsignal1 (Qbuffer_read_only, Fcurrent_buffer ());
return Qnil;
}
-
-extern Lisp_Object Qdelete_window;
-
-DEFUN ("bury-buffer", Fbury_buffer, Sbury_buffer, 0, 1, "",
- doc: /* Put BUFFER-OR-NAME at the end of the list of all buffers.
-There it is the least likely candidate for `other-buffer' to return;
-thus, the least likely buffer for \\[switch-to-buffer] to select by
-default.
-
-The argument may be a buffer name or an actual buffer object. If
-BUFFER-OR-NAME is nil or omitted, bury the current buffer and remove it
-from the selected window if it is displayed there. If the selected
-window is dedicated to its buffer, delete that window if there are other
-windows on the same frame. If the selected window is the only window on
-its frame, iconify that frame. */)
- (register Lisp_Object buffer_or_name)
-{
- Lisp_Object buffer;
-
- /* Figure out what buffer we're going to bury. */
- if (NILP (buffer_or_name))
- {
- Lisp_Object tem;
- XSETBUFFER (buffer, current_buffer);
-
- tem = Fwindow_buffer (selected_window);
- /* If we're burying the current buffer, unshow it. */
- if (EQ (buffer, tem))
- {
- if (NILP (Fwindow_dedicated_p (selected_window)))
- Fswitch_to_buffer (Fother_buffer (buffer, Qnil, Qnil), Qnil);
- else if (NILP (XWINDOW (selected_window)->parent))
- Ficonify_frame (Fwindow_frame (selected_window));
- else
- call1 (Qdelete_window, selected_window);
- }
- }
- else
- {
- buffer = Fget_buffer (buffer_or_name);
- if (NILP (buffer))
- nsberror (buffer_or_name);
- }
-
- /* Move buffer to the end of the buffer list. Do nothing if the
- buffer is killed. */
- if (!NILP (BVAR (XBUFFER (buffer), name)))
- {
- Lisp_Object aelt, list;
-
- aelt = Frassq (buffer, Vbuffer_alist);
- list = Fmemq (aelt, Vbuffer_alist);
- Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
- XSETCDR (list, Qnil);
- Vbuffer_alist = nconc2 (Vbuffer_alist, list);
-
- XFRAME (selected_frame)->buffer_list
- = Fdelq (buffer, XFRAME (selected_frame)->buffer_list);
- XFRAME (selected_frame)->buried_buffer_list
- = Fcons (buffer, Fdelq (buffer, XFRAME (selected_frame)->buried_buffer_list));
- }
-
- return Qnil;
-}
\f
DEFUN ("erase-buffer", Ferase_buffer, Serase_buffer, 0, 0, "*",
doc: /* Delete the entire contents of the current buffer.
Qchange_major_mode_hook = intern_c_string ("change-major-mode-hook");
staticpro (&Qchange_major_mode_hook);
+ DEFVAR_LISP ("buffer-list-update-hook", Vbuffer_list_update_hook,
+ doc: /* Hook run when the buffer list changes.
+Functions running this hook are `get-buffer-create',
+`make-indirect-buffer', `rename-buffer', `kill-buffer',
+`record-buffer' and `unrecord-buffer'. */);
+ Vbuffer_list_update_hook = Qnil;
+ Qbuffer_list_update_hook = intern_c_string ("buffer-list-update-hook");
+ staticpro (&Qbuffer_list_update_hook);
+
defsubr (&Sbuffer_live_p);
defsubr (&Sbuffer_list);
defsubr (&Sget_buffer);
defsubr (&Sother_buffer);
defsubr (&Sbuffer_enable_undo);
defsubr (&Skill_buffer);
+ defsubr (&Srecord_buffer);
+ defsubr (&Sunrecord_buffer);
defsubr (&Sset_buffer_major_mode);
- defsubr (&Sswitch_to_buffer);
defsubr (&Scurrent_buffer);
defsubr (&Sset_buffer);
defsubr (&Sbarf_if_buffer_read_only);
- defsubr (&Sbury_buffer);
defsubr (&Serase_buffer);
defsubr (&Sbuffer_swap_text);
defsubr (&Sset_buffer_multibyte);
EXFUN (Fbarf_if_buffer_read_only, 0);
EXFUN (Fcurrent_buffer, 0);
EXFUN (Fother_buffer, 3);
+extern Lisp_Object other_buffer_safely (Lisp_Object);
EXFUN (Foverlay_get, 2);
EXFUN (Fbuffer_modified_p, 1);
EXFUN (Fset_buffer_modified_p, 1);
#include "nsterm.h"
#endif
-Lisp_Object Qwindowp, Qwindow_live_p, Qdelete_window;
+Lisp_Object Qwindowp, Qwindow_live_p;
static Lisp_Object Qwindow_configuration_p, Qrecord_window_buffer;
-static Lisp_Object Qwindow_deletable_p, Qdisplay_buffer;
+static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer;
static Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window;
static Lisp_Object Qresize_root_window, Qresize_root_window_vertically;
static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command;
return selected_window;
}
+int window_select_count;
+
/* If select_window is called with inhibit_point_swap non-zero it will
not store point of the old selected window's buffer back into that
window's pointm slot. This is needed by Fset_window_configuration to
DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
doc: /* Return window following WINDOW in cyclic ordering of windows.
-WINDOW defaults to the selected window. The optional arguments
-MINIBUF and ALL-FRAMES specify the set of windows to consider.
-
-MINIBUF t means consider the minibuffer window even if the
-minibuffer is not active. MINIBUF nil or omitted means consider
-the minibuffer window only if the minibuffer is active. Any
-other value means do not consider the minibuffer window even if
-the minibuffer is active.
-
-Several frames may share a single minibuffer; if the minibuffer
-is active, all windows on all frames that share that minibuffer
-are considered too. Therefore, if you are using a separate
-minibuffer frame and the minibuffer is active and MINIBUF says it
-counts, `next-window' considers the windows in the frame from
-which you entered the minibuffer, as well as the minibuffer
-window.
+WINDOW must be a live window and defaults to the selected one. The
+optional arguments MINIBUF and ALL-FRAMES specify the set of windows to
+consider.
+
+MINIBUF nil or omitted means consider the minibuffer window only if the
+minibuffer is active. MINIBUF t means consider the minibuffer window
+even if the minibuffer is not active. Any other value means do not
+consider the minibuffer window even if the minibuffer is active.
+
+ALL-FRAMES nil or omitted means consider all windows on WINDOW's frame,
+plus the minibuffer window if specified by the MINIBUF argument. If the
+minibuffer counts, consider all windows on all frames that share that
+minibuffer too. The following non-nil values of ALL-FRAMES have special
+meanings:
+
+- t means consider all windows on all existing frames.
+
+- `visible' means consider all windows on all visible frames.
+
+- 0 (the number zero) means consider all windows on all visible and
+ iconified frames.
+
+- A frame means consider all windows on that frame only.
-ALL-FRAMES nil or omitted means consider all windows on WINDOW's
- frame, plus the minibuffer window if specified by the MINIBUF
- argument, see above. If the minibuffer counts, consider all
- windows on all frames that share that minibuffer too.
-ALL-FRAMES t means consider all windows on all existing frames.
-ALL-FRAMES `visible' means consider all windows on all visible
- frames on the current terminal.
-ALL-FRAMES 0 means consider all windows on all visible and
- iconified frames on the current terminal.
-ALL-FRAMES a frame means consider all windows on that frame only.
Anything else means consider all windows on WINDOW's frame and no
- others.
+others.
If you use consistent values for MINIBUF and ALL-FRAMES, you can use
`next-window' to iterate through the entire cycle of acceptable
DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
doc: /* Return window preceding WINDOW in cyclic ordering of windows.
-WINDOW defaults to the selected window. The optional arguments
-MINIBUF and ALL-FRAMES specify the set of windows to consider.
-For the precise meaning of these arguments see `next-window'.
+WINDOW must be a live window and defaults to the selected one. The
+optional arguments MINIBUF and ALL-FRAMES specify the set of windows to
+consider.
+
+MINIBUF nil or omitted means consider the minibuffer window only if the
+minibuffer is active. MINIBUF t means consider the minibuffer window
+even if the minibuffer is not active. Any other value means do not
+consider the minibuffer window even if the minibuffer is active.
+
+ALL-FRAMES nil or omitted means consider all windows on WINDOW's frame,
+plus the minibuffer window if specified by the MINIBUF argument. If the
+minibuffer counts, consider all windows on all frames that share that
+minibuffer too. The following non-nil values of ALL-FRAMES have special
+meanings:
+
+- t means consider all windows on all existing frames.
+
+- `visible' means consider all windows on all visible frames.
+
+- 0 (the number zero) means consider all windows on all visible and
+ iconified frames.
+
+- A frame means consider all windows on that frame only.
+
+Anything else means consider all windows on WINDOW's frame and no
+others.
If you use consistent values for MINIBUF and ALL-FRAMES, you can
use `previous-window' to iterate through the entire cycle of
}
-DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
- doc: /* Select another window in cyclic ordering of windows.
-COUNT specifies the number of windows to skip, starting with the
-selected window, before making the selection. If COUNT is
-positive, skip COUNT windows forwards. If COUNT is negative,
-skip -COUNT windows backwards. COUNT zero means do not skip any
-window, so select the selected window. In an interactive call,
-COUNT is the numeric prefix argument. Return nil.
-
-This function uses `next-window' for finding the window to select.
-The argument ALL-FRAMES has the same meaning as in `next-window',
-but the MINIBUF argument of `next-window' is always effectively
-nil. */)
- (Lisp_Object count, Lisp_Object all_frames)
-{
- Lisp_Object window;
- int i;
-
- CHECK_NUMBER (count);
- window = selected_window;
-
- for (i = XINT (count); i > 0; --i)
- window = Fnext_window (window, Qnil, all_frames);
- for (; i < 0; ++i)
- window = Fprevious_window (window, Qnil, all_frames);
-
- Fselect_window (window, Qnil);
- return Qnil;
-}
-
-
/* Return a list of windows in cyclic ordering. Arguments are like
for `next-window'. */
enum window_loop
{
WINDOW_LOOP_UNUSED,
- GET_BUFFER_WINDOW, /* Arg is buffer */
- DELETE_BUFFER_WINDOWS, /* Arg is buffer */
- UNSHOW_BUFFER, /* Arg is buffer */
- REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
+ GET_BUFFER_WINDOW, /* Arg is buffer */
+ REPLACE_BUFFER_IN_WINDOWS_SAFELY, /* Arg is buffer */
+ REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
CHECK_ALL_WINDOWS
};
window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frames)
{
Lisp_Object window, windows, best_window, frame_arg;
+ int frame_best_window_flag = 0;
struct frame *f;
struct gcpro gcpro1;
is visible, since Fwindow_list skips non-visible frames if
that is desired, under the control of frame_arg. */
if (!MINI_WINDOW_P (w)
- /* For UNSHOW_BUFFER, we must always consider all windows. */
- || type == UNSHOW_BUFFER
+ /* For REPLACE_BUFFER_IN_WINDOWS_SAFELY, we must always
+ consider all windows. */
+ || type == REPLACE_BUFFER_IN_WINDOWS_SAFELY
|| (mini && minibuf_level > 0))
switch (type)
{
case GET_BUFFER_WINDOW:
if (EQ (w->buffer, obj)
- /* Don't find any minibuffer window
- except the one that is currently in use. */
- && (MINI_WINDOW_P (w)
- ? EQ (window, minibuf_window)
- : 1))
+ /* Don't find any minibuffer window except the one that
+ is currently in use. */
+ && (MINI_WINDOW_P (w) ? EQ (window, minibuf_window) : 1))
{
- if (NILP (best_window))
- best_window = window;
- else if (EQ (window, selected_window))
- /* Prefer to return selected-window. */
+ if (EQ (window, selected_window))
+ /* Preferably return the selected window. */
RETURN_UNGCPRO (window);
- else if (EQ (Fwindow_frame (window), selected_frame))
- /* Prefer windows on the current frame. */
- best_window = window;
- }
- break;
-
- case DELETE_BUFFER_WINDOWS:
- if (EQ (w->buffer, obj))
- {
- struct frame *fr = XFRAME (WINDOW_FRAME (w));
-
- /* If this window is dedicated, and in a frame of its own,
- kill the frame. */
- if (EQ (window, FRAME_ROOT_WINDOW (fr))
- && !NILP (w->dedicated)
- && other_visible_frames (fr))
- {
- /* Skip the other windows on this frame.
- There might be one, the minibuffer! */
- while (CONSP (XCDR (windows))
- && EQ (XWINDOW (XCAR (windows))->frame,
- XWINDOW (XCAR (XCDR (windows)))->frame))
- windows = XCDR (windows);
-
- /* Now we can safely delete the frame. */
- delete_frame (w->frame, Qnil);
- }
- else if (NILP (w->parent))
+ else if (EQ (XWINDOW (window)->frame, selected_frame)
+ && !frame_best_window_flag)
+ /* Prefer windows on the current frame (but don't
+ choose another one if we have one already). */
{
- /* If we're deleting the buffer displayed in the
- only window on the frame, find a new buffer to
- display there. */
- Lisp_Object buffer;
- buffer = Fother_buffer (obj, Qnil, w->frame);
- /* Reset dedicated state of window. */
- w->dedicated = Qnil;
- Fset_window_buffer (window, buffer, Qnil);
- if (EQ (window, selected_window))
- Fset_buffer (w->buffer);
+ best_window = window;
+ frame_best_window_flag = 1;
}
- else
- call1 (Qdelete_window, window);
+ else if (NILP (best_window))
+ best_window = window;
}
break;
- case UNSHOW_BUFFER:
+ case REPLACE_BUFFER_IN_WINDOWS_SAFELY:
+ /* We could simply check whether the buffer shown by window
+ is live, and show another buffer in case it isn't. */
if (EQ (w->buffer, obj))
{
- Lisp_Object buffer;
- struct frame *fr = XFRAME (w->frame);
-
- /* Find another buffer to show in this window. */
- buffer = Fother_buffer (obj, Qnil, w->frame);
-
- /* If this window is dedicated, and in a frame of its own,
- kill the frame. */
- if (EQ (window, FRAME_ROOT_WINDOW (fr))
- && !NILP (w->dedicated)
- && other_visible_frames (fr))
- {
- /* Skip the other windows on this frame.
- There might be one, the minibuffer! */
- while (CONSP (XCDR (windows))
- && EQ (XWINDOW (XCAR (windows))->frame,
- XWINDOW (XCAR (XCDR (windows)))->frame))
- windows = XCDR (windows);
-
- /* Now we can safely delete the frame. */
- delete_frame (w->frame, Qnil);
- }
- else if (!NILP (w->dedicated) && !NILP (w->parent))
- {
- Lisp_Object window_to_delete;
- XSETWINDOW (window_to_delete, w);
- /* If this window is dedicated and not the only window
- in its frame, then kill it. */
- call1 (Qdelete_window, window_to_delete);
- }
- else
- {
- /* Otherwise show a different buffer in the window. */
- w->dedicated = Qnil;
- Fset_window_buffer (window, buffer, Qnil);
- if (EQ (window, selected_window))
- Fset_buffer (w->buffer);
- }
+ /* Undedicate WINDOW. */
+ w->dedicated = Qnil;
+ /* Make WINDOW show the buffer returned by
+ other_buffer_safely, don't run any hooks. */
+ set_window_buffer
+ (window, other_buffer_safely (w->buffer), 0, 0);
+ /* If WINDOW is the selected window, make its buffer
+ current. But do so only if the window shows the
+ current buffer (Bug#6454). */
+ if (EQ (window, selected_window)
+ && XBUFFER (w->buffer) == current_buffer)
+ Fset_buffer (w->buffer);
}
break;
}
-DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
- 0, 2, "bDelete windows on (buffer): ",
- doc: /* Delete all windows showing BUFFER-OR-NAME.
-BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
-defaults to the current buffer.
-
-Optional second argument FRAME controls which frames are affected.
-If optional argument FRAME is `visible', search all visible frames.
-If FRAME is 0, search all visible and iconified frames.
-If FRAME is nil, search all frames.
-If FRAME is t, search only the selected frame.
-If FRAME is a frame, search only that frame.
-When a window showing BUFFER-OR-NAME is dedicated and the only window of
-its frame, that frame is deleted when there are other frames left. */)
- (Lisp_Object buffer_or_name, Lisp_Object frame)
+void
+replace_buffer_in_windows (Lisp_Object buffer)
{
- Lisp_Object buffer;
-
- /* FRAME uses t and nil to mean the opposite of what window_loop
- expects. */
- if (NILP (frame))
- frame = Qt;
- else if (EQ (frame, Qt))
- frame = Qnil;
-
- if (NILP (buffer_or_name))
- buffer = Fcurrent_buffer ();
- else
- {
- buffer = Fget_buffer (buffer_or_name);
- CHECK_BUFFER (buffer);
- }
-
- window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
-
- return Qnil;
+ call1 (Qreplace_buffer_in_windows, buffer);
}
-DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
- Sreplace_buffer_in_windows,
- 0, 1, "bReplace buffer in windows: ",
- doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
-BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
-defaults to the current buffer.
-
-When a window showing BUFFER-OR-NAME is dedicated that window is
-deleted. If that window is the only window on its frame, that frame is
-deleted too when there are other frames left. If there are no other
-frames left, some other buffer is displayed in that window. */)
- (Lisp_Object buffer_or_name)
-{
- Lisp_Object buffer;
-
- if (NILP (buffer_or_name))
- buffer = Fcurrent_buffer ();
- else
- {
- buffer = Fget_buffer (buffer_or_name);
- CHECK_BUFFER (buffer);
- }
-
- window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
-
- return Qnil;
-}
-/* Replace BUFFER with some other buffer in all windows
- of all frames, even those on other keyboards. */
+/* Safely replace BUFFER with some other buffer in all windows of all
+ frames, even those on other keyboards. */
void
-replace_buffer_in_all_windows (Lisp_Object buffer)
+replace_buffer_in_windows_safely (Lisp_Object buffer)
{
Lisp_Object tail, frame;
- /* A single call to window_loop won't do the job
- because it only considers frames on the current keyboard.
- So loop manually over frames, and handle each one. */
+ /* A single call to window_loop won't do the job because it only
+ considers frames on the current keyboard. So loop manually over
+ frames, and handle each one. */
FOR_EACH_FRAME (tail, frame)
- window_loop (UNSHOW_BUFFER, buffer, 1, frame);
+ window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
}
\f
/* If *ROWS or *COLS are too small a size for FRAME, set them to the
return 1;
}
\f
-int window_select_count;
-
static Lisp_Object Fset_window_margins (Lisp_Object, Lisp_Object, Lisp_Object);
static Lisp_Object Fset_window_fringes (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object);
Lisp_Object, Lisp_Object);
static Lisp_Object Fset_window_vscroll (Lisp_Object, Lisp_Object, Lisp_Object);
+/* The following three routines are needed for running a window's
+ configuration change hook. */
static void
run_funs (Lisp_Object funs)
{
call0 (XCAR (funs));
}
-static Lisp_Object select_window_norecord (Lisp_Object window);
-static Lisp_Object select_frame_norecord (Lisp_Object frame);
+static Lisp_Object
+select_window_norecord (Lisp_Object window)
+{
+ return WINDOW_LIVE_P (window)
+ ? Fselect_window (window, Qt) : selected_window;
+}
+
+static Lisp_Object
+select_frame_norecord (Lisp_Object frame)
+{
+ return FRAME_LIVE_P (XFRAME (frame))
+ ? Fselect_frame (frame, Qt) : selected_frame;
+}
void
run_window_configuration_change_hook (struct frame *f)
DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
-WINDOW defaults to the selected window. BUFFER-OR-NAME must be a buffer
-or the name of an existing buffer. Optional third argument KEEP-MARGINS
-non-nil means that WINDOW's current display margins, fringe widths, and
-scroll bar settings are preserved; the default is to reset these from
-the local settings for BUFFER-OR-NAME or the frame defaults. Return nil.
+WINDOW has to be a live window and defaults to the selected one.
+BUFFER-OR-NAME must be a buffer or the name of an existing buffer.
+
+Optional third argument KEEP-MARGINS non-nil means that WINDOW's current
+display margins, fringe widths, and scroll bar settings are preserved;
+the default is to reset these from the local settings for BUFFER-OR-NAME
+or the frame defaults. Return nil.
This function throws an error when WINDOW is strongly dedicated to its
buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
else if (!EQ (tem, Qt))
/* w->buffer is t when the window is first being set up. */
{
- if (EQ (tem, buffer))
- return Qnil;
- else if (EQ (w->dedicated, Qt))
- error ("Window is dedicated to `%s'", SDATA (BVAR (XBUFFER (tem), name)));
- else
- w->dedicated = Qnil;
+ if (!EQ (tem, buffer))
+ {
+ if (EQ (w->dedicated, Qt))
+ /* WINDOW is strongly dedicated to its buffer, signal an
+ error. */
+ error ("Window is dedicated to `%s'", SDATA (BVAR (XBUFFER (tem), name)));
+ else
+ /* WINDOW is weakly dedicated to its buffer, reset
+ dedicatedness. */
+ w->dedicated = Qnil;
+
+ call1 (Qrecord_window_buffer, window);
+ }
unshow_buffer (w);
}
set_window_buffer (window, buffer, 1, !NILP (keep_margins));
- return Qnil;
-}
-static Lisp_Object
-select_window_norecord (Lisp_Object window)
-{
- return WINDOW_LIVE_P (window)
- ? Fselect_window (window, Qt) : selected_window;
-}
-
-static Lisp_Object
-select_frame_norecord (Lisp_Object frame)
-{
- return FRAME_LIVE_P (XFRAME (frame))
- ? Fselect_frame (frame, Qt) : selected_frame;
+ return Qnil;
}
\f
static Lisp_Object
DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0,
doc: /* Split window OLD.
Second argument TOTAL-SIZE specifies the number of lines or columns of the
-new window. In any case TOTAL-SIZE must be a positive integer
+new window. In any case TOTAL-SIZE must be a positive integer.
Third argument SIDE nil (or `below') specifies that the new window shall
be located below WINDOW. SIDE `above' means the new window shall be
else error ("Failed to resize minibuffer window");
}
\f
-\f
/* Mark window cursors off for all windows in the window tree rooted
at W by setting their phys_cursor_on_p flag to zero. Called from
xterm.c, e.g. when a frame is cleared and thereby all cursors on
return Qnil;
}
-
DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
0, 1, 0,
doc: /* Return the height in lines of the text display area of WINDOW.
defsubr (&Sset_window_display_table);
defsubr (&Snext_window);
defsubr (&Sprevious_window);
- defsubr (&Sother_window);
defsubr (&Sget_buffer_window);
- defsubr (&Sdelete_windows_on);
- defsubr (&Sreplace_buffer_in_windows);
defsubr (&Sdelete_other_windows_internal);
defsubr (&Sdelete_window_internal);
defsubr (&Sresize_mini_window_internal);
void
keys_of_window (void)
{
- initial_define_key (control_x_map, 'o', "other-window");
initial_define_key (control_x_map, '<', "scroll-left");
initial_define_key (control_x_map, '>', "scroll-right");
extern Lisp_Object window_from_coordinates (struct frame *, int, int,
enum window_part *, int);
EXFUN (Fwindow_dedicated_p, 1);
+extern void resize_frame_windows (struct frame *, int, int);
extern void delete_all_subwindows (Lisp_Object);
extern void freeze_window_starts (struct frame *, int);
extern void grow_mini_window (struct window *, int);
extern Lisp_Object Vwindow_list;
EXFUN (Fwindow_buffer, 1);
-EXFUN (Fwindow_frame, 1);
EXFUN (Fget_buffer_window, 2);
EXFUN (Fwindow_minibuffer_p, 1);
EXFUN (Fselected_window, 0);
extern int window_body_cols (struct window *w);
EXFUN (Frecenter, 1);
extern void temp_output_buffer_show (Lisp_Object);
-extern void replace_buffer_in_all_windows (Lisp_Object);
+extern void replace_buffer_in_windows_safely (Lisp_Object);
extern void init_window_once (void);
extern void init_window (void);
extern void syms_of_window (void);
extern void keys_of_window (void);
-extern void resize_frame_windows (struct frame *, int, int);
-
#endif /* not WINDOW_H_INCLUDED */