Blame clutter/clutter-script-parser.c

Packit 31ecd5
/*
Packit 31ecd5
 * Clutter.
Packit 31ecd5
 *
Packit 31ecd5
 * An OpenGL based 'interactive canvas' library.
Packit 31ecd5
 *
Packit 31ecd5
 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
Packit 31ecd5
 * Copyright (C) 2009 Intel Corportation
Packit 31ecd5
 *
Packit 31ecd5
 * This library is free software; you can redistribute it and/or
Packit 31ecd5
 * modify it under the terms of the GNU Lesser General Public
Packit 31ecd5
 * License as published by the Free Software Foundation; either
Packit 31ecd5
 * version 2 of the License, or (at your option) any later version.
Packit 31ecd5
 *
Packit 31ecd5
 * This library is distributed in the hope that it will be useful,
Packit 31ecd5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 31ecd5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 31ecd5
 * Lesser General Public License for more details.
Packit 31ecd5
 *
Packit 31ecd5
 * You should have received a copy of the GNU Lesser General Public
Packit 31ecd5
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Packit 31ecd5
 *
Packit 31ecd5
 * Original author:
Packit 31ecd5
 *
Packit 31ecd5
 *      Emmanuele Bassi <ebassi@linux.intel.com>
Packit 31ecd5
 */
Packit 31ecd5
Packit 31ecd5
#ifdef HAVE_CONFIG_H
Packit 31ecd5
#include "config.h"
Packit 31ecd5
#endif
Packit 31ecd5
Packit 31ecd5
#include <string.h>
Packit 31ecd5
#include <stdlib.h>
Packit 31ecd5
Packit 31ecd5
#include <glib.h>
Packit 31ecd5
#include <gmodule.h>
Packit 31ecd5
Packit 31ecd5
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
Packit 31ecd5
#include "deprecated/clutter-container.h"
Packit 31ecd5
#include "deprecated/clutter-alpha.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-actor.h"
Packit 31ecd5
#include "clutter-debug.h"
Packit 31ecd5
#include "clutter-enum-types.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-script.h"
Packit 31ecd5
#include "clutter-script-private.h"
Packit 31ecd5
#include "clutter-scriptable.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-stage-manager.h"
Packit 31ecd5
Packit 31ecd5
#include "clutter-private.h"
Packit 31ecd5
Packit 31ecd5
static void clutter_script_parser_object_end (JsonParser *parser,
Packit 31ecd5
                                              JsonObject *object);
