GSettings : Utiliser un schéma

Quelques pistes pour charger un objet GSettings dans une application Gnome 3, en python ou en javascript.

Présentation

Nous partirons d'une application « myapp » possédant un dossier « data » contenant lui-même un dossier « schema » dans lequel nous stockerons les schémas GSettings.

  • myapp
    • data
Organisation de l'application de test.

Création du schéma

GSettings se base sur l'utilisation d'un schéma de configuration au format xml :

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
    <schema path="/org/myapp/" id="org.myapp">
        <key name="boolkey" type="b">
            <default>true</default>
            <summary>A boolean configuration key.</summary>
            <description>...</description>
        </key>
        <key name="strkey" type="s">
            <default>"string"</default>
            <summary>A string configuration key.</summary>
            <description>...</description>
        </key>
        <key name="intkey" type="i">
            <default>25</default>
            <range min="0" max="100" />
            <summary>A integer configuration key.</summary>
            <description>...</description>
        </key>
        <key name="choicekey" type="s">
            <choices>
                <choice value="choice 1"/>
                <choice value="choice 2"/>
            </choices>
            <default>"choice 1"</default>
            <summary>A choice configuration key.</summary>
        </key>
    </schema>
</schemalist>
Schéma de configuration GSettings de notre application.

La documentation de GSettings fournit la DTD de ce type de fichier qui est structuré autour d'une liste d'éléments key représentant des données de configuration. Chaque clé doit être définie par :

  • Un attribut type correspondant à son type.
  • Un attribut name pour l'identifier.
  • Un élément default pour spécifier sa valeur par défaut.

Chaque clé peut aussi contenir les éléments suivants :

  • sumamry : courte définition de la clé.
  • description : description de la clé.

Ces fichiers de schémas doivent avoir un nom qui se termine par « gschema.xml ». Ils ne sont utilisés que sous forme compilée, compilation qui s'effectue grâce au programme glib-compile-schemas.

  • myapp
    • data
      • schema
        • org.myapp.gschema.xml
Insertion d'un schéma dans l'application.

Compilation du schéma

Compilation au niveau du système

La documentation Gnome précise que les schémas compilés doivent être placés dans un des répertoires système de données (XDG_DATA_DIRS)(1) pour pouvoir être lus, GSettings ne pouvant pas les lire dans le répertoire local de données propre à l'utilisateur (XDG_DATA_HOME)(2). C'est un problème si on souhaite l'utiliser pour développer un plugin Gedit ou une extension Gnome-shell par exemple : l'utilisateur devra copier le fichier xml et le compiler dans un répertoire système avec les droits administrateurs :

# Se loguer en root
su -

# Copier le schéma dans le répretoire système adéquat
cp path/to/myapp/data/schema/org.myapp.gschema.xml /usr/share/glib-2.0/schemas/

# (Re)compiler les schémas GSettings.
glib-compile-schemas /usr/share/glib-2.0/schemas/
Copie et compilation d'un schéma dans /usr/share/glib-2.0/schemas/.

Compilation embarquée

Cette manipulation est une véritable regression par rapport à GConf. On peut cependant l'éviter en compilant le schéma à l'endroit où il se trouve :

glib-compile-schemas path/to/myapp/data/schema/
Compilation du schéma en « embarqué ».

La commande glib-compile-schemas va créer un fichier de compilation nommé « gschemas.compiled ».

  • myapp
    • data
      • schema
        • gschemas.compiled
        • org.myapp.gschema.xml
Embarquement de la compilation du schéma dans l'application.

Compilation locale

Comme expliqué plus haut, GSettings n'est pas capable de lire des schémas de configuration déployés en local dans ~/.local/share/glib-2.0/schemas/. En fait, cela n'est pas tout à fait vrai, cela grâce à la variable d'environnement GSETTINGS_SCHEMA_DIR :

GSETTINGS_SCHEMA_DIR. This variable can be set to the name of a directory that is considered in addition to the glib-2.0/schemas subdirectories of the XDG system data dirs when looking for compiled schemas for GSettings.

Running GIO applications

Cependant, pour pouvoir utiliser GSETTINGS_SCHEMA_DIR, il faut que l'utilisateur la définisse lui-même car elle ne l'est pas par défaut - du moins sous Fedora 17, définition à effectuer dans le fichier .profile par exemple :

# GSettings local dir
GSETTINGS_SCHEMA_DIR=$HOME/.local/share/glib-2.0/schemas/
export GSETTINGS_SCHEMA_DIR
Définition de GSETTINGS_SCHEMA_DIR dans ~/.profile.

Il faudra ensuite copier le schéma de configuration dans ce répertoire et lancer sa compilation :

import os

def schema_to_local(schema_file):
    '''
    Copier et compiler un schéma GSettings dans le répertoire local
    @param schema_dir: chemin du schéma
    @return: True si la compilation a été effectuée, False sinon.
    '''
    local_schema_dir = os.environ.get('GSETTINGS_SCHEMA_DIR')
    if local_schema_dir is not None:
        cmd_copy = 'cp ' schema_file + ' ' + local_schema_dir
        cmd_compil = 'glib-compile-schemas ' + local_schema_dir
        os.system(cmd_copy)
        os.system(cmd_compil)
        
        return True
        
    return False
Copie et compilation du schéma dans le répertoire local (python).
# Copier et compiler un schéma Gsettings local.
# param $1: chemin du schéma
schema_to_local() {
    if [[ $1 ]]; then
        if [[ $GSETTINGS_SCHEMA_DIR ]]; then
            cp $1 $GSETTINGS_SCHEMA_DIR
            glib-compile-schemas $GSETTINGS_SCHEMA_DIR
        else
            echo "GSETTINGS_SCHEMA_DIR is not defined"
        fi
    fi
}
Copie et compilation du schéma dans le répertoire local (bash).

Obliger l'utilisateur à définir une variable d'environnement pour avoir à disposition la configuration d'un plugin Gedit ou d'une extension gnome-shell est tout de même contraignant, moins que de devoir installer des fichiers avec des droits administrateurs mais contraignant tout de même. La compilation dans le plugin reste donc la solution la plus acceptable, en attendant que GSETTINGS_SCHEMA_DIR soit définie par les systèmes d'exploitation.

Chargement du schéma

Nous pouvons maintenant charger un objet Gsettings dans notre code en partant du principe que le schéma à utiliser sera éventuellement installé localement :

from gi.repository import Gio
import os

def get_settings(schema_name, schema_dir = None):
    '''
    Charger un objet de configuration Gio.Settings.
    
    La méthode cherche d'abord si la configuration demandée est chargé globalement.
    Si ce n'est pas le cas, elle tentera de charger un schéma 'local', présent
    dans le répertoire 'schema_dir'.
    
    @param schema_name: Nom du schéma.
    @param schema_dir: répertoire du schéma.
    @return: Gio.Settings ou None
    '''
    schemas = Gio.Settings.list_schemas()
    
    if schema_name in schemas:
        return Gio.Settings.new(schema_name)
    
    if schema_dir is not None and os.path.isdir(schema_dir):
        schema_source = Gio.SettingsSchemaSource.new_from_directory(
            schema_dir, 
            Gio.SettingsSchemaSource.get_default(), 
            False
        )
        schema = schema_source.lookup(schema_name, False)
        
        if schema is not None:
            return Gio.Settings.new_full(schema, None, None)
    
    return None
Lire un schéma GSettings (python).

const Gio = imports.gi.Gio;
/**
 *  Charger un objet de configuration Gio.Settings.
 *  
 *  La méthode cherche d'abord si la configuration demandée est chargé globalement.
 *  Si ce n'est pas le cas, elle tentera de charger un schéma 'local', présent
 *  dans le répertoire 'schema_dir'.
 *  
 *  @param {String} schema_name Nom du schéma.
 *  @param {String} [schema_dir] Répertoire local du schéma.
 *  @return {Gio.Settings|null}
 */
const get_settings = function (schema_name, schema_dir) {
    let schemas = Gio.Settings.list_schemas(),
        schema_source,
        schema;
    
    if (schema_name in schemas) {
        return new Gio.Settings({ settings_schema: schemas[schema_name] });
    }
    
    if (schema_dir) {
        let dir = Gio.File.new_for_path(schema_dir);
        if (!dir.query_exists(null)) {
            return null;
        }
    }
    schema_source = Gio.SettingsSchemaSource.new_from_directory(
        schema_dir,
        Gio.SettingsSchemaSource.get_default(),
        false
    );
    schema = schema_source.lookup(schema_name, false);
    
    if (schema) {
        return new Gio.Settings({ settings_schema: schema });
    }
    
    return null;
}
Lire un schéma GSettings (javascript).

Ressources et références

GIO Reference Manual. Gnome Dev Center. GSettings

GIO Reference Manual. Gnome Dev Center. Running GIO applications

BASTIAN, Waldo ; LORTIE, Ryan ; POETTERING, Lennart. XDG Base Directory Specification. freedesktop.org

GConf Reference Manual. Gnome Dev Center

CARRICK, Micah. Using GSettings with Python/PyGObject. micahcarrick.com,

Extensions. Gnome Live, . Extension Preferences