Subject: RE: bug#2249: 23.0.90;default-frame-alist: Invalid function: (menu-bar-lines . 1)

From: "Drew Adams" <[email-masked]>
Date: Tue, 10 Feb 2009 07:44:44 -0800

> From: martin rudalics Sent: Tuesday, February 10, 2009 6:07 AM
>  > 3. Custom buffer shows:
>  >         Default Frame Alist:
>  > 	Parameter: menu-bar-lines
>  > 	            Value: 1
>  > 	Parameter: tool-bar-lines
>  > 	            Value: 1
>  > 	   State: CHANGED outside Customize; operating on it 
>  >            here may be unreliable.
>  >
>  > 4. Click "State" button, select "Show Saved Lisp 
>  >    Expresion".  Custom buffer now shows:
>  > 	default-frame-alist: nil
>  >         State: CHANGED outside Customize; operating on it 
>  >                here may be unreliable. (lisp)
> 
> This is an old issue, see, for example
> http://lists.gnu.org/archive/html/emacs-devel/2000-11/msg00244.html
> http://lists.gnu.org/archive/html/emacs-devel/2007-12/msg01194.html
> 
> `default-frame-alist' really shouldn't be customizable.

Please do not remove `default-frame-alist' as a defcustom, at least not without
providing a reasonable alternative for Customize.

Think, for the moment, of each frame parameter as a user option. If an option is
changed outside Customize, then if you later Customize it you see exactly that:
the new current value and the state of CHANGED outside Customize. If you don't
want Customize changes to override how it gets set outside Customize, then don't
save those changes.

The problem here is that Customize users might not notice that some particular
parameter in the list is something that they don't want to save. Or they might
not know that they can delete it from `default-frame-alist' - they might think
that each frame parameter must be present in the option. Concentrating on some
other parameter in the list, which they just changed using Customize, they save,
and later find out that they also overwrote something they didn't want to.

One partial solution to this might be to refine the display of state - make it
per list entry. If a user saw "CHANGED outside Customize" next to an individual
parameter in the list, that would be a helpful heads-up alert - that is the
purpose of that state message. 

There would remain, however, the problems that (a) a user still might not notice
such a message, if s?he concentrates on some other parameter, and (b) even if
it's noticed, the user might not know what to do - might not know that s?he can
simply delete that parameter from `default-frame-alist'.

Also, I don't know how easy it would be to change Customize to keep track of and
notify changes to individual list elements. I suspect it might not be easy, and
would be tantamount to creating separate options for the individual frame
parameters.

In a way, these problems exist for any collection-valued option, but it is more
likely that they become problems in practice for `default-frame-alist', because
(a) it is useful to customize that option and (b) it can be useful to set
individual frame parameters outside Customize.

A few other things might help here, in addition to pushing the CHANGED state
message into the individual list items: 

1. Spell things out in the doc string of `default-frame-alist' (and similar
vars). Say some of what was just said above. Let users know that they can delete
any parameters from the list - that there will nevertheless be a value for such
a deleted parameter, provided by default.

2. When the user tries to save the option value, for each CHANGED parameter,
make the user decide whether to (a) save the parameter value changed from
outside or (b) drop the parameter from the list. Again, that would require
tracking the state of each parameter individually.

3. Make it possible for commands that change a single frame parameter outside
Customize to also save `default-frame-alist', at least optionally. That would
make it less likely to have "CHANGED" displayed when a user Customizes
`default-frame-alist'. 

The problem for #3 is that such a set-and-save command shouldn't save any other
changed parameters. If another parameter that is already explicitly present in
`default-frame-alist' has also been changed, then when the option is saved by
the command, that parameter must keep its previous value before the change, that
is, keep its saved value. If that parameter was not explicitly present in the
option, then the command should not save it as part of the option (it should be
dropped from the collection before saving).

Another possibility would be to replace the single option `default-frame-alist'
with a set of several separate options. In some ways that would be less
convenient, but it might be easier for users to understand and use. Dunno what
other repercussions there might be.

Another possibility would be to just remove from the option certain parameters
that are most likely to be problematic (e.g. `tool-bar-lines',
`menu-bar-lines'), making only those parameters into separate user options. That
would not solve the problem generally, but it might be a reasonable piecemeal
approach - if the problem later raises its head a lot for some other parameter,
then we could consider converting that parameter too into a separate option.

But there should definitely remain some way to use Customize for the default
frame parameters (either individually or collectively). And the problems
mentioned exist for all collection options - they are just manifested more for
`default-frame-alist' because users have common, simple ways to alter some of
the individual list elements outside Customize without saving them.

Summary: I agree there is a usability problem. I don't favor the "solution" of
simply making `default-frame-parameters' be an internal variable.

This is something that should be discussed carefully in emacs-devel, after the
release. There are likely to be complexities that might not be obvious at first.
(And changes to the basic way of doing things wrt `default-frame-alist' are
likely to necessitate basic change to some existing user and 3rd-party code.)