Subject: bug#79291: bug when using frameset register + tab-bar

From: Juri Linkov <[email-masked]>
Date: Wed, 27 Aug 2025 22:29:42 +0300

>> >> > 09) close other tabs with 'C-x t 1'
>> >> > 10) change window layout with 'C-x 1' and 'C-x <left>'
>> >> > 11) restore frameset with 'C-x r j a'
>> >> > 12) BUG: it shows 03 tabs, must should show only 1
>> >> 
>> >> We need to clarify the semantics of 'C-x r f':
>> >> what it's expected for it to do with tabs?
>> >
>> > Theoretically, tabs are not part of a frameset, so I think the
>> > expectations here are incorrect.
>> 
>> However, for example, in the desktop file tabs are part of a frameset,
>> and tabs are restored by restoring the frameset from the desktop file.
>
> I'm confused: if framesets support tabs and their restoration, then
> why did you say that we need to clarify what "C-x r f" does with tabs?

I don't use "C-x r f" and didn't know what it does,
so needed to look at 'frameset-to-register',
and surprisingly it uses the same 'frameset-save'
that is used by the desktop.  

But the problem is that its filters didn't use 'copy-tree'
for tabs, so any changes in tabs within the current session
also modified the data saved in the register too.

I didn't find a suitable existing filter in 'frameset-filter-params'
that uses 'copy-tree' on saving, so added a new filter ':copy-tree':

diff --git a/lisp/frameset.el b/lisp/frameset.el
index ee30f77c3ba..38b7e3e31a8 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -439,7 +439,8 @@ frameset-session-filter-alist
   (append
    '((left            . frameset-filter-iconified)
      (minibuffer      . frameset-filter-minibuffer)
-     (top             . frameset-filter-iconified))
+     (top             . frameset-filter-iconified)
+     (tabs            . :copy-tree))
    (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.")
@@ -515,6 +516,7 @@ frameset-filter-alist
 parameter), and ACTION can be:
 
  nil       The parameter is copied to FILTERED.
+ :copy-tree The parameter is copied to FILTERED with `copy-tree'.
  :never    The parameter is never copied to FILTERED.
  :save     The parameter is copied only when saving the frame.
  :restore  The parameter is copied only when restoring the frame.
@@ -686,6 +688,8 @@ frameset-filter-params
       (pcase (cdr (assq (car current) filter-alist))
 	('nil
 	 (push (if saving current (copy-tree current)) filtered))
+	(:copy-tree
+	 (push (copy-tree current) filtered))
 	(:never
 	 nil)
 	(:restore