1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-25 10:47:00 +00:00

Move/add window-buffer-related functions to window.el.

* 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.

* 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.
This commit is contained in:
Martin Rudalics 2011-06-11 11:50:37 +02:00
parent b50691aaaf
commit 9397e56f74
11 changed files with 1164 additions and 707 deletions

View File

@ -1,3 +1,40 @@
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

View File

@ -454,11 +454,6 @@ Major modes that edit things other than ordinary files may change this
(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")

View File

@ -1288,100 +1288,6 @@ return value, which may be passed as the REQUIRE-MATCH arg to
'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.

View File

@ -95,6 +95,7 @@
(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")
@ -156,7 +157,6 @@
(load "language/cham")
(load "indent")
(load "window")
(load "frame")
(load "term/tty-colors")
(load "font-core")

View File

@ -52,60 +52,6 @@ wait this many seconds after Emacs becomes idle before doing an update."
(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)))
;;; next-error support framework

View File

@ -2078,6 +2078,74 @@ WINDOW can be any window and defaults to the selected window."
"Return non-nil if WINDOW is the root window of its frame."
(eq window (frame-root-window window)))
(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)
@ -2285,6 +2353,518 @@ window signal an error."
(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))
;;; Splitting windows.
(defsubst window-split-min-size (&optional horizontal)
@ -2569,22 +3149,14 @@ window."
(<= (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.
@ -2603,7 +3175,12 @@ The selected window remains selected. Return the new window."
(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)
@ -3545,6 +4122,29 @@ consider all visible or iconified frames on the current terminal."
(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
@ -3587,6 +4187,130 @@ at the front of the list of recently selected ones."
;; 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)))
(defun set-window-text-height (window height)
"Set the height in lines of the text display area of WINDOW to HEIGHT.
@ -4258,21 +4982,6 @@ active. This function is run by `mouse-autoselect-window-timer'."
(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.
@ -4293,6 +5002,7 @@ Otherwise, consult the value of `truncate-partial-width-windows'
(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)

View File

@ -1,3 +1,54 @@
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

View File

@ -131,13 +131,15 @@ static Lisp_Object Qprotected_field;
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;
@ -171,9 +173,9 @@ Value is nil if OBJECT is not a buffer or if it has been killed. */)
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;
@ -185,9 +187,9 @@ frame parameter come first, followed by the rest of the buffers. */)
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. */
@ -209,7 +211,7 @@ frame parameter come first, followed by the rest of the buffers. */)
args[2] = prevlist;
return Fnconc (3, args);
}
else
return general;
}
@ -384,6 +386,9 @@ even if it is dead. The return value is never nil. */)
/* 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
@ -659,6 +664,10 @@ CLONE nil means the indirect buffer's state is reset to default values. */)
set_buffer_internal_1 (old_b);
}
/* Run buffer-list-update-hook. */
if (!NILP (Vrun_hooks))
call1 (Vrun_hooks, Qbuffer_list_update_hook);
return buf;
}
@ -1262,75 +1271,82 @@ This does not change the name of the visited file (if any). */)
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 (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))
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))))
{
tem = call1 (pred, buf);
if (NILP (tem))
continue;
}
if (NILP (visible_ok))
tem = Fget_buffer_window (buf, Qvisible);
else
tem = Qnil;
if (NILP (tem))
if (!NILP (visible_ok)
|| NILP (Fget_buffer_window (buf, Qvisible)))
return buf;
if (NILP (notsogood))
else if (NILP (notsogood))
notsogood = buf;
}
}
if (!NILP (notsogood))
return notsogood;
else
{
buf = Fget_buffer (build_string ("*scratch*"));
if (NILP (buf))
{
@ -1339,6 +1355,37 @@ If BUFFER is omitted or nil, some interesting buffer is returned. */)
}
return buf;
}
}
/* 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;
}
buf = Fget_buffer (build_string ("*scratch*"));
if (NILP (buf))
{
buf = Fget_buffer_create (build_string ("*scratch*"));
Fset_buffer_major_mode (buf);
}
return buf;
}
DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
0, 1, "",
@ -1509,13 +1556,20 @@ with SIGHUP. */)
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.
@ -1589,83 +1643,103 @@ with SIGHUP. */)
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;
}
/* 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);
/* 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;
/* 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);
/* Run buffer-list-update-hook. */
if (!NILP (Vrun_hooks))
call1 (Vrun_hooks, Qbuffer_list_update_hook);
}
/* Effectively do Vbuffer_alist = Fdelq (list, Vbuffer_alist);
we cannot use Fdelq itself here because it allows quitting. */
if (NILP (prev))
Vbuffer_alist = XCDR (Vbuffer_alist);
else
XSETCDR (prev, XCDR (XCDR (prev)));
XSETCDR (list, Vbuffer_alist);
Vbuffer_alist = list;
/* Effectively do a delq on buried_buffer_list. */
prev = Qnil;
for (list = XFRAME (frame)->buried_buffer_list; CONSP (list);
list = XCDR (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)
{
if (EQ (XCAR (list), buf))
{
if (NILP (prev))
XFRAME (frame)->buried_buffer_list = XCDR (list);
else
XSETCDR (prev, XCDR (XCDR (prev)));
break;
}
prev = list;
CHECK_BUFFER (buffer);
record_buffer (buffer);
return buffer;
}
/* Now move this buffer to the front of frame_buffer_list also. */
/* 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. */
prev = Qnil;
for (list = frame_buffer_list (frame); CONSP (list);
list = XCDR (list))
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)
{
if (EQ (XCAR (list), buf))
break;
prev = list;
}
Lisp_Object aelt, link, tem;
register struct frame *f = XFRAME (selected_frame);
/* Effectively do delq. */
CHECK_BUFFER (buffer);
if (CONSP (list))
{
if (NILP (prev))
set_frame_buffer_list (frame,
XCDR (frame_buffer_list (frame)));
else
XSETCDR (prev, XCDR (XCDR (prev)));
/* 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;
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 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,
@ -1708,86 +1782,6 @@ the current buffer's major mode. */)
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)
@ -1937,70 +1931,6 @@ DEFUN ("barf-if-buffer-read-only", Fbarf_if_buffer_read_only,
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;
}
DEFUN ("erase-buffer", Ferase_buffer, Serase_buffer, 0, 0, "*",
doc: /* Delete the entire contents of the current buffer.
@ -6101,6 +6031,15 @@ The function `kill-all-local-variables' runs this before doing anything else. *
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);
@ -6122,12 +6061,12 @@ The function `kill-all-local-variables' runs this before doing anything else. *
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);

View File

@ -3011,6 +3011,7 @@ extern Lisp_Object set_buffer_if_live (Lisp_Object);
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);

View File

@ -50,9 +50,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#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;
@ -310,6 +310,8 @@ selected windows appears and to which many commands apply. */)
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
@ -2210,33 +2212,30 @@ next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, in
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.
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 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.
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.
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.
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.
@ -2252,9 +2251,32 @@ windows, eventually ending up back at the window you started with.
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
@ -2267,37 +2289,6 @@ reverse order. */)
}
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'. */
@ -2398,8 +2389,7 @@ enum window_loop
{
WINDOW_LOOP_UNUSED,
GET_BUFFER_WINDOW, /* Arg is buffer */
DELETE_BUFFER_WINDOWS, /* Arg is buffer */
UNSHOW_BUFFER, /* Arg is buffer */
REPLACE_BUFFER_IN_WINDOWS_SAFELY, /* Arg is buffer */
REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
CHECK_ALL_WINDOWS
};
@ -2408,6 +2398,7 @@ static Lisp_Object
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;
@ -2457,111 +2448,52 @@ window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frame
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. */
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). */
{
best_window = window;
frame_best_window_flag = 1;
}
else if (NILP (best_window))
best_window = window;
}
break;
case DELETE_BUFFER_WINDOWS:
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))
{
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))
{
/* 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. */
/* Undedicate WINDOW. */
w->dedicated = Qnil;
Fset_window_buffer (window, buffer, Qnil);
if (EQ (window, selected_window))
/* 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);
}
else
call1 (Qdelete_window, window);
}
break;
case UNSHOW_BUFFER:
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);
}
}
break;
case REDISPLAY_BUFFER_WINDOWS:
@ -2875,85 +2807,26 @@ window-start value is reasonable when this function is called. */)
}
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);
call1 (Qreplace_buffer_in_windows, buffer);
}
window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
return Qnil;
}
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);
}
/* If *ROWS or *COLS are too small a size for FRAME, set them to the
@ -3014,8 +2887,6 @@ adjust_window_margins (struct window *w)
return 1;
}
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);
@ -3023,6 +2894,8 @@ static Lisp_Object Fset_window_scroll_bars (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)
{
@ -3031,8 +2904,19 @@ 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)
@ -3209,11 +3093,13 @@ WINDOW can be any window and defaults to the selected one. */)
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
@ -3238,33 +3124,27 @@ This function runs `window-scroll-functions' before running
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))
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;
}
static Lisp_Object
display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p, Lisp_Object override_frame)
@ -3799,7 +3679,7 @@ resize_frame_windows (struct frame *f, int size, int horflag)
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
@ -4280,7 +4160,6 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
else error ("Failed to resize minibuffer window");
}
/* 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
@ -5337,7 +5216,6 @@ and redisplay normally--don't erase and redraw the frame. */)
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.
@ -6865,10 +6743,7 @@ function `window-nest' and altered by the function `set-window-nest'. */);
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);
@ -6917,7 +6792,6 @@ function `window-nest' and altered by the function `set-window-nest'. */);
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");

View File

@ -827,6 +827,7 @@ extern Lisp_Object make_window (void);
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);
@ -902,7 +903,6 @@ extern Lisp_Object Qwindowp, Qwindow_live_p;
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);
@ -918,12 +918,10 @@ extern int window_internal_height (struct window *);
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 */