* 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
* Matthias Clasen <mclasen@redhat.com>
#include <glibintl.h>
-G_DEFINE_ABSTRACT_TYPE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
-
typedef struct _GSettingsBackendClosure GSettingsBackendClosure;
typedef struct _GSettingsBackendWatch GSettingsBackendWatch;
GMutex lock;
};
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
+
/* For g_settings_backend_sync_default(), we only want to actually do
* the sync if the backend already exists. This avoids us creating an
* entire GSettingsBackend in order to call a do-nothing sync()
* g_settings_backend_create_tree() is a convenience function to create
* suitable trees.
*
- * <note><para>
- * The #GSettingsBackend API is exported to allow third-party
+ * The GSettingsBackend API is exported to allow third-party
* implementations, but does not carry the same stability guarantees
* as the public GIO API. For this reason, you have to define the
- * C preprocessor symbol #G_SETTINGS_ENABLE_BACKEND before including
- * <filename>gio/gsettingsbackend.h</filename>
- * </para></note>
+ * C preprocessor symbol %G_SETTINGS_ENABLE_BACKEND before including
+ * `gio/gsettingsbackend.h`.
**/
static gboolean
struct _GSettingsBackendClosure
{
- void (*function) (GObject *target,
- GSettingsBackend *backend,
- const gchar *name,
- gpointer data1,
- gpointer data2);
-
- GSettingsBackend *backend;
- GObject *target;
- gchar *name;
- gpointer data1;
- GBoxedFreeFunc data1_free;
- gpointer data2;
+ void (*function) (GObject *target,
+ GSettingsBackend *backend,
+ const gchar *name,
+ gpointer origin_tag,
+ gchar **names);
+
+ GMainContext *context;
+ GObject *target;
+ GSettingsBackend *backend;
+ gchar *name;
+ gpointer origin_tag;
+ gchar **names;
};
static void
* g_settings_backend_watch:
* @backend: a #GSettingsBackend
* @target: the GObject (typically GSettings instance) to call back to
- * @context: a #GMainContext, or %NULL
+ * @context: (allow-none): a #GMainContext, or %NULL
* ...: callbacks...
*
* Registers a new watch on a #GSettingsBackend.
GSettingsBackendClosure *closure = user_data;
closure->function (closure->target, closure->backend, closure->name,
- closure->data1, closure->data2);
+ closure->origin_tag, closure->names);
- closure->data1_free (closure->data1);
g_object_unref (closure->backend);
g_object_unref (closure->target);
+ g_strfreev (closure->names);
g_free (closure->name);
g_slice_free (GSettingsBackendClosure, closure);
return FALSE;
}
-static gpointer
-pointer_id (gpointer a)
-{
- return a;
-}
-
static void
-pointer_ignore (gpointer a)
+g_settings_backend_dispatch_signal (GSettingsBackend *backend,
+ gsize function_offset,
+ const gchar *name,
+ gpointer origin_tag,
+ const gchar * const *names)
{
-}
-
-static void
-g_settings_backend_dispatch_signal (GSettingsBackend *backend,
- gsize function_offset,
- const gchar *name,
- gpointer data1,
- GBoxedCopyFunc data1_copy,
- GBoxedFreeFunc data1_free,
- gpointer data2)
-{
- GSettingsBackendWatch *suffix, *watch, *next;
-
- if (data1_copy == NULL)
- data1_copy = pointer_id;
-
- if (data1_free == NULL)
- data1_free = pointer_ignore;
+ GSettingsBackendWatch *watch;
+ GSList *closures = NULL;
/* We're in a little bit of a tricky situation here. We need to hold
* a lock while traversing the list, but we don't want to hold the
* lock while calling back into user code.
*
- * Since we're not holding the lock while we call user code, we can't
- * render the list immutable. We can, however, store a pointer to a
- * given suffix of the list and render that suffix immutable.
- *
- * Adds will never modify the suffix since adds always come in the
- * form of prepends. We can also prevent removes from modifying the
- * suffix since removes only happen in response to the last reference
- * count dropping -- so just add a reference to everything in the
- * suffix.
+ * We work around this by creating a bunch of GSettingsBackendClosure
+ * objects while holding the lock and dispatching them after. We
+ * never touch the list without holding the lock.
*/
g_mutex_lock (&backend->priv->lock);
- suffix = backend->priv->watches;
- for (watch = suffix; watch; watch = watch->next)
- g_object_ref (watch->target);
- g_mutex_unlock (&backend->priv->lock);
-
- /* The suffix is now immutable, so this is safe. */
- for (watch = suffix; watch; watch = next)
+ for (watch = backend->priv->watches; watch; watch = watch->next)
{
GSettingsBackendClosure *closure;
closure = g_slice_new (GSettingsBackendClosure);
+ closure->context = watch->context;
closure->backend = g_object_ref (backend);
- closure->target = watch->target; /* we took our ref above */
+ closure->target = g_object_ref (watch->target);
closure->function = G_STRUCT_MEMBER (void *, watch->vtable,
function_offset);
closure->name = g_strdup (name);
- closure->data1 = data1_copy (data1);
- closure->data1_free = data1_free;
- closure->data2 = data2;
+ closure->origin_tag = origin_tag;
+ closure->names = g_strdupv ((gchar **) names);
- /* we do this here because 'watch' may not live to the end of this
- * iteration of the loop (since we may unref the target below).
- */
- next = watch->next;
+ closures = g_slist_prepend (closures, closure);
+ }
+ g_mutex_unlock (&backend->priv->lock);
+
+ while (closures)
+ {
+ GSettingsBackendClosure *closure = closures->data;
- if (watch->context)
- g_main_context_invoke (watch->context,
+ if (closure->context)
+ g_main_context_invoke (closure->context,
g_settings_backend_invoke_closure,
closure);
else
g_settings_backend_invoke_closure (closure);
+
+ closures = g_slist_delete_link (closures, closures);
}
}
g_settings_backend_dispatch_signal (backend,
G_STRUCT_OFFSET (GSettingsListenerVTable,
changed),
- key, origin_tag, NULL, NULL, NULL);
+ key, origin_tag, NULL);
}
/**
g_settings_backend_dispatch_signal (backend,
G_STRUCT_OFFSET (GSettingsListenerVTable,
keys_changed),
- path, (gpointer) items,
- (GBoxedCopyFunc) g_strdupv,
- (GBoxedFreeFunc) g_strfreev,
- origin_tag);
+ path, origin_tag, items);
}
/**
g_settings_backend_dispatch_signal (backend,
G_STRUCT_OFFSET (GSettingsListenerVTable,
path_changed),
- path, origin_tag, NULL, NULL, NULL);
+ path, origin_tag, NULL);
}
/**
g_settings_backend_dispatch_signal (backend,
G_STRUCT_OFFSET (GSettingsListenerVTable,
writable_changed),
- key, NULL, NULL, NULL, NULL);
+ key, NULL, NULL);
}
/**
g_settings_backend_dispatch_signal (backend,
G_STRUCT_OFFSET (GSettingsListenerVTable,
path_writable_changed),
- path, NULL, NULL, NULL, NULL);
+ path, NULL, NULL);
}
typedef struct
}
/*< private >
+ * g_settings_backend_read_user_value:
+ * @backend: a #GSettingsBackend implementation
+ * @key: the key to read
+ * @expected_type: a #GVariantType
+ *
+ * Reads the 'user value' of a key.
+ *
+ * This is the value of the key that the user has control over and has
+ * set for themselves. Put another way: if the user did not set the
+ * value for themselves, then this will return %NULL (even if the
+ * sysadmin has provided a default value).
+ *
+ * Returns: the value that was read, or %NULL
+ */
+GVariant *
+g_settings_backend_read_user_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type)
+{
+ GVariant *value;
+
+ value = G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->read_user_value (backend, key, expected_type);
+
+ if (value != NULL)
+ value = g_variant_take_ref (value);
+
+ if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type))
+ {
+ g_variant_unref (value);
+ value = NULL;
+ }
+
+ return value;
+}
+
+/*< private >
* g_settings_backend_write:
* @backend: a #GSettingsBackend implementation
* @key: the name of the key
GVariant *value,
gpointer origin_tag)
{
- return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ gboolean success;
+
+ g_variant_ref_sink (value);
+ success = G_SETTINGS_BACKEND_GET_CLASS (backend)
->write (backend, key, value, origin_tag);
+ g_variant_unref (value);
+
+ return success;
}
/*< private >
- * g_settings_backend_write_keys:
+ * g_settings_backend_write_tree:
* @backend: a #GSettingsBackend implementation
- * @values: a #GTree containing key-value pairs to write
+ * @tree: a #GTree containing key-value pairs to write
* @origin_tag: the origin tag
*
* Writes one or more keys. This call will never block.
{
}
+static GVariant *
+g_settings_backend_real_read_user_value (GSettingsBackend *backend,
+ const gchar *key,
+ const GVariantType *expected_type)
+{
+ return g_settings_backend_read (backend, key, expected_type, FALSE);
+}
+
static void
g_settings_backend_init (GSettingsBackend *backend)
{
- backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend,
- G_TYPE_SETTINGS_BACKEND,
- GSettingsBackendPrivate);
+ backend->priv = g_settings_backend_get_instance_private (backend);
g_mutex_init (&backend->priv->lock);
}
class->subscribe = ignore_subscription;
class->unsubscribe = ignore_subscription;
- gobject_class->finalize = g_settings_backend_finalize;
+ class->read_user_value = g_settings_backend_real_read_user_value;
- g_type_class_add_private (class, sizeof (GSettingsBackendPrivate));
+ gobject_class->finalize = g_settings_backend_finalize;
}
static void
* g_settings_backend_get_default:
*
* Returns the default #GSettingsBackend. It is possible to override
- * the default by setting the <envar>GSETTINGS_BACKEND</envar>
- * environment variable to the name of a settings backend.
+ * the default by setting the `GSETTINGS_BACKEND` environment variable
+ * to the name of a settings backend.
*
* The user gets a reference to the backend.
*