1 #include "tilda-config.h"
4 #include "tilda-types.h"
6 #include "translation.h"
8 #include <glib-object.h> /* for GType */
9 #include <stdlib.h> /* for exit() */
11 GKeyFile *config_defaults = NULL;
12 GKeyFile *config_userprefs = NULL;
16 * 1) Configuration forward-migration, automatically, on startup.
19 /* The main idea behind this configuration system is that each type of GObject
20 * that needs to use the system implements its own lookup scheme. I tried to
21 * do this as generically as possible, by using just the GObject property names,
22 * and then looking up their type and using that to use the correct parsing
25 * It is basically function overloading (for example, from C++) but done in C.
26 * Rather complicated, if you ask me. Also a complete pain. But the result
31 tilda_config_lookup_version (GKeyFile *keyfile, GError **error)
35 return g_key_file_get_string (keyfile, "Meta", "version", error);
39 tilda_config_parse_integer (GKeyFile *keyfile,
40 const gchar *group_name,
46 debug_assert (G_IS_VALUE(value));
51 /* Try to get the value */
52 ret = g_key_file_get_integer (keyfile, group_name, key, &error);
57 g_propagate_error (user_error, error);
61 /* We successfully parsed the int, so set it in the GValue */
62 g_value_set_int (value, ret);
68 tilda_config_parse_boolean (GKeyFile *keyfile,
69 const gchar *group_name,
75 debug_assert (G_IS_VALUE(value));
80 /* Try to get the value */
81 ret = g_key_file_get_boolean (keyfile, group_name, key, &error);
86 g_propagate_error (user_error, error);
91 g_value_set_boolean (value, ret);
97 tilda_config_parse_string (GKeyFile *keyfile,
98 const gchar *group_name,
104 debug_assert (G_IS_VALUE(value));
106 GError *error = NULL;
109 /* Try to get the value */
110 ret = g_key_file_get_string (keyfile, group_name, key, &error);
112 /* Check for error */
115 g_propagate_error (user_error, error);
120 g_value_set_string (value, ret);
125 #define key_is(STR) (g_ascii_strcasecmp(key,(STR)) == 0)
128 tilda_config_parse_enum (GKeyFile *keyfile,
129 const gchar *group_name,
135 GError *error = NULL;
136 GEnumClass *enum_class;
137 GEnumValue *enum_value;
139 if (key_is("backspace-binding") || key_is("delete-binding"))
140 enum_class = g_type_class_peek (vte_terminal_erase_binding_get_type());
141 else if (key_is("dynamic-title"))
142 enum_class = g_type_class_peek (tilda_dynamic_title_get_type());
143 else if (key_is("exit-action"))
144 enum_class = g_type_class_peek (tilda_child_exit_action_get_type());
145 else if (key_is("scrollbar-position"))
146 enum_class = g_type_class_peek (tilda_scrollbar_position_get_type());
147 else if (key_is("animation-orientation") || key_is("tab-position"))
148 enum_class = g_type_class_peek (gtk_position_type_get_type());
151 g_critical ("FIXME: developer error -- unknown enum key used: %s\n", key);
156 /* Get the value from the config as a string */
157 ret = g_key_file_get_string (keyfile, group_name, key, &error);
161 g_propagate_error (user_error, error);
165 enum_value = g_enum_get_value_by_nick (enum_class, ret);
169 /* This is exactly the same error that is returned by g_key_file_get_integer()
170 * when it cannot correctly parse the value. */
171 g_set_error (user_error,
173 G_KEY_FILE_ERROR_INVALID_VALUE,
174 _("Key file contains key '%s' in group '%s' which has value that cannot be interpreted."), key, group_name);
178 /* All was successful, let's set it */
179 g_value_set_enum (value, enum_value->value);
184 tilda_controller_set_property_from_config (TildaController *self, const gchar *property)
187 debug_assert (TILDA_IS_CONTROLLER(self));
189 GError *error = NULL;
193 GValue *value = g_new0 (GValue, 1);
194 gboolean (*parse_func) (GKeyFile *keyfile, const gchar *group_name, const gchar *key, GValue *value, GError **error);
196 /* Get the pspec for this property */
197 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self), property);
199 /* Make sure that this property exists */
202 g_critical ("FIXME: developer error -- unable to find property: %s\n", property);
206 /* Initialize the GValue that is going to hold the returned value */
207 g_value_init (value, pspec->value_type);
209 /* Set the correct function to do the parsing */
210 if (g_type_is_a (pspec->value_type, G_TYPE_INT))
211 parse_func = tilda_config_parse_integer;
212 else if (g_type_is_a (pspec->value_type, G_TYPE_BOOLEAN))
213 parse_func = tilda_config_parse_boolean;
214 else if (g_type_is_a (pspec->value_type, G_TYPE_STRING))
215 parse_func = tilda_config_parse_string;
216 else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM))
217 parse_func = tilda_config_parse_enum;
220 g_critical ("FIXME: developer error -- unknown property type: %s\n", g_type_name(pspec->value_type));
224 /* Do the [Controller] lookup */
225 ret = parse_func (config_userprefs, "Controller", property, value, &error);
229 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
230 g_warning (error->message);
232 g_clear_error (&error);
237 /* Do the [Global] lookup */
238 ret = parse_func (config_userprefs, "Global", property, value, &error);
242 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
243 g_warning (error->message);
245 g_clear_error (&error);
250 /* Do the [controller-defaults] lookup */
251 ret = parse_func (config_defaults, "controller-defaults", property, value, &error);
255 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
256 g_warning (error->message);
258 g_clear_error (&error);
260 /* This is somewhat of a nasty hack, but I really do want to just set the property to
261 * NULL if there is no default, but ONLY for strings. */
262 if (parse_func == tilda_config_parse_string)
264 g_value_set_string (value, NULL);
272 g_critical (_("Unable to find a value for controller property: %s\n"), property);
277 g_object_set_property (G_OBJECT(self), property, value);
278 g_value_unset (value);
284 tilda_window_set_property_from_config (TildaWindow *self, const gchar *property)
287 debug_assert (TILDA_IS_WINDOW(self));
290 GError *error = NULL;
294 GValue *value = g_new0(GValue, 1);
295 gboolean (*parse_func) (GKeyFile *keyfile, const gchar *group_name, const gchar *key, GValue *value, GError **error);
297 /* Get the pspec for this property */
298 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self), property);
300 /* Make sure that this property exists */
303 g_critical ("FIXME: developer error -- unable to find property: %s\n", property);
307 /* Initialize the GValue that is going to hold the returned value */
308 g_value_init (value, pspec->value_type);
310 /* Set the correct function to do the parsing */
311 if (g_type_is_a (pspec->value_type, G_TYPE_INT))
312 parse_func = tilda_config_parse_integer;
313 else if (g_type_is_a (pspec->value_type, G_TYPE_BOOLEAN))
314 parse_func = tilda_config_parse_boolean;
315 else if (g_type_is_a (pspec->value_type, G_TYPE_STRING))
316 parse_func = tilda_config_parse_string;
317 else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM))
318 parse_func = tilda_config_parse_enum;
321 g_critical ("FIXME: developer error -- unknown property type: %s\n", g_type_name(pspec->value_type));
325 /* Do the [Window] lookup */
326 group_name = g_strdup_printf ("Window%d", self->number);
327 ret = parse_func (config_userprefs, group_name, property, value, &error);
332 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
333 g_warning (error->message);
335 g_clear_error (&error);
340 /* Do the [Global] lookup */
341 ret = parse_func (config_userprefs, "Global", property, value, &error);
345 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
346 g_warning (error->message);
348 g_clear_error (&error);
353 /* Do the [window-defaults] lookup */
354 ret = parse_func (config_defaults, "window-defaults", property, value, &error);
358 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
359 g_warning (error->message);
361 g_clear_error (&error);
363 /* This is somewhat of a nasty hack, but I really do want to just set the property to
364 * NULL if there is no default, but ONLY for strings. */
365 if (parse_func == tilda_config_parse_string)
367 g_value_set_string (value, NULL);
375 g_critical (_("Unable to find a value for window property: %s\n"), property);
380 g_object_set_property (G_OBJECT(self), property, value);
381 g_value_unset (value);
387 tilda_terminal_set_property_from_config (TildaTerminal *self, const gchar *property)
390 debug_assert (TILDA_IS_TERMINAL(self));
392 TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
394 GError *error = NULL;
398 GValue *value = g_new0 (GValue, 1);
399 gboolean (*parse_func) (GKeyFile *keyfile, const gchar *group_name, const gchar *key, GValue *value, GError **error);
401 /* Get the pspec for this property */
402 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self), property);
404 /* Make sure that this property exists */
407 g_critical ("FIXME: developer error -- unable to find property: %s\n", property);
411 /* Initialize the GValue that is going to hold the returned value */
412 g_value_init (value, pspec->value_type);
414 /* Set the correct function to do the parsing */
415 if (g_type_is_a (pspec->value_type, G_TYPE_INT))
416 parse_func = tilda_config_parse_integer;
417 else if (g_type_is_a (pspec->value_type, G_TYPE_BOOLEAN))
418 parse_func = tilda_config_parse_boolean;
419 else if (g_type_is_a (pspec->value_type, G_TYPE_STRING))
420 parse_func = tilda_config_parse_string;
421 else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM))
422 parse_func = tilda_config_parse_enum;
425 g_critical ("FIXME: developer error -- unknown property type: %s\n", g_type_name(pspec->value_type));
429 /* Do the [Window/Terminal] lookup */
430 group_name = g_strdup_printf ("Window%d/Terminal%d", parent_window->number, self->number);
431 ret = parse_func (config_userprefs, group_name, property, value, &error);
436 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
437 g_warning (error->message);
439 g_clear_error (&error);
444 /* Do the [Window] lookup */
445 group_name = g_strdup_printf ("Window%d", parent_window->number);
446 ret = parse_func (config_userprefs, group_name, property, value, &error);
451 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
452 g_warning (error->message);
454 g_clear_error (&error);
459 /* Do the [Global] lookup */
460 ret = parse_func (config_userprefs, "Global", property, value, &error);
464 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
465 g_warning (error->message);
467 g_clear_error (&error);
472 /* Do the [terminal-defaults] lookup */
473 ret = parse_func (config_defaults, "terminal-defaults", property, value, &error);
477 if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
478 g_warning (error->message);
480 g_clear_error (&error);
482 /* This is somewhat of a nasty hack, but I really do want to just set the property to
483 * NULL if there is no default, but ONLY for strings. */
484 if (parse_func == tilda_config_parse_string)
486 g_value_set_string (value, NULL);
494 g_critical (_("Unable to find a value for terminal property: %s\n"), property);
499 g_object_set_property (G_OBJECT(self), property, value);
500 g_value_unset (value);
506 tilda_config_init (const gchar *userprefs_filename)
508 gchar *defaults_filename;
509 GError *error = NULL;
511 /* Call g_type_class_ref() on all enum types that are being used */
512 g_type_class_ref (vte_terminal_erase_binding_get_type());
513 g_type_class_ref (tilda_dynamic_title_get_type());
514 g_type_class_ref (tilda_child_exit_action_get_type());
515 g_type_class_ref (tilda_scrollbar_position_get_type());
516 g_type_class_ref (gtk_position_type_get_type());
518 /* Create the defaults file's path */
519 defaults_filename = g_build_filename ("share-tilda.conf", NULL); // FIXME: use /usr/share/tilda
521 /* Create the keyfiles */
522 config_defaults = g_key_file_new ();
523 config_userprefs = g_key_file_new ();
525 /* Check if the defaults exist, and load them */
526 if (!g_file_test (defaults_filename, G_FILE_TEST_EXISTS))
528 g_critical (_("No configuration defaults file found. Tilda may not work.\n"));
532 if (!g_key_file_load_from_file (config_defaults, defaults_filename, G_KEY_FILE_NONE, &error))
534 g_critical (_("Error reading configuration defaults: %s\n"), error->message);
535 g_clear_error (&error);
539 /* Check if the user's config exists, and load it */
540 if (!g_file_test (userprefs_filename, G_FILE_TEST_EXISTS))
542 g_warning (_("No user configuration file found, using defaults\n"));
546 if (!g_key_file_load_from_file (config_userprefs, userprefs_filename, G_KEY_FILE_NONE, &error))
548 g_warning (_("Error reading user configuration: %s\n"), error->message);
549 g_clear_error (&error);
553 /* This is just here for the future. Currently, it is acceptable to run without
554 * a configuration, though Tilda may not work very well. */
559 * Since we DO NOT allow writing to the configuration file from a Tilda
560 * process (only from the wizard), this does nothing more than free the
561 * defaults hashtable, and free the opened keyfile.
566 /* Since we never write the config file from within Tilda,
567 * we can just close the files. */
568 g_key_file_free (config_defaults);
569 g_key_file_free (config_userprefs);
571 config_defaults = NULL;
572 config_userprefs = NULL;
577 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */