mutter/clutter/clutter-script-parser.c

350 lines
7.8 KiB
C

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include "clutter-actor.h"
#include "clutter-behaviour.h"
#include "clutter-container.h"
#include "clutter-script.h"
#include "clutter-script-private.h"
#include "clutter-scriptable.h"
#include "clutter-debug.h"
#include "clutter-private.h"
GType
clutter_script_get_type_from_symbol (const gchar *symbol)
{
static GModule *module = NULL;
GTypeGetFunc func;
GType gtype = G_TYPE_INVALID;
if (!module)
module = g_module_open (NULL, G_MODULE_BIND_LAZY);
if (g_module_symbol (module, symbol, (gpointer)&func))
gtype = func ();
return gtype;
}
GType
clutter_script_get_type_from_class (const gchar *name)
{
static GModule *module = NULL;
GTypeGetFunc func;
GString *symbol_name = g_string_new ("");
char c, *symbol;
int i;
GType gtype = G_TYPE_INVALID;
if (!module)
module = g_module_open (NULL, 0);
for (i = 0; name[i] != '\0'; i++)
{
c = name[i];
/* skip if uppercase, first or previous is uppercase */
if ((c == g_ascii_toupper (c) &&
i > 0 && name[i-1] != g_ascii_toupper (name[i-1])) ||
(i > 2 && name[i] == g_ascii_toupper (name[i]) &&
name[i-1] == g_ascii_toupper (name[i-1]) &&
name[i-2] == g_ascii_toupper (name[i-2])))
g_string_append_c (symbol_name, '_');
g_string_append_c (symbol_name, g_ascii_tolower (c));
}
g_string_append (symbol_name, "_get_type");
symbol = g_string_free (symbol_name, FALSE);
if (g_module_symbol (module, symbol, (gpointer)&func))
{
CLUTTER_NOTE (SCRIPT, "Type function: %s", symbol);
gtype = func ();
}
g_free (symbol);
return gtype;
}
gboolean
clutter_script_enum_from_string (GType type,
const gchar *string,
gint *enum_value)
{
GEnumClass *eclass;
GEnumValue *ev;
gchar *endptr;
gint value;
gboolean retval = TRUE;
g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
g_return_val_if_fail (string != NULL, 0);
value = strtoul (string, &endptr, 0);
if (endptr != string) /* parsed a number */
*enum_value = value;
else
{
eclass = g_type_class_ref (type);
ev = g_enum_get_value_by_name (eclass, string);
if (!ev)
ev = g_enum_get_value_by_nick (eclass, string);
if (ev)
*enum_value = ev->value;
else
retval = FALSE;
g_type_class_unref (eclass);
}
return retval;
}
gboolean
clutter_script_flags_from_string (GType type,
const gchar *string,
gint *flags_value)
{
GFlagsClass *fclass;
gchar *endptr, *prevptr;
guint i, j, ret, value;
gchar *flagstr;
GFlagsValue *fv;
const gchar *flag;
gunichar ch;
gboolean eos;
g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
g_return_val_if_fail (string != 0, 0);
ret = TRUE;
value = strtoul (string, &endptr, 0);
if (endptr != string) /* parsed a number */
*flags_value = value;
else
{
fclass = g_type_class_ref (type);
flagstr = g_strdup (string);
for (value = i = j = 0; ; i++)
{
eos = flagstr[i] == '\0';
if (!eos && flagstr[i] != '|')
continue;
flag = &flagstr[j];
endptr = &flagstr[i];
if (!eos)
{
flagstr[i++] = '\0';
j = i;
}
/* trim spaces */
for (;;)
{
ch = g_utf8_get_char (flag);
if (!g_unichar_isspace (ch))
break;
flag = g_utf8_next_char (flag);
}
while (endptr > flag)
{
prevptr = g_utf8_prev_char (endptr);
ch = g_utf8_get_char (prevptr);
if (!g_unichar_isspace (ch))
break;
endptr = prevptr;
}
if (endptr > flag)
{
*endptr = '\0';
fv = g_flags_get_value_by_name (fclass, flag);
if (!fv)
fv = g_flags_get_value_by_nick (fclass, flag);
if (fv)
value |= fv->value;
else
{
ret = FALSE;
break;
}
}
if (eos)
{
*flags_value = value;
break;
}
}
g_free (flagstr);
g_type_class_unref (fclass);
}
return ret;
}
static gboolean
parse_knot_from_array (JsonArray *array,
ClutterKnot *knot)
{
JsonNode *val;
if (json_array_get_length (array) < 2)
return FALSE;
val = json_array_get_element (array, 0);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
knot->x = json_node_get_int (val);
val = json_array_get_element (array, 1);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
knot->y = json_node_get_int (val);
return TRUE;
}
static gboolean
parse_knot_from_object (JsonObject *object,
ClutterKnot *knot)
{
JsonNode *val;
if (json_object_get_size (object) < 2)
return FALSE;
val = json_object_get_member (object, "x");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
knot->x = json_node_get_int (val);
val = json_object_get_member (object, "y");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
knot->y = json_node_get_int (val);
return TRUE;
}
gboolean
clutter_script_parse_knot (ClutterScript *script,
JsonNode *node,
ClutterKnot *knot)
{
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (knot != NULL, FALSE);
switch (JSON_NODE_TYPE (node))
{
case JSON_NODE_ARRAY:
return parse_knot_from_array (json_node_get_array (node), knot);
case JSON_NODE_OBJECT:
return parse_knot_from_object (json_node_get_object (node), knot);
default:
break;
}
return FALSE;
}
static gboolean
parse_geometry_from_array (JsonArray *array,
ClutterGeometry *geometry)
{
JsonNode *val;
if (json_array_get_length (array) < 4)
return FALSE;
val = json_array_get_element (array, 0);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->x = json_node_get_int (val);
val = json_array_get_element (array, 1);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->y = json_node_get_int (val);
val = json_array_get_element (array, 2);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->width = json_node_get_int (val);
val = json_array_get_element (array, 3);
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->height = json_node_get_int (val);
return TRUE;
}
static gboolean
parse_geometry_from_object (JsonObject *object,
ClutterGeometry *geometry)
{
JsonNode *val;
if (json_object_get_size (object) < 4)
return FALSE;
val = json_object_get_member (object, "x");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->x = json_node_get_int (val);
val = json_object_get_member (object, "y");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->y = json_node_get_int (val);
val = json_object_get_member (object, "width");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->width = json_node_get_int (val);
val = json_object_get_member (object, "height");
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE)
geometry->height = json_node_get_int (val);
return TRUE;
}
gboolean
clutter_script_parse_geometry (ClutterScript *script,
JsonNode *node,
ClutterGeometry *geometry)
{
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
g_return_val_if_fail (node != NULL, FALSE);
g_return_val_if_fail (geometry != NULL, FALSE);
switch (JSON_NODE_TYPE (node))
{
case JSON_NODE_ARRAY:
return parse_geometry_from_array (json_node_get_array (node), geometry);
case JSON_NODE_OBJECT:
return parse_geometry_from_object (json_node_get_object (node), geometry);
default:
break;
}
return FALSE;
}