/*
* Copyright © 2010 Codethink Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see .
*
* Author: Ryan Lortie
*/
#include "config.h"
#define G_SETTINGS_ENABLE_BACKEND
#include
#include "../engine/dconf-engine.h"
#include
#include
typedef GSettingsBackendClass DConfSettingsBackendClass;
typedef struct
{
GSettingsBackend backend;
DConfEngine *engine;
} DConfSettingsBackend;
static GType dconf_settings_backend_get_type (void);
G_DEFINE_TYPE (DConfSettingsBackend, dconf_settings_backend, G_TYPE_SETTINGS_BACKEND)
static GVariant *
dconf_settings_backend_read (GSettingsBackend *backend,
const gchar *key,
const GVariantType *expected_type,
gboolean default_value)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
return dconf_engine_read (dcsb->engine,
default_value ? DCONF_READ_DEFAULT_VALUE : 0,
NULL, key);
}
static GVariant *
dconf_settings_backend_read_user_value (GSettingsBackend *backend,
const gchar *key,
const GVariantType *expected_type)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
return dconf_engine_read (dcsb->engine, DCONF_READ_USER_VALUE, NULL, key);
}
static gboolean
dconf_settings_backend_write (GSettingsBackend *backend,
const gchar *key,
GVariant *value,
gpointer origin_tag)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
DConfChangeset *change;
gboolean success;
change = dconf_changeset_new ();
dconf_changeset_set (change, key, value);
success = dconf_engine_change_fast (dcsb->engine, change, origin_tag, NULL);
dconf_changeset_unref (change);
return success;
}
static gboolean
dconf_settings_backend_add_to_changeset (gpointer key,
gpointer value,
gpointer data)
{
dconf_changeset_set (data, key, value);
return FALSE;
}
static gboolean
dconf_settings_backend_write_tree (GSettingsBackend *backend,
GTree *tree,
gpointer origin_tag)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
DConfChangeset *change;
gboolean success;
if (g_tree_nnodes (tree) == 0)
return TRUE;
change = dconf_changeset_new ();
g_tree_foreach (tree, dconf_settings_backend_add_to_changeset, change);
success = dconf_engine_change_fast (dcsb->engine, change, origin_tag, NULL);
dconf_changeset_unref (change);
return success;
}
static void
dconf_settings_backend_reset (GSettingsBackend *backend,
const gchar *key,
gpointer origin_tag)
{
dconf_settings_backend_write (backend, key, NULL, origin_tag);
}
static gboolean
dconf_settings_backend_get_writable (GSettingsBackend *backend,
const gchar *name)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
return dconf_engine_is_writable (dcsb->engine, name);
}
static void
dconf_settings_backend_subscribe (GSettingsBackend *backend,
const gchar *name)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
dconf_engine_watch_fast (dcsb->engine, name);
}
static void
dconf_settings_backend_unsubscribe (GSettingsBackend *backend,
const gchar *name)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
dconf_engine_unwatch_fast (dcsb->engine, name);
}
static void
dconf_settings_backend_sync (GSettingsBackend *backend)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
dconf_engine_sync (dcsb->engine);
}
static void
dconf_settings_backend_free_weak_ref (gpointer data)
{
GWeakRef *weak_ref = data;
g_weak_ref_clear (weak_ref);
g_slice_free (GWeakRef, weak_ref);
}
static void
dconf_settings_backend_init (DConfSettingsBackend *dcsb)
{
GWeakRef *weak_ref;
weak_ref = g_slice_new (GWeakRef);
g_weak_ref_init (weak_ref, dcsb);
dcsb->engine = dconf_engine_new (NULL, weak_ref, dconf_settings_backend_free_weak_ref);
}
static void
dconf_settings_backend_finalize (GObject *object)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) object;
dconf_engine_unref (dcsb->engine);
G_OBJECT_CLASS (dconf_settings_backend_parent_class)
->finalize (object);
}
static void
dconf_settings_backend_class_init (GSettingsBackendClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = dconf_settings_backend_finalize;
class->read = dconf_settings_backend_read;
class->read_user_value = dconf_settings_backend_read_user_value;
class->write = dconf_settings_backend_write;
class->write_tree = dconf_settings_backend_write_tree;
class->reset = dconf_settings_backend_reset;
class->get_writable = dconf_settings_backend_get_writable;
class->subscribe = dconf_settings_backend_subscribe;
class->unsubscribe = dconf_settings_backend_unsubscribe;
class->sync = dconf_settings_backend_sync;
}
void
g_io_module_load (GIOModule *module)
{
g_type_module_use (G_TYPE_MODULE (module));
g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
dconf_settings_backend_get_type (),
"dconf", 100);
}
void
g_io_module_unload (GIOModule *module)
{
g_assert_not_reached ();
}
gchar **
g_io_module_query (void)
{
return g_strsplit (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, "!", 0);
}
void
dconf_engine_change_notify (DConfEngine *engine,
const gchar *prefix,
const gchar * const *changes,
const gchar *tag,
gboolean is_writability,
gpointer origin_tag,
gpointer user_data)
{
GWeakRef *weak_ref = user_data;
DConfSettingsBackend *dcsb;
dcsb = g_weak_ref_get (weak_ref);
if (dcsb == NULL)
return;
if (changes[0] == NULL)
return;
if (is_writability)
{
/* We know that the engine does it this way... */
g_assert (changes[0][0] == '\0' && changes[1] == NULL);
if (g_str_has_suffix (prefix, "/"))
g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (dcsb), prefix);
else
g_settings_backend_writable_changed (G_SETTINGS_BACKEND (dcsb), prefix);
}
/* We send the normal change notification even in the event that this
* was a writability notification because adding/removing a lock could
* impact the value that gets read.
*/
if (changes[1] == NULL)
{
if (g_str_has_suffix (prefix, "/"))
g_settings_backend_path_changed (G_SETTINGS_BACKEND (dcsb), prefix, origin_tag);
else
g_settings_backend_changed (G_SETTINGS_BACKEND (dcsb), prefix, origin_tag);
}
else
g_settings_backend_keys_changed (G_SETTINGS_BACKEND (dcsb), prefix, changes, origin_tag);
}