Subject: RE: bug#14964: 24.3.50; doc of `compare-window-configurations'

From: Drew Adams <[email-masked]>
Date: Sun, 28 Jul 2013 11:56:41 -0700 (PDT)

Let me know if you think I've left something out.

> In particular, according to current-frame-configuration's docstring:
>   Its car is `frame-configuration'.
>   Each element of the cdr is a list of the form (FRAME ALIST WINDOW-CONFIG),
>   where
>     FRAME is a frame object,
>     ALIST is an association list specifying some of FRAME's parameters, and
>     WINDOW-CONFIG is a window configuration object for FRAME."
> 
> - FRAME, as a frame object, can not be serialized to disk. Serializing
> it means serializing its contents and attributes, as I try to do in
> desktop.el.
> - ALIST specifies "some of FRAME's parameters", but it doesn't say
> which ones, or the criteria used to select them, or why these
> parameters are important and not others.
> - WINDOW-CONFIG is also not serializable, but Martin's
> window-state-(get|put) does something similar.
> 
> So, what do you expect of "Lisp-readable frame configurations"?

In brief:

 Tighten it up.  Harmonize the new readable frame & window data
 structures with the existing non-readable frame and window
 configuration structures.  Enable code to use them the same way.

 Offer explicit readable frame and window configs whose contents and
 structure are as compatible as possible with the current, non-readable
 ones.  Some existing code that uses such configs would then just work,
 and future code too would use structures that say what they are.

I don't know which frame parameters are included in ALIST.  What I
would like is that, if possible, those that are included currently in
a non-readable frame config are also included in a readable one.

FRAME itself would have to be dropped (since it is a frame object).
The FRAME is useful only to code that expects a live frame.  Clearly,
if a readable frame config is read then it would be used to either
create a new frame or to try to reuse an existing frame (e.g., in a
new session) that best "fits" the recorded info.

The frame name is anyway among the parameters in ALIST.  I don't think
we can do better than this: drop FRAME - preferably use a placeholder
such a nil for it.  

Except that we might be able to include some frame parameters that
ALIST leaves out, perhaps in the form of a second alist (to separate the
two sets of parameters, so the original set is identifiable, if that
is important).  If we do that then ALIST would hopefully be the same as
for a non-readable frame config.

I don't know which parameters you include now (e.g., for Desktop) that
are not included in ALIST.  I have no idea whether there is any need
for the two sets of recorded parameters (for readable and non-readable)
to be different.  If not, so much the better.

And even if there is a need for them to be different, perhaps there is
no real need to keep ALIST compatible, i.e., having the same set for
readable and non-readable versions.  In that case, all of the frame
parameters that you can represent readably could be included in the
same ALIST argument, and the form of the frame config would be identical.
(The only difference would be the FRAME value - it would be replaced by
nil, for instance.)

> A Lisp readable frame configuration is not very different of a desktop
> frame-state, 

I think you mean that it is not very different from a desktop SET of
frame stateS (plural) - or a state that represents multiple frames.
A frame config represents a set of frames (which could of course be a
singleton set), not just a single frame.

> and any function that serializes it will necessarily do
> something similar to desktop-save-frames (details of output format can
> vary, of course).

Yes, of course.  It's all about factoring and generalizing: the focus
is on representing an arbitrary set of frames, not on saving a desktop.

The form of the result would be similar to the non Lisp-readable frame
config: a list with `frame-configuration' as car, a nil FRAME as cadr
(for example), an ALIST of the traditional or standard frame parameters
(i.e., the same ones), and a readable version of the frame's window
configuration.

That would (if we think it is important to separate these) be followed by
any additional frame parameters that are not recorded for the non
Lisp-readable frame config.  Or alternatively, if it is not important to
keep those separate (identifiable as such), then just include them in
ALIST.  If all recorded frame parameters are in ALIST, then the only
differences from a non-readable frame config are (a) a nil FRAME (or some
other convention for FRAME) and (b) the fact that each component is
readable.

> Which differences are you're interested in? (Other
> than the currrent API of desktop-save-frames being currently not very
> reuse-friendly, I mean.)

See above.  Doing this might also mean that we would want to leverage
it in the desktop.el code at some point - dunno.  In any case, some code
factoring in desktop.el would be helpful anyway, as we've discussed.
It is not the first priority for desktop.el, perhaps, but it will be
good if it is done at some point.

> IIUC, what you would do is, either add parameters to the current
> frame-configuration functions to obtain a serializable config,

Yes, that is what I mentioned: an optional parameter 'WRITABLE, for
instance, similar to what Martin did for `window-state-get'.  (WRITABLE
is actually READABLE, in my book, but either name is OK.)

E.g. (current-frame-configuration t) would return a writable & readable
frame configuration.

> or add a serialize-frame-config function.

That too would be OK, but why bother to first create a non-readable
frame config and then serialize it?  It would be good to have such a
serialize-frame-config function anyway, for cases where you already
have a non-readable frame config.  But I think it would be good for
a function like `current-frame-configuration' to be able to create a
readable config directly too.

> Isn't that more or less what I've been doing?

Not explicitly, IIUC.  The desktop code does not use, and does not
provide for, readable frame configurations.

