After a window has been deleted (see Deleting Windows) it cannot be used any more by functions that require a valid window as their argument even if some Lisp variable still references that window. When the last reference to a window has ceased to exist, the window’s Lisp object will be eventually recycled by the garbage collector (see Garbage Collection).
There are two ways to resurrect a deleted window whose object has not
been yet recycled by the collector: The first is to keep a reference to
that window in a saved window configuration (see Window Configurations) and then call set-window-configuration with that
configuration as argument. The second one is to keep a reference to
that window in a variable or let-bind it and then use that reference as
refer argument in split-window (see Splitting Windows).
The major difference between these two is that
set-window-configuration restores the frame layout as it existed
before deleting the window. The split-window approach, on the
other hand, allows for arbitrary variations of the layout.
Consider the following example starting with a frame containing a single window showing the buffer *scratch*:
(let* ((old (selected-window))
(new (split-window old nil 'right))
overlay)
(with-current-buffer (get-buffer-create "*Messages*")
(set-window-buffer new (current-buffer))
(setq overlay (make-overlay (point-min) (point-max)))
(overlay-put overlay 'face 'highlight)
(overlay-put overlay 'window new)
(message "new %s parent %s" new (window-parent new))
(sit-for 3))
(delete-window new)
(setq new (split-window old nil 'left))
(set-window-buffer new (get-buffer-create "*Messages*"))
(format "new %s parent %s" new (window-parent new)))
When you run that code in *scratch* it will first split the window showing *scratch* to display *Messages* in a new window on the right. It also sets up an overlay with a window property to highlight the text of *Messages* in the new window and displays a message showing the new window and its parent in the window tree. It then deletes the new window and resurrects it on the left of the *scratch* window again displaying a message showing the new window and its parent in the window tree.
Note that both, new window and its parent have changed after moving the *Messages* window to the left. Also, the highlighting disappears because any properties set up for the new window on the right are lost when the new window is re-created on the left.
The following code uses the refer argument of split-window
instead.
(let* ((old (selected-window))
(new (split-window old nil 'right))
overlay)
(with-current-buffer (get-buffer-create "*Messages*")
(set-window-buffer new (current-buffer))
(setq overlay (make-overlay (point-min) (point-max)))
(overlay-put overlay 'face 'highlight)
(overlay-put overlay 'window new)
(message "new %s parent %s" new (window-parent new))
(sit-for 3))
(delete-window new)
(split-window old nil 'left nil new)
(format "new %s parent %s" new (window-parent new)))
Note that all properties of the resurrected window like its decorations,
parameters as well as any overlays with a window property are preserved
as if that window had never been deleted. The only things that changed
are its position in the window tree and consequently the values returned
by window-left-child of its parent window as well as the values
returned by window-prev-sibling and window-next-sibling of
the window and its sibling.
The following code passes both, the new window on the right and its
parent, via the refer argument to split-window instead.
(let* ((old (selected-window))
(new (split-window old nil 'right))
(parent (window-parent new))
overlay)
(with-current-buffer (get-buffer-create "*Messages*")
(set-window-buffer new (current-buffer))
(setq overlay (make-overlay (point-min) (point-max)))
(overlay-put overlay 'face 'highlight)
(overlay-put overlay 'window new)
(message "new %s parent %s" new (window-parent new))
(sit-for 3))
(delete-window new)
(split-window old nil 'left nil (cons new parent))
(format "new %s parent %s" new (window-parent new)))
Note that the parent window has been resurrected along with the new window.
Resurrecting dead windows is useful to preserve the identity of windows in actions that are supposed to do that like moving windows around on a frame or hiding them temporarily. Any properties of such a window like its decorations, the buffer it has shown previously, that buffer’s start and point position in the window, the window’s dedicated status or its cursor type are left untouched and there’s no need to recreate them from scratch. For internal windows, the value of that window’s combination limit is preserved which means that the window can be recombined (see Recombining Windows) as before.