/* * Copyright © 2011, 2012, 2013 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 . */ #include #include #include #include #include #include #include #include #include #define G_SETTINGS_ENABLE_BACKEND #include #include "terminal-schemas.h" #include "terminal-profiles-list.h" #include "terminal-type-builtins.h" #include "terminal-debug.h" #include "terminal-libgsystem.h" static gboolean clean = FALSE; static gboolean dry_run = FALSE; static gboolean force = FALSE; static gboolean verbose = FALSE; static const GOptionEntry options[] = { { "clean", 0, 0, G_OPTION_ARG_NONE, &clean, NULL, NULL }, { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, NULL, NULL }, { "force", 0, 0, G_OPTION_ARG_NONE, &force, NULL, NULL }, { "verbose", 0, 0, G_OPTION_ARG_NONE, &verbose, NULL, NULL }, { NULL } }; #define ERROR_DOMAIN (g_intern_static_string ("gnome-terminal-migration-error")) #define TERMINAL_PATH_PREFIX "/org/gnome/terminal/" enum { ERROR_GENERIC }; #define GCONF_PREFIX "/apps/gnome-terminal" #define GCONF_GLOBAL_PREFIX GCONF_PREFIX "/global" #define GCONF_PROFILES_PREFIX GCONF_PREFIX "/profiles" #define KEY_ALLOW_BOLD "allow_bold" #define KEY_BACKGROUND_COLOR "background_color" #define KEY_BACKGROUND_DARKNESS "background_darkness" #define KEY_BACKGROUND_IMAGE_FILE "background_image" #define KEY_BACKGROUND_TYPE "background_type" #define KEY_BACKSPACE_BINDING "backspace_binding" #define KEY_BOLD_COLOR "bold_color" #define KEY_BOLD_COLOR_SAME_AS_FG "bold_color_same_as_fg" #define KEY_CURSOR_BLINK_MODE "cursor_blink_mode" #define KEY_CURSOR_SHAPE "cursor_shape" #define KEY_CUSTOM_COMMAND "custom_command" #define KEY_DEFAULT_SHOW_MENUBAR "default_show_menubar" #define KEY_DEFAULT_SIZE_COLUMNS "default_size_columns" #define KEY_DEFAULT_SIZE_ROWS "default_size_rows" #define KEY_DELETE_BINDING "delete_binding" #define KEY_ENCODING "encoding" #define KEY_EXIT_ACTION "exit_action" #define KEY_FONT "font" #define KEY_FOREGROUND_COLOR "foreground_color" #define KEY_LOGIN_SHELL "login_shell" #define KEY_PALETTE "palette" #define KEY_SCROLL_BACKGROUND "scroll_background" #define KEY_SCROLLBACK_LINES "scrollback_lines" #define KEY_SCROLLBACK_UNLIMITED "scrollback_unlimited" #define KEY_SCROLLBAR_POSITION "scrollbar_position" #define KEY_SCROLL_ON_KEYSTROKE "scroll_on_keystroke" #define KEY_SCROLL_ON_OUTPUT "scroll_on_output" #define KEY_SILENT_BELL "silent_bell" #define KEY_USE_CUSTOM_COMMAND "use_custom_command" #define KEY_USE_SYSTEM_FONT "use_system_font" #define KEY_USE_THEME_COLORS "use_theme_colors" #define KEY_VISIBLE_NAME "visible_name" static const GConfEnumStringPair erase_binding_pairs[] = { { VTE_ERASE_AUTO, "auto" }, { VTE_ERASE_ASCII_BACKSPACE, "control-h" }, { VTE_ERASE_ASCII_DELETE, "ascii-del" }, { VTE_ERASE_DELETE_SEQUENCE, "escape-sequence" }, { VTE_ERASE_TTY, "tty" }, { -1, NULL } }; static const GConfEnumStringPair scrollbar_position_pairs[] = { { GTK_POLICY_ALWAYS, "left" }, { GTK_POLICY_ALWAYS, "right" }, { GTK_POLICY_NEVER, "hidden" }, { -1, NULL } }; static gboolean string_to_enum (GType type, const char *s, int *val) { GEnumClass *klass; GEnumValue *eval = NULL; guint i; klass = g_type_class_ref (type); for (i = 0; i < klass->n_values; ++i) { if (strcmp (klass->values[i].value_nick, s) != 0) continue; eval = &klass->values[i]; break; } if (eval) *val = eval->value; g_type_class_unref (klass); return eval != NULL; } static void migrate_bool (GConfClient *client, const char *gconf_path, const char *gconf_key, GSettings *settings, const char *settings_key, gboolean invert) { GConfValue *value; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_BOOL) g_settings_set_boolean (settings, settings_key, invert ? !gconf_value_get_bool (value) : gconf_value_get_bool (value)); if (value) gconf_value_free (value); } static void migrate_int (GConfClient *client, const char *gconf_path, const char *gconf_key, GSettings *settings, const char *settings_key) { GConfValue *value; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_INT) g_settings_set_int (settings, settings_key, gconf_value_get_int (value)); if (value) gconf_value_free (value); } static void migrate_string (GConfClient *client, const char *gconf_path, const char *gconf_key, GSettings *settings, const char *settings_key) { GConfValue *value; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_STRING) g_settings_set_string (settings, settings_key, gconf_value_get_string (value)); if (value) gconf_value_free (value); } #if 0 static void migrate_string_list (GConfClient *client, const char *gconf_path, const char *gconf_key, GSettings *settings, const char *settings_key) { GConfValue *value; GVariantBuilder builder; GSList *l; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_LIST && gconf_value_get_list_type (value) == GCONF_VALUE_STRING) { g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); for (l = gconf_value_get_list (value); l != NULL; l = l->next) g_variant_builder_add (&builder, "s", gconf_value_get_string (l->data)); g_settings_set (settings, settings_key, "as", &builder); } if (value) gconf_value_free (value); } #endif static void migrate_enum (GConfClient *client, const char *gconf_path, const char *gconf_key, const GConfEnumStringPair *pairs, GSettings *settings, const char *settings_key) { GConfValue *value; int val; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_STRING && gconf_string_to_enum ((GConfEnumStringPair*) pairs, gconf_value_get_string (value), &val)) g_settings_set_enum (settings, settings_key, val); if (value) gconf_value_free (value); } static void migrate_genum (GConfClient *client, const char *gconf_path, const char *gconf_key, GSettings *settings, const char *settings_key, GType enum_type) { GConfValue *value; int val; char *key; key = gconf_concat_dir_and_key (gconf_path, gconf_key); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_STRING && string_to_enum (enum_type, gconf_value_get_string (value), &val)) g_settings_set_enum (settings, settings_key, val); if (value) gconf_value_free (value); } static void migrate_palette (GConfClient *client, const char *gconf_path, GSettings *settings) { GConfValue *value; char *key; char **strv; key = gconf_concat_dir_and_key (gconf_path, KEY_PALETTE); value = gconf_client_get_without_default (client, key, NULL); g_free (key); if (value != NULL && value->type == GCONF_VALUE_STRING) { strv = g_strsplit (gconf_value_get_string (value), ":", -1); g_settings_set_strv (settings, TERMINAL_PROFILE_PALETTE_KEY, (const char * const *) strv); g_strfreev (strv); } if (value) gconf_value_free (value); } static gboolean migrate_global_prefs (GSettings *settings, GError **error) { GConfClient *client; client = gconf_client_get_default (); migrate_bool (client, GCONF_GLOBAL_PREFIX, "confirm_window_close", settings, TERMINAL_SETTING_CONFIRM_CLOSE_KEY, FALSE); migrate_bool (client, GCONF_GLOBAL_PREFIX, "use_mnemonics", settings, TERMINAL_SETTING_ENABLE_MNEMONICS_KEY, FALSE); migrate_bool (client, GCONF_GLOBAL_PREFIX, "use_menu_accelerator", settings, TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, FALSE); g_object_unref (client); return TRUE; } static gboolean settings_backend_is_dconf (void) { gs_unref_object GSettingsBackend *backend; backend = g_settings_backend_get_default (); return g_str_equal (G_OBJECT_TYPE_NAME (backend), "DConfSettingsBackend"); } static void do_clean (void) { DConfClient *client; if (!settings_backend_is_dconf ()) { if (verbose) g_printerr ("Not using DConf settings backend; not cleaning.\n"); return; } if (verbose) g_printerr ("Cleaning…\n"); #ifdef HAVE_DCONF_1_2 client = dconf_client_new (NULL, NULL, NULL, NULL); dconf_client_write (client, TERMINAL_PATH_PREFIX, NULL, NULL, NULL, NULL); #else /* modern DConf */ client = dconf_client_new (); dconf_client_write_sync (client, TERMINAL_PATH_PREFIX, NULL, NULL, NULL, NULL); #endif g_object_unref (client); } static void migrate_profile (TerminalSettingsList *list, GConfClient *client, const char *gconf_id, const char *default_gconf_id) { GSettings *settings; char *child_name, *path; gs_free char *name; gboolean is_default; if (g_strcmp0 (gconf_id, default_gconf_id) == 0) { /* Re-use the default list child */ settings = terminal_settings_list_ref_default_child (list); is_default = TRUE; } else { child_name = terminal_settings_list_add_child (list, NULL); settings = terminal_settings_list_ref_child (list, child_name); g_free (child_name); is_default = FALSE; } path = gconf_concat_dir_and_key (GCONF_PROFILES_PREFIX, gconf_id); migrate_string (client, path, KEY_VISIBLE_NAME, settings, TERMINAL_PROFILE_VISIBLE_NAME_KEY); g_settings_get (settings, TERMINAL_PROFILE_VISIBLE_NAME_KEY, "s", &name); if (name[0] == '\0') g_settings_set_string (settings, TERMINAL_PROFILE_VISIBLE_NAME_KEY, is_default ? _("Default") : _("Unnamed")); migrate_string (client, path, KEY_FOREGROUND_COLOR, settings, TERMINAL_PROFILE_FOREGROUND_COLOR_KEY); migrate_string (client, path, KEY_BACKGROUND_COLOR, settings, TERMINAL_PROFILE_BACKGROUND_COLOR_KEY); migrate_string (client, path, KEY_BOLD_COLOR, settings, TERMINAL_PROFILE_BOLD_COLOR_KEY); migrate_bool (client, path, KEY_BOLD_COLOR_SAME_AS_FG, settings, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY, FALSE); migrate_bool (client, path, KEY_ALLOW_BOLD, settings, TERMINAL_PROFILE_ALLOW_BOLD_KEY, FALSE); migrate_bool (client, path, KEY_SILENT_BELL, settings, TERMINAL_PROFILE_AUDIBLE_BELL_KEY, TRUE); migrate_int (client, path, KEY_DEFAULT_SIZE_COLUMNS, settings, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY); migrate_int (client, path, KEY_DEFAULT_SIZE_ROWS, settings, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY); migrate_enum (client, path, KEY_SCROLLBAR_POSITION, scrollbar_position_pairs, settings, TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY); { // FIX these as -1 == unlimited? migrate_int (client, path, KEY_SCROLLBACK_LINES, settings, TERMINAL_PROFILE_SCROLLBACK_LINES_KEY); migrate_bool (client, path, KEY_SCROLLBACK_UNLIMITED, settings, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY, FALSE); } migrate_bool (client, path, KEY_SCROLL_ON_KEYSTROKE, settings, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY, FALSE); migrate_bool (client, path, KEY_SCROLL_ON_OUTPUT, settings, TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY, FALSE); migrate_genum (client, path, KEY_EXIT_ACTION, settings, TERMINAL_PROFILE_EXIT_ACTION_KEY, TERMINAL_TYPE_EXIT_ACTION); migrate_bool (client, path, KEY_LOGIN_SHELL, settings, TERMINAL_PROFILE_LOGIN_SHELL_KEY, FALSE); migrate_bool (client, path, KEY_USE_CUSTOM_COMMAND, settings, TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY, FALSE); migrate_string (client, path, KEY_CUSTOM_COMMAND, settings, TERMINAL_PROFILE_CUSTOM_COMMAND_KEY); migrate_genum (client, path, KEY_CURSOR_BLINK_MODE, settings, TERMINAL_PROFILE_CURSOR_BLINK_MODE_KEY, VTE_TYPE_CURSOR_BLINK_MODE); migrate_genum (client, path, KEY_CURSOR_SHAPE, settings, TERMINAL_PROFILE_CURSOR_SHAPE_KEY, VTE_TYPE_CURSOR_SHAPE); migrate_palette (client, path, settings); migrate_string (client, path, KEY_FONT, settings, TERMINAL_PROFILE_FONT_KEY); migrate_enum (client, path, KEY_BACKSPACE_BINDING, erase_binding_pairs, settings, TERMINAL_PROFILE_BACKSPACE_BINDING_KEY); migrate_enum (client, path, KEY_DELETE_BINDING, erase_binding_pairs, settings, TERMINAL_PROFILE_DELETE_BINDING_KEY); migrate_bool (client, path, KEY_USE_THEME_COLORS, settings, TERMINAL_PROFILE_USE_THEME_COLORS_KEY, FALSE); migrate_bool (client, path, KEY_USE_SYSTEM_FONT, settings, TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY, FALSE); migrate_string (client, path, KEY_ENCODING, settings, TERMINAL_PROFILE_ENCODING_KEY); g_free (path); g_object_unref (settings); } static gboolean migrate_profiles (GSettings *global_settings, GError **error) { TerminalSettingsList *list; GConfClient *client; GConfValue *value, *dvalue; GSList *l; const char *default_profile; client = gconf_client_get_default (); dvalue = gconf_client_get (client, GCONF_GLOBAL_PREFIX "/default_profile", NULL); if (dvalue != NULL && dvalue->type == GCONF_VALUE_STRING) default_profile = gconf_value_get_string (dvalue); else default_profile = NULL; list = terminal_profiles_list_new (); value = gconf_client_get (client, GCONF_GLOBAL_PREFIX "/profile_list", NULL); if (value != NULL && value->type == GCONF_VALUE_LIST && gconf_value_get_list_type (value) == GCONF_VALUE_STRING) { for (l = gconf_value_get_list (value); l != NULL; l = l->next) { migrate_profile (list, client, gconf_value_get_string (l->data), default_profile); } } /* Some settings used to be per-profile but are now global; * take these from the default profile. */ if (default_profile) { char *path; path = gconf_concat_dir_and_key (GCONF_PROFILES_PREFIX, default_profile); migrate_bool (client, path, KEY_DEFAULT_SHOW_MENUBAR, global_settings, TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY, FALSE); g_free (path); } if (value) gconf_value_free (value); if (dvalue) gconf_value_free (dvalue); g_object_unref (client); g_object_unref (list); return TRUE; } static gboolean migrate_accels (GSettings *global_settings, GError **error) { static const const struct { const char *gconf_key; const char *settings_key; } const data[] = { { "new_tab", "new-tab" }, { "new_window", "new-window" }, { "close_tab", "close-tab" }, { "close_window", "close-window" }, { "copy", "copy" }, { "paste", "paste" }, { "toggle_menubar", "toggle-menubar" }, { "full_screen", "full-screen" }, { "zoom_in", "zoom-in" }, { "zoom_out", "zoom-out" }, { "zoom_normal", "zoom-normal" }, { "reset", "reset" }, { "reset_and_clear", "reset-and-clear" }, { "prev_tab", "prev-tab" }, { "next_tab", "next-tab" }, { "move_tab_left", "move-tab-left" }, { "move_tab_right", "move-tab-right" }, { "detach_tab", "detach-tab" }, { "switch_to_tab_1", "switch-to-tab-1" }, { "switch_to_tab_2", "switch-to-tab-2" }, { "switch_to_tab_3", "switch-to-tab-3" }, { "switch_to_tab_4", "switch-to-tab-4" }, { "switch_to_tab_5", "switch-to-tab-5" }, { "switch_to_tab_6", "switch-to-tab-6" }, { "switch_to_tab_7", "switch-to-tab-7" }, { "switch_to_tab_8", "switch-to-tab-8" }, { "switch_to_tab_9", "switch-to-tab-9" }, { "switch_to_tab_10", "switch-to-tab-10" }, { "switch_to_tab_11", "switch-to-tab-11" }, { "switch_to_tab_12", "switch-to-tab-12" }, { "help", "help" } }; GConfClient *client; GSettings *settings; guint i; char *gconf_path; GConfValue *value; client = gconf_client_get_default (); settings = g_settings_get_child (global_settings, "keybindings"); for (i = 0; i < G_N_ELEMENTS (data); ++i) { gconf_path = g_strdup_printf ("/apps/gnome-terminal/keybindings/%s", data[i].gconf_key); value = gconf_client_get_without_default (client, gconf_path, NULL); g_free (gconf_path); if (value == NULL) continue; if (value->type == GCONF_VALUE_STRING) g_settings_set_string (settings, data[i].settings_key, gconf_value_get_string (value)); gconf_value_free (value); } g_object_unref (settings); g_object_unref (client); return TRUE; } static gboolean migrate (GSettings *global_settings, GError **error) { return migrate_global_prefs (global_settings, error) && migrate_profiles (global_settings, error) && migrate_accels (global_settings, error); } static void update_schema_version (void) { GSettings *settings; if (verbose) g_printerr ("Updating schema version\n"); settings = g_settings_new (TERMINAL_SETTING_SCHEMA); g_settings_set_uint (settings, TERMINAL_SETTING_SCHEMA_VERSION, TERMINAL_SCHEMA_VERSION); g_object_unref (settings); } int main (int argc, char *argv[]) { GOptionContext *context; GError *error = NULL; GSettings *global_settings; int rv = EXIT_SUCCESS; setlocale (LC_ALL, ""); _terminal_debug_init (); context = g_option_context_new (""); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_option_context_free (context); g_printerr ("Error parsing arguments: %s\n", error->message); g_error_free (error); return EXIT_FAILURE; } g_option_context_free (context); global_settings = g_settings_new (TERMINAL_SETTING_SCHEMA); if (clean) { if (!force) { g_printerr ("--clean requires --force\n"); rv = EXIT_FAILURE; goto out; } do_clean (); } if (g_settings_get_uint (global_settings, TERMINAL_SETTING_SCHEMA_VERSION) >= TERMINAL_SCHEMA_VERSION) { if (verbose) g_printerr ("Already migrated.\n"); if (!force) goto out; } if (!migrate (global_settings, &error)) { g_printerr ("Error: %s\n", error->message); g_error_free (error); goto out; } update_schema_version (); if (verbose) g_printerr ("Syncing gsettings…\n"); g_settings_sync (); if (verbose) g_printerr ("Migration successful!\n"); out: g_object_unref (global_settings); return rv; }