summaryrefslogtreecommitdiff
path: root/gtk/gtkthemes.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtkthemes.c')
-rw-r--r--gtk/gtkthemes.c198
1 files changed, 179 insertions, 19 deletions
diff --git a/gtk/gtkthemes.c b/gtk/gtkthemes.c
index 571ec6574e..e79b737fa4 100644
--- a/gtk/gtkthemes.c
+++ b/gtk/gtkthemes.c
@@ -37,20 +37,34 @@
#include "config.h"
#include "gtkintl.h"
-typedef struct _GtkThemeEnginePrivate GtkThemeEnginePrivate;
+typedef struct _GtkThemeEnginePlugin GtkThemeEnginePlugin;
-struct _GtkThemeEnginePrivate {
- GtkThemeEngine engine;
-
+struct _GtkThemeEngine
+{
GModule *library;
- void *name;
void (*init) (GtkThemeEngine *);
void (*exit) (void);
+ GtkRcStyle *(*create_rc_style) ();
+ gchar *name;
+
+ GSList *plugins; /* TypePlugins for this engine */
+
guint refcount;
};
+struct _GtkThemeEnginePlugin
+{
+ GTypePlugin plugin;
+
+ GtkThemeEngine *engine;
+ gchar *engine_name;
+ GTypeInfo info;
+ GType type;
+ GType parent_type;
+};
+
static GHashTable *engine_hash = NULL;
#ifdef __EMX__
@@ -67,7 +81,7 @@ static void gen_8_3_dll_name(gchar *name, gchar *fullname)
GtkThemeEngine*
gtk_theme_engine_get (const gchar *name)
{
- GtkThemeEnginePrivate *result;
+ GtkThemeEngine *result;
if (!engine_hash)
engine_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -121,17 +135,20 @@ gtk_theme_engine_get (const gchar *name)
}
else
{
- result = g_new (GtkThemeEnginePrivate, 1);
+ result = g_new (GtkThemeEngine, 1);
result->refcount = 1;
result->name = g_strdup (name);
result->library = library;
+ result->plugins = NULL;
/* extract symbols from the lib */
if (!g_module_symbol (library, "theme_init",
(gpointer *)&result->init) ||
!g_module_symbol (library, "theme_exit",
- (gpointer *)&result->exit))
+ (gpointer *)&result->exit) ||
+ !g_module_symbol (library, "theme_create_rc_style",
+ (gpointer *)&result->create_rc_style))
{
g_warning (g_module_error());
g_free (result);
@@ -156,28 +173,171 @@ gtk_theme_engine_ref (GtkThemeEngine *engine)
{
g_return_if_fail (engine != NULL);
- ((GtkThemeEnginePrivate *)engine)->refcount++;
+ engine->refcount++;
}
void
gtk_theme_engine_unref (GtkThemeEngine *engine)
{
- GtkThemeEnginePrivate *private;
- private = (GtkThemeEnginePrivate *)engine;
+ GSList *tmp_list;
g_return_if_fail (engine != NULL);
- g_return_if_fail (private->refcount > 0);
+ g_return_if_fail (engine->refcount > 0);
- private->refcount--;
+ engine->refcount--;
- if (private->refcount == 0)
+ if (engine->refcount == 0)
{
- private->exit();
+ engine->exit();
+
+ g_hash_table_remove (engine_hash, engine->name);
+
+ tmp_list = engine->plugins;
+ while (tmp_list)
+ {
+ GtkThemeEnginePlugin *plugin = tmp_list->data;
+ plugin->engine = NULL;
+
+ tmp_list = tmp_list->next;
+ }
+ g_slist_free (engine->plugins);
- g_hash_table_remove (engine_hash, private->name);
+ g_module_close (engine->library);
+ g_free (engine->name);
+ g_free (engine);
+ }
+}
+
+GtkRcStyle *
+gtk_theme_engine_create_rc_style (GtkThemeEngine *engine)
+{
+ g_return_val_if_fail (engine != NULL, NULL);
+
+ return engine->create_rc_style ();
+}
+
+static void
+gtk_theme_engine_plugin_ref (GTypePlugin *plugin)
+{
+ GtkThemeEnginePlugin *theme_plugin = (GtkThemeEnginePlugin *)plugin;
+
+ if (theme_plugin->engine == NULL)
+ {
+ gtk_theme_engine_get (theme_plugin->engine_name);
+ if (!theme_plugin->engine)
+ {
+ g_warning ("An attempt to create an instance of a type from\n"
+ "a previously loaded theme engine was made after the engine\n"
+ "was unloaded, but the engine could not be reloaded or no longer\n"
+ "implements the type. Bad things will happen.\n");
+ }
+ }
+ else
+ gtk_theme_engine_ref (theme_plugin->engine);
+}
+
+static void
+gtk_theme_engine_plugin_unref (GTypePlugin *plugin)
+{
+ GtkThemeEnginePlugin *theme_plugin = (GtkThemeEnginePlugin *)plugin;
+
+ g_return_if_fail (theme_plugin->engine != NULL);
+
+ gtk_theme_engine_unref (theme_plugin->engine);
+}
+
+static void
+gtk_theme_engine_complete_type_info (GTypePlugin *plugin,
+ GType g_type,
+ GTypeInfo *info,
+ GTypeValueTable *value_table)
+{
+ GtkThemeEnginePlugin *theme_plugin = (GtkThemeEnginePlugin *)plugin;
+
+ *info = theme_plugin->info;
+}
+
+static GTypePluginVTable gtk_theme_engine_plugin_vtable = {
+ gtk_theme_engine_plugin_ref,
+ gtk_theme_engine_plugin_unref,
+ gtk_theme_engine_complete_type_info,
+ NULL
+};
+
+/**
+ * gtk_theme_engine_register_type:
+ * @engine: a #GtkThemeEngine
+ * @parent_type: the type for the parent class
+ * @type_name: name for the type
+ * @type_info: type information structure
+ *
+ * Looks up or registers a type that is implemented with a particular
+ * theme engine. If a type with name @type_name is already registered,
+ * the #GType identifier for the type is returned, otherwise the type
+ * is newly registered, and the resulting #GType identifier returned.
+ *
+ * As long as any instances of the type exist, the a reference will be
+ * held to the theme engine and the theme engine will not be unloaded.
+ *
+ * Return value: the type identifier for the class.
+ **/
+GType
+gtk_theme_engine_register_type (GtkThemeEngine *engine,
+ GType parent_type,
+ const gchar *type_name,
+ const GTypeInfo *type_info)
+{
+ GtkThemeEnginePlugin *plugin;
+ GType type;
+
+ g_return_val_if_fail (engine != NULL, 0);
+ g_return_val_if_fail (type_name != NULL, 0);
+ g_return_val_if_fail (type_info != NULL, 0);
+
+ type = g_type_from_name (type_name);
+ if (type)
+ plugin = (GtkThemeEnginePlugin *)g_type_get_plugin (type);
+ else
+ {
+ plugin = g_new (GtkThemeEnginePlugin, 1);
+
+ plugin->plugin.vtable = &gtk_theme_engine_plugin_vtable;
+ plugin->engine = NULL;
+ plugin->engine_name = NULL;
+ plugin->parent_type = parent_type;
+ plugin->type = g_type_register_dynamic (parent_type, type_name, (GTypePlugin *)plugin);
+ }
+
+ if (plugin->engine)
+ {
+ if (plugin->engine != engine)
+ {
+ g_warning ("Two different theme engines tried to register '%s'.", type_name);
+ return 0;
+ }
+
+ if (plugin->parent_type != parent_type)
+ {
+ g_warning ("Type '%s' recreated with different parent type.\n"
+ "(was '%s', now '%s')", type_name,
+ g_type_name (plugin->parent_type),
+ g_type_name (parent_type));
+ return 0;
+ }
+ }
+ else
+ {
+ plugin->engine = engine;
+ if (plugin->engine_name)
+ g_free (plugin->engine_name);
+
+ plugin->engine_name = g_strdup (engine->name);
- g_module_close (private->library);
- g_free (private->name);
- g_free (private);
+ plugin->info = *type_info;
+
+ engine->plugins = g_slist_prepend (engine->plugins, plugin);
}
+
+ return plugin->type;
}
+