X-0018 設定の変更を自動で反映させる

prefs.js の設定項目や RDF ファイルの内容が変更された場合に、それを自動で感知して処理を行わせる仕組みが、 XPCOM には用意されています。

Preferences Listener

Preferences Listener (というのは正式な名前ではありませんが、 Navigator のソースコード内ではそういう名前で書かれていました)は、指定した名前を含む設定項目が変更された場合に、指定した関数を自動で実行するためのものです。とりあえず、以下のような二つの関数を定義しておいて下さい。

// 監視を開始する
function addPrefListener(aObserver) {
    try {
        var pbi = Components.classes['@mozilla.org/preferences;1'].getService(Components.interfaces.nsIPrefBranchInternal);
        pbi.addObserver(aObserver.domain, aObserver, false);
    } catch(e) {}
}

// 監視を終了する
function removePrefListener(aObserver) {
    try {
        var pbi = Components.classes['@mozilla.org/preferences;1'].getService(Components.interfaces.nsIPrefBranchInternal);
        pbi.removeObserver(aObserver.domain, aObserver);
    } catch(e) {}
}

例えば、ツールバーのボタンの表示・非表示を app.showbutton.button1, app.showbutton.button2 などの設定名で保存しておき、アプリ起動時に設定を見てボタンの表示・非表示を切り替えるようにしていたとしましょう。設定を反映させるのは起動時の一回だけですから、起動中に設定が変更された場合、ボタンの表示は再起動するまで変わりません。これはちょっとマヌケですよね。

こんな時は、以下のような Listener を定義して addPrefListener で登録しておけば OK です。

var buttonPrefListener = {
    domain  : 'app.showbutton',
        //"app.showbutton.XXX"という名前の設定が変更された場合全てで処理を行う

    observe : function(aSubject, aTopic, aPrefstring) {
        if (aTopic == 'nsPref:changed') {
            ...
            // 設定が変更された時の処理
        }
    }
};

addPrefListener(buttonPrefListener); // 登録処理

全てのウィンドウで起動時に Preferences Listener を登録しておけば、他のウィンドウでも自動的に処理が行われます。 Navigator でも実際に、ツールバーのボタンの表示設定を反映する処理に使われています。

RDF DataSource Observer

prefs.js ではなく RDF ファイルに設定を保存している場合は、 RDF DataSource Observer を使います。 Observer はデータソースごとに登録します。

var RDFObserver = {
    onAssert: function (aDataSource, aSource, aProperty, aTarget) {
        // 何らかのデータがデータソースに追加された時
    },

    onUnassert: function (aDataSource, aSource, aProperty, aTarget) {
        // 何らかのデータがデータソースに追加された時
    },

    onChange: function (aDataSource, aSource, aProperty, aOldTarget, aNewTarget) {
        // リソースが変更された時
    },

    onMove: function (aDataSource, aOldSource, aNewSource, aProperty, aTarget) {
        // リソースが移動された時
    },

    beginUpdateBatch: function (aDataSource) {
        // 上記それぞれの処理が始まった時
    },

    endUpdateBatch: function (aDataSource) {
        // 上記それぞれの処理が全て終わった時
    }
};

const RDF = Components.classes['@mozilla.org/rdf/rdf-service;1']
                      .getService(Components.interfaces.nsIRDFService);
var dsource = RDF.GetDataSource('file:///c:/ ... /data.rdf');

dsource.AddObserver(RDFObserver); //監視を開始
// dsource.RemoveObserver(RDFObserver); //監視を終了

これは、 Navigator でも実際に、ブックマークの内容が変更された場合の処理に使われています。