Packit 31ecd5
static void clutter_script_parser_parse_end  (JsonParser *parser);
Packit 31ecd5
Packit 31ecd5
#define clutter_script_parser_get_type  _clutter_script_parser_get_type
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE (ClutterScriptParser, clutter_script_parser, JSON_TYPE_PARSER);
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_script_parser_class_init (ClutterScriptParserClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  JsonParserClass *parser_class = JSON_PARSER_CLASS (klass);
Packit 31ecd5
Packit 31ecd5
  parser_class->object_end = clutter_script_parser_object_end;
Packit 31ecd5
  parser_class->parse_end = clutter_script_parser_parse_end;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_script_parser_init (ClutterScriptParser *parser)
Packit 31ecd5
{
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
GType
Packit 31ecd5
_clutter_script_get_type_from_symbol (const gchar *symbol)
Packit 31ecd5
{
Packit 31ecd5
  static GModule *module = NULL;
Packit 31ecd5
  GTypeGetFunc func;
Packit 31ecd5
  GType gtype = G_TYPE_INVALID;
Packit 31ecd5
Packit 31ecd5
  if (!module)
Packit 31ecd5
    module = g_module_open (NULL, 0);
Packit 31ecd5
  
Packit 31ecd5
  if (g_module_symbol (module, symbol, (gpointer)&func))
Packit 31ecd5
    gtype = func ();
Packit 31ecd5
  
Packit 31ecd5
  return gtype;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
GType
Packit 31ecd5
_clutter_script_get_type_from_class (const gchar *name)
Packit 31ecd5
{
Packit 31ecd5
  static GModule *module = NULL;
Packit 31ecd5
  GString *symbol_name = g_string_sized_new (64);
Packit 31ecd5
  GType gtype = G_TYPE_INVALID;
Packit 31ecd5
  GTypeGetFunc func;
Packit 31ecd5
  gchar *symbol;
Packit 31ecd5
  gint i;
Packit 31ecd5
Packit 31ecd5
  if (G_UNLIKELY (!module))
Packit 31ecd5
    module = g_module_open (NULL, 0);
Packit 31ecd5
  
Packit 31ecd5
  for (i = 0; name[i] != '\0'; i++)
Packit 31ecd5
    {
Packit 31ecd5
      gchar c = name[i];
Packit 31ecd5
Packit 31ecd5
      /* the standard naming policy for GObject-based libraries
Packit 31ecd5
       * is:
Packit 31ecd5
       *
Packit 31ecd5
       *   NAME := INITIAL_WORD WORD+
Packit 31ecd5
       *   INITIAL_WORD := [A-Z][a-z0-9]*
Packit 31ecd5
       *   WORD := [A-Z]{1,2}[a-z0-9]+ | [A-Z]{2,}
Packit 31ecd5
       *
Packit 31ecd5
       * for instance:
Packit 31ecd5
       *
Packit 31ecd5
       *   GString -> g_string
Packit 31ecd5
       *   GtkCTree -> gtk_ctree
Packit 31ecd5
       *   ClutterX11TexturePixmap -> clutter_x11_texture_pixmap
Packit 31ecd5
       *
Packit 31ecd5
       * see:
Packit 31ecd5
       *
Packit 31ecd5
       * http://mail.gnome.org/archives/gtk-devel-list/2007-June/msg00022.html
Packit 31ecd5
       *
Packit 31ecd5
       * and:
Packit 31ecd5
       *
Packit 31ecd5
       * http://git.gnome.org/cgit/gtk+/plain/gtk/gtkbuilderparser.c
Packit 31ecd5
       */
Packit 31ecd5
Packit 31ecd5
      if ((c == g_ascii_toupper (c) &&
Packit 31ecd5
           i > 0 && name[i - 1] != g_ascii_toupper (name[i - 1])) ||
Packit 31ecd5
          (i > 2 && name[i] == g_ascii_toupper (name[i]) &&
Packit 31ecd5
           name[i - 1] == g_ascii_toupper (name[i - 1]) &&
Packit 31ecd5
           name[i - 2] == g_ascii_toupper (name[i - 2])))
Packit 31ecd5
        g_string_append_c (symbol_name, '_');
Packit 31ecd5
Packit 31ecd5
      g_string_append_c (symbol_name, g_ascii_tolower (c));
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_string_append (symbol_name, "_get_type");
Packit 31ecd5
  
Packit 31ecd5
  symbol = g_string_free (symbol_name, FALSE);
Packit 31ecd5
Packit 31ecd5
  if (g_module_symbol (module, symbol, (gpointer)&func))
Packit 31ecd5
    {
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Type function: %s", symbol);
Packit 31ecd5
      gtype = func ();
Packit 31ecd5
    }
Packit 31ecd5
  
Packit 31ecd5
  g_free (symbol);
Packit 31ecd5
Packit 31ecd5
  return gtype;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/*
Packit 31ecd5
 * clutter_script_enum_from_string:
Packit 31ecd5
 * @type: a #GType for an enumeration type
Packit 31ecd5
 * @string: the enumeration value as a string
Packit 31ecd5
 * @enum_value: (out): return location for the enumeration value as an integer
Packit 31ecd5
 *
Packit 31ecd5
 * Converts an enumeration value inside @string into a numeric
Packit 31ecd5
 * value and places it into @enum_value.
Packit 31ecd5
 *
Packit 31ecd5
 * The enumeration value can be an integer, the enumeration nick
Packit 31ecd5
 * or the enumeration name, as part of the #GEnumValue structure.
Packit 31ecd5
 *
Packit 31ecd5
 * Return value: %TRUE if the conversion was successfull.
Packit 31ecd5
 */
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_enum_from_string (GType        type,
Packit 31ecd5
                                  const gchar *string,
Packit 31ecd5
                                  gint        *enum_value)
Packit 31ecd5
{
Packit 31ecd5
  GEnumClass *eclass;
Packit 31ecd5
  GEnumValue *ev;
Packit 31ecd5
  gchar *endptr;
Packit 31ecd5
  gint value;
Packit 31ecd5
  gboolean retval = TRUE;
Packit 31ecd5
  
Packit 31ecd5
  g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
Packit 31ecd5
  g_return_val_if_fail (string != NULL, 0);
Packit 31ecd5
  
Packit 31ecd5
  value = strtoul (string, &endptr, 0);
Packit 31ecd5
  if (endptr != string) /* parsed a number */
Packit 31ecd5
    *enum_value = value;
Packit 31ecd5
  else
Packit 31ecd5
    {
Packit 31ecd5
      eclass = g_type_class_ref (type);
Packit 31ecd5
      ev = g_enum_get_value_by_name (eclass, string);
Packit 31ecd5
      if (!ev)
Packit 31ecd5
	ev = g_enum_get_value_by_nick (eclass, string);
Packit 31ecd5
Packit 31ecd5
      if (ev)
Packit 31ecd5
	*enum_value = ev->value;
Packit 31ecd5
      else
Packit 31ecd5
        retval = FALSE;
Packit 31ecd5
      
Packit 31ecd5
      g_type_class_unref (eclass);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return retval;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_flags_from_string (GType        type,
Packit 31ecd5
                                   const gchar *string,
Packit 31ecd5
                                   gint        *flags_value)
Packit 31ecd5
{
Packit 31ecd5
  gchar *endptr, *prevptr;
Packit 31ecd5
  guint i, j, ret, value;
Packit 31ecd5
  gchar *flagstr;
Packit 31ecd5
  GFlagsValue *fv;
Packit 31ecd5
  const gchar *flag;
Packit 31ecd5
Packit 31ecd5
  g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
Packit 31ecd5
  g_return_val_if_fail (string != NULL, 0);
Packit 31ecd5
Packit 31ecd5
  ret = TRUE;
Packit 31ecd5
  
Packit 31ecd5
  value = strtoul (string, &endptr, 0);
Packit 31ecd5
  if (endptr != string) /* parsed a number */
Packit 31ecd5
    *flags_value = value;
Packit 31ecd5
  else
Packit 31ecd5
    {
Packit 31ecd5
      GFlagsClass *fclass;
Packit 31ecd5
Packit 31ecd5
      fclass = g_type_class_ref (type);
Packit 31ecd5
Packit 31ecd5
      flagstr = g_strdup (string);
Packit 31ecd5
      for (value = i = j = 0; ; i++)
Packit 31ecd5
	{
Packit 31ecd5
          gboolean eos = (flagstr[i] == '\0') ? TRUE : FALSE;
Packit 31ecd5
	  
Packit 31ecd5
	  if (!eos && flagstr[i] != '|')
Packit 31ecd5
	    continue;
Packit 31ecd5
	  
Packit 31ecd5
	  flag = &flagstr[j];
Packit 31ecd5
	  endptr = &flagstr[i];
Packit 31ecd5
	  
Packit 31ecd5
	  if (!eos)
Packit 31ecd5
	    {
Packit 31ecd5
	      flagstr[i++] = '\0';
Packit 31ecd5
	      j = i;
Packit 31ecd5
	    }
Packit 31ecd5
	  
Packit 31ecd5
	  /* trim spaces */
Packit 31ecd5
	  for (;;)
Packit 31ecd5
	    {
Packit 31ecd5
	      gunichar ch = g_utf8_get_char (flag);
Packit 31ecd5
	      if (!g_unichar_isspace (ch))
Packit 31ecd5
		break;
Packit 31ecd5
Packit 31ecd5
	      flag = g_utf8_next_char (flag);
Packit 31ecd5
	    }
Packit 31ecd5
	  
Packit 31ecd5
	  while (endptr > flag)
Packit 31ecd5
	    {
Packit 31ecd5
              gunichar ch;
Packit 31ecd5
Packit 31ecd5
	      prevptr = g_utf8_prev_char (endptr);
Packit 31ecd5
Packit 31ecd5
	      ch = g_utf8_get_char (prevptr);
Packit 31ecd5
	      if (!g_unichar_isspace (ch))
Packit 31ecd5
		break;
Packit 31ecd5
Packit 31ecd5
	      endptr = prevptr;
Packit 31ecd5
	    }
Packit 31ecd5
	  
Packit 31ecd5
	  if (endptr > flag)
Packit 31ecd5
	    {
Packit 31ecd5
	      *endptr = '\0';
Packit 31ecd5
Packit 31ecd5
	      fv = g_flags_get_value_by_name (fclass, flag);
Packit 31ecd5
	      
Packit 31ecd5
	      if (!fv)
Packit 31ecd5
		fv = g_flags_get_value_by_nick (fclass, flag);
Packit 31ecd5
	      
Packit 31ecd5
	      if (fv)
Packit 31ecd5
		value |= fv->value;
Packit 31ecd5
	      else
Packit 31ecd5
		{
Packit 31ecd5
		  ret = FALSE;
Packit 31ecd5
		  break;
Packit 31ecd5
		}
Packit 31ecd5
	    }
Packit 31ecd5
	  
Packit 31ecd5
	  if (eos)
Packit 31ecd5
	    {
Packit 31ecd5
	      *flags_value = value;
Packit 31ecd5
	      break;
Packit 31ecd5
	    }
Packit 31ecd5
	}
Packit 31ecd5
      
Packit 31ecd5
      g_free (flagstr);
Packit 31ecd5
      
Packit 31ecd5
      g_type_class_unref (fclass);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return ret;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_knot_from_array (JsonArray   *array,
Packit 31ecd5
                       ClutterKnot *knot)
Packit 31ecd5
{
Packit 31ecd5
  if (json_array_get_length (array) != 2)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  knot->x = json_array_get_int_element (array, 0);
Packit 31ecd5
  knot->y = json_array_get_int_element (array, 1);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_knot_from_object (JsonObject  *object,
Packit 31ecd5
                        ClutterKnot *knot)
Packit 31ecd5
{
Packit 31ecd5
  if (json_object_has_member (object, "x"))
Packit 31ecd5
    knot->x = json_object_get_int_member (object, "x");
Packit 31ecd5
  else
Packit 31ecd5
    knot->x = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "y"))
Packit 31ecd5
    knot->y = json_object_get_int_member (object, "y");
Packit 31ecd5
  else
Packit 31ecd5
    knot->y = 0;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_knot (ClutterScript *script,
Packit 31ecd5
                            JsonNode      *node,
Packit 31ecd5
                            ClutterKnot   *knot)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (knot != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      return parse_knot_from_array (json_node_get_array (node), knot);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      return parse_knot_from_object (json_node_get_object (node), knot);
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_geometry_from_array (JsonArray       *array,
Packit 31ecd5
                           ClutterGeometry *geometry)
Packit 31ecd5
{
Packit 31ecd5
  if (json_array_get_length (array) != 4)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  geometry->x = json_array_get_int_element (array, 0);
Packit 31ecd5
  geometry->y = json_array_get_int_element (array, 1);
Packit 31ecd5
  geometry->width = json_array_get_int_element (array, 2);
Packit 31ecd5
  geometry->height = json_array_get_int_element (array, 3);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_geometry_from_object (JsonObject      *object,
Packit 31ecd5
                            ClutterGeometry *geometry)
Packit 31ecd5
{
Packit 31ecd5
  if (json_object_has_member (object, "x"))
Packit 31ecd5
    geometry->x = json_object_get_int_member (object, "x");
Packit 31ecd5
  else
Packit 31ecd5
    geometry->x = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "y"))
Packit 31ecd5
    geometry->y = json_object_get_int_member (object, "y");
Packit 31ecd5
  else
Packit 31ecd5
    geometry->y = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "width"))
Packit 31ecd5
    geometry->width = json_object_get_int_member (object, "width");
Packit 31ecd5
  else
Packit 31ecd5
    geometry->width = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "height"))
Packit 31ecd5
    geometry->height = json_object_get_int_member (object, "height");
Packit 31ecd5
  else
Packit 31ecd5
    geometry->height = 0;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_geometry (ClutterScript   *script,
Packit 31ecd5
                                JsonNode        *node,
Packit 31ecd5
                                ClutterGeometry *geometry)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (geometry != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      return parse_geometry_from_array (json_node_get_array (node), geometry);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      return parse_geometry_from_object (json_node_get_object (node), geometry);
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_color_from_array (JsonArray    *array,
Packit 31ecd5
                        ClutterColor *color)
Packit 31ecd5
{
Packit 31ecd5
  if (json_array_get_length (array) != 3 ||
Packit 31ecd5
      json_array_get_length (array) != 4)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  color->red   = CLAMP (json_array_get_int_element (array, 0), 0, 255);
Packit 31ecd5
  color->green = CLAMP (json_array_get_int_element (array, 1), 0, 255);
Packit 31ecd5
  color->blue  = CLAMP (json_array_get_int_element (array, 2), 0, 255);
Packit 31ecd5
Packit 31ecd5
  if (json_array_get_length (array) == 4)
Packit 31ecd5
    color->alpha = CLAMP (json_array_get_int_element (array, 3), 0, 255);
Packit 31ecd5
  else
Packit 31ecd5
    color->alpha = 255;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_color_from_object (JsonObject   *object,
Packit 31ecd5
                         ClutterColor *color)
Packit 31ecd5
{
Packit 31ecd5
  if (json_object_has_member (object, "red"))
Packit 31ecd5
    color->red = CLAMP (json_object_get_int_member (object, "red"), 0, 255);
Packit 31ecd5
  else
Packit 31ecd5
    color->red = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "green"))
Packit 31ecd5
    color->green = CLAMP (json_object_get_int_member (object, "green"), 0, 255);
Packit 31ecd5
  else
Packit 31ecd5
    color->green = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "blue"))
Packit 31ecd5
    color->blue = CLAMP (json_object_get_int_member (object, "blue"), 0, 255);
Packit 31ecd5
  else
Packit 31ecd5
    color->blue = 0;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "alpha"))
Packit 31ecd5
    color->alpha = CLAMP (json_object_get_int_member (object, "alpha"), 0, 255);
Packit 31ecd5
  else
Packit 31ecd5
    color->alpha = 255;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_color (ClutterScript *script,
Packit 31ecd5
                             JsonNode      *node,
Packit 31ecd5
                             ClutterColor  *color)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (color != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      return parse_color_from_array (json_node_get_array (node), color);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      return parse_color_from_object (json_node_get_object (node), color);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_VALUE:
Packit 31ecd5
      return clutter_color_from_string (color, json_node_get_string (node));
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_point_from_array (JsonArray    *array,
Packit 31ecd5
                        ClutterPoint *point)
Packit 31ecd5
{
Packit 31ecd5
  if (json_array_get_length (array) != 2)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  point->x = json_array_get_double_element (array, 0);
Packit 31ecd5
  point->y = json_array_get_double_element (array, 1);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_point_from_object (JsonObject   *object,
Packit 31ecd5
                         ClutterPoint *point)
Packit 31ecd5
{
Packit 31ecd5
  if (json_object_has_member (object, "x"))
Packit 31ecd5
    point->x = json_object_get_double_member (object, "x");
Packit 31ecd5
  else
Packit 31ecd5
    point->x = 0.f;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "y"))
Packit 31ecd5
    point->y = json_object_get_double_member (object, "y");
Packit 31ecd5
  else
Packit 31ecd5
    point->y = 0.f;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_point (ClutterScript *script,
Packit 31ecd5
                             JsonNode      *node,
Packit 31ecd5
                             ClutterPoint  *point)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (point != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      return parse_point_from_array (json_node_get_array (node), point);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      return parse_point_from_object (json_node_get_object (node), point);
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_size_from_array (JsonArray   *array,
Packit 31ecd5
                       ClutterSize *size)
Packit 31ecd5
{
Packit 31ecd5
  if (json_array_get_length (array) != 2)
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  size->width = json_array_get_double_element (array, 0);
Packit 31ecd5
  size->height = json_array_get_double_element (array, 1);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
parse_size_from_object (JsonObject  *object,
Packit 31ecd5
                        ClutterSize *size)
Packit 31ecd5
{
Packit 31ecd5
  if (json_object_has_member (object, "width"))
Packit 31ecd5
    size->width = json_object_get_double_member (object, "width");
Packit 31ecd5
  else
Packit 31ecd5
    size->width = 0.f;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "height"))
Packit 31ecd5
    size->height = json_object_get_double_member (object, "height");
Packit 31ecd5
  else
Packit 31ecd5
    size->height = 0.f;
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_size (ClutterScript *script,
Packit 31ecd5
                            JsonNode      *node,
Packit 31ecd5
                            ClutterSize   *size)
Packit 31ecd5
{
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (size != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      return parse_size_from_array (json_node_get_array (node), size);
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      return parse_size_from_object (json_node_get_object (node), size);
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
const gchar *
Packit 31ecd5
_clutter_script_get_id_from_node (JsonNode *node)
Packit 31ecd5
{
Packit 31ecd5
  JsonObject *object;
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      object = json_node_get_object (node);
Packit 31ecd5
      if (json_object_has_member (object, "id"))
Packit 31ecd5
        return json_object_get_string_member (object, "id");
Packit 31ecd5
      break;
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_VALUE:
Packit 31ecd5
      return json_node_get_string (node);
Packit 31ecd5
Packit 31ecd5
    default:
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return NULL;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static GList *
Packit 31ecd5
parse_children (ObjectInfo *oinfo,
Packit 31ecd5
                JsonNode   *node)
Packit 31ecd5
{
Packit 31ecd5
  JsonArray *array;
Packit 31ecd5
  GList *retval;
Packit 31ecd5
  guint array_len, i;
Packit 31ecd5
Packit 31ecd5
  if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
Packit 31ecd5
    return NULL;
Packit 31ecd5
Packit 31ecd5
  retval = oinfo->children;
Packit 31ecd5
Packit 31ecd5
  array = json_node_get_array (node);
Packit 31ecd5
  array_len = json_array_get_length (array);
Packit 31ecd5
Packit 31ecd5
  for (i = 0; i < array_len; i++)
Packit 31ecd5
    {
Packit 31ecd5
      JsonNode *child = json_array_get_element (array, i);
Packit 31ecd5
      const gchar *id_;
Packit 31ecd5
Packit 31ecd5
      id_ = _clutter_script_get_id_from_node (child);
Packit 31ecd5
      if (id_ != NULL)
Packit 31ecd5
        retval = g_list_prepend (retval, g_strdup (id_));
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return g_list_reverse (retval);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static GList *
Packit 31ecd5
parse_signals (ClutterScript *script,
Packit 31ecd5
               ObjectInfo    *oinfo,
Packit 31ecd5
               JsonNode      *node)
Packit 31ecd5
{
Packit 31ecd5
  JsonArray *array;
Packit 31ecd5
  GList *retval;
Packit 31ecd5
  guint array_len, i;
Packit 31ecd5
Packit 31ecd5
  if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
Packit 31ecd5
    {
Packit 31ecd5
      _clutter_script_warn_invalid_value (script, "signals", "Array", node);
Packit 31ecd5
      return NULL;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  retval = oinfo->signals;
Packit 31ecd5
  array = json_node_get_array (node);
Packit 31ecd5
  array_len = json_array_get_length (array);
Packit 31ecd5
Packit 31ecd5
  for (i = 0; i < array_len; i++)
Packit 31ecd5
    {
Packit 31ecd5
      JsonNode *val = json_array_get_element (array, i);
Packit 31ecd5
      SignalInfo *sinfo = NULL;
Packit 31ecd5
      JsonObject *object;
Packit 31ecd5
      const gchar *name;
Packit 31ecd5
Packit 31ecd5
      if (JSON_NODE_TYPE (val) != JSON_NODE_OBJECT)
Packit 31ecd5
        {
Packit 31ecd5
          _clutter_script_warn_invalid_value (script,
Packit 31ecd5
                                              "signals array", "Object",
Packit 31ecd5
                                              node);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      object = json_node_get_object (val);
Packit 31ecd5
Packit 31ecd5
      /* mandatory: "name" */
Packit 31ecd5
      if (!json_object_has_member (object, "name"))
Packit 31ecd5
        {
Packit 31ecd5
          _clutter_script_warn_missing_attribute (script, NULL, "name");
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
      else
Packit 31ecd5
        {
Packit 31ecd5
          name = json_object_get_string_member (object, "name");
Packit 31ecd5
          if (!name)
Packit 31ecd5
            {
Packit 31ecd5
              _clutter_script_warn_invalid_value (script,
Packit 31ecd5
                                                  "name", "string",
Packit 31ecd5
                                                  val);
Packit 31ecd5
              continue;
Packit 31ecd5
            }
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      /* mandatory: "target-state" or "handler" */
Packit 31ecd5
      if (json_object_has_member (object, "target-state"))
Packit 31ecd5
        {
Packit 31ecd5
          const gchar *state = NULL;
Packit 31ecd5
          const gchar *target = NULL;
Packit 31ecd5
          gboolean warp_to = FALSE;
Packit 31ecd5
Packit 31ecd5
          target = json_object_get_string_member (object, "target-state");
Packit 31ecd5
          if (target == NULL)
Packit 31ecd5
            {
Packit 31ecd5
              _clutter_script_warn_invalid_value (script,
Packit 31ecd5
                                                  "target-state", "string",
Packit 31ecd5
                                                  val);
Packit 31ecd5
              continue;
Packit 31ecd5
            }
Packit 31ecd5
Packit 31ecd5
          if (json_object_has_member (object, "states"))
Packit 31ecd5
            state = json_object_get_string_member (object, "states");
Packit 31ecd5
Packit 31ecd5
          if (json_object_has_member (object, "warp"))
Packit 31ecd5
            warp_to = json_object_get_boolean_member (object, "warp");
Packit 31ecd5
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                        "Added signal '%s' (states:%s, target-state:%s, warp:%s)",
Packit 31ecd5
                        name,
Packit 31ecd5
                        state != NULL ? state : "<default>", target,
Packit 31ecd5
                        warp_to ? "true" : "false");
Packit 31ecd5
Packit 31ecd5
          sinfo = g_slice_new0 (SignalInfo);
Packit 31ecd5
          sinfo->is_handler = FALSE;
Packit 31ecd5
          sinfo->name = g_strdup (name);
Packit 31ecd5
          sinfo->state = g_strdup (state);
Packit 31ecd5
          sinfo->target = g_strdup (target);
Packit 31ecd5
          sinfo->warp_to = warp_to;
Packit 31ecd5
        }
Packit 31ecd5
      else if (json_object_has_member (object, "handler"))
Packit 31ecd5
        {
Packit 31ecd5
          const gchar *handler;
Packit 31ecd5
          const gchar *connect;
Packit 31ecd5
          GConnectFlags flags = 0;
Packit 31ecd5
Packit 31ecd5
          handler = json_object_get_string_member (object, "handler");
Packit 31ecd5
          if (handler == NULL)
Packit 31ecd5
            {
Packit 31ecd5
              _clutter_script_warn_invalid_value (script,
Packit 31ecd5
                                                  "handler", "string",
Packit 31ecd5
                                                  val);
Packit 31ecd5
              continue;
Packit 31ecd5
            }
Packit 31ecd5
Packit 31ecd5
          /* optional: "object" */
Packit 31ecd5
          if (json_object_has_member (object, "object"))
Packit 31ecd5
            connect = json_object_get_string_member (object, "object");
Packit 31ecd5
          else
Packit 31ecd5
            connect = NULL;
Packit 31ecd5
Packit 31ecd5
          /* optional: "after" */
Packit 31ecd5
          if (json_object_has_member (object, "after"))
Packit 31ecd5
            {
Packit 31ecd5
              if (json_object_get_boolean_member (object, "after"))
Packit 31ecd5
                flags |= G_CONNECT_AFTER;
Packit 31ecd5
            }
Packit 31ecd5
Packit 31ecd5
          /* optional: "swapped" */
Packit 31ecd5
          if (json_object_has_member (object, "swapped"))
Packit 31ecd5
            {
Packit 31ecd5
              if (json_object_get_boolean_member (object, "swapped"))
Packit 31ecd5
                flags |= G_CONNECT_SWAPPED;
Packit 31ecd5
            }
Packit 31ecd5
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                        "Added signal '%s' (handler:%s, object:%s, flags:%d)",
Packit 31ecd5
                        name,
Packit 31ecd5
                        handler, connect, flags);
Packit 31ecd5
Packit 31ecd5
          sinfo = g_slice_new0 (SignalInfo);
Packit 31ecd5
          sinfo->is_handler = TRUE;
Packit 31ecd5
          sinfo->name = g_strdup (name);
Packit 31ecd5
          sinfo->handler = g_strdup (handler);
Packit 31ecd5
          sinfo->object = g_strdup (connect);
Packit 31ecd5
          sinfo->flags = flags;
Packit 31ecd5
        }
Packit 31ecd5
      else
Packit 31ecd5
        _clutter_script_warn_missing_attribute (script,
Packit 31ecd5
                                                NULL,
Packit 31ecd5
                                                "handler or state");
Packit 31ecd5
      if (sinfo != NULL)
Packit 31ecd5
        retval = g_list_prepend (retval, sinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return retval;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static ClutterTimeline *
Packit 31ecd5
construct_timeline (ClutterScript *script,
Packit 31ecd5
                    JsonObject    *object)
Packit 31ecd5
{
Packit 31ecd5
  ClutterTimeline *retval = NULL;
Packit 31ecd5
  ObjectInfo *oinfo;
Packit 31ecd5
  GList *members, *l;
Packit 31ecd5
Packit 31ecd5
  /* we fake an ObjectInfo so we can reuse clutter_script_construct_object()
Packit 31ecd5
   * here; we do not save it inside the hash table, because if this had
Packit 31ecd5
   * been a named object then we wouldn't have ended up here in the first
Packit 31ecd5
   * place
Packit 31ecd5
   */
Packit 31ecd5
  oinfo = g_slice_new0 (ObjectInfo);
Packit 31ecd5
  oinfo->gtype = CLUTTER_TYPE_TIMELINE;
Packit 31ecd5
  oinfo->id = g_strdup ("dummy");
Packit 31ecd5
Packit 31ecd5
  members = json_object_get_members (object);
Packit 31ecd5
  for (l = members; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      const gchar *name = l->data;
Packit 31ecd5
      JsonNode *node = json_object_get_member (object, name);
Packit 31ecd5
      PropertyInfo *pinfo = g_slice_new0 (PropertyInfo);
Packit 31ecd5
Packit 31ecd5
      pinfo->name = g_strdelimit (g_strdup (name), G_STR_DELIMITERS, '-');
Packit 31ecd5
      pinfo->node = json_node_copy (node);
Packit 31ecd5
Packit 31ecd5
      oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (members);
Packit 31ecd5
Packit 31ecd5
  _clutter_script_construct_object (script, oinfo);
Packit 31ecd5
  _clutter_script_apply_properties (script, oinfo);
Packit 31ecd5
  retval = CLUTTER_TIMELINE (oinfo->object);
Packit 31ecd5
Packit 31ecd5
  /* we transfer ownership to the alpha function, so we ref before
Packit 31ecd5
   * destroying the ObjectInfo to avoid the timeline going away
Packit 31ecd5
   */
Packit 31ecd5
  g_object_ref (retval);
Packit 31ecd5
  object_info_free (oinfo);
Packit 31ecd5
Packit 31ecd5
  return retval;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
/* define the names of the animation modes to match the ones
Packit 31ecd5
 * that developers might be more accustomed to
Packit 31ecd5
 */
Packit 31ecd5
static const struct
Packit 31ecd5
{
Packit 31ecd5
  const gchar *name;
Packit 31ecd5
  ClutterAnimationMode mode;
Packit 31ecd5
} animation_modes[] = {
Packit 31ecd5
  { "linear", CLUTTER_LINEAR },
Packit 31ecd5
  { "easeInQuad", CLUTTER_EASE_IN_QUAD },
Packit 31ecd5
  { "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
Packit 31ecd5
  { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
Packit 31ecd5
  { "easeInCubic", CLUTTER_EASE_IN_CUBIC },
Packit 31ecd5
  { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
Packit 31ecd5
  { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
Packit 31ecd5
  { "easeInQuart", CLUTTER_EASE_IN_QUART },
Packit 31ecd5
  { "easeOutQuart", CLUTTER_EASE_OUT_QUART },
Packit 31ecd5
  { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
Packit 31ecd5
  { "easeInQuint", CLUTTER_EASE_IN_QUINT },
Packit 31ecd5
  { "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
Packit 31ecd5
  { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
Packit 31ecd5
  { "easeInSine", CLUTTER_EASE_IN_SINE },
Packit 31ecd5
  { "easeOutSine", CLUTTER_EASE_OUT_SINE },
Packit 31ecd5
  { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
Packit 31ecd5
  { "easeInExpo", CLUTTER_EASE_IN_EXPO },
Packit 31ecd5
  { "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
Packit 31ecd5
  { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
Packit 31ecd5
  { "easeInCirc", CLUTTER_EASE_IN_CIRC },
Packit 31ecd5
  { "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
Packit 31ecd5
  { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
Packit 31ecd5
  { "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
Packit 31ecd5
  { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
Packit 31ecd5
  { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
Packit 31ecd5
  { "easeInBack", CLUTTER_EASE_IN_BACK },
Packit 31ecd5
  { "easeOutBack", CLUTTER_EASE_OUT_BACK },
Packit 31ecd5
  { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
Packit 31ecd5
  { "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
Packit 31ecd5
  { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
Packit 31ecd5
  { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
Packit 31ecd5
Packit 31ecd5
gulong
Packit 31ecd5
_clutter_script_resolve_animation_mode (JsonNode *node)
Packit 31ecd5
{
Packit 31ecd5
  gint i, res = CLUTTER_CUSTOM_MODE;
Packit 31ecd5
Packit 31ecd5
  if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
Packit 31ecd5
    return CLUTTER_CUSTOM_MODE;
Packit 31ecd5
Packit 31ecd5
  if (json_node_get_value_type (node) == G_TYPE_INT64)
Packit 31ecd5
    return json_node_get_int (node);
Packit 31ecd5
Packit 31ecd5
  if (json_node_get_value_type (node) == G_TYPE_STRING)
Packit 31ecd5
    {
Packit 31ecd5
      const gchar *name = json_node_get_string (node);
Packit 31ecd5
Packit 31ecd5
      /* XXX - we might be able to optimize by changing the ordering
Packit 31ecd5
       * of the animation_modes array, e.g.
Packit 31ecd5
       *  - special casing linear
Packit 31ecd5
       *  - tokenizing ('ease', 'In', 'Sine') and matching on token
Packit 31ecd5
       *  - binary searching?
Packit 31ecd5
       */
Packit 31ecd5
      for (i = 0; i < n_animation_modes; i++)
Packit 31ecd5
        {
Packit 31ecd5
          if (strcmp (animation_modes[i].name, name) == 0)
Packit 31ecd5
            return animation_modes[i].mode;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      if (_clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE,
Packit 31ecd5
                                            name,
Packit 31ecd5
                                            &res))
Packit 31ecd5
        return res;
Packit 31ecd5
Packit 31ecd5
      g_warning ("Unable to find the animation mode '%s'", name);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return CLUTTER_CUSTOM_MODE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static ClutterAlphaFunc
Packit 31ecd5
resolve_alpha_func (const gchar *name)
Packit 31ecd5
{
Packit 31ecd5
  static GModule *module = NULL;
Packit 31ecd5
  ClutterAlphaFunc func;
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name);
Packit 31ecd5
Packit 31ecd5
  if (G_UNLIKELY (!module))
Packit 31ecd5
    module = g_module_open (NULL, 0);
Packit 31ecd5
Packit 31ecd5
  if (g_module_symbol (module, name, (gpointer) &func))
Packit 31ecd5
    {
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table",
Packit 31ecd5
                    name);
Packit 31ecd5
      return func;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return NULL;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
GObject *
Packit 31ecd5
_clutter_script_parse_alpha (ClutterScript *script,
Packit 31ecd5
                             JsonNode      *node)
Packit 31ecd5
{
Packit 31ecd5
  GObject *retval = NULL;
Packit 31ecd5
  JsonObject *object;
Packit 31ecd5
  ClutterTimeline *timeline = NULL;
Packit 31ecd5
  ClutterAlphaFunc alpha_func = NULL;
Packit 31ecd5
  ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE;
Packit 31ecd5
  JsonNode *val;
Packit 31ecd5
  gboolean unref_timeline = FALSE;
Packit 31ecd5
Packit 31ecd5
  if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT)
Packit 31ecd5
    return NULL;
Packit 31ecd5
Packit 31ecd5
  object = json_node_get_object (node);
Packit 31ecd5
Packit 31ecd5
  val = json_object_get_member (object, "timeline");
Packit 31ecd5
  if (val)
Packit 31ecd5
    {
Packit 31ecd5
      if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE &&
Packit 31ecd5
          json_node_get_string (val) != NULL)
Packit 31ecd5
        {
Packit 31ecd5
          const gchar *id_ = json_node_get_string (val);
Packit 31ecd5
Packit 31ecd5
          timeline =
Packit 31ecd5
            CLUTTER_TIMELINE (clutter_script_get_object (script, id_));
Packit 31ecd5
        }
Packit 31ecd5
      else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT)
Packit 31ecd5
        {
Packit 31ecd5
          timeline = construct_timeline (script, json_node_get_object (val));
Packit 31ecd5
          unref_timeline = TRUE;
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  val = json_object_get_member (object, "mode");
Packit 31ecd5
  if (val != NULL)
Packit 31ecd5
    mode = _clutter_script_resolve_animation_mode (val);
Packit 31ecd5
Packit 31ecd5
  if (mode == CLUTTER_CUSTOM_MODE)
Packit 31ecd5
    {
Packit 31ecd5
      val = json_object_get_member (object, "function");
Packit 31ecd5
      if (val && json_node_get_string (val) != NULL)
Packit 31ecd5
        {
Packit 31ecd5
          alpha_func = resolve_alpha_func (json_node_get_string (val));
Packit 31ecd5
          if (!alpha_func)
Packit 31ecd5
            {
Packit 31ecd5
              g_warning ("Unable to find the function '%s' in the "
Packit 31ecd5
                         "Clutter alpha functions or the symbols table",
Packit 31ecd5
                         json_node_get_string (val));
Packit 31ecd5
            }
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)",
Packit 31ecd5
                unref_timeline ? "implicit" : "explicit",
Packit 31ecd5
                timeline ? timeline : 0x0,
Packit 31ecd5
                mode != CLUTTER_CUSTOM_MODE ? mode : 0,
Packit 31ecd5
                alpha_func ? alpha_func : 0x0);
Packit 31ecd5
Packit 31ecd5
  retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL);
Packit 31ecd5
Packit 31ecd5
  if (mode != CLUTTER_CUSTOM_MODE)
Packit 31ecd5
    clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode);
Packit 31ecd5
Packit 31ecd5
  if (alpha_func != NULL)
Packit 31ecd5
    clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL);
Packit 31ecd5
Packit 31ecd5
  clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline);
Packit 31ecd5
Packit 31ecd5
  /* if we created an implicit timeline, the Alpha has full ownership
Packit 31ecd5
   * of it now, since it won't be accessible from ClutterScript
Packit 31ecd5
   */
Packit 31ecd5
  if (unref_timeline)
Packit 31ecd5
    g_object_unref (timeline);
Packit 31ecd5
Packit 31ecd5
  return retval;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_script_parser_object_end (JsonParser *json_parser,
Packit 31ecd5
                                  JsonObject *object)
Packit 31ecd5
{
Packit 31ecd5
  ClutterScriptParser *parser = CLUTTER_SCRIPT_PARSER (json_parser);
Packit 31ecd5
  ClutterScript *script = parser->script;
Packit 31ecd5
  ObjectInfo *oinfo;
Packit 31ecd5
  JsonNode *val;
Packit 31ecd5
  const gchar *id_;
Packit 31ecd5
  GList *members, *l;
Packit 31ecd5
Packit 31ecd5
  /* if the object definition does not have an 'id' field we'll
Packit 31ecd5
   * fake one for it...
Packit 31ecd5
   */
Packit 31ecd5
  if (!json_object_has_member (object, "id"))
Packit 31ecd5
    {
Packit 31ecd5
      gchar *fake;
Packit 31ecd5
Packit 31ecd5
      /* ... unless it doesn't even have a type - in which case
Packit 31ecd5
       * it is an internal object definition and we're not
Packit 31ecd5
       * supposed to touch it
Packit 31ecd5
       */
Packit 31ecd5
      if (!json_object_has_member (object, "type"))
Packit 31ecd5
        return;
Packit 31ecd5
Packit 31ecd5
      fake = _clutter_script_generate_fake_id (script);
Packit 31ecd5
      json_object_set_string_member (object, "id", fake);
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                    "Adding fake id '%s' to object of type '%s'",
Packit 31ecd5
                    json_object_get_string_member (object, "id"),
Packit 31ecd5
                    json_object_get_string_member (object, "type"));
Packit 31ecd5
Packit 31ecd5
      g_free (fake);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (!json_object_has_member (object, "type"))
Packit 31ecd5
    {
Packit 31ecd5
      val = json_object_get_member (object, "id");
Packit 31ecd5
Packit 31ecd5
      _clutter_script_warn_missing_attribute (script,
Packit 31ecd5
                                              json_node_get_string (val),
Packit 31ecd5
                                              "type");
Packit 31ecd5
      return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  id_ = json_object_get_string_member (object, "id");
Packit 31ecd5
  CLUTTER_NOTE (SCRIPT, "Getting object info for object '%s'", id_);
Packit 31ecd5
Packit 31ecd5
  oinfo = _clutter_script_get_object_info (script, id_);
Packit 31ecd5
  if (oinfo == NULL)
Packit 31ecd5
    {
Packit 31ecd5
      const gchar *class_name;
Packit 31ecd5
Packit 31ecd5
      oinfo = g_slice_new0 (ObjectInfo);
Packit 31ecd5
      oinfo->merge_id = _clutter_script_get_last_merge_id (script);
Packit 31ecd5
      oinfo->id = g_strdup (id_);
Packit 31ecd5
      oinfo->has_unresolved = TRUE;
Packit 31ecd5
Packit 31ecd5
      class_name = json_object_get_string_member (object, "type");
Packit 31ecd5
      oinfo->class_name = g_strdup (class_name);
Packit 31ecd5
Packit 31ecd5
      if (json_object_has_member (object, "type_func"))
Packit 31ecd5
        {
Packit 31ecd5
          const gchar *type_func;
Packit 31ecd5
Packit 31ecd5
          type_func = json_object_get_string_member (object, "type_func");
Packit 31ecd5
          oinfo->type_func = g_strdup (type_func);
Packit 31ecd5
Packit 31ecd5
          /* remove the type_func member; we don't want it to
Packit 31ecd5
           * pollute the object members
Packit 31ecd5
           */
Packit 31ecd5
          json_object_remove_member (object, "type_func");
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "children"))
Packit 31ecd5
    {
Packit 31ecd5
      val = json_object_get_member (object, "children");
Packit 31ecd5
      oinfo->children = parse_children (oinfo, val);
Packit 31ecd5
Packit 31ecd5
      json_object_remove_member (object, "children");
Packit 31ecd5
Packit 31ecd5
      oinfo->has_unresolved = TRUE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (object, "signals"))
Packit 31ecd5
    {
Packit 31ecd5
      val = json_object_get_member (object, "signals");
Packit 31ecd5
      oinfo->signals = parse_signals (script, oinfo, val);
Packit 31ecd5
Packit 31ecd5
      json_object_remove_member (object, "signals");
Packit 31ecd5
Packit 31ecd5
      oinfo->has_unresolved = TRUE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (strcmp (oinfo->class_name, "ClutterStage") == 0 &&
Packit 31ecd5
      json_object_has_member (object, "is-default"))
Packit 31ecd5
    {
Packit 31ecd5
      oinfo->is_actor = TRUE;
Packit 31ecd5
      oinfo->is_stage = TRUE;
Packit 31ecd5
      oinfo->is_stage_default =
Packit 31ecd5
        json_object_get_boolean_member (object, "is-default");
Packit 31ecd5
Packit 31ecd5
      json_object_remove_member (object, "is-default");
Packit 31ecd5
    }
Packit 31ecd5
  else
Packit 31ecd5
    oinfo->is_stage_default = FALSE;
Packit 31ecd5
Packit 31ecd5
  members = json_object_get_members (object);
Packit 31ecd5
  for (l = members; l; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      const gchar *name = l->data;
Packit 31ecd5
      PropertyInfo *pinfo;
Packit 31ecd5
      JsonNode *node;
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Object '%s' member '%s'",
Packit 31ecd5
                    oinfo->id,
Packit 31ecd5
                    name);
Packit 31ecd5
Packit 31ecd5
      /* we have already parsed these */
Packit 31ecd5
      if (strcmp (name, "id") == 0 || strcmp (name, "type") == 0)
Packit 31ecd5
        continue;
Packit 31ecd5
Packit 31ecd5
      node = json_object_get_member (object, name);
Packit 31ecd5
Packit 31ecd5
      /* this should not really happen; we're getting a list of
Packit 31ecd5
       * member names, and if one does not map a real member
Packit 31ecd5
       * value then it's likely that something has gone wrong
Packit 31ecd5
       */
Packit 31ecd5
      if (G_UNLIKELY (node == NULL))
Packit 31ecd5
        {
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                        "Empty node for member '%s' of object '%s' (type: %s)",
Packit 31ecd5
                        name,
Packit 31ecd5
                        oinfo->id,
Packit 31ecd5
                        oinfo->class_name);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      pinfo = g_slice_new (PropertyInfo);
Packit 31ecd5
Packit 31ecd5
      pinfo->name = g_strdup (name);
Packit 31ecd5
      pinfo->node = json_node_copy (node);
Packit 31ecd5
      pinfo->pspec = NULL;
Packit 31ecd5
      pinfo->is_child = g_str_has_prefix (name, "child::") ? TRUE : FALSE;
Packit 31ecd5
      pinfo->is_layout = g_str_has_prefix (name, "layout::") ? TRUE : FALSE;
Packit 31ecd5
Packit 31ecd5
      oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
Packit 31ecd5
      oinfo->has_unresolved = TRUE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (members);
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                "Added object '%s' (type:%s, id:%d, props:%d, signals:%d)",
Packit 31ecd5
                oinfo->id,
Packit 31ecd5
                oinfo->class_name,
Packit 31ecd5
                oinfo->merge_id,
Packit 31ecd5
                g_list_length (oinfo->properties),
Packit 31ecd5
                g_list_length (oinfo->signals));
Packit 31ecd5
Packit 31ecd5
  _clutter_script_add_object_info (script, oinfo);
Packit 31ecd5
  _clutter_script_construct_object (script, oinfo);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
clutter_script_parser_parse_end (JsonParser *parser)
Packit 31ecd5
{
Packit 31ecd5
  clutter_script_ensure_objects (CLUTTER_SCRIPT_PARSER (parser)->script);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_translatable_string (ClutterScript *script,
Packit 31ecd5
                                           JsonNode      *node,
Packit 31ecd5
                                           char         **str)
Packit 31ecd5
{
Packit 31ecd5
  JsonObject *obj;
Packit 31ecd5
  const char *string, *domain, *context;
Packit 31ecd5
  const char *res;
Packit 31ecd5
  gboolean translatable;
Packit 31ecd5
Packit 31ecd5
  if (!JSON_NODE_HOLDS_OBJECT (node))
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  obj = json_node_get_object (node);
Packit 31ecd5
  if (!(json_object_has_member (obj, "translatable") &&
Packit 31ecd5
        json_object_has_member (obj, "string")))
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  translatable = json_object_get_boolean_member (obj, "translatable");
Packit 31ecd5
Packit 31ecd5
  string = json_object_get_string_member (obj, "string");
Packit 31ecd5
  if (string == NULL || *string == '\0')
Packit 31ecd5
    return FALSE;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (obj, "context"))
Packit 31ecd5
    context = json_object_get_string_member (obj, "context");
Packit 31ecd5
  else
Packit 31ecd5
    context = NULL;
Packit 31ecd5
Packit 31ecd5
  if (json_object_has_member (obj, "domain"))
Packit 31ecd5
    domain = json_object_get_string_member (obj, "domain");
Packit 31ecd5
  else
Packit 31ecd5
    domain = NULL;
Packit 31ecd5
Packit 31ecd5
  if (domain == NULL || *domain == '\0')
Packit 31ecd5
    domain = clutter_script_get_translation_domain (script);
Packit 31ecd5
Packit 31ecd5
  if (translatable)
Packit 31ecd5
    {
Packit 31ecd5
      if (context != NULL && *context != '\0')
Packit 31ecd5
        res = g_dpgettext2 (domain, context, string);
Packit 31ecd5
      else
Packit 31ecd5
        res = g_dgettext (domain, string);
Packit 31ecd5
    }
Packit 31ecd5
  else
Packit 31ecd5
    res = string;
Packit 31ecd5
Packit 31ecd5
  if (str != NULL)
Packit 31ecd5
    *str = g_strdup (res);
Packit 31ecd5
Packit 31ecd5
  return TRUE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
gboolean
Packit 31ecd5
_clutter_script_parse_node (ClutterScript *script,
Packit 31ecd5
                            GValue        *value,
Packit 31ecd5
                            const gchar   *name,
Packit 31ecd5
                            JsonNode      *node,
Packit 31ecd5
                            GParamSpec    *pspec)
Packit 31ecd5
{
Packit 31ecd5
  GValue node_value = G_VALUE_INIT;
Packit 31ecd5
  gboolean retval = FALSE;
Packit 31ecd5
Packit 31ecd5
  g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), FALSE);
Packit 31ecd5
  g_return_val_if_fail (name != NULL, FALSE);
Packit 31ecd5
  g_return_val_if_fail (node != NULL, FALSE);
Packit 31ecd5
Packit 31ecd5
  switch (JSON_NODE_TYPE (node))
Packit 31ecd5
    {
Packit 31ecd5
    case JSON_NODE_OBJECT:
Packit 31ecd5
      /* if we don't have a GParamSpec we can't infer the type
Packit 31ecd5
       * of the property; this usually means that this property
Packit 31ecd5
       * is a custom member that will be parsed by the Scriptable
Packit 31ecd5
       * interface implementantion
Packit 31ecd5
       */
Packit 31ecd5
      if (pspec == NULL && !G_IS_VALUE (value))
Packit 31ecd5
        return FALSE;
Packit 31ecd5
      else
Packit 31ecd5
        {
Packit 31ecd5
          GType p_type;
Packit 31ecd5
          ObjectInfo *oinfo;
Packit 31ecd5
          const gchar *id_;
Packit 31ecd5
Packit 31ecd5
          if (G_IS_VALUE (value))
Packit 31ecd5
            p_type = G_VALUE_TYPE (value);
Packit 31ecd5
          else
Packit 31ecd5
            {
Packit 31ecd5
              p_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
Packit 31ecd5
              g_value_init (value, p_type);
Packit 31ecd5
            }
Packit 31ecd5
Packit 31ecd5
          if (g_type_is_a (p_type, G_TYPE_OBJECT))
Packit 31ecd5
            {
Packit 31ecd5
              /* default GObject handling: we get the id and
Packit 31ecd5
               * retrieve the ObjectInfo for it; since the object
Packit 31ecd5
               * definitions are parsed leaf-first we are guaranteed
Packit 31ecd5
               * to have a defined object at this point
Packit 31ecd5
               */
Packit 31ecd5
              id_ = _clutter_script_get_id_from_node (node);
Packit 31ecd5
              if (id_ == NULL || *id_ == '\0')
Packit 31ecd5
                return FALSE;
Packit 31ecd5
Packit 31ecd5
              oinfo = _clutter_script_get_object_info (script, id_);
Packit 31ecd5
              if (oinfo == NULL || oinfo->gtype == G_TYPE_INVALID )
Packit 31ecd5
                return FALSE;
Packit 31ecd5
Packit 31ecd5
              if (g_type_is_a (oinfo->gtype, p_type))
Packit 31ecd5
                {
Packit 31ecd5
                  /* force construction, even though it should
Packit 31ecd5
                   * not be necessary; we don't need the properties
Packit 31ecd5
                   * to be applied as well: they will when the
Packit 31ecd5
                   * ScriptParser finishes
Packit 31ecd5
                   */
Packit 31ecd5
                  _clutter_script_construct_object (script, oinfo);
Packit 31ecd5
Packit 31ecd5
                  g_value_set_object (value, oinfo->object);
Packit 31ecd5
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == CLUTTER_TYPE_KNOT)
Packit 31ecd5
            {
Packit 31ecd5
              ClutterKnot knot = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* knot := { "x" : (int), "y" : (int) } */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_knot (script, node, &knot))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &knot);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == CLUTTER_TYPE_GEOMETRY)
Packit 31ecd5
            {
Packit 31ecd5
              ClutterGeometry geom = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* geometry := {
Packit 31ecd5
               *        "x" : (int),
Packit 31ecd5
               *        "y" : (int),
Packit 31ecd5
               *        "width" : (int),
Packit 31ecd5
               *        "height" : (int)
Packit 31ecd5
               * }
Packit 31ecd5
               */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_geometry (script, node, &geom))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &geom);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == CLUTTER_TYPE_COLOR)
Packit 31ecd5
            {
Packit 31ecd5
              ClutterColor color = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* color := {
Packit 31ecd5
               *        "red" : (int),
Packit 31ecd5
               *        "green" : (int),
Packit 31ecd5
               *        "blue" : (int),
Packit 31ecd5
               *        "alpha" : (int)
Packit 31ecd5
               * }
Packit 31ecd5
               */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_color (script, node, &color))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &color;;
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == CLUTTER_TYPE_POINT)
Packit 31ecd5
            {
Packit 31ecd5
              ClutterPoint point = CLUTTER_POINT_INIT_ZERO;
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_point (script, node, &point))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &point);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == CLUTTER_TYPE_SIZE)
Packit 31ecd5
            {
Packit 31ecd5
              ClutterSize size = CLUTTER_SIZE_INIT_ZERO;
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_size (script, node, &size))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &size);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (p_type == G_TYPE_STRING)
Packit 31ecd5
            {
Packit 31ecd5
              char *str = NULL;
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_translatable_string (script, node, &str))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_take_string (value, str);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
         }
Packit 31ecd5
      return FALSE;
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_ARRAY:
Packit 31ecd5
      if (!pspec && !G_IS_VALUE (value))
Packit 31ecd5
        return FALSE;
Packit 31ecd5
      else
Packit 31ecd5
        {
Packit 31ecd5
          if (!G_IS_VALUE (value))
Packit 31ecd5
            g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
Packit 31ecd5
Packit 31ecd5
          if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterKnot knot = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* knot := [ (int), (int) ] */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_knot (script, node, &knot))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &knot);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_GEOMETRY))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterGeometry geom = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* geometry := [ (int), (int), (int), (int) ] */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_geometry (script, node, &geom))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &geom);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (CLUTTER_VALUE_HOLDS_COLOR (value))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterColor color = { 0, };
Packit 31ecd5
Packit 31ecd5
              /* color := [ (int), (int), (int), (int) ] */
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_color (script, node, &color))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &color;;
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_POINT))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterPoint point = CLUTTER_POINT_INIT_ZERO;
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_point (script, node, &point))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &point);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (value, CLUTTER_TYPE_SIZE))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterSize size = CLUTTER_SIZE_INIT_ZERO;
Packit 31ecd5
Packit 31ecd5
              if (_clutter_script_parse_size (script, node, &size))
Packit 31ecd5
                {
Packit 31ecd5
                  g_value_set_boxed (value, &size);
Packit 31ecd5
                  return TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
Packit 31ecd5
            {
Packit 31ecd5
              JsonArray *array = json_node_get_array (node);
Packit 31ecd5
              guint i, array_len = json_array_get_length (array);
Packit 31ecd5
              GPtrArray *str_array = g_ptr_array_sized_new (array_len);
Packit 31ecd5
Packit 31ecd5
              /* strv := [ (str), (str), ... ] */
Packit 31ecd5
Packit 31ecd5
              for (i = 0; i < array_len; i++)
Packit 31ecd5
                {
Packit 31ecd5
                  JsonNode *val = json_array_get_element (array, i);
Packit 31ecd5
Packit 31ecd5
                  if (JSON_NODE_TYPE (val) != JSON_NODE_VALUE &&
Packit 31ecd5
                      json_node_get_string (val) == NULL)
Packit 31ecd5
                    continue;
Packit 31ecd5
Packit 31ecd5
                  g_ptr_array_add (str_array,
Packit 31ecd5
                                   (gpointer) json_node_get_string (val));
Packit 31ecd5
                }
Packit 31ecd5
Packit 31ecd5
              g_value_set_boxed (value, str_array->pdata);
Packit 31ecd5
              g_ptr_array_free (str_array, TRUE);
Packit 31ecd5
Packit 31ecd5
              return TRUE;
Packit 31ecd5
            }
Packit 31ecd5
        }
Packit 31ecd5
      return FALSE;
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_NULL:
Packit 31ecd5
      return FALSE;
Packit 31ecd5
Packit 31ecd5
    case JSON_NODE_VALUE:
Packit 31ecd5
      json_node_get_value (node, &node_value);
Packit 31ecd5
Packit 31ecd5
      if (!pspec && !G_IS_VALUE (value))
Packit 31ecd5
        g_value_init (value, G_VALUE_TYPE (&node_value));
Packit 31ecd5
      else if (pspec)
Packit 31ecd5
        g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
Packit 31ecd5
Packit 31ecd5
      switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
Packit 31ecd5
        {
Packit 31ecd5
        /* fundamental JSON types */
Packit 31ecd5
        case G_TYPE_INT64:
Packit 31ecd5
        case G_TYPE_DOUBLE:
Packit 31ecd5
        case G_TYPE_STRING:
Packit 31ecd5
        case G_TYPE_BOOLEAN:
Packit 31ecd5
          g_value_copy (&node_value, value);
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_INT:
Packit 31ecd5
          g_value_set_int (value, g_value_get_int64 (&node_value));
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_UINT:
Packit 31ecd5
          g_value_set_uint (value, (guint) g_value_get_int64 (&node_value));
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_ULONG:
Packit 31ecd5
          g_value_set_ulong (value, (gulong) g_value_get_int64 (&node_value));
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_UCHAR:
Packit 31ecd5
          g_value_set_uchar (value, (guchar) g_value_get_int64 (&node_value));
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_FLOAT:
Packit 31ecd5
          if (G_VALUE_HOLDS (&node_value, G_TYPE_DOUBLE))
Packit 31ecd5
            {
Packit 31ecd5
              g_value_set_float (value, g_value_get_double (&node_value));
Packit 31ecd5
              retval = TRUE;
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
Packit 31ecd5
            {
Packit 31ecd5
              g_value_set_float (value, g_value_get_int64 (&node_value));
Packit 31ecd5
              retval = TRUE;
Packit 31ecd5
            }
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_ENUM:
Packit 31ecd5
          if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
Packit 31ecd5
            {
Packit 31ecd5
              g_value_set_enum (value, g_value_get_int64 (&node_value));
Packit 31ecd5
              retval = TRUE;
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
Packit 31ecd5
            {
Packit 31ecd5
              gint enum_value;
Packit 31ecd5
Packit 31ecd5
              retval = _clutter_script_enum_from_string (G_VALUE_TYPE (value),
Packit 31ecd5
                                                         g_value_get_string (&node_value),
Packit 31ecd5
                                                         &enum_value);
Packit 31ecd5
              if (retval)
Packit 31ecd5
                g_value_set_enum (value, enum_value);
Packit 31ecd5
            }
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_FLAGS:
Packit 31ecd5
          if (G_VALUE_HOLDS (&node_value, G_TYPE_INT64))
Packit 31ecd5
            {
Packit 31ecd5
              g_value_set_flags (value, g_value_get_int64 (&node_value));
Packit 31ecd5
              retval = TRUE;
Packit 31ecd5
            }
Packit 31ecd5
          else if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
Packit 31ecd5
            {
Packit 31ecd5
              gint flags_value;
Packit 31ecd5
Packit 31ecd5
              retval = _clutter_script_flags_from_string (G_VALUE_TYPE (value),
Packit 31ecd5
                                                          g_value_get_string (&node_value),
Packit 31ecd5
                                                          &flags_value);
Packit 31ecd5
              if (retval)
Packit 31ecd5
                g_value_set_flags (value, flags_value);
Packit 31ecd5
            }
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_BOXED:
Packit 31ecd5
          if (G_VALUE_HOLDS (value, CLUTTER_TYPE_COLOR))
Packit 31ecd5
            {
Packit 31ecd5
              ClutterColor color = { 0, };
Packit 31ecd5
Packit 31ecd5
              retval = _clutter_script_parse_color (script, node, &color;;
Packit 31ecd5
              if (retval)
Packit 31ecd5
                clutter_value_set_color (value, &color;;
Packit 31ecd5
            }
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        case G_TYPE_OBJECT:
Packit 31ecd5
          if (G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
Packit 31ecd5
            {
Packit 31ecd5
              const gchar *str = g_value_get_string (&node_value);
Packit 31ecd5
              GObject *object = clutter_script_get_object (script, str);
Packit 31ecd5
              if (object)
Packit 31ecd5
                {
Packit 31ecd5
                  CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                                "Assigning '%s' (%s) to property '%s'",
Packit 31ecd5
                                str,
Packit 31ecd5
                                G_OBJECT_TYPE_NAME (object),
Packit 31ecd5
                                name);
Packit 31ecd5
Packit 31ecd5
                  g_value_set_object (value, object);
Packit 31ecd5
                  retval = TRUE;
Packit 31ecd5
                }
Packit 31ecd5
            }
Packit 31ecd5
          break;
Packit 31ecd5
Packit 31ecd5
        default:
Packit 31ecd5
          retval = FALSE;
Packit 31ecd5
          break;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      if (G_VALUE_TYPE (value) == G_TYPE_GTYPE &&
Packit 31ecd5
          G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
Packit 31ecd5
        {
Packit 31ecd5
          const gchar *str = g_value_get_string (&node_value);
Packit 31ecd5
          GType type = clutter_script_get_type_from_name (script, str);
Packit 31ecd5
          g_value_set_gtype (value, type);
Packit 31ecd5
          retval = TRUE;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      g_value_unset (&node_value);
Packit 31ecd5
      break;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  return retval;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static GList *
Packit 31ecd5
clutter_script_translate_parameters (ClutterScript  *script,
Packit 31ecd5
                                     GObject        *object,
Packit 31ecd5
                                     const gchar    *name,
Packit 31ecd5
                                     GList          *properties,
Packit 31ecd5
                                     GArray        **params)
Packit 31ecd5
{
Packit 31ecd5
  ClutterScriptable *scriptable = NULL;
Packit 31ecd5
  ClutterScriptableIface *iface = NULL;
Packit 31ecd5
  GList *l, *unparsed;
Packit 31ecd5
  gboolean parse_custom = FALSE;
Packit 31ecd5
Packit 31ecd5
  *params = g_array_new (FALSE, FALSE, sizeof (GParameter));
Packit 31ecd5
Packit 31ecd5
  if (CLUTTER_IS_SCRIPTABLE (object))
Packit 31ecd5
    {
Packit 31ecd5
      scriptable = CLUTTER_SCRIPTABLE (object);
Packit 31ecd5
      iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
Packit 31ecd5
Packit 31ecd5
      if (iface->parse_custom_node)
Packit 31ecd5
        parse_custom = TRUE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  unparsed = NULL;
Packit 31ecd5
Packit 31ecd5
  for (l = properties; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      PropertyInfo *pinfo = l->data;
Packit 31ecd5
      GParameter param = { NULL };
Packit 31ecd5
      gboolean res = FALSE;
Packit 31ecd5
Packit 31ecd5
      if (pinfo->is_child || pinfo->is_layout)
Packit 31ecd5
        {
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT, "Skipping %s property '%s'",
Packit 31ecd5
                        pinfo->is_child ? "child" : "layout",
Packit 31ecd5
                        pinfo->name);
Packit 31ecd5
          unparsed = g_list_prepend (unparsed, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Parsing %s property (id:%s)",
Packit 31ecd5
                    pinfo->pspec ? "regular" : "custom",
Packit 31ecd5
                    pinfo->name);
Packit 31ecd5
Packit 31ecd5
      if (parse_custom)
Packit 31ecd5
        res = iface->parse_custom_node (scriptable, script, &param.value,
Packit 31ecd5
                                        pinfo->name,
Packit 31ecd5
                                        pinfo->node);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        res = _clutter_script_parse_node (script, &param.value,
Packit 31ecd5
                                          pinfo->name,
Packit 31ecd5
                                          pinfo->node,
Packit 31ecd5
                                          pinfo->pspec);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        {
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT, "Property '%s' ignored", pinfo->name);
Packit 31ecd5
          unparsed = g_list_prepend (unparsed, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      param.name = g_strdup (pinfo->name);
Packit 31ecd5
Packit 31ecd5
      g_array_append_val (*params, param);
Packit 31ecd5
Packit 31ecd5
      property_info_free (pinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (properties);
Packit 31ecd5
Packit 31ecd5
  return unparsed;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static GList *
Packit 31ecd5
clutter_script_construct_parameters (ClutterScript  *script,
Packit 31ecd5
                                     GType           gtype,
Packit 31ecd5
                                     const gchar    *name,
Packit 31ecd5
                                     GList          *properties,
Packit 31ecd5
                                     GArray        **construct_params)
Packit 31ecd5
{
Packit 31ecd5
  GObjectClass *klass;
Packit 31ecd5
  GList *l, *unparsed;
Packit 31ecd5
Packit 31ecd5
  klass = g_type_class_ref (gtype);
Packit 31ecd5
  g_assert (klass != NULL);
Packit 31ecd5
Packit 31ecd5
  *construct_params = g_array_new (FALSE, FALSE, sizeof (GParameter));
Packit 31ecd5
Packit 31ecd5
  unparsed = NULL;
Packit 31ecd5
Packit 31ecd5
  for (l = properties; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      PropertyInfo *pinfo = l->data;
Packit 31ecd5
      GParameter param = { NULL };
Packit 31ecd5
      GParamSpec *pspec = NULL;
Packit 31ecd5
Packit 31ecd5
      /* we allow custom property names for classes, so if we
Packit 31ecd5
       * don't find a corresponding GObject property for this
Packit 31ecd5
       * class we just skip it and let the class itself deal
Packit 31ecd5
       * with it later on
Packit 31ecd5
       */
Packit 31ecd5
      pspec = g_object_class_find_property (klass, pinfo->name);
Packit 31ecd5
      if (pspec)
Packit 31ecd5
        pinfo->pspec = g_param_spec_ref (pspec);
Packit 31ecd5
      else
Packit 31ecd5
        {
Packit 31ecd5
          pinfo->pspec = NULL;
Packit 31ecd5
          unparsed = g_list_prepend (unparsed, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
Packit 31ecd5
        {
Packit 31ecd5
          unparsed = g_list_prepend (unparsed, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      param.name = g_strdup (pinfo->name);
Packit 31ecd5
Packit 31ecd5
      if (!_clutter_script_parse_node (script, &param.value,
Packit 31ecd5
                                       pinfo->name,
Packit 31ecd5
                                       pinfo->node,
Packit 31ecd5
                                       pinfo->pspec))
Packit 31ecd5
        {
Packit 31ecd5
          unparsed = g_list_prepend (unparsed, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      g_array_append_val (*construct_params, param);
Packit 31ecd5
Packit 31ecd5
      property_info_free (pinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (properties);
Packit 31ecd5
Packit 31ecd5
  g_type_class_unref (klass);
Packit 31ecd5
Packit 31ecd5
  return unparsed;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
apply_layout_properties (ClutterScript    *script,
Packit 31ecd5
                         ClutterContainer *container,
Packit 31ecd5
                         ClutterActor     *actor,
Packit 31ecd5
                         ObjectInfo       *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  ClutterScriptable *scriptable = NULL;
Packit 31ecd5
  ClutterScriptableIface *iface = NULL;
Packit 31ecd5
  gboolean parse_custom_node = FALSE;
Packit 31ecd5
  GList *l, *unresolved, *properties;
Packit 31ecd5
  ClutterLayoutManager *manager;
Packit 31ecd5
  GType meta_type;
Packit 31ecd5
Packit 31ecd5
  manager = g_object_get_data (G_OBJECT (container), "clutter-layout-manager");
Packit 31ecd5
  if (manager == NULL)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  meta_type = _clutter_layout_manager_get_child_meta_type (manager);
Packit 31ecd5
  if (meta_type == G_TYPE_INVALID)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  CLUTTER_NOTE (SCRIPT, "Layout manager of type '%s' with meta type '%s'",
Packit 31ecd5
                G_OBJECT_TYPE_NAME (manager),
Packit 31ecd5
                g_type_name (meta_type));
Packit 31ecd5
Packit 31ecd5
  /* shortcut, to avoid typechecking every time */
Packit 31ecd5
  if (CLUTTER_IS_SCRIPTABLE (manager))
Packit 31ecd5
    {
Packit 31ecd5
      scriptable = CLUTTER_SCRIPTABLE (manager);
Packit 31ecd5
      iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
Packit 31ecd5
Packit 31ecd5
      parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  properties = oinfo->properties;
Packit 31ecd5
  oinfo->properties = NULL;
Packit 31ecd5
Packit 31ecd5
  unresolved = NULL;
Packit 31ecd5
  for (l = properties; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      PropertyInfo *pinfo = l->data;
Packit 31ecd5
      GValue value = G_VALUE_INIT;
Packit 31ecd5
      gboolean res = FALSE;
Packit 31ecd5
      const gchar *name;
Packit 31ecd5
Packit 31ecd5
      if (!pinfo->is_layout)
Packit 31ecd5
        {
Packit 31ecd5
          unresolved = g_list_prepend (unresolved, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      name = pinfo->name + strlen ("layout::");
Packit 31ecd5
Packit 31ecd5
      pinfo->pspec =
Packit 31ecd5
        clutter_layout_manager_find_child_property (manager, name);
Packit 31ecd5
Packit 31ecd5
      if (pinfo->pspec != NULL)
Packit 31ecd5
        g_param_spec_ref (pinfo->pspec);
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Parsing %s layout property (id:%s)",
Packit 31ecd5
                    pinfo->pspec != NULL ? "regular" : "custom",
Packit 31ecd5
                    name);
Packit 31ecd5
Packit 31ecd5
      if (parse_custom_node)
Packit 31ecd5
        res = iface->parse_custom_node (scriptable, script, &value,
Packit 31ecd5
                                        name,
Packit 31ecd5
                                        pinfo->node);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        res = _clutter_script_parse_node (script, &value,
Packit 31ecd5
                                          name,
Packit 31ecd5
                                          pinfo->node,
Packit 31ecd5
                                          pinfo->pspec);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        {
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT, "Layout property '%s' ignored", name);
Packit 31ecd5
          unresolved = g_list_prepend (unresolved, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                    "Setting %s layout property '%s' (type:%s) to "
Packit 31ecd5
                    "object '%s' (id:%s)",
Packit 31ecd5
                    iface->set_custom_property != NULL ? "custom" : "regular",
Packit 31ecd5
                    name,
Packit 31ecd5
                    g_type_name (G_VALUE_TYPE (&value)),
Packit 31ecd5
                    g_type_name (oinfo->gtype),
Packit 31ecd5
                    oinfo->id);
Packit 31ecd5
Packit 31ecd5
      clutter_layout_manager_child_set_property (manager, container, actor,
Packit 31ecd5
                                                 name,
Packit 31ecd5
                                                 &value);
Packit 31ecd5
Packit 31ecd5
      g_value_unset (&value);
Packit 31ecd5
Packit 31ecd5
      property_info_free (pinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (properties);
Packit 31ecd5
Packit 31ecd5
  oinfo->properties = unresolved;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
apply_child_properties (ClutterScript    *script,
Packit 31ecd5
                        ClutterContainer *container,
Packit 31ecd5
                        ClutterActor     *actor,
Packit 31ecd5
                        ObjectInfo       *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  ClutterScriptable *scriptable = NULL;
Packit 31ecd5
  ClutterScriptableIface *iface = NULL;
Packit 31ecd5
  gboolean parse_custom_node = FALSE;
Packit 31ecd5
  GList *l, *unresolved, *properties;
Packit 31ecd5
  GObjectClass *klass;
Packit 31ecd5
  GType meta_type;
Packit 31ecd5
Packit 31ecd5
  meta_type = CLUTTER_CONTAINER_GET_IFACE (container)->child_meta_type;
Packit 31ecd5
  if (meta_type == G_TYPE_INVALID)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  klass = G_OBJECT_GET_CLASS (container);
Packit 31ecd5
Packit 31ecd5
  /* shortcut, to avoid typechecking every time */
Packit 31ecd5
  if (CLUTTER_IS_SCRIPTABLE (container))
Packit 31ecd5
    {
Packit 31ecd5
      scriptable = CLUTTER_SCRIPTABLE (container);
Packit 31ecd5
      iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
Packit 31ecd5
Packit 31ecd5
      parse_custom_node = iface->parse_custom_node != NULL ? TRUE : FALSE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  properties = oinfo->properties;
Packit 31ecd5
  oinfo->properties = NULL;
Packit 31ecd5
Packit 31ecd5
  unresolved = NULL;
Packit 31ecd5
  for (l = properties; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      PropertyInfo *pinfo = l->data;
Packit 31ecd5
      GValue value = G_VALUE_INIT;
Packit 31ecd5
      gboolean res = FALSE;
Packit 31ecd5
      const gchar *name;
Packit 31ecd5
Packit 31ecd5
      if (!pinfo->is_child)
Packit 31ecd5
        {
Packit 31ecd5
          unresolved = g_list_prepend (unresolved, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      name = pinfo->name + strlen ("child::");
Packit 31ecd5
Packit 31ecd5
      pinfo->pspec =
Packit 31ecd5
        clutter_container_class_find_child_property (klass, name);
Packit 31ecd5
Packit 31ecd5
      if (pinfo->pspec != NULL)
Packit 31ecd5
        g_param_spec_ref (pinfo->pspec);
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Parsing %s child property (id:%s)",
Packit 31ecd5
                    pinfo->pspec != NULL ? "regular" : "custom",
Packit 31ecd5
                    name);
Packit 31ecd5
Packit 31ecd5
      if (parse_custom_node)
Packit 31ecd5
        res = iface->parse_custom_node (scriptable, script, &value,
Packit 31ecd5
                                        name,
Packit 31ecd5
                                        pinfo->node);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        res = _clutter_script_parse_node (script, &value,
Packit 31ecd5
                                          name,
Packit 31ecd5
                                          pinfo->node,
Packit 31ecd5
                                          pinfo->pspec);
Packit 31ecd5
Packit 31ecd5
      if (!res)
Packit 31ecd5
        {
Packit 31ecd5
          CLUTTER_NOTE (SCRIPT, "Child property '%s' ignored", name);
Packit 31ecd5
          unresolved = g_list_prepend (unresolved, pinfo);
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                    "Setting %s child property '%s' (type:%s) to "
Packit 31ecd5
                    "object '%s' (id:%s)",
Packit 31ecd5
                    iface->set_custom_property != NULL ? "custom" : "regular",
Packit 31ecd5
                    name,
Packit 31ecd5
                    g_type_name (G_VALUE_TYPE (&value)),
Packit 31ecd5
                    g_type_name (oinfo->gtype),
Packit 31ecd5
                    oinfo->id);
Packit 31ecd5
Packit 31ecd5
      clutter_container_child_set_property (container, actor,
Packit 31ecd5
                                            name,
Packit 31ecd5
                                            &value);
Packit 31ecd5
Packit 31ecd5
      g_value_unset (&value);
Packit 31ecd5
Packit 31ecd5
      property_info_free (pinfo);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_free (properties);
Packit 31ecd5
Packit 31ecd5
  oinfo->properties = unresolved;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
add_children (ClutterScript *script,
Packit 31ecd5
              ObjectInfo    *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  ClutterContainer *container = CLUTTER_CONTAINER (oinfo->object);
Packit 31ecd5
  GList *l, *unresolved;
Packit 31ecd5
Packit 31ecd5
  unresolved = NULL;
Packit 31ecd5
  for (l = oinfo->children; l != NULL; l = l->next)
Packit 31ecd5
    {
Packit 31ecd5
      const gchar *name = l->data;
Packit 31ecd5
      GObject *object = NULL;
Packit 31ecd5
      ObjectInfo *child_info;
Packit 31ecd5
Packit 31ecd5
      child_info = _clutter_script_get_object_info (script, name);
Packit 31ecd5
      if (child_info != NULL)
Packit 31ecd5
        {
Packit 31ecd5
          _clutter_script_construct_object (script, child_info);
Packit 31ecd5
          object = child_info->object;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      if (object == NULL)
Packit 31ecd5
        {
Packit 31ecd5
          unresolved = g_list_prepend (unresolved, g_strdup (name));
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      if (!CLUTTER_IS_ACTOR (object))
Packit 31ecd5
        {
Packit 31ecd5
          g_warning ("The object definition '%s' (type: %s) is not "
Packit 31ecd5
                     "an actor, but it is referenced in the 'children' "
Packit 31ecd5
                     "member of the container '%s' (type: %s); skipping.",
Packit 31ecd5
                     child_info->id,
Packit 31ecd5
                     g_type_name (child_info->gtype),
Packit 31ecd5
                     oinfo->id,
Packit 31ecd5
                     g_type_name (oinfo->gtype));
Packit 31ecd5
          continue;
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT, "Adding children '%s' to actor of type '%s'",
Packit 31ecd5
                    name,
Packit 31ecd5
                    g_type_name (G_OBJECT_TYPE (container)));
Packit 31ecd5
Packit 31ecd5
      clutter_container_add_actor (container, CLUTTER_ACTOR (object));
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
Packit 31ecd5
  g_list_free (oinfo->children);
Packit 31ecd5
Packit 31ecd5
  oinfo->children = unresolved;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static inline void
Packit 31ecd5
_clutter_script_check_unresolved (ClutterScript *script,
Packit 31ecd5
                                  ObjectInfo    *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  if (oinfo->children != NULL && CLUTTER_IS_CONTAINER (oinfo->object))
Packit 31ecd5
    add_children (script, oinfo);
Packit 31ecd5
Packit 31ecd5
  /* this is a bit *eugh*, but it allows us to effectively make sure
Packit 31ecd5
   * that child and layout properties are parsed and applied to the
Packit 31ecd5
   * right child
Packit 31ecd5
   */
Packit 31ecd5
  if (oinfo->properties != NULL && CLUTTER_IS_ACTOR (oinfo->object))
Packit 31ecd5
    {
Packit 31ecd5
      ClutterActor *parent;
Packit 31ecd5
Packit 31ecd5
      parent = clutter_actor_get_parent (CLUTTER_ACTOR (oinfo->object));
Packit 31ecd5
      if (parent != NULL)
Packit 31ecd5
        {
Packit 31ecd5
          ClutterContainer *container = CLUTTER_CONTAINER (parent);
Packit 31ecd5
          ClutterActor *child;
Packit 31ecd5
Packit 31ecd5
          for (child = clutter_actor_get_first_child (parent);
Packit 31ecd5
               child != NULL;
Packit 31ecd5
               child = clutter_actor_get_next_sibling (child))
Packit 31ecd5
            {
Packit 31ecd5
              ObjectInfo *child_info;
Packit 31ecd5
              const gchar *id_;
Packit 31ecd5
Packit 31ecd5
              id_ = clutter_get_script_id (G_OBJECT (child));
Packit 31ecd5
              if (id_ == NULL || *id_ == '\0')
Packit 31ecd5
                continue;
Packit 31ecd5
Packit 31ecd5
              child_info = _clutter_script_get_object_info (script, id_);
Packit 31ecd5
              if (child_info == NULL)
Packit 31ecd5
                continue;
Packit 31ecd5
Packit 31ecd5
              apply_child_properties (script, container,
Packit 31ecd5
                                      child,
Packit 31ecd5
                                      child_info);
Packit 31ecd5
              apply_layout_properties (script, container,
Packit 31ecd5
                                       child,
Packit 31ecd5
                                       child_info);
Packit 31ecd5
            }
Packit 31ecd5
        }
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (oinfo->properties || oinfo->children)
Packit 31ecd5
    oinfo->has_unresolved = TRUE;
Packit 31ecd5
  else
Packit 31ecd5
    oinfo->has_unresolved = FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
void
Packit 31ecd5
_clutter_script_apply_properties (ClutterScript *script,
Packit 31ecd5
                                  ObjectInfo    *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  ClutterScriptable *scriptable = NULL;
Packit 31ecd5
  ClutterScriptableIface *iface = NULL;
Packit 31ecd5
  gboolean set_custom_property = FALSE;
Packit 31ecd5
  GObject *object = oinfo->object;
Packit 31ecd5
  GList *properties;
Packit 31ecd5
  GArray *params;
Packit 31ecd5
  guint i;
Packit 31ecd5
Packit 31ecd5
  if (!oinfo->has_unresolved)
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  /* shortcut, to avoid typechecking every time */
Packit 31ecd5
  if (CLUTTER_IS_SCRIPTABLE (object))
Packit 31ecd5
    {
Packit 31ecd5
      scriptable = CLUTTER_SCRIPTABLE (object);
Packit 31ecd5
      iface = CLUTTER_SCRIPTABLE_GET_IFACE (scriptable);
Packit 31ecd5
Packit 31ecd5
      if (iface->set_custom_property)
Packit 31ecd5
        set_custom_property = TRUE;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  /* then we get the rest of the parameters, asking the object itself
Packit 31ecd5
   * to translate them for us, if we cannot do that
Packit 31ecd5
   */
Packit 31ecd5
  properties = oinfo->properties;
Packit 31ecd5
  oinfo->properties = clutter_script_translate_parameters (script,
Packit 31ecd5
                                                           object,
Packit 31ecd5
                                                           oinfo->id,
Packit 31ecd5
                                                           properties,
Packit 31ecd5
                                                           &params);
Packit 31ecd5
Packit 31ecd5
  /* consume all the properties we could translate in this pass */
Packit 31ecd5
  for (i = 0; i < params->len; i++)
Packit 31ecd5
    {
Packit 31ecd5
      GParameter *param = &g_array_index (params, GParameter, i);
Packit 31ecd5
Packit 31ecd5
      CLUTTER_NOTE (SCRIPT,
Packit 31ecd5
                    "Setting %s property '%s' (type:%s) to object '%s' (id:%s)",
Packit 31ecd5
                    set_custom_property ? "custom" : "regular",
Packit 31ecd5
                    param->name,
Packit 31ecd5
                    g_type_name (G_VALUE_TYPE (&param->value)),
Packit 31ecd5
                    g_type_name (oinfo->gtype),
Packit 31ecd5
                    oinfo->id);
Packit 31ecd5
Packit 31ecd5
      if (set_custom_property)
Packit 31ecd5
        iface->set_custom_property (scriptable, script,
Packit 31ecd5
                                    param->name,
Packit 31ecd5
                                    &param->value);
Packit 31ecd5
      else
Packit 31ecd5
        g_object_set_property (object, param->name, &param->value);
Packit 31ecd5
Packit 31ecd5
      g_free ((gchar *) param->name);
Packit 31ecd5
      g_value_unset (&param->value);
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  g_array_free (params, TRUE);
Packit 31ecd5
Packit 31ecd5
  _clutter_script_check_unresolved (script, oinfo);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
void
Packit 31ecd5
_clutter_script_construct_object (ClutterScript *script,
Packit 31ecd5
                                  ObjectInfo    *oinfo)
Packit 31ecd5
{
Packit 31ecd5
  GArray *params = NULL;
Packit 31ecd5
  guint i;
Packit 31ecd5
Packit 31ecd5
  /* we have completely updated the object */
Packit 31ecd5
  if (oinfo->object != NULL)
Packit 31ecd5
    {
Packit 31ecd5
      if (oinfo->has_unresolved)
Packit 31ecd5
        _clutter_script_check_unresolved (script, oinfo);
Packit 31ecd5
Packit 31ecd5
      return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  if (oinfo->gtype == G_TYPE_INVALID)
Packit 31ecd5
    {
Packit 31ecd5
      if (G_UNLIKELY (oinfo->type_func))
Packit 31ecd5
        oinfo->gtype = _clutter_script_get_type_from_symbol (oinfo->type_func);
Packit 31ecd5
      else
Packit 31ecd5
        oinfo->gtype = clutter_script_get_type_from_name (script, oinfo->class_name);
Packit 31ecd5
Packit 31ecd5
      if (G_UNLIKELY (oinfo->gtype == G_TYPE_INVALID))
Packit 31ecd5
        return;
Packit 31ecd5
    }
Packit 31ecd5
Packit 31ecd5
  oinfo->is_actor = g_type_is_a (oinfo->gtype, CLUTTER_TYPE_ACTOR);
Packit 31ecd5
  if (oinfo->is_actor)
Packit 31ecd5
    oinfo->is_stage = g_type_is_a (oinfo->gtype, CLUTTER_TYPE_STAGE);
Packit 31ecd5
Packit 31ecd5
  if (oinfo->is_stage && oinfo->is_stage_default)
Packit 31ecd5
    {
Packit 31ecd5
      ClutterStageManager *manager = clutter_stage_manager_get_default ();
Packit 31ecd5
      GList *properties = oinfo->properties;
Packit 31ecd5
      ClutterStage *default_stage;
Packit 31ecd5
Packit 31ecd5
      /* the default stage is a complex beast: we cannot create it using
Packit 31ecd5
       * g_object_newv() but we need clutter_script_construct_parameters()
Packit 31ecd5
       * to add the GParamSpec to the PropertyInfo pspec member, so
Packit 31ecd5
       * that we don't have to implement every complex property (like
Packit 31ecd5
       * the "color" one) directly inside the ClutterStage class.
Packit 31ecd5
       */
Packit 31ecd5
      oinfo->properties =
Packit 31ecd5
        clutter_script_construct_parameters (script,
Packit 31ecd5
                                             oinfo->gtype,
Packit 31ecd5
                                             oinfo->id,
Packit 31ecd5
                                             properties,
Packit 31ecd5
                                             &params);
Packit 31ecd5
Packit 31ecd5
      default_stage = clutter_stage_manager_get_default_stage (manager);
Packit 31ecd5
      oinfo->object = G_OBJECT (default_stage);
Packit 31ecd5
Packit 31ecd5
      for (i = 0; i < params->len; i++)
Packit 31ecd5
        {
Packit 31ecd5
          GParameter *param = &g_array_index (params, GParameter, i);
Packit 31ecd5
Packit 31ecd5
          g_free ((gchar *) param->name);
Packit 31ecd5
          g_value_unset (&param->value);
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      g_array_free (params, TRUE);
Packit 31ecd5
    }
Packit 31ecd5
  else
Packit 31ecd5
    {
Packit 31ecd5
      GList *properties = oinfo->properties;
Packit 31ecd5
      GParameter *parameters;
Packit 31ecd5
Packit 31ecd5
      /* every other object: first, we get the construction parameters */
Packit 31ecd5
      oinfo->properties =
Packit 31ecd5
        clutter_script_construct_parameters (script,
Packit 31ecd5
                                             oinfo->gtype,
Packit 31ecd5
                                             oinfo->id,
Packit 31ecd5
                                             properties,
Packit 31ecd5
                                             &params);
Packit 31ecd5
Packit 31ecd5
      parameters = (GParameter *) (void *) params->data;
Packit 31ecd5
      oinfo->object = g_object_newv (oinfo->gtype,
Packit 31ecd5
                                     params->len,
Packit 31ecd5
                                     parameters);
Packit 31ecd5
Packit 31ecd5
      /* by sinking the floating reference, we make sure that the reference
Packit 31ecd5
       * count is correct whether the object is referenced from somewhere
Packit 31ecd5
       * else too or only by this ClutterScript object.
Packit 31ecd5
       */
Packit 31ecd5
      g_object_ref_sink (oinfo->object);
Packit 31ecd5
Packit 31ecd5
      for (i = 0; i < params->len; i++)
Packit 31ecd5
        {
Packit 31ecd5
          GParameter *param = &g_array_index (params, GParameter, i);
Packit 31ecd5
Packit 31ecd5
          g_free ((gchar *) param->name);
Packit 31ecd5
          g_value_unset (&param->value);
Packit 31ecd5
        }
Packit 31ecd5
Packit 31ecd5
      g_array_free (params, TRUE);
Packit 31ecd5
   }
Packit 31ecd5
Packit 31ecd5
  g_assert (oinfo->object != NULL);
Packit 31ecd5
Packit 31ecd5
  if (CLUTTER_IS_SCRIPTABLE (oinfo->object))
Packit 31ecd5
    clutter_scriptable_set_id (CLUTTER_SCRIPTABLE (oinfo->object), oinfo->id);
Packit 31ecd5
  else
Packit 31ecd5
    g_object_set_data_full (oinfo->object, "clutter-script-id",
Packit 31ecd5
                            g_strdup (oinfo->id),
Packit 31ecd5
                            g_free);
Packit 31ecd5
Packit 31ecd5
  _clutter_script_check_unresolved (script, oinfo);
Packit 31ecd5
}