From 7d5ffe8af8348bf1b3ff888816f2517ee4aa345e Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Tue, 16 Nov 2021 15:10:41 +0000 Subject: [PATCH] Undelete deleted frames. * lisp/frame.el (undelete-frame): New command. (undeleted-frame--save-deleted-frame): New auxiliary function. (undelete-frame--deleted-frames): New auxiliary variable. (make-frame-command): Add a prefix argument, and call the new command. * lisp/menu-bar.el (menu-bar-file-menu): Add an entry for the new command. * doc/emacs/frames.tex (Creating Frames, Frame Commands): Document the new command. * etc/NEWS: Document the new command. See bug#51883. --- doc/emacs/frames.texi | 11 ++++++--- etc/NEWS | 10 ++++++++ lisp/frame.el | 56 +++++++++++++++++++++++++++++++++++++++---- lisp/menu-bar.el | 4 ++++ 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi index c14ada2957..f5ede6af5e 100644 --- a/doc/emacs/frames.texi +++ b/doc/emacs/frames.texi @@ -452,8 +452,11 @@ Creating Frames @item C-x 5 2 @kindex C-x 5 2 @findex make-frame-command -Create a new frame using the default frame parameters -(@code{make-frame-command}). +Create a new frame using the default frame parameters, or, with a prefix +argument, undelete one of the 16 most recently deleted frames +(@code{make-frame-command}). A prefix argument undeletes the last deleted +frame, a numerical prefix argument between 0 and 15 undeletes the +corresponding deleted frame, where 0 is the most recently deleted frame. @item C-x 5 c @kindex C-x 5 c @@ -510,7 +513,9 @@ Frame Commands @kindex C-x 5 0 @findex delete-frame Delete the selected frame (@code{delete-frame}). This signals an -error if there is only one frame. +error if there is only one frame. The 16 most recently deleted frames +can be undeleted with the @kbd{C-x 5 2} command, when it is used with +a prefix argument. @item C-z @kindex C-z @r{(X windows)} diff --git a/etc/NEWS b/etc/NEWS index 312fc18f4f..ab47f8cf5b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -130,6 +130,16 @@ For example, a 'display-buffer-alist' entry of will make the body of the chosen window 40 columns wide. For the height use 'window-height' in combination with 'body-lines'. +--- +** Frames + ++++ +*** With a prefix argument, the key 'C-x 5 2' undeletes deleted frames. +The 16 most recently deleted frames can be undeleted. A prefix argument +undeletes the last deleted frame, a numerical prefix argument between 0 +and 15 undeletes the corresponding deleted frame, where 0 is the most +recently deleted frame. + ** Better detection of text suspiciously reordered on display. The function 'bidi-find-overridden-directionality' has been extended to detect reordering effects produced by embeddings and isolates diff --git a/lisp/frame.el b/lisp/frame.el index 2c73737a54..2085397b30 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -775,16 +775,23 @@ close-display-connection (mapc #'delete-frame frames) (x-close-connection display)))) -(defun make-frame-command () +(defun make-frame-command (&optional arg) "Make a new frame, on the same terminal as the selected frame. If the terminal is a text-only terminal, this also selects the new frame. +With a prefix argument ARG, undelete the most recently deleted +frame. +With a numerical prefix argument ARG between 0 and 15, undelete +the ARGth deleted frame, where 0 is most recently deleted frame. + When called from Lisp, returns the new frame." - (interactive) - (if (display-graphic-p) - (make-frame) - (select-frame (make-frame)))) + (interactive "P") + (if arg + (undelete-frame arg) + (if (display-graphic-p) + (make-frame) + (select-frame (make-frame))))) (defun clone-frame (&optional frame no-windows) "Make a new frame with the same parameters and windows as FRAME. @@ -2484,6 +2491,45 @@ delete-other-frames (if iconify (iconify-frame this) (delete-frame this))) (setq this next)))) +(eval-when-compile (require 'frameset)) + +(defvar undelete-frame--deleted-frames nil + "Internal variable used by `undelete-frame--save-deleted-frame'.") + +(defun undeleted-frame--save-deleted-frame (frame) + "Save the configuration of frames deleted with `delete-frame'. +Only the 16 most recently deleted frames are saved." + (when (frame-live-p frame) + (setq undelete-frame--deleted-frames + (cons (cons + (display-graphic-p) + (frameset-save (list frame))) + undelete-frame--deleted-frames)) + (if (> (length undelete-frame--deleted-frames) 16) + (setq undelete-frame--deleted-frames + (butlast undelete-frame--deleted-frames))))) + +(add-hook 'delete-frame-functions #'undeleted-frame--save-deleted-frame) + +(defun undelete-frame (&optional arg) + "Undelete a frame deleted with `delete-frame'. +When ARG is nil or a list, the last deleted frame is undeleted. +When ARG is a number between 0 and 15, the ARGth deleted frame is +undeleted. +When called from Lisp, returns the new frame." + (interactive "P") + (let* ((frames (frame-list)) + (n (if (listp arg) 0 arg)) + (frameset (nth n undelete-frame--deleted-frames))) + (when (and frameset + (eq (display-graphic-p) (car frameset))) + (setq undelete-frame--deleted-frames + (delq frameset undelete-frame--deleted-frames)) + (frameset-restore (cdr frameset)) + (let ((frame (car (seq-difference (frame-list) frames)))) + (when frame + (select-frame-set-input-focus frame) + frame))))) ;;; Window dividers. (defgroup window-divider nil diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 1a81f1a3d0..a1e0195bb5 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -109,6 +109,10 @@ menu-bar-file-menu (bindings--define-key menu [separator-tab] menu-bar-separator)) + (bindings--define-key menu [undelete-last-deleted-frame] + '(menu-item "Undelete Frame" undelete-frame + :help "Undelete last deleted frame")) + ;; Don't use delete-frame as event name because that is a special ;; event. (bindings--define-key menu [delete-this-frame] -- 2.33.0