diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index fe3dc573df5..b6937b7fd48 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -6264,15 +6264,15 @@ Window Configurations @code{minibuffer-selected-window}. In this case, the function returns @code{nil}. Otherwise, it returns @code{t}. -If the buffer of a window of @var{configuration} has been killed since -@var{configuration} was made, that window is, as a rule, removed from -the restored configuration. However, if that window is the last window -remaining in the restored configuration, another live buffer is shown in -it. Also, if the variable @var{window-kept-windows-functions} is -non-@code{nil}, any window whose buffer is now dead is not deleted. -Rather, this function will show another live buffer in that window and -include an entry for that window when calling any function in -@var{window-kept-windows-functions} (@pxref{Window Hooks}). +If this function tries to restore a non-minibuffer window whose buffer +was killed since @var{configuration} was made, it will proceed as +follows: If the abnormal hook @code{window-kept-windows-functions} is +@code{nil} and the window is dedicated to its buffer, it will try to +delete that window. Otherwise, or if it cannot delete the window, it +will show another live buffer in it. + +This function runs the abnormal hook @var{window-kept-windows-functions} +(@pxref{Window Hooks}). Here is a way of using this function to get the same effect as @code{save-window-excursion}: @@ -6361,19 +6361,20 @@ Window Configurations frame before putting @var{state} into it. If @var{window} is @code{nil}, it puts the window state into a new window. -If the buffer of any window recorded in @var{state} has been killed -since @var{state} was made, that window is, as a rule, not restored. -However, if that window is the only window in @var{state}, another live -buffer will be shown in it. Also, if the variable -@var{window-kept-windows-functions} is non-@code{nil}, any window whose -buffer is now dead is restored. This function will show another live -buffer in it and include an entry for that window when calling a -function in @var{window-kept-windows-functions} (@pxref{Window Hooks}). +If this function tries to restore a non-minibuffer window whose buffer +was killed since @var{state} was made, it will proceed as follows: If +the abnormal hook @code{window-kept-windows-functions} is @code{nil} and +the window is dedicated to its buffer, it will try to delete that +window. Otherwise, or if it cannot delete the window, it will show +another live buffer in it. If the optional argument @var{ignore} is non-@code{nil}, it means to ignore minimum window sizes and fixed-size restrictions. If @var{ignore} is @code{safe}, this means windows can get as small as one line and/or two columns. + +This function runs the abnormal hook @var{window-kept-windows-functions} +(@pxref{Window Hooks}). @end defun The functions @code{window-state-get} and @code{window-state-put} also @@ -6641,7 +6642,7 @@ Window Hooks This variable holds a list of functions that Emacs will call after restoring a window configuration via @code{set-window-configuration} or state via @code{window-state-put} (@pxref{Window Configurations}). When -the value of this variable is non-@code{nil}, these functions will not +the value of this variable is non-@code{nil}, these functions will never delete any window whose buffer has been killed since the corresponding configuration or state was saved, but show some live buffer in it. diff --git a/lisp/window.el b/lisp/window.el index 29336f573f8..11ef490ec68 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -6393,7 +6393,9 @@ window--state-put-2 ;; save the window with the intention of deleting it later ;; if possible. (switch-to-prev-buffer window) - (if window-kept-windows-functions + (unless (window-minibuffer-p window) + (cond + (window-kept-windows-functions (let* ((start (cdr (assq 'start state))) ;; Handle both - marker positions from writable ;; states and markers from non-writable states. @@ -6401,12 +6403,14 @@ window--state-put-2 (marker-last-position start) start)) (point (cdr (assq 'point state))) - (point-pos (if (markerp point) - (marker-last-position point) - point))) - (push (list window old-buffer-or-name start-pos point-pos) - window-state-put-kept-windows)) - (push window window-state-put-stale-windows)))))))) + (point-pos (if (markerp point) + (marker-last-position point) + point))) + (push (list window old-buffer-or-name start-pos point-pos) + window-state-put-kept-windows))) + ((window-dedicated-p window) + (push window window-state-put-stale-windows))) + (set-window-dedicated-p window nil)))))))) (defun window-state-put (state &optional window ignore) "Put window state STATE into WINDOW. @@ -6421,16 +6425,22 @@ window-state-put windows can get as small as `window-safe-min-height' and `window-safe-min-width'. -If the abnormal hook `window-kept-windows-functions' is non-nil, -do not delete any windows saved by STATE whose buffers were -deleted since STATE was saved. Rather, show some live buffer in -them and call the functions in `window-kept-windows-functions' -with a list of two arguments: the frame where STATE was put and a -list of entries for each such window. Each entry contains four -elements - the window, its old buffer and the last positions of -`window-start' and `window-point' for the buffer in that window. -Always check the window for liveness because another function run -by this hook may have deleted it." +If this function tries to restore a non-minibuffer window whose buffer +was killed since STATE was made, it will proceed as follows: + +- If the abnormal hook `window-kept-windows-functions' is nil and the + window is dedicated to its buffer, it will try to delete that window. + +- Otherwise, or if it cannot delete the window, it will show another + buffer in it. + +Call the functions in `window-kept-windows-functions' with a list of two +arguments: the frame where STATE was put and a list of entries for each +window whose buffer has been killed since STATE was made. Each entry +contains four elements - the window, its old buffer and the last +positions of `window-start' and `window-point' for the buffer in that +window. Always check the window for liveness because another function +run by this hook may have deleted it." (setq window-state-put-stale-windows nil) (setq window-state-put-kept-windows nil) diff --git a/src/buffer.c b/src/buffer.c index 126f3eb055a..e8daa93c2d9 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -327,6 +327,11 @@ bset_name (struct buffer *b, Lisp_Object val) b->name_ = val; } static void +bset_last_name (struct buffer *b, Lisp_Object val) +{ + b->last_name_ = val; +} +static void bset_overwrite_mode (struct buffer *b, Lisp_Object val) { b->overwrite_mode_ = val; @@ -647,6 +652,7 @@ DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 2, 0, name = Fcopy_sequence (buffer_or_name); set_string_intervals (name, NULL); bset_name (b, name); + bset_last_name (b, name); b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks); bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt); @@ -866,6 +872,7 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, name = Fcopy_sequence (name); set_string_intervals (name, NULL); bset_name (b, name); + bset_last_name (b, name); /* An indirect buffer shares undo list of its base (Bug#18180). */ bset_undo_list (b, BVAR (b->base_buffer, undo_list)); @@ -1282,6 +1289,16 @@ DEFUN ("buffer-name", Fbuffer_name, Sbuffer_name, 0, 1, 0, return BVAR (decode_buffer (buffer), name); } +DEFUN ("buffer-last-name", Fbuffer_last_name, Sbuffer_last_name, 0, 1, 0, + doc: /* Return last name of BUFFER, as a string. +BUFFER defaults to the current buffer. + +This is the last name of BUFFER before it has been renamed or killed. */) + (Lisp_Object buffer) +{ + return BVAR (decode_buffer (buffer), last_name); +} + DEFUN ("buffer-file-name", Fbuffer_file_name, Sbuffer_file_name, 0, 1, 0, doc: /* Return name of file BUFFER is visiting, or nil if none. No argument or nil as argument means use the current buffer. */) @@ -1652,6 +1669,7 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2, (register Lisp_Object newname, Lisp_Object unique) { register Lisp_Object tem, buf; + Lisp_Object oldname = BVAR (current_buffer, name); Lisp_Object requestedname = newname; CHECK_STRING (newname); @@ -1669,12 +1687,12 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2, if (NILP (unique) && XBUFFER (tem) == current_buffer) return BVAR (current_buffer, name); if (!NILP (unique)) - newname = Fgenerate_new_buffer_name (newname, - BVAR (current_buffer, name)); + newname = Fgenerate_new_buffer_name (newname, oldname); else error ("Buffer name `%s' is in use", SDATA (newname)); } + bset_last_name (current_buffer, oldname); bset_name (current_buffer, newname); /* Catch redisplay's attention. Unless we do this, the mode lines for @@ -2087,6 +2105,7 @@ DEFUN ("kill-buffer", Fkill_buffer, Skill_buffer, 0, 1, "bKill buffer: ", This gets rid of them for certain. */ reset_buffer_local_variables (b, 1); + bset_last_name (b, BVAR (b, name)); bset_name (b, Qnil); block_input (); @@ -4658,6 +4677,7 @@ init_buffer_once (void) /* These used to be stuck at 0 by default, but now that the all-zero value means Qnil, we have to initialize them explicitly. */ bset_name (&buffer_local_flags, make_fixnum (0)); + bset_last_name (&buffer_local_flags, make_fixnum (0)); bset_mark (&buffer_local_flags, make_fixnum (0)); bset_local_var_alist (&buffer_local_flags, make_fixnum (0)); bset_keymap (&buffer_local_flags, make_fixnum (0)); @@ -6018,6 +6038,7 @@ Functions (implicitly) running this hook are `get-buffer-create', defsubr (&Smake_indirect_buffer); defsubr (&Sgenerate_new_buffer_name); defsubr (&Sbuffer_name); + defsubr (&Sbuffer_last_name); defsubr (&Sbuffer_file_name); defsubr (&Sbuffer_base_buffer); defsubr (&Sbuffer_local_value); diff --git a/src/buffer.h b/src/buffer.h index 87ba2802b39..bbe1aeff668 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -309,6 +309,9 @@ #define BVAR(buf, field) ((buf)->field ## _) /* The name of this buffer. */ Lisp_Object name_; + /* The last name of this buffer before it was renamed or killed. */ + Lisp_Object last_name_; + /* The name of the file visited in this buffer, or nil. */ Lisp_Object filename_; diff --git a/src/window.c b/src/window.c index ea761fad8bc..c0fadbdff43 100644 --- a/src/window.c +++ b/src/window.c @@ -7109,11 +7109,14 @@ DEFUN ("set-window-configuration", Fset_window_configuration, the mini-window of the frame doesn't get set to the corresponding element of CONFIGURATION. -Normally, this function will try to delete any dead window in -CONFIGURATION whose buffer has been deleted since CONFIGURATION was -made. However, if the abnormal hook `window-kept-windows-functions' is -non-nil, it will preserve such a window in the restored layout and show -another buffer in it. +If this function tries to restore a non-minibuffer window whose buffer +was killed since CONFIGURATION was made, it will proceed as follows: + +- If the abnormal hook `window-kept-windows-functions' is nil and the + window is dedicated to its buffer, it will try to delete that window. + +- Otherwise, or if it cannot delete the window, it will show another + buffer in it. After restoring the frame layout, this function runs the abnormal hook `window-kept-windows-functions' with two arguments - the frame whose @@ -7378,7 +7381,7 @@ DEFUN ("set-window-configuration", Fset_window_configuration, BUF_PT (XBUFFER (w->contents)), BUF_PT_BYTE (XBUFFER (w->contents))); w->start_at_line_beg = true; - if (!NILP (Vwindow_kept_windows_functions)) + if (!NILP (Vwindow_kept_windows_functions) && !MINI_WINDOW_P (w)) kept_windows = Fcons (list4 (window, p->buffer, Fmarker_last_position (p->start), Fmarker_last_position (p->pointm)), @@ -7398,16 +7401,20 @@ DEFUN ("set-window-configuration", Fset_window_configuration, set_marker_restricted_both (w->pointm, w->contents, 0, 0); set_marker_restricted_both (w->old_pointm, w->contents, 0, 0); w->start_at_line_beg = true; - if (!NILP (w->dedicated)) - /* Record this window as dead. */ - dead_windows = Fcons (window, dead_windows); - /* Make sure window is no more dedicated. */ - wset_dedicated (w, Qnil); - if (!NILP (Vwindow_kept_windows_functions)) - kept_windows = Fcons (list4 (window, p->buffer, - Fmarker_last_position (p->start), - Fmarker_last_position (p->pointm)), - kept_windows); + if (!MINI_WINDOW_P (w)) + { + if (!NILP (Vwindow_kept_windows_functions)) + kept_windows + = Fcons (list4 (window, p->buffer, + Fmarker_last_position (p->start), + Fmarker_last_position (p->pointm)), + kept_windows); + else if (!NILP (w->dedicated)) + /* Try to delete this window later. */ + dead_windows = Fcons (window, dead_windows); + /* Make sure window is no more dedicated. */ + wset_dedicated (w, Qnil); + } } } @@ -7459,7 +7466,7 @@ DEFUN ("set-window-configuration", Fset_window_configuration, unblock_input (); /* Scan dead buffer windows. */ - if (!NILP (Vwindow_kept_windows_functions)) + if (NILP (Vwindow_kept_windows_functions)) for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows)) { window = XCAR (dead_windows);