mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-11-02 09:22:16 +01:00
GSettingsBackend: simplify event handling
Drop the 'vtable' business and switch to a single callback that takes a new GSettingsEvent structure. This patch temporarily regresses delayed settings: if a key set within a delayed settings backend becomes non-writable, it is no longer removed from the changeset.
This commit is contained in:
@@ -111,7 +111,6 @@ gdbus-daemon-generated.h gdbus-daemon-generated.c: $(srcdir)/dbus-daemon.xml $(s
|
||||
$(NULL)
|
||||
|
||||
settings_headers = \
|
||||
gsettingsbackend.h \
|
||||
gsettingsschema.h \
|
||||
gsettings.h
|
||||
|
||||
@@ -624,6 +623,7 @@ gio_headers = \
|
||||
|
||||
gioincludedir=$(includedir)/glib-2.0/gio/
|
||||
gioinclude_HEADERS = \
|
||||
gsettingsbackend.h \
|
||||
$(gio_headers) \
|
||||
gioenumtypes.h
|
||||
|
||||
|
||||
@@ -264,146 +264,14 @@ g_delayed_settings_backend_revert (GDelayedSettingsBackend *delayed)
|
||||
}
|
||||
}
|
||||
|
||||
/* change notification */
|
||||
static void
|
||||
delayed_backend_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag)
|
||||
g_delayed_settings_got_event (GObject *target,
|
||||
const GSettingsEvent *event)
|
||||
{
|
||||
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
|
||||
|
||||
if (origin_tag != delayed->priv)
|
||||
g_settings_backend_changed (G_SETTINGS_BACKEND (delayed),
|
||||
key, origin_tag);
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_backend_keys_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
const gchar * const *items,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
|
||||
|
||||
if (origin_tag != delayed->priv)
|
||||
g_settings_backend_keys_changed (G_SETTINGS_BACKEND (delayed),
|
||||
path, items, origin_tag);
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_backend_path_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
|
||||
|
||||
if (origin_tag != delayed->priv)
|
||||
g_settings_backend_path_changed (G_SETTINGS_BACKEND (delayed),
|
||||
path, origin_tag);
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_backend_writable_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key)
|
||||
{
|
||||
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
|
||||
gboolean last_one = FALSE;
|
||||
|
||||
g_mutex_lock (&delayed->priv->lock);
|
||||
|
||||
if (g_tree_lookup (delayed->priv->delayed, key) != NULL &&
|
||||
!g_settings_backend_get_writable (delayed->priv->backend, key))
|
||||
{
|
||||
/* drop the key from our changeset if it just became read-only.
|
||||
* no need to signal since the writable change below implies it.
|
||||
*
|
||||
* note that the item in the tree may very well be set to NULL in
|
||||
* the case that the user stored a reset. we intentionally don't
|
||||
* drop the key in this case since a reset will always succeed
|
||||
* (even against a non-writable key).
|
||||
*/
|
||||
g_tree_remove (delayed->priv->delayed, key);
|
||||
|
||||
/* if that was the only key... */
|
||||
last_one = g_tree_nnodes (delayed->priv->delayed) == 0;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&delayed->priv->lock);
|
||||
|
||||
if (last_one)
|
||||
g_delayed_settings_backend_notify_unapplied (delayed);
|
||||
|
||||
g_settings_backend_writable_changed (G_SETTINGS_BACKEND (delayed), key);
|
||||
}
|
||||
|
||||
/* slow method until we get foreach-with-remove in GTree
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const gchar *path;
|
||||
const gchar **keys;
|
||||
gsize index;
|
||||
} CheckPrefixState;
|
||||
|
||||
static gboolean
|
||||
check_prefix (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
CheckPrefixState *state = data;
|
||||
|
||||
if (g_str_has_prefix (key, state->path))
|
||||
state->keys[state->index++] = key;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
delayed_backend_path_writable_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path)
|
||||
{
|
||||
GDelayedSettingsBackend *delayed = G_DELAYED_SETTINGS_BACKEND (target);
|
||||
gboolean last_one = FALSE;
|
||||
gsize n_keys;
|
||||
|
||||
g_mutex_lock (&delayed->priv->lock);
|
||||
|
||||
n_keys = g_tree_nnodes (delayed->priv->delayed);
|
||||
|
||||
if (n_keys > 0)
|
||||
{
|
||||
CheckPrefixState state = { path, g_new (const gchar *, n_keys) };
|
||||
gsize i;
|
||||
|
||||
/* collect a list of possibly-affected keys (ie: matching the path) */
|
||||
g_tree_foreach (delayed->priv->delayed, check_prefix, &state);
|
||||
|
||||
/* drop the keys that have been affected.
|
||||
*
|
||||
* don't drop 'reset' keys (see above) */
|
||||
for (i = 0; i < state.index; i++)
|
||||
if (g_tree_lookup (delayed->priv->delayed, state.keys[i]) != NULL &&
|
||||
!g_settings_backend_get_writable (delayed->priv->backend,
|
||||
state.keys[i]))
|
||||
g_tree_remove (delayed->priv->delayed, state.keys[i]);
|
||||
|
||||
g_free (state.keys);
|
||||
|
||||
last_one = g_tree_nnodes (delayed->priv->delayed) == 0;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&delayed->priv->lock);
|
||||
|
||||
if (last_one)
|
||||
g_delayed_settings_backend_notify_unapplied (delayed);
|
||||
|
||||
g_settings_backend_path_writable_changed (G_SETTINGS_BACKEND (delayed),
|
||||
path);
|
||||
if (event->origin_tag != delayed->priv)
|
||||
g_settings_backend_report_event (G_SETTINGS_BACKEND (delayed), event);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -470,13 +338,6 @@ g_delayed_settings_backend_new (GSettingsBackend *backend,
|
||||
gpointer owner,
|
||||
GMainContext *owner_context)
|
||||
{
|
||||
static GSettingsListenerVTable vtable = {
|
||||
delayed_backend_changed,
|
||||
delayed_backend_path_changed,
|
||||
delayed_backend_keys_changed,
|
||||
delayed_backend_writable_changed,
|
||||
delayed_backend_path_writable_changed
|
||||
};
|
||||
GDelayedSettingsBackend *delayed;
|
||||
|
||||
delayed = g_object_new (G_TYPE_DELAYED_SETTINGS_BACKEND, NULL);
|
||||
@@ -487,7 +348,7 @@ g_delayed_settings_backend_new (GSettingsBackend *backend,
|
||||
g_object_weak_ref (owner, g_delayed_settings_backend_disown, delayed);
|
||||
|
||||
g_settings_backend_watch (delayed->priv->backend,
|
||||
&vtable, G_OBJECT (delayed), NULL);
|
||||
g_delayed_settings_got_event, G_OBJECT (delayed), NULL);
|
||||
|
||||
return delayed;
|
||||
}
|
||||
|
||||
@@ -1132,6 +1132,7 @@ g_file_descriptor_based_get_type
|
||||
g_file_descriptor_based_get_fd
|
||||
#endif
|
||||
g_settings_backend_get_type
|
||||
g_settings_backend_report_event
|
||||
g_settings_backend_changed
|
||||
g_settings_backend_flatten_tree
|
||||
g_settings_backend_keys_changed
|
||||
|
||||
258
gio/gsettings.c
258
gio/gsettings.c
@@ -316,124 +316,175 @@ g_settings_real_writable_change_event (GSettings *settings,
|
||||
}
|
||||
|
||||
static void
|
||||
settings_backend_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag)
|
||||
g_settings_emit_signal (GSettings *settings,
|
||||
GSettingsEventType type,
|
||||
const GQuark *quarks,
|
||||
gint n_items)
|
||||
{
|
||||
gboolean ignore_this;
|
||||
guint signal_id;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case G_SETTINGS_EVENT_CHANGE:
|
||||
signal_id = g_settings_signals[SIGNAL_CHANGE_EVENT];
|
||||
break;
|
||||
|
||||
case G_SETTINGS_EVENT_WRITABLE_CHANGE:
|
||||
signal_id = g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT];
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* writable-change-event signals are emitted in a different way */
|
||||
if (signal_id == g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT])
|
||||
{
|
||||
if (n_items > 0)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
g_signal_emit (settings, signal_id, 0, quarks[i], &ignore_this);
|
||||
}
|
||||
else
|
||||
g_signal_emit (settings, signal_id, 0, (GQuark) 0, &ignore_this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_emit (settings, signal_id, 0, quarks, n_items, &ignore_this);
|
||||
}
|
||||
|
||||
static void
|
||||
g_settings_got_event (GObject *target,
|
||||
const GSettingsEvent *event)
|
||||
{
|
||||
GSettings *settings = G_SETTINGS (target);
|
||||
gboolean ignore_this;
|
||||
gint i;
|
||||
const gchar *prefix;
|
||||
const gchar *path;
|
||||
gint prefix_len;
|
||||
gint path_len;
|
||||
|
||||
/* We used to assert here:
|
||||
/* The path of the GSettings always ends with '/'.
|
||||
*
|
||||
* settings->priv->backend == backend
|
||||
* For path '/a/b/', consider these prefixes:
|
||||
*
|
||||
* but it could be the case that a notification is queued for delivery
|
||||
* while someone calls g_settings_delay() (which changes the backend).
|
||||
* - /x/ does not match
|
||||
* - /a/b/ want to match -- this is us directly
|
||||
* - /a/ want to match -- this may impact us
|
||||
* - /a/b/c want to match -- 'c' may be a key
|
||||
* - /a/b/c/ does not match
|
||||
*
|
||||
* Since the delay backend would just pass that straight through
|
||||
* anyway, it doesn't make sense to try to detect this case.
|
||||
* Therefore, we just accept it.
|
||||
* We can quickly determine if we are in a 'want to match' situation
|
||||
* by fast-forwarding the common part of the GSettings path and the
|
||||
* event prefix.
|
||||
*/
|
||||
path = settings->priv->path;
|
||||
prefix = event->prefix;
|
||||
|
||||
for (i = 0; key[i] == settings->priv->path[i]; i++);
|
||||
|
||||
if (settings->priv->path[i] == '\0' &&
|
||||
g_settings_schema_has_key (settings->priv->schema, key + i))
|
||||
while (*prefix && *prefix == *path)
|
||||
{
|
||||
GQuark quark;
|
||||
|
||||
quark = g_quark_from_string (key + i);
|
||||
g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
|
||||
0, &quark, 1, &ignore_this);
|
||||
prefix++;
|
||||
path++;
|
||||
}
|
||||
}
|
||||
prefix_len = strlen (prefix);
|
||||
path_len = strlen (path);
|
||||
|
||||
static void
|
||||
settings_backend_path_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GSettings *settings = G_SETTINGS (target);
|
||||
gboolean ignore_this;
|
||||
/* If after removing the common prefix, we are left with characters in
|
||||
* both then it is clear that we are in a non-matching situation.
|
||||
*/
|
||||
if (prefix_len && path_len)
|
||||
return;
|
||||
|
||||
if (g_str_has_prefix (settings->priv->path, path))
|
||||
g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
|
||||
0, NULL, 0, &ignore_this);
|
||||
}
|
||||
|
||||
static void
|
||||
settings_backend_keys_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
const gchar * const *items,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GSettings *settings = G_SETTINGS (target);
|
||||
gboolean ignore_this;
|
||||
gint i;
|
||||
|
||||
for (i = 0; settings->priv->path[i] &&
|
||||
settings->priv->path[i] == path[i]; i++);
|
||||
|
||||
if (path[i] == '\0')
|
||||
if (prefix_len)
|
||||
{
|
||||
GQuark quarks[256];
|
||||
gint j, l = 0;
|
||||
/* If part of the prefix is remaining then the only possibility is
|
||||
* that we are emitting a change notification for a single key
|
||||
* belonging to this settings object. The remainder of that
|
||||
* prefix (after stripping our path) is exactly the name of that
|
||||
* key.
|
||||
*
|
||||
* Necessarily, this key must not contain a slash in any part of
|
||||
* it. This is a somewhat common case, so we explicitly check
|
||||
* that before attempting to do a lookup of the key.
|
||||
*/
|
||||
if (strchr (prefix, '/'))
|
||||
return;
|
||||
|
||||
for (j = 0; items[j]; j++)
|
||||
{
|
||||
const gchar *item = items[j];
|
||||
gint k;
|
||||
/* If the prefix doesn't end with a slash (as we just verified)
|
||||
* then it had better be the case that the keys array is empty.
|
||||
* We don't bother verifying that, though.
|
||||
*
|
||||
* We just check if the prefix is the name of one of our keys.
|
||||
*/
|
||||
if (g_settings_schema_has_key (settings->priv->schema, prefix))
|
||||
{
|
||||
GQuark quark;
|
||||
|
||||
for (k = 0; item[k] == settings->priv->path[i + k]; k++);
|
||||
|
||||
if (settings->priv->path[i + k] == '\0' &&
|
||||
g_settings_schema_has_key (settings->priv->schema, item + k))
|
||||
quarks[l++] = g_quark_from_string (item + k);
|
||||
|
||||
/* "256 quarks ought to be enough for anybody!"
|
||||
* If this bites you, I'm sorry. Please file a bug.
|
||||
*/
|
||||
g_assert (l < 256);
|
||||
}
|
||||
|
||||
if (l > 0)
|
||||
g_signal_emit (settings, g_settings_signals[SIGNAL_CHANGE_EVENT],
|
||||
0, quarks, l, &ignore_this);
|
||||
quark = g_quark_from_string (prefix);
|
||||
g_settings_emit_signal (settings, event->type, &quark, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The entire prefix is consumed. This means that the prefix
|
||||
* ended with a slash and matched our path.
|
||||
*
|
||||
* We may still have some remaining part of the path, however. If
|
||||
* that is true, we need to verify that each item in the keys
|
||||
* array has this component as a prefix.
|
||||
*/
|
||||
|
||||
static void
|
||||
settings_backend_writable_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key)
|
||||
{
|
||||
GSettings *settings = G_SETTINGS (target);
|
||||
gboolean ignore_this;
|
||||
gint i;
|
||||
/* If the key array is empty then all items under this path have
|
||||
* changed. We don't care about any remaining part of our path in
|
||||
* this case since everything has changed.
|
||||
*/
|
||||
if (event->keys[0] == NULL)
|
||||
g_settings_emit_signal (settings, event->type, NULL, 0);
|
||||
|
||||
for (i = 0; key[i] == settings->priv->path[i]; i++);
|
||||
else
|
||||
{
|
||||
GQuark *quarks;
|
||||
gint n, i, j;
|
||||
|
||||
if (settings->priv->path[i] == '\0' &&
|
||||
g_settings_schema_has_key (settings->priv->schema, key + i))
|
||||
g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT],
|
||||
0, g_quark_from_string (key + i), &ignore_this);
|
||||
}
|
||||
n = g_strv_length (event->keys);
|
||||
|
||||
static void
|
||||
settings_backend_path_writable_changed (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path)
|
||||
{
|
||||
GSettings *settings = G_SETTINGS (target);
|
||||
gboolean ignore_this;
|
||||
if (20 < n)
|
||||
quarks = g_new (GQuark, n);
|
||||
else
|
||||
quarks = g_newa (GQuark, n);
|
||||
|
||||
if (g_str_has_prefix (settings->priv->path, path))
|
||||
g_signal_emit (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT],
|
||||
0, (GQuark) 0, &ignore_this);
|
||||
j = 0;
|
||||
for (i = 0; event->keys[i]; i++)
|
||||
{
|
||||
gchar *key = event->keys[i];
|
||||
|
||||
/* Check the prefix */
|
||||
if (!g_str_has_prefix (key, path))
|
||||
continue;
|
||||
|
||||
/* Remove that component from the key */
|
||||
key += path_len;
|
||||
|
||||
/* Do the slash check as above, and for the same reason */
|
||||
if (strchr (key, '/'))
|
||||
continue;
|
||||
|
||||
/* Check if it's actually a key */
|
||||
if (g_settings_schema_has_key (settings->priv->schema, key))
|
||||
quarks[j++] = g_quark_from_string (key);
|
||||
}
|
||||
|
||||
/* Only signal if we actually had a match. */
|
||||
if (j > 0)
|
||||
g_settings_emit_signal (settings, event->type, quarks, j);
|
||||
|
||||
if (20 < n)
|
||||
g_free (quarks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Properties, Construction, Destruction {{{1 */
|
||||
@@ -546,14 +597,6 @@ g_settings_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static const GSettingsListenerVTable listener_vtable = {
|
||||
settings_backend_changed,
|
||||
settings_backend_path_changed,
|
||||
settings_backend_keys_changed,
|
||||
settings_backend_writable_changed,
|
||||
settings_backend_path_writable_changed
|
||||
};
|
||||
|
||||
static void
|
||||
g_settings_constructed (GObject *object)
|
||||
{
|
||||
@@ -579,7 +622,8 @@ g_settings_constructed (GObject *object)
|
||||
settings->priv->backend = g_settings_backend_get_default ();
|
||||
|
||||
g_settings_backend_watch (settings->priv->backend,
|
||||
&listener_vtable, G_OBJECT (settings),
|
||||
g_settings_got_event,
|
||||
G_OBJECT (settings),
|
||||
settings->priv->main_context);
|
||||
g_settings_backend_subscribe (settings->priv->backend,
|
||||
settings->priv->path);
|
||||
@@ -1907,7 +1951,7 @@ g_settings_delay (GSettings *settings)
|
||||
|
||||
settings->priv->backend = G_SETTINGS_BACKEND (settings->priv->delayed);
|
||||
g_settings_backend_watch (settings->priv->backend,
|
||||
&listener_vtable, G_OBJECT (settings),
|
||||
g_settings_got_event, G_OBJECT (settings),
|
||||
settings->priv->main_context);
|
||||
|
||||
g_object_notify (G_OBJECT (settings), "delay-apply");
|
||||
|
||||
@@ -126,26 +126,18 @@ is_path (const gchar *path)
|
||||
|
||||
struct _GSettingsBackendWatch
|
||||
{
|
||||
GObject *target;
|
||||
const GSettingsListenerVTable *vtable;
|
||||
GMainContext *context;
|
||||
GSettingsBackendWatch *next;
|
||||
GObject *target;
|
||||
GSettingsEventFunc function;
|
||||
GMainContext *context;
|
||||
GSettingsBackendWatch *next;
|
||||
};
|
||||
|
||||
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;
|
||||
GSettingsEventFunc function;
|
||||
GSettingsBackend *backend;
|
||||
GObject *target;
|
||||
GSettingsEvent event;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -198,10 +190,10 @@ g_settings_backend_watch_weak_notify (gpointer data,
|
||||
* value of @origin_tag given to any callbacks.
|
||||
**/
|
||||
void
|
||||
g_settings_backend_watch (GSettingsBackend *backend,
|
||||
const GSettingsListenerVTable *vtable,
|
||||
GObject *target,
|
||||
GMainContext *context)
|
||||
g_settings_backend_watch (GSettingsBackend *backend,
|
||||
GSettingsEventFunc callback,
|
||||
GObject *target,
|
||||
GMainContext *context)
|
||||
{
|
||||
GSettingsBackendWatch *watch;
|
||||
|
||||
@@ -241,7 +233,7 @@ g_settings_backend_watch (GSettingsBackend *backend,
|
||||
|
||||
watch = g_slice_new (GSettingsBackendWatch);
|
||||
watch->context = context;
|
||||
watch->vtable = vtable;
|
||||
watch->function = callback;
|
||||
watch->target = target;
|
||||
g_object_weak_ref (target, g_settings_backend_watch_weak_notify, backend);
|
||||
|
||||
@@ -268,47 +260,24 @@ g_settings_backend_invoke_closure (gpointer user_data)
|
||||
{
|
||||
GSettingsBackendClosure *closure = user_data;
|
||||
|
||||
closure->function (closure->target, closure->backend, closure->name,
|
||||
closure->data1, closure->data2);
|
||||
closure->function (closure->target, &closure->event);
|
||||
|
||||
closure->data1_free (closure->data1);
|
||||
g_object_unref (closure->backend);
|
||||
g_object_unref (closure->target);
|
||||
g_free (closure->name);
|
||||
g_strfreev (closure->event.keys);
|
||||
g_free (closure->event.prefix);
|
||||
|
||||
g_slice_free (GSettingsBackendClosure, closure);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
pointer_id (gpointer a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
static void
|
||||
pointer_ignore (gpointer a)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
void
|
||||
g_settings_backend_report_event (GSettingsBackend *backend,
|
||||
const GSettingsEvent *event)
|
||||
{
|
||||
GSettingsBackendWatch *suffix, *watch, *next;
|
||||
|
||||
if (data1_copy == NULL)
|
||||
data1_copy = pointer_id;
|
||||
|
||||
if (data1_free == NULL)
|
||||
data1_free = pointer_ignore;
|
||||
|
||||
/* 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.
|
||||
@@ -337,12 +306,11 @@ g_settings_backend_dispatch_signal (GSettingsBackend *backend,
|
||||
closure = g_slice_new (GSettingsBackendClosure);
|
||||
closure->backend = g_object_ref (backend);
|
||||
closure->target = watch->target; /* we took our ref above */
|
||||
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->function = watch->function;
|
||||
closure->event.type = event->type;
|
||||
closure->event.prefix = g_strdup (event->prefix);
|
||||
closure->event.keys = g_strdupv (event->keys);
|
||||
closure->event.origin_tag = event->origin_tag;
|
||||
|
||||
/* 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).
|
||||
@@ -394,13 +362,18 @@ g_settings_backend_changed (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GSettingsEvent event;
|
||||
gchar *null = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
|
||||
g_return_if_fail (is_key (key));
|
||||
|
||||
g_settings_backend_dispatch_signal (backend,
|
||||
G_STRUCT_OFFSET (GSettingsListenerVTable,
|
||||
changed),
|
||||
key, origin_tag, NULL, NULL, NULL);
|
||||
event.type = G_SETTINGS_EVENT_CHANGE;
|
||||
event.prefix = (gchar *) key;
|
||||
event.keys = &null;
|
||||
event.origin_tag = origin_tag;
|
||||
|
||||
g_settings_backend_report_event (backend, &event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -440,19 +413,20 @@ g_settings_backend_keys_changed (GSettingsBackend *backend,
|
||||
gchar const * const *items,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GSettingsEvent event;
|
||||
|
||||
g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
|
||||
g_return_if_fail (is_path (path));
|
||||
|
||||
/* XXX: should do stricter checking (ie: inspect each item) */
|
||||
g_return_if_fail (items != NULL);
|
||||
|
||||
g_settings_backend_dispatch_signal (backend,
|
||||
G_STRUCT_OFFSET (GSettingsListenerVTable,
|
||||
keys_changed),
|
||||
path, (gpointer) items,
|
||||
(GBoxedCopyFunc) g_strdupv,
|
||||
(GBoxedFreeFunc) g_strfreev,
|
||||
origin_tag);
|
||||
event.type = G_SETTINGS_EVENT_CHANGE;
|
||||
event.prefix = (gchar *) path;
|
||||
event.keys = (gchar **) items;
|
||||
event.origin_tag = origin_tag;
|
||||
|
||||
g_settings_backend_report_event (backend, &event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,13 +464,18 @@ g_settings_backend_path_changed (GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GSettingsEvent event;
|
||||
gchar *null = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
|
||||
g_return_if_fail (is_path (path));
|
||||
|
||||
g_settings_backend_dispatch_signal (backend,
|
||||
G_STRUCT_OFFSET (GSettingsListenerVTable,
|
||||
path_changed),
|
||||
path, origin_tag, NULL, NULL, NULL);
|
||||
event.type = G_SETTINGS_EVENT_CHANGE;
|
||||
event.prefix = (gchar *) path;
|
||||
event.keys = &null;
|
||||
event.origin_tag = origin_tag;
|
||||
|
||||
g_settings_backend_report_event (backend, &event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,13 +494,18 @@ void
|
||||
g_settings_backend_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *key)
|
||||
{
|
||||
GSettingsEvent event;
|
||||
gchar *null = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
|
||||
g_return_if_fail (is_key (key));
|
||||
|
||||
g_settings_backend_dispatch_signal (backend,
|
||||
G_STRUCT_OFFSET (GSettingsListenerVTable,
|
||||
writable_changed),
|
||||
key, NULL, NULL, NULL, NULL);
|
||||
event.type = G_SETTINGS_EVENT_WRITABLE_CHANGE;
|
||||
event.prefix = (gchar *) key;
|
||||
event.keys = &null;
|
||||
event.origin_tag = NULL;
|
||||
|
||||
g_settings_backend_report_event (backend, &event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,13 +525,18 @@ void
|
||||
g_settings_backend_path_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *path)
|
||||
{
|
||||
GSettingsEvent event;
|
||||
gchar *null = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
|
||||
g_return_if_fail (is_path (path));
|
||||
|
||||
g_settings_backend_dispatch_signal (backend,
|
||||
G_STRUCT_OFFSET (GSettingsListenerVTable,
|
||||
path_writable_changed),
|
||||
path, NULL, NULL, NULL, NULL);
|
||||
event.type = G_SETTINGS_EVENT_WRITABLE_CHANGE;
|
||||
event.prefix = (gchar *) path;
|
||||
event.keys = &null;
|
||||
event.origin_tag = NULL;
|
||||
|
||||
g_settings_backend_report_event (backend, &event);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -104,36 +104,52 @@ struct _GSettingsBackend
|
||||
GSettingsBackendPrivate *priv;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_SETTINGS_EVENT_CHANGE,
|
||||
G_SETTINGS_EVENT_WRITABLE_CHANGE
|
||||
} GSettingsEventType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSettingsEventType type;
|
||||
gchar *prefix;
|
||||
gchar **keys;
|
||||
gpointer origin_tag;
|
||||
} GSettingsEvent;
|
||||
|
||||
GType g_settings_backend_get_type (void);
|
||||
|
||||
void g_settings_backend_changed (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_path_changed (GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_flatten_tree (GTree *tree,
|
||||
gchar **path,
|
||||
const gchar ***keys,
|
||||
GVariant ***values);
|
||||
void g_settings_backend_keys_changed (GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gchar const * const *items,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_report_event (GSettingsBackend *backend,
|
||||
const GSettingsEvent *event);
|
||||
void g_settings_backend_changed (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_path_changed (GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_flatten_tree (GTree *tree,
|
||||
gchar **path,
|
||||
const gchar ***keys,
|
||||
GVariant ***values);
|
||||
void g_settings_backend_keys_changed (GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gchar const * const *items,
|
||||
gpointer origin_tag);
|
||||
|
||||
void g_settings_backend_path_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *path);
|
||||
void g_settings_backend_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *key);
|
||||
void g_settings_backend_changed_tree (GSettingsBackend *backend,
|
||||
GTree *tree,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_path_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *path);
|
||||
void g_settings_backend_writable_changed (GSettingsBackend *backend,
|
||||
const gchar *key);
|
||||
void g_settings_backend_changed_tree (GSettingsBackend *backend,
|
||||
GTree *tree,
|
||||
gpointer origin_tag);
|
||||
|
||||
GSettingsBackend * g_settings_backend_get_default (void);
|
||||
|
||||
GSettingsBackend * g_keyfile_settings_backend_new (const gchar *filename,
|
||||
const gchar *root_path,
|
||||
const gchar *root_group);
|
||||
GSettingsBackend * g_keyfile_settings_backend_new (const gchar *filename,
|
||||
const gchar *root_path,
|
||||
const gchar *root_group);
|
||||
|
||||
GSettingsBackend * g_null_settings_backend_new (void);
|
||||
|
||||
|
||||
@@ -26,71 +26,51 @@
|
||||
|
||||
#include "gsettingsbackend.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (* changed) (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag);
|
||||
void (* path_changed) (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path,
|
||||
gpointer origin_tag);
|
||||
void (* keys_changed) (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *prefix,
|
||||
const gchar * const *names,
|
||||
gpointer origin_tag);
|
||||
void (* writable_changed) (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *key);
|
||||
void (* path_writable_changed) (GObject *target,
|
||||
GSettingsBackend *backend,
|
||||
const gchar *path);
|
||||
} GSettingsListenerVTable;
|
||||
typedef void (* GSettingsEventFunc) (GObject *target,
|
||||
const GSettingsEvent *event);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_watch (GSettingsBackend *backend,
|
||||
const GSettingsListenerVTable *vtable,
|
||||
GObject *target,
|
||||
GMainContext *context);
|
||||
void g_settings_backend_watch (GSettingsBackend *backend,
|
||||
GSettingsEventFunc callback,
|
||||
GObject *target,
|
||||
GMainContext *context);
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_unwatch (GSettingsBackend *backend,
|
||||
GObject *target);
|
||||
void g_settings_backend_unwatch (GSettingsBackend *backend,
|
||||
GObject *target);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GTree * g_settings_backend_create_tree (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GVariant * g_settings_backend_read (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
const GVariantType *expected_type,
|
||||
gboolean default_value);
|
||||
GVariant * g_settings_backend_read (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
const GVariantType *expected_type,
|
||||
gboolean default_value);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean g_settings_backend_write (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
GVariant *value,
|
||||
gpointer origin_tag);
|
||||
gboolean g_settings_backend_write (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
GVariant *value,
|
||||
gpointer origin_tag);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean g_settings_backend_write_tree (GSettingsBackend *backend,
|
||||
GTree *tree,
|
||||
gpointer origin_tag);
|
||||
gboolean g_settings_backend_write_tree (GSettingsBackend *backend,
|
||||
GTree *tree,
|
||||
gpointer origin_tag);
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_reset (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag);
|
||||
void g_settings_backend_reset (GSettingsBackend *backend,
|
||||
const gchar *key,
|
||||
gpointer origin_tag);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean g_settings_backend_get_writable (GSettingsBackend *backend,
|
||||
const char *key);
|
||||
gboolean g_settings_backend_get_writable (GSettingsBackend *backend,
|
||||
const char *key);
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_unsubscribe (GSettingsBackend *backend,
|
||||
const char *name);
|
||||
void g_settings_backend_unsubscribe (GSettingsBackend *backend,
|
||||
const char *name);
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_subscribe (GSettingsBackend *backend,
|
||||
const char *name);
|
||||
void g_settings_backend_subscribe (GSettingsBackend *backend,
|
||||
const char *name);
|
||||
G_GNUC_INTERNAL
|
||||
GPermission * g_settings_backend_get_permission (GSettingsBackend *backend,
|
||||
const gchar *path);
|
||||
GPermission * g_settings_backend_get_permission (GSettingsBackend *backend,
|
||||
const gchar *path);
|
||||
G_GNUC_INTERNAL
|
||||
void g_settings_backend_sync_default (void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user