a highly automated and intuitive digital audio workstation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

578 lines
14 KiB

// SPDX-FileCopyrightText: © 2018-2022 Alexandros Theodotou <alex@zrythm.org>
// SPDX-License-Identifier: LicenseRef-ZrythmLicense
/**
* \file
*
* Application settings.
*/
#include "zrythm-config.h"
#include <stdio.h>
#include <stdlib.h>
#include "settings/plugin_settings.h"
#include "settings/settings.h"
#include "settings/user_shortcuts.h"
#include "utils/gtk.h"
#include "utils/mem.h"
#include "utils/objects.h"
#include "utils/string.h"
#include "utils/strv_builder.h"
#include "utils/terminal.h"
#include "zrythm.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define G_SETTINGS_ENABLE_BACKEND
#include <gio/gsettingsbackend.h>
/**
* Initializes settings.
*/
Settings *
settings_new (void)
{
Settings * self = object_new (Settings);
if (ZRYTHM_TESTING)
{
return self;
}
self->general = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".general");
self->export_audio = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".export.audio");
self->export_midi = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".export.midi");
self->monitor = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".monitor");
self->ui =
g_settings_new (GSETTINGS_ZRYTHM_PREFIX ".ui");
self->ui_inspector = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".ui.inspector");
self->ui_mixer = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".ui.mixer");
self->ui_plugin_browser = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".ui.plugin-browser");
self->ui_panels = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".ui.panels");
self->ui_file_browser = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".ui.file-browser");
self->transport = g_settings_new (
GSETTINGS_ZRYTHM_PREFIX ".transport");
#define PREFERENCES_PREFIX \
GSETTINGS_ZRYTHM_PREFIX ".preferences."
#define NEW_PREFERENCES_SETTINGS(a, b) \
self->preferences_##a##_##b = g_settings_new ( \
PREFERENCES_PREFIX #a "." #b); \
g_return_val_if_fail ( \
self->preferences_##a##_##b, NULL)
NEW_PREFERENCES_SETTINGS (dsp, pan);
NEW_PREFERENCES_SETTINGS (editing, audio);
NEW_PREFERENCES_SETTINGS (editing, automation);
NEW_PREFERENCES_SETTINGS (editing, undo);
NEW_PREFERENCES_SETTINGS (general, engine);
NEW_PREFERENCES_SETTINGS (general, paths);
NEW_PREFERENCES_SETTINGS (general, updates);
NEW_PREFERENCES_SETTINGS (plugins, uis);
NEW_PREFERENCES_SETTINGS (plugins, paths);
NEW_PREFERENCES_SETTINGS (projects, general);
NEW_PREFERENCES_SETTINGS (ui, general);
NEW_PREFERENCES_SETTINGS (scripting, general);
#undef PREFERENCES_PREFIX
g_return_val_if_fail (
self->general && self->export_audio && self->ui
&& self->ui_inspector,
NULL);
#if 0
/* plugin settings */
GSettingsBackend * psettings_backend =
g_keyfile_settings_backend_new (
"/filesystem/path/plugin-settings.ini",
"/",
NULL);
self->plugin_settings =
g_settings_new_with_backend (
GSETTINGS_ZRYTHM_PREFIX ".plugin-settings",
psettings_backend);
g_settings_set_boolean (
self->plugin_settings, "loop", 1);
#endif
self->plugin_settings = plugin_settings_new ();
g_return_val_if_fail (
self->plugin_settings, NULL);
self->user_shortcuts = user_shortcuts_new ();
if (!self->user_shortcuts)
{
g_warning ("failed to parse user shortcuts");
}
return self;
}
static int
print_or_reset_schema (
GSettingsSchema * schema,
const char * schema_str,
int print_only,
int pretty_print)
{
GSettings * settings =
g_settings_new (schema_str);
char ** keys =
g_settings_schema_list_keys (schema);
char tmp[8000];
if (print_only)
{
sprintf (
tmp, _ ("Schema %s%s%s"),
pretty_print ? TERMINAL_BOLD : "",
schema_str,
pretty_print ? TERMINAL_RESET : "");
printf (
"%s%s\n",
pretty_print ? TERMINAL_UNDERLINE : "",
tmp);
}
else
{
printf (
_ ("Resetting schema %s...\n"), schema_str);
}
int i = 0;
char * key;
while ((key = keys[i++]))
{
GSettingsSchemaKey * schema_key =
g_settings_schema_get_key (schema, key);
g_return_val_if_fail (schema_key, -1);
if (print_only)
{
GVariant * val =
g_settings_get_value (settings, key);
char * var_str = g_variant_print (val, 0);
printf (
" %s%s%s=%s%s%s\n",
pretty_print
? TERMINAL_COLOR_MAGENTA TERMINAL_BOLD
: "",
key, pretty_print ? TERMINAL_RESET : "",
pretty_print ? TERMINAL_COLOR_YELLOW : "",
var_str,
pretty_print ? TERMINAL_RESET : "");
if (pretty_print)
{
const char * description =
g_settings_schema_key_get_description (
schema_key);
printf (" %s\n", _ (description));
}
}
else if (
/* don't reset install-dir */
string_is_equal (key, "install-dir"))
{
sprintf (tmp, _ ("skipping %s"), key);
printf (" %s\n", tmp);
}
else
{
GVariant * val =
g_settings_schema_key_get_default_value (
schema_key);
g_return_val_if_fail (val, -1);
char * var_str = g_variant_print (val, 0);
sprintf (
tmp, _ ("resetting %s to %s"), key,
var_str);
printf (" %s\n", tmp);
int ret = g_settings_set_value (
settings, key, val);
if (!ret)
{
g_warning ("Failed to set value");
return -1;
}
}
}
return 0;
}
/**
* @param print_only Only print the settings without
* resetting.
*/
static int
print_or_reset (
int print_only,
int pretty_print,
int exit_on_finish)
{
GSettingsSchemaSource * source =
g_settings_schema_source_get_default ();
char ** non_relocatable;
g_settings_schema_source_list_schemas (
source, 1, &non_relocatable, NULL);
int i = 0;
char * schema_str;
while ((schema_str = non_relocatable[i++]))
{
if (string_contains_substr (
schema_str, GSETTINGS_ZRYTHM_PREFIX))
{
GSettingsSchema * schema =
g_settings_schema_source_lookup (
source, schema_str, 1);
if (!schema)
{
fprintf (
stderr,
_ ("Failed to find schema %s. %s is likely not installed"),
schema_str, PROGRAM_NAME);
if (exit_on_finish)
exit (1);
else
return -1;
}
if (print_or_reset_schema (
schema, schema_str, print_only,
pretty_print))
{
if (print_only)
{
fprintf (
stderr,
_ ("Failed to view schema %s"),
schema_str);
}
else
{
fprintf (
stderr,
_ ("Failed to reset schema %s"),
schema_str);
}
if (exit_on_finish)
exit (1);
else
return -1;
}
}
}
if (!print_only)
{
g_settings_sync ();
}
return 0;
}
/**
* Resets settings to defaults.
*
* @param window Window to set transient to if
* confirming, otherwise console confirmation will
* be used.
* @param exit_on_finish Exit with a code on
* finish.
*
* @return Whether successfully reset.
*/
bool
settings_reset_to_factory (
bool confirm,
GtkWindow * window,
bool exit_on_finish)
{
if (confirm)
{
if (window)
{
GtkDialog * dialog = GTK_DIALOG (
gtk_message_dialog_new_with_markup (
window,
GTK_DIALOG_DESTROY_WITH_PARENT
| GTK_DIALOG_MODAL,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_OK_CANCEL, NULL));
gtk_message_dialog_set_markup (
GTK_MESSAGE_DIALOG (dialog),
_ ("This will reset Zrythm to "
"factory settings. <b>You will lose "
"all your preferences</b>. "
"Continue?"));
gtk_window_set_title (
GTK_WINDOW (dialog),
_ ("Reset to Factory Settings"));
int response =
z_gtk_dialog_run (dialog, true);
if (response != GTK_RESPONSE_OK)
return false;
}
else
{
printf (
"%s ",
_ ("This will reset Zrythm to factory "
"settings. You will lose all your "
"preferences. "
"Type 'y' to continue:"));
char c = getchar ();
if (c != 'y')
{
printf (_ ("Aborting...\n"));
if (exit_on_finish)
exit (0);
return false;
}
}
}
print_or_reset (0, 0, exit_on_finish);
printf (
_ ("Reset to factory settings successful\n"));
return true;
}
/**
* Prints the current settings.
*/
void
settings_print (int pretty_print)
{
print_or_reset (1, pretty_print, 0);
}
GVariant *
settings_get_range (
const char * schema,
const char * key)
{
GSettingsSchemaSource * source =
g_settings_schema_source_get_default ();
GSettingsSchema * g_settings_schema =
g_settings_schema_source_lookup (
source, schema, 1);
GSettingsSchemaKey * schema_key =
g_settings_schema_get_key (
g_settings_schema, key);
GVariant * range =
g_settings_schema_key_get_range (schema_key);
g_settings_schema_key_unref (schema_key);
g_settings_schema_unref (g_settings_schema);
return range;
}
GVariant *
settings_get_default_value (
const char * schema,
const char * key)
{
GSettingsSchemaSource * source =
g_settings_schema_source_get_default ();
GSettingsSchema * g_settings_schema =
g_settings_schema_source_lookup (
source, schema, 1);
GSettingsSchemaKey * schema_key =
g_settings_schema_get_key (
g_settings_schema, key);
GVariant * def_val =
g_settings_schema_key_get_default_value (
schema_key);
g_settings_schema_key_unref (schema_key);
g_settings_schema_unref (g_settings_schema);
return def_val;
}
double
settings_get_default_value_double (
const char * schema,
const char * key)
{
GVariant * def_val =
settings_get_default_value (schema, key);
double ret = g_variant_get_double (def_val);
g_variant_unref (def_val);
return ret;
}
void
settings_get_range_double (
const char * schema,
const char * key,
double * lower,
double * upper)
{
GVariant * range =
settings_get_range (schema, key);
GVariant * range_vals =
g_variant_get_child_value (range, 1);
range_vals =
g_variant_get_child_value (range_vals, 0);
GVariant * lower_var =
g_variant_get_child_value (range_vals, 0);
GVariant * upper_var =
g_variant_get_child_value (range_vals, 1);
*lower = g_variant_get_double (lower_var);
*upper = g_variant_get_double (upper_var);
g_variant_unref (range_vals);
g_variant_unref (lower_var);
g_variant_unref (upper_var);
}
/**
* Returns whether the "as" key contains the given
* string.
*/
bool
settings_strv_contains_str (
GSettings * settings,
const char * key,
const char * val)
{
char ** strv =
g_settings_get_strv (settings, key);
for (int i = 0;; i++)
{
char * str = strv[i];
if (!str)
break;
if (string_is_equal (str, val))
{
g_strfreev (strv);
return true;
}
}
g_strfreev (strv);
return false;
}
/**
* Appends the given string to a key of type "as".
*/
void
settings_append_to_strv (
GSettings * settings,
const char * key,
const char * val,
bool ignore_if_duplicate)
{
if (
ignore_if_duplicate && !ZRYTHM_TESTING
&& settings_strv_contains_str (
settings, key, val))
{
return;
}
g_debug (
"%s: key %s val %s ignore if duplicate %d",
__func__, key, val, ignore_if_duplicate);
StrvBuilder * builder = strv_builder_new ();
char ** strv =
ZRYTHM_TESTING
? NULL
: g_settings_get_strv (settings, key);
if (strv)
strv_builder_addv (
builder, (const char **) strv);
strv_builder_add (builder, val);
char ** new_strv = strv_builder_end (builder);
if (ZRYTHM_TESTING)
{
for (size_t i = 0; new_strv[i] != NULL; i++)
{
char * tmp = new_strv[i];
g_message ("setting [%zu]: %s", i, tmp);
}
}
else
{
g_settings_set_strv (
settings, key,
(const char * const *) new_strv);
}
g_strfreev (strv);
g_strfreev (new_strv);
}
/**
* Frees settings.
*/
void
settings_free (Settings * self)
{
#define FREE_SETTING(x) \
g_object_unref_and_null (self->x)
FREE_SETTING (general);
FREE_SETTING (preferences_dsp_pan);
FREE_SETTING (preferences_editing_audio);
FREE_SETTING (preferences_editing_automation);
FREE_SETTING (preferences_editing_undo);
FREE_SETTING (preferences_general_engine);
FREE_SETTING (preferences_general_paths);
FREE_SETTING (preferences_general_updates);
FREE_SETTING (preferences_plugins_uis);
FREE_SETTING (preferences_plugins_paths);
FREE_SETTING (preferences_projects_general);
FREE_SETTING (preferences_ui_general);
FREE_SETTING (preferences_scripting_general);
FREE_SETTING (monitor);
FREE_SETTING (ui);
FREE_SETTING (transport);
FREE_SETTING (export_audio);
FREE_SETTING (export_midi);
FREE_SETTING (ui_mixer);
FREE_SETTING (ui_inspector);
FREE_SETTING (ui_panels);
FREE_SETTING (ui_plugin_browser);
FREE_SETTING (ui_file_browser);
#undef FREE_SETTING
object_free_w_func_and_null (
plugin_settings_free, self->plugin_settings);
object_free_w_func_and_null (
user_shortcuts_free, self->user_shortcuts);
object_zero_and_free (self);
}