[Usability] writeup of prefs storage plan



Hi,

I just found this in my home directory, I wrote it a while ago and
forgot to mail it off. This is taking into account comments I got last
time I posted on this topic.

I also forgot to implement gnome_client_get_global_id(). I think this
is just:

 const char*
 gnome_client_get_global_id (void)
 {
   return g_getenv ("GNOME_GLOBAL_SESSION_ID");
 }

So, not a big deal. ;-) Well, there's also the matter of having
gnome-session set that env variable, but also not a big deal.

Send more comments. Where should we post the final writeup?

Havoc

Proposal for handling the storage of preferences and session state
using the GNOME platform.

Definitions:

 - application session ID: a globally-unique string identifying an
   application instance. Applications receive their ID from the
   session manager; to get your ID, call gnome_client_get_id().  The
   ID is in Latin-1 encoding. The ID may be NULL, if the app isn't
   connected to a session manager yet. This is specified by the 
   XSMP protocol.

 - session: a collection of application instances, possibly under 
   some user-provided name. For example, user might have "Home" 
   and "Work" sessions. The set of application instances can 
   be saved to disk, and then later restored. That is, each 
   application provides the session manager with a command line 
   to restart the app; the session manager records this information,
   and uses it to restart apps next time you log in.

 - global session ID: a unique string identifying a _session_. The
   global session ID is a GNOME extension, and may not be supported by
   all session managers. Retrieve it using
   gnome_client_get_global_id(). The global session ID is a string
   that all applications in the current session will know about, but
   no applications outside the current session will know about.
   
   Think of the global session ID as a session ID for the current
   instance of the desktop considered as a whole. i.e. pretend GNOME 
   is an application, the global ID is its session ID.

   For robustness, the global session ID for the default session will
   be simply "Default" or the like, and never change. This ensures
   that users who never use named sessions will never lose settings,
   and ensures that users can safely kill off their session files
   without losing settings.

 - profile: a named set of application settings, as in the "terminal 
   class" of gnome-terminal. This makes sense when an app may 
   be used in multiple contexts by the same user, and that user
   may want different settings in each context.
 
How to save data:

 Data can be namespaced in the following ways:

   - by including the application session ID in the data key, 
     the saved data will only apply to one copy of an app

   - by including the global session ID in the data key, the saved
     data will only apply to app instances that are in the session
     with that ID

   - by including no session ID in a data key, the saved data will 
     apply to all app instances in all sessions

 To create a GConf key including a session ID, use the normal prefix
 you would use (according to the key-naming conventions in the GConf
 manual), but append "sessions/SESSIONID" to that prefix.  For
 example, Galeon stores preferences in the /apps/galeon/ directory. It
 would store session state in /apps/galeon/sessions/SESSIONID/
 instead. GNOME stores GNOME-wide preferences in /desktop/gnome/; it
 would store GNOME-wide per-session preferences in
 /desktop/gnome/sessions/GLOBALSESSIONID. Note that SESSIONID must be
 escaped with gconf_escape_key() prior to using it in a GConf key.

 Use a similar rule when storing data in files. For example, you might
 have a file ~/.myappname/sessions/SESSIONID with per-session
 information.

What data to put where:

  . Only settings related to application _instance_ state should be
    stored under the application's session ID. Examples are the
    currently-open windows, what documents are opened in the windows,
    where the cursor is located. Most settings are global preferences, 
    not session state.

  . The window manager stores window positions. Apps need not bother
    to do so.

  . Important or critical data, including preferences that take effort
    to set up, should never be stored per-session. If a user spends a
    lot of time setting up their panel or terminal, they don't want to
    lose that data when changing sessions, or if something goes wrong
    with the session system.  (See implementation notes on this
    topic.) Data such as documents should NEVER go in the
    instance-specific location.

  . User preferences should almost always apply globally to all app
    instances in all sessions. With GConf this can happen without 
    even restarting the app instances.

  . Settings that are per-session, but not associated with a
    particular application instance, should go under the global
    session ID. For example, we might make the desktop background 
    per-session.

  . In no case should the same setting be stored both per-instance and
    globally. This simply makes no sense, and results in a UI that
    makes no sense, and implementation code that makes no sense.  For
    example, if I have a setting "open directories in a new window,"
    that setting cannot be saved per-session sometimes and globally
    some other times. Pick one.

  . Per-session settings should not appear in any prefs dialogs,
    because it's confusing. Prefs dialogs should affect the global
    state of the app.

