thoughts on GSettingsList

Hi all,

I've been putting off GSettingsList for a while because of a criticism
that vuntz raised during the hackfest.  It's a fairly valid criticism
that I'll describe here, along with my thoughts for a solution.  This is
a bit of a request for comments and a hopes that the braindumping
process itself will prove to be useful.

If you don't know, GSettingsList is a way to have a list of like-typed
GSettings instances associated with a given parent.  For example, you
could store your list of gnome-terminal profiles or Telepathy accounts
using this mechanism.

The API is something like

   string add_item ();
   void rm_item (string name);
   GSettings get_item (string name);
   string[] list_items ();

If gnome-terminal had its list of profiles and had "Default" and
"bigfont" profiles, the layout in dconf would look something like this:


also, there is a "/apps/g-t/profiles/list" key.  It is a list of
strings: ['Default', 'bigfont'].

What vuntz didn't like (and what I don't like) is that you can remove an
item from the "list" but still have garbage settings left for it in the

Going forward it makes sense (and I would like) to tie the existence of
a item of the list to the result of calling the directory enumeration
API on dconf (ie: it's impossible to have garbage, because if you have
garbage then it's not garbage, but recognised as a valid list item).

The main issue with this is that it goes somewhat against the dynamic
creation/removing of paths that dconf follows.  Consider, for example,
that we create a new profile "white" that has all the default settings
(as per the schema) to start with.  This means that no key in dconf
starts with


which means that "white" won't show up when we enumerate

There are two main solutions here:

   1) change how dconf works to support explicit empty directories.
      There are a lot of reasons that I don't like this, and I guess I
      don't need to explain them.  It's also difficult to express in the
      file format (but definitely not impossible).

   2) Store some sort of "/apps/g-t/profiles/.exists" key.  This is what
      my current line of thinking is (and I guess many people are
      familiar with this hack from some other semi-related uses).

The idea then is that you bring a list item into existence using
".exists" and remove it using the "reset" call that is implemented by
the backend (which is a recursive directory removal).


There are three main unsolved issues here, though.  This system, when
compare with the old one, suffers a major feature regression: it is no
longer possible to permute the order of the items in the list.  I'm not
sure if anyone cares about this.  I used to think it was important, but
I'm happy to abandon/ignore it if nobody complains too loudly.


The second issue is how we deal with seeding the default contents of the
list.  There are a few approaches that can be taken here.

  - null approach: list initially contains zero items.

      - this is very easy, but probably insufficient.

  - better approach: list initially contains one item where the default
    values of that item are taken from the schema for items (ie: the
    default values of the initially-existing item are equal to the
    default values that would be applied to newly created items)

      - maybe a good compromise, but vuntz says he can imagine places
        where this, also, would be insufficient.

  - full-on approach: an arbitrary number of initial items can exist,
    each one with its own set of initial values.

      - quite difficult, i recon, but probably necessary.

Option zero is trivial and insufficient.  For both reasons, I don't
discuss it here.

The other two options have a significant requirement: the ability to
remove the initial items from the list.  Keeping in mind that in the
default state the dconf database is completely empty, we need to build
the list of available items by consulting both the database and the
schema.  How do we store into the database a note that says we should
ignore the information in the schema?

My main idea here is that if we have an item in the schema called
"Default" then we could write a key "/apps/g-t/profiles/.anti-Default".
This would have the effect that listing of the "Default" item based
solely on its existence in the schema would be suppressed.  If the
"Default/" item appeared explicitly in the database then I imagine it
would still appear in the list (ie: in the case that we have "Default/"
and ".anti-Default" both explicitly in the database, then we ignore the
".anti-Default" item).  This furthers the "no garbage" ideal.

This setup of having ".anti-Default" in the profile directory itself
means that we can do a single list operation against the backend to get
all the information that we need in order to tell the user about what's
there.  I dislike the idea of setting ".exists" to false for this reason
but also for the reason that it allows for lingering garbage.


The last issue is related to lockdown.  What sorts of lockdown do we
wish to support?

        (aside) A quick summary of how lockdown works in dconf: first,
        dconf keys are always given with no '/' at the end, and dconf
        directories are always given with a trailing '/'.
        You specify zero or more strings that start with '/' and do not
        contain '//' (ie: you give keys and directories).
        For each key specified, you may not write to that key.
        For each path specified, you may not write to any key under that
        path (recursively).
        I'm not particularly interested in changing this part.

It is clear that we can prevent all changes to the list, its contents
and the contents of the items by locking down /apps/g-t/profiles/.  Can
we do finer-grained locks?

  - prevent removing some of the existing profiles
  - prevent adding some new profiles
  - prevent modification to a specific existing profile

and do some of these things imply others?  For example, preventing
modification to a given profile probably always implies that it can't be
removed either (otherwise you could remove it, replace it, make
modifications to the replacement).

In the case where we want to lock the user into the schema defaults for
one item but allow them to add others, we have two main possibilities
(sysadmins could pick which they prefer):

  1) Create /apps/g-t/profiles/Defaults/.exists and lock all
     of /apps/g-t/profiles/Defaults/ (ie: any user attempt to create an
     anti-Default results in that being ignored by virtue of "Defaults/"
     explicitly existing)

  2) Lock /apps/g-t/profiles/.anti-Default itself in addition to locking
     /apps/g-t/profiles/Default/.  ie: the first one to prevent removes
     and the second to prevent changes.

I like #2 since it allows the UI to mark the "Remove" button insensitive
based on a "is writable?" query against ".anti-Default".

But how do we prevent adding new items without locking everything down
entirely?  Maybe some ".no-new-items" key in "/apps/g-t/profiles/" that
instructs GSettings to ignore any new keys that were added?  The
sysadmin could create and lock this.  Seems like a bit of a hack?

What if the sysadmin wants to add some new default items that are not in
the schema and lock those into existence and prevent the addition of any
others but still allow removals or modifications?
".only-these-new-items" with a list of strings?  Does anybody actually
care about this?

I'm OK with ignoring the lockdown issues in the first-pass at a new
implementation as long as I can feel reasonably confident that I'm not
designing myself into a corner.


Ok.  I lied.  4 items.

During the GSettings hackfest, the schema format underwent some
substantial simplification.  It used to support subclassed schemas
(subclasses could override default values of the parent class).  This
functionality was removed, but will probably need to be brought back to
support the case of multiple initial list items with different default
values (ie: one subclass per initial item).  I very much wonder how that
will work...

So that's it.  Those are the big GSettingsList issues.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]