[gnome-terminal] settings: Consolidate settings related code into one source file



commit 24371c711ec61943a89eabc36c1450fe7e999930
Author: Christian Persch <chpe src gnome org>
Date:   Fri Aug 26 22:10:31 2022 +0200

    settings: Consolidate settings related code into one source file

 src/meson.build                |   2 +-
 src/terminal-app.cc            |   1 +
 src/terminal-client-utils.cc   |  96 ---------
 src/terminal-client-utils.hh   |   9 -
 src/terminal-settings-list.cc  |   1 +
 src/terminal-settings-utils.cc | 479 ++++++++++++++++++++++++++++++++++++++++-
 src/terminal-settings-utils.hh |  49 ++++-
 src/terminal-util.cc           | 377 --------------------------------
 src/terminal-util.hh           |   2 -
 9 files changed, 522 insertions(+), 494 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index 72ead5ab..6676fbb2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -346,7 +346,7 @@ prefs_main = executable(
 
 # Legacy client
 
-client_sources = client_util_sources + debug_sources + dbus_sources + i18n_sources + profiles_sources + 
types_sources + files(
+client_sources = client_util_sources + debug_sources + dbus_sources + i18n_sources + profiles_sources + 
settings_utils_sources + types_sources + files(
   'terminal-options.cc',
   'terminal-options.hh',
   'terminal.cc',
diff --git a/src/terminal-app.cc b/src/terminal-app.cc
index 4dab8d36..59a4db15 100644
--- a/src/terminal-app.cc
+++ b/src/terminal-app.cc
@@ -36,6 +36,7 @@
 #include "terminal-profiles-list.hh"
 #include "terminal-util.hh"
 #include "terminal-schemas.hh"
+#include "terminal-settings-utils.hh"
 #include "terminal-defines.hh"
 #include "terminal-libgsystem.hh"
 
diff --git a/src/terminal-client-utils.cc b/src/terminal-client-utils.cc
index d20f984a..8604a22d 100644
--- a/src/terminal-client-utils.cc
+++ b/src/terminal-client-utils.cc
@@ -430,99 +430,3 @@ out:
 #endif
   return nullptr;
 }
-
-#ifdef ENABLE_DEBUG
-
-static gboolean
-settings_change_event_cb(GSettings* settings,
-                         void* keys,
-                         int n_keys,
-                         void* data)
-{
-  gs_free char* schema_id = nullptr;
-  gs_free char* path = nullptr;
-  g_object_get(settings,
-               "schema-id", &schema_id,
-               "path", &path,
-               nullptr);
-
-  auto const qkeys = reinterpret_cast<GQuark*>(keys);
-  for (auto i = 0; i < n_keys; ++i) {
-    auto key = g_quark_to_string(qkeys[i]);
-    _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
-                          "Bridge backend ::change-event schema %s path %s key %s\n",
-                          schema_id, path, key);
-  }
-
-  return false; // propagate
-}
-
-static gboolean
-settings_writable_change_event_cb(GSettings* settings,
-                                  char const* key,
-                                  void* data)
-{
-  gs_free char* schema_id = nullptr;
-  gs_free char* path = nullptr;
-  g_object_get(settings,
-               "schema-id", &schema_id,
-               "path", &path,
-               nullptr);
-
-  _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
-                        "Bridge backend ::writeable-change-event schema %s path %s key %s\n",
-                        schema_id, path, key);
-
-  return false; // propagate
-}
-
-#endif /* ENABLE_DEBUG */
-
-GSettings*
-terminal_g_settings_new_with_path (GSettingsBackend* backend,
-                                   GSettingsSchemaSource* source,
-                                   char const* schema_id,
-                                   char const* path)
-{
-  gs_unref_settings_schema GSettingsSchema* schema =
-    g_settings_schema_source_lookup(source,
-                                    schema_id,
-                                    TRUE /* recursive */);
-  g_assert_nonnull(schema);
-
-  auto const settings = g_settings_new_full(schema,
-                                            backend,
-                                            path);
-
-#ifdef ENABLE_DEBUG
-  _TERMINAL_DEBUG_IF(TERMINAL_DEBUG_BRIDGE) {
-
-    _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
-                          "Creating GSettings for schema %s at %s with backend %s\n",
-                          schema_id, path,
-                          backend ? G_OBJECT_TYPE_NAME(backend) : "(default)");
-
-    if (backend != nullptr &&
-        g_str_equal(G_OBJECT_TYPE_NAME(backend), "TerminalSettingsBridgeBackend")) {
-      g_signal_connect(settings,
-                       "change-event",
-                       G_CALLBACK(settings_change_event_cb),
-                       nullptr);
-      g_signal_connect(settings,
-                       "writable-change-event",
-                       G_CALLBACK(settings_writable_change_event_cb),
-                       nullptr);
-    }
-  }
-#endif /* ENABLE_DEBUG */
-
-  return settings;
-}
-
-GSettings*
-terminal_g_settings_new(GSettingsBackend* backend,
-                        GSettingsSchemaSource* source,
-                        char const* schema_id)
-{
-  return terminal_g_settings_new_with_path(backend, source, schema_id, nullptr);
-}
diff --git a/src/terminal-client-utils.hh b/src/terminal-client-utils.hh
index ed556de5..33e5c909 100644
--- a/src/terminal-client-utils.hh
+++ b/src/terminal-client-utils.hh
@@ -65,15 +65,6 @@ char const* const* terminal_client_get_environment_prefix_filters (void);
 
 char** terminal_client_filter_environment           (char** envv) G_GNUC_MALLOC;
 