Implementation notes:

  . There is no real reason why app-instance-specific data needs to be
    in GConf, though it may be convenient and there is nothing wrong
    with it. Storing app-instance-specific data in files is fine,
    because the features of GConf just aren't required.

  . Often you want to allow per-session setups, but setting up an
    application involves noticeable user effort. One suggested
    solution to this problem is to have a "named profile" feature in
    the application. Make the list of profiles, and the contents of
    each profile, a global preference. Make the currently-active
    profile a per-session or per-instance setting. This means that
    only the easy-to-restore "active profile" can be lost if the user
    switches sessions, but the user can still trivially return to the 
    previous setup, i.e. no data is lost.

    A "Default" profile should always exist, for robustness; all
    preferences are stored in the "Default" profile if the user never
    uses the named profile feature.

    Opening a new app instance should always create an instance with 
    the Default profile. i.e. don't do something like open new
    instances with the most-recently-used profile. This leads to 
    a situation where users can't predict which profile a new app 
    instance will have.

    An app with profiles should have a "Preferences" dialog that edits
    whichever profile is active, if the profile includes all
    preferences. However, the prefs dialog should not include an
    option to change the current profile, because that fails to
    emphasize the per-instance nature of the active profile; instead,
    the profile should be chosen from a menu or the like. This also
    allows naive users to ignore the profiles feature, and simply use
    the preferences dialog without seeing it.

    If an app only includes some of its settings in the profile, and
    makes other settings apply to all copies of the app, then the
    settings that always apply should be in the Preferences dialog,
    and the settings that are per-profile should be in a separate
    dialog called something like "Edit Profile." That is, the prefs
    dialog should not be a mixture of a profile editor and
    profile-spanning prefs, because then the user can't tell which
    settings are per-profile.

    Profiles are sort of inherently complicated, so apps that don't
    need them (i.e. most apps) should not have them.

  . We may also have a desktop-wide "profile" feature; this is
    "location management," basically. (As I understand it.)  For
    desktop-wide profiles, the name of the currently-active profile
    (location) would be stored under the global session ID, but the
    list of profiles to choose from would be available in all
    sessions.

  . As mentioned earlier, session IDs are in Latin-1; to display them,
    convert to UTF-8; to use them as a GConf key, use
    gconf_escape_key().

  . gnome_client_get_id () returns the application instance ID

  . gnome_client_get_global_id () returns the global session ID

  . Applications MUST ALWAYS open the same number of windows they
    had open at session save time. If you haven't implemented this, 
    DO NOT connect to the session manager, because you will confuse
    the window manager out of its mind. Call
    gnome_disable_master_client() prior to initializing libgnomeui, 
    until you've implemented SM correctly.

  . When setting the RestartCommand for your app, use 
    the standard --sm-client-id option to pass the current session ID
    to the restarted app.

  . For plain GTK apps, there's a start on a standalone SM library 
    in msm/gsmclient, in CVS; also, twm, metacity, and xclock
    are examples of apps containing SM client code you could look 
    at.

  . If you store session state in GConf, the DiscardCommand should 
    use "gconftool-2" explicitly (not "gconftool") because 
    only gconftool-2 supports the --recursive-delete option 
    for blowing away an entire directory.

How this looks to users:

 Users need not use named sessions, and need not use named
 profiles. Both features will be semi-hidden in the UI. If the
 features are not activated (by creating names other than "Default"),
 then all preferences appear to be global, and when the user saves
 session they can expect the same set of apps to be opened in the same
 positions next time they log in. If the user never saves their
 session, they always get the default apps in the default
 positions. That's all that happens, the user model is very simple (in
 fact no user model is required, stuff just works as expected).

 If named sessions are used, users see this as the ability to save a
 set of currently open apps under some name, to be reopened later.

 If named profiles are used, users see this as a way to "bookmark"
 certain groups of preferences to be restored. Named profiles should
 only be used in a few apps where it really makes sense, for example 
 for gnome-terminal.

Issues/Discussion:

 What terminology and organization do we use when presenting things to
 users? Profiles are the most interesting thing from this standpoint.
 
 One UI for panel profiles might be a "Name this configuration..."
 menu item to create a new profile with the current state, and a
 "Configuration" menu listing all the configurations. This
 could come pre-stocked with "Windows", "CDE", and "Ximian" style
 configs, for example.

     Name This Configuration...
     Current Configuration ->
          Windows 
          CDE
          Ximian

 gnome-terminal could work just the same way:
    
     Name This Configuration...
     Current Configuration ->
          Linux console
          Black-on-white
          37337 E
          xterm

 For panel, there are global prefs that affect panels in all profiles;
 e.g. the global keybindings. Suggestion: put these in the
 Preferences... dialog, and have all per-panel settings in the
 Properties... dialog for a particular panel. Then a profile contains
 the list of current panels, and the properties of those panels. The
 active profile gets saved with the session.

 For gnome-terminal, the Preferences... dialog could just edit the 
 current profile, and all settings are stored per-profile.

 For the panel, nearly everything in the current "Global prefs" dialog
 could actually be per-panel, the line between global and per-panel
 seems pretty random at the moment. If profiles only include per-panel
 state, perhaps some of those global prefs should be moved into the
 per-panel properties dialog.





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