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: /apps/g-t/stuff... /apps/g-t/profiles/ /apps/g-t/profiles/Default/ /apps/g-t/profiles/bigfont/ 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 database. 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 /apps/g-t/profiles/white/ which means that "white" won't show up when we enumerate "/apps/g-t/profiles/". 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. Cheers _______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list