-GSettings* terminal_g_settings_new (GSettingsBackend* backend,
-                                    GSettingsSchemaSource* source,
-                                    char const* schema_id);
-
-GSettings* terminal_g_settings_new_with_path (GSettingsBackend* backend,
-                                              GSettingsSchemaSource* source,
-                                              char const* schema_id,
-                                              char const* path);
-
 G_END_DECLS
 
 #endif /* TERMINAL_UTIL_UTILS_H */
diff --git a/src/terminal-settings-list.cc b/src/terminal-settings-list.cc
index 03f85999..12d74a4a 100644
--- a/src/terminal-settings-list.cc
+++ b/src/terminal-settings-list.cc
@@ -27,6 +27,7 @@
 #include <gio/gsettingsbackend.h>
 
 #include "terminal-type-builtins.hh"
+#include "terminal-settings-utils.hh"
 #include "terminal-schemas.hh"
 #include "terminal-debug.hh"
 #include "terminal-dconf.hh"
diff --git a/src/terminal-settings-utils.cc b/src/terminal-settings-utils.cc
index 9110d4b5..0b52ef8a 100644
--- a/src/terminal-settings-utils.cc
+++ b/src/terminal-settings-utils.cc
@@ -19,8 +19,483 @@
 #define G_SETTINGS_ENABLE_BACKEND
 
 #include "terminal-settings-utils.hh"
+#include "terminal-client-utils.hh"
+#include "terminal-debug.hh"
+#include "terminal-libgsystem.hh"
 