And the `window-state-*' functions do not explicitly provide for
readable window configurations.  Consider something like this, for
example:

(defun readable-window-config (window-configuration)
  "Return a Lisp-readable representation of WINDOW-CONFIGURATION.
The form is (window-configuration FRAME-NAME . ROOT-WINDOW-STATE)."
  ;; Record the name of the frame and its root window state.
  (let ((winfr  (window-configuration-frame window-configuration)))
    `(window-configuration
      ,(frame-parameter winfr 'name)
      . ,(window-state-get (frame-root-window winfr) 'WRITABLE))))

Just one possibility, as an illustration of what I mean.

> If there is information that frame-configuration saves and
> desktop-save-frames does not, and is information that can be
> meaningfully restored in another Emacs session, we can discuss
> adding it.

I'm not aware of any, and I have not looked.  The point is not
additional info but the form of the packaged info.  The aim for this
would be to provide standard, readable frame and window config
structures.

Using a defstruct would also be OK, but then the form would be even
more different from a (current) non-readable frame config, for
instance.  I would not oppose using a defstruct for both readable
and non-readable.  A defstruct has some advantages.

> > E.g., a frame config would continue to look like this, even when
> > Lisp-readable: (frame-configuration FRAME+WINDOW-CONFIG...)
> >
> > where FRAME+WINDOW-CONFIG would be a Lisp-readable representation
> > of a frame (a set of frame parameters, preferably at least the
> > same ones recorded now) plus the frame's window configuration.
> 
> I see your little trick here ;-)

Well *I* don't see my little trick.  What do you mean?

I just tried to write down more or less what I see in an existing
frame config: it is just that form, no?  Let me know if I'm missing
something here.

> A frame configuration is not the configuration of a frame, but of
> all existing frames.

Yes, but more correctly, of any set of frames.  Yes, it is created by
`current-frame-configuration', which records all existing frames at
the time of invocation.  But it does not necessarily continue to
represent all of the existing frames.

> So a serialized frame configuration would be
> (frame-configuration (FRAME+WINDOW-CONFIG)...)

Sorry, I don't understand that at all.  Why introduce another list
level?  It would be just what I wrote, I think:
(frame-configuration FRAME+WINDOW-CONFIG...)

The only difference would be in the representation of
FRAME+WINDOW-CONFIG.  It would be a readable representation of a
frame, including its window configuration.

> and that's just syntactic sugar over what a desktop frame-state
> currently is: ((FRAME-PARAMS . WINDOW-STATE)...)

Granted, but it is sugar that would let code use the result as it
now uses a non-readable frame config.  That's the point: use frame
configs.

If we need to change something in the definition of a frame config,
so that it includes more or less info than now, then so be it.

But the point is to have a standard structure that code can use and
manipulate.  That is already the case currently, with the exception
that it the structure components are not readable/writable.

You can currently get the frame parameters (those that are recorded) or
the window config from any frame in the config and then do something
with them.  You can even construct a new frame config (assuming you know
which parameters to record): each frame is recorded as just a list of
a frame, (some of) its parameters, and a window config.  You can augment
an existing frame config, adding another frame representation, etc.

Clearly, a defstruct representation might be better, and I don't oppose
that.  But if we did that then it might be nice to create a wrapper
level that enables old code that expects the traditional form (a list)
to continue to work.  A nice-to-have more than a requirement, I guess.

> No, I just want to understand what is being requested. In other
> words, the API that does not exist currently and you'd like to see.

See above for some more info.  In sum, provide aalternative,
Lisp-readable representations of both frame configs and window configs,
and update the functions that use/create such configs to also use/create
the readable form (creating a readable config would be optional via an
optional `WRITABLE parameter).

> > a. these structures documented, i.e., the structure advertised as
> >    such, or
> > b. access functions defined for their parts.
> 
> I'd like to see that, too.
> 
> > IOW, either an open, advertised structure or a black box but
> > providing advertised ways to get at the various components.
> 
> As previously discussed, in private and in my last emacs-devel
> message, I'm open to that but I don't think that providing an API to
> serialize individual frames makes much sense. But ways to make
> desktop-save-frames more open and accesible? Definitely I'm in.

I did not mention serializing individual frames here, AFAIK.  But I'm
actually in favor of that as well, like we do for windows with
`window-state-get' + WRITABLE.  Why not?

(defun readable-frame (frame)
  "Return a Lisp-readable representation of FRAME.
Form is (frame . FRAME-PARAMETERS)."
    `(frame . ,(desktop--filter-frame-parms (frame-parameters frame) t)))

Probably if we did that then we would want to let you specify the
frame parameters to record via one or more parameters to the function
rather than using `desktop--filter-frame-parms' inside the function body.

And for a readable window also, we might want to have a (window...)
structure (list), which would just involve putting a wrapper around
what is already provided by `window-state-get' (with non-nil WRITABLE).

I am not saying that a readable frame config would bother to directly
include such readable individual frame representations, with their
(frame...) wrappers.  I don't see a need for that.  Likewise, for a
readable window config: no need to include (window...) wrappers.

But for manipulating individual readable frames and windows, why not
use such a standard representation, which says what it is.  Easy to
test etc.  (Yes, a defstruct is also a possibility here too, but would
perhaps be overkill.)