219
241
G_DEFINE_TYPE (ClutterScript, clutter_script, G_TYPE_OBJECT);
222
warn_missing_attribute (ClutterScript *script,
224
const gchar *attribute)
226
ClutterScriptPrivate *priv = script->priv;
230
g_warning ("%s:%d: object '%s' has no '%s' attribute",
231
priv->is_filename ? priv->filename : "<input>",
232
json_parser_get_current_line (priv->parser),
238
g_warning ("%s:%d: object has no '%s' attribute",
239
priv->is_filename ? priv->filename : "<input>",
240
json_parser_get_current_line (priv->parser),
246
warn_invalid_value (ClutterScript *script,
247
const gchar *attribute,
248
const gchar *expected,
251
ClutterScriptPrivate *priv = script->priv;
255
g_warning ("%s:%d: invalid value of type '%s' for attribute '%s':"
256
"a value of type '%s' is expected",
257
priv->is_filename ? priv->filename : "<input>",
258
json_parser_get_current_line (priv->parser),
259
json_node_type_name (node),
265
g_warning ("%s:%d: invalid value for attribute '%s':"
266
"a value of type '%s' is expected",
267
priv->is_filename ? priv->filename : "<input>",
268
json_parser_get_current_line (priv->parser),
275
get_id_from_node (JsonNode *node)
279
switch (JSON_NODE_TYPE (node))
281
case JSON_NODE_OBJECT:
282
object = json_node_get_object (node);
283
if (json_object_has_member (object, "id"))
285
JsonNode *id = json_object_get_member (object, "id");
287
return json_node_get_string (id);
291
case JSON_NODE_VALUE:
292
return json_node_get_string (node);
302
parse_children (ObjectInfo *oinfo,
309
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
312
retval = oinfo->children;
314
array = json_node_get_array (node);
315
array_len = json_array_get_length (array);
317
for (i = 0; i < array_len; i++)
319
JsonNode *child = json_array_get_element (array, i);
322
id = get_id_from_node (child);
324
retval = g_list_prepend (retval, g_strdup (id));
327
return g_list_reverse (retval);
331
parse_signals (ClutterScript *script,
339
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
341
warn_invalid_value (script, "signals", "Array", node);
345
retval = oinfo->signals;
346
array = json_node_get_array (node);
347
array_len = json_array_get_length (array);
349
for (i = 0; i < array_len; i++)
351
JsonNode *val = json_array_get_element (array, i);
355
const gchar *handler;
356
const gchar *connect;
357
GConnectFlags flags = 0;
359
if (JSON_NODE_TYPE (val) != JSON_NODE_OBJECT)
361
warn_invalid_value (script, "signals array", "Object", node);
365
object = json_node_get_object (val);
367
/* mandatory: "name" */
368
if (!json_object_has_member (object, "name"))
370
warn_missing_attribute (script, NULL, "name");
375
val = json_object_get_member (object, "name");
376
if ((JSON_NODE_TYPE (val) == JSON_NODE_VALUE) &&
377
json_node_get_string (val) != NULL)
378
name = json_node_get_string (val);
381
warn_invalid_value (script, "name", "string", val);
386
/* mandatory: "handler" */
387
if (!json_object_has_member (object, "handler"))
389
warn_missing_attribute (script, NULL, "handler");
394
val = json_object_get_member (object, "handler");
395
if ((JSON_NODE_TYPE (val) == JSON_NODE_VALUE) &&
396
json_node_get_string (val) != NULL)
397
handler = json_node_get_string (val);
400
warn_invalid_value (script, "handler", "string", val);
405
/* optional: "object" */
406
if (json_object_has_member (object, "object"))
408
val = json_object_get_member (object, "object");
409
if ((JSON_NODE_TYPE (val) == JSON_NODE_VALUE) &&
410
json_node_get_string (val) != NULL)
411
connect = json_node_get_string (val);
418
/* optional: "after" */
419
if (json_object_has_member (object, "after"))
421
val = json_object_get_member (object, "after");
422
if (json_node_get_boolean (val))
423
flags |= G_CONNECT_AFTER;
426
/* optional: "swapped" */
427
if (json_object_has_member (object, "swapped"))
429
val = json_object_get_member (object, "swapped");
430
if (json_node_get_boolean (val))
431
flags |= G_CONNECT_SWAPPED;
434
CLUTTER_NOTE (SCRIPT,
435
"Parsing signal '%s' (handler:%s, object:%s, flags:%d)",
437
handler, connect, flags);
439
sinfo = g_slice_new0 (SignalInfo);
440
sinfo->name = g_strdup (name);
441
sinfo->handler = g_strdup (handler);
442
sinfo->object = g_strdup (connect);
443
sinfo->flags = flags;
445
retval = g_list_prepend (retval, sinfo);
452
parse_behaviours (ObjectInfo *oinfo,
459
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
462
retval = oinfo->behaviours;
464
array = json_node_get_array (node);
465
array_len = json_array_get_length (array);
467
for (i = 0; i < array_len; i++)
469
JsonNode *child = json_array_get_element (array, i);
472
id = get_id_from_node (child);
474
retval = g_list_prepend (retval, g_strdup (id));
477
return g_list_reverse (retval);
480
static ClutterTimeline *
481
construct_timeline (ClutterScript *script,
484
ClutterTimeline *retval = NULL;
488
/* we fake an ObjectInfo so we can reuse clutter_script_construct_object()
489
* here; we do not save it inside the hash table, because if this had
490
* been a named object then we wouldn't have ended up here in the first
493
oinfo = g_slice_new0 (ObjectInfo);
494
oinfo->gtype = CLUTTER_TYPE_TIMELINE;
495
oinfo->id = g_strdup ("dummy");
497
members = json_object_get_members (object);
498
for (l = members; l != NULL; l = l->next)
500
const gchar *name = l->data;
501
JsonNode *node = json_object_get_member (object, name);
502
PropertyInfo *pinfo = g_slice_new0 (PropertyInfo);
504
pinfo->name = g_strdelimit (g_strdup (name), G_STR_DELIMITERS, '-');
507
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
510
g_list_free (members);
512
retval = CLUTTER_TIMELINE (clutter_script_construct_object (script, oinfo));
514
/* we transfer ownership to the alpha function later */
515
oinfo->is_toplevel = FALSE;
516
object_info_free (oinfo);
521
/* define the names of the animation modes to match the ones
522
* that developers might be more accustomed to
527
ClutterAnimationMode mode;
528
} animation_modes[] = {
529
{ "linear", CLUTTER_LINEAR },
530
{ "easeInQuad", CLUTTER_EASE_IN_QUAD },
531
{ "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
532
{ "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
533
{ "easeInCubic", CLUTTER_EASE_IN_CUBIC },
534
{ "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
535
{ "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
536
{ "easeInQuart", CLUTTER_EASE_IN_QUART },
537
{ "easeOutQuart", CLUTTER_EASE_OUT_QUART },
538
{ "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
539
{ "easeInQuint", CLUTTER_EASE_IN_QUINT },
540
{ "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
541
{ "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
542
{ "easeInSine", CLUTTER_EASE_IN_SINE },
543
{ "easeOutSine", CLUTTER_EASE_OUT_SINE },
544
{ "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
545
{ "easeInExpo", CLUTTER_EASE_IN_EXPO },
546
{ "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
547
{ "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
548
{ "easeInCirc", CLUTTER_EASE_IN_CIRC },
549
{ "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
550
{ "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
551
{ "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
552
{ "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
553
{ "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
554
{ "easeInBack", CLUTTER_EASE_IN_BACK },
555
{ "easeOutBack", CLUTTER_EASE_OUT_BACK },
556
{ "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
557
{ "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
558
{ "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
559
{ "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
562
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
564
static ClutterAnimationMode
565
resolve_animation_mode (const gchar *name)
569
for (i = 0; i < n_animation_modes; i++)
571
if (strcmp (animation_modes[i].name, name) == 0)
572
return animation_modes[i].mode;
575
if (clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE,
579
g_warning ("Unable to find the animation mode '%s'", name);
581
return CLUTTER_CUSTOM_MODE;
584
static ClutterAlphaFunc
585
resolve_alpha_func (const gchar *name)
587
static GModule *module = NULL;
588
ClutterAlphaFunc func;
590
CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name);
592
if (G_UNLIKELY (!module))
593
module = g_module_open (NULL, G_MODULE_BIND_LAZY);
595
if (g_module_symbol (module, name, (gpointer) &func))
597
CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table",
606
clutter_script_parse_alpha (ClutterScript *script,
609
GObject *retval = NULL;
611
ClutterTimeline *timeline = NULL;
612
ClutterAlphaFunc alpha_func = NULL;
613
ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE;
615
gboolean unref_timeline = FALSE;
617
if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT)
620
object = json_node_get_object (node);
622
val = json_object_get_member (object, "timeline");
625
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE &&
626
json_node_get_string (val) != NULL)
628
const gchar *id = json_node_get_string (val);
631
CLUTTER_TIMELINE (clutter_script_get_object (script, id));
633
else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT)
635
timeline = construct_timeline (script, json_node_get_object (val));
636
unref_timeline = TRUE;
640
val = json_object_get_member (object, "mode");
641
if (val && json_node_get_string (val) != NULL)
642
mode = resolve_animation_mode (json_node_get_string (val));
644
if (mode == CLUTTER_CUSTOM_MODE)
646
val = json_object_get_member (object, "function");
647
if (val && json_node_get_string (val) != NULL)
649
alpha_func = resolve_alpha_func (json_node_get_string (val));
652
g_warning ("Unable to find the function '%s' in the "
653
"Clutter alpha functions or the symbols table",
654
json_node_get_string (val));
659
CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)",
660
unref_timeline ? "implicit" : "explicit",
661
timeline ? timeline : 0x0,
662
mode != CLUTTER_CUSTOM_MODE ? mode : 0,
663
alpha_func ? alpha_func : 0x0);
665
retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL);
667
if (mode != CLUTTER_CUSTOM_MODE)
668
clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode);
670
if (alpha_func != NULL)
671
clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL);
673
clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline);
675
g_object_unref (timeline);
681
json_object_end (JsonParser *parser,
685
ClutterScript *script = user_data;
686
ClutterScriptPrivate *priv = script->priv;
692
if (!json_object_has_member (object, "id"))
696
if (!json_object_has_member (object, "type"))
699
fake = g_strdup_printf ("script-%d-%d",
701
priv->last_unknown++);
703
val = json_node_new (JSON_NODE_VALUE);
704
json_node_set_string (val, fake);
705
json_object_set_member (object, "id", val);
710
if (!json_object_has_member (object, "type"))
712
val = json_object_get_member (object, "id");
714
warn_missing_attribute (script, json_node_get_string (val), "type");
718
val = json_object_get_member (object, "id");
719
id = json_node_get_string (val);
721
oinfo = g_hash_table_lookup (priv->objects, id);
722
if (G_LIKELY (!oinfo))
724
oinfo = g_slice_new0 (ObjectInfo);
725
oinfo->merge_id = priv->last_merge_id;
726
oinfo->id = g_strdup (id);
728
val = json_object_get_member (object, "type");
729
oinfo->class_name = json_node_dup_string (val);
731
if (json_object_has_member (object, "type_func"))
733
val = json_object_get_member (object, "type_func");
734
oinfo->type_func = json_node_dup_string (val);
736
json_object_remove_member (object, "type_func");
740
if (json_object_has_member (object, "children"))
742
val = json_object_get_member (object, "children");
743
oinfo->children = parse_children (oinfo, val);
745
json_object_remove_member (object, "children");
748
if (json_object_has_member (object, "behaviours"))
750
val = json_object_get_member (object, "behaviours");
751
oinfo->behaviours = parse_behaviours (oinfo, val);
753
json_object_remove_member (object, "behaviours");
756
if (json_object_has_member (object, "signals"))
758
val = json_object_get_member (object, "signals");
759
oinfo->signals = parse_signals (script, oinfo, val);
761
json_object_remove_member (object, "signals");
764
if (strcmp (oinfo->class_name, "ClutterStage") == 0 &&
765
json_object_has_member (object, "is-default"))
767
val = json_object_get_member (object, "is-default");
768
oinfo->is_stage_default = json_node_get_boolean (val);
770
json_object_remove_member (object, "is-default");
773
oinfo->is_stage_default = FALSE;
775
oinfo->is_toplevel = FALSE;
776
oinfo->is_unmerged = FALSE;
777
oinfo->has_unresolved = TRUE;
779
members = json_object_get_members (object);
780
for (l = members; l; l = l->next)
782
const gchar *name = l->data;
786
/* we have already parsed these */
787
if (strcmp (name, "id") == 0 || strcmp (name, "type") == 0)
790
node = json_object_get_member (object, name);
792
pinfo = g_slice_new (PropertyInfo);
794
pinfo->name = g_strdup (name);
798
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
801
g_list_free (members);
803
CLUTTER_NOTE (SCRIPT,
804
"Added object '%s' (type:%s, id:%d, props:%d, signals:%d)",
808
g_list_length (oinfo->properties),
809
g_list_length (oinfo->signals));
811
g_hash_table_steal (priv->objects, oinfo->id);
812
g_hash_table_insert (priv->objects, oinfo->id, oinfo);
814
oinfo->object = clutter_script_construct_object (script, oinfo);
818
clutter_script_parse_node (ClutterScript *script,
824
GValue node_value = { 0, };
825
gboolean retval = FALSE;
827
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
828
g_return_val_if_fail (name != NULL, FALSE);
829
g_return_val_if_fail (node != NULL, FALSE);
831
switch (JSON_NODE_TYPE (node))
833
case JSON_NODE_OBJECT:
838
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
840
if (G_VALUE_HOLDS (value, CLUTTER_TYPE_ALPHA))
844
alpha = clutter_script_parse_alpha (script, node);
847
g_value_set_object (value, alpha);
851
else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT))
853
ClutterKnot knot = { 0, };
855
/* knot := { "x" : (int), "y" : (int) } */
857
if (clutter_script_parse_knot (script, node, &knot))
859
g_value_set_boxed (value, &knot);
863
else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_GEOMETRY))
865
ClutterGeometry geom = { 0, };
875
if (clutter_script_parse_geometry (script, node, &geom))
877
g_value_set_boxed (value, &geom);
881
else if (CLUTTER_VALUE_HOLDS_COLOR (value))
883
ClutterColor color = { 0, };
893
if (clutter_script_parse_color (script, node, &color))
895
g_value_set_boxed (value, &color);
902
case JSON_NODE_ARRAY:
907
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
909
if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT))
911
ClutterKnot knot = { 0, };
913
/* knot := [ (int), (int) ] */
915
if (clutter_script_parse_knot (script, node, &knot))
917
g_value_set_boxed (value, &knot);
921
else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_GEOMETRY))
923
ClutterGeometry geom = { 0, };
925
/* geometry := [ (int), (int), (int), (int) ] */
927
if (clutter_script_parse_geometry (script, node, &geom))
929
g_value_set_boxed (value, &geom);
933
else if (CLUTTER_VALUE_HOLDS_COLOR (value))
935
ClutterColor color = { 0, };
937
/* color := [ (int), (int), (int), (int) ] */
939
if (clutter_script_parse_color (script, node, &color))
941
g_value_set_boxed (value, &color);
945
else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
947
JsonArray *array = json_node_get_array (node);
948
guint i, array_len = json_array_get_length (array);
949
GPtrArray *str_array = g_ptr_array_sized_new (array_len);
951
/* strv := [ (str), (str), ... ] */
953
for (i = 0; i < array_len; i++)
955
JsonNode *val = json_array_get_element (array, i);
957
if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE &&
958
json_node_get_string (val) == NULL)
961
g_ptr_array_add (str_array,
962
(gpointer) json_node_get_string (val));
965
g_value_set_boxed (value, str_array->pdata);
966
g_ptr_array_free (str_array, TRUE);
976
case JSON_NODE_VALUE:
977
json_node_get_value (node, &node_value);
980
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
982
g_value_init (value, G_VALUE_TYPE (&node_value));
984
switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
986
/* fundamental JSON types */
991
g_value_copy (&node_value, value);
996
g_value_set_uint (value, (guint) g_value_get_int (&node_value));
1001
g_value_set_ulong (value, (gulong) g_value_get_int (&node_value));
1006
g_value_set_uchar (value, (guchar) g_value_get_int (&node_value));
1011
if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE))
1013
g_value_set_float (value, g_value_get_double (&node_value));
1016
else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
1018
g_value_set_float (value, g_value_get_int64 (&node_value));
1024
if (G_VALUE_HOLDS (&node_value, G_TYPE_INT))
1026
g_value_set_enum (value, g_value_get_int (&node_value));
1029
else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1033
retval = clutter_script_enum_from_string (G_VALUE_TYPE (value),
1034
g_value_get_string (&node_value),
1037
g_value_set_enum (value, enum_value);
1042
if (G_VALUE_HOLDS (&node_value, G_TYPE_INT))
1044
g_value_set_flags (value, g_value_get_int (&node_value));
1047
else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1051
retval = clutter_script_flags_from_string (G_VALUE_TYPE (value),
1052
g_value_get_string (&node_value),
1055
g_value_set_flags (value, flags_value);
1060
if (G_VALUE_HOLDS (value, CLUTTER_TYPE_COLOR))
1062
if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1064
const gchar *str = g_value_get_string (&node_value);
1065
ClutterColor color = { 0, };
1067
if (str && str[0] != '\0')
1068
clutter_color_from_string (&color, str);
1070
g_value_set_boxed (value, &color);
1077
#ifdef USE_GDKPIXBUF
1078
if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
1080
if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1082
const gchar *str = g_value_get_string (&node_value);
1083
GdkPixbuf *pixbuf = NULL;
1087
if (g_path_is_absolute (str))
1088
path = g_strdup (str);
1091
gchar *dirname = NULL;
1093
if (script->priv->is_filename)
1094
dirname = g_path_get_dirname (script->priv->filename);
1096
dirname = g_get_current_dir ();
1098
path = g_build_filename (dirname, str, NULL);
1103
pixbuf = gdk_pixbuf_new_from_file (path, &error);
1106
g_warning ("Unable to open image at path '%s': %s",
1109
g_error_free (error);
1113
g_value_take_object (value, pixbuf);
1122
if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
1124
const gchar *str = g_value_get_string (&node_value);
1125
GObject *object = clutter_script_get_object (script, str);
1128
g_value_set_object (value, object);
1141
g_value_unset (&node_value);
1149
clutter_script_translate_parameters (ClutterScript *script,
1155
ClutterScriptable *scriptable = NULL;
1156
ClutterScriptableIface *iface = NULL;
1157
GList *l, *unparsed;
1158
gboolean parse_custom = FALSE;
1160
*params = g_array_new (FALSE, FALSE, sizeof (GParameter));
1162
if (CLUTTER_IS_SCRIPTABLE (object))
1164
scriptable = CLUTTER_SCRIPTABLE (object);
1165
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
1167
if (iface->parse_custom_node)
1168
parse_custom = TRUE;
1173
for (l = properties; l != NULL; l = l->next)
1175
PropertyInfo *pinfo = l->data;
1176
GParameter param = { NULL };
1177
gboolean res = FALSE;
1179
CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)",
1180
pinfo->pspec ? "regular" : "custom",
1184
res = iface->parse_custom_node (scriptable, script, ¶m.value,
1189
res = clutter_script_parse_node (script, ¶m.value,
1196
unparsed = g_list_prepend (unparsed, pinfo);
1200
param.name = g_strdup (pinfo->name);
1202
g_array_append_val (*params, param);
1204
property_info_free (pinfo);
1207
g_list_free (properties);
1213
clutter_script_construct_parameters (ClutterScript *script,
1217
GArray **construct_params)
1219
GObjectClass *klass;
1220
GList *l, *unparsed;
1222
klass = g_type_class_ref (gtype);
1223
g_assert (klass != NULL);
1225
*construct_params = g_array_new (FALSE, FALSE, sizeof (GParameter));
1229
for (l = properties; l != NULL; l = l->next)
1231
PropertyInfo *pinfo = l->data;
1232
GParameter param = { NULL };
1233
GParamSpec *pspec = NULL;
1235
/* we allow custom property names for classes, so if we
1236
* don't find a corresponding GObject property for this
1237
* class we just skip it and let the class itself deal
1240
pspec = g_object_class_find_property (klass, pinfo->name);
1242
pinfo->pspec = g_param_spec_ref (pspec);
1245
pinfo->pspec = NULL;
1246
unparsed = g_list_prepend (unparsed, pinfo);
1250
if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
1252
unparsed = g_list_prepend (unparsed, pinfo);
1256
param.name = g_strdup (pinfo->name);
1258
if (!clutter_script_parse_node (script, ¶m.value,
1263
unparsed = g_list_prepend (unparsed, pinfo);
1267
g_array_append_val (*construct_params, param);
1269
property_info_free (pinfo);
1272
g_list_free (properties);
1274
g_type_class_unref (klass);
1280
apply_behaviours (ClutterScript *script,
1281
ClutterActor *actor,
1285
GList *l, *unresolved;
1288
for (l = oinfo->behaviours; l != NULL; l = l->next)
1290
const gchar *name = l->data;
1292
object = clutter_script_get_object (script, name);
1295
ObjectInfo *behaviour_info;
1297
behaviour_info = g_hash_table_lookup (script->priv->objects, name);
1299
object = clutter_script_construct_object (script, behaviour_info);
1304
unresolved = g_list_prepend (unresolved, g_strdup (name));
1308
CLUTTER_NOTE (SCRIPT, "Applying behaviour '%s' to actor of type '%s'",
1310
g_type_name (G_OBJECT_TYPE (actor)));
1312
clutter_behaviour_apply (CLUTTER_BEHAVIOUR (object), actor);
1315
g_list_foreach (oinfo->behaviours, (GFunc) g_free, NULL);
1316
g_list_free (oinfo->behaviours);
1318
oinfo->behaviours = unresolved;
1322
add_children (ClutterScript *script,
1323
ClutterContainer *container,
1327
GList *l, *unresolved;
1330
for (l = oinfo->children; l != NULL; l = l->next)
1332
const gchar *name = l->data;
1334
object = clutter_script_get_object (script, name);
1337
ObjectInfo *child_info;
1339
child_info = g_hash_table_lookup (script->priv->objects, name);
1341
object = clutter_script_construct_object (script, child_info);
1346
unresolved = g_list_prepend (unresolved, g_strdup (name));
1350
CLUTTER_NOTE (SCRIPT, "Adding children '%s' to actor of type '%s'",
1352
g_type_name (G_OBJECT_TYPE (container)));
1354
clutter_container_add_actor (container, CLUTTER_ACTOR (object));
1357
g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
1358
g_list_free (oinfo->children);
1360
oinfo->children = unresolved;
1363
/* top-level classes: these classes are the roots of the
1364
* hiearchy; some of them must be unreferenced, whilst
1365
* others are owned by other instances
1369
const gchar *type_name;
1370
guint is_toplevel : 1;
1371
} clutter_toplevels[] = {
1372
{ "ClutterActor", FALSE },
1373
{ "ClutterAlpha", FALSE },
1374
{ "ClutterBehaviour", TRUE },
1375
{ "ClutterEffectTemplate", TRUE },
1376
{ "ClutterModel", TRUE },
1377
{ "ClutterScore", TRUE },
1378
{ "ClutterTimeline", TRUE }
1381
static guint n_clutter_toplevels = G_N_ELEMENTS (clutter_toplevels);
1384
clutter_script_construct_object (ClutterScript *script,
1390
GArray *construct_params;
1391
ClutterScriptable *scriptable = NULL;
1392
ClutterScriptableIface *iface = NULL;
1393
gboolean set_custom_property = FALSE;
1395
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL);
1396
g_return_val_if_fail (oinfo != NULL, NULL);
1398
/* we have completely updated the object */
1399
if (oinfo->object && !oinfo->has_unresolved)
1400
return oinfo->object;
1402
if (oinfo->gtype == G_TYPE_INVALID)
1404
if (G_UNLIKELY (oinfo->type_func))
1405
oinfo->gtype = clutter_script_get_type_from_symbol (oinfo->type_func);
1407
oinfo->gtype = clutter_script_get_type_from_name (script, oinfo->class_name);
1410
if (G_UNLIKELY (oinfo->gtype == G_TYPE_INVALID))
1414
object = oinfo->object;
1415
else if (oinfo->gtype == CLUTTER_TYPE_STAGE && oinfo->is_stage_default)
1417
/* the default stage is a complex beast: we cannot create it using
1418
* g_object_newv() but we need clutter_script_construct_parameters()
1419
* to add the GParamSpec to the PropertyInfo pspec member, so
1420
* that we don't have to implement every complex property (like
1421
* the "color" one) directly inside the ClutterStage class.
1424
clutter_script_construct_parameters (script,
1430
object = G_OBJECT (clutter_stage_get_default ());
1432
for (i = 0; i < construct_params->len; i++)
1434
GParameter *param = &g_array_index (construct_params, GParameter, i);
1436
g_free ((gchar *) param->name);
1437
g_value_unset (¶m->value);
1440
g_array_free (construct_params, TRUE);
1444
/* every other object: first, we get the construction parameters */
1446
clutter_script_construct_parameters (script,
1452
object = g_object_newv (oinfo->gtype,
1453
construct_params->len,
1454
(GParameter *) construct_params->data);
1456
for (i = 0; i < construct_params->len; i++)
1458
GParameter *param = &g_array_index (construct_params, GParameter, i);
1460
g_free ((gchar *) param->name);
1461
g_value_unset (¶m->value);
1464
g_array_free (construct_params, TRUE);
1467
/* shortcut, to avoid typechecking every time */
1468
if (CLUTTER_IS_SCRIPTABLE (object))
1470
scriptable = CLUTTER_SCRIPTABLE (object);
1471
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
1473
if (iface->set_custom_property)
1474
set_custom_property = TRUE;
1477
/* then we get the rest of the parameters, asking the object itself
1478
* to translate them for us, if we cannot do that
1480
oinfo->properties = clutter_script_translate_parameters (script,
1486
/* consume all the properties we could translate in this pass */
1487
for (i = 0; i < params->len; i++)
1489
GParameter *param = &g_array_index (params, GParameter, i);
1491
CLUTTER_NOTE (SCRIPT,
1492
"Setting %s property '%s' (type:%s) to object '%s' (id:%s)",
1493
set_custom_property ? "custom" : "regular",
1495
g_type_name (G_VALUE_TYPE (¶m->value)),
1496
g_type_name (oinfo->gtype),
1499
if (set_custom_property)
1500
iface->set_custom_property (scriptable, script,
1504
g_object_set_property (object, param->name, ¶m->value);
1506
g_free ((gchar *) param->name);
1507
g_value_unset (¶m->value);
1509
g_array_free (params, TRUE);
1511
for (i = 0; i < n_clutter_toplevels; i++)
1513
const gchar *t_name = clutter_toplevels[i].type_name;
1516
t_type = clutter_script_get_type_from_name (script, t_name);
1517
if (g_type_is_a (oinfo->gtype, t_type))
1519
oinfo->is_toplevel = clutter_toplevels[i].is_toplevel;
1524
/* XXX - at the moment, we are adding the children (and constructing
1525
* the scenegraph) after we applied all the properties of an object;
1526
* this usually ensures that an object is fully constructed before
1527
* it is added to its parent. unfortunately, this also means that
1528
* children cannot reference the parent's state inside their own
1532
* http://bugzilla.openedhand.com/show_bug.cgi?id=1042
1535
if (oinfo->children && CLUTTER_IS_CONTAINER (object))
1536
add_children (script, CLUTTER_CONTAINER (object), oinfo);
1538
if (oinfo->behaviours && CLUTTER_IS_ACTOR (object))
1539
apply_behaviours (script, CLUTTER_ACTOR (object), oinfo);
1541
if (oinfo->properties || oinfo->children || oinfo->behaviours)
1542
oinfo->has_unresolved = TRUE;
1544
oinfo->has_unresolved = FALSE;
1547
clutter_scriptable_set_id (scriptable, oinfo->id);
1549
g_object_set_data_full (object, "clutter-script-id",
1550
g_strdup (oinfo->id),
1557
construct_each_object (gpointer key,
1561
ClutterScript *script = data;
1562
ObjectInfo *oinfo = value;
1565
oinfo->object = clutter_script_construct_object (script, oinfo);
1569
json_parse_end (JsonParser *parser,
1572
ClutterScript *script = user_data;
1573
ClutterScriptPrivate *priv = script->priv;
1575
g_hash_table_foreach (priv->objects, construct_each_object, script);
1579
244
clutter_script_real_get_type_from_name (ClutterScript *script,
1580
245
const gchar *type_name)