459
479
case JSON_NODE_OBJECT:
460
480
return parse_color_from_object (json_node_get_object (node), color);
482
case JSON_NODE_VALUE:
483
return clutter_color_from_string (color, json_node_get_string (node));
493
get_id_from_node (JsonNode *node)
497
switch (JSON_NODE_TYPE (node))
499
case JSON_NODE_OBJECT:
500
object = json_node_get_object (node);
501
if (json_object_has_member (object, "id"))
502
return json_object_get_string_member (object, "id");
505
case JSON_NODE_VALUE:
506
return json_node_get_string (node);
516
parse_children (ObjectInfo *oinfo,
523
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
526
retval = oinfo->children;
528
array = json_node_get_array (node);
529
array_len = json_array_get_length (array);
531
for (i = 0; i < array_len; i++)
533
JsonNode *child = json_array_get_element (array, i);
536
id = get_id_from_node (child);
538
retval = g_list_prepend (retval, g_strdup (id));
541
return g_list_reverse (retval);
545
parse_signals (ClutterScript *script,
553
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
555
_clutter_script_warn_invalid_value (script, "signals", "Array", node);
559
retval = oinfo->signals;
560
array = json_node_get_array (node);
561
array_len = json_array_get_length (array);
563
for (i = 0; i < array_len; i++)
565
JsonNode *val = json_array_get_element (array, i);
569
const gchar *handler;
570
const gchar *connect;
571
GConnectFlags flags = 0;
573
if (JSON_NODE_TYPE (val) != JSON_NODE_OBJECT)
575
_clutter_script_warn_invalid_value (script,
576
"signals array", "Object",
581
object = json_node_get_object (val);
583
/* mandatory: "name" */
584
if (!json_object_has_member (object, "name"))
586
_clutter_script_warn_missing_attribute (script, NULL, "name");
591
name = json_object_get_string_member (object, "name");
594
_clutter_script_warn_invalid_value (script,
601
/* mandatory: "handler" */
602
if (!json_object_has_member (object, "handler"))
604
_clutter_script_warn_missing_attribute (script, NULL, "handler");
609
handler = json_object_get_string_member (object, "handler");
612
_clutter_script_warn_invalid_value (script,
619
/* optional: "object" */
620
if (json_object_has_member (object, "object"))
621
connect = json_object_get_string_member (object, "object");
625
/* optional: "after" */
626
if (json_object_has_member (object, "after"))
628
if (json_object_get_boolean_member (object, "after"))
629
flags |= G_CONNECT_AFTER;
632
/* optional: "swapped" */
633
if (json_object_has_member (object, "swapped"))
635
if (json_object_get_boolean_member (object, "swapped"))
636
flags |= G_CONNECT_SWAPPED;
639
CLUTTER_NOTE (SCRIPT,
640
"Parsing signal '%s' (handler:%s, object:%s, flags:%d)",
642
handler, connect, flags);
644
sinfo = g_slice_new0 (SignalInfo);
645
sinfo->name = g_strdup (name);
646
sinfo->handler = g_strdup (handler);
647
sinfo->object = g_strdup (connect);
648
sinfo->flags = flags;
650
retval = g_list_prepend (retval, sinfo);
657
parse_behaviours (ObjectInfo *oinfo,
664
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
667
retval = oinfo->behaviours;
669
array = json_node_get_array (node);
670
array_len = json_array_get_length (array);
672
for (i = 0; i < array_len; i++)
674
JsonNode *child = json_array_get_element (array, i);
677
id = get_id_from_node (child);
679
retval = g_list_prepend (retval, g_strdup (id));
682
return g_list_reverse (retval);
685
static ClutterTimeline *
686
construct_timeline (ClutterScript *script,
689
ClutterTimeline *retval = NULL;
693
/* we fake an ObjectInfo so we can reuse clutter_script_construct_object()
694
* here; we do not save it inside the hash table, because if this had
695
* been a named object then we wouldn't have ended up here in the first
698
oinfo = g_slice_new0 (ObjectInfo);
699
oinfo->gtype = CLUTTER_TYPE_TIMELINE;
700
oinfo->id = g_strdup ("dummy");
702
members = json_object_get_members (object);
703
for (l = members; l != NULL; l = l->next)
705
const gchar *name = l->data;
706
JsonNode *node = json_object_get_member (object, name);
707
PropertyInfo *pinfo = g_slice_new0 (PropertyInfo);
709
pinfo->name = g_strdelimit (g_strdup (name), G_STR_DELIMITERS, '-');
710
pinfo->node = json_node_copy (node);
712
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
715
g_list_free (members);
717
_clutter_script_construct_object (script, oinfo);
718
_clutter_script_apply_properties (script, oinfo);
719
retval = CLUTTER_TIMELINE (oinfo->object);
721
/* we transfer ownership to the alpha function later */
722
oinfo->is_toplevel = FALSE;
723
object_info_free (oinfo);
728
/* define the names of the animation modes to match the ones
729
* that developers might be more accustomed to
734
ClutterAnimationMode mode;
735
} animation_modes[] = {
736
{ "linear", CLUTTER_LINEAR },
737
{ "easeInQuad", CLUTTER_EASE_IN_QUAD },
738
{ "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
739
{ "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
740
{ "easeInCubic", CLUTTER_EASE_IN_CUBIC },
741
{ "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
742
{ "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
743
{ "easeInQuart", CLUTTER_EASE_IN_QUART },
744
{ "easeOutQuart", CLUTTER_EASE_OUT_QUART },
745
{ "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
746
{ "easeInQuint", CLUTTER_EASE_IN_QUINT },
747
{ "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
748
{ "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
749
{ "easeInSine", CLUTTER_EASE_IN_SINE },
750
{ "easeOutSine", CLUTTER_EASE_OUT_SINE },
751
{ "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
752
{ "easeInExpo", CLUTTER_EASE_IN_EXPO },
753
{ "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
754
{ "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
755
{ "easeInCirc", CLUTTER_EASE_IN_CIRC },
756
{ "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
757
{ "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
758
{ "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
759
{ "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
760
{ "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
761
{ "easeInBack", CLUTTER_EASE_IN_BACK },
762
{ "easeOutBack", CLUTTER_EASE_OUT_BACK },
763
{ "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
764
{ "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
765
{ "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
766
{ "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
769
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
772
clutter_script_resolve_animation_mode (JsonNode *node)
774
gint i, res = CLUTTER_CUSTOM_MODE;
776
if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
777
return CLUTTER_CUSTOM_MODE;
779
if (json_node_get_value_type (node) == G_TYPE_INT64)
780
return json_node_get_int (node);
782
if (json_node_get_value_type (node) == G_TYPE_STRING)
784
const gchar *name = json_node_get_string (node);
786
/* XXX - we might be able to optimize by changing the ordering
787
* of the animation_modes array, e.g.
788
* - special casing linear
789
* - tokenizing ('ease', 'In', 'Sine') and matching on token
790
* - binary searching?
792
for (i = 0; i < n_animation_modes; i++)
794
if (strcmp (animation_modes[i].name, name) == 0)
795
return animation_modes[i].mode;
798
if (clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE,
803
g_warning ("Unable to find the animation mode '%s'", name);
806
return CLUTTER_CUSTOM_MODE;
809
static ClutterAlphaFunc
810
resolve_alpha_func (const gchar *name)
812
static GModule *module = NULL;
813
ClutterAlphaFunc func;
815
CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name);
817
if (G_UNLIKELY (!module))
818
module = g_module_open (NULL, 0);
820
if (g_module_symbol (module, name, (gpointer) &func))
822
CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table",
831
_clutter_script_parse_alpha (ClutterScript *script,
834
GObject *retval = NULL;
836
ClutterTimeline *timeline = NULL;
837
ClutterAlphaFunc alpha_func = NULL;
838
ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE;
840
gboolean unref_timeline = FALSE;
842
if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT)
845
object = json_node_get_object (node);
847
val = json_object_get_member (object, "timeline");
850
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE &&
851
json_node_get_string (val) != NULL)
853
const gchar *id = json_node_get_string (val);
856
CLUTTER_TIMELINE (clutter_script_get_object (script, id));
858
else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT)
860
timeline = construct_timeline (script, json_node_get_object (val));
861
unref_timeline = TRUE;
865
val = json_object_get_member (object, "mode");
867
mode = clutter_script_resolve_animation_mode (val);
869
if (mode == CLUTTER_CUSTOM_MODE)
871
val = json_object_get_member (object, "function");
872
if (val && json_node_get_string (val) != NULL)
874
alpha_func = resolve_alpha_func (json_node_get_string (val));
877
g_warning ("Unable to find the function '%s' in the "
878
"Clutter alpha functions or the symbols table",
879
json_node_get_string (val));
884
CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)",
885
unref_timeline ? "implicit" : "explicit",
886
timeline ? timeline : 0x0,
887
mode != CLUTTER_CUSTOM_MODE ? mode : 0,
888
alpha_func ? alpha_func : 0x0);
890
retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL);
892
if (mode != CLUTTER_CUSTOM_MODE)
893
clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode);
895
if (alpha_func != NULL)
896
clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL);
898
clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline);
900
g_object_unref (timeline);
906
clutter_script_parser_object_end (JsonParser *json_parser,
909
ClutterScriptParser *parser = CLUTTER_SCRIPT_PARSER (json_parser);
910
ClutterScript *script = parser->script;
916
if (!json_object_has_member (object, "id"))
920
if (!json_object_has_member (object, "type"))
923
fake = _clutter_script_generate_fake_id (script);
925
val = json_node_new (JSON_NODE_VALUE);
926
json_node_set_string (val, fake);
927
json_object_set_member (object, "id", val);
932
if (!json_object_has_member (object, "type"))
934
val = json_object_get_member (object, "id");
936
_clutter_script_warn_missing_attribute (script,
937
json_node_get_string (val),
942
id = json_object_get_string_member (object, "id");
944
oinfo = _clutter_script_get_object_info (script, id);
945
if (G_LIKELY (!oinfo))
947
const gchar *class_name;
949
oinfo = g_slice_new0 (ObjectInfo);
950
oinfo->merge_id = _clutter_script_get_last_merge_id (script);
951
oinfo->id = g_strdup (id);
953
class_name = json_object_get_string_member (object, "type");
954
oinfo->class_name = g_strdup (class_name);
956
if (json_object_has_member (object, "type_func"))
958
const gchar *type_func;
960
type_func = json_object_get_string_member (object, "type_func");
961
oinfo->type_func = g_strdup (type_func);
963
json_object_remove_member (object, "type_func");
967
if (json_object_has_member (object, "children"))
969
val = json_object_get_member (object, "children");
970
oinfo->children = parse_children (oinfo, val);
972
json_object_remove_member (object, "children");
975
if (json_object_has_member (object, "behaviours"))
977
val = json_object_get_member (object, "behaviours");
978
oinfo->behaviours = parse_behaviours (oinfo, val);
980
json_object_remove_member (object, "behaviours");
983
if (json_object_has_member (object, "signals"))
985
val = json_object_get_member (object, "signals");
986
oinfo->signals = parse_signals (script, oinfo, val);
988
json_object_remove_member (object, "signals");
991
if (strcmp (oinfo->class_name, "ClutterStage") == 0 &&
992
json_object_has_member (object, "is-default"))
994
oinfo->is_stage_default =
995
json_object_get_boolean_member (object, "is-default");
997
json_object_remove_member (object, "is-default");
1000
oinfo->is_stage_default = FALSE;
1002
oinfo->is_toplevel = FALSE;
1003
oinfo->is_unmerged = FALSE;
1004
oinfo->has_unresolved = TRUE;
1006
members = json_object_get_members (object);
1007
for (l = members; l; l = l->next)
1009
const gchar *name = l->data;
1010
PropertyInfo *pinfo;
1013
/* we have already parsed these */
1014
if (strcmp (name, "id") == 0 || strcmp (name, "type") == 0)
1017
node = json_object_get_member (object, name);
1019
pinfo = g_slice_new (PropertyInfo);
1021
pinfo->name = g_strdup (name);
1022
pinfo->node = json_node_copy (node);
1023
pinfo->pspec = NULL;
1024
pinfo->is_child = g_str_has_prefix (name, "child::") ? TRUE : FALSE;
1026
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
1029
g_list_free (members);
1031
CLUTTER_NOTE (SCRIPT,
1032
"Added object '%s' (type:%s, id:%d, props:%d, signals:%d)",
1036
g_list_length (oinfo->properties),
1037
g_list_length (oinfo->signals));
1039
_clutter_script_add_object_info (script, oinfo);
1040
_clutter_script_construct_object (script, oinfo);
1044
clutter_script_parser_parse_end (JsonParser *parser)
1046
clutter_script_ensure_objects (CLUTTER_SCRIPT_PARSER (parser)->script);
1050
clutter_script_parse_node (ClutterScript *script,
1056
GValue node_value = { 0, };
1057
gboolean retval = FALSE;
1059
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
1060
g_return_val_if_fail (name != NULL, FALSE);
1061
g_return_val_if_fail (node != NULL, FALSE);
1063
switch (JSON_NODE_TYPE (node))
1065
case JSON_NODE_OBJECT:
1066
/* if we don't have a GParamSpec we can't infer the type
1067
* of the property; this usually means that this property
1068
* is a custom member that will be parsed by the Scriptable
1069
* interface implementantion
1075
GType p_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
1079
g_value_init (value, p_type);
1081
if (g_type_is_a (p_type, G_TYPE_OBJECT))
1083
/* default GObject handling: we get the id and
1084
* retrieve the ObjectInfo for it; since the object
1085
* definitions are parsed leaf-first we are guaranteed
1086
* to have a defined object at this point
1088
id = get_id_from_node (node);
1089
if (id == NULL || *id == '\0')
1092
oinfo = _clutter_script_get_object_info (script, id);
1093
if (oinfo == NULL || oinfo->gtype == G_TYPE_INVALID )
1096
if (g_type_is_a (oinfo->gtype, p_type))
1098
/* force construction, even though it should
1099
* not be necessary; we don't need the properties
1100
* to be applied as well: they will when the
1101
* ScriptParser finishes
1103
_clutter_script_construct_object (script, oinfo);
1105
g_value_set_object (value, oinfo->object);
1110
else if (p_type == CLUTTER_TYPE_KNOT)
1112
ClutterKnot knot = { 0, };
1114
/* knot := { "x" : (int), "y" : (int) } */
1116
if (clutter_script_parse_knot (script, node, &knot))
1118
g_value_set_boxed (value, &knot);
1122
else if (p_type == CLUTTER_TYPE_GEOMETRY)
1124
ClutterGeometry geom = { 0, };
1134
if (clutter_script_parse_geometry (script, node, &geom))
1136
g_value_set_boxed (value, &geom);
1140
else if (p_type == CLUTTER_TYPE_COLOR)
1142
ClutterColor color = { 0, };
1152
if (clutter_script_parse_color (script, node, &color))
1154
g_value_set_boxed (value, &color);
1161
case JSON_NODE_ARRAY:
1166
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1168
if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT))
1170
ClutterKnot knot = { 0, };
1172
/* knot := [ (int), (int) ] */
1174
if (clutter_script_parse_knot (script, node, &knot))
1176
g_value_set_boxed (value, &knot);
1180
else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_GEOMETRY))
1182
ClutterGeometry geom = { 0, };
1184
/* geometry := [ (int), (int), (int), (int) ] */
1186
if (clutter_script_parse_geometry (script, node, &geom))
1188
g_value_set_boxed (value, &geom);
1192
else if (CLUTTER_VALUE_HOLDS_COLOR (value))
1194
ClutterColor color = { 0, };
1196
/* color := [ (int), (int), (int), (int) ] */
1198
if (clutter_script_parse_color (script, node, &color))
1200
g_value_set_boxed (value, &color);
1204
else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
1206
JsonArray *array = json_node_get_array (node);
1207
guint i, array_len = json_array_get_length (array);
1208
GPtrArray *str_array = g_ptr_array_sized_new (array_len);
1210
/* strv := [ (str), (str), ... ] */
1212
for (i = 0; i < array_len; i++)
1214
JsonNode *val = json_array_get_element (array, i);
1216
if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE &&
1217
json_node_get_string (val) == NULL)
1220
g_ptr_array_add (str_array,
1221
(gpointer) json_node_get_string (val));
1224
g_value_set_boxed (value, str_array->pdata);
1225
g_ptr_array_free (str_array, TRUE);
1232
case JSON_NODE_NULL:
1235
case JSON_NODE_VALUE:
1236
json_node_get_value (node, &node_value);
1239
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1241
g_value_init (value, G_VALUE_TYPE (&node_value));
1243
switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
1245
/* fundamental JSON types */
1249
case G_TYPE_BOOLEAN:
1250
g_value_copy (&node_value, value);
1255
g_value_set_int (value, g_value_get_int64 (&node_value));
1260
g_value_set_uint (value, (guint) g_value_get_int64 (&node_value));
1265
g_value_set_ulong (value, (gulong) g_value_get_int64 (&node_value));
1270
g_value_set_uchar (value, (guchar) g_value_get_int64 (&node_value));
1275
if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE))
1277
g_value_set_float (value, g_value_get_double (&node_value));
1280
else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
1282
g_value_set_float (value, g_value_get_int64 (&node_value));
1288
if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
1290
g_value_set_enum (value, g_value_get_int64 (&node_value));
1293
else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1297
retval = clutter_script_enum_from_string (G_VALUE_TYPE (value),
1298
g_value_get_string (&node_value),
1301
g_value_set_enum (value, enum_value);
1306
if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
1308
g_value_set_flags (value, g_value_get_int64 (&node_value));
1311
else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1315
retval = clutter_script_flags_from_string (G_VALUE_TYPE (value),
1316
g_value_get_string (&node_value),
1319
g_value_set_flags (value, flags_value);
1324
if (G_VALUE_HOLDS (value, CLUTTER_TYPE_COLOR))
1326
ClutterColor color = { 0, };
1328
retval = clutter_script_parse_color (script, node, &color);
1330
clutter_value_set_color (value, &color);
1335
if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1337
const gchar *str = g_value_get_string (&node_value);
1338
GObject *object = clutter_script_get_object (script, str);
1341
CLUTTER_NOTE (SCRIPT,
1342
"Assigning '%s' (%s) to property '%s'",
1344
G_OBJECT_TYPE_NAME (object),
1347
g_value_set_object (value, object);
1358
g_value_unset (&node_value);
1366
clutter_script_translate_parameters (ClutterScript *script,
1372
ClutterScriptable *scriptable = NULL;
1373
ClutterScriptableIface *iface = NULL;
1374
GList *l, *unparsed;
1375
gboolean parse_custom = FALSE;
1377
*params = g_array_new (FALSE, FALSE, sizeof (GParameter));
1379
if (CLUTTER_IS_SCRIPTABLE (object))
1381
scriptable = CLUTTER_SCRIPTABLE (object);
1382
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
1384
if (iface->parse_custom_node)
1385
parse_custom = TRUE;
1390
for (l = properties; l != NULL; l = l->next)
1392
PropertyInfo *pinfo = l->data;
1393
GParameter param = { NULL };
1394
gboolean res = FALSE;
1396
if (pinfo->is_child)
1398
CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", pinfo->name);
1399
unparsed = g_list_prepend (unparsed, pinfo);
1403
CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)",
1404
pinfo->pspec ? "regular" : "custom",
1408
res = iface->parse_custom_node (scriptable, script, ¶m.value,
1413
res = clutter_script_parse_node (script, ¶m.value,
1420
CLUTTER_NOTE (SCRIPT, "Property '%s' ignored", pinfo->name);
1421
unparsed = g_list_prepend (unparsed, pinfo);
1425
param.name = g_strdup (pinfo->name);
1427
g_array_append_val (*params, param);
1429
property_info_free (pinfo);
1432
g_list_free (properties);
1438
clutter_script_construct_parameters (ClutterScript *script,
1442
GArray **construct_params)
1444
GObjectClass *klass;
1445
GList *l, *unparsed;
1447
klass = g_type_class_ref (gtype);
1448
g_assert (klass != NULL);
1450
*construct_params = g_array_new (FALSE, FALSE, sizeof (GParameter));
1454
for (l = properties; l != NULL; l = l->next)
1456
PropertyInfo *pinfo = l->data;
1457
GParameter param = { NULL };
1458
GParamSpec *pspec = NULL;
1460
/* we allow custom property names for classes, so if we
1461
* don't find a corresponding GObject property for this
1462
* class we just skip it and let the class itself deal
1465
pspec = g_object_class_find_property (klass, pinfo->name);
1467
pinfo->pspec = g_param_spec_ref (pspec);
1470
pinfo->pspec = NULL;
1471
unparsed = g_list_prepend (unparsed, pinfo);
1475
if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
1477
unparsed = g_list_prepend (unparsed, pinfo);
1481
param.name = g_strdup (pinfo->name);
1483
if (!clutter_script_parse_node (script, ¶m.value,
1488
unparsed = g_list_prepend (unparsed, pinfo);
1492
g_array_append_val (*construct_params, param);
1494
property_info_free (pinfo);
1497
g_list_free (properties);
1499
g_type_class_unref (klass);
1505
apply_child_properties (ClutterScript *script,
1506
ClutterContainer *container,
1507
ClutterActor *actor,
1510
ClutterScriptable *scriptable = NULL;
1511
ClutterScriptableIface *iface = NULL;
1512
gboolean set_custom_property = FALSE;
1513
gboolean parse_custom_node = FALSE;
1514
GList *l, *unresolved, *properties;
1515
GObjectClass *klass;
1518
meta_type = CLUTTER_CONTAINER_GET_IFACE (container)->child_meta_type;
1519
if (meta_type == G_TYPE_INVALID)
1522
klass = G_OBJECT_GET_CLASS (container);
1524
/* shortcut, to avoid typechecking every time */
1525
if (CLUTTER_IS_SCRIPTABLE (container))
1527
scriptable = CLUTTER_SCRIPTABLE (container);
1528
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
1530
parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE;
1531
set_custom_property = iface->set_custom_property != NULL ? TRUE : FALSE;
1534
properties = oinfo->properties;
1535
oinfo->properties = NULL;
1538
for (l = properties; l != NULL; l = l->next)
1540
PropertyInfo *pinfo = l->data;
1541
GValue value = { 0, };
1542
gboolean res = FALSE;
1545
if (!pinfo->is_child)
1547
unresolved = g_list_prepend (unresolved, pinfo);
1551
name = pinfo->name + strlen ("child::");
1554
clutter_container_class_find_child_property (klass, name);
1556
if (pinfo->pspec != NULL)
1557
g_param_spec_ref (pinfo->pspec);
1559
CLUTTER_NOTE (SCRIPT, "Parsing %s child property (id:%s)",
1560
pinfo->pspec != NULL ? "regular" : "custom",
1563
if (parse_custom_node)
1564
res = iface->parse_custom_node (scriptable, script, &value,
1569
res = clutter_script_parse_node (script, &value,
1576
CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", name);
1577
unresolved = g_list_prepend (unresolved, pinfo);
1582
CLUTTER_NOTE (SCRIPT,
1583
"Setting %s child property '%s' (type:%s) to "
1584
"object '%s' (id:%s)",
1585
set_custom_property ? "custom" : "regular",
1587
g_type_name (G_VALUE_TYPE (&value)),
1588
g_type_name (oinfo->gtype),
1591
clutter_container_child_set_property (container, actor,
1595
g_value_unset (&value);
1597
property_info_free (pinfo);
1600
g_list_free (properties);
1602
oinfo->properties = unresolved;
1606
apply_behaviours (ClutterScript *script,
1609
ClutterActor *actor = CLUTTER_ACTOR (oinfo->object);
1610
GList *l, *unresolved;
1613
for (l = oinfo->behaviours; l != NULL; l = l->next)
1615
const gchar *name = l->data;
1616
ObjectInfo *behaviour_info;
1617
GObject *object = NULL;
1619
behaviour_info = _clutter_script_get_object_info (script, name);
1620
if (behaviour_info != NULL)
1622
_clutter_script_construct_object (script, behaviour_info);
1623
object = behaviour_info->object;
1628
unresolved = g_list_prepend (unresolved, g_strdup (name));
1632
CLUTTER_NOTE (SCRIPT, "Applying behaviour '%s' to actor of type '%s'",
1634
g_type_name (G_OBJECT_TYPE (actor)));
1636
clutter_behaviour_apply (CLUTTER_BEHAVIOUR (object), actor);
1639
g_list_foreach (oinfo->behaviours, (GFunc) g_free, NULL);
1640
g_list_free (oinfo->behaviours);
1642
oinfo->behaviours = unresolved;
1646
add_children (ClutterScript *script,
1649
ClutterContainer *container = CLUTTER_CONTAINER (oinfo->object);
1650
GList *l, *unresolved;
1653
for (l = oinfo->children; l != NULL; l = l->next)
1655
const gchar *name = l->data;
1656
GObject *object = NULL;
1657
ObjectInfo *child_info;
1659
child_info = _clutter_script_get_object_info (script, name);
1660
if (child_info != NULL)
1662
_clutter_script_construct_object (script, child_info);
1663
object = child_info->object;
1668
unresolved = g_list_prepend (unresolved, g_strdup (name));
1672
if (!CLUTTER_IS_ACTOR (object))
1674
g_warning ("The object definition '%s' (type: %s) is not "
1675
"an actor, but it is referenced in the 'children' "
1676
"member of the container '%s' (type: %s); skipping.",
1678
g_type_name (child_info->gtype),
1680
g_type_name (oinfo->gtype));
1684
CLUTTER_NOTE (SCRIPT, "Adding children '%s' to actor of type '%s'",
1686
g_type_name (G_OBJECT_TYPE (container)));
1688
clutter_container_add_actor (container, CLUTTER_ACTOR (object));
1690
apply_child_properties (script,
1691
container, CLUTTER_ACTOR (object),
1695
g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
1696
g_list_free (oinfo->children);
1698
oinfo->children = unresolved;
1702
_clutter_script_check_unresolved (ClutterScript *script,
1705
if (oinfo->children != NULL && CLUTTER_IS_CONTAINER (oinfo->object))
1706
add_children (script, oinfo);
1708
if (oinfo->behaviours != NULL && CLUTTER_IS_ACTOR (oinfo->object))
1709
apply_behaviours (script, oinfo);
1711
if (oinfo->properties || oinfo->children || oinfo->behaviours)
1712
oinfo->has_unresolved = TRUE;
1714
oinfo->has_unresolved = FALSE;
1718
_clutter_script_apply_properties (ClutterScript *script,
1721
ClutterScriptable *scriptable = NULL;
1722
ClutterScriptableIface *iface = NULL;
1723
gboolean set_custom_property = FALSE;
1724
GObject *object = oinfo->object;
1729
if (!oinfo->has_unresolved)
1732
/* shortcut, to avoid typechecking every time */
1733
if (CLUTTER_IS_SCRIPTABLE (object))
1735
scriptable = CLUTTER_SCRIPTABLE (object);
1736
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
1738
if (iface->set_custom_property)
1739
set_custom_property = TRUE;
1742
/* then we get the rest of the parameters, asking the object itself
1743
* to translate them for us, if we cannot do that
1745
properties = oinfo->properties;
1746
oinfo->properties = clutter_script_translate_parameters (script,
1752
/* consume all the properties we could translate in this pass */
1753
for (i = 0; i < params->len; i++)
1755
GParameter *param = &g_array_index (params, GParameter, i);
1757
CLUTTER_NOTE (SCRIPT,
1758
"Setting %s property '%s' (type:%s) to object '%s' (id:%s)",
1759
set_custom_property ? "custom" : "regular",
1761
g_type_name (G_VALUE_TYPE (¶m->value)),
1762
g_type_name (oinfo->gtype),
1765
if (set_custom_property)
1766
iface->set_custom_property (scriptable, script,
1770
g_object_set_property (object, param->name, ¶m->value);
1772
g_free ((gchar *) param->name);
1773
g_value_unset (¶m->value);
1776
g_array_free (params, TRUE);
1778
_clutter_script_check_unresolved (script, oinfo);
1782
_clutter_script_construct_object (ClutterScript *script,
1788
/* we have completely updated the object */
1789
if (oinfo->object != NULL)
1791
if (oinfo->has_unresolved)
1792
_clutter_script_check_unresolved (script, oinfo);
1797
if (oinfo->gtype == G_TYPE_INVALID)
1799
if (G_UNLIKELY (oinfo->type_func))
1800
oinfo->gtype = clutter_script_get_type_from_symbol (oinfo->type_func);
1802
oinfo->gtype = clutter_script_get_type_from_name (script, oinfo->class_name);
1804
if (G_UNLIKELY (oinfo->gtype == G_TYPE_INVALID))
1807
oinfo->is_toplevel =
1808
g_type_is_a (oinfo->gtype, G_TYPE_INITIALLY_UNOWNED)
1813
if (oinfo->gtype == CLUTTER_TYPE_STAGE && oinfo->is_stage_default)
1815
GList *properties = oinfo->properties;
1817
/* the default stage is a complex beast: we cannot create it using
1818
* g_object_newv() but we need clutter_script_construct_parameters()
1819
* to add the GParamSpec to the PropertyInfo pspec member, so
1820
* that we don't have to implement every complex property (like
1821
* the "color" one) directly inside the ClutterStage class.
1824
clutter_script_construct_parameters (script,
1830
oinfo->object = G_OBJECT (clutter_stage_get_default ());
1832
for (i = 0; i < params->len; i++)
1834
GParameter *param = &g_array_index (params, GParameter, i);
1836
g_free ((gchar *) param->name);
1837
g_value_unset (¶m->value);
1840
g_array_free (params, TRUE);
1844
GList *properties = oinfo->properties;
1846
/* every other object: first, we get the construction parameters */
1848
clutter_script_construct_parameters (script,
1854
oinfo->object = g_object_newv (oinfo->gtype,
1856
(GParameter *) params->data);
1858
for (i = 0; i < params->len; i++)
1860
GParameter *param = &g_array_index (params, GParameter, i);
1862
g_free ((gchar *) param->name);
1863
g_value_unset (¶m->value);
1866
g_array_free (params, TRUE);
1869
g_assert (oinfo->object != NULL);
1871
if (CLUTTER_IS_SCRIPTABLE (oinfo->object))
1872
clutter_scriptable_set_id (CLUTTER_SCRIPTABLE (oinfo->object), oinfo->id);
1874
g_object_set_data_full (oinfo->object, "clutter-script-id",
1875
g_strdup (oinfo->id),
1878
_clutter_script_check_unresolved (script, oinfo);