dbus/glib/examples/statemachine/statemachine.c
Colin Walters e888647a70 2005-07-08 Colin Walters <walters@verbum.org>
* tools/Makefile.am: Kill of print-introspect in favor of using
	dbus-send --print-reply=literal.
	* tools/print-introspect.c: Deleted.

	* test/glib/test-service-glib.xml:
	* test/glib/test-service-glib.c (my_object_get_objs): New test
	for "ao".

	* test/glib/test-dbus-glib.c (echo_received_cb): Free echo data.
	(main): Test GetObjs.

	* glib/examples/statemachine/Makefile.am:
	* glib/examples/statemachine/sm-marshal.list:
	* glib/examples/statemachine/statemachine-client.c:
	* glib/examples/statemachine/statemachine-server.c:
	* glib/examples/statemachine/statemachine-server.xml:
	* glib/examples/statemachine/statemachine.c:
	* glib/examples/statemachine/statemachine.h:
	* glib/examples/statemachine/statemachine.xml:

	New example.

	* glib/examples/example-service.c (main): Move invocation
	of dbus_g_object_type_install_info earlier, to emphasize it
	should only be done once.

	* glib/examples/example-signal-emitter.c (main): Ditto.

	* glib/examples/Makefile.am (SUBDIRS): Include statemachine.

	* glib/dbus-gvalue.h (dbus_gtype_to_signature)
	(dbus_gvalue_marshal): Update prototypes.

	* glib/dbus-gvalue.c: Update all marshalling functions to take
	const GValue instead of GValue.
	(signature_iter_to_g_type_array): Return a GPtrArray for nonfixed
	types.
	(dbus_gvalue_to_signature): Update for dbus_gtype_to_signature
	change.
	(dbus_gtype_to_signature): Handle generic collecitons and maps.
	Return a newly-allocated string.
	(demarshal_proxy, demarshal_object_path, demarshal_object)
	(demarshal_strv, demarshal_ghashtable): Set error, don't assert if
	we get the wrong types from message.
	(get_type_demarshaller): New function, extracted from
	dbus_gvalue_demarshal.
	(demarshal_collection): New function, demarshals generic
	collection.
	(dbus_gvalue_demarshal): Just invoke result of
	get_type_demarshaller.  Throw error if we don't have one.
	(marshal_garray_basic): Abort on OOM.
	(get_type_marshaller): New function, extracted from
	dbus_gvalue_marshal.
	(collection_marshal_iterator, marshal_collection): New functions;
	implements generic marshalling for an iteratable specialized
	collection.
	(dbus_gvalue_marshal): Just invoke result of get_type_marshaller.

	* glib/dbus-gvalue-utils.c (gvalue_from_ptrarray_value): Handle
	G_TYPE_STRING.
	(ptrarray_value_from_gvalue): Ditto.
	(ptrarray_append, ptrarray_free): New functions.
	(slist_constructor, slist_iterator, slist_copy_elt, slist_copy)
	(slist_append, slist_end_append, slist_free): New functions.
	(dbus_g_type_specialized_builtins_init): Add append fuctions
	for GPtrArray and GSList.  Register GSList.
	(test_specialized_hash, _dbus_gvalue_utils_test): New functions.

	* glib/dbus-gtype-specialized.h (DBusGTypeSpecializedAppendContext):
	New.
	(dbus_g_type_specialized_collection_init_append)
	(dbus_g_type_specialized_collection_append)
	(dbus_g_type_specialized_collection_end_append): Prototype.
	(DBusGTypeSpecializedCollectionVtable): Add append_func and
	end_append_func.

	* glib/dbus-gtype-specialized.c (dbus_g_type_specialized_collection_init_append)
	(dbus_g_type_specialized_collection_append)
	(dbus_g_type_specialized_collection_end_append): New functions.
	(dbus_g_type_map_value_iterate): Take const GValue.
	(dbus_g_type_collection_value_iterate): Ditto.

	* glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run
	_dbus_gvalue_utils_test.

	* glib/dbus-gtest.h: Prototype it.

	* glib/dbus-gproxy.c (dbus_g_proxy_manager_filter): Avoid
	using uninitialized owner_list.
	(dbus_g_proxy_begin_call_internal): Move return_if_fail to
	public API.
	(dbus_g_proxy_end_call_internal): Update to use error set
	from dbus_gvalue_demarshal instead of setting it here.
	(dbus_g_proxy_begin_call): Move return_if_fail here.

	* glib/dbus-gobject.c (write_interface): Update for
	dbus_gtype_to_signature returning new string.

	* configure.in: Add glib/examples/statemachine.
