theme: convert stylesheet loading to GFile

In preparation to making it a GResource.

https://bugzilla.gnome.org/show_bug.cgi?id=736936
This commit is contained in:
Cosimo Cecchi 2014-09-18 19:22:02 -07:00 committed by Jasper St. Pierre
parent 328bb1c21b
commit 642bf2b778
6 changed files with 113 additions and 97 deletions

View File

@ -74,7 +74,7 @@ function disableExtension(uuid) {
if (extension.stylesheet) { if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet.get_path()); theme.unload_stylesheet(extension.stylesheet);
} }
try { try {
@ -118,7 +118,7 @@ function enableExtension(uuid) {
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]); let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
if (stylesheetFile.query_exists(null)) { if (stylesheetFile.query_exists(null)) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.load_stylesheet(stylesheetFile.get_path()); theme.load_stylesheet(stylesheetFile);
extension.stylesheet = stylesheetFile; extension.stylesheet = stylesheetFile;
break; break;
} }

View File

@ -228,8 +228,8 @@ function _loadDefaultStylesheet() {
if (!sessionMode.isPrimary) if (!sessionMode.isPrimary)
return; return;
let stylesheet = global.datadir + '/theme/' + sessionMode.stylesheetName; let stylesheet = Gio.File.new_for_path(global.datadir + '/theme/' + sessionMode.stylesheetName);
if (_defaultCssStylesheet == stylesheet) if (_defaultCssStylesheet && _defaultCssStylesheet.equal(stylesheet))
return; return;
_defaultCssStylesheet = stylesheet; _defaultCssStylesheet = stylesheet;
@ -256,7 +256,7 @@ function getThemeStylesheet() {
* Set the theme CSS file that the shell will load * Set the theme CSS file that the shell will load
*/ */
function setThemeStylesheet(cssStylesheet) { function setThemeStylesheet(cssStylesheet) {
_cssStylesheet = cssStylesheet; _cssStylesheet = Gio.File.new_for_path(cssStylesheet);
} }
/** /**

View File

@ -60,13 +60,13 @@ struct _StTheme
{ {
GObject parent; GObject parent;
char *application_stylesheet; GFile *application_stylesheet;
char *default_stylesheet; GFile *default_stylesheet;
char *theme_stylesheet; GFile *theme_stylesheet;
GSList *custom_stylesheets; GSList *custom_stylesheets;
GHashTable *stylesheets_by_filename; GHashTable *stylesheets_by_file;
GHashTable *filenames_by_stylesheet; GHashTable *files_by_stylesheet;
CRCascade *cascade; CRCascade *cascade;
}; };
@ -98,12 +98,25 @@ G_DEFINE_TYPE (StTheme, st_theme, G_TYPE_OBJECT)
#define strqcmp(str,lit,lit_len) \ #define strqcmp(str,lit,lit_len) \
(strlen (str) != (lit_len) || memcmp (str, lit, lit_len)) (strlen (str) != (lit_len) || memcmp (str, lit, lit_len))
static gboolean
file_equal0 (GFile *file1,
GFile *file2)
{
if (file1 == file2)
return TRUE;
if ((file1 == NULL) || (file2 == NULL))
return FALSE;
return g_file_equal (file1, file2);
}
static void static void
st_theme_init (StTheme *theme) st_theme_init (StTheme *theme)
{ {
theme->stylesheets_by_filename = g_hash_table_new_full (g_str_hash, g_str_equal, theme->stylesheets_by_file = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
(GDestroyNotify)g_free, (GDestroyNotify)cr_stylesheet_unref); (GDestroyNotify)g_object_unref, (GDestroyNotify)cr_stylesheet_unref);
theme->filenames_by_stylesheet = g_hash_table_new (g_direct_hash, g_direct_equal); theme->files_by_stylesheet = g_hash_table_new (g_direct_hash, g_direct_equal);
} }
static void static void
@ -124,10 +137,10 @@ st_theme_class_init (StThemeClass *klass)
*/ */
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_APPLICATION_STYLESHEET, PROP_APPLICATION_STYLESHEET,
g_param_spec_string ("application-stylesheet", g_param_spec_object ("application-stylesheet",
"Application Stylesheet", "Application Stylesheet",
"Stylesheet with application-specific styling", "Stylesheet with application-specific styling",
NULL, G_TYPE_FILE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
/** /**
@ -138,10 +151,10 @@ st_theme_class_init (StThemeClass *klass)
*/ */
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_THEME_STYLESHEET, PROP_THEME_STYLESHEET,
g_param_spec_string ("theme-stylesheet", g_param_spec_object ("theme-stylesheet",
"Theme Stylesheet", "Theme Stylesheet",
"Stylesheet with theme-specific styling", "Stylesheet with theme-specific styling",
NULL, G_TYPE_FILE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
/** /**
@ -152,10 +165,10 @@ st_theme_class_init (StThemeClass *klass)
*/ */
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_DEFAULT_STYLESHEET, PROP_DEFAULT_STYLESHEET,
g_param_spec_string ("default-stylesheet", g_param_spec_object ("default-stylesheet",
"Default Stylesheet", "Default Stylesheet",
"Stylesheet with global default styling", "Stylesheet with global default styling",
NULL, G_TYPE_FILE,
G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
signals[STYLESHEETS_CHANGED] = signals[STYLESHEETS_CHANGED] =
@ -168,23 +181,32 @@ st_theme_class_init (StThemeClass *klass)
} }
static CRStyleSheet * static CRStyleSheet *
parse_stylesheet (const char *filename, parse_stylesheet (GFile *file,
GError **error) GError **error)
{ {
enum CRStatus status; enum CRStatus status;
CRStyleSheet *stylesheet; CRStyleSheet *stylesheet;
char *contents;
gsize length;
if (filename == NULL) if (file == NULL)
return NULL; return NULL;
status = cr_om_parser_simply_parse_file ((const guchar *) filename, if (!g_file_load_contents (file, NULL, &contents, &length, NULL, error))
return NULL;
status = cr_om_parser_simply_parse_buf ((const guchar *) contents,
length,
CR_UTF_8, CR_UTF_8,
&stylesheet); &stylesheet);
g_free (contents);
if (status != CR_OK) if (status != CR_OK)
{ {
char *uri = g_file_get_uri (file);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Error parsing stylesheet '%s'; errcode:%d", filename, status); "Error parsing stylesheet '%s'; errcode:%d", uri, status);
g_free (uri);
return NULL; return NULL;
} }
@ -203,12 +225,12 @@ _st_theme_parse_declaration_list (const char *str)
/* Just g_warning for now until we have something nicer to do */ /* Just g_warning for now until we have something nicer to do */
static CRStyleSheet * static CRStyleSheet *
parse_stylesheet_nofail (const char *filename) parse_stylesheet_nofail (GFile *file)
{ {
GError *error = NULL; GError *error = NULL;
CRStyleSheet *result; CRStyleSheet *result;
result = parse_stylesheet (filename, &error); result = parse_stylesheet (file, &error);
if (error) if (error)
{ {
g_warning ("%s", error->message); g_warning ("%s", error->message);
@ -219,35 +241,33 @@ parse_stylesheet_nofail (const char *filename)
static void static void
insert_stylesheet (StTheme *theme, insert_stylesheet (StTheme *theme,
const char *filename, GFile *file,
CRStyleSheet *stylesheet) CRStyleSheet *stylesheet)
{ {
char *filename_copy;
if (stylesheet == NULL) if (stylesheet == NULL)
return; return;
filename_copy = g_strdup(filename); g_object_ref (file);
cr_stylesheet_ref (stylesheet); cr_stylesheet_ref (stylesheet);
g_hash_table_insert (theme->stylesheets_by_filename, filename_copy, stylesheet); g_hash_table_insert (theme->stylesheets_by_file, file, stylesheet);
g_hash_table_insert (theme->filenames_by_stylesheet, stylesheet, filename_copy); g_hash_table_insert (theme->files_by_stylesheet, stylesheet, file);
} }
gboolean gboolean
st_theme_load_stylesheet (StTheme *theme, st_theme_load_stylesheet (StTheme *theme,
const char *path, GFile *file,
GError **error) GError **error)
{ {
CRStyleSheet *stylesheet; CRStyleSheet *stylesheet;
stylesheet = parse_stylesheet (path, error); stylesheet = parse_stylesheet (file, error);
if (!stylesheet) if (!stylesheet)
return FALSE; return FALSE;
stylesheet->app_data = GUINT_TO_POINTER (TRUE); stylesheet->app_data = GUINT_TO_POINTER (TRUE);
insert_stylesheet (theme, path, stylesheet); insert_stylesheet (theme, file, stylesheet);
cr_stylesheet_ref (stylesheet); cr_stylesheet_ref (stylesheet);
theme->custom_stylesheets = g_slist_prepend (theme->custom_stylesheets, stylesheet); theme->custom_stylesheets = g_slist_prepend (theme->custom_stylesheets, stylesheet);
g_signal_emit (theme, signals[STYLESHEETS_CHANGED], 0); g_signal_emit (theme, signals[STYLESHEETS_CHANGED], 0);
@ -257,11 +277,11 @@ st_theme_load_stylesheet (StTheme *theme,
void void
st_theme_unload_stylesheet (StTheme *theme, st_theme_unload_stylesheet (StTheme *theme,
const char *path) GFile *file)
{ {
CRStyleSheet *stylesheet; CRStyleSheet *stylesheet;
stylesheet = g_hash_table_lookup (theme->stylesheets_by_filename, path); stylesheet = g_hash_table_lookup (theme->stylesheets_by_file, file);
if (!stylesheet) if (!stylesheet)
return; return;
@ -269,8 +289,8 @@ st_theme_unload_stylesheet (StTheme *theme,
return; return;
theme->custom_stylesheets = g_slist_remove (theme->custom_stylesheets, stylesheet); theme->custom_stylesheets = g_slist_remove (theme->custom_stylesheets, stylesheet);
g_hash_table_remove (theme->stylesheets_by_filename, path); g_hash_table_remove (theme->stylesheets_by_file, file);
g_hash_table_remove (theme->filenames_by_stylesheet, stylesheet); g_hash_table_remove (theme->files_by_stylesheet, stylesheet);
cr_stylesheet_unref (stylesheet); cr_stylesheet_unref (stylesheet);
g_signal_emit (theme, signals[STYLESHEETS_CHANGED], 0); g_signal_emit (theme, signals[STYLESHEETS_CHANGED], 0);
} }
@ -279,7 +299,7 @@ st_theme_unload_stylesheet (StTheme *theme,
* st_theme_get_custom_stylesheets: * st_theme_get_custom_stylesheets:
* @theme: an #StTheme * @theme: an #StTheme
* *
* Returns: (transfer full) (element-type utf8): the list of stylesheet filenames * Returns: (transfer full) (element-type GFile): the list of stylesheet files
* that were loaded with st_theme_load_stylesheet() * that were loaded with st_theme_load_stylesheet()
*/ */
GSList* GSList*
@ -291,9 +311,9 @@ st_theme_get_custom_stylesheets (StTheme *theme)
for (iter = theme->custom_stylesheets; iter; iter = iter->next) for (iter = theme->custom_stylesheets; iter; iter = iter->next)
{ {
CRStyleSheet *stylesheet = iter->data; CRStyleSheet *stylesheet = iter->data;
gchar *filename = g_hash_table_lookup (theme->filenames_by_stylesheet, stylesheet); GFile *file = g_hash_table_lookup (theme->files_by_stylesheet, stylesheet);
result = g_slist_prepend (result, g_strdup (filename)); result = g_slist_prepend (result, g_object_ref (file));
} }
return result; return result;
@ -334,12 +354,12 @@ st_theme_finalize (GObject * object)
g_slist_free (theme->custom_stylesheets); g_slist_free (theme->custom_stylesheets);
theme->custom_stylesheets = NULL; theme->custom_stylesheets = NULL;
g_hash_table_destroy (theme->stylesheets_by_filename); g_hash_table_destroy (theme->stylesheets_by_file);
g_hash_table_destroy (theme->filenames_by_stylesheet); g_hash_table_destroy (theme->files_by_stylesheet);
g_free (theme->application_stylesheet); g_clear_object (&theme->application_stylesheet);
g_free (theme->theme_stylesheet); g_clear_object (&theme->theme_stylesheet);
g_free (theme->default_stylesheet); g_clear_object (&theme->default_stylesheet);
if (theme->cascade) if (theme->cascade)
{ {
@ -362,36 +382,39 @@ st_theme_set_property (GObject *object,
{ {
case PROP_APPLICATION_STYLESHEET: case PROP_APPLICATION_STYLESHEET:
{ {
const char *path = g_value_get_string (value); GFile *file = g_value_get_object (value);
if (path != theme->application_stylesheet) if (!file_equal0 (file, theme->application_stylesheet))
{ {
g_free (theme->application_stylesheet); g_clear_object (&theme->application_stylesheet);
theme->application_stylesheet = g_strdup (path); if (file != NULL)
theme->application_stylesheet = g_object_ref (file);
} }
break; break;
} }
case PROP_THEME_STYLESHEET: case PROP_THEME_STYLESHEET:
{ {
const char *path = g_value_get_string (value); GFile *file = g_value_get_object (value);
if (path != theme->theme_stylesheet) if (!file_equal0 (file, theme->theme_stylesheet))
{ {
g_free (theme->theme_stylesheet); g_clear_object (&theme->theme_stylesheet);
theme->theme_stylesheet = g_strdup (path); if (file != NULL)
theme->theme_stylesheet = g_object_ref (file);
} }
break; break;
} }
case PROP_DEFAULT_STYLESHEET: case PROP_DEFAULT_STYLESHEET:
{ {
const char *path = g_value_get_string (value); GFile *file = g_value_get_object (value);
if (path != theme->default_stylesheet) if (!file_equal0 (file, theme->default_stylesheet))
{ {
g_free (theme->default_stylesheet); g_clear_object (&theme->default_stylesheet);
theme->default_stylesheet = g_strdup (path); if (file != NULL)
theme->default_stylesheet = g_object_ref (file);
} }
break; break;
@ -413,13 +436,13 @@ st_theme_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_APPLICATION_STYLESHEET: case PROP_APPLICATION_STYLESHEET:
g_value_set_string (value, theme->application_stylesheet); g_value_set_object (value, theme->application_stylesheet);
break; break;
case PROP_THEME_STYLESHEET: case PROP_THEME_STYLESHEET:
g_value_set_string (value, theme->theme_stylesheet); g_value_set_object (value, theme->theme_stylesheet);
break; break;
case PROP_DEFAULT_STYLESHEET: case PROP_DEFAULT_STYLESHEET:
g_value_set_string (value, theme->default_stylesheet); g_value_set_object (value, theme->default_stylesheet);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -439,9 +462,9 @@ st_theme_get_property (GObject *object,
* Return value: the newly created theme object * Return value: the newly created theme object
**/ **/
StTheme * StTheme *
st_theme_new (const char *application_stylesheet, st_theme_new (GFile *application_stylesheet,
const char *theme_stylesheet, GFile *theme_stylesheet,
const char *default_stylesheet) GFile *default_stylesheet)
{ {
StTheme *theme = g_object_new (ST_TYPE_THEME, StTheme *theme = g_object_new (ST_TYPE_THEME,
"application-stylesheet", application_stylesheet, "application-stylesheet", application_stylesheet,
@ -852,26 +875,19 @@ add_matched_properties (StTheme *a_this,
if (import_rule->sheet == NULL) if (import_rule->sheet == NULL)
{ {
char *filename = NULL; GFile *file = NULL;
if (import_rule->url->stryng && import_rule->url->stryng->str) if (import_rule->url->stryng && import_rule->url->stryng->str)
{ {
GFile *file;
file = _st_theme_resolve_url (a_this, file = _st_theme_resolve_url (a_this,
a_nodesheet, a_nodesheet,
import_rule->url->stryng->str); import_rule->url->stryng->str);
filename = g_file_get_path (file); import_rule->sheet = parse_stylesheet (file, NULL);
g_object_unref (file);
} }
if (filename)
import_rule->sheet = parse_stylesheet (filename, NULL);
if (import_rule->sheet) if (import_rule->sheet)
{ {
insert_stylesheet (a_this, filename, import_rule->sheet); insert_stylesheet (a_this, file, import_rule->sheet);
/* refcount of stylesheets starts off at zero, so we don't need to unref! */ /* refcount of stylesheets starts off at zero, so we don't need to unref! */
} }
else else
@ -882,8 +898,8 @@ add_matched_properties (StTheme *a_this,
import_rule->sheet = (CRStyleSheet *) - 1; import_rule->sheet = (CRStyleSheet *) - 1;
} }
if (filename) if (file)
g_free (filename); g_object_unref (file);
} }
if (import_rule->sheet != (CRStyleSheet *) - 1) if (import_rule->sheet != (CRStyleSheet *) - 1)
@ -1018,7 +1034,7 @@ _st_theme_resolve_url (StTheme *theme,
const char *url) const char *url)
{ {
char *scheme; char *scheme;
GFile *stylesheet, *resource; GFile *resource;
if ((scheme = g_uri_parse_scheme (url))) if ((scheme = g_uri_parse_scheme (url)))
{ {
@ -1027,21 +1043,18 @@ _st_theme_resolve_url (StTheme *theme,
} }
else if (base_stylesheet != NULL) else if (base_stylesheet != NULL)
{ {
const char *base_filename = NULL; GFile *base_file = NULL, *parent;
char *dirname;
base_filename = g_hash_table_lookup (theme->filenames_by_stylesheet, base_stylesheet); base_file = g_hash_table_lookup (theme->files_by_stylesheet, base_stylesheet);
/* This is an internal function, if we get here with /* This is an internal function, if we get here with
a bad @base_stylesheet we have a problem. */ a bad @base_stylesheet we have a problem. */
g_assert (base_filename); g_assert (base_file);
dirname = g_path_get_dirname (base_filename); parent = g_file_get_parent (base_file);
stylesheet = g_file_new_for_path (dirname); resource = g_file_resolve_relative_path (parent, url);
resource = g_file_resolve_relative_path (stylesheet, url);
g_object_unref (stylesheet); g_object_unref (parent);
g_free (dirname);
} }
else else
{ {

View File

@ -47,12 +47,12 @@ typedef struct _StThemeClass StThemeClass;
GType st_theme_get_type (void) G_GNUC_CONST; GType st_theme_get_type (void) G_GNUC_CONST;
StTheme *st_theme_new (const char *application_stylesheet, StTheme *st_theme_new (GFile *application_stylesheet,
const char *theme_stylesheet, GFile *theme_stylesheet,
const char *default_stylesheet); GFile *default_stylesheet);
gboolean st_theme_load_stylesheet (StTheme *theme, const char *path, GError **error); gboolean st_theme_load_stylesheet (StTheme *theme, GFile *file, GError **error);
void st_theme_unload_stylesheet (StTheme *theme, const char *path); void st_theme_unload_stylesheet (StTheme *theme, GFile *file);
GSList *st_theme_get_custom_stylesheets (StTheme *theme); GSList *st_theme_get_custom_stylesheets (StTheme *theme);
G_END_DECLS G_END_DECLS

View File

@ -430,14 +430,16 @@ main (int argc, char **argv)
StTheme *theme; StTheme *theme;
StThemeContext *context; StThemeContext *context;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
GFile *file;
gtk_init (&argc, &argv); gtk_init (&argc, &argv);
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1; return 1;
theme = st_theme_new ("st/test-theme.css", file = g_file_new_for_path ("st/test-theme.css");
NULL, NULL); theme = st_theme_new (file, NULL, NULL);
g_object_unref (file);
stage = clutter_stage_new (); stage = clutter_stage_new ();
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage)); context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const St = imports.gi.St; const St = imports.gi.St;
@ -10,7 +11,7 @@ function init(stage) {
Environment.init(); Environment.init();
let context = St.ThemeContext.get_for_stage(stage); let context = St.ThemeContext.get_for_stage(stage);
let stylesheetPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/test.css"; let stylesheetPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/test.css";
let theme = new St.Theme({ application_stylesheet: stylesheetPath }); let theme = new St.Theme({ application_stylesheet: Gio.File.new_for_path(stylesheetPath) });
context.set_theme(theme); context.set_theme(theme);
} }