1/**
2 * Since Nix does not have a standard location like /usr/share where GSettings system
3 * could look for schemas, we need to point the software to a correct location somehow.
4 * For executables, we handle this using wrappers but this is not an option for libraries like e-d-s.
5 * Instead, we patch the source code to look for the schema in a schema source
6 * through a hardcoded path to the schema.
7 *
8 * For each schema id referenced in the source code (e.g. org.gnome.evolution),
9 * a variable name such as `EVOLUTION` must be provided in the ./glib-schema-to-var.json JSON file.
10 * It will end up in the resulting patch as `@EVOLUTION@` placeholder, which should be replaced at build time
11 * with a path to the directory containing a `gschemas.compiled` file that includes the schema.
12 */
13
14@initialize:python@
15@@
16import json
17
18cpp_constants = {}
19
20def register_cpp_constant(const_name, val):
21 cpp_constants[const_name] = val.strip()
22
23def resolve_cpp_constant(const_name):
24 return cpp_constants.get(const_name, const_name)
25
26with open("./glib-schema-to-var.json") as mapping_file:
27 schema_to_var = json.load(mapping_file);
28
29def get_schema_directory(schema_id):
30 # Sometimes the schema id is referenced using C preprocessor #define constant in the same file
31 # let’s try to resolve it first.
32 schema_id = resolve_cpp_constant(schema_id.strip()).strip('"')
33 if schema_id in schema_to_var:
34 return f'"@{schema_to_var[schema_id]}@"'
35 raise Exception(f"Unknown schema path {schema_id!r}, please add it to ./glib-schema-to-var.json")
36
37
38@script:python schema_exists_fn@
39fn;
40@@
41import json
42
43with open("./glib-schema-exists-function.json") as fn_file:
44 if (fn := json.load(fn_file)):
45 coccinelle.fn = fn
46
47
48@find_cpp_constants@
49identifier const_name;
50expression val;
51@@
52
53#define const_name val
54
55@script:python record_cpp_constants depends on find_cpp_constants@
56const_name << find_cpp_constants.const_name;
57val << find_cpp_constants.val;
58@@
59
60register_cpp_constant(const_name, val)
61
62
63@depends on ever record_cpp_constants || never record_cpp_constants@
64// We want to run after #define constants have been collected but even if there are no #defines.
65expression SCHEMA_ID;
66expression settings;
67// Coccinelle does not like autocleanup macros in + sections,
68// let’s use fresh id with concatenation to produce the code as a string.
69fresh identifier schema_source_decl = "g_autoptr(GSettingsSchemaSource) " ## "schema_source";
70fresh identifier schema_decl = "g_autoptr(GSettingsSchema) " ## "schema";
71fresh identifier SCHEMA_DIRECTORY = script:python(SCHEMA_ID) { get_schema_directory(SCHEMA_ID) };
72@@
73-settings = g_settings_new(SCHEMA_ID);
74+{
75+ schema_source_decl;
76+ schema_decl;
77+ schema_source = g_settings_schema_source_new_from_directory(SCHEMA_DIRECTORY,
78+ g_settings_schema_source_get_default(),
79+ TRUE,
80+ NULL);
81+ schema = g_settings_schema_source_lookup(schema_source, SCHEMA_ID, FALSE);
82+ settings = g_settings_new_full(schema, NULL, NULL);
83+}
84
85
86@depends on ever record_cpp_constants || never record_cpp_constants@
87// We want to run after #define constants have been collected but even if there are no #defines.
88expression SCHEMA_ID;
89expression settings;
90expression BACKEND;
91// Coccinelle does not like autocleanup macros in + sections,
92// let’s use fresh id with concatenation to produce the code as a string.
93fresh identifier schema_source_decl = "g_autoptr(GSettingsSchemaSource) " ## "schema_source";
94fresh identifier schema_decl = "g_autoptr(GSettingsSchema) " ## "schema";
95fresh identifier SCHEMA_DIRECTORY = script:python(SCHEMA_ID) { get_schema_directory(SCHEMA_ID) };
96@@
97-settings = g_settings_new_with_backend(SCHEMA_ID, BACKEND);
98+{
99+ schema_source_decl;
100+ schema_decl;
101+ schema_source = g_settings_schema_source_new_from_directory(SCHEMA_DIRECTORY,
102+ g_settings_schema_source_get_default(),
103+ TRUE,
104+ NULL);
105+ schema = g_settings_schema_source_lookup(schema_source, SCHEMA_ID, FALSE);
106+ settings = g_settings_new_full(schema, BACKEND, NULL);
107+}
108
109
110@depends on ever record_cpp_constants || never record_cpp_constants@
111// We want to run after #define constants have been collected but even if there are no #defines.
112expression SCHEMA_ID;
113expression settings;
114expression BACKEND;
115expression PATH;
116// Coccinelle does not like autocleanup macros in + sections,
117// let’s use fresh id with concatenation to produce the code as a string.
118fresh identifier schema_source_decl = "g_autoptr(GSettingsSchemaSource) " ## "schema_source";
119fresh identifier schema_decl = "g_autoptr(GSettingsSchema) " ## "schema";
120fresh identifier SCHEMA_DIRECTORY = script:python(SCHEMA_ID) { get_schema_directory(SCHEMA_ID) };
121@@
122-settings = g_settings_new_with_backend_and_path(SCHEMA_ID, BACKEND, PATH);
123+{
124+ schema_source_decl;
125+ schema_decl;
126+ schema_source = g_settings_schema_source_new_from_directory(SCHEMA_DIRECTORY,
127+ g_settings_schema_source_get_default(),
128+ TRUE,
129+ NULL);
130+ schema = g_settings_schema_source_lookup(schema_source, SCHEMA_ID, FALSE);
131+ settings = g_settings_new_full(schema, BACKEND, PATH);
132+}
133
134
135@depends on ever record_cpp_constants || never record_cpp_constants@
136// We want to run after #define constants have been collected but even if there are no #defines.
137expression SCHEMA_ID;
138expression settings;
139expression PATH;
140// Coccinelle does not like autocleanup macros in + sections,
141// let’s use fresh id with concatenation to produce the code as a string.
142fresh identifier schema_source_decl = "g_autoptr(GSettingsSchemaSource) " ## "schema_source";
143fresh identifier schema_decl = "g_autoptr(GSettingsSchema) " ## "schema";
144fresh identifier SCHEMA_DIRECTORY = script:python(SCHEMA_ID) { get_schema_directory(SCHEMA_ID) };
145@@
146-settings = g_settings_new_with_path(SCHEMA_ID, PATH);
147+{
148+ schema_source_decl;
149+ schema_decl;
150+ schema_source = g_settings_schema_source_new_from_directory(SCHEMA_DIRECTORY,
151+ g_settings_schema_source_get_default(),
152+ TRUE,
153+ NULL);
154+ schema = g_settings_schema_source_lookup(schema_source, SCHEMA_ID, FALSE);
155+ settings = g_settings_new_full(schema, NULL, PATH);
156+}
157
158
159@replace_schema_exists_fns depends on ever record_cpp_constants || never record_cpp_constants@
160// We want to run after #define constants have been collected but even if there are no #defines.
161expression SCHEMA_ID;
162identifier schema_exists_fn.fn;
163@@
164-fn(SCHEMA_ID)
165+TRUE