mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 03:22:04 +00:00
2007-10-10 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/json/json-parser.c: Use the commodity JsonNode API and accept bare values as root nodes. * clutter/clutter-script-private.h: * clutter/clutter-script.c: Unreference the created objects only if they are top-levels, like ClutterBehaviour and ClutterTimelines. Actors have floating references, so we just transfer ownership to their containers, and the stage is owned by the backend. Add the "type_func" key to the object definition, so the user can supply its own GType function if the class name doesn't follow the GObject rules. Document the ClutterScript public API.
This commit is contained in:
parent
8faf9b9964
commit
7aa52af5dd
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
2007-10-10 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter/json/json-parser.c: Use the commodity JsonNode API
|
||||
and accept bare values as root nodes.
|
||||
|
||||
* clutter/clutter-script-private.h:
|
||||
* clutter/clutter-script.c: Unreference the created objects
|
||||
only if they are top-levels, like ClutterBehaviour and
|
||||
ClutterTimelines. Actors have floating references, so we
|
||||
just transfer ownership to their containers, and the stage
|
||||
is owned by the backend. Add the "type_func" key to the
|
||||
object definition, so the user can supply its own GType
|
||||
function if the class name doesn't follow the GObject rules.
|
||||
Document the ClutterScript public API.
|
||||
|
||||
2007-10-10 Matthew Allum <mallum@openedhand.com>
|
||||
|
||||
* clutter/clutter-actor.c:
|
||||
|
@ -34,8 +34,9 @@ G_BEGIN_DECLS
|
||||
typedef GType (* GTypeGetFunc) (void);
|
||||
|
||||
typedef struct {
|
||||
gchar *class_name;
|
||||
gchar *id;
|
||||
gchar *class_name;
|
||||
gchar *type_func;
|
||||
|
||||
GList *properties;
|
||||
GList *children;
|
||||
@ -43,6 +44,8 @@ typedef struct {
|
||||
|
||||
GType gtype;
|
||||
GObject *object;
|
||||
|
||||
guint is_toplevel : 1;
|
||||
} ObjectInfo;
|
||||
|
||||
typedef struct {
|
||||
|
@ -83,6 +83,18 @@
|
||||
* }
|
||||
* </programlisting>
|
||||
*
|
||||
* And then to apply a defined behaviour to an actor defined inside the
|
||||
* definition of an actor, the "behaviour" member can be used:
|
||||
*
|
||||
* <programlisting>
|
||||
* {
|
||||
* "id" : "my-rotating-actor",
|
||||
* "type" : "ClutterTexture",
|
||||
* ...
|
||||
* "behaviours" : [ "rotate-behaviour" ]
|
||||
* }
|
||||
* </programlisting>
|
||||
*
|
||||
* #ClutterScript is available since Clutter 0.6
|
||||
*/
|
||||
|
||||
@ -130,6 +142,22 @@ G_DEFINE_TYPE (ClutterScript, clutter_script, G_TYPE_OBJECT);
|
||||
|
||||
static void object_info_free (gpointer data);
|
||||
|
||||
static GType
|
||||
resolve_type (const gchar *symbol)
|
||||
{
|
||||
static GModule *module = NULL;
|
||||
GTypeGetFunc func;
|
||||
GType gtype = G_TYPE_INVALID;
|
||||
|
||||
if (!module)
|
||||
module = g_module_open (NULL, 0);
|
||||
|
||||
if (g_module_symbol (module, symbol, (gpointer)&func))
|
||||
gtype = func ();
|
||||
|
||||
return gtype;
|
||||
}
|
||||
|
||||
/* tries to map a name in camel case into the corresponding get_type()
|
||||
* function, e.g.:
|
||||
*
|
||||
@ -306,6 +334,7 @@ construct_timeline (ClutterScript *script,
|
||||
|
||||
retval = CLUTTER_TIMELINE (clutter_script_construct_object (script, oinfo));
|
||||
|
||||
/* it needs to survive */
|
||||
g_object_ref (retval);
|
||||
object_info_free (oinfo);
|
||||
|
||||
@ -536,6 +565,7 @@ json_object_end (JsonParser *parser,
|
||||
JsonNode *val;
|
||||
GList *members, *l;
|
||||
|
||||
/* ignore any non-named object */
|
||||
if (!json_object_has_member (object, "id"))
|
||||
return;
|
||||
|
||||
@ -555,6 +585,14 @@ json_object_end (JsonParser *parser,
|
||||
val = json_object_get_member (object, "type");
|
||||
oinfo->class_name = json_node_dup_string (val);
|
||||
|
||||
if (json_object_has_member (object, "type_func"))
|
||||
{
|
||||
val = json_object_get_member (object, "type_func");
|
||||
oinfo->type_func = json_node_dup_string (val);
|
||||
}
|
||||
|
||||
oinfo->is_toplevel = FALSE;
|
||||
|
||||
members = json_object_get_members (object);
|
||||
for (l = members; l; l = l->next)
|
||||
{
|
||||
@ -708,6 +746,9 @@ translate_property (ClutterScript *script,
|
||||
retval = TRUE;
|
||||
break;
|
||||
case G_TYPE_ENUM:
|
||||
/* enumeration values can be expressed using the nick field
|
||||
* of GEnumValue or the actual integer value
|
||||
*/
|
||||
if (G_VALUE_HOLDS (src, G_TYPE_STRING))
|
||||
{
|
||||
const gchar *string = g_value_get_string (src);
|
||||
@ -736,6 +777,9 @@ translate_property (ClutterScript *script,
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* translates the PropertyInfo structure into a GParameter array to
|
||||
* be fed to g_object_newv()
|
||||
*/
|
||||
static void
|
||||
translate_properties (ClutterScript *script,
|
||||
ObjectInfo *oinfo,
|
||||
@ -923,7 +967,11 @@ clutter_script_construct_object (ClutterScript *script,
|
||||
|
||||
if (oinfo->gtype == G_TYPE_INVALID)
|
||||
{
|
||||
if (oinfo->type_func)
|
||||
oinfo->gtype = resolve_type (oinfo->type_func);
|
||||
else
|
||||
oinfo->gtype = resolve_type_lazily (oinfo->class_name);
|
||||
|
||||
if (oinfo->gtype == G_TYPE_INVALID)
|
||||
return NULL;
|
||||
}
|
||||
@ -958,6 +1006,10 @@ clutter_script_construct_object (ClutterScript *script,
|
||||
if (CLUTTER_IS_ACTOR (oinfo->object) && oinfo->behaviours)
|
||||
apply_behaviours (script, CLUTTER_ACTOR (oinfo->object), oinfo->behaviours);
|
||||
|
||||
if (CLUTTER_IS_BEHAVIOUR (oinfo->object) ||
|
||||
CLUTTER_IS_TIMELINE (oinfo->object))
|
||||
oinfo->is_toplevel = TRUE;
|
||||
|
||||
if (oinfo->id)
|
||||
g_object_set_data_full (oinfo->object, "clutter-script-name",
|
||||
g_strdup (oinfo->id),
|
||||
@ -995,8 +1047,9 @@ object_info_free (gpointer data)
|
||||
ObjectInfo *oinfo = data;
|
||||
GList *l;
|
||||
|
||||
g_free (oinfo->class_name);
|
||||
g_free (oinfo->id);
|
||||
g_free (oinfo->class_name);
|
||||
g_free (oinfo->type_func);
|
||||
|
||||
for (l = oinfo->properties; l; l = l->next)
|
||||
{
|
||||
@ -1014,7 +1067,7 @@ object_info_free (gpointer data)
|
||||
g_list_foreach (oinfo->behaviours, (GFunc) g_free, NULL);
|
||||
g_list_free (oinfo->behaviours);
|
||||
|
||||
if (oinfo->object)
|
||||
if (oinfo->is_toplevel && oinfo->object)
|
||||
g_object_unref (oinfo->object);
|
||||
|
||||
g_slice_free (ObjectInfo, oinfo);
|
||||
@ -1066,12 +1119,40 @@ clutter_script_init (ClutterScript *script)
|
||||
object_info_free);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_script_new:
|
||||
*
|
||||
* Creates a new #ClutterScript instance. #ClutterScript can be used
|
||||
* to load objects definitions for scenegraph elements, like actors,
|
||||
* or behavioural elements, like behaviours and timelines. The
|
||||
* definitions must be encoded using the JavaScript Object Notation (JSON)
|
||||
* language.
|
||||
*
|
||||
* Return value: the newly created #ClutterScript instance. Use
|
||||
* g_object_unref() when done.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
ClutterScript *
|
||||
clutter_script_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_SCRIPT, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_script_load_from_file:
|
||||
* @script: a #ClutterScript
|
||||
* @filename: the full path to the definition file
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Loads the definitions from @filename into @script and merges with
|
||||
* the currently loaded ones, if any.
|
||||
*
|
||||
* Return value: on error, zero is returned and @error is set
|
||||
* accordingly. On success, a positive integer is returned.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_script_load_from_file (ClutterScript *script,
|
||||
const gchar *filename,
|
||||
@ -1102,6 +1183,22 @@ clutter_script_load_from_file (ClutterScript *script,
|
||||
return priv->last_merge_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_script_load_from_data:
|
||||
* @script: a #ClutterScript
|
||||
* @data: a buffer containing the definitions
|
||||
* @length: the length of the buffer, or -1 if @data is a NUL-terminated
|
||||
* buffer
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Loads the definitions from @data into @script and merges with
|
||||
* the currently loaded ones, if any.
|
||||
*
|
||||
* Return value: on error, zero is returned and @error is set
|
||||
* accordingly. On success, a positive integer is returned.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
guint
|
||||
clutter_script_load_from_data (ClutterScript *script,
|
||||
const gchar *data,
|
||||
@ -1133,6 +1230,19 @@ clutter_script_load_from_data (ClutterScript *script,
|
||||
return priv->last_merge_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_script_get_object:
|
||||
* @script: a #ClutterScript
|
||||
* @name: the name of the object to retrieve
|
||||
*
|
||||
* Retrieves the object bound to @name. This function does not increment
|
||||
* the reference count of the returned object.
|
||||
*
|
||||
* Return value: the named object, or %NULL if no object with the
|
||||
* given name was available
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
GObject *
|
||||
clutter_script_get_object (ClutterScript *script,
|
||||
const gchar *name)
|
||||
@ -1169,6 +1279,20 @@ clutter_script_get_objects_valist (ClutterScript *script,
|
||||
return g_list_reverse (retval);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_script_get_objects:
|
||||
* @script: a #ClutterScript
|
||||
* @first_name: the name of the first object to retrieve
|
||||
* @Varargs: a %NULL-terminated list of names
|
||||
*
|
||||
* Retrieves a list of objects for the given names. This function does
|
||||
* not increment the reference count of the returned objects.
|
||||
*
|
||||
* Return value: a newly allocated #GList containing the found objects,
|
||||
* or %NULL. Use g_list_free() when done using it.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
GList *
|
||||
clutter_script_get_objects (ClutterScript *script,
|
||||
const gchar *first_name,
|
||||
|
@ -343,7 +343,6 @@ json_parse_array (JsonParser *parser,
|
||||
while (token != G_TOKEN_RIGHT_BRACE)
|
||||
{
|
||||
JsonNode *node = NULL;
|
||||
GValue value = { 0, };
|
||||
|
||||
if (token == G_TOKEN_COMMA)
|
||||
{
|
||||
@ -421,44 +420,25 @@ json_parse_array (JsonParser *parser,
|
||||
switch (token)
|
||||
{
|
||||
case G_TOKEN_INT:
|
||||
g_value_init (&value, G_TYPE_INT);
|
||||
g_value_set_int (&value, scanner->value.v_int);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_int (node, scanner->value.v_int);
|
||||
break;
|
||||
|
||||
case G_TOKEN_FLOAT:
|
||||
g_value_init (&value, G_TYPE_DOUBLE);
|
||||
g_value_set_double (&value, scanner->value.v_float);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_double (node, scanner->value.v_float);
|
||||
break;
|
||||
|
||||
case G_TOKEN_STRING:
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, scanner->value.v_string);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_string (node, scanner->value.v_string);
|
||||
break;
|
||||
|
||||
case JSON_TOKEN_TRUE:
|
||||
case JSON_TOKEN_FALSE:
|
||||
g_value_init (&value, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&value, token == JSON_TOKEN_TRUE ? TRUE : FALSE);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_boolean (node, token == JSON_TOKEN_TRUE ? TRUE
|
||||
: FALSE);
|
||||
break;
|
||||
|
||||
case JSON_TOKEN_NULL:
|
||||
@ -515,7 +495,6 @@ json_parse_object (JsonParser *parser,
|
||||
{
|
||||
JsonNode *node = NULL;
|
||||
gchar *name = NULL;
|
||||
GValue value = { 0, };
|
||||
|
||||
if (token == G_TOKEN_COMMA)
|
||||
{
|
||||
@ -621,44 +600,25 @@ json_parse_object (JsonParser *parser,
|
||||
switch (token)
|
||||
{
|
||||
case G_TOKEN_INT:
|
||||
g_value_init (&value, G_TYPE_INT);
|
||||
g_value_set_int (&value, scanner->value.v_int);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_int (node, scanner->value.v_int);
|
||||
break;
|
||||
|
||||
case G_TOKEN_FLOAT:
|
||||
g_value_init (&value, G_TYPE_DOUBLE);
|
||||
g_value_set_double (&value, scanner->value.v_float);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_double (node, scanner->value.v_float);
|
||||
break;
|
||||
|
||||
case G_TOKEN_STRING:
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, scanner->value.v_string);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_string (node, scanner->value.v_string);
|
||||
break;
|
||||
|
||||
case JSON_TOKEN_TRUE:
|
||||
case JSON_TOKEN_FALSE:
|
||||
g_value_init (&value, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&value, token == JSON_TOKEN_TRUE ? TRUE : FALSE);
|
||||
|
||||
node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_value (node, &value);
|
||||
|
||||
g_value_unset (&value);
|
||||
json_node_set_boolean (node, token == JSON_TOKEN_TRUE ? TRUE
|
||||
: FALSE);
|
||||
break;
|
||||
|
||||
case JSON_TOKEN_NULL:
|
||||
@ -713,6 +673,25 @@ json_parse_statement (JsonParser *parser,
|
||||
priv->root = priv->current_node = json_node_new (JSON_NODE_NULL);
|
||||
return G_TOKEN_NONE;
|
||||
|
||||
case JSON_TOKEN_TRUE:
|
||||
case JSON_TOKEN_FALSE:
|
||||
priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE);
|
||||
json_node_set_boolean (priv->current_node,
|
||||
token == JSON_TOKEN_TRUE ? TRUE : FALSE);
|
||||
return G_TOKEN_NONE;
|
||||
|
||||
case G_TOKEN_INT:
|
||||
case G_TOKEN_FLOAT:
|
||||
case G_TOKEN_STRING:
|
||||
priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE);
|
||||
if (token == G_TOKEN_INT)
|
||||
json_node_set_int (priv->current_node, scanner->value.v_int);
|
||||
else if (token == G_TOKEN_FLOAT)
|
||||
json_node_set_double (priv->current_node, scanner->value.v_float);
|
||||
else
|
||||
json_node_set_string (priv->current_node, scanner->value.v_string);
|
||||
return G_TOKEN_NONE;
|
||||
|
||||
default:
|
||||
g_scanner_get_next_token (scanner);
|
||||
return G_TOKEN_SYMBOL;
|
||||
|
@ -1,3 +1,9 @@
|
||||
2007-10-10 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter.types:
|
||||
* Makefile.am: Add ClutterScript and ignore clutter-script-private.h
|
||||
to avoid picking up private symbols.
|
||||
|
||||
2007-08-21 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter-sections.txt: Move ClutterStage and ClutterStageClass
|
||||
|
@ -54,6 +54,7 @@ IGNORE_HFILES=\
|
||||
clutter-keysyms.h \
|
||||
clutter-keysyms-table.h \
|
||||
clutter-enum-types.h \
|
||||
clutter-script-private.h \
|
||||
stamp-clutter-enum-types.h \
|
||||
stamp-clutter-marshal.h \
|
||||
cogl \
|
||||
|
@ -24,3 +24,4 @@ clutter_entry_get_type
|
||||
clutter_box_get_type
|
||||
clutter_hbox_get_type
|
||||
clutter_vbox_get_type
|
||||
clutter_script_get_type
|
||||
|
Loading…
Reference in New Issue
Block a user