GConfig Plans and Design

note: these are my design notes of december 2006, when I started working on gconfig design. gconfig is not exactly like this anymore, and only the tenets are the important part. EmmanueleBassi

Design tenets

  • this goes in between glib/gobject and gtk+
  • no more paths
  • object persistence
  • you can have a section of the database, never the entire database
  • reuse the same remote object for the same object path
  • you need a schema
  • you need a schema

  • you don't need a schema file
  • leave the daemon out of the reads
  • leave the client library out of the writes
  • have multiple namespaces
  • have multiple backends
  • leave the schemas out of the database
  • validate everything client-side
  • think of a gconf migration path that doesn't break API (ABI is fine)
  • lockdown policy

Assumptions

  • configuration object path (like D-Bus paths): namespace:/path/to/object

  • preference: attribute of the object at the configuration object path

Low level API

  • GConfigBackend: interface for database backends
    • multiple backends
    • loadable modules
    • each backend has the base path it's been assigned by the user via configuration file
    • each backend has a set, a get, a list preferences and a list paths method, all accepting paths
  • GConfigSource: remote object for database objects
    • remote object
    • loads the backend needed for the namespace+path
    • registers a filter function on the bus
    • holds a counter for the number of factories (proxies) it has
    • if the counter reaches 0, unrefs the backend
  • GConfigFactory: local object for database objects
    • bound to a namespace+path
    • loads the schema object
    • validates data when setting (fails if not valid)
    • validates data when getting (fails if not valid, returns the schema default)
    • changes notification: GSignal "changed" for every change, "changed::preference" for the changes of "preference"
    • multiple factories for the same configuration path map to a single source
  • GConfigSchema: shallow object for a schema (from file, buffer or in-code)
    • can be created from scratch and assigned to a factory
    • can be created from a file or a buffer and assigned to a factory

API usage examples

  • get two preferences from the applications:/org/gnome/Test configuration object:

  GConfigFactory *factory;
  gchar *foo;
  gint bar;

  factory = g_config_get_applications_factory ("/org/gnome/Test", "test.schemas");
  g_config_factory_get (factory, "foo", &foo, "bar", &bar, NULL);
  
  g_object_unref (factory);
  • set a preference of the applications:/org/gnome/Test configuration object, with direct error reporting:

  if (!g_config_factory_set_preference (factory, "bar", new_bar))
    {
      GError *error;
      g_config_factory_get_error (factory, &error);
      g_warning ("Error: %s", error->message);
      g_error_free (error); 
    }
  • set a preference with indirect error reporting:

  static void
  on_error_cb (GConfigFactory *factory,
               const GError   *error,
               gpointer        user_data)
  {
    ...
  }
  ...
  g_signal_connect (factory, "error", G_CALLBACK (on_error_cb), NULL);
  g_config_factory_set (factory, "bar", new_bar, NULL);
  • change notification:

  static void
  on_foo_changed_cb (GConfigFactory *factory,
                     const gchar    *preference, /* "foo" */
                     GConfigSchema  *schema,
                     gpointer        user_data)
  {
    gchar *foo;

    g_config_factory_get (factory, preference, &foo, NULL);
  }
  ...
  g_signal_connect (factory, "changed::foo", G_CALLBACK (on_foo_changed_cb), NULL);

Configuration

  • gconfig resource file (similar to gtkrc, parsed by GScanner)

  • define namespaces, define backends

  namespace "applications" {
    readable = TRUE
    writable = TRUE
    backend "file" {
      base_path "$HOME/.gconfig/applications"
    }
  }

  namespace "system" {
    readable = TRUE
    writable = TRUE
    backend "bdb" {
      base_path "$HOME/.gconfig/system"
    }
  }
  • all the defaults are stored inside schemas files
  • administrators must override a schema, not a value inside the database

  schema "org.gnome.Foo" {
    # override the file containing the schema
    path "/etc/gconfig/local/our-foo"
  }

  schema "org.gnome.Bar" {
    # override a preference - a schema for org.gnome.Bar/baz *must* exist
    preference "baz" {
      type = "int"
      value = 42
    }
  }

Schemas

  • FIXME

Backends

  • current backends: file (keyfile-based), dummy (in-memory table)

Namespaces

  • defined by default:
    • applications - name says it all

    • system - system stuff, like gtk theme, icon theme, UI prefs, etc.

    • session - things that must persist for a session, but can be discarded afterwards (tests, preview settings, etc.)

  • a user/application can add namespaces inside the gconfig resource file and bind them to a backend

Lockdown policy

  • defined per-schema
  • API to ask the daemon to lock an object down (granularity: readable, writable, visible)
    • writable will make any further call for setting a preference for that object fail

    • readable will make any further call for getting a preference for that object fail

    • visible will make any further call for getting a factory for that object fail

  • how do we decide if a lock down request should be honoured?

EmmanueleBassi/GConfig (last edited 2008-02-03 14:44:22 by anonymous)