Add functions to dynamically load/unload stylesheets

For implementing extensions, we want the ability to add a stylesheet
dynamically, and unload it as well.

https://bugzilla.gnome.org/show_bug.cgi?id=599661
This commit is contained in:
Colin Walters 2009-10-24 13:10:15 -04:00
parent 368d484dee
commit b6cc9c7ff6
2 changed files with 86 additions and 18 deletions

View File

@ -44,6 +44,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <gio/gio.h>
#include "st-theme-node.h" #include "st-theme-node.h"
#include "st-theme-private.h" #include "st-theme-private.h"
@ -68,6 +70,7 @@ struct _StTheme
char *application_stylesheet; char *application_stylesheet;
char *default_stylesheet; char *default_stylesheet;
char *theme_stylesheet; char *theme_stylesheet;
GSList *custom_stylesheets;
GHashTable *stylesheets_by_filename; GHashTable *stylesheets_by_filename;
GHashTable *filenames_by_stylesheet; GHashTable *filenames_by_stylesheet;
@ -193,24 +196,19 @@ convert_rgba_RGBA (char *buf)
} }
static CRStyleSheet * static CRStyleSheet *
parse_stylesheet (const char *filename) parse_stylesheet (const char *filename,
GError **error)
{ {
enum CRStatus status; enum CRStatus status;
char *contents; char *contents;
gsize length; gsize length;
GError *error = NULL;
CRStyleSheet *stylesheet = NULL; CRStyleSheet *stylesheet = NULL;
if (filename == NULL) if (filename == NULL)
return NULL; return NULL;
if (!g_file_get_contents (filename, &contents ,&length, &error)) if (!g_file_get_contents (filename, &contents, &length, error))
{ return NULL;
g_warning("Couldn't read stylesheet: %s", error->message);
g_error_free (error);
return NULL;
}
convert_rgba_RGBA (contents); convert_rgba_RGBA (contents);
@ -218,11 +216,14 @@ parse_stylesheet (const char *filename)
length, length,
CR_UTF_8, CR_UTF_8,
&stylesheet); &stylesheet);
g_free (contents);
if (status != CR_OK) if (status != CR_OK)
g_warning ("Error parsing stylesheet '%s'", filename); {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
g_free (contents); "Error parsing stylesheet '%s'; errcode:%d", filename, status);
return NULL;
}
return stylesheet; return stylesheet;
} }
@ -243,7 +244,8 @@ _st_theme_parse_declaration_list (const char *str)
} }
#else /* LIBCROCO_VERSION_NUMBER >= 602 */ #else /* LIBCROCO_VERSION_NUMBER >= 602 */
static CRStyleSheet * static CRStyleSheet *
parse_stylesheet (const char *filename) parse_stylesheet (const char *filename,
GError **error)
{ {
enum CRStatus status; enum CRStatus status;
CRStyleSheet *stylesheet; CRStyleSheet *stylesheet;
@ -257,7 +259,8 @@ parse_stylesheet (const char *filename)
if (status != CR_OK) if (status != CR_OK)
{ {
g_warning ("Error parsing stylesheet '%s'", filename); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Error parsing stylesheet '%s'; errcode:%d", filename, status);
return NULL; return NULL;
} }
@ -272,6 +275,22 @@ _st_theme_parse_declaration_list (const char *str)
} }
#endif /* LIBCROCO_VERSION_NUMBER < 602 */ #endif /* LIBCROCO_VERSION_NUMBER < 602 */
/* Just g_warning for now until we have something nicer to do */
static CRStyleSheet *
parse_stylesheet_nofail (const char *filename)
{
GError *error = NULL;
CRStyleSheet *result;
result = parse_stylesheet (filename, &error);
if (error)
{
g_warning ("%s", error->message);
g_clear_error (&error);
}
return result;
}
static void static void
insert_stylesheet (StTheme *theme, insert_stylesheet (StTheme *theme,
const char *filename, const char *filename,
@ -289,6 +308,42 @@ insert_stylesheet (StTheme *theme,
g_hash_table_insert (theme->filenames_by_stylesheet, stylesheet, filename_copy); g_hash_table_insert (theme->filenames_by_stylesheet, stylesheet, filename_copy);
} }
gboolean
st_theme_load_stylesheet (StTheme *theme,
const char *path,
GError **error)
{
CRStyleSheet *stylesheet;
stylesheet = parse_stylesheet (path, error);
if (!stylesheet)
return FALSE;
insert_stylesheet (theme, path, stylesheet);
theme->custom_stylesheets = g_slist_prepend (theme->custom_stylesheets, stylesheet);
return TRUE;
}
void
st_theme_unload_stylesheet (StTheme *theme,
const char *path)
{
CRStyleSheet *stylesheet;
stylesheet = g_hash_table_lookup (theme->stylesheets_by_filename, path);
if (!stylesheet)
return;
if (!g_slist_find (theme->custom_stylesheets, stylesheet))
return;
theme->custom_stylesheets = g_slist_remove (theme->custom_stylesheets, stylesheet);
g_hash_table_remove (theme->stylesheets_by_filename, path);
g_hash_table_remove (theme->filenames_by_stylesheet, stylesheet);
cr_stylesheet_unref (stylesheet);
}
static GObject * static GObject *
st_theme_constructor (GType type, st_theme_constructor (GType type,
guint n_construct_properties, guint n_construct_properties,
@ -305,9 +360,9 @@ st_theme_constructor (GType type,
construct_properties); construct_properties);
theme = ST_THEME (object); theme = ST_THEME (object);
application_stylesheet = parse_stylesheet (theme->application_stylesheet); application_stylesheet = parse_stylesheet_nofail (theme->application_stylesheet);
theme_stylesheet = parse_stylesheet (theme->theme_stylesheet); theme_stylesheet = parse_stylesheet_nofail (theme->theme_stylesheet);
default_stylesheet = parse_stylesheet (theme->default_stylesheet); default_stylesheet = parse_stylesheet_nofail (theme->default_stylesheet);
theme->cascade = cr_cascade_new (application_stylesheet, theme->cascade = cr_cascade_new (application_stylesheet,
theme_stylesheet, theme_stylesheet,
@ -328,6 +383,10 @@ st_theme_finalize (GObject * object)
{ {
StTheme *theme = ST_THEME (object); StTheme *theme = ST_THEME (object);
g_slist_foreach (theme->custom_stylesheets, (GFunc) cr_stylesheet_unref, NULL);
g_slist_free (theme->custom_stylesheets);
theme->custom_stylesheets = NULL;
g_hash_table_destroy (theme->stylesheets_by_filename); g_hash_table_destroy (theme->stylesheets_by_filename);
g_hash_table_destroy (theme->filenames_by_stylesheet); g_hash_table_destroy (theme->filenames_by_stylesheet);
@ -559,6 +618,7 @@ id_add_sel_matches_style (CRAdditionalSel *a_add_sel,
} }
/** /**
*additional_selector_matches_style:
*Evaluates if a given additional selector matches an style node. *Evaluates if a given additional selector matches an style node.
*@param a_add_sel the additional selector to consider. *@param a_add_sel the additional selector to consider.
*@param a_node the style node to consider. *@param a_node the style node to consider.
@ -862,7 +922,7 @@ add_matched_properties (StTheme *a_this,
import_rule->url->stryng->str); import_rule->url->stryng->str);
if (filename) if (filename)
import_rule->sheet = parse_stylesheet (filename); import_rule->sheet = parse_stylesheet (filename, NULL);
if (import_rule->sheet) if (import_rule->sheet)
{ {
@ -980,6 +1040,7 @@ _st_theme_get_matched_properties (StTheme *theme,
enum CRStyleOrigin origin = 0; enum CRStyleOrigin origin = 0;
CRStyleSheet *sheet = NULL; CRStyleSheet *sheet = NULL;
GPtrArray *props = g_ptr_array_new (); GPtrArray *props = g_ptr_array_new ();
GSList *iter;
g_return_val_if_fail (ST_IS_THEME (theme), NULL); g_return_val_if_fail (ST_IS_THEME (theme), NULL);
g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL); g_return_val_if_fail (ST_IS_THEME_NODE (node), NULL);
@ -993,6 +1054,9 @@ _st_theme_get_matched_properties (StTheme *theme,
add_matched_properties (theme, sheet, node, props); add_matched_properties (theme, sheet, node, props);
} }
for (iter = theme->custom_stylesheets; iter; iter = iter->next)
add_matched_properties (theme, iter->data, node, props);
/* We count on a stable sort here so that later declarations come /* We count on a stable sort here so that later declarations come
* after earlier declarations */ * after earlier declarations */
g_ptr_array_sort (props, compare_declarations); g_ptr_array_sort (props, compare_declarations);

View File

@ -33,6 +33,10 @@ StTheme *st_theme_new (const char *application_stylesheet,
const char *theme_stylesheet, const char *theme_stylesheet,
const char *default_stylesheet); const char *default_stylesheet);
gboolean st_theme_load_stylesheet (StTheme *theme, const char *path, GError **error);
void st_theme_unload_stylesheet (StTheme *theme, const char *path);
G_END_DECLS G_END_DECLS
#endif /* __ST_THEME_H__ */ #endif /* __ST_THEME_H__ */