/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* bonobo-generic-factory.c: a GenericFactory object.
*
* The BonoboGenericFactory object is used to instantiate new
* Bonobo::GenericFactory objects. It acts as a wrapper for the
* Bonobo::GenericFactory CORBA interface, and dispatches to
* a user-specified factory function whenever its create_object()
* method is invoked.
*
* Author:
* Miguel de Icaza (miguel@kernel.org)
* ÉRDI Gergõ (cactus@cactus.rulez.org): cleanup
*
* Copyright 1999, 2001 Ximian, Inc., 2001 Gergõ Érdi
*/
#include <config.h>
#include <string.h>
#include <glib-object.h>
#include <bonobo/Bonobo.h>
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-types.h>
#include <bonobo/bonobo-marshal.h>
#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-generic-factory.h>
#include <bonobo/bonobo-context.h>
#include <bonobo/bonobo-running-context.h>
#include <bonobo/bonobo-debug.h>
#include "bonobo-private.h"
#define DEFAULT_LAST_UNREF_TIMEOUT 2000
#define STARTUP_TIMEOUT 60000
struct _BonoboGenericFactoryPrivate {
/* The function factory */
GClosure *factory_closure;
/* The component_id for this generic factory */
char *act_iid;
/* Whether we should register with the activation server */
gboolean noreg;
/* Startup timeout when no object is ever requested */
guint startup_timeout_id;
/* Timeout after last unref before quitting */
guint last_unref_timeout_id;
guint last_unref_timeout; /* miliseconds */
guint last_unref_ignore; /* ignore last-unref caused by temporary objects */
gboolean last_unref_set; /* keep track of last-unref status during "ignore" period */
};
static GObjectClass *bonobo_generic_factory_parent_class = NULL;
static CORBA_Object
impl_Bonobo_ObjectFactory_createObject (PortableServer_Servant servant,
const CORBA_char *obj_act_iid,
CORBA_Environment *ev)
{
BonoboGenericFactoryClass *class;
BonoboGenericFactory *factory;
BonoboObject *object;
factory = BONOBO_GENERIC_FACTORY (bonobo_object (servant));
class = BONOBO_GENERIC_FACTORY_CLASS (G_OBJECT_GET_CLASS (factory));
BONOBO_LOCK();
/* Cancel the startup timeout, if active. */
if (factory->priv->startup_timeout_id) {
g_source_destroy (g_main_context_find_source_by_id
(NULL, factory->priv->startup_timeout_id));
factory->priv->startup_timeout_id = 0;
}
/* Cancel the last unref timeout, if active. */
if (factory->priv->last_unref_timeout_id) {
g_source_destroy (g_main_context_find_source_by_id
(NULL, factory->priv->last_unref_timeout_id));
factory->priv->last_unref_timeout_id = 0;
}
BONOBO_UNLOCK();
object = (*class->new_generic) (factory, obj_act_iid);
factory = NULL; /* unreffed by new_generic in the shlib case */
if (!object)
return CORBA_OBJECT_NIL;
return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev);
}
/**
* bonobo_generic_factory_construct_noreg:
* @factory: The object to be initialized.
* @act_iid: The GOAD id that the new factory will implement.
* @factory_closure: A Multi object factory closure.
*
* Initializes @c_factory with the supplied closure and iid.
*/
void
bonobo_generic_factory_construct_noreg (BonoboGenericFactory *factory,
const char *act_iid,
GClosure *factory_closure)
{
g_return_if_fail (BONOBO_IS_GENERIC_FACTORY (factory));
factory->priv->act_iid = g_strdup (act_iid);
factory->priv->noreg = TRUE;
if (factory_closure)
factory->priv->factory_closure =
bonobo_closure_store (factory_closure, bonobo_marshal_OBJECT__STRING);
}
/**
* bonobo_generic_factory_construct:
* @factory: The object to be initialized.
* @act_iid: The Bonobo activation id that the new factory will implement.
* Bonobo::GenericFactory interface and which will be used to
* construct this BonoboGenericFactory Gtk object.
* @factory_closure: A Multi object factory closure.
*
* Initializes @c_factory with and registers the new factory with
* the name server.
*
* Returns: The initialized BonoboGenericFactory object or NULL
* if already registered.
*/
BonoboGenericFactory *
bonobo_generic_factory_construct (BonoboGenericFactory *factory,
const char *act_iid,
GClosure *factory_closure)
{
int ret;
g_return_val_if_fail (BONOBO_IS_GENERIC_FACTORY (factory), NULL);
bonobo_generic_factory_construct_noreg (factory, act_iid, factory_closure);
factory->priv->noreg = FALSE;
ret = bonobo_activation_active_server_register (act_iid, BONOBO_OBJREF (factory));
if (ret != Bonobo_ACTIVATION_REG_SUCCESS) {
bonobo_object_unref (BONOBO_OBJECT (factory));
#ifdef G_ENABLE_DEBUG
if (_bonobo_debug_flags & BONOBO_DEBUG_LIFECYCLE) {
const char *err;
switch (ret)
{
case Bonobo_ACTIVATION_REG_SUCCESS: err = "success"; break;
case Bonobo_ACTIVATION_REG_NOT_LISTED: err = "not listed"; break;
case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE: err = "already active"; break;
case Bonobo_ACTIVATION_REG_ERROR: err = "error"; break;
default: err = "(invalid error!)"; break;
}
g_warning ("'%s' factory registration failed: %s",
act_iid, err);
}
#endif
return NULL;
}
return factory;
}
/**
* bonobo_generic_factory_new_closure:
* @act_iid: The GOAD id that this factory implements
* @factory_closure: A closure which is used to create new BonoboObject instances.
*
* This is a helper routine that simplifies the creation of factory
* objects for GNOME objects. The @factory_closure closure will be
* invoked by the CORBA server when a request arrives to create a new
* instance of an object supporting the Bonobo::Generic interface.
* The factory callback routine is passed the @data pointer to provide
* the creation function with some state information.
*
* Returns: A BonoboGenericFactory object that has an activated
* Bonobo::GenericFactory object that has registered with the GNOME
* name server.
*/
BonoboGenericFactory *
bonobo_generic_factory_new_closure (const char *act_iid,
GClosure *factory_closure)
{
BonoboGenericFactory *factory;
g_return_val_if_fail (act_iid != NULL, NULL);
g_return_val_if_fail (factory_closure != NULL, NULL);
factory = g_object_new (bonobo_generic_factory_get_type (), NULL);
return bonobo_generic_factory_construct (
factory, act_iid, factory_closure);
}
/**
* bonobo_generic_factory_new:
* @act_iid: The GOAD id that this factory implements
* @factory_cb: A callback which is used to create new BonoboObject instances.
* @user_data: The closure data to be passed to the @factory callback routine.
*
* This is a helper routine that simplifies the creation of factory
* objects for GNOME objects. The @factory function will be
* invoked by the CORBA server when a request arrives to create a new
* instance of an object supporting the Bonobo::Generic interface.
* The factory callback routine is passed the @data pointer to provide
* the creation function with some state information.
*
* Returns: A BonoboGenericFactory object that has an activated
* Bonobo::GenericFactory object that has registered with the GNOME
* name server.
*/
BonoboGenericFactory *
bonobo_generic_factory_new (const char *act_iid,
BonoboFactoryCallback factory_cb,
gpointer user_data)
{
return bonobo_generic_factory_new_closure (
act_iid, g_cclosure_new (G_CALLBACK (factory_cb), user_data, NULL));
}
static void
bonobo_generic_factory_destroy (BonoboObject *object)
{
BonoboGenericFactory *factory = BONOBO_GENERIC_FACTORY (object);
if (factory->priv) {
if (!factory->priv->noreg && factory->priv->act_iid)
bonobo_activation_active_server_unregister (
factory->priv->act_iid, BONOBO_OBJREF (factory));
g_free (factory->priv->act_iid);
if (factory->priv->factory_closure)
g_closure_unref (factory->priv->factory_closure);
/* Cancel the startup timeout, if active. */
if (factory->priv->startup_timeout_id)
g_source_destroy (g_main_context_find_source_by_id
(NULL, factory->priv->startup_timeout_id));
/* Cancel the last unref timeout, if active. */
if (factory->priv->last_unref_timeout_id)
g_source_destroy (g_main_context_find_source_by_id
(NULL, factory->priv->last_unref_timeout_id));
g_free (factory->priv);
factory->priv = NULL;
}
BONOBO_OBJECT_CLASS (bonobo_generic_factory_parent_class)->destroy (object);
}
static gboolean
last_unref_timeout (gpointer data)
{
BonoboGenericFactory *factory = BONOBO_GENERIC_FACTORY (data);
bonobo_main_quit ();
factory->priv->last_unref_timeout_id = 0;
return FALSE;
}
static BonoboObject *
bonobo_generic_factory_new_generic (BonoboGenericFactory *factory,
const char *act_iid)
{
BonoboObject *ret;
g_return_val_if_fail (factory != NULL, NULL);
g_return_val_if_fail (BONOBO_IS_GENERIC_FACTORY (factory), NULL);
BONOBO_LOCK();
factory->priv->last_unref_ignore++;
BONOBO_UNLOCK();
bonobo_closure_invoke (factory->priv->factory_closure,
BONOBO_TYPE_OBJECT, &ret,
BONOBO_TYPE_GENERIC_FACTORY, factory,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, act_iid, G_TYPE_INVALID);
BONOBO_LOCK();
factory->priv->last_unref_ignore--;
if (ret) /* since we are returning a new object, even if
* last-unref was previously caught it no longer
* applies */
factory->priv->last_unref_set = FALSE;
if (factory->priv->last_unref_set) {
factory->priv->last_unref_timeout_id = g_timeout_add
(factory->priv->last_unref_timeout, last_unref_timeout, factory);
factory->priv->last_unref_set = FALSE;
}
BONOBO_UNLOCK();
return ret;
}
static void
bonobo_generic_factory_class_init (BonoboGenericFactoryClass *klass)
{
BonoboObjectClass *bonobo_object_class = (BonoboObjectClass *) klass;
POA_Bonobo_GenericFactory__epv *epv = &klass->epv;
epv->createObject = impl_Bonobo_ObjectFactory_createObject;
bonobo_object_class->destroy = bonobo_generic_factory_destroy;
klass->new_generic = bonobo_generic_factory_new_generic;
bonobo_generic_factory_parent_class = g_type_class_peek_parent (klass);
}
static void
bonobo_generic_factory_init (GObject *object)
{
BonoboGenericFactory *factory = BONOBO_GENERIC_FACTORY (object);
factory->priv = g_new0 (BonoboGenericFactoryPrivate, 1);
factory->priv->noreg = FALSE;
factory->priv->last_unref_timeout = DEFAULT_LAST_UNREF_TIMEOUT;
}
BONOBO_TYPE_FUNC_FULL (BonoboGenericFactory,
Bonobo_GenericFactory,
BONOBO_TYPE_OBJECT,
bonobo_generic_factory)
static gboolean
startup_timeout (gpointer data)
{
BonoboGenericFactory *factory = BONOBO_GENERIC_FACTORY (data);
bonobo_main_quit ();
factory->priv->startup_timeout_id = 0;
return FALSE;
}
static void
last_unref_cb (BonoboRunningContext *context, BonoboGenericFactory *factory)
{
g_return_if_fail (BONOBO_IS_GENERIC_FACTORY (factory));
if (factory->priv->last_unref_ignore) {
factory->priv->last_unref_set = TRUE;
return;
}
g_return_if_fail (!factory->priv->last_unref_timeout_id);
factory->priv->last_unref_timeout_id = g_timeout_add
(factory->priv->last_unref_timeout, last_unref_timeout, factory);
}
/**
* bonobo_generic_factory_main:
* @act_iid: the oaf iid of the factory
* @factory_cb: the factory callback
* @user_data: a user data pointer
*
* A Generic 'main' routine so we don't stick a load of code
* inside a public macro. See also bonobo_generic_factory_main_timeout().
*
* Return value: 0 on success, 1 on failure.
**/
int
bonobo_generic_factory_main (const char *act_iid,
BonoboFactoryCallback factory_cb,
gpointer user_data)
{
return bonobo_generic_factory_main_timeout
(act_iid, factory_cb, user_data, DEFAULT_LAST_UNREF_TIMEOUT);
}
/**
* bonobo_generic_factory_main_timeout:
* @act_iid: the oaf iid of the factory
* @factory_cb: the factory callback
* @user_data: a user data pointer
* @quit_timeout: ammount of time to wait (miliseconds) after all
* objects have been released before quitting the main loop.
*
* A Generic 'main' routine so we don't stick a load of code
* inside a public macro.
*
* Return value: 0 on success, 1 on failure.
**/
int
bonobo_generic_factory_main_timeout (const char *act_iid,
BonoboFactoryCallback factory_cb,
gpointer user_data,
guint quit_timeout)
{
BonoboGenericFactory *factory;
factory = bonobo_generic_factory_new (
act_iid, factory_cb, user_data);
if (factory) {
BonoboObject *context;
guint signal;
factory->priv->last_unref_timeout = quit_timeout;
context = bonobo_running_context_new ();
signal = g_signal_connect (G_OBJECT (context), "last-unref",
G_CALLBACK (last_unref_cb), factory);
bonobo_running_context_ignore_object (BONOBO_OBJREF (factory));
/* Create timeout here so if we haven't created anything
* within a few minutes we just quit */
factory->priv->startup_timeout_id = g_timeout_add
(STARTUP_TIMEOUT, startup_timeout, factory);
bonobo_main ();
g_signal_handler_disconnect (G_OBJECT (context), signal);
bonobo_object_unref (BONOBO_OBJECT (factory));
bonobo_object_unref (context);
return bonobo_debug_shutdown ();
} else
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1