[gnome-terminal] all: Add settings schema verifier
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-terminal] all: Add settings schema verifier
- Date: Fri, 4 Jun 2021 18:13:30 +0000 (UTC)
commit cfa851b9e4851805cbcdd477961a6c3b11c4bee5
Author: Christian Persch <chpe src gnome org>
Date: Fri Jun 4 20:13:18 2021 +0200
all: Add settings schema verifier
Add external schemas, and build a reference gschema.compiled. At
startup, verify that the installed compiled schemas conform to that
reference schema; if not, use the reference schema as schema source
instead.
This fixes the problem where, on upgrade, or through an otherwise failed
recompile of the gschemas.compiled cache, where the upgrade to
gnome-terminal added ettings keys, the server will abort when trying to get
that new key.
E.g. https://bugzilla.redhat.com/show_bug.cgi?id=1961775 which is just
the latest instance of this problem occurring.
meson.build | 2 +
src/external.gschema.xml | 143 +++++++++++++++
src/meson.build | 15 ++
src/terminal-app.cc | 11 +-
src/terminal-client-utils.cc | 1 +
src/terminal-util.cc | 421 ++++++++++++++++++++++++++++++++++++++-----
src/terminal-util.hh | 5 +-
7 files changed, 545 insertions(+), 53 deletions(-)
---
diff --git a/meson.build b/meson.build
index 3a430262..d09893ed 100644
--- a/meson.build
+++ b/meson.build
@@ -80,6 +80,7 @@ gt_localedir = get_option('localedir')
gt_prefix = get_option('prefix')
gt_pkgdatadir = gt_datadir / gt_name
+gt_pkglibdir = gt_libdir / gt_name
gt_schemadir = gt_datadir / 'glib-2.0' / 'schemas'
@@ -327,6 +328,7 @@ configure_file(
# Utilities
+glib_compile_schemas = find_program('glib-compile-schemas')
xsltproc = find_program('xsltproc')
# Subdirs
diff --git a/src/external.gschema.xml b/src/external.gschema.xml
new file mode 100644
index 00000000..79c31664
--- /dev/null
+++ b/src/external.gschema.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright © 2021 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/>.
+-->
+<schemalist>
+
+ <!-- From gsettings-desktop-schemas -->
+
+ <schema id="org.gnome.desktop.interface"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/org/gnome/desktop/interface/">
+ <key name="monospace-font-name"
+ type="s">
+ <default>'DejaVu Sans Mono 10'</default>
+ </key>
+ </schema>
+
+ <enum id="org.gnome.desktop.GDesktopProxyMode">
+ <value nick="none"
+ value="0"/>
+ <value nick="manual"
+ value="1"/>
+ <value nick="auto"
+ value="2"/>
+ </enum>
+
+ <schema id="org.gnome.system.proxy.http"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/system/proxy/http/">
+ <key name="host"
+ type="s">
+ <default>''</default>
+ </key>
+ <key name="port"
+ type="i">
+ <range min="0"
+ max="65535" />
+ <default>8080</default>
+ </key>
+ <key name="use-authentication"
+ type="b">
+ <default>false</default>
+ </key>
+ <key name="authentication-user"
+ type="s">
+ <default>''</default>
+ </key>
+ <key name="authentication-password"
+ type="s">
+ <default>''</default>
+ </key>
+ </schema>
+
+ <schema id="org.gnome.system.proxy.https"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/system/proxy/https/">
+ <key name="host"
+ type="s">
+ <default>''</default>
+ </key>
+ <key name="port"
+ type="i">
+ <range min="0"
+ max="65535" />
+ <default>0</default>
+ </key>
+ </schema>
+
+ <schema id="org.gnome.system.proxy.ftp"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/system/proxy/ftp/">
+ <key name="host"
+ type="s">
+ <default>''</default>
+ </key>
+ <key name="port"
+ type="i">
+ <range min="0"
+ max="65535" />
+ <default>0</default>
+ </key>
+ </schema>
+
+ <schema id="org.gnome.system.proxy.socks"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/system/proxy/socks/">
+ <key name="host"
+ type="s">
+ <default>''</default>
+ </key>
+ <key name="port"
+ type="i">
+ <range min="0"
+ max="65535" />
+ <default>0</default>
+ </key>
+ </schema>
+
+ <schema id="org.gnome.system.proxy"
+ gettext-domain="gsettings-desktop-schemas"
+ path="/system/proxy/">
+ <child name="http"
+ schema="org.gnome.system.proxy.http" />
+ <child name="https"
+ schema="org.gnome.system.proxy.https" />
+ <child name="ftp"
+ schema="org.gnome.system.proxy.ftp" />
+ <child name="socks"
+ schema="org.gnome.system.proxy.socks" />
+ <key name="mode"
+ enum="org.gnome.desktop.GDesktopProxyMode">
+ <default>'none'</default>
+ </key>
+ <key name="ignore-hosts"
+ type="as">
+ <default>['localhost', '127.0.0.0/8', '::1']</default>
+ </key>
+ </schema>
+
+ <!-- From gtk+ -->
+
+ <schema id="org.gtk.Settings.Debug"
+ path="/org/gtk/settings/debug/">
+ <key name="enable-inspector-keybinding"
+ type="b">
+ <default>false</default>
+ </key>
+ </schema>
+
+</schemalist>
diff --git a/src/meson.build b/src/meson.build
index fe0c77ce..5491ba5f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -208,6 +208,7 @@ server_cxxflags = [
'-DTERMINAL_COMPILATION',
'-DVTE_DISABLE_DEPRECATION_WARNINGS',
'-DTERM_LOCALEDIR="@0@"'.format(gt_prefix / gt_localedir),
+ '-DTERM_PKGLIBDIR="@0@"'.format(gt_prefix / gt_pkglibdir),
]
server_deps = [
@@ -293,6 +294,7 @@ client_cxxflags = [
'-DTERM_DATADIR="@0@"'.format(gt_prefix / gt_datadir),
'-DTERM_LOCALEDIR="@0@"'.format(gt_prefix / gt_localedir),
'-DTERM_PKGDATADIR="@0@"'.format(gt_prefix / gt_pkgdatadir),
+ '-DTERM_PKGLIBDIR="@0@"'.format(gt_prefix / gt_pkglibdir),
]
client_deps = [
@@ -327,6 +329,19 @@ meson.add_install_script(
gt_prefix / gt_schemadir,
)
+reference_schemas = custom_target(
+ 'gschemas.compiled',
+ command: [
+ glib_compile_schemas,
+ '--targetdir', meson.current_build_dir(),
+ '--schema-file', files(gt_dns_name + '.gschema.xml'),
+ '--schema-file', files('external.gschema.xml'),
+ ],
+ install: true,
+ install_dir: gt_prefix / gt_pkglibdir,
+ output: 'gschemas.compiled',
+)
+
# Nautilus extension
if get_option('nautilus_extension')
diff --git a/src/terminal-app.cc b/src/terminal-app.cc
index 3f456a2e..39d3da16 100644
--- a/src/terminal-app.cc
+++ b/src/terminal-app.cc
@@ -70,8 +70,6 @@
#define GTK_SETTING_PREFER_DARK_THEME "gtk-application-prefer-dark-theme"
#define GTK_DEBUG_SETTING_SCHEMA "org.gtk.Settings.Debug"
-#define GTK_DEBUG_ENABLE_INSPECTOR_KEY "enable-inspector-keybinding"
-#define GTK_DEBUG_ENABLE_INSPECTOR_TYPE G_VARIANT_TYPE_BOOLEAN
#ifdef DISUNIFY_NEW_TERMINAL_SECTION
#error Use a gsettings override instead
@@ -810,7 +808,7 @@ terminal_app_init (TerminalApp *app)
gtk_window_set_default_icon_name (GNOME_TERMINAL_ICON_NAME);
- app->schema_source = g_settings_schema_source_get_default();
+ app->schema_source = terminal_g_settings_schema_source_get_default();
/* Desktop proxy settings */
app->system_proxy_settings = terminal_g_settings_new(app->schema_source,
@@ -845,10 +843,9 @@ terminal_app_init (TerminalApp *app)
TERMINAL_SETTING_SCHEMA);
/* Gtk debug settings */
- app->gtk_debug_settings = terminal_g_settings_new_checked(app->schema_source,
- GTK_DEBUG_SETTING_SCHEMA,
- GTK_DEBUG_ENABLE_INSPECTOR_KEY,
- GTK_DEBUG_ENABLE_INSPECTOR_TYPE);
+ app->gtk_debug_settings = terminal_g_settings_new(app->schema_source,
+ GTK_DEBUG_SETTING_SCHEMA);
+;
/* These are internal settings that exists only for distributions
* to override, so we cache them on startup and don't react to changes.
diff --git a/src/terminal-client-utils.cc b/src/terminal-client-utils.cc
index 4d7ed70d..122ea3b8 100644
--- a/src/terminal-client-utils.cc
+++ b/src/terminal-client-utils.cc
@@ -294,6 +294,7 @@ terminal_g_settings_new_with_path (GSettingsSchemaSource* source,
g_settings_schema_source_lookup(source,
schema_id,
TRUE /* recursive */);
+ g_assert_nonnull(schema);
return g_settings_new_full(schema,
nullptr /* default backend */,
diff --git a/src/terminal-util.cc b/src/terminal-util.cc
index 7fbb1f78..e6f49583 100644
--- a/src/terminal-util.cc
+++ b/src/terminal-util.cc
@@ -773,48 +773,6 @@ s_to_rgba (GVariant *variant,
return TRUE;
}
-/**
- * terminal_g_settings_new_checked:
- * @schema_source: a #GSettingsSchemaSource
- * @schema_id: a settings schema ID
- * @mandatory_key: the name of a key that must exist in the schema
- * @mandatory_key_type: the expected value type of @mandatory_key
- *
- * Creates a #GSettings for @schema_id, if this schema exists and
- * has a key named @mandatory_key (if non-%nullptr) with the value type
- * @mandatory_key_type.
- *
- * Returns: (transfer full): a new #GSettings, or %nullptr
- */
-GSettings *
-terminal_g_settings_new_checked(GSettingsSchemaSource* schema_source,
- const char *schema_id,
- const char *mandatory_key,
- const GVariantType *mandatory_key_type)
-{
- gs_unref_settings_schema GSettingsSchema *schema;
-
- schema = g_settings_schema_source_lookup(schema_source,
- schema_id,
- TRUE);
- if (schema == nullptr)
- return nullptr;
-
- if (mandatory_key) {
- gs_unref_settings_schema_key GSettingsSchemaKey *key;
-
- key = g_settings_schema_get_key (schema, mandatory_key);
- if (key == nullptr)
- return nullptr;
-
- if (!g_variant_type_equal (g_settings_schema_key_get_value_type (key),
- mandatory_key_type))
- return nullptr;
- }
-
- return g_settings_new_full (schema, nullptr, nullptr);
-}
-
/**
* terminal_g_settings_get_rgba:
* @settings: a #GSettings
@@ -1605,3 +1563,382 @@ 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;
+ }
+
+ /* The source interval must be contained within the reference interval */
+ gboolean ok = FALSE;
+
+ if (g_variant_is_of_type(reference_data, G_VARIANT_TYPE("(ii)"))) {
+ int source_min, source_max;
+ g_variant_get(source_data, "(ii)", &source_min, &source_max);
+
+ int reference_min, reference_max;
+ g_variant_get(reference_data, "(ii)", &reference_min, &reference_max);
+
+ ok = (source_min >= reference_min && source_max <= reference_max);
+ } else if (g_variant_is_of_type(reference_data, G_VARIANT_TYPE("(dd)"))) {
+ double source_min, source_max;
+ g_variant_get(source_data, "(dd)", &source_min, &source_max);
+
+ double reference_min, reference_max;
+ g_variant_get(reference_data, "(dd)", &reference_min, &reference_max);
+
+ ok = (source_min >= reference_min && source_max <= reference_max);
+ } else {
+ /* Our schemas don't use this. If that changes, need to implement this! */
+ g_assert_not_reached();
+ }
+
+ if (!ok) {
+ 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_error GError* error = nullptr;
+ GSettingsSchemaSource* reference_source =
+ g_settings_schema_source_new_from_directory(TERM_PKGLIBDIR,
+ 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);
+
+ g_settings_schema_source_unref(reference_source);
+ 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 888a0fb0..f4b7292b 100644
--- a/src/terminal-util.hh
+++ b/src/terminal-util.hh
@@ -71,10 +71,7 @@ char **terminal_util_get_etc_shells (void);
gboolean terminal_util_get_is_shell (const char *command);
-GSettings *terminal_g_settings_new_checked(GSettingsSchemaSource* schema_source,
- const char *schema_id,
- const char *mandatory_key,
- const GVariantType *mandatory_key_type);
+GSettingsSchemaSource* terminal_g_settings_schema_source_get_default(void);
const GdkRGBA *terminal_g_settings_get_rgba (GSettings *settings,
const char *key,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]