-#include <gio/gio.h>
+#ifdef ENABLE_DEBUG
+
+static gboolean
+settings_change_event_cb(GSettings* settings,
+                         void* keys,
+                         int n_keys,
+                         void* data)
+{
+  gs_free char* schema_id = nullptr;
+  gs_free char* path = nullptr;
+  g_object_get(settings,
+               "schema-id", &schema_id,
+               "path", &path,
+               nullptr);
+
+  auto const qkeys = reinterpret_cast<GQuark*>(keys);
+  for (auto i = 0; i < n_keys; ++i) {
+    auto key = g_quark_to_string(qkeys[i]);
+    _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
+                          "Bridge backend ::change-event schema %s path %s key %s\n",
+                          schema_id, path, key);
+  }
+
+  return false; // propagate
+}
+
+static gboolean
+settings_writable_change_event_cb(GSettings* settings,
+                                  char const* key,
+                                  void* data)
+{
+  gs_free char* schema_id = nullptr;
+  gs_free char* path = nullptr;
+  g_object_get(settings,
+               "schema-id", &schema_id,
+               "path", &path,
+               nullptr);
+
+  _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
+                        "Bridge backend ::writeable-change-event schema %s path %s key %s\n",
+                        schema_id, path, key);
+
+  return false; // propagate
+}
+
+#endif /* ENABLE_DEBUG */
+
+GSettings*
+terminal_g_settings_new_with_path (GSettingsBackend* backend,
+                                   GSettingsSchemaSource* source,
+                                   char const* schema_id,
+                                   char const* path)
+{
+  gs_unref_settings_schema GSettingsSchema* schema =
+    g_settings_schema_source_lookup(source,
+                                    schema_id,
+                                    TRUE /* recursive */);
+  g_assert_nonnull(schema);
+
+  auto const settings = g_settings_new_full(schema,
+                                            backend,
+                                            path);
+
+#ifdef ENABLE_DEBUG
+  _TERMINAL_DEBUG_IF(TERMINAL_DEBUG_BRIDGE) {
+
+    _terminal_debug_print(TERMINAL_DEBUG_BRIDGE,
+                          "Creating GSettings for schema %s at %s with backend %s\n",
+                          schema_id, path,
+                          backend ? G_OBJECT_TYPE_NAME(backend) : "(default)");
+
+    if (backend != nullptr &&
+        g_str_equal(G_OBJECT_TYPE_NAME(backend), "TerminalSettingsBridgeBackend")) {
+      g_signal_connect(settings,
+                       "change-event",
+                       G_CALLBACK(settings_change_event_cb),
+                       nullptr);
+      g_signal_connect(settings,
+                       "writable-change-event",
+                       G_CALLBACK(settings_writable_change_event_cb),
+                       nullptr);
+    }
+  }
+#endif /* ENABLE_DEBUG */
+
+  return settings;
+}
+
+GSettings*
+terminal_g_settings_new(GSettingsBackend* backend,
+                        GSettingsSchemaSource* source,
+                        char const* schema_id)
+{
+  return terminal_g_settings_new_with_path(backend, source, schema_id, nullptr);
+}
+
+#if defined(TERMINAL_SERVER) || defined(TERMINAL_PREFERENCES)
+
+#define TERMINAL_SCHEMA_VERIFIER_ERROR (g_quark_from_static_string("TerminalSchemaVerifier"))
+
+typedef enum {
+  TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING,
+  TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH,
+  TERMINAL_SCHEMA_VERIFIER_KEY_MISSING,
+  TERMINAL_SCHEMA_VERIFIER_KEY_TYPE,
+  TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE,
+  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL,
+  TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING,
+} TerminalSchemaVerifierError;
+
+static gboolean
+strv_contains(char const* const* strv,
+              char const* str)
+{
+  if (strv == nullptr)
+    return FALSE;
+
+  for (size_t i = 0; strv[i]; i++) {
+    if (g_str_equal (strv[i], str))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+schema_key_range_compatible(GSettingsSchema* source_schema,
+                            GSettingsSchemaKey* source_key,
+                            char const* key,
+                            GSettingsSchemaKey* reference_key,
+                            GError** error)
+{
+  gs_unref_variant GVariant* source_range =
+    g_settings_schema_key_get_range(source_key);
+  gs_unref_variant GVariant* reference_range =
+    g_settings_schema_key_get_range(reference_key);
+
+  char const* source_type = nullptr;
+  gs_unref_variant GVariant* source_data = nullptr;
+  g_variant_get(source_range, "(&sv)", &source_type, &source_data);
+
+  char const* reference_type = nullptr;
+  gs_unref_variant GVariant* reference_data = nullptr;
+  g_variant_get(reference_range, "(&sv)", &reference_type, &reference_data);
+
+  if (!g_str_equal(source_type, reference_type)) {
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE,
+                "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"",
+                g_settings_schema_get_id(source_schema),
+                key, source_type, reference_type);
+    return FALSE;
+  }
+
+  if (g_str_equal(reference_type, "type"))
+    ; /* no constraints; this is fine */
+  else if (g_str_equal(reference_type, "enum")) {
+    size_t source_values_len = 0;
+    gs_free char const** source_values = g_variant_get_strv(source_data, &source_values_len);
+
+    size_t reference_values_len = 0;
+    gs_free char const** reference_values = g_variant_get_strv(reference_data, &reference_values_len);
+
+    /* Check that every enum value in source is valid according to the reference */
+    for (size_t i = 0; i < source_values_len; ++i) {
+      if (!strv_contains(reference_values, source_values[i])) {
+        g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                    TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE,
+                    "Schema \"%s\" key \"%s\" has enum value \"%s\" not in reference schema",
+                    g_settings_schema_get_id(source_schema),
+                    key, source_values[i]);
+        return FALSE;
+      }
+    }
+  } else if (g_str_equal(reference_type, "flags")) {
+    /* Our schemas don't use flags. If that changes, need to implement this! */
+    g_assert_not_reached();
+  } else if (g_str_equal(reference_type, "range")) {
+    if (!g_variant_is_of_type(source_data,
+                              g_variant_get_type(reference_data))) {
+      char const* source_type_str = g_variant_get_type_string(source_data);
+      char const* reference_type_str = g_variant_get_type_string(reference_data);
+      g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH,
+                  "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"",
+                  g_settings_schema_get_id(source_schema),
+                  key, source_type_str, reference_type_str);
+      return FALSE;
+    }
+
+    gs_unref_variant GVariant* reference_min = nullptr;
+    gs_unref_variant GVariant* reference_max = nullptr;
+    g_variant_get(reference_data, "(**)", &reference_min, &reference_max);
+
+    gs_unref_variant GVariant* source_min = nullptr;
+    gs_unref_variant GVariant* source_max = nullptr;
+    g_variant_get(source_data, "(**)", &source_min, &source_max);
+
+    /* The source interval must be contained within the reference interval */
+    if (g_variant_compare(source_min, reference_min) < 0 ||
+        g_variant_compare(source_max, reference_max) > 0) {
+      g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL,
+                  "Schema \"%s\" key \"%s\" has range interval not contained in reference range interval",
+                  g_settings_schema_get_id(source_schema), key);
+        return FALSE;
+    }
+  } else {
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN,
+                "Schema \"%s\" key \"%s\" has unknown range type \"%s\"",
+                g_settings_schema_get_id(source_schema),
+                key, reference_type);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+schema_verify_key(GSettingsSchema* source_schema,
+                  char const* key,
+                  GSettingsSchema* reference_schema,
+                  GError** error)
+{
+  if (!g_settings_schema_has_key(source_schema, key)) {
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_KEY_MISSING,
+                "Schema \"%s\" has missing key \"%s\"",
+                g_settings_schema_get_id(source_schema), key);
+    return FALSE;
+  }
+
+  gs_unref_settings_schema_key GSettingsSchemaKey* source_key =
+    g_settings_schema_get_key(source_schema, key);
+  g_assert_nonnull(source_key);
+
+  gs_unref_settings_schema_key GSettingsSchemaKey* reference_key =
+    g_settings_schema_get_key(reference_schema, key);
+  g_assert_nonnull(reference_key);
+
+  GVariantType const* source_type = g_settings_schema_key_get_value_type(source_key);
+  GVariantType const* reference_type = g_settings_schema_key_get_value_type(reference_key);
+  if (!g_variant_type_equal(source_type, reference_type)) {
+    gs_free char* source_type_str = g_variant_type_dup_string(source_type);
+    gs_free char* reference_type_str = g_variant_type_dup_string(reference_type);
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_KEY_TYPE,
+                "Schema \"%s\" has type \"%s\" but reference type is \"%s\"",
+                g_settings_schema_get_id(source_schema),
+                source_type_str, reference_type_str);
+    return FALSE;
+  }
+
+  gs_unref_variant GVariant* source_default = g_settings_schema_key_get_default_value(source_key);
+  if (!g_settings_schema_key_range_check(reference_key, source_default)) {
+    gs_free char* source_value_str = g_variant_print(source_default, TRUE);
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT,
+                "Schema \"%s\" default value \"%s\" does not conform to reference schema",
+                g_settings_schema_get_id(source_schema), source_value_str);
+    return FALSE;
+  }
+
+  if (!schema_key_range_compatible(source_schema,
+                                   source_key,
+                                   key,
+                                   reference_key,
+                                   error))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+schema_verify_child(GSettingsSchema* source_schema,
+                    char const* child_name,
+                    GSettingsSchema* reference_schema,
+                    GError** error)
+{
+  /* Should verify the child's schema ID is as expected and exists in
+   * the source, but there appears to be no API to get the schema ID of
+   * the child.
+   *
+   * We work around this missing verification by never calling
+   * g_settings_get_child() and instead always constructing the child
+   * GSettings directly; and the existence and correctness of that
+   * schema is verified by the per-schema checks.
+   */
+
+  return TRUE;
+}
+
+static gboolean
+schema_verify(GSettingsSchema* source_schema,
+              GSettingsSchema* reference_schema,
+              GError** error)
+{
+  /* Verify path */
+  char const* source_path = g_settings_schema_get_path(source_schema);
+  char const* reference_path = g_settings_schema_get_path(reference_schema);
+  if (g_strcmp0(source_path, reference_path) != 0) {
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH,
+                "Schema \"%s\" has path \"%s\" but reference path is \"%s\"",
+                g_settings_schema_get_id(source_schema),
+                source_path ? source_path : "(null)",
+                reference_path ? reference_path : "(null)");
+    return FALSE;
+  }
+
+  /* Verify keys */
+  gs_strfreev char** keys = g_settings_schema_list_keys(reference_schema);
+  if (keys) {
+    for (int i = 0; keys[i]; ++i) {
+      if (!schema_verify_key(source_schema,
+                             keys[i],
+                             reference_schema,
+                             error))
+        return FALSE;
+    }
+  }
+
+  /* Verify child schemas */
+  gs_strfreev char** source_children = g_settings_schema_list_children(source_schema);
+  gs_strfreev char** reference_children = g_settings_schema_list_children(reference_schema);
+  if (reference_children) {
+    for (size_t i = 0; reference_children[i]; ++i) {
+      if (!strv_contains((char const* const*)source_children, reference_children[i])) {
+        g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                    TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING,
+                    "Schema \"%s\" has missing child \"%s\"",
+                    g_settings_schema_get_id(source_schema),
+                    reference_children[i]);
+        return FALSE;
+      }
+
+      if (!schema_verify_child(source_schema,
+                               reference_children[i],
+                               reference_schema,
+                               error))
+          return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
+schemas_source_verify_schema_by_name(GSettingsSchemaSource* source,
+                                     char const* schema_name,
+                                     GSettingsSchemaSource* reference_source,
+                                     GError** error)
+{
+  gs_unref_settings_schema GSettingsSchema* source_schema =
+    g_settings_schema_source_lookup(source, schema_name, TRUE /* recursive */);
+
+  if (!source_schema) {
+    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
+                TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING,
+                "Schema \"%s\" is missing", schema_name);
+    return FALSE;
+  }
+
+  gs_unref_settings_schema GSettingsSchema* reference_schema =
+    g_settings_schema_source_lookup(reference_source,
+                                    schema_name,
+                                    FALSE /* recursive */);
+  g_assert_nonnull(reference_schema);
+
+  return schema_verify(source_schema,
+                       reference_schema,
+                       error);
+}
+
+static gboolean
+schemas_source_verify_schemas(GSettingsSchemaSource* source,
+                              char const* const* schemas,
+                              GSettingsSchemaSource* reference_source,
+                              GError** error)
+{
+  if (!schemas)
+    return TRUE;
+
+  for (int i = 0; schemas[i]; ++i) {
+    if (!schemas_source_verify_schema_by_name(source,
+                                              schemas[i],
+                                              reference_source,
+                                              error))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+schemas_source_verify(GSettingsSchemaSource* source,
+                      GSettingsSchemaSource* reference_source,
+                      GError** error)
+{
+  gs_strfreev char** reloc_schemas = nullptr;
+  gs_strfreev char** nonreloc_schemas = nullptr;
+
+  g_settings_schema_source_list_schemas(reference_source,
+                                        FALSE /* recursive */,
+                                        &reloc_schemas,
+                                        &nonreloc_schemas);
+
+  if (!schemas_source_verify_schemas(source,
+                                     (char const* const*)reloc_schemas,
+                                     reference_source,
+                                     error))
+    return FALSE;
+
+  if (!schemas_source_verify_schemas(source,
+                                     (char const* const*)nonreloc_schemas,
+                                     reference_source,
+                                     error))
+    return FALSE;
+
+  return TRUE;
+}
+
+GSettingsSchemaSource*
+terminal_g_settings_schema_source_get_default(void)
+{
+  GSettingsSchemaSource* default_source = g_settings_schema_source_get_default();
+
+  gs_free auto schema_dir =
+    terminal_client_get_directory_uninstalled(
+#if defined(TERMINAL_SERVER)
+                                              TERM_LIBEXECDIR,
+#elif defined(TERMINAL_PREFERENCES)
+                                              TERM_PKGLIBDIR,
+#else
+#error Need to define installed location
+#endif
+                                              TERM_PKGLIBDIR,
+                                              "gschemas.compiled",
+                                              GFileTest(0));
+
+  gs_free_error GError* error = nullptr;
+  GSettingsSchemaSource* reference_source =
+    g_settings_schema_source_new_from_directory(schema_dir,
+                                                nullptr /* parent source */,
+                                                FALSE /* trusted */,
+                                                &error);
+  if (!reference_source)  {
+    /* Can only use the installed schemas, or abort here. */
+    g_printerr("Failed to load reference schemas: %s\n"
+               "Using unverified installed schemas.\n",
+               error->message);
+
+    return g_settings_schema_source_ref(default_source);
+  }
+
+  if (!schemas_source_verify(default_source, reference_source, &error)) {
+    g_printerr("Installed schemas failed verification: %s\n"
+               "Falling back to built-in reference schemas.\n",
+               error->message);
+
+    return reference_source; /* transfer */
+  }
+
+  /* Installed schemas verified; use them. */
+  g_settings_schema_source_unref(reference_source);
+  return g_settings_schema_source_ref(default_source);
+}
 
 // BEGIN copied from glib/gio/gsettingsbackend.c
 
@@ -354,3 +829,5 @@ terminal_g_settings_backend_sync(GSettingsBackend* backend)
 }
 
 // END copied from glib
+
+#endif /* TERMINAL_SERVER || TERMINAL_PREFERENCES */
diff --git a/src/terminal-settings-utils.hh b/src/terminal-settings-utils.hh
index a64712b9..90ca6256 100644
--- a/src/terminal-settings-utils.hh
+++ b/src/terminal-settings-utils.hh
@@ -1,3 +1,40 @@
+/*
+ * Copyright © 2008, 2010, 2022 Christian Persch
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+#include <gio/gsettingsbackend.h>
+
+GSettings* terminal_g_settings_new (GSettingsBackend* backend,
+                                    GSettingsSchemaSource* source,
+                                    char const* schema_id);
+
+GSettings* terminal_g_settings_new_with_path (GSettingsBackend* backend,
+                                              GSettingsSchemaSource* source,
+                                              char const* schema_id,
+                                              char const* path);
+
+GSettingsSchemaSource* terminal_g_settings_schema_source_get_default(void);
+
+GTree* terminal_g_settings_backend_create_tree(void);
+
+// BEGIN copied from glib/gio/gsettingsbackendinternal.h
+
 /*
  * Copyright © 2009, 2010 Codethink Limited
  * Copyright © 2010 Red Hat, Inc.
@@ -19,12 +56,6 @@
  *          Matthias Clasen <mclasen redhat com>
  */
 
-#pragma once
-
-#include <gio/gsettingsbackend.h>
-
-GTree* terminal_g_settings_backend_create_tree(void);
-
 GPermission* terminal_g_settings_backend_get_permission(GSettingsBackend* backend,
                                                         char const*path);
 
@@ -58,5 +89,7 @@ gboolean terminal_g_settings_backend_write(GSettingsBackend* backend,
                                            void* origin_tag);
 
 gboolean terminal_g_settings_backend_write_tree(GSettingsBackend* backend,
-                                                      GTree*tree,
-                                                      void* origin_tag);
+                                                GTree* tree,
+                                                void* origin_tag);
+
+// END copied from glib
diff --git a/src/terminal-util.cc b/src/terminal-util.cc
index 36554315..b430efca 100644
--- a/src/terminal-util.cc
+++ b/src/terminal-util.cc
@@ -1570,380 +1570,3 @@ terminal_util_check_envv(char const* const* strv)
 
   return TRUE;
 }
-
-#define TERMINAL_SCHEMA_VERIFIER_ERROR (g_quark_from_static_string("TerminalSchemaVerifier"))
-
-typedef enum {
-  TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING,
-  TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH,
-  TERMINAL_SCHEMA_VERIFIER_KEY_MISSING,
-  TERMINAL_SCHEMA_VERIFIER_KEY_TYPE,
-  TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE,
-  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL,
-  TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING,
-} TerminalSchemaVerifierError;
-
-static gboolean
-strv_contains(char const* const* strv,
-              char const* str)
-{
-  if (strv == nullptr)
-    return FALSE;
-
-  for (size_t i = 0; strv[i]; i++) {
-    if (g_str_equal (strv[i], str))
-      return TRUE;
-  }
-
-  return FALSE;
-}
-
-static gboolean
-schema_key_range_compatible(GSettingsSchema* source_schema,
-                            GSettingsSchemaKey* source_key,
-                            char const* key,
-                            GSettingsSchemaKey* reference_key,
-                            GError** error)
-{
-  gs_unref_variant GVariant* source_range =
-    g_settings_schema_key_get_range(source_key);
-  gs_unref_variant GVariant* reference_range =
-    g_settings_schema_key_get_range(reference_key);
-
-  char const* source_type = nullptr;
-  gs_unref_variant GVariant* source_data = nullptr;
-  g_variant_get(source_range, "(&sv)", &source_type, &source_data);
-
-  char const* reference_type = nullptr;
-  gs_unref_variant GVariant* reference_data = nullptr;
-  g_variant_get(reference_range, "(&sv)", &reference_type, &reference_data);
-
-  if (!g_str_equal(source_type, reference_type)) {
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE,
-                "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"",
-                g_settings_schema_get_id(source_schema),
-                key, source_type, reference_type);
-    return FALSE;
-  }
-
-  if (g_str_equal(reference_type, "type"))
-    ; /* no constraints; this is fine */
-  else if (g_str_equal(reference_type, "enum")) {
-    size_t source_values_len = 0;
-    gs_free char const** source_values = g_variant_get_strv(source_data, &source_values_len);
-
-    size_t reference_values_len = 0;
-    gs_free char const** reference_values = g_variant_get_strv(reference_data, &reference_values_len);
-
-    /* Check that every enum value in source is valid according to the reference */
-    for (size_t i = 0; i < source_values_len; ++i) {
-      if (!strv_contains(reference_values, source_values[i])) {
-        g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                    TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE,
-                    "Schema \"%s\" key \"%s\" has enum value \"%s\" not in reference schema",
-                    g_settings_schema_get_id(source_schema),
-                    key, source_values[i]);
-        return FALSE;
-      }
-    }
-  } else if (g_str_equal(reference_type, "flags")) {
-    /* Our schemas don't use flags. If that changes, need to implement this! */
-    g_assert_not_reached();
-  } else if (g_str_equal(reference_type, "range")) {
-    if (!g_variant_is_of_type(source_data,
-                              g_variant_get_type(reference_data))) {
-      char const* source_type_str = g_variant_get_type_string(source_data);
-      char const* reference_type_str = g_variant_get_type_string(reference_data);
-      g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH,
-                  "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"",
-                  g_settings_schema_get_id(source_schema),
-                  key, source_type_str, reference_type_str);
-      return FALSE;
-    }
-
-    gs_unref_variant GVariant* reference_min = nullptr;
-    gs_unref_variant GVariant* reference_max = nullptr;
-    g_variant_get(reference_data, "(**)", &reference_min, &reference_max);
-
-    gs_unref_variant GVariant* source_min = nullptr;
-    gs_unref_variant GVariant* source_max = nullptr;
-    g_variant_get(source_data, "(**)", &source_min, &source_max);
-
-    /* The source interval must be contained within the reference interval */
-    if (g_variant_compare(source_min, reference_min) < 0 ||
-        g_variant_compare(source_max, reference_max) > 0) {
-      g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                  TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL,
-                  "Schema \"%s\" key \"%s\" has range interval not contained in reference range interval",
-                  g_settings_schema_get_id(source_schema), key);
-        return FALSE;
-    }
-  } else {
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN,
-                "Schema \"%s\" key \"%s\" has unknown range type \"%s\"",
-                g_settings_schema_get_id(source_schema),
-                key, reference_type);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-static gboolean
-schema_verify_key(GSettingsSchema* source_schema,
-                  char const* key,
-                  GSettingsSchema* reference_schema,
-                  GError** error)
-{
-  if (!g_settings_schema_has_key(source_schema, key)) {
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_KEY_MISSING,
-                "Schema \"%s\" has missing key \"%s\"",
-                g_settings_schema_get_id(source_schema), key);
-    return FALSE;
-  }
-
-  gs_unref_settings_schema_key GSettingsSchemaKey* source_key =
-    g_settings_schema_get_key(source_schema, key);
-  g_assert_nonnull(source_key);
-
-  gs_unref_settings_schema_key GSettingsSchemaKey* reference_key =
-    g_settings_schema_get_key(reference_schema, key);
-  g_assert_nonnull(reference_key);
-
-  GVariantType const* source_type = g_settings_schema_key_get_value_type(source_key);
-  GVariantType const* reference_type = g_settings_schema_key_get_value_type(reference_key);
-  if (!g_variant_type_equal(source_type, reference_type)) {
-    gs_free char* source_type_str = g_variant_type_dup_string(source_type);
-    gs_free char* reference_type_str = g_variant_type_dup_string(reference_type);
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_KEY_TYPE,
-                "Schema \"%s\" has type \"%s\" but reference type is \"%s\"",
-                g_settings_schema_get_id(source_schema),
-                source_type_str, reference_type_str);
-    return FALSE;
-  }
-
-  gs_unref_variant GVariant* source_default = g_settings_schema_key_get_default_value(source_key);
-  if (!g_settings_schema_key_range_check(reference_key, source_default)) {
-    gs_free char* source_value_str = g_variant_print(source_default, TRUE);
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT,
-                "Schema \"%s\" default value \"%s\" does not conform to reference schema",
-                g_settings_schema_get_id(source_schema), source_value_str);
-    return FALSE;
-  }
-
-  if (!schema_key_range_compatible(source_schema,
-                                   source_key,
-                                   key,
-                                   reference_key,
-                                   error))
-    return FALSE;
-
-  return TRUE;
-}
-
-static gboolean
-schema_verify_child(GSettingsSchema* source_schema,
-                    char const* child_name,
-                    GSettingsSchema* reference_schema,
-                    GError** error)
-{
-  /* Should verify the child's schema ID is as expected and exists in
-   * the source, but there appears to be no API to get the schema ID of
-   * the child.
-   *
-   * We work around this missing verification by never calling
-   * g_settings_get_child() and instead always constructing the child
-   * GSettings directly; and the existence and correctness of that
-   * schema is verified by the per-schema checks.
-   */
-
-  return TRUE;
-}
-
-static gboolean
-schema_verify(GSettingsSchema* source_schema,
-              GSettingsSchema* reference_schema,
-              GError** error)
-{
-  /* Verify path */
-  char const* source_path = g_settings_schema_get_path(source_schema);
-  char const* reference_path = g_settings_schema_get_path(reference_schema);
-  if (g_strcmp0(source_path, reference_path) != 0) {
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH,
-                "Schema \"%s\" has path \"%s\" but reference path is \"%s\"",
-                g_settings_schema_get_id(source_schema),
-                source_path ? source_path : "(null)",
-                reference_path ? reference_path : "(null)");
-    return FALSE;
-  }
-
-  /* Verify keys */
-  gs_strfreev char** keys = g_settings_schema_list_keys(reference_schema);
-  if (keys) {
-    for (int i = 0; keys[i]; ++i) {
-      if (!schema_verify_key(source_schema,
-                             keys[i],
-                             reference_schema,
-                             error))
-        return FALSE;
-    }
-  }
-
-  /* Verify child schemas */
-  gs_strfreev char** source_children = g_settings_schema_list_children(source_schema);
-  gs_strfreev char** reference_children = g_settings_schema_list_children(reference_schema);
-  if (reference_children) {
-    for (size_t i = 0; reference_children[i]; ++i) {
-      if (!strv_contains((char const* const*)source_children, reference_children[i])) {
-        g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                    TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING,
-                    "Schema \"%s\" has missing child \"%s\"",
-                    g_settings_schema_get_id(source_schema),
-                    reference_children[i]);
-        return FALSE;
-      }
-
-      if (!schema_verify_child(source_schema,
-                               reference_children[i],
-                               reference_schema,
-                               error))
-          return FALSE;
-    }
-  }
-
-  return TRUE;
-}
-
-static gboolean
-schemas_source_verify_schema_by_name(GSettingsSchemaSource* source,
-                                     char const* schema_name,
-                                     GSettingsSchemaSource* reference_source,
-                                     GError** error)
-{
-  gs_unref_settings_schema GSettingsSchema* source_schema =
-    g_settings_schema_source_lookup(source, schema_name, TRUE /* recursive */);
-
-  if (!source_schema) {
-    g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR,
-                TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING,
-                "Schema \"%s\" is missing", schema_name);
-    return FALSE;
-  }
-
-  gs_unref_settings_schema GSettingsSchema* reference_schema =
-    g_settings_schema_source_lookup(reference_source,
-                                    schema_name,
-                                    FALSE /* recursive */);
-  g_assert_nonnull(reference_schema);
-
-  return schema_verify(source_schema,
-                       reference_schema,
-                       error);
-}
-
-static gboolean
-schemas_source_verify_schemas(GSettingsSchemaSource* source,
-                              char const* const* schemas,
-                              GSettingsSchemaSource* reference_source,
-                              GError** error)
-{
-  if (!schemas)
-    return TRUE;
-
-  for (int i = 0; schemas[i]; ++i) {
-    if (!schemas_source_verify_schema_by_name(source,
-                                              schemas[i],
-                                              reference_source,
-                                              error))
-      return FALSE;
-  }
-
-  return TRUE;
-}
-
-static gboolean
-schemas_source_verify(GSettingsSchemaSource* source,
-                      GSettingsSchemaSource* reference_source,
-                      GError** error)
-{
-  gs_strfreev char** reloc_schemas = nullptr;
-  gs_strfreev char** nonreloc_schemas = nullptr;
-
-  g_settings_schema_source_list_schemas(reference_source,
-                                        FALSE /* recursive */,
-                                        &reloc_schemas,
-                                        &nonreloc_schemas);
-
-  if (!schemas_source_verify_schemas(source,
-                                     (char const* const*)reloc_schemas,
-                                     reference_source,
-                                     error))
-    return FALSE;
-
-  if (!schemas_source_verify_schemas(source,
-                                     (char const* const*)nonreloc_schemas,
-                                     reference_source,
-                                     error))
-    return FALSE;
-
-  return TRUE;
-}
-
-
-GSettingsSchemaSource*
-terminal_g_settings_schema_source_get_default(void)
-{
-  GSettingsSchemaSource* default_source = g_settings_schema_source_get_default();
-
-  gs_free auto schema_dir =
-    terminal_client_get_directory_uninstalled(
-#if defined(TERMINAL_SERVER)
-                                              TERM_LIBEXECDIR,
-#elif defined(TERMINAL_PREFERENCES)
-                                              TERM_PKGLIBDIR,
-#else
-#error Need to define installed location
-#endif
-                                              TERM_PKGLIBDIR,
-                                              "gschemas.compiled",
-                                              GFileTest(0));
-
-  gs_free_error GError* error = nullptr;
-  GSettingsSchemaSource* reference_source =
-    g_settings_schema_source_new_from_directory(schema_dir,
-                                                nullptr /* parent source */,
-                                                FALSE /* trusted */,
-                                                &error);
-  if (!reference_source)  {
-    /* Can only use the installed schemas, or abort here. */
-    g_printerr("Failed to load reference schemas: %s\n"
-               "Using unverified installed schemas.\n",
-               error->message);
-
-    return g_settings_schema_source_ref(default_source);
-  }
-
-  if (!schemas_source_verify(default_source, reference_source, &error)) {
-    g_printerr("Installed schemas failed verification: %s\n"
-               "Falling back to built-in reference schemas.\n",
-               error->message);
-
-    return reference_source; /* transfer */
-  }
-
-  /* Installed schemas verified; use them. */
-  g_settings_schema_source_unref(reference_source);
-  return g_settings_schema_source_ref(default_source);
-}
diff --git a/src/terminal-util.hh b/src/terminal-util.hh
index f4b7292b..d980725e 100644
--- a/src/terminal-util.hh
+++ b/src/terminal-util.hh
@@ -71,8 +71,6 @@ char **terminal_util_get_etc_shells (void);
 
 gboolean terminal_util_get_is_shell (const char *command);
 
-GSettingsSchemaSource* terminal_g_settings_schema_source_get_default(void);
-
 const GdkRGBA *terminal_g_settings_get_rgba (GSettings  *settings,
                                              const char *key,
                                              GdkRGBA    *rgba);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]