diff options
-rw-r--r-- | src/ui/theme-parser.c | 290 |
1 files changed, 118 insertions, 172 deletions
diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c index e79396b2..91b565db 100644 --- a/src/ui/theme-parser.c +++ b/src/ui/theme-parser.c @@ -91,8 +91,8 @@ typedef struct GSList *states; const char *theme_name; /* name of theme (directory it's in) */ - char *theme_file; /* theme filename */ - char *theme_dir; /* dir the theme is inside */ + const char *theme_file; /* theme filename */ + const char *theme_dir; /* dir the theme is inside */ MetaTheme *theme; /* theme being parsed */ guint format_version; /* version of format of theme file */ char *name; /* name of named thing being parsed */ @@ -296,9 +296,6 @@ parse_info_init (ParseInfo *info) static void parse_info_free (ParseInfo *info) { - g_free (info->theme_file); - g_free (info->theme_dir); - g_slist_free (info->states); if (info->theme) @@ -3989,66 +3986,121 @@ text_handler (GMarkupParseContext *context, #define MARCO_THEME_FILENAME_FORMAT "metacity-theme-%d.xml" -MetaTheme* -meta_theme_load (const char *theme_name, - GError **err) +/* If the theme is not-corrupt, keep looking for alternate versions + * in other locations we might be compatible with + */ +static gboolean +theme_error_is_fatal (GError *error) +{ + return error->domain != G_FILE_ERROR; +} + +static MetaTheme* +load_theme (const char *theme_dir, + const char *theme_name, + guint major_version, + GError **error) { GMarkupParseContext *context; - GError *error; ParseInfo info; char *text; gsize length; + char *theme_filename; char *theme_file; - char *theme_dir; MetaTheme *retval; - guint version; - const gchar* const* xdg_data_dirs; - int i; + + g_return_val_if_fail (error && *error == NULL, NULL); text = NULL; - length = 0; retval = NULL; context = NULL; - theme_dir = NULL; - theme_file = NULL; + theme_filename = g_strdup_printf (MARCO_THEME_FILENAME_FORMAT, major_version); + theme_file = g_build_filename (theme_dir, theme_filename, NULL); - if (meta_is_debugging ()) + if (!g_file_get_contents (theme_file, &text, &length, error)) + goto out; + + meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file); + + parse_info_init (&info); + + info.theme_name = theme_name; + info.theme_file = theme_file; + info.theme_dir = theme_dir; + + info.format_version = major_version; + + context = g_markup_parse_context_new (&marco_theme_parser, 0, &info, NULL); + + if (!g_markup_parse_context_parse (context, text, length, error)) + goto out; + + if (!g_markup_parse_context_end_parse (context, error)) + goto out; + + retval = info.theme; + info.theme = NULL; + + out: + if (*error && !theme_error_is_fatal (*error)) + meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", + theme_file, (*error)->message); + + g_free (theme_filename); + g_free (theme_file); + g_free (text); + + if (context) + { + g_markup_parse_context_free (context); + parse_info_free (&info); + } + + return retval; +} + +static gboolean +keep_trying (GError **error) +{ + if (*error && !theme_error_is_fatal (*error)) { - gchar *theme_filename = g_strdup_printf (MARCO_THEME_FILENAME_FORMAT, - THEME_VERSION); + g_clear_error (error); + return TRUE; + } + + return FALSE; +} - /* Try in themes in our source tree */ - theme_dir = g_build_filename ("./themes", theme_name, NULL); +MetaTheme* +meta_theme_load (const char *theme_name, + GError **err) +{ + GError *error = NULL; + char *theme_dir; + MetaTheme *retval; + const gchar* const* xdg_data_dirs; + int version; + int i; - theme_file = g_build_filename (theme_dir, - theme_filename, - NULL); + retval = NULL; - error = NULL; - if (!g_file_get_contents (theme_file, - &text, - &length, - &error)) + if (meta_is_debugging ()) + { + /* We try all supported major versions from current to oldest */ + for (version = THEME_VERSION; (version > 0); version--) { - meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", - theme_file, error->message); - g_error_free (error); - g_free (theme_dir); - g_free (theme_file); - theme_file = NULL; - } - version = THEME_VERSION; + theme_dir = g_build_filename ("./themes", theme_name, NULL); + retval = load_theme (theme_dir, theme_name, version, &error); - g_free (theme_filename); + if (!keep_trying (&error)) + goto out; + } } - /* We try all supported versions from current to oldest */ - for (version = THEME_VERSION; (version > 0) && (text == NULL); version--) + /* We try all supported major versions from current to oldest */ + for (version = THEME_VERSION; (version > 0); version--) { - gchar *theme_filename = g_strdup_printf (MARCO_THEME_FILENAME_FORMAT, - version); - /* We try first in home dir, XDG_DATA_DIRS, then system dir for themes */ /* Try home dir for themes */ @@ -4058,155 +4110,49 @@ meta_theme_load (const char *theme_name, THEME_SUBDIR, NULL); - theme_file = g_build_filename (theme_dir, - theme_filename, - NULL); - - error = NULL; - if (!g_file_get_contents (theme_file, - &text, - &length, - &error)) - { - meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", - theme_file, error->message); - g_error_free (error); - g_free (theme_dir); - g_free (theme_file); - theme_file = NULL; - } + retval = load_theme (theme_dir, theme_name, version, &error); + g_free (theme_dir); + if (!keep_trying (&error)) + goto out; /* Try each XDG_DATA_DIRS for theme */ xdg_data_dirs = g_get_system_data_dirs(); for(i = 0; xdg_data_dirs[i] != NULL; i++) { - if (text == NULL) - { - theme_dir = g_build_filename (xdg_data_dirs[i], - "themes", - theme_name, - THEME_SUBDIR, - NULL); - - theme_file = g_build_filename (theme_dir, - theme_filename, - NULL); - - error = NULL; - if (!g_file_get_contents (theme_file, - &text, - &length, - &error)) - { - meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", - theme_file, error->message); - g_error_free (error); - g_free (theme_dir); - g_free (theme_file); - theme_file = NULL; - } - else - { - break; - } - } - } - - /* Look for themes in MARCO_DATADIR */ - if (text == NULL) - { - theme_dir = g_build_filename (MARCO_DATADIR, + theme_dir = g_build_filename (xdg_data_dirs[i], "themes", theme_name, THEME_SUBDIR, NULL); - theme_file = g_build_filename (theme_dir, - theme_filename, - NULL); - - error = NULL; - if (!g_file_get_contents (theme_file, - &text, - &length, - &error)) - { - meta_topic (META_DEBUG_THEMES, "Failed to read theme from file %s: %s\n", - theme_file, error->message); - g_error_free (error); - g_free (theme_dir); - g_free (theme_file); - theme_file = NULL; - } + retval = load_theme (theme_dir, theme_name, version, &error); + g_free (theme_dir); + if (!keep_trying (&error)) + goto out; } - - g_free (theme_filename); - } - - if (text == NULL) - { - g_set_error (err, META_THEME_ERROR, META_THEME_ERROR_FAILED, - _("Failed to find a valid file for theme %s\n"), - theme_name); - - return NULL; /* all fallbacks failed */ + /* Look for themes in MARCO_DATADIR */ + theme_dir = g_build_filename (MARCO_DATADIR, + "themes", + theme_name, + THEME_SUBDIR, + NULL); + retval = load_theme (theme_dir, theme_name, version, &error); + g_free (theme_dir); + if (!keep_trying (&error)) + goto out; } - meta_topic (META_DEBUG_THEMES, "Parsing theme file %s\n", theme_file); - - - parse_info_init (&info); - info.theme_name = theme_name; - - /* pass ownership to info so we free it with the info */ - info.theme_file = theme_file; - info.theme_dir = theme_dir; - - info.format_version = version + 1; - - context = g_markup_parse_context_new (&marco_theme_parser, - 0, &info, NULL); - - error = NULL; - if (!g_markup_parse_context_parse (context, - text, - length, - &error)) - goto out; - - error = NULL; - if (!g_markup_parse_context_end_parse (context, &error)) - goto out; - - goto out; - out: - if (context) - g_markup_parse_context_free (context); - g_free (text); - - if (info.theme) - info.theme->format_version = info.format_version; + if (!error && !retval) + g_set_error (&error, META_THEME_ERROR, META_THEME_ERROR_FAILED, + _("Failed to find a valid file for theme %s\n"), + theme_name); if (error) { g_propagate_error (err, error); } - else if (info.theme) - { - /* Steal theme from info */ - retval = info.theme; - info.theme = NULL; - } - else - { - g_set_error (err, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Theme file %s did not contain a root <metacity_theme> element"), - info.theme_file); - } - - parse_info_free (&info); return retval; } |