summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2022-08-26 22:10:31 +0200
committerChristian Persch <chpe@src.gnome.org>2022-08-26 22:10:31 +0200
commit24371c711ec61943a89eabc36c1450fe7e999930 (patch)
tree6942e15e6ca14bd5016d0aff6a8eec9f19b0ae9c /src
parent267e79ee128a956da7769882e5c7d29967cebac6 (diff)
downloadgnome-terminal-24371c711ec61943a89eabc36c1450fe7e999930.tar.gz
settings: Consolidate settings related code into one source file
Diffstat (limited to 'src')
-rw-r--r--src/meson.build2
-rw-r--r--src/terminal-app.cc1
-rw-r--r--src/terminal-client-utils.cc96
-rw-r--r--src/terminal-client-utils.hh9
-rw-r--r--src/terminal-settings-list.cc1
-rw-r--r--src/terminal-settings-utils.cc479
-rw-r--r--src/terminal-settings-utils.hh49
-rw-r--r--src/terminal-util.cc377
-rw-r--r--src/terminal-util.hh2
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,4 +1,41 @@
/*
+ * 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);