2005-07-08 16:25:39 +00:00

351 lines
7.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include "statemachine.h"
static void clear_pending_tasks (SMObject *object);
static void state_change (SMObject *object, SMObjectState new_state);
static void sm_object_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void sm_object_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
enum
{
PROP_0,
PROP_NAME,
};
enum
{
STATE_CHANGED,
ACQUISITION_FAILED,
ACQUISITION_PROGRESS,
LAST_SIGNAL
};
static guint sm_object_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(SMObject, sm_object, G_TYPE_OBJECT)
static void
sm_object_init (SMObject *obj)
{
obj->state = SM_OBJECT_STATE_SHUTDOWN;
}
static void
sm_object_class_init (SMObjectClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
object_class->set_property = sm_object_set_property;
object_class->get_property = sm_object_get_property;
g_object_class_install_property (object_class,
PROP_NAME,
g_param_spec_string ("name",
"name",
"name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
sm_object_signals[STATE_CHANGED] =
g_signal_new ("state-changed",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
sm_object_signals[ACQUISITION_PROGRESS] =
g_signal_new ("acquisition-progress",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
g_cclosure_marshal_VOID__DOUBLE,
G_TYPE_NONE, 1, G_TYPE_DOUBLE);
sm_object_signals[ACQUISITION_FAILED] =
g_signal_new ("acquisition-failed",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
/* This should really be standard. */
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
GQuark
sm_error_quark (void)
{
static GQuark ret = 0;
if (!ret)
ret = g_quark_from_static_string ("SMObjectErrorQuark");
return ret;
}
GType
sm_object_state_get_type (void)
{
static GType etype = 0;
if (etype == 0)
{
static const GEnumValue values[] =
{
ENUM_ENTRY (SM_OBJECT_STATE_SHUTDOWN, "Shutdown"),
ENUM_ENTRY (SM_OBJECT_STATE_INITIALIZED, "Loading"),
ENUM_ENTRY (SM_OBJECT_STATE_ACQUIRED, "Resource acquired"),
ENUM_ENTRY (SM_OBJECT_STATE_OPERATING, "Operating normally"),
{ 0, 0, 0 }
};
etype = g_enum_register_static ("SMObjectState", values);
}
return etype;
}
GType
sm_error_get_type (void)
{
static GType etype = 0;
if (etype == 0)
{
static const GEnumValue values[] =
{
ENUM_ENTRY (SM_ERROR_INVALID_STATE, "InvalidState"),
ENUM_ENTRY (SM_ERROR_NAME_IN_USE, "NameInUse"),
{ 0, 0, 0 }
};
g_assert (SM_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
etype = g_enum_register_static ("SMError", values);
}
return etype;
}
static void
sm_object_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SMObject *sm = SM_OBJECT (object);
switch (prop_id)
{
case PROP_NAME:
sm->name = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
sm_object_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SMObject *sm= SM_OBJECT (object);
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, sm->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
queue_task (SMObject *object, guint delay, GSourceFunc func)
{
guint id;
id = g_timeout_add (delay, func, object);
object->pending_tasks = g_slist_prepend (object->pending_tasks, GUINT_TO_POINTER (id));
}
static gboolean
idle_state_change (gpointer data)
{
SMObject *object = data;
state_change (object, object->requested_state);
return FALSE;
}
static gboolean
idle_further_acquire (gpointer data)
{
SMObject *object = data;
object->acquisition_progress += g_random_double_range (0.05, 0.5);
if (object->acquisition_progress > 1.0)
{
object->acquisition_progress = 1.0;
return FALSE;
}
else
{
g_signal_emit (object, sm_object_signals[ACQUISITION_PROGRESS], 0, object->acquisition_progress);
return TRUE;
}
}
static void
clear_pending_tasks (SMObject *object)
{
GSList *tmp;
for (tmp = object->pending_tasks; tmp; tmp = tmp->next)
g_source_remove (GPOINTER_TO_UINT (tmp->data));
g_slist_free (object->pending_tasks);
object->pending_tasks = NULL;
}
static const char *
state_to_string (SMObjectState state)
{
GEnumValue *value;
GEnumClass *prop_class;
const char *ret;
prop_class = g_type_class_ref (SM_TYPE_OBJECT_STATE);
value = g_enum_get_value (prop_class, state);
ret = value->value_nick;
g_type_class_unref (prop_class);
return ret;
}
static void
state_change (SMObject *object, SMObjectState new_state)
{
g_signal_emit (object, sm_object_signals[STATE_CHANGED], 0,
state_to_string (object->state),
state_to_string (new_state));
clear_pending_tasks (object);
if (new_state == SM_OBJECT_STATE_ACQUIRED)
{
object->acquisition_progress = 0.0;
queue_task (object, 1000, idle_further_acquire);
}
else if (new_state == SM_OBJECT_STATE_INITIALIZED)
{
if (g_random_int_range (0, 2) == 0)
{
object->requested_state = SM_OBJECT_STATE_ACQUIRED;
queue_task (object, 3000, idle_state_change);
}
}
object->state = new_state;
}
gboolean
sm_object_get_info (SMObject *object, char **name, char **state, GError **error)
{
*name= g_strdup (object->name);
*state = g_strdup (state_to_string (object->state));
return TRUE;
}
gboolean
sm_object_start (SMObject *object, GError **error)
{
if (object->state != SM_OBJECT_STATE_SHUTDOWN)
{
g_set_error (error,
SM_ERROR,
SM_ERROR_INVALID_STATE,
"%s",
"Can't start from non-shutdown state");
return FALSE;
}
state_change (object, SM_OBJECT_STATE_INITIALIZED);
return TRUE;
}
gboolean
sm_object_shutdown (SMObject *object, GError **error)
{
if (object->state != SM_OBJECT_STATE_INITIALIZED)
{
g_set_error (error,
SM_ERROR,
SM_ERROR_INVALID_STATE,
"%s",
"Can't shutdown from shutdown state");
return FALSE;
}
state_change (object, SM_OBJECT_STATE_SHUTDOWN);
return TRUE;
}
gboolean
sm_object_reinitialize (SMObject *object, GError **error)
{
if (object->state != SM_OBJECT_STATE_ACQUIRED
&& object->state != SM_OBJECT_STATE_OPERATING)
{
g_set_error (error,
SM_ERROR,
SM_ERROR_INVALID_STATE,
"Can't reinitialize from state %d",
object->state);
return FALSE;
}
state_change (object, SM_OBJECT_STATE_INITIALIZED);
return TRUE;
}
gboolean
sm_object_reacquire (SMObject *object, GError **error)
{
if (object->state != SM_OBJECT_STATE_ACQUIRED)
{
g_set_error (error,
SM_ERROR,
SM_ERROR_INVALID_STATE,
"Can't reacquire from state %d",
object->state);
return FALSE;
}
state_change (object, SM_OBJECT_STATE_ACQUIRED);
return TRUE;
}
gboolean
sm_object_get_acquiring_progress (SMObject *object, gdouble *out, GError **error)
{
if (object->state != SM_OBJECT_STATE_ACQUIRED)
{
g_set_error (error,
SM_ERROR,
SM_ERROR_INVALID_STATE,
"Can't get progress from state %d",
object->state);
return FALSE;
}
*out = object->acquisition_progress;
return TRUE;
}