grim/guifications3

moved gflib-gtk to the new cmake module
cmake
2010-12-15, Gary Kramlich
b6418db658c1
moved gflib-gtk to the new cmake module
/*
* Guifications - The end-all, be-all notification framework
* Copyright (C) 2003-2009 Gary Kramlich <grim@reaperworld.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <gflib/gf_native_plugin.h>
#include <stdlib.h>
#include <gmodule.h>
#include <gflib/gf_intl.h>
#include <gflib/gf_log.h>
#define GF_NATIVE_PLUGIN_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), GF_TYPE_NATIVE_PLUGIN, GfNativePluginPriv))
/******************************************************************************
* Structs
*****************************************************************************/
typedef struct _GfNativePluginPriv GfNativePluginPriv;
typedef struct _GfNativePluginTypeInfo GfNativePluginTypeInfo;
typedef struct _GfNativePluginInterfaceInfo GfNativePluginInterfaceInfo;
struct _GfNativePluginPriv {
GModule *module;
guint use_count;
GSList *type_infos;
GSList *interface_infos;
};
struct _GfNativePluginTypeInfo {
gboolean loaded;
GType type;
GType parent;
GTypeInfo info;
};
struct _GfNativePluginInterfaceInfo {
gboolean loaded;
GType instance_type;
GType interface_type;
GInterfaceInfo info;
};
/******************************************************************************
* Enums
*****************************************************************************/
enum {
PROP_ZERO,
PROP_MODULE,
PROP_LAST,
};
/******************************************************************************
* Functions
*****************************************************************************/
typedef gboolean (*GfNativePluginLoadFunc)(GfNativePlugin *);
typedef gboolean (*GfNativePluginUnloadFunc)(GfNativePlugin *);
/******************************************************************************
* Globals
*****************************************************************************/
static GObjectClass *parent_class = NULL;
/******************************************************************************
* Helpers
*****************************************************************************/
static GfNativePluginTypeInfo *
gf_native_plugin_find_type_info(GfNativePlugin *plugin, GType type) {
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
GSList *l = NULL;
for(l = priv->type_infos; l; l = l->next) {
GfNativePluginTypeInfo *info = (GfNativePluginTypeInfo *)(l->data);
if(info->type == type)
return info;
}
return NULL;
}
static GfNativePluginInterfaceInfo *
gf_native_plugin_find_interface_info(GfNativePlugin *plugin,
GType instance_type,
GType interface_type)
{
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
GSList *l = NULL;
for(l = priv->interface_infos; l; l = l->next) {
GfNativePluginInterfaceInfo *info =
(GfNativePluginInterfaceInfo *)(l->data);
if(info->instance_type == instance_type &&
info->interface_type == interface_type)
{
return info;
}
}
return NULL;
}
/******************************************************************************
* Interface Stuff
*****************************************************************************/
static void
gf_native_plugin_priv_use(GTypePlugin *plugin) {
GfNativePlugin *native = GF_NATIVE_PLUGIN(plugin);
if(!gf_native_plugin_use(native)) {
GfPluginInfo *info = gf_plugin_get_info(GF_PLUGIN(native));
const gchar *name = (info) ? info->name : "(unknown)";
gf_log_critical("GfNativePlugin",
"Fatal error - Could not reload previously loaded "
"plugin '%s'\n",
name);
}
}
static void
gf_native_plugin_complete_type_info(GTypePlugin *plugin, GType type,
GTypeInfo *info,
GTypeValueTable *value_table)
{
GfNativePlugin *native = GF_NATIVE_PLUGIN(plugin);
GfNativePluginTypeInfo *native_info =
gf_native_plugin_find_type_info(native, type);
*info = native_info->info;
if(native_info->info.value_table)
*value_table = *native_info->info.value_table;
}
static void
gf_native_plugin_complete_interface_info(GTypePlugin *plugin,
GType instance_type,
GType interface_type,
GInterfaceInfo *info)
{
GfNativePlugin *native = GF_NATIVE_PLUGIN(plugin);
GfNativePluginInterfaceInfo *iface_info =
gf_native_plugin_find_interface_info(native, instance_type,
interface_type);
*info = iface_info->info;
}
static void
gf_native_plugin_iface_init(GTypePluginClass *iface) {
iface->use_plugin = gf_native_plugin_priv_use;
iface->unuse_plugin = (void (*)(GTypePlugin *))gf_native_plugin_unuse;
iface->complete_type_info = gf_native_plugin_complete_type_info;
iface->complete_interface_info = gf_native_plugin_complete_interface_info;
}
/******************************************************************************
* Object Stuff
*****************************************************************************/
static void
gf_native_plugin_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *psec)
{
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(obj);
switch(param_id) {
case PROP_MODULE:
g_value_set_pointer(value, priv->module);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
break;
}
}
static void
gf_native_plugin_set_property(GObject *obj, guint param_id,
const GValue *value, GParamSpec *psec)
{
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(obj);
switch(param_id) {
case PROP_MODULE:
priv->module = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, psec);
break;
}
}
static void
gf_native_plugin_finalize(GObject *obj) {
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(obj);
g_slist_free(priv->type_infos);
g_slist_free(priv->interface_infos);
G_OBJECT_CLASS(parent_class)->finalize(obj);
}
static void
gf_native_plugin_class_init(GfNativePluginClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
parent_class = g_type_class_peek_parent(klass);
g_type_class_add_private(klass, sizeof(GfNativePluginPriv));
obj_class->finalize = gf_native_plugin_finalize;
obj_class->get_property = gf_native_plugin_get_property;
obj_class->set_property = gf_native_plugin_set_property;
g_object_class_install_property(
obj_class,
PROP_MODULE,
g_param_spec_pointer(
"module",
P_("The GModule"),
P_("The GModule for this plugin."),
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
/******************************************************************************
* API
*****************************************************************************/
GType
gf_native_plugin_get_type(void) {
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(GfNativePluginClass),
NULL,
NULL,
(GClassInitFunc)gf_native_plugin_class_init,
NULL,
NULL,
sizeof(GfNativePlugin),
0,
NULL,
};
static const GInterfaceInfo iface_info = {
(GInterfaceInitFunc)gf_native_plugin_iface_init,
NULL,
NULL
};
type = g_type_register_static(GF_TYPE_PLUGIN,
"GfNativePlugin",
&info, 0);
g_type_add_interface_static(type, G_TYPE_TYPE_PLUGIN, &iface_info);
}
return type;
}
/**
* gf_native_plugin_use:
* @plugin: a #GfNativePlugin
*
* Calls the @use_plugin function from the #GfNativePluginClass of @plugin.
* There should be no need to use this function outside of the GObject type
* system itself.
*
* Return Value: TRUE if successful, FALSE otherwise.
*/
gboolean
gf_native_plugin_use(GfNativePlugin *plugin) {
GfNativePluginPriv *priv = NULL;
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), FALSE);
priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
priv->use_count++;
if(priv->use_count == 1) {
GfNativePluginLoadFunc load = NULL;
GSList *l = NULL;
gpointer func = NULL;
if(!g_module_symbol(priv->module, "gf_native_plugin_load", &func)) {
priv->use_count--;
return FALSE;
}
load = (GfNativePluginLoadFunc)func;
if(!(load && load(plugin))) {
priv->use_count--;
return FALSE;
}
for(l = priv->type_infos; l; l = l->next) {
GfNativePluginTypeInfo *info = (GfNativePluginTypeInfo *)(l->data);
if(!info->loaded) {
GfPluginInfo *plugin_info =
gf_plugin_get_info(GF_PLUGIN(plugin));
const gchar *name = (plugin_info) ? plugin_info->name :
"(unknown)";
gf_log_warning("GfNativePlugin",
"plugin '%s' failed to register type '%s'\n",
name, g_type_name(info->type));
return FALSE;
}
}
}
return TRUE;
}
/**
* gf_native_plugin_unuse:
* @plugin: a #GfNativePlugin
*
* Calls the @unuse_plugin function from the #GfNativePluginClass of @plugin.
* There should be no need to use this function outside of the GObject type
* system itself.
*
* Return Value: TRUE on success, FALSE otherwise.
*/
gboolean
gf_native_plugin_unuse(GfNativePlugin *plugin) {
GfNativePluginPriv *priv = NULL;
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), FALSE);
priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
g_return_val_if_fail(priv->use_count > 0, FALSE);
priv->use_count--;
if(priv->use_count == 0) {
GfNativePluginUnloadFunc unload = NULL;
GSList *l = NULL;
gpointer func = NULL;
if(!g_module_symbol(priv->module, "gf_native_plugin_unload", &func)) {
priv->use_count++;
return FALSE;
}
unload = (GfNativePluginUnloadFunc)func;
if(!(unload && unload(plugin))) {
priv->use_count++;
return FALSE;
}
for(l = priv->type_infos; l; l = l->next) {
GfNativePluginTypeInfo *info = (GfNativePluginTypeInfo *)(l->data);
info->loaded = FALSE;
return FALSE;
}
}
return TRUE;
}
/**
* gf_native_plugin_register_type:
* @plugin: a #GfNativePlugin
* @parent: The type of the parent class
* @name: name for the type
* @info: type information structure
* @flags: flags field providing details about the type
*
* Looks up or registers a type that is implemented via @plugin.
*
* Return Value: the new or existing type ID
*/
GType
gf_native_plugin_register_type(GfNativePlugin *plugin, GType parent,
const gchar *name, const GTypeInfo *info,
GTypeFlags flags)
{
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
GfNativePluginTypeInfo *type_info = NULL;
GType type = G_TYPE_INVALID;
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), G_TYPE_INVALID);
g_return_val_if_fail(name, G_TYPE_INVALID);
g_return_val_if_fail(info, G_TYPE_INVALID);
type = g_type_from_name(name);
if(type != G_TYPE_INVALID) {
/* this type is already loaded, let's make sure it's the same plugin
* loading it again.
*/
GTypePlugin *old = g_type_get_plugin(type);
if(old != G_TYPE_PLUGIN(plugin)) {
gf_log_warning("GfNativePlugin",
"Two different plugins tried to register '%s'\n",
name);
return G_TYPE_INVALID;
}
/* The same plugin is reloading the type */
type_info = gf_native_plugin_find_type_info(plugin, type);
if(type_info->parent != parent) {
/* eek, them bastards tried to reparent this type! */
const gchar *parent_name = g_type_name(parent);
gf_log_warning("GfNativePlugin",
"Type '%s' was recreated with a different parent "
"type.\n (was '%s', now '%s')\n",
name, g_type_name(type_info->parent),
(parent_name) ? parent_name : "(unknown)");
return G_TYPE_INVALID;
}
/* we need to free the old value table if the old type had one */
if(type_info->info.value_table)
g_free((GTypeValueTable *)type_info->info.value_table);
} else {
/* the type hasn't been loaded before, so now we need to add it */
type_info = g_new(GfNativePluginTypeInfo, 1);
type_info->parent = parent;
type_info->type = g_type_register_dynamic(parent, name,
G_TYPE_PLUGIN(plugin), flags);
priv->type_infos = g_slist_prepend(priv->type_infos, type_info);
}
/* ok, now finish up */
type_info->loaded = TRUE;
type_info->info = *info;
if(info->value_table) {
type_info->info.value_table = g_memdup(info->value_table,
sizeof(GTypeValueTable));
}
return type_info->type;
}
/**
* gf_native_plugin_add_interface:
* @plugin: a #GfNativePlugin
* @instance_type: type to which to add the interface
* @interface_type: interface type to add
* @interface_info: type information structure
*
* Registers an additional interface for @instance_type.
*/
void
gf_native_plugin_add_interface(GfNativePlugin *plugin, GType instance_type,
GType interface_type,
const GInterfaceInfo *interface_info)
{
GfNativePluginPriv *priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
GfNativePluginInterfaceInfo *iface_info = NULL;
g_return_if_fail(GF_IS_NATIVE_PLUGIN(plugin));
g_return_if_fail(interface_info);
if(g_type_is_a(instance_type, interface_type)) {
GTypePlugin *old = g_type_interface_get_plugin(instance_type,
interface_type);
if(!old) {
gf_log_warning("GfNativePlugin",
"Interface '%s' for '%s' was previously registered "
"statically or for a parent type.",
g_type_name(interface_type),
g_type_name(instance_type));
return;
} else if(old != G_TYPE_PLUGIN(plugin)) {
gf_log_warning("GfNativePlugin",
"Two different plugins tried to register interface "
"'%s' for '%s'.",
g_type_name(interface_type),
g_type_name(instance_type));
return;
}
iface_info = gf_native_plugin_find_interface_info(plugin,
instance_type,
interface_type);
g_return_if_fail(iface_info);
} else {
iface_info = g_new0(GfNativePluginInterfaceInfo, 1);
iface_info->instance_type = instance_type;
iface_info->interface_type = interface_type;
g_type_add_interface_dynamic(instance_type, interface_type,
G_TYPE_PLUGIN(plugin));
priv->interface_infos = g_slist_prepend(priv->interface_infos,
iface_info);
}
iface_info->loaded = TRUE;
iface_info->info = *interface_info;
}
/**
* gf_native_plugin_register_enum:
* @plugin: a #GfNativePlugin
* @name: name for the type
* @values: an array of #GEnumValue structs for the possible enumeration
* values. The array is terminated by a struct with all members
* being 0.
*
* Looks up or registers an enumeration that is implemented with @plugin.
*
* Return Value: the new or existing type ID
*/
GType
gf_native_plugin_register_enum(GfNativePlugin *plugin, const gchar *name,
const GEnumValue *values)
{
GTypeInfo enum_info = { 0, };
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), G_TYPE_INVALID);
g_return_val_if_fail(name, G_TYPE_INVALID);
g_return_val_if_fail(values, G_TYPE_INVALID);
g_enum_complete_type_info(G_TYPE_ENUM, &enum_info, values);
return gf_native_plugin_register_type(plugin, G_TYPE_ENUM, name,
&enum_info, 0);
}
/**
* gf_native_plugin_register_flags:
* @plugin: a #GfNativePlugin
* @name: name for the type
* @values: an array of GFlagsValue structs for the possible flags values.
* The array is terminated by a struct with all members being 0.
*
* Looks up or registers a flags type that is implemented with @plugin.
*
* Return Value: the new or existing type ID
*/
GType
gf_native_plugin_register_flags(GfNativePlugin *plugin, const gchar *name,
const GFlagsValue *values)
{
GTypeInfo flags_info = { 0, };
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), G_TYPE_INVALID);
g_return_val_if_fail(name, G_TYPE_INVALID);
g_return_val_if_fail(values, G_TYPE_INVALID);
g_flags_complete_type_info(G_TYPE_FLAGS, &flags_info, values);
return gf_native_plugin_register_type(plugin, G_TYPE_FLAGS, name,
&flags_info, 0);
}
/**
* gf_native_plugin_get_module:
* @plugin: a #GfNativePlugin
*
* Gets the #GModule that was open for @plugin.
*
* Return Value: The #GModule for @plugin.
*/
GModule *
gf_native_plugin_get_module(GfNativePlugin *plugin) {
GfNativePluginPriv *priv = NULL;
g_return_val_if_fail(GF_IS_NATIVE_PLUGIN(plugin), NULL);
priv = GF_NATIVE_PLUGIN_GET_PRIVATE(plugin);
return priv->module;
}