[gnome-builder] libide/tweaks: add binding abstraction
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide/tweaks: add binding abstraction
- Date: Wed, 24 Aug 2022 09:26:43 +0000 (UTC)
commit 2601379d32746342939f6acaba48af5a7b8e1d80
Author: Christian Hergert <chergert redhat com>
Date: Wed Aug 24 01:58:25 2022 -0700
libide/tweaks: add binding abstraction
Rather than all the settings/object binding madness we have now, I want
to see IdeTweaksWidget get a "binding" property that can have these as
an object defined within it.
That will allow for us to do a lot more interesting things without having
to shoehorn the widgets multiple property bindings and/or actions.
I don't like how many GSettings are created here, but we can optimize that
later if it becomes a problem. GSettings already has backends which make
a lot of that "fast enough".
src/libide/tweaks/ide-tweaks-binding.c | 242 ++++++++++++++++++++++
src/libide/tweaks/ide-tweaks-binding.h | 62 ++++++
src/libide/tweaks/ide-tweaks-init.c | 3 +
src/libide/tweaks/ide-tweaks-property.c | 294 ++++++++++++++++++++++++++
src/libide/tweaks/ide-tweaks-property.h | 49 +++++
src/libide/tweaks/ide-tweaks-setting.c | 355 ++++++++++++++++++++++++++++++++
src/libide/tweaks/ide-tweaks-setting.h | 54 +++++
src/libide/tweaks/ide-tweaks-widget.c | 3 +-
src/libide/tweaks/libide-tweaks.h | 3 +
src/libide/tweaks/meson.build | 6 +
10 files changed, 1070 insertions(+), 1 deletion(-)
---
diff --git a/src/libide/tweaks/ide-tweaks-binding.c b/src/libide/tweaks/ide-tweaks-binding.c
new file mode 100644
index 000000000..0693cecbf
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-binding.c
@@ -0,0 +1,242 @@
+/* ide-tweaks-binding.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-tweaks-binding"
+
+#include "config.h"
+
+#include "ide-tweaks-binding.h"
+
+typedef struct
+{
+ GWeakRef instance;
+ GParamSpec *pspec;
+ int inhibit;
+} IdeTweaksBindingPrivate;
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (IdeTweaksBinding, ide_tweaks_binding, IDE_TYPE_TWEAKS_ITEM)
+
+enum {
+ CHANGED,
+ N_SIGNALS
+};
+
+static guint signals [N_SIGNALS];
+
+static void
+ide_tweaks_binding_inhibit (IdeTweaksBinding *self)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+
+ g_assert (IDE_IS_TWEAKS_BINDING (self));
+ g_assert (priv->inhibit >= 0);
+
+ priv->inhibit++;
+}
+
+static void
+ide_tweaks_binding_uninhibit (IdeTweaksBinding *self)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+
+ g_assert (IDE_IS_TWEAKS_BINDING (self));
+ g_assert (priv->inhibit > 0);
+
+ priv->inhibit--;
+}
+
+static void
+ide_tweaks_binding_real_changed (IdeTweaksBinding *self)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+ g_autoptr(GObject) instance = NULL;
+ g_auto(GValue) value = G_VALUE_INIT;
+
+ g_assert (IDE_IS_TWEAKS_BINDING (self));
+
+ if (!(instance = g_weak_ref_get (&priv->instance)))
+ return;
+
+ g_assert (G_IS_OBJECT (instance));
+ g_assert (priv->pspec != NULL);
+ g_assert (priv->inhibit > 0);
+
+ g_value_init (&value, priv->pspec->value_type);
+ if (ide_tweaks_binding_get_value (self, &value))
+ g_object_set_property (instance, priv->pspec->name, &value);
+}
+
+static void
+ide_tweaks_binding_dispose (GObject *object)
+{
+ IdeTweaksBinding *self = (IdeTweaksBinding *)object;
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+
+ g_weak_ref_set (&priv->instance, NULL);
+ priv->pspec = NULL;
+
+ G_OBJECT_CLASS (ide_tweaks_binding_parent_class)->dispose (object);
+}
+
+static void
+ide_tweaks_binding_finalize (GObject *object)
+{
+ IdeTweaksBinding *self = (IdeTweaksBinding *)object;
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+
+ g_weak_ref_clear (&priv->instance);
+
+ G_OBJECT_CLASS (ide_tweaks_binding_parent_class)->finalize (object);
+}
+
+static void
+ide_tweaks_binding_class_init (IdeTweaksBindingClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = ide_tweaks_binding_dispose;
+ object_class->finalize = ide_tweaks_binding_finalize;
+
+ klass->changed = ide_tweaks_binding_real_changed;
+
+ signals [CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IdeTweaksBindingClass, changed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+ide_tweaks_binding_init (IdeTweaksBinding *self)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+
+ g_weak_ref_init (&priv->instance, NULL);
+}
+
+void
+ide_tweaks_binding_changed (IdeTweaksBinding *self)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_BINDING (self));
+
+ ide_tweaks_binding_inhibit (self);
+ g_signal_emit (self, signals [CHANGED], 0);
+ ide_tweaks_binding_uninhibit (self);
+}
+
+gboolean
+ide_tweaks_binding_get_value (IdeTweaksBinding *self,
+ GValue *value)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_BINDING (self), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+ g_return_val_if_fail (G_VALUE_TYPE (value) != G_TYPE_INVALID, FALSE);
+
+ return IDE_TWEAKS_BINDING_GET_CLASS (self)->get_value (self, value);
+}
+
+void
+ide_tweaks_binding_set_value (IdeTweaksBinding *self,
+ const GValue *value)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_BINDING (self));
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (G_IS_VALUE (value));
+
+ IDE_TWEAKS_BINDING_GET_CLASS (self)->set_value (self, value);
+}
+
+static void
+ide_tweaks_binding_instance_notify_cb (IdeTweaksBinding *self,
+ GParamSpec *pspec,
+ GObject *instance)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+ g_auto(GValue) value = G_VALUE_INIT;
+
+ g_assert (IDE_IS_TWEAKS_BINDING (self));
+ g_assert (pspec != NULL);
+ g_assert (G_IS_OBJECT (instance));
+
+ if (priv->inhibit > 0)
+ return;
+
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (instance, pspec->name, &value);
+ ide_tweaks_binding_set_value (self, &value);
+}
+
+void
+ide_tweaks_binding_unbind (IdeTweaksBinding *self)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+ g_autoptr(GObject) instance = NULL;
+
+ g_return_if_fail (IDE_IS_TWEAKS_BINDING (self));
+
+ if ((instance = g_weak_ref_get (&priv->instance)))
+ {
+ g_weak_ref_set (&priv->instance, NULL);
+ priv->pspec = NULL;
+
+ g_signal_handlers_disconnect_by_func (instance,
+ G_CALLBACK (ide_tweaks_binding_instance_notify_cb),
+ self);
+ }
+}
+
+void
+ide_tweaks_binding_bind (IdeTweaksBinding *self,
+ gpointer instance,
+ const char *property_name)
+{
+ IdeTweaksBindingPrivate *priv = ide_tweaks_binding_get_instance_private (self);
+ g_autofree char *signal_name = NULL;
+
+ g_return_if_fail (IDE_IS_TWEAKS_BINDING (self));
+ g_return_if_fail (G_IS_OBJECT (instance));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (priv->inhibit == 0);
+
+ ide_tweaks_binding_unbind (self);
+
+ if (!(priv->pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (instance), property_name)))
+ {
+ g_critical ("Object of type %s does not have a property named %s",
+ G_OBJECT_TYPE_NAME (instance), property_name);
+ return;
+ }
+
+ g_weak_ref_set (&priv->instance, instance);
+
+ /* Get notifications on property changes */
+ signal_name = g_strdup_printf ("notify::%s", property_name);
+ g_signal_connect_object (instance,
+ signal_name,
+ G_CALLBACK (ide_tweaks_binding_instance_notify_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ /* Copy state to the widget */
+ ide_tweaks_binding_changed (self);
+}
diff --git a/src/libide/tweaks/ide-tweaks-binding.h b/src/libide/tweaks/ide-tweaks-binding.h
new file mode 100644
index 000000000..c299ba7ab
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-binding.h
@@ -0,0 +1,62 @@
+/* ide-tweaks-binding.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_TWEAKS_INSIDE) && !defined (IDE_TWEAKS_COMPILATION)
+# error "Only <libide-tweaks.h> can be included directly."
+#endif
+
+#include "ide-tweaks-item.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TWEAKS_BINDING (ide_tweaks_binding_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_DERIVABLE_TYPE (IdeTweaksBinding, ide_tweaks_binding, IDE, TWEAKS_BINDING, IdeTweaksItem)
+
+struct _IdeTweaksBindingClass
+{
+ IdeTweaksItemClass parent_class;
+
+ void (*changed) (IdeTweaksBinding *self);
+ gboolean (*get_value) (IdeTweaksBinding *self,
+ GValue *value);
+ void (*set_value) (IdeTweaksBinding *self,
+ const GValue *value);
+};
+
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_binding_changed (IdeTweaksBinding *self);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_tweaks_binding_get_value (IdeTweaksBinding *self,
+ GValue *value);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_binding_set_value (IdeTweaksBinding *self,
+ const GValue *value);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_binding_bind (IdeTweaksBinding *self,
+ gpointer instance,
+ const char *property_name);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_binding_unbind (IdeTweaksBinding *self);
+
+G_END_DECLS
diff --git a/src/libide/tweaks/ide-tweaks-init.c b/src/libide/tweaks/ide-tweaks-init.c
index fa0308603..63173d7d6 100644
--- a/src/libide/tweaks/ide-tweaks-init.c
+++ b/src/libide/tweaks/ide-tweaks-init.c
@@ -34,6 +34,7 @@ _ide_tweaks_init (void)
g_type_ensure (IDE_TYPE_TWEAKS);
g_type_ensure (IDE_TYPE_TWEAKS_ADDIN);
+ g_type_ensure (IDE_TYPE_TWEAKS_BINDING);
g_type_ensure (IDE_TYPE_TWEAKS_CAPTION);
g_type_ensure (IDE_TYPE_TWEAKS_CHOICE);
g_type_ensure (IDE_TYPE_TWEAKS_COMBO);
@@ -45,8 +46,10 @@ _ide_tweaks_init (void)
g_type_ensure (IDE_TYPE_TWEAKS_INFO);
g_type_ensure (IDE_TYPE_TWEAKS_ITEM);
g_type_ensure (IDE_TYPE_TWEAKS_PAGE);
+ g_type_ensure (IDE_TYPE_TWEAKS_PROPERTY);
g_type_ensure (IDE_TYPE_TWEAKS_RADIO);
g_type_ensure (IDE_TYPE_TWEAKS_SECTION);
+ g_type_ensure (IDE_TYPE_TWEAKS_SETTING);
g_type_ensure (IDE_TYPE_TWEAKS_SETTINGS);
g_type_ensure (IDE_TYPE_TWEAKS_SPIN);
g_type_ensure (IDE_TYPE_TWEAKS_SWITCH);
diff --git a/src/libide/tweaks/ide-tweaks-property.c b/src/libide/tweaks/ide-tweaks-property.c
new file mode 100644
index 000000000..d14b964d3
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-property.c
@@ -0,0 +1,294 @@
+/* ide-tweaks-property.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-tweaks-property"
+
+#include "config.h"
+
+#include "ide-tweaks-property.h"
+
+struct _IdeTweaksProperty
+{
+ IdeTweaksBinding parent_instance;
+ GWeakRef instance;
+ const char *name;
+ gulong notify_handler;
+};
+
+enum {
+ PROP_0,
+ PROP_OBJECT,
+ PROP_NAME,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (IdeTweaksProperty, ide_tweaks_property, IDE_TYPE_TWEAKS_BINDING)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_tweaks_property_object_notify_cb (IdeTweaksProperty *self,
+ GParamSpec *pspec,
+ GObject *instance)
+{
+ g_assert (IDE_IS_TWEAKS_PROPERTY (self));
+ g_assert (G_IS_OBJECT (instance));
+
+ ide_tweaks_binding_changed (IDE_TWEAKS_BINDING (self));
+}
+
+static GObject *
+ide_tweaks_property_acquire (IdeTweaksProperty *self)
+{
+ g_autoptr(GObject) instance = NULL;
+
+ g_assert (IDE_IS_TWEAKS_PROPERTY (self));
+
+ if (self->name == NULL)
+ return NULL;
+
+ if ((instance = g_weak_ref_get (&self->instance)))
+ {
+ if (self->notify_handler == 0)
+ {
+ g_autofree char *signal_name = g_strdup_printf ("notify::%s", self->name);
+
+ self->notify_handler =
+ g_signal_connect_object (instance,
+ signal_name,
+ G_CALLBACK (ide_tweaks_property_object_notify_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ }
+ }
+
+ return g_steal_pointer (&instance);
+}
+
+static gboolean
+ide_tweaks_property_get_value (IdeTweaksBinding *binding,
+ GValue *value)
+{
+ IdeTweaksProperty *self = (IdeTweaksProperty *)binding;
+ g_autoptr(GObject) instance = NULL;
+
+ g_return_val_if_fail (IDE_IS_TWEAKS_PROPERTY (self), FALSE);
+ g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+ g_return_val_if_fail (self->name != NULL, FALSE);
+
+ if ((instance = ide_tweaks_property_acquire (self)))
+ g_object_get_property (instance, self->name, value);
+
+ return instance != NULL;
+}
+
+static void
+ide_tweaks_property_set_value (IdeTweaksBinding *binding,
+ const GValue *value)
+{
+ IdeTweaksProperty *self = (IdeTweaksProperty *)binding;
+ g_autoptr(GObject) instance = NULL;
+
+ g_return_if_fail (IDE_IS_TWEAKS_PROPERTY (self));
+ g_return_if_fail (G_IS_VALUE (value));
+ g_return_if_fail (self->name != NULL);
+
+ if ((instance = ide_tweaks_property_acquire (self)))
+ g_object_set_property (instance, self->name, value);
+}
+
+static gboolean
+ide_tweaks_property_set_object_internal (IdeTweaksProperty *self,
+ GObject *object)
+{
+ g_autoptr(GObject) previous = NULL;
+
+ g_assert (IDE_IS_TWEAKS_PROPERTY (self));
+ g_assert (!object || G_IS_OBJECT (object));
+
+ previous = g_weak_ref_get (&self->instance);
+ if (previous == object)
+ return FALSE;
+
+ g_clear_signal_handler (&self->notify_handler, previous);
+ g_weak_ref_set (&self->instance, object);
+
+ return TRUE;
+}
+
+static void
+ide_tweaks_property_dispose (GObject *object)
+{
+ IdeTweaksProperty *self = (IdeTweaksProperty *)object;
+
+ ide_tweaks_property_set_object_internal (self, NULL);
+ self->name = NULL;
+
+ g_assert (self->name == NULL);
+ g_assert (self->notify_handler == 0);
+ g_assert (g_weak_ref_get (&self->instance) == NULL);
+
+ G_OBJECT_CLASS (ide_tweaks_property_parent_class)->finalize (object);
+}
+
+static void
+ide_tweaks_property_finalize (GObject *object)
+{
+ IdeTweaksProperty *self = (IdeTweaksProperty *)object;
+
+ g_weak_ref_clear (&self->instance);
+
+ G_OBJECT_CLASS (ide_tweaks_property_parent_class)->finalize (object);
+}
+
+static void
+ide_tweaks_property_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTweaksProperty *self = IDE_TWEAKS_PROPERTY (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, ide_tweaks_property_get_name (self));
+ break;
+
+ case PROP_OBJECT:
+ g_value_take_object (value, ide_tweaks_property_dup_object (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_tweaks_property_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTweaksProperty *self = IDE_TWEAKS_PROPERTY (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ ide_tweaks_property_set_name (self, g_value_get_string (value));
+ break;
+
+ case PROP_OBJECT:
+ ide_tweaks_property_set_object (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_tweaks_property_class_init (IdeTweaksPropertyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeTweaksBindingClass *tweaks_binding_class = IDE_TWEAKS_BINDING_CLASS (klass);
+
+ object_class->dispose = ide_tweaks_property_dispose;
+ object_class->finalize = ide_tweaks_property_finalize;
+ object_class->get_property = ide_tweaks_property_get_property;
+ object_class->set_property = ide_tweaks_property_set_property;
+
+ tweaks_binding_class->get_value = ide_tweaks_property_get_value;
+ tweaks_binding_class->set_value = ide_tweaks_property_set_value;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_OBJECT] =
+ g_param_spec_object ("object", NULL, NULL,
+ G_TYPE_OBJECT,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_tweaks_property_init (IdeTweaksProperty *self)
+{
+ g_weak_ref_init (&self->instance, NULL);
+}
+
+IdeTweaksProperty *
+ide_tweaks_property_new (void)
+{
+ return g_object_new (IDE_TYPE_TWEAKS_PROPERTY, NULL);
+}
+
+const char *
+ide_tweaks_property_get_name (IdeTweaksProperty *self)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_PROPERTY (self), NULL);
+
+ return self->name;
+}
+
+void
+ide_tweaks_property_set_name (IdeTweaksProperty *self,
+ const char *name)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_PROPERTY (self));
+
+ name = g_intern_string (name);
+
+ if (name != self->name)
+ {
+ self->name = name;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_NAME]);
+ }
+}
+
+/**
+ * ide_tweaks_property_dup_object:
+ * @self: a #IdeTweaksProperty
+ *
+ * Gets the object to tweak the property of.
+ *
+ * Returns: (transfer full) (nullable): a #GObject or %NULL
+ */
+GObject *
+ide_tweaks_property_dup_object (IdeTweaksProperty *self)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_PROPERTY (self), NULL);
+
+ return g_weak_ref_get (&self->instance);
+}
+
+void
+ide_tweaks_property_set_object (IdeTweaksProperty *self,
+ GObject *object)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_PROPERTY (self));
+ g_return_if_fail (!object || G_IS_OBJECT (object));
+
+ if (ide_tweaks_property_set_object_internal (self, object))
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_OBJECT]);
+}
diff --git a/src/libide/tweaks/ide-tweaks-property.h b/src/libide/tweaks/ide-tweaks-property.h
new file mode 100644
index 000000000..84d65f4b8
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-property.h
@@ -0,0 +1,49 @@
+/* ide-tweaks-property.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_TWEAKS_INSIDE) && !defined (IDE_TWEAKS_COMPILATION)
+# error "Only <libide-tweaks.h> can be included directly."
+#endif
+
+#include "ide-tweaks-binding.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TWEAKS_PROPERTY (ide_tweaks_property_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeTweaksProperty, ide_tweaks_property, IDE, TWEAKS_PROPERTY, IdeTweaksBinding)
+
+IDE_AVAILABLE_IN_ALL
+IdeTweaksProperty *ide_tweaks_property_new (void);
+IDE_AVAILABLE_IN_ALL
+GObject *ide_tweaks_property_dup_object (IdeTweaksProperty *self);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_property_set_object (IdeTweaksProperty *self,
+ GObject *object);
+IDE_AVAILABLE_IN_ALL
+const char *ide_tweaks_property_get_name (IdeTweaksProperty *self);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_property_set_name (IdeTweaksProperty *self,
+ const char *name);
+
+G_END_DECLS
diff --git a/src/libide/tweaks/ide-tweaks-setting.c b/src/libide/tweaks/ide-tweaks-setting.c
new file mode 100644
index 000000000..5c27cf083
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-setting.c
@@ -0,0 +1,355 @@
+/* ide-tweaks-setting.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-tweaks-setting"
+
+#include "config.h"
+
+#include "ide-tweaks.h"
+#include "ide-tweaks-setting.h"
+
+#include "gsettings-mapping.h"
+
+struct _IdeTweaksSetting
+{
+ IdeTweaksBinding parent_instance;
+ const char *schema_id;
+ const char *schema_key;
+ char *path_suffix;
+ GSettings *settings;
+ const GVariantType *expected_type;
+ gulong changed_handler;
+};
+
+enum {
+ PROP_0,
+ PROP_SCHEMA_ID,
+ PROP_SCHEMA_KEY,
+ PROP_PATH_SUFFIX,
+ N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (IdeTweaksSetting, ide_tweaks_setting, IDE_TYPE_TWEAKS_BINDING)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_tweaks_setting_settings_changed_cb (IdeTweaksSetting *self,
+ const char *key,
+ GSettings *settings)
+{
+ g_assert (IDE_IS_TWEAKS_SETTING (self));
+ g_assert (key != NULL);
+ g_assert (G_IS_SETTINGS (settings));
+
+ if (settings != self->settings)
+ return;
+
+ ide_tweaks_binding_changed (IDE_TWEAKS_BINDING (self));
+}
+
+static GSettings *
+ide_tweaks_setting_acquire (IdeTweaksSetting *self,
+ const char **key,
+ const GVariantType **expected_type)
+{
+ g_assert (IDE_IS_TWEAKS_SETTING (self));
+
+ if (key != NULL)
+ *key = self->schema_key;
+
+ if (expected_type != NULL)
+ *expected_type = NULL;
+
+ if (self->schema_id == NULL || self->schema_key == NULL)
+ return NULL;
+
+ if (self->settings == NULL)
+ {
+ g_autoptr(GSettingsSchema) schema = NULL;
+ g_autoptr(GSettingsSchemaKey) schema_key = NULL;
+ g_autofree char *path = NULL;
+ g_autofree char *signal_name = NULL;
+ g_autoptr(GVariant) value = NULL;
+ IdeTweaksItem *root;
+ const char *project_id = NULL;
+
+ if ((root = ide_tweaks_item_get_root (IDE_TWEAKS_ITEM (self))) && IDE_IS_TWEAKS (root))
+ project_id = ide_tweaks_get_project_id (IDE_TWEAKS (root));
+
+ if (!(path = ide_settings_resolve_schema_path (self->schema_id, project_id, self->path_suffix)))
+ return NULL;
+
+ if (!(self->settings = g_settings_new_with_path (self->schema_id, path)))
+ return NULL;
+
+ g_object_get (self->settings,
+ "settings-schema", &schema,
+ NULL);
+ schema_key = g_settings_schema_get_key (schema, self->schema_key);
+ self->expected_type = g_settings_schema_key_get_value_type (schema_key);
+
+ value = g_settings_get_value (self->settings, self->schema_key);
+ signal_name = g_strdup_printf ("changed::%s", self->schema_key);
+
+ self->changed_handler =
+ g_signal_connect_object (self->settings,
+ signal_name,
+ G_CALLBACK (ide_tweaks_setting_settings_changed_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ }
+
+ if (expected_type != NULL)
+ *expected_type = self->expected_type;
+
+ return g_object_ref (self->settings);
+}
+
+static void
+ide_tweaks_setting_release (IdeTweaksSetting *self)
+{
+ g_assert (IDE_IS_TWEAKS_SETTING (self));
+
+ g_clear_signal_handler (&self->changed_handler, self->settings);
+ g_clear_object (&self->settings);
+ self->expected_type = NULL;
+}
+
+static gboolean
+ide_tweaks_setting_get_value (IdeTweaksBinding *binding,
+ GValue *value)
+{
+ IdeTweaksSetting *self = (IdeTweaksSetting *)binding;
+ g_autoptr(GSettings) settings = NULL;
+ const char *key = NULL;
+
+ g_assert (IDE_IS_TWEAKS_SETTING (self));
+ g_assert (G_IS_VALUE (value));
+
+ if ((settings = ide_tweaks_setting_acquire (self, &key, NULL)))
+ {
+ g_autoptr(GVariant) variant = g_settings_get_value (settings, key);
+
+ if (variant != NULL)
+ return g_settings_get_mapping (value, variant, NULL);
+ }
+
+ return FALSE;
+}
+
+static void
+ide_tweaks_setting_set_value (IdeTweaksBinding *binding,
+ const GValue *value)
+{
+ IdeTweaksSetting *self = (IdeTweaksSetting *)binding;
+ g_autoptr(GSettings) settings = NULL;
+ const GVariantType *expected_type = NULL;
+ const char *key = NULL;
+
+ g_assert (IDE_IS_TWEAKS_SETTING (self));
+ g_assert (G_IS_VALUE (value));
+
+ if ((settings = ide_tweaks_setting_acquire (self, &key, &expected_type)))
+ {
+ g_autoptr(GVariant) variant = g_settings_set_mapping (value, expected_type, NULL);
+
+ if (variant != NULL)
+ g_settings_set_value (settings, key, variant);
+ }
+}
+
+static void
+ide_tweaks_setting_dispose (GObject *object)
+{
+ IdeTweaksSetting *self = (IdeTweaksSetting *)object;
+
+ ide_tweaks_setting_release (self);
+ g_clear_pointer (&self->path_suffix, g_free);
+
+ G_OBJECT_CLASS (ide_tweaks_setting_parent_class)->finalize (object);
+}
+
+static void
+ide_tweaks_setting_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTweaksSetting *self = IDE_TWEAKS_SETTING (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCHEMA_ID:
+ g_value_set_static_string (value, ide_tweaks_setting_get_schema_id (self));
+ break;
+
+ case PROP_SCHEMA_KEY:
+ g_value_set_static_string (value, ide_tweaks_setting_get_schema_key (self));
+ break;
+
+ case PROP_PATH_SUFFIX:
+ g_value_set_string (value, ide_tweaks_setting_get_path_suffix (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_tweaks_setting_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTweaksSetting *self = IDE_TWEAKS_SETTING (object);
+
+ switch (prop_id)
+ {
+ case PROP_SCHEMA_ID:
+ ide_tweaks_setting_set_schema_id (self, g_value_get_string (value));
+ break;
+
+ case PROP_SCHEMA_KEY:
+ ide_tweaks_setting_set_schema_key (self, g_value_get_string (value));
+ break;
+
+ case PROP_PATH_SUFFIX:
+ ide_tweaks_setting_set_path_suffix (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_tweaks_setting_class_init (IdeTweaksSettingClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeTweaksBindingClass *tweaks_binding_class = IDE_TWEAKS_BINDING_CLASS (klass);
+
+ object_class->dispose = ide_tweaks_setting_dispose;
+ object_class->get_property = ide_tweaks_setting_get_property;
+ object_class->set_property = ide_tweaks_setting_set_property;
+
+ tweaks_binding_class->get_value = ide_tweaks_setting_get_value;
+ tweaks_binding_class->set_value = ide_tweaks_setting_set_value;
+
+ properties[PROP_SCHEMA_ID] =
+ g_param_spec_string ("schema-id", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_SCHEMA_KEY] =
+ g_param_spec_string ("schema-key", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties[PROP_PATH_SUFFIX] =
+ g_param_spec_string ("path-suffix", NULL, NULL,
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_tweaks_setting_init (IdeTweaksSetting *self)
+{
+}
+
+IdeTweaksSetting *
+ide_tweaks_setting_new (void)
+{
+ return g_object_new (IDE_TYPE_TWEAKS_SETTING, NULL);
+}
+
+const char *
+ide_tweaks_setting_get_schema_id (IdeTweaksSetting *self)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_SETTING (self), NULL);
+
+ return self->schema_id;
+}
+
+void
+ide_tweaks_setting_set_schema_id (IdeTweaksSetting *self,
+ const char *schema_id)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_SETTING (self));
+
+ schema_id = g_intern_string (schema_id);
+
+ if (schema_id != self->schema_id)
+ {
+ ide_tweaks_setting_release (self);
+ self->schema_id = schema_id;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SCHEMA_ID]);
+ }
+}
+
+const char *
+ide_tweaks_setting_get_schema_key (IdeTweaksSetting *self)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_SETTING (self), NULL);
+
+ return self->schema_key;
+}
+
+void
+ide_tweaks_setting_set_schema_key (IdeTweaksSetting *self,
+ const char *schema_key)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_SETTING (self));
+
+ schema_key = g_intern_string (schema_key);
+
+ if (schema_key != self->schema_key)
+ {
+ ide_tweaks_setting_release (self);
+ self->schema_key = schema_key;
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SCHEMA_KEY]);
+ }
+}
+
+const char *
+ide_tweaks_setting_get_path_suffix (IdeTweaksSetting *self)
+{
+ g_return_val_if_fail (IDE_IS_TWEAKS_SETTING (self), NULL);
+
+ return self->path_suffix;
+}
+
+void
+ide_tweaks_setting_set_path_suffix (IdeTweaksSetting *self,
+ const char *path_suffix)
+{
+ g_return_if_fail (IDE_IS_TWEAKS_SETTING (self));
+
+ path_suffix = g_intern_string (path_suffix);
+
+ if (ide_set_string (&self->path_suffix, path_suffix))
+ {
+ ide_tweaks_setting_release (self);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PATH_SUFFIX]);
+ }
+}
diff --git a/src/libide/tweaks/ide-tweaks-setting.h b/src/libide/tweaks/ide-tweaks-setting.h
new file mode 100644
index 000000000..30059dae8
--- /dev/null
+++ b/src/libide/tweaks/ide-tweaks-setting.h
@@ -0,0 +1,54 @@
+/* ide-tweaks-setting.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_TWEAKS_INSIDE) && !defined (IDE_TWEAKS_COMPILATION)
+# error "Only <libide-tweaks.h> can be included directly."
+#endif
+
+#include "ide-tweaks-binding.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TWEAKS_SETTING (ide_tweaks_setting_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeTweaksSetting, ide_tweaks_setting, IDE, TWEAKS_SETTING, IdeTweaksBinding)
+
+IDE_AVAILABLE_IN_ALL
+IdeTweaksSetting *ide_tweaks_setting_new (void);
+IDE_AVAILABLE_IN_ALL
+const char *ide_tweaks_setting_get_schema_id (IdeTweaksSetting *self);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_setting_set_schema_id (IdeTweaksSetting *self,
+ const char *schema_id);
+IDE_AVAILABLE_IN_ALL
+const char *ide_tweaks_setting_get_schema_key (IdeTweaksSetting *self);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_setting_set_schema_key (IdeTweaksSetting *self,
+ const char *schema_key);
+IDE_AVAILABLE_IN_ALL
+const char *ide_tweaks_setting_get_path_suffix (IdeTweaksSetting *self);
+IDE_AVAILABLE_IN_ALL
+void ide_tweaks_setting_set_path_suffix (IdeTweaksSetting *self,
+ const char *path_suffix);
+
+G_END_DECLS
diff --git a/src/libide/tweaks/ide-tweaks-widget.c b/src/libide/tweaks/ide-tweaks-widget.c
index c9f2c6d87..7c5db0279 100644
--- a/src/libide/tweaks/ide-tweaks-widget.c
+++ b/src/libide/tweaks/ide-tweaks-widget.c
@@ -85,7 +85,8 @@ ide_tweaks_widget_copy (IdeTweaksItem *item)
(pspec->flags & G_PARAM_CONSTRUCT_ONLY) != 0)
continue;
- if (g_type_is_a (pspec->value_type, IDE_TYPE_TWEAKS_SETTINGS))
+ if (g_type_is_a (pspec->value_type, IDE_TYPE_TWEAKS_SETTINGS) ||
+ g_type_is_a (pspec->value_type, IDE_TYPE_TWEAKS_BINDING))
clone_item_property (item, copy, pspec->name);
}
diff --git a/src/libide/tweaks/libide-tweaks.h b/src/libide/tweaks/libide-tweaks.h
index d354275c7..380d557d4 100644
--- a/src/libide/tweaks/libide-tweaks.h
+++ b/src/libide/tweaks/libide-tweaks.h
@@ -23,6 +23,7 @@
#define IDE_TWEAKS_INSIDE
# include "ide-tweaks.h"
# include "ide-tweaks-addin.h"
+# include "ide-tweaks-binding.h"
# include "ide-tweaks-caption.h"
# include "ide-tweaks-choice.h"
# include "ide-tweaks-combo.h"
@@ -34,8 +35,10 @@
# include "ide-tweaks-info.h"
# include "ide-tweaks-item.h"
# include "ide-tweaks-page.h"
+# include "ide-tweaks-property.h"
# include "ide-tweaks-radio.h"
# include "ide-tweaks-section.h"
+# include "ide-tweaks-setting.h"
# include "ide-tweaks-settings.h"
# include "ide-tweaks-spin.h"
# include "ide-tweaks-switch.h"
diff --git a/src/libide/tweaks/meson.build b/src/libide/tweaks/meson.build
index a283e522a..3403991e8 100644
--- a/src/libide/tweaks/meson.build
+++ b/src/libide/tweaks/meson.build
@@ -10,6 +10,7 @@ libide_tweaks_public_headers = [
'libide-tweaks.h',
'ide-tweaks.h',
'ide-tweaks-addin.h',
+ 'ide-tweaks-binding.h',
'ide-tweaks-caption.h',
'ide-tweaks-choice.h',
'ide-tweaks-combo.h',
@@ -21,8 +22,10 @@ libide_tweaks_public_headers = [
'ide-tweaks-info.h',
'ide-tweaks-item.h',
'ide-tweaks-page.h',
+ 'ide-tweaks-property.h',
'ide-tweaks-radio.h',
'ide-tweaks-section.h',
+ 'ide-tweaks-setting.h',
'ide-tweaks-settings.h',
'ide-tweaks-spin.h',
'ide-tweaks-switch.h',
@@ -40,6 +43,7 @@ install_headers(libide_tweaks_public_headers, subdir: libide_tweaks_header_subdi
libide_tweaks_public_sources = [
'ide-tweaks.c',
'ide-tweaks-addin.c',
+ 'ide-tweaks-binding.c',
'ide-tweaks-caption.c',
'ide-tweaks-choice.c',
'ide-tweaks-combo.c',
@@ -51,8 +55,10 @@ libide_tweaks_public_sources = [
'ide-tweaks-info.c',
'ide-tweaks-item.c',
'ide-tweaks-page.c',
+ 'ide-tweaks-property.c',
'ide-tweaks-radio.c',
'ide-tweaks-section.c',
+ 'ide-tweaks-setting.c',
'ide-tweaks-settings.c',
'ide-tweaks-spin.c',
'ide-tweaks-switch.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]