Subject: Re: bug#51883: 29.0.50; Command to get accidentally deleted frames back

From: Juri Linkov <[email-masked]>
Date: Thu, 27 Jan 2022 19:19:45 +0200

>> -           (seq-remove (lambda (elem) (eq (car elem) 'name))
>> -                       (frame-parameters frame)))
>> +          (seq-remove (lambda (elem)
>> +                        (memq (car elem) '(name window-id outer-window-id parent-id)))
>> +                      (frame-parameters frame)))
>
> Could you move this list into a variable and then use it in
> `frameset.el` when computing `frameset-persistent-filter-alist` (tho
> I suspect they should be in `frameset-session-filter-alist` even they
> currently aren't in there, which might be a bug in `frameset.el`).

Done in this patch (for master):

diff --git a/src/frame.c b/src/frame.c
index 8aaff949ba..b0b9d1184e 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -6495,6 +6495,14 @@ focus (where a frame immediately loses focus when it's left by the mouse
 iconify the top level frame instead.  */);
   iconify_child_frame = Qiconify_top_level;
 
+  DEFVAR_LISP ("frame-internal-parameters", frame_internal_parameters,
+	       doc: /* Frame parameters specific to every frame.  */);
+#ifdef HAVE_X_WINDOWS
+  frame_internal_parameters = list4 (Qname, Qparent_id, Qwindow_id, Qouter_window_id);
+#else
+  frame_internal_parameters = list3 (Qname, Qparent_id, Qwindow_id);
+#endif
+
   defsubr (&Sframep);
   defsubr (&Sframe_live_p);
   defsubr (&Swindow_system);
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 10714af1fa..05884eed3a 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -436,10 +436,11 @@ frameset-prop
 
 ;;;###autoload
 (defvar frameset-session-filter-alist
-  '((name            . :never)
-    (left            . frameset-filter-iconified)
-    (minibuffer      . frameset-filter-minibuffer)
-    (top             . frameset-filter-iconified))
+  (append
+   '((left            . frameset-filter-iconified)
+     (minibuffer      . frameset-filter-minibuffer)
+     (top             . frameset-filter-iconified))
+   (mapcar (lambda (p) (cons p :never)) frame-internal-parameters))
   "Minimum set of parameters to filter for live (on-session) framesets.
 DO NOT MODIFY.  See `frameset-filter-alist' for a full description.")
 
@@ -468,14 +469,11 @@ frameset-persistent-filter-alist
      (GUI:height                  . frameset-filter-unshelve-param)
      (GUI:width                   . frameset-filter-unshelve-param)
      (height                      . frameset-filter-shelve-param)
-     (outer-window-id             . :never)
      (parent-frame                . :never)
-     (parent-id                   . :never)
      (mouse-wheel-frame           . :never)
      (tty                         . frameset-filter-tty-to-GUI)
      (tty-type                    . frameset-filter-tty-to-GUI)
      (width                       . frameset-filter-shelve-param)
-     (window-id                   . :never)
      (window-system               . :never))
    frameset-session-filter-alist)
   "Parameters to filter for persistent framesets.
diff --git a/lisp/frame.el b/lisp/frame.el
index 599ffe591a..d9b21783b9 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -798,8 +798,9 @@ clone-frame
          (windows (unless no-windows
                     (window-state-get (frame-root-window frame))))
          (default-frame-alist
-           (seq-remove (lambda (elem) (eq (car elem) 'name))
-                       (frame-parameters frame)))
+          (seq-remove (lambda (elem)
+                        (memq (car elem) frame-internal-parameters))
+                      (frame-parameters frame)))
          (new-frame (make-frame)))
     (when windows
       (window-state-put windows (frame-root-window new-frame) 'safe))
@@ -2529,8 +2530,6 @@ 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--handle-delete-frame'.")
 
@@ -2540,20 +2539,12 @@ undelete-frame--handle-delete-frame
   (when (frame-live-p frame)
     (setq undelete-frame--deleted-frames
           (cons
-           (cons
+           (list
             (display-graphic-p)
-            (frameset-save
-             (list frame)
-             ;; When the daemon is started from a graphical
-             ;; environment, TTY frames have a 'display' parameter set
-             ;; to the value of $DISPLAY (see the note in
-             ;; `server--on-display-p').  Do not store that parameter
-             ;; in the frameset, otherwise `frameset-restore' attempts
-             ;; to restore a graphical frame.
-             :filters (if (display-graphic-p)
-                          frameset-filter-alist
-                        (cons '(display . :never)
-                              frameset-filter-alist))))
+            (seq-remove (lambda (elem)
+                          (memq (car elem) frame-internal-parameters))
+                       (frame-parameters frame))
+            (window-state-get (frame-root-window frame)))
            undelete-frame--deleted-frames))
     (if (> (length undelete-frame--deleted-frames) 16)
         (setq undelete-frame--deleted-frames
@@ -2583,26 +2574,25 @@ undelete-frame
     (if (consp arg)
         (user-error "Missing deleted frame number argument")
       (let* ((number (pcase arg ('nil 1) ('- -1) (_ arg)))
-             (frames (frame-list))
-             (frameset (nth (1- number) undelete-frame--deleted-frames))
+             (frame-data (nth (1- number) undelete-frame--deleted-frames))
              (graphic (display-graphic-p)))
         (if (not (<= 1 number 16))
             (user-error "%d is not a valid deleted frame number argument"
                         number)
-          (if (not frameset)
+          (if (not frame-data)
               (user-error "No deleted frame with number %d" number)
-            (if (not (eq graphic (car frameset)))
+            (if (not (eq graphic (nth 0 frame-data)))
                 (user-error
                  "Cannot undelete a %s display frame on a %s display"
                  (if graphic "non-graphic" "graphic")
                  (if graphic "graphic" "non-graphic"))
               (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)))))))))
+                    (delq frame-data undelete-frame--deleted-frames))
+              (let* ((default-frame-alist (nth 1 frame-data))
+                     (frame (make-frame)))
+                (window-state-put (nth 2 frame-data) (frame-root-window frame) 'safe)
+                (select-frame-set-input-focus frame)
+                frame))))))))
 
 ;;; Window dividers.
 (defgroup window-divider nil