mirror of
https://github.com/brl/mutter.git
synced 2025-04-29 13:19:39 +00:00
script: Allow parsing child properties
The ClutterScript parser needs to be extended to parse child properties and apply them after an actor has been added to a container. In order to distinguish child properties from regular GObject properties we can use the "child::" prefix, e.g.: { "type" : "ClutterRectangle", "id" : "child-01", "child::has-focus" : true, ... } Parsing child properties can be deferred to the ClutterScriptable interface, just like regular properties.
This commit is contained in:
parent
c52d878032
commit
95d78acb4c
1
.gitignore
vendored
1
.gitignore
vendored
@ -219,6 +219,7 @@ TAGS
|
|||||||
/tests/conform/test-cogl-viewport
|
/tests/conform/test-cogl-viewport
|
||||||
/tests/conform/test-texture-fbo
|
/tests/conform/test-texture-fbo
|
||||||
/tests/conform/test-script-single
|
/tests/conform/test-script-single
|
||||||
|
/tests/conform/test-script-child
|
||||||
/tests/micro-bench/test-text-perf
|
/tests/micro-bench/test-text-perf
|
||||||
/tests/micro-bench/test-text
|
/tests/micro-bench/test-text
|
||||||
/tests/micro-bench/test-picking
|
/tests/micro-bench/test-picking
|
||||||
|
@ -1008,6 +1008,7 @@ clutter_script_parser_object_end (JsonParser *json_parser,
|
|||||||
pinfo->name = g_strdup (name);
|
pinfo->name = g_strdup (name);
|
||||||
pinfo->node = json_node_copy (node);
|
pinfo->node = json_node_copy (node);
|
||||||
pinfo->pspec = NULL;
|
pinfo->pspec = NULL;
|
||||||
|
pinfo->is_child = g_str_has_prefix (name, "child::") ? TRUE : FALSE;
|
||||||
|
|
||||||
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
|
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
|
||||||
}
|
}
|
||||||
@ -1352,6 +1353,13 @@ clutter_script_translate_parameters (ClutterScript *script,
|
|||||||
GParameter param = { NULL };
|
GParameter param = { NULL };
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
|
if (pinfo->is_child)
|
||||||
|
{
|
||||||
|
CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", pinfo->name);
|
||||||
|
unparsed = g_list_prepend (unparsed, pinfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)",
|
CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)",
|
||||||
pinfo->pspec ? "regular" : "custom",
|
pinfo->pspec ? "regular" : "custom",
|
||||||
pinfo->name);
|
pinfo->name);
|
||||||
@ -1453,6 +1461,107 @@ clutter_script_construct_parameters (ClutterScript *script,
|
|||||||
return unparsed;
|
return unparsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
apply_child_properties (ClutterScript *script,
|
||||||
|
ClutterContainer *container,
|
||||||
|
ClutterActor *actor,
|
||||||
|
ObjectInfo *oinfo)
|
||||||
|
{
|
||||||
|
ClutterScriptable *scriptable = NULL;
|
||||||
|
ClutterScriptableIface *iface = NULL;
|
||||||
|
gboolean set_custom_property = FALSE;
|
||||||
|
gboolean parse_custom_node = FALSE;
|
||||||
|
GList *l, *unresolved, *properties;
|
||||||
|
GObjectClass *klass;
|
||||||
|
GType meta_type;
|
||||||
|
|
||||||
|
meta_type = CLUTTER_CONTAINER_GET_IFACE (container)->child_meta_type;
|
||||||
|
if (meta_type == G_TYPE_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
klass = G_OBJECT_GET_CLASS (container);
|
||||||
|
|
||||||
|
/* shortcut, to avoid typechecking every time */
|
||||||
|
if (CLUTTER_IS_SCRIPTABLE (container))
|
||||||
|
{
|
||||||
|
scriptable = CLUTTER_SCRIPTABLE (container);
|
||||||
|
iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
|
||||||
|
|
||||||
|
parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE;
|
||||||
|
set_custom_property = iface->set_custom_property != NULL ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties = oinfo->properties;
|
||||||
|
oinfo->properties = NULL;
|
||||||
|
|
||||||
|
unresolved = NULL;
|
||||||
|
for (l = properties; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
PropertyInfo *pinfo = l->data;
|
||||||
|
GValue value = { 0, };
|
||||||
|
const gchar *name;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
if (!pinfo->is_child)
|
||||||
|
{
|
||||||
|
unresolved = g_list_prepend (unresolved, pinfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = pinfo->name + strlen ("child::");
|
||||||
|
|
||||||
|
pinfo->pspec =
|
||||||
|
clutter_container_class_find_child_property (klass, name);
|
||||||
|
|
||||||
|
if (pinfo->pspec != NULL)
|
||||||
|
g_param_spec_ref (pinfo->pspec);
|
||||||
|
|
||||||
|
CLUTTER_NOTE (SCRIPT, "Parsing %s child property (id:%s)",
|
||||||
|
pinfo->pspec != NULL ? "regular" : "custom",
|
||||||
|
name);
|
||||||
|
|
||||||
|
if (parse_custom_node)
|
||||||
|
res = iface->parse_custom_node (scriptable, script, &value,
|
||||||
|
name,
|
||||||
|
pinfo->node);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
res = clutter_script_parse_node (script, &value,
|
||||||
|
name,
|
||||||
|
pinfo->node,
|
||||||
|
pinfo->pspec);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", name);
|
||||||
|
unresolved = g_list_prepend (unresolved, pinfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLUTTER_NOTE (SCRIPT,
|
||||||
|
"Setting %s child property '%s' (type:%s) to "
|
||||||
|
"object '%s' (id:%s)",
|
||||||
|
set_custom_property ? "custom" : "regular",
|
||||||
|
name,
|
||||||
|
g_type_name (G_VALUE_TYPE (&value)),
|
||||||
|
g_type_name (oinfo->gtype),
|
||||||
|
oinfo->id);
|
||||||
|
|
||||||
|
clutter_container_child_set_property (container, actor,
|
||||||
|
name,
|
||||||
|
&value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
|
||||||
|
property_info_free (pinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (properties);
|
||||||
|
|
||||||
|
oinfo->properties = unresolved;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
apply_behaviours (ClutterScript *script,
|
apply_behaviours (ClutterScript *script,
|
||||||
ObjectInfo *oinfo)
|
ObjectInfo *oinfo)
|
||||||
@ -1525,6 +1634,10 @@ add_children (ClutterScript *script,
|
|||||||
g_type_name (G_OBJECT_TYPE (container)));
|
g_type_name (G_OBJECT_TYPE (container)));
|
||||||
|
|
||||||
clutter_container_add_actor (container, CLUTTER_ACTOR (object));
|
clutter_container_add_actor (container, CLUTTER_ACTOR (object));
|
||||||
|
|
||||||
|
apply_child_properties (script,
|
||||||
|
container, CLUTTER_ACTOR (object),
|
||||||
|
child_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
|
g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
|
||||||
|
@ -78,6 +78,8 @@ typedef struct {
|
|||||||
gchar *name;
|
gchar *name;
|
||||||
JsonNode *node;
|
JsonNode *node;
|
||||||
GParamSpec *pspec;
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
guint is_child : 1;
|
||||||
} PropertyInfo;
|
} PropertyInfo;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -88,6 +88,8 @@ test_conformance_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS)
|
|||||||
|
|
||||||
test_conformance_LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_WINSYS@-@CLUTTER_API_VERSION@.la $(CLUTTER_LIBS)
|
test_conformance_LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_WINSYS@-@CLUTTER_API_VERSION@.la $(CLUTTER_LIBS)
|
||||||
|
|
||||||
|
test_conformance_LDFLAGS = -rdynamic
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
.PHONY: test-report test-report-normal test-report-disable-npots
|
.PHONY: test-report test-report-normal test-report-disable-npots
|
||||||
.PHONY: full-report full-report-normal full-report-disable-npots
|
.PHONY: full-report full-report-normal full-report-disable-npots
|
||||||
|
@ -186,6 +186,7 @@ main (int argc, char **argv)
|
|||||||
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_readpixels);
|
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_readpixels);
|
||||||
|
|
||||||
TEST_CONFORM_SIMPLE ("/script", test_script_single);
|
TEST_CONFORM_SIMPLE ("/script", test_script_single);
|
||||||
|
TEST_CONFORM_SIMPLE ("/script", test_script_child);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,162 @@
|
|||||||
|
|
||||||
#include "test-conform-common.h"
|
#include "test-conform-common.h"
|
||||||
|
|
||||||
|
#define TEST_TYPE_GROUP (test_group_get_type ())
|
||||||
|
#define TEST_TYPE_GROUP_META (test_group_meta_get_type ())
|
||||||
|
|
||||||
|
#define TEST_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP, TestGroup))
|
||||||
|
#define TEST_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP))
|
||||||
|
|
||||||
|
#define TEST_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP_META, TestGroupMeta))
|
||||||
|
#define TEST_IS_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP_META))
|
||||||
|
|
||||||
|
typedef struct _ClutterGroup TestGroup;
|
||||||
|
|
||||||
|
typedef struct _TestGroupMeta {
|
||||||
|
ClutterChildMeta parent_instance;
|
||||||
|
|
||||||
|
guint is_focus : 1;
|
||||||
|
} TestGroupMeta;
|
||||||
|
|
||||||
|
typedef struct _ClutterGroupClass TestGroupClass;
|
||||||
|
typedef struct _ClutterChildMetaClass TestGroupMetaClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (TestGroupMeta, test_group_meta, CLUTTER_TYPE_CHILD_META);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_META_0,
|
||||||
|
|
||||||
|
PROP_META_FOCUS
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_meta_set_property (GObject *gobject,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
TestGroupMeta *self = TEST_GROUP_META (gobject);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_META_FOCUS:
|
||||||
|
self->is_focus = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_meta_get_property (GObject *gobject,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
TestGroupMeta *self = TEST_GROUP_META (gobject);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_META_FOCUS:
|
||||||
|
g_value_set_boolean (value, self->is_focus);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_meta_class_init (TestGroupMetaClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
gobject_class->set_property = test_group_meta_set_property;
|
||||||
|
gobject_class->get_property = test_group_meta_get_property;
|
||||||
|
|
||||||
|
pspec = g_param_spec_boolean ("focus", "Focus", "Focus",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_property (gobject_class, PROP_META_FOCUS, pspec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_meta_init (TestGroupMeta *meta)
|
||||||
|
{
|
||||||
|
meta->is_focus = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_container_iface_init (ClutterContainerIface *iface)
|
||||||
|
{
|
||||||
|
iface->child_meta_type = TEST_TYPE_GROUP_META;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (TestGroup, test_group, CLUTTER_TYPE_GROUP,
|
||||||
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
|
||||||
|
clutter_container_iface_init));
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_class_init (TestGroupClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_group_init (TestGroup *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_script_child (TestConformSimpleFixture *fixture,
|
||||||
|
gconstpointer dummy)
|
||||||
|
{
|
||||||
|
ClutterScript *script = clutter_script_new ();
|
||||||
|
GObject *container, *actor;
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean focus_ret;
|
||||||
|
gchar *test_file;
|
||||||
|
|
||||||
|
test_file = clutter_test_get_data_file ("test-script-child.json");
|
||||||
|
clutter_script_load_from_file (script, test_file, &error);
|
||||||
|
if (g_test_verbose () && (error != NULL))
|
||||||
|
g_warning ("Unable to load '%s': %s", test_file, error->message);
|
||||||
|
g_assert (error == NULL);
|
||||||
|
|
||||||
|
container = actor = NULL;
|
||||||
|
clutter_script_get_objects (script,
|
||||||
|
"test-group", &container,
|
||||||
|
"test-rect-1", &actor,
|
||||||
|
NULL);
|
||||||
|
g_assert (TEST_IS_GROUP (container));
|
||||||
|
g_assert (CLUTTER_IS_RECTANGLE (actor));
|
||||||
|
|
||||||
|
focus_ret = FALSE;
|
||||||
|
clutter_container_child_get (CLUTTER_CONTAINER (container),
|
||||||
|
CLUTTER_ACTOR (actor),
|
||||||
|
"focus", &focus_ret,
|
||||||
|
NULL);
|
||||||
|
g_assert (focus_ret);
|
||||||
|
|
||||||
|
actor = clutter_script_get_object (script, "test-rect-2");
|
||||||
|
g_assert (CLUTTER_IS_RECTANGLE (actor));
|
||||||
|
|
||||||
|
focus_ret = FALSE;
|
||||||
|
clutter_container_child_get (CLUTTER_CONTAINER (container),
|
||||||
|
CLUTTER_ACTOR (actor),
|
||||||
|
"focus", &focus_ret,
|
||||||
|
NULL);
|
||||||
|
g_assert (!focus_ret);
|
||||||
|
|
||||||
|
g_object_unref (script);
|
||||||
|
clutter_actor_destroy (CLUTTER_ACTOR (container));
|
||||||
|
g_free (test_file);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_script_single (TestConformSimpleFixture *fixture,
|
test_script_single (TestConformSimpleFixture *fixture,
|
||||||
gconstpointer dummy)
|
gconstpointer dummy)
|
||||||
|
21
tests/data/test-script-child.json
Normal file
21
tests/data/test-script-child.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"type" : "TestGroup",
|
||||||
|
"id" : "test-group",
|
||||||
|
"children" : [
|
||||||
|
{
|
||||||
|
"type" : "ClutterRectangle",
|
||||||
|
"id" : "test-rect-1",
|
||||||
|
"width" : 100.0,
|
||||||
|
"height" : 100.0,
|
||||||
|
"color" : [ 255, 0, 0, 255 ],
|
||||||
|
"child::focus" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "ClutterRectangle",
|
||||||
|
"id" : "test-rect-2",
|
||||||
|
"width" : 100.0,
|
||||||
|
"height" : 100.0,
|
||||||
|
"color" : [ 0, 255, 0, 255